From 1553e2bf4700f7bcad999d37361dd0357eb45599 Mon Sep 17 00:00:00 2001 From: n1dhn Date: Wed, 8 Dec 2021 14:31:53 +0530 Subject: [PATCH 01/49] Latest updated codes for didRef, rubixCore, and platform along with the jars 1. Removed syncing from start api, token transfer and mining 2. Every node pins their own DID and Public share 3. Consesus ID fix at receiver side and quorum side 4. Disabled Credit Security 5. New APIs to view, add and remove bootstrap lists too 6. Supports type 2 7. Calls IPFS repo in /start 8. IPFS daemon runs with --enable-gc Coded by Aparna, Reviewed by Team Signed-off-by: n1dhn --- .../rubix/Consensus/InitiatorConsensus.java | 167 +++++----------- .../rubix/Consensus/InitiatorProcedure.java | 2 + src/com/rubix/Consensus/QuorumConsensus.java | 65 +----- src/com/rubix/Resources/APIHandler.java | 30 ++- src/com/rubix/Resources/Functions.java | 42 ++-- src/com/rubix/Resources/IPFSNetwork.java | 47 ++++- src/com/rubix/TokenTransfer/ProofCredits.java | 189 ++++++++++-------- .../rubix/TokenTransfer/TokenReceiver.java | 23 ++- 8 files changed, 264 insertions(+), 301 deletions(-) diff --git a/src/com/rubix/Consensus/InitiatorConsensus.java b/src/com/rubix/Consensus/InitiatorConsensus.java index 0babc9cc..7a3b20af 100644 --- a/src/com/rubix/Consensus/InitiatorConsensus.java +++ b/src/com/rubix/Consensus/InitiatorConsensus.java @@ -1,32 +1,19 @@ package com.rubix.Consensus; -import static com.rubix.Resources.Functions.DATA_PATH; -import static com.rubix.Resources.Functions.LOGGER_PATH; -import static com.rubix.Resources.Functions.QUORUM_COUNT; -import static com.rubix.Resources.Functions.getValues; -import static com.rubix.Resources.Functions.minQuorum; -import static com.rubix.Resources.Functions.nodeData; -import static com.rubix.Resources.IPFSNetwork.forward; -import static com.rubix.Resources.IPFSNetwork.repo; -import static com.rubix.Resources.IPFSNetwork.swarmConnectP2P; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.PrintStream; -import java.net.Socket; -import java.util.ArrayList; - import com.rubix.AuthenticateNode.Authenticate; import com.rubix.Resources.IPFSNetwork; - +import io.ipfs.api.IPFS; import org.apache.log4j.Logger; import org.apache.log4j.PropertyConfigurator; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import java.io.*; +import java.net.Socket; +import java.util.ArrayList; -import io.ipfs.api.IPFS; +import static com.rubix.Resources.Functions.*; +import static com.rubix.Resources.IPFSNetwork.*; public class InitiatorConsensus { @@ -38,23 +25,24 @@ public class InitiatorConsensus { private static final Object countLock = new Object(); private static final Object signLock = new Object(); public static ArrayList quorumWithShares = new ArrayList<>(); - public static volatile int[] quorumResponse = {0, 0, 0}; - public static volatile JSONArray finalQuorumSignsArray = new JSONArray(); + public static volatile int[] quorumResponse = {0,0,0}; /** * This method increments the quorumResponse variable */ - private static synchronized boolean voteNCount(int i, int quorumSize) { + private static synchronized boolean voteNCount(int i,int quorumSize) { boolean status; PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); synchronized (countLock) { - if (quorumResponse[i] < minQuorum(quorumSize)) { + if(quorumResponse[i] { try { - swarmConnectP2P(quorumID[j], ipfs); + swarmConnectP2P(quorumID[j],ipfs); String quorumDidIpfsHash = getValues(DATA_PATH + "DataTable.json", "didHash", "peerid", quorumID[j]); String quorumWidIpfsHash = getValues(DATA_PATH + "DataTable.json", "walletHash", "peerid", quorumID[j]); nodeData(quorumDidIpfsHash, quorumWidIpfsHash, ipfs); String appName = quorumID[j].concat(role); - forward(appName, PORT + j, quorumID[j]); - InitiatorConsensusLogger.debug("Connected to " + quorumID[j] + "on port " + (PORT + j) + "with AppName" + appName); - qSocket[j] = new Socket("127.0.0.1", PORT + j); + InitiatorConsensusLogger.debug("quourm ID "+quorumID[j]+ " appname "+appName); + forward(appName, PORT+j, quorumID[j]); + InitiatorConsensusLogger.debug("Connected to " + quorumID[j] + "on port "+(PORT+j)+ "with AppName" + appName); + qSocket[j] = new Socket("127.0.0.1", PORT+j); qIn[j] = new BufferedReader(new InputStreamReader(qSocket[j].getInputStream())); qOut[j] = new PrintStream(qSocket[j].getOutputStream()); - qOut[j].println("qstcmrequest"); - qVerification[j] = qIn[j].readLine(); - JSONObject quorumDetails = new JSONObject(qVerification[j]); - String cmData = IPFSNetwork.get(quorumDetails.getString("CreditMapping"), ipfs); - - JSONObject qstContent = new JSONObject(quorumDetails.getString("QuorumSignedTransactions")); - - -// if (qstContent.length() == 0 && role == "alpha") { -// InitiatorConsensusLogger.warn("Alpha quorum (" + quorumID[j] + ") has no credits"); -// } -// if (cmContent.length() == 0 && role == "alpha") { -// InitiatorConsensusLogger.warn("Alpha quorum (" + quorumID[j] + ") has no credits in credit mapping data"); -// } - - if (!qstContent.has("minestatus") && qstContent.length() != 0) { - if (!qstContent.toString().contains("empty")) { - JSONArray cmContent = new JSONArray(cmData); - String credits = qstContent.getString("credits"); - - String creditContent = IPFSNetwork.get(credits, ipfs); - JSONArray credObject = new JSONArray(creditContent); - for (int k = 0; k < credObject.length(); k++) { - JSONObject object = credObject.getJSONObject(k); - String did = object.getString("did"); - String sign = object.getString("sign"); - String signHash = object.getString("hash"); - - JSONObject hashedCredObject = new JSONObject(); - hashedCredObject.put("did", did); - hashedCredObject.put("hash", signHash); - hashedCredObject.put("signature", sign); - - - if (!(Authenticate.verifySignature(hashedCredObject.toString()))) - InitiatorConsensusLogger.warn("Credit verification failed for Alpha quorum (" + quorumID[j] + ") credits"); - - - if (cmContent != null) { - for (int l = 0; l < cmContent.length(); l++) { - if ((cmContent.getJSONObject(l).getString("hash") == signHash)) { - InitiatorConsensusLogger.warn("Credit verification failed for Alpha quorum (" + quorumID[j] + ") credits - Hash matched in Credits Mapping file"); - } - } - } - - } - } - } - - qOut[j].println(detailsToken); qResponse[j] = qIn[j].readLine(); if (qResponse[j].equals("Auth_Failed")) { IPFSNetwork.executeIPFSCommands("ipfs p2p close -t /p2p/" + quorumID[j]); - } else { - InitiatorConsensusLogger.debug("Signature Received from " + quorumID[j]); + } + else { + InitiatorConsensusLogger.debug("Signature Received from " + quorumID[j] + " " + qResponse[j]); if (quorumResponse[index] > minQuorum(quorumSize)) { qOut[j].println("null"); IPFSNetwork.executeIPFSCommands("ipfs p2p close -t /p2p/" + quorumID[j]); @@ -208,41 +144,42 @@ public static JSONObject start(String data, IPFS ipfs, int PORT, int index, Stri detailsToVerify.put("hash", hash); detailsToVerify.put("signature", qResponse[j]); if (Authenticate.verifySignature(detailsToVerify.toString())) { - boolean voteStatus = voteNCount(index, quorumSize); + InitiatorConsensusLogger.debug(role + " node authenticated at index " + index); + boolean voteStatus = voteNCount(index,quorumSize); if (quorumResponse[index] <= minQuorum(quorumSize) && voteStatus) { - while (quorumResponse[index] < minQuorum(quorumSize)) { - } - quorumSign(didHash, hash, qResponse[j], index, quorumSize, alphaSize); + InitiatorConsensusLogger.debug("waiting for " +quorumSize +" +signs " + role); + while (quorumResponse[index] < minQuorum(quorumSize)) {} + InitiatorConsensusLogger.debug("between Q1- to Q"+quorumSize+" for index " + index); + quorumSign(didHash, qResponse[j], index,quorumSize,alphaSize); quorumWithShares.add(quorumPeersObject.getString(j)); - while (quorumSignature.length() < (minQuorum(alphaSize) + 2 * minQuorum(7))) { - } - - qOut[j].println(finalQuorumSignsArray); + while (quorumSignature.length() < (minQuorum(alphaSize) + 2* minQuorum(7))) {} + InitiatorConsensusLogger.debug("sending Qsign of length " + quorumSignature.length() + "at index " + index); + qOut[j].println(quorumSignature); IPFSNetwork.executeIPFSCommands("ipfs p2p close -t /p2p/" + quorumID[j]); - } else { - + } + else { + InitiatorConsensusLogger.debug("sending null for slow quorum "); qOut[j].println("null"); IPFSNetwork.executeIPFSCommands("ipfs p2p close -t /p2p/" + quorumID[j]); } InitiatorConsensusLogger.debug("Quorum Count : " + quorumResponse + "Signature count : " + quorumSignature.length()); } else { InitiatorConsensusLogger.debug("node failed authentication with index " + index + " with role " + role + " with did " + didHash + " and data to verify " + detailsToVerify); + InitiatorConsensusLogger.debug("recheck result is " + Authenticate.verifySignature(detailsToVerify.toString())); IPFSNetwork.executeIPFSCommands("ipfs p2p close -t /p2p/" + quorumID[j]); } } } } catch (IOException | JSONException e) { - IPFSNetwork.executeIPFSCommands("ipfs p2p close -t /p2p/" + quorumID[j]); - InitiatorConsensusLogger.error("IOException Occurred"); + IPFSNetwork.executeIPFSCommands("ipfs p2p close -t /p2p/"+ quorumID[j]); + InitiatorConsensusLogger.error("IOException Occurred", e); e.printStackTrace(); } }); quorumThreads[j].start(); } - while (quorumResponse[index] < minQuorum(quorumSize) || quorumSignature.length() < (minQuorum(alphaSize) + 2 * minQuorum(7))) { - } - repo(ipfs); + while(quorumResponse[index] < minQuorum(quorumSize) || quorumSignature.length() < (minQuorum(alphaSize) + 2* minQuorum(7))){} } catch (JSONException e) { InitiatorConsensusLogger.error("JSON Exception Occurred", e); diff --git a/src/com/rubix/Consensus/InitiatorProcedure.java b/src/com/rubix/Consensus/InitiatorProcedure.java index 5d26d05f..8041f9ea 100644 --- a/src/com/rubix/Consensus/InitiatorProcedure.java +++ b/src/com/rubix/Consensus/InitiatorProcedure.java @@ -44,6 +44,8 @@ public static void consensusSetUp(String data,IPFS ipfs, int PORT,int alphaSize) String authSenderByQuorumHash="", authQuorumHash=""; authSenderByQuorumHash = message; authQuorumHash = calculateHash(authSenderByQuorumHash.concat(receiverDidIpfs), "SHA3-256"); + InitiatorProcedureLogger.debug("Sender by Quorum Hash" + authSenderByQuorumHash); + InitiatorProcedureLogger.debug("Quorum Auth Hash" + authQuorumHash); try { payload.put("sender", senderDidIpfs); diff --git a/src/com/rubix/Consensus/QuorumConsensus.java b/src/com/rubix/Consensus/QuorumConsensus.java index e10ae9a3..b1bb1dcb 100644 --- a/src/com/rubix/Consensus/QuorumConsensus.java +++ b/src/com/rubix/Consensus/QuorumConsensus.java @@ -1,7 +1,6 @@ package com.rubix.Consensus; import com.rubix.AuthenticateNode.Authenticate; -import com.rubix.AuthenticateNode.PropImage; import com.rubix.Resources.IPFSNetwork; import io.ipfs.api.IPFS; import org.apache.log4j.Logger; @@ -9,6 +8,7 @@ import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; + import java.io.*; import java.net.ServerSocket; import java.net.Socket; @@ -63,47 +63,11 @@ public void run() { serverSocket = new ServerSocket(port); socket = serverSocket.accept(); - BufferedReader dataReq = new BufferedReader(new InputStreamReader(socket.getInputStream())); BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); - PrintStream dataResp = new PrintStream(socket.getOutputStream()); PrintStream out = new PrintStream(socket.getOutputStream()); JSONObject readSenderData; String getData; - String qstReq; - - //? check for incoming request for QST - - qstReq = dataReq.readLine(); - if (qstReq.contains("qstcmrequest")) { - - QuorumConsensusLogger.debug("Sender reqesting QuorumSignedTransactions.json and CreditMapping.json: " + qstReq); - - File creditsMapping = new File(WALLET_DATA_PATH + "CreditMapping.json"); - if(!creditsMapping.exists()) { - QuorumConsensusLogger.debug("File doesn't exist"); - creditsMapping.createNewFile(); - writeToFile(creditsMapping.toString(), "[]", false); - } - JSONArray qstContent = new JSONArray(readFile(WALLET_DATA_PATH + "QuorumSignedTransactions.json")); - JSONObject qstObjectSend = new JSONObject(); - if(qstContent.length() > 0) - qstObjectSend = qstContent.getJSONObject(qstContent.length() - 1); - - String cmFileHash = IPFSNetwork.add(WALLET_DATA_PATH + "CreditMapping.json", ipfs); - - JSONObject qResponse = new JSONObject(); - qResponse.put("QuorumSignedTransactions", qstObjectSend.toString()); - qResponse.put("CreditMapping", cmFileHash); - - dataResp.println(qResponse.toString()); - } - - - //TODO: if the incoming request contains the keyword "request", push the QST to IPFS and send the two hashes back to the sender. - - //? This is where quorum fetched the data send from initiatorConsensus (Line 148) - getData = in.readLine(); if (getData.contains("ping check")) { QuorumConsensusLogger.debug("Ping check from sender: " + getData); @@ -136,7 +100,7 @@ public void run() { ArrayList dhtOwnersList = dhtOwnerCheck(verifySenderHash); QuorumConsensusLogger.debug("Providers: " + dhtOwnersList); boolean consensusIDcheck = false; - if(dhtOwnersList.size() == 2 && dhtOwnersList.contains(senderPID) && dhtOwnersList.contains(receiverPID)) + if(dhtOwnersList.size() <= 2 && dhtOwnersList.contains(senderPID)) consensusIDcheck = true; @@ -151,39 +115,16 @@ public void run() { String creditval; creditval = in.readLine(); QuorumConsensusLogger.debug("credit value " + creditval); - if (!creditval.equals("null")) { //commented as per test for multiple consensus threads - FileWriter shareWriter = new FileWriter(new File(LOGGER_PATH + "mycredit.txt"), true); shareWriter.write(creditval); shareWriter.close(); File readCredit = new File(LOGGER_PATH + "mycredit.txt"); String credit = add(readCredit.toString(), ipfs); - - // adding credit to credit mapping - JSONArray CreditBody = new JSONArray(creditval); - JSONObject creditMappingObject = new JSONObject(); - JSONArray creditMappingArray = new JSONArray(); - - for(int i = 0; i < CreditBody.length(); i++){ - JSONObject object = CreditBody.getJSONObject(i); - String key = object.getString("did"); - String sign = object.getString("sign"); - String creditHash = calculateHash(sign, "SHA3-256"); - - creditMappingObject.put("did", key); - creditMappingObject.put("sign", sign); - creditMappingObject.put("hash", creditHash); - creditMappingObject.put("tid", transactionID); - - creditMappingArray.put(creditMappingObject); - - writeToFile(WALLET_DATA_PATH + "CreditMapping.json", creditMappingArray.toString(), false); - - } JSONObject storeDetailsQuorum = new JSONObject(); storeDetailsQuorum.put("tid", transactionID); storeDetailsQuorum.put("consensusID", verifySenderHash); + storeDetailsQuorum.put("minestatus", false); storeDetailsQuorum.put("sign", senderPrivatePos); storeDetailsQuorum.put("credits", credit); storeDetailsQuorum.put("senderdid", senderDidIpfsHash); diff --git a/src/com/rubix/Resources/APIHandler.java b/src/com/rubix/Resources/APIHandler.java index 6563a971..809442fd 100644 --- a/src/com/rubix/Resources/APIHandler.java +++ b/src/com/rubix/Resources/APIHandler.java @@ -2,9 +2,14 @@ import com.rubix.TokenTransfer.ProofCredits; import com.rubix.TokenTransfer.TokenSender; -import io.ipfs.api.*; -import org.apache.log4j.*; -import org.json.*; +import io.ipfs.api.IPFS; +import io.ipfs.api.Peer; +import org.apache.log4j.Logger; +import org.apache.log4j.PropertyConfigurator; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + import java.io.BufferedReader; import java.io.File; import java.io.IOException; @@ -17,7 +22,7 @@ import java.util.*; import static com.rubix.Resources.Functions.*; -import static com.rubix.Resources.IPFSNetwork.executeIPFSCommands; +import static com.rubix.Resources.IPFSNetwork.*; public class APIHandler { private static final Logger APILogger = Logger.getLogger(APIHandler.class); @@ -197,6 +202,23 @@ public static JSONArray accountInformation() throws JSONException { return resultArray; } + /** + * A method to add and host your DID ans Public share to ipfs + */ + public static void addPublicData(){ + String peerID = getPeerID(DATA_PATH + "DID.json"); + String didHash = getValues(DATA_PATH + "DataTable.json", "didHash", "peerid", peerID); + String walletHash = getValues(DATA_PATH + "DataTable.json", "walletHash", "peerid", peerID); + + add(DATA_PATH.concat(didHash).concat("/DID.png"), ipfs); + pin(didHash, ipfs); + + add(DATA_PATH.concat(didHash).concat("/PublicShare.png"), ipfs); + pin(walletHash, ipfs); + + APILogger.debug("Data Added and Pinned"); + } + /** * A call to sync all the nodes in the network * @return Message if failed or succeeded diff --git a/src/com/rubix/Resources/Functions.java b/src/com/rubix/Resources/Functions.java index b7331468..7788ae6c 100644 --- a/src/com/rubix/Resources/Functions.java +++ b/src/com/rubix/Resources/Functions.java @@ -1,6 +1,5 @@ package com.rubix.Resources; -import static com.rubix.Resources.APIHandler.networkInfo; import static com.rubix.Resources.IPFSNetwork.checkSwarmConnect; import static com.rubix.Resources.IPFSNetwork.executeIPFSCommands; import static com.rubix.Resources.IPFSNetwork.forwardCheck; @@ -15,8 +14,6 @@ import java.io.IOException; import java.io.InputStreamReader; import java.net.HttpURLConnection; -import java.net.MalformedURLException; -import java.net.ProtocolException; import java.net.URL; import java.nio.charset.StandardCharsets; import java.nio.file.Files; @@ -137,7 +134,6 @@ public static void pathSet() { } - //? public static void nodeData(String did, String wid, IPFS ipfs) throws IOException { PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); File dataFolder = new File(DATA_PATH + did + "/"); @@ -221,7 +217,6 @@ public static String getSystemUser() { * @return (String) hash */ - //? rubix-crypto public static String calculateHash(String message, String algorithm) { PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); MessageDigest digest = null; @@ -562,6 +557,7 @@ public static ArrayList QuorumCheck(JSONArray quorum, int size) { quorumPeer = getValues(DATA_PATH + "DataTable.json", "peerid", "didHash", quorum.getString(i)); if (checkSwarmConnect().contains(quorumPeer)) { peers.add(quorumPeer); + FunctionsLogger.debug(quorumPeer + " added to list"); } } catch (JSONException e) { FunctionsLogger.error("JSON Exception Occurred", e); @@ -589,8 +585,11 @@ public static void QuorumSwarmConnect(JSONArray quorum, IPFS ipfs) { for (int i = 0; i < quorum.length(); i++) { String quorumPeer; try { + FunctionsLogger.debug("Quorum DID: "+ quorum.getString(i)); quorumPeer = getValues(DATA_PATH + "DataTable.json", "peerid", "didHash", quorum.getString(i)); - + FunctionsLogger.debug("Quorum PID: "+ quorumPeer); + // Commented by Anuradha K; A new method swamConnectP2P is implemented for swarm connection + // IPFSNetwork.swarmConnect(quorumPeer,ipfs); IPFSNetwork.swarmConnectP2P(quorumPeer,ipfs); } catch (JSONException e) { @@ -643,6 +642,7 @@ public static int[] getPrivatePosition(int[] positions, int[] privateArray) { public static JSONObject randomPositions(String role, String hash, int numberOfPositions, int[] pvt1) throws JSONException { int u = 0, l = 0, m = 0; + long st = System.currentTimeMillis(); int[] hashCharacters = new int[256]; int[] randomPositions = new int[32]; int[] randPos = new int[256]; @@ -687,6 +687,8 @@ public static JSONObject randomPositions(String role, String hash, int numberOfP JSONObject resultObject = new JSONObject(); resultObject.put("originalPos", originalPos); resultObject.put("posForSign", posForSign); + long et = System.currentTimeMillis(); + FunctionsLogger.debug("Time taken for randomPositions Calculation " + (et - st)); return resultObject; } @@ -723,7 +725,7 @@ public static void deleteFile(String fileName) { FunctionsLogger.error("IOException Occurred", e); e.printStackTrace(); } - + FunctionsLogger.debug("File Deletion successful"); } @@ -765,30 +767,15 @@ public static void deleteFile(String fileName) { public static void launch() { pathSet(); PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); - int syncFlag = 0; + try { executeIPFSCommands("ipfs daemon --enable-gc"); - if (!SYNC_IP.contains("127.0.0.1")) { - networkInfo(); - syncFlag = 1; - } - } catch (MalformedURLException e) { - FunctionsLogger.error("MalformedURL Exception Occurred", e); - e.printStackTrace(); - } catch (ProtocolException e) { - FunctionsLogger.error("Protocol Exception Occurred", e); - e.printStackTrace(); - } catch (IOException e) { - FunctionsLogger.error("IO Exception Occurred", e); - e.printStackTrace(); - } catch (JSONException e) { + } catch (Exception e) { e.printStackTrace(); } - if (syncFlag == 1) - FunctionsLogger.info("Synced Successfully!"); - else - FunctionsLogger.info("Not synced! Try again after sometime."); + + FunctionsLogger.debug("Enabled ipfs GC"); } /** @@ -797,7 +784,6 @@ public static void launch() { * @return A message * @throws JSONException handle all JSON Exceptions */ - //? self-test public static String checkDirectory() throws JSONException { setDir(); File mainDir = new File(dirPath); @@ -1049,7 +1035,7 @@ public static JSONArray getQuorum(String betaHash,String gammaHash,String sender responseQuorumPick.append(outputQuorumPick); } inQuorumPick.close(); - + FunctionsLogger.debug(" responsequorumpick " + responseQuorumPick.toString()); quorumArray = new JSONArray(responseQuorumPick.toString()); return quorumArray; } diff --git a/src/com/rubix/Resources/IPFSNetwork.java b/src/com/rubix/Resources/IPFSNetwork.java index 72c894ea..1d312b37 100644 --- a/src/com/rubix/Resources/IPFSNetwork.java +++ b/src/com/rubix/Resources/IPFSNetwork.java @@ -1,5 +1,30 @@ package com.rubix.Resources; +import static com.rubix.Constants.IPFSConstants.bootstrap; +import static com.rubix.Constants.IPFSConstants.daemon; +import static com.rubix.Constants.IPFSConstants.forward; +import static com.rubix.Constants.IPFSConstants.listen; +import static com.rubix.Constants.IPFSConstants.p2p; +import static com.rubix.Constants.IPFSConstants.shutdown; +import static com.rubix.Resources.Functions.BOOTSTRAPS; +import static com.rubix.Resources.Functions.LOGGER_PATH; +import static com.rubix.Resources.Functions.getOsName; + +import java.awt.image.BufferedImage; +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.List; + +import javax.imageio.ImageIO; + +import org.apache.log4j.Logger; +import org.apache.log4j.PropertyConfigurator; +import org.json.JSONException; + import io.ipfs.api.IPFS; import io.ipfs.api.MerkleNode; import io.ipfs.api.NamedStreamable; @@ -65,6 +90,7 @@ public static boolean forwardCheck(String application, int port, String peerid) } public static String checkSwarmConnect() { + IPFSNetworkLogger.debug("check swarm peers request"); String response = executeIPFSCommandsResponse("ipfs swarm peers"); return response; } @@ -188,6 +214,7 @@ public static String swarmConnectProcess(MultiAddress multiAddress) { sb.append(line); sb.append("\n"); } + IPFSNetworkLogger.debug(command + " output: " + sb.toString()); if (!OS.contains("Windows")) P.waitFor(); br.close(); @@ -426,6 +453,7 @@ public static void repo(IPFS ipfs) { } public static String executeIPFSCommandsResponse(String command) { + IPFSNetworkLogger.debug("executeIPFSCommandsResponse for command " + command); PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); String OS = getOsName(); String result; @@ -453,7 +481,8 @@ public static String executeIPFSCommandsResponse(String command) { } if (command.contains(listen) || command.contains(forward) || command.contains("swarm") - || command.contains(p2p) || command.contains(shutdown)) { + || command.contains(p2p) || command.contains(shutdown) || command.contains(bootstrap)) { + IPFSNetworkLogger.debug("executing command " + command); p = new ProcessBuilder(commands); process = p.start(); @@ -471,7 +500,8 @@ public static String executeIPFSCommandsResponse(String command) { return result; } else { - return "wrong command ".concat(command); + IPFSNetworkLogger.debug("unhandled command " + command); + return "wrong command"; } } catch (IOException e) { @@ -483,7 +513,7 @@ public static String executeIPFSCommandsResponse(String command) { result = e.toString(); e.printStackTrace(); } - + IPFSNetworkLogger.debug("return string "); return result; } @@ -520,7 +550,7 @@ public static void executeIPFSCommands(String command) { } if (command.contains(listen) || command.contains(forward) || command.contains(p2p) - || command.contains(shutdown)) { + || command.contains(shutdown) || command.contains(bootstrap)) { p = new ProcessBuilder(commands); process = p.start(); @@ -549,27 +579,34 @@ public static void swarmConnectP2P(String peerid, IPFS ipfs) throws JSONExceptio PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); String bootNode; boolean swarmConnected = false; + IPFSNetworkLogger.debug("swarm connect p2p" + peerid); MultiAddress multiAddress = new MultiAddress("/ipfs/" + peerid); String output = swarmConnectProcess(multiAddress); if (!output.contains("success")) { + IPFSNetworkLogger.debug("Connecting via bootstrap "); + IPFSNetworkLogger.debug("Bootstraps " + BOOTSTRAPS + "size " + BOOTSTRAPS.length()); for (int i = 0; i < BOOTSTRAPS.length(); i++) { if (!swarmConnected) { bootNode = String.valueOf(BOOTSTRAPS.get(i)); bootNode = bootNode.substring(bootNode.length() - 46); + IPFSNetworkLogger.debug("bootnode is " + bootNode); multiAddress = new MultiAddress("/ipfs/" + bootNode + "/p2p-circuit/ipfs/" + peerid); output = swarmConnectProcess(multiAddress); if (!output.contains("success")) { - IPFSNetworkLogger.debug("swarm attempt failed with " + peerid); + IPFSNetworkLogger.debug("swarm attempt failed"); } else { + IPFSNetworkLogger.debug("Connected via bootstrap node: " + bootNode); swarmConnected = true; } } } + } else { + IPFSNetworkLogger.debug("Swarm Connected p2p : " + peerid); } } diff --git a/src/com/rubix/TokenTransfer/ProofCredits.java b/src/com/rubix/TokenTransfer/ProofCredits.java index 5eab47b1..c4a73851 100644 --- a/src/com/rubix/TokenTransfer/ProofCredits.java +++ b/src/com/rubix/TokenTransfer/ProofCredits.java @@ -1,18 +1,32 @@ package com.rubix.TokenTransfer; -import com.rubix.Consensus.InitiatorConsensus; -import com.rubix.Consensus.InitiatorProcedure; -import com.rubix.Resources.Functions; -import com.rubix.Resources.IPFSNetwork; -import io.ipfs.api.IPFS; -import org.apache.log4j.Logger; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; +import static com.rubix.Resources.Functions.DATA_PATH; +import static com.rubix.Resources.Functions.EXPLORER_IP; +import static com.rubix.Resources.Functions.LOGGER_PATH; +import static com.rubix.Resources.Functions.PAYMENTS_PATH; +import static com.rubix.Resources.Functions.QuorumCheck; +import static com.rubix.Resources.Functions.QuorumSwarmConnect; +import static com.rubix.Resources.Functions.SEND_PORT; +import static com.rubix.Resources.Functions.SYNC_IP; +import static com.rubix.Resources.Functions.TOKENCHAIN_PATH; +import static com.rubix.Resources.Functions.TOKENS_PATH; +import static com.rubix.Resources.Functions.WALLET_DATA_PATH; +import static com.rubix.Resources.Functions.calculateHash; +import static com.rubix.Resources.Functions.deleteFile; +import static com.rubix.Resources.Functions.getQuorum; +import static com.rubix.Resources.Functions.minQuorum; +import static com.rubix.Resources.Functions.mineUpdate; +import static com.rubix.Resources.Functions.readFile; +import static com.rubix.Resources.Functions.updateJSON; +import static com.rubix.Resources.Functions.updateQuorum; +import static com.rubix.Resources.Functions.writeToFile; +import static com.rubix.Resources.IPFSNetwork.repo; -import javax.net.ssl.HttpsURLConnection; -import java.io.*; +import java.io.BufferedReader; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import java.text.DateFormat; @@ -23,8 +37,17 @@ import java.util.Iterator; import java.util.List; -import static com.rubix.Resources.Functions.*; -import static com.rubix.Resources.IPFSNetwork.repo; +import javax.net.ssl.HttpsURLConnection; + +import org.apache.log4j.*; +import org.json.*; + +import com.rubix.Consensus.InitiatorConsensus; +import com.rubix.Consensus.InitiatorProcedure; +import com.rubix.Resources.Functions; +import com.rubix.Resources.IPFSNetwork; + +import io.ipfs.api.*; public class ProofCredits { @@ -35,8 +58,8 @@ public class ProofCredits { private static ArrayList alphaPeersList; private static ArrayList betaPeersList; private static ArrayList gammaPeersList; - private static int sizeOfQuorum = 0; - private static int alphaSize = 0; + private static int sizeOfQuorum=0; + private static int alphaSize=0; public static JSONObject create(String data, IPFS ipfs) throws IOException, JSONException { @@ -45,15 +68,15 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON String receiverDidIpfsHash = detailsObject.getString("receiverDidIpfsHash"); String pvt = detailsObject.getString("pvt"); int type = detailsObject.getInt("type"); - int creditUsed = 0; - long totalTime = 0; + int creditUsed=0; + long totalTime=0; JSONArray alphaQuorum = new JSONArray(); - JSONArray betaQuorum = new JSONArray(); - JSONArray gammaQuorum = new JSONArray(); + JSONArray betaQuorum=new JSONArray(); + JSONArray gammaQuorum=new JSONArray(); - int creditsRequired = 50000, level; + int level = 0,tokenNumber = 0,availableCredits = 0, balance=0,creditsRequired=500000,level_credit=0; long starttime = System.currentTimeMillis(); JSONArray resJsonData = new JSONArray(); new JSONObject(); @@ -61,11 +84,18 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON //Reading proofcredits.json - String jsonFilePath = WALLET_DATA_PATH + "QuorumSignedTransactions.json"; + String jsonFilePath = WALLET_DATA_PATH+"QuorumSignedTransactions.json"; JSONArray records = new JSONArray(readFile(jsonFilePath)); - int balance = records.length(); + balance = records.length(); JSONArray prooftid = new JSONArray(); - int availableCredits = records.length(); + for (int i = 0; i < balance; i++) { + JSONObject temp = records.getJSONObject(i); + if(temp.getBoolean("minestatus")==false) { + availableCredits++; + //prooftid.put(temp.getString("tid")); + // records.getJSONObject(i).put("minestatus",true); + } + } String GET_URL_credit = SYNC_IP + "/getlevel"; URL URLobj_credit = new URL(GET_URL_credit); @@ -88,18 +118,18 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON //creditUsed = responseJSON.getInt("credits"); - resJsonData_credit = new JSONObject(response_credit.toString()); - int level_credit = resJsonData_credit.getInt("level"); - creditsRequired = (int) Math.pow(2, (2 + level_credit)); - ProofCreditsLogger.debug("credits required " + creditsRequired); + resJsonData_credit = new JSONObject(response_credit.toString()); + level_credit = resJsonData_credit.getInt("level"); + creditsRequired =(int) Math.pow(2,(2+level_credit)); + ProofCreditsLogger.debug("credits required " + creditsRequired); } else ProofCreditsLogger.debug("GET request not worked"); - ProofCreditsLogger.debug("credits required " + creditsRequired + " available credits " + availableCredits); + ProofCreditsLogger.debug("credits required " + creditsRequired+ " available credits "+ availableCredits); - if (availableCredits >= creditsRequired) { + if (availableCredits>=creditsRequired) { //String GET_URL = SYNC_IP+"/getInfo?count="+availableCredits; @@ -139,11 +169,11 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON for (int i = 0; i < resJsonData.length(); i++) { token.put(Functions.mineToken(resJsonData.getJSONObject(i).getInt("level"), resJsonData.getJSONObject(i).getInt("token"))); - creditUsed += (int) Math.pow(2, (2 + resJsonData.getJSONObject(i).getInt("level"))); + creditUsed+=(int) Math.pow(2,(2+resJsonData.getJSONObject(i).getInt("level"))); } - if (resJsonData.getJSONObject(0).getInt("level") == 1) + if(resJsonData.getJSONObject(0).getInt("level")==1) creditUsed = 10; String comments = resJsonData.toString() + prooftid; @@ -151,53 +181,54 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON String authSenderByRecHash = calculateHash(token + receiverDidIpfsHash + comments, "SHA3-256"); String tid = calculateHash(authSenderByRecHash, "SHA3-256"); - writeToFile(LOGGER_PATH + "tempbeta", tid.concat(receiverDidIpfsHash), false); - String betaHash = IPFSNetwork.add(LOGGER_PATH + "tempbeta", ipfs); - deleteFile(LOGGER_PATH + "tempbeta"); + writeToFile(LOGGER_PATH+"tempbeta", tid.concat(receiverDidIpfsHash), false); + String betaHash = IPFSNetwork.add(LOGGER_PATH+"tempbeta", ipfs); + deleteFile(LOGGER_PATH+"tempbeta"); - writeToFile(LOGGER_PATH + "tempgamma", tid.concat(receiverDidIpfsHash), false); - String gammaHash = IPFSNetwork.add(LOGGER_PATH + "tempgamma", ipfs); - deleteFile(LOGGER_PATH + "tempgamma"); + writeToFile(LOGGER_PATH+"tempgamma", tid.concat(receiverDidIpfsHash), false); + String gammaHash = IPFSNetwork.add(LOGGER_PATH+"tempgamma", ipfs); + deleteFile(LOGGER_PATH+"tempgamma"); JSONArray quorumArray; - // JSONArray quorumArray= getQuorum(betaHash,gammaHash,receiverDidIpfsHash,receiverDidIpfsHash,token.length()); - // JSONArray quorumArray = new JSONArray(readFile(DATA_PATH + "quorumlist.json")); + // JSONArray quorumArray= getQuorum(betaHash,gammaHash,receiverDidIpfsHash,receiverDidIpfsHash,token.length()); + // JSONArray quorumArray = new JSONArray(readFile(DATA_PATH + "quorumlist.json")); switch (type) { - case 2: { - quorumArray = new JSONArray(readFile(DATA_PATH + "quorumlist.json")); - break; - } + case 2: { + quorumArray = new JSONArray(readFile(DATA_PATH + "quorumlist.json")); + break; + } default: { - quorumArray = getQuorum(betaHash, gammaHash, receiverDidIpfsHash, receiverDidIpfsHash, token.length()); - } + quorumArray= getQuorum(betaHash,gammaHash,receiverDidIpfsHash,receiverDidIpfsHash,token.length()); + } } + + QuorumSwarmConnect(quorumArray,ipfs); - QuorumSwarmConnect(quorumArray, ipfs); - - alphaSize = quorumArray.length() - 14; + alphaSize=quorumArray.length()-14; - for (int i = 0; i < alphaSize; i++) + for(int i=0;i= 3 * minQuorum(7))) { APIResponse.put("did", receiverDidIpfsHash); @@ -231,18 +262,19 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON int counter = 0; for (int i = 0; i < balance; i++) { JSONObject temp = records.getJSONObject(i); - if (counter < creditUsed) { + if (temp.getBoolean("minestatus") == false && (counter < creditUsed)) { prooftid.put(temp.getString("tid")); + records.getJSONObject(i).put("minestatus", true); counter++; } } for (int i = 0; i < token.length(); i++) { - writeToFile(LOGGER_PATH + "tempToken", token.getString(i), false); - String tokenHash = IPFSNetwork.add(LOGGER_PATH + "tempToken", ipfs); + writeToFile(LOGGER_PATH+"tempToken", token.getString(i), false); + String tokenHash = IPFSNetwork.add(LOGGER_PATH+"tempToken", ipfs); writeToFile(TOKENS_PATH + tokenHash, token.getString(i), false); - deleteFile(LOGGER_PATH + "tempToken"); + deleteFile(LOGGER_PATH+"tempToken"); writeToFile(TOKENCHAIN_PATH + tokenHash + ".json", "[]", false); JSONObject temp = new JSONObject(); temp.put("tokenHash", tokenHash); @@ -251,22 +283,21 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON updateJSON("add", PAYMENTS_PATH + "BNK00.json", tempArray.toString()); } - File usedCreditsFile = new File(WALLET_DATA_PATH + "MinedCreditsHistory.json"); - if(!usedCreditsFile.exists()){ - writeToFile(String.valueOf(usedCreditsFile), "[]", false); - } - writeToFile(String.valueOf(usedCreditsFile), records.toString(), false); + writeToFile(jsonFilePath,records.toString(),false); +// FileWriter File = new FileWriter(jsonFilePath); +// File.write(records.toString()); +// File.close(); ProofCreditsLogger.debug("Updated balance of node : " + (balance - creditUsed)); long endtime = System.currentTimeMillis(); - totalTime = endtime - starttime; + totalTime=endtime-starttime; Iterator keys = InitiatorConsensus.quorumSignature.keys(); JSONArray signedQuorumList = new JSONArray(); while (keys.hasNext()) signedQuorumList.put(keys.next()); - updateQuorum(quorumArray, signedQuorumList, true, type); - mineUpdate(receiverDidIpfsHash, creditUsed); + updateQuorum(quorumArray,signedQuorumList,true,type); + mineUpdate(receiverDidIpfsHash,creditUsed); APIResponse.put("did", receiverDidIpfsHash); APIResponse.put("tid", tid); APIResponse.put("token", token); @@ -274,7 +305,7 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON APIResponse.put("quorumlist", signedQuorumList); APIResponse.put("time", totalTime); APIResponse.put("status", "Success"); - APIResponse.put("message", token.length() + " tokens mined"); + APIResponse.put("message", token.length()+" tokens mined"); DateFormat formatter = new SimpleDateFormat("yyyy/MM/dd"); Date date = new Date(); @@ -283,7 +314,7 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON transactionRecord.put("role", "Sender"); transactionRecord.put("tokens", token); transactionRecord.put("txn", tid); - transactionRecord.put("quorumList", signedQuorumList); + transactionRecord.put("quorumList",signedQuorumList); transactionRecord.put("senderDID", receiverDidIpfsHash); transactionRecord.put("receiverDID", receiverDidIpfsHash); transactionRecord.put("Date", currentTime); @@ -318,7 +349,7 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON dataToSend.put("bank_id", "01"); dataToSend.put("user_did", receiverDidIpfsHash); dataToSend.put("token_id", token); - dataToSend.put("level", level); + dataToSend.put("level",level); dataToSend.put("denomination", 1); String populate = dataToSend.toString(); @@ -354,7 +385,7 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON List tokenList = new ArrayList<>(); for (int i = 0; i < token.length(); i++) tokenList.add(token.getString(i)); - String urlTxn = EXPLORER_IP + "/CreateOrUpdateRubixTransaction"; + String urlTxn = EXPLORER_IP+"/CreateOrUpdateRubixTransaction"; URL objTxn = new URL(urlTxn); HttpsURLConnection conTxn = (HttpsURLConnection) objTxn.openConnection(); @@ -414,7 +445,9 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON ProofCreditsLogger.warn("error from mine service"); return APIResponse; } - } else { + } + else + { APIResponse.put("did", receiverDidIpfsHash); APIResponse.put("tid", "null"); APIResponse.put("status", "Failed"); diff --git a/src/com/rubix/TokenTransfer/TokenReceiver.java b/src/com/rubix/TokenTransfer/TokenReceiver.java index 05546232..a89c1543 100644 --- a/src/com/rubix/TokenTransfer/TokenReceiver.java +++ b/src/com/rubix/TokenTransfer/TokenReceiver.java @@ -55,6 +55,10 @@ public static String receive() { ArrayList quorumDID = new ArrayList<>(); PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); + DateFormat formatter = new SimpleDateFormat("yyyy/MM/dd"); + Date date = new Date(); + LocalDate currentTime = LocalDate.parse(formatter.format(date).replace("/", "-")); + String receiverPeerID = getPeerID(DATA_PATH + "DID.json"); String receiverDidIpfsHash = getValues(DATA_PATH + "DataTable.json", "didHash", "peerid", receiverPeerID); @@ -159,7 +163,7 @@ public static String receive() { ss.close(); return APIResponse.toString(); } - else if(!(dhtOwnersList.size() == 1 && dhtOwnersList.contains(senderPeerID))){ + else if(!(dhtOwnersList.size() <= 2 && dhtOwnersList.contains(senderPeerID))){ String errorMessage = "Consensus ID not unique: " + dhtOwnersList.size() + " owns the hash " + dhtOwnersList; output.println("421"); APIResponse.put("did", senderDidIpfsHash); @@ -216,15 +220,15 @@ else if(!(ipfsGetFlag == tokenCount)){ if (Status.equals("Consensus Reached")) { // String QuorumDetails = input.readLine(); -// TokenReceiverLogger.debug("Quorum Signatures: " + QuorumDetails); + TokenReceiverLogger.debug("Quorum Signatures: " + QuorumDetails); quorumSignatures = new JSONObject(QuorumDetails); int alphaSize = quorumSignatures.length() - 10; // String selectQuorumHash = calculateHash(senderToken, "SHA3-256"); String verifyQuorumHash = calculateHash(getCIDipfsHash.concat(receiverDidIpfsHash), "SHA3-256"); -// TokenReceiverLogger.debug("Quorum Hash on Receiver Side " + verifyQuorumHash); -// TokenReceiverLogger.debug("Quorum Signatures length : " + quorumSignatures.length()); + TokenReceiverLogger.debug("Quorum Hash on Receiver Side " + verifyQuorumHash); + TokenReceiverLogger.debug("Quorum Signatures length : " + quorumSignatures.length()); Iterator keys = quorumSignatures.keys(); while (keys.hasNext()) { @@ -240,8 +244,9 @@ else if(!(ipfsGetFlag == tokenCount)){ quorumDataFolder.mkdirs(); IPFSNetwork.getImage(quorumDidIpfsHash, ipfs, DATA_PATH + quorumDidIpfsHash + "/DID.png"); IPFSNetwork.getImage(quorumWidIpfsHash, ipfs, DATA_PATH + quorumDidIpfsHash + "/PublicShare.png"); -// TokenReceiverLogger.debug("Quorum Data " + quorumDidIpfsHash + " Added"); - } + TokenReceiverLogger.debug("Quorum Data " + quorumDidIpfsHash + " Added"); + } else + TokenReceiverLogger.debug("Quorum Data " + quorumDidIpfsHash + " Available"); } for (int i = 0; i < quorumSignatures.length(); i++) { @@ -269,8 +274,8 @@ else if(!(ipfsGetFlag == tokenCount)){ detailsForVerify.put("signature", senderSignature); boolean yesSender = Authenticate.verifySignature(detailsForVerify.toString()); -// TokenReceiverLogger.debug("Sender auth hash " + hash); -// TokenReceiverLogger.debug("Quorum Auth : " + yesQuorum + "Sender Auth : " + yesSender); + TokenReceiverLogger.debug("Sender auth hash " + hash); + TokenReceiverLogger.debug("Quorum Auth : " + yesQuorum + "Sender Auth : " + yesSender); if (!(yesSender && yesQuorum)) { output.println("420"); APIResponse.put("did", senderDidIpfsHash); @@ -358,7 +363,7 @@ else if(!(ipfsGetFlag == tokenCount)){ APIResponse.put("tokens", tokens); APIResponse.put("comment", comment); APIResponse.put("message", "Transaction Successful"); -// TokenReceiverLogger.info(" Transaction Successful"); + TokenReceiverLogger.info(" Transaction Successful"); executeIPFSCommands(" ipfs p2p close -t /p2p/" + senderPeerID); output.close(); input.close(); From 5834c228c2581c51d87e051fe74b62494b66ca90 Mon Sep 17 00:00:00 2001 From: KiranHRubix Date: Thu, 9 Dec 2021 16:56:02 +0530 Subject: [PATCH 02/49] Updates InitiatorConsensus class --- .../rubix/AuthenticateNode/Authenticate.java | 3 +- .../rubix/Consensus/InitiatorConsensus.java | 123 ++++++++++++++++++ 2 files changed, 125 insertions(+), 1 deletion(-) diff --git a/src/com/rubix/AuthenticateNode/Authenticate.java b/src/com/rubix/AuthenticateNode/Authenticate.java index c26a8b44..74c276e0 100644 --- a/src/com/rubix/AuthenticateNode/Authenticate.java +++ b/src/com/rubix/AuthenticateNode/Authenticate.java @@ -59,7 +59,8 @@ public static boolean verifySignature(String detailString) throws IOException, J positionsLevelZero[k] = ((originalPos[k]) / 8); StringBuilder decentralizedIDForAuth = new StringBuilder(); - for (int value : positionsLevelZero) decentralizedIDForAuth.append(senderDIDBin.charAt(value)); + for (int value : positionsLevelZero) + decentralizedIDForAuth.append(senderDIDBin.charAt(value)); if (recombinedResult.equals(decentralizedIDForAuth.toString())) { AuthenticateLogger.info("Verification True"); return true; diff --git a/src/com/rubix/Consensus/InitiatorConsensus.java b/src/com/rubix/Consensus/InitiatorConsensus.java index 0babc9cc..dcadc1ec 100644 --- a/src/com/rubix/Consensus/InitiatorConsensus.java +++ b/src/com/rubix/Consensus/InitiatorConsensus.java @@ -66,6 +66,8 @@ private static synchronized boolean voteNCount(int i, int quorumSize) { * * @param quorumDID DID of the Quorum * @param quorumSignResponse Signature of the Quorum + * @param hash + * */ private static synchronized void quorumSign(String quorumDID, String hash, String quorumSignResponse, int index, int quorumSize, int alphaSize) { PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); @@ -88,6 +90,30 @@ private static synchronized void quorumSign(String quorumDID, String hash, Strin } } + /** + * This method stores all the quorum signatures until required count for consensus + * + * @param quorumDID DID of the Quorum + * @param quorumSignResponse Signature of the Quorum + */ + + private static synchronized void quorumSign(String quorumDID, String quorumSignResponse, int index, int quorumSize, int alphaSize) { + PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); + synchronized (signLock) { + try { + if (quorumSignature.length() < minQuorum(alphaSize) + 2 * minQuorum(7) && quorumResponse[index] <= minQuorum(quorumSize)) { + quorumSignature.put(quorumDID, quorumSignResponse); + InitiatorConsensusLogger.debug("quorum sign added current length " + quorumSignature.length()); + } else { + InitiatorConsensusLogger.debug("quorum already reached consensus " + quorumSignature.length()); + } + } catch (JSONException e) { + InitiatorConsensusLogger.error("JSON Exception Occurred", (Throwable)e); + e.printStackTrace(); + } + } + } + /** * This method runs the consensus @@ -250,4 +276,101 @@ public static JSONObject start(String data, IPFS ipfs, int PORT, int index, Stri } return quorumSignature; } + + + + public static JSONObject startNft(String data, IPFS ipfs, int PORT, int index, String role, JSONArray quorumPeersObject, int alphaSize, int quorumSize) throws JSONException { + String[] qResponse = new String[QUORUM_COUNT]; + Socket[] qSocket = new Socket[QUORUM_COUNT]; + PrintStream[] qOut = new PrintStream[QUORUM_COUNT]; + BufferedReader[] qIn = new BufferedReader[QUORUM_COUNT]; + String[] quorumID = new String[QUORUM_COUNT]; + PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); + JSONObject dataObject = new JSONObject(data); + String hash = dataObject.getString("hash"); + JSONArray tokenDetails = dataObject.getJSONArray("details"); + quorumResponse[index] = 0; + InitiatorConsensusLogger.debug("quorum peer role " + role + " length " + quorumPeersObject.length()); + try { + JSONObject detailsToken = tokenDetails.getJSONObject(0); + JSONObject sharesToken = tokenDetails.getJSONObject(1); + String[] shares = new String[minQuorum(7) - 1]; + for (int i = 0; i < shares.length; i++) { + int p = i + 1; + shares[i] = sharesToken.getString("Share" + p); + } + for (int j = 0; j < quorumPeersObject.length(); j++) + quorumID[j] = quorumPeersObject.getString(j); + Thread[] quorumThreads = new Thread[quorumPeersObject.length()]; + for (int k = 0; k < quorumPeersObject.length(); k++) { + int j = k; + quorumThreads[k] = new Thread(() -> { + try { + swarmConnectP2P(quorumID[j], ipfs); + String quorumDidIpfsHash = getValues(DATA_PATH + "DataTable.json", "didHash", "peerid", quorumID[j]); + String quorumWidIpfsHash = getValues(DATA_PATH + "DataTable.json", "walletHash", "peerid", quorumID[j]); + nodeData(quorumDidIpfsHash, quorumWidIpfsHash, ipfs); + String appName = quorumID[j].concat(role); + InitiatorConsensusLogger.debug("quourm ID " + quorumID[j] + " appname " + appName); + IPFSNetwork.forward(appName, PORT + j, quorumID[j]); + InitiatorConsensusLogger.debug("Connected to " + quorumID[j] + "on port " + PORT + j + "with AppName" + appName); + qSocket[j] = new Socket("127.0.0.1", PORT + j); + qIn[j] = new BufferedReader(new InputStreamReader(qSocket[j].getInputStream())); + qOut[j] = new PrintStream(qSocket[j].getOutputStream()); + qOut[j].println(detailsToken); + qResponse[j] = qIn[j].readLine(); + if (qResponse[j].equals("Auth_Failed")) { + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + quorumID[j]); + } else { + InitiatorConsensusLogger.debug("Signature Received from " + quorumID[j] + " " + qResponse[j]); + if (quorumResponse[index] > minQuorum(quorumSize)) { + qOut[j].println("null"); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + quorumID[j]); + } else { + String didHash = getValues(DATA_PATH + "DataTable.json", "didHash", "peerid", quorumID[j]); + JSONObject detailsToVerify = new JSONObject(); + detailsToVerify.put("did", didHash); + detailsToVerify.put("hash", hash); + detailsToVerify.put("signature", qResponse[j]); + if (Authenticate.verifySignature(detailsToVerify.toString())) { + InitiatorConsensusLogger.debug(role + " node authenticated at index " + role); + boolean voteStatus = voteNCount(index, quorumSize); + if (quorumResponse[index] <= minQuorum(quorumSize) && voteStatus) { + InitiatorConsensusLogger.debug("waiting for " + quorumSize + " + signs " + role); + while (quorumResponse[index] < minQuorum(quorumSize)); + InitiatorConsensusLogger.debug("between Q1- to Q" + quorumSize + " for index " + index); + quorumSign(didHash, qResponse[j], index, quorumSize, alphaSize); + quorumWithShares.add(quorumPeersObject.getString(j)); + while (quorumSignature.length() < minQuorum(alphaSize) + 2 * minQuorum(7)); + InitiatorConsensusLogger.debug("sending Qsign of length " + quorumSignature.length() + " at index " + index); + qOut[j].println(quorumSignature); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + quorumID[j]); + } else { + InitiatorConsensusLogger.debug("sending null for slow quorum "); + qOut[j].println("null"); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + quorumID[j]); + } + InitiatorConsensusLogger.debug("Quorum Count : " + quorumResponse + " Signature count : " + quorumSignature.length()); + } else { + InitiatorConsensusLogger.debug("node failed authentication with index " + index + " with role " + role + " with did " + didHash + " and data to verify " + detailsToVerify); + InitiatorConsensusLogger.debug("recheck result is " + Authenticate.verifySignature(detailsToVerify.toString())); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + quorumID[j]); + } + } + } + } catch (IOException|JSONException|NullPointerException e) { + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + quorumID[j]); + InitiatorConsensusLogger.error("IOException Occurred", e); + e.printStackTrace(); + } + }); + quorumThreads[j].start(); + } + while (quorumResponse[index] < minQuorum(quorumSize) || quorumSignature.length() < minQuorum(alphaSize) + 2 * minQuorum(7)); + } catch (JSONException e) { + InitiatorConsensusLogger.error("JSON Exception Occurred", (Throwable)e); + e.printStackTrace(); + } + return quorumSignature; + } } From 2d53c120779a5aa6b497ea810278551868dc8fc6 Mon Sep 17 00:00:00 2001 From: KiranHRubix Date: Thu, 9 Dec 2021 17:42:45 +0530 Subject: [PATCH 03/49] Updated InitiatorProcedure class --- .../rubix/Consensus/InitiatorProcedure.java | 97 ++++++++++++++++++- 1 file changed, 96 insertions(+), 1 deletion(-) diff --git a/src/com/rubix/Consensus/InitiatorProcedure.java b/src/com/rubix/Consensus/InitiatorProcedure.java index 5d26d05f..1d9c958b 100644 --- a/src/com/rubix/Consensus/InitiatorProcedure.java +++ b/src/com/rubix/Consensus/InitiatorProcedure.java @@ -16,7 +16,7 @@ public class InitiatorProcedure { public static String essential; - public static String senderSignQ; + public static String senderSignQ,sellerSignQ; public static JSONObject payload = new JSONObject(); public static JSONObject alphaReply, betaReply, gammaReply; @@ -126,4 +126,99 @@ public static void consensusSetUp(String data,IPFS ipfs, int PORT,int alphaSize) while (InitiatorConsensus.quorumSignature.length() < (minQuorum(alphaSize) + 2* minQuorum(7))) {} InitiatorProcedureLogger.debug("ABG Consensus completed with length " +InitiatorConsensus.quorumSignature.length()); } + + + public static void nftConsensusSetUp(String data, IPFS ipfs, int PORT, int alphaSize) throws JSONException { + PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); + JSONObject dataObject = new JSONObject(data); + String tid = dataObject.getString("tid"); + String message = dataObject.getString("message"); + String messageContent = dataObject.getString("messageRbx"); + String hash2Quorum = dataObject.getString("hash2Quorum"); + String buyerDidIpfsHash = dataObject.getString("buyerDidIpfsHash"); + String pvt = dataObject.getString("pvt"); + String sellerDidIpfsHash = dataObject.getString("sellerDidIpfsHash"); + String nftTokenIpfsHash = dataObject.getString("nftToken"); + JSONArray rbxTokens = dataObject.getJSONArray("rbxTokens"); + JSONArray alphaList = dataObject.getJSONArray("alphaList"); + JSONArray betaList = dataObject.getJSONArray("betaList"); + JSONArray gammaList = dataObject.getJSONArray("gammaList"); + String authSellerByQuorumHash = "", authQuorumHash = ""; + authSellerByQuorumHash = hash2Quorum; + authQuorumHash = calculateHash(authSellerByQuorumHash.concat(buyerDidIpfsHash), "SHA3-256"); + InitiatorProcedureLogger.debug("Hash for seller authentication to quorum : " + authSellerByQuorumHash); + InitiatorProcedureLogger.debug("Hash for Quorum Authentication : " + authQuorumHash); + try { + payload.put("seller", sellerDidIpfsHash); + payload.put("nftToken", nftTokenIpfsHash); + payload.put("buyer", buyerDidIpfsHash); + payload.put("rbxTokens", rbxTokens); + payload.put("tid", tid); + } catch (JSONException e) { + InitiatorProcedureLogger.error("JSON Exception occurred", (Throwable)e); + e.printStackTrace(); + } + Split.split(payload.toString()); + int[][] shares = Split.get135Shares(); + InitiatorProcedureLogger.debug("NFT Payload Split Success"); + essential = SeperateShares.getShare(shares, payload.toString().length(), 0); + String Q1Share = SeperateShares.getShare(shares, payload.toString().length(), 1); + String Q2Share = SeperateShares.getShare(shares, payload.toString().length(), 2); + String Q3Share = SeperateShares.getShare(shares, payload.toString().length(), 3); + String Q4Share = SeperateShares.getShare(shares, payload.toString().length(), 4); + JSONObject data1 = new JSONObject(); + JSONObject data2 = new JSONObject(); + try { + sellerSignQ = getSignFromShares(pvt, authSellerByQuorumHash); + data1.put("sign", sellerSignQ); + data1.put("senderDID", sellerDidIpfsHash); + data1.put("Tid", tid); + data1.put("Hash", authSellerByQuorumHash); + data1.put("RID", buyerDidIpfsHash); + data1.put("message", message); + data1.put("rbxMessage", messageContent); + data1.put("type", "nft"); + data2.put("Share1", Q1Share); + data2.put("Share2", Q2Share); + data2.put("Share3", Q3Share); + data2.put("Share4", Q4Share); + } catch (JSONException|java.io.IOException e) { + InitiatorProcedureLogger.error("JSON Exception occurred", e); + e.printStackTrace(); + } + JSONArray detailsForQuorum = new JSONArray(); + detailsForQuorum.put(data1); + detailsForQuorum.put(data2); + InitiatorProcedureLogger.debug("Invoking Consensus"); + JSONObject dataSend = new JSONObject(); + dataSend.put("hash", authQuorumHash); + dataSend.put("details", detailsForQuorum); + Thread alphaThread = new Thread(() -> { + try { + alphaReply = InitiatorConsensus.startNft(dataSend.toString(), ipfs, PORT, 0, "alpha", alphaList, alphaSize, alphaSize); + } catch (JSONException e) { + e.printStackTrace(); + } + }); + Thread betaThread = new Thread(() -> { + try { + betaReply = InitiatorConsensus.startNft(dataSend.toString(), ipfs, PORT + 100, 1, "beta", betaList, alphaSize, 7); + } catch (JSONException e) { + e.printStackTrace(); + } + }); + Thread gammaThread = new Thread(() -> { + try { + gammaReply = InitiatorConsensus.startNft(dataSend.toString(), ipfs, PORT + 107, 2, "gamma", gammaList, alphaSize, 7); + } catch (JSONException e) { + e.printStackTrace(); + } + }); + InitiatorConsensus.quorumSignature = new JSONObject(); + alphaThread.start(); + betaThread.start(); + gammaThread.start(); + while (InitiatorConsensus.quorumSignature.length() < minQuorum(alphaSize) + 2 * minQuorum(7)); + InitiatorProcedureLogger.debug("ABG Consensus completed with length " + InitiatorConsensus.quorumSignature.length()); + } } From 57107927b1a6b09fff287e6fd5f72d8be86e0a22 Mon Sep 17 00:00:00 2001 From: KiranHRubix Date: Fri, 10 Dec 2021 11:44:35 +0530 Subject: [PATCH 04/49] Crerated NFT module - added Buyer , seller class --- src/com/rubix/NFT/Buyer.java | 415 ++++++++++++++++++++++++++++ src/com/rubix/NFT/Seller.java | 499 ++++++++++++++++++++++++++++++++++ 2 files changed, 914 insertions(+) create mode 100644 src/com/rubix/NFT/Buyer.java create mode 100644 src/com/rubix/NFT/Seller.java diff --git a/src/com/rubix/NFT/Buyer.java b/src/com/rubix/NFT/Buyer.java new file mode 100644 index 00000000..64de5405 --- /dev/null +++ b/src/com/rubix/NFT/Buyer.java @@ -0,0 +1,415 @@ +package com.rubix.NFT; + + +import com.rubix.AuthenticateNode.Authenticate; +import com.rubix.Resources.FractionChooser; +import com.rubix.Resources.Functions; +import com.rubix.Resources.IPFSNetwork; +import io.ipfs.api.IPFS; +import java.awt.image.BufferedImage; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileWriter; +import java.io.InputStreamReader; +import java.io.PrintStream; +import java.net.ServerSocket; +import java.net.Socket; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Iterator; +import javax.imageio.ImageIO; +import org.apache.log4j.Logger; +import org.apache.log4j.PropertyConfigurator; +import org.json.JSONArray; +import org.json.JSONObject; + +public class Buyer { + public static Logger BuyerLogger = Logger.getLogger(Buyer.class); + + private static final JSONObject APIResponse = new JSONObject(); + + private static final IPFS ipfs = new IPFS("/ip4/127.0.0.1/tcp/" + Functions.IPFS_PORT); + + public static String receive() { + Functions.pathSet(); + ServerSocket ss = null; + Socket sk = null; + String sellerPeerID = null; + try { + int quorumSignVerifyCount = 0; + JSONObject quorumSignatures = null; + ArrayList quorumDID = new ArrayList<>(); + PropertyConfigurator.configure(Functions.LOGGER_PATH + "log4jWallet.properties"); + String buyerPeerID = Functions.getPeerID(Functions.DATA_PATH + "DID.json"); + String buyerDidIpfsHash = Functions.getValues(Functions.DATA_PATH + "DataTable.json", "didHash", "peerid", buyerPeerID); + IPFSNetwork.listen(buyerPeerID + "NFT", Functions.BUYER_PORT); + ss = new ServerSocket(Functions.BUYER_PORT); + BuyerLogger.debug("Listening on " + Functions.BUYER_PORT + " with app name " + buyerPeerID + "NFT"); + sk = ss.accept(); + BufferedReader input = new BufferedReader(new InputStreamReader(sk.getInputStream())); + PrintStream output = new PrintStream(sk.getOutputStream()); + long startTime = System.currentTimeMillis(); + sellerPeerID = input.readLine(); + BuyerLogger.debug("Seller PeerID received"); + String sellerDidIpfsHash = Functions.getValues(Functions.DATA_PATH + "DataTable.json", "didHash", "peerid", sellerPeerID); + String sellerWidIpfsHash = Functions.getValues(Functions.DATA_PATH + "DataTable.json", "walletHash", "peerid", sellerPeerID); + if (!sellerDidIpfsHash.contains("Qm") || !sellerWidIpfsHash.contains("Qm")) { + output.println("420"); + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Invalid Seller DID."); + BuyerLogger.info("Seller details not available in datatable"); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); + output.close(); + input.close(); + sk.close(); + ss.close(); + return APIResponse.toString(); + } + Functions.nodeData(sellerDidIpfsHash, sellerWidIpfsHash, ipfs); + File sellerDIDFile = new File(Functions.DATA_PATH + sellerDidIpfsHash + "DID.png"); + if (!sellerDIDFile.exists()) { + output.println("420"); + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Seller details not available in network , please sync"); + BuyerLogger.info("Sender details not available"); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); + output.close(); + input.close(); + sk.close(); + ss.close(); + return APIResponse.toString(); + } + output.println("200"); + BuyerLogger.debug("PeerAuth sent to Seller"); + String nftData = input.readLine(); + BuyerLogger.debug("NFT Token details received from Seller"); + JSONObject nftTokenDetails = new JSONObject(nftData); + String nftToken = nftTokenDetails.getString("nftToken"); + String nftTokenChain = nftTokenDetails.getString("nftTokenChain"); + String message = nftTokenDetails.toString(); + String nftID = Functions.calculateHash(message, "SHA3-256"); + Functions.writeToFile(Functions.LOGGER_PATH + "nftID", nftID, Boolean.valueOf(false)); + String nftIdIpfsHash = IPFSNetwork.addHashOnly(Functions.LOGGER_PATH + "nftID", ipfs); + Functions.deleteFile(Functions.LOGGER_PATH + "nftID"); + String nftTokenChainContent = IPFSNetwork.get(nftTokenChain, ipfs); + String nftTokenContent = IPFSNetwork.get(nftToken, ipfs); + BuyerLogger.debug("NFT token content extracted"); + IPFSNetwork.repo(ipfs); + if (!IPFSNetwork.dhtEmpty(nftIdIpfsHash, ipfs)) { + BuyerLogger.debug("NFT ID not unique" + nftIdIpfsHash); + output.println("420"); + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "NFT ID not unique"); + BuyerLogger.info("NFT ID not unique"); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); + output.close(); + input.close(); + sk.close(); + ss.close(); + return APIResponse.toString(); + } + if (nftTokenContent.equals("")) { + output.println("421"); + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Invalid NFT Token"); + BuyerLogger.info("Invalid NFT Token"); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); + output.close(); + input.close(); + sk.close(); + ss.close(); + return APIResponse.toString(); + } + output.println("200"); + BuyerLogger.debug("NftTokenAuth: 200. Sent to Seller"); + String assetData = input.readLine(); + BuyerLogger.debug("Received asset details from Seller"); + JSONObject assetDetails = new JSONObject(assetData); + String eKey = assetDetails.getString("eKey"); + String dKey = assetDetails.getString("dKey"); + int amount = assetDetails.getInt("amount"); + JSONArray rbxTokens = FractionChooser.calculate(amount); + JSONArray rbxTokenHeader = FractionChooser.tokenHeader; + ArrayList rbxTokensChainsPushed = new ArrayList<>(); + if (rbxTokens.length() == 0) { + output.println("420"); + BuyerLogger.debug("Insufficient balance with buyer"); + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Insufficient balance"); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); + output.close(); + input.close(); + sk.close(); + ss.close(); + return APIResponse.toString(); + } + for (int i = 0; i < rbxTokens.length(); i++) { + File rbxtoken = new File(Functions.TOKENS_PATH); + File rbxtokenchain = new File(Functions.TOKENCHAIN_PATH); + BuyerLogger.debug("" + rbxtoken + " and " + rbxtoken); + if (!rbxtoken.exists() || !rbxtokenchain.exists()) { + output.println("421"); + BuyerLogger.info("Tokens Not Verified"); + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Invalid token(s)"); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); + output.close(); + input.close(); + sk.close(); + ss.close(); + return APIResponse.toString(); + } + IPFSNetwork.add(Functions.TOKENS_PATH, ipfs); + String tokenChainHash = IPFSNetwork.add(Functions.TOKENCHAIN_PATH, ipfs); + rbxTokensChainsPushed.add(tokenChainHash); + } + JSONObject rbxTokenDetails = new JSONObject(); + rbxTokenDetails.put("rbxTokens", rbxTokens); + rbxTokenDetails.put("rbxTokenChains", rbxTokensChainsPushed); + rbxTokenDetails.put("rbxTokenHeader", rbxTokenHeader); + String pvt = Functions.DATA_PATH+ buyerDidIpfsHash + "PrivateShare.png"; + String buyerSign = Functions.getSignFromShares(pvt, Functions.calculateHash("" + rbxTokens + rbxTokens + rbxTokensChainsPushed.toString(), "SHA3-256")); + JSONObject rbxData = new JSONObject(); + rbxData.put("rbxTokenDetails", rbxTokenDetails); + rbxData.put("authBuyerBySeller", buyerSign); + output.println(rbxData); + BuyerLogger.debug("Sent rbxData and Buyer sign for authentication to seller."); + String rbxTokensAuth = input.readLine(); + if (rbxTokensAuth.equals("421")) { + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "RBX tokens not verified at seller node"); + BuyerLogger.info("RBX tokens not verified at sender node"); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); + output.close(); + input.close(); + sk.close(); + ss.close(); + return APIResponse.toString(); + } + if (rbxTokensAuth.equals("420")) { + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Consensus ID not Unique"); + BuyerLogger.info("Consensus ID not Unique"); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); + output.close(); + input.close(); + sk.close(); + ss.close(); + return APIResponse.toString(); + } + BuyerLogger.debug("consensus/seller details received from Seller"); + JSONObject consensusDetails = new JSONObject(rbxTokensAuth); + String sellerSignature = consensusDetails.getString("sign"); + String tid = consensusDetails.getString("tid"); + String comment = consensusDetails.getString("comment"); + String Status = consensusDetails.getString("status"); + String QuorumDetails = consensusDetails.getString("quorumsign"); + BuyerLogger.debug("Consensus Status: " + Status); + if (!Status.equals("Consensus Failed")) { + boolean yesQuorum = false; + if (Status.equals("Consensus Reached")) { + BuyerLogger.debug("Quorum Signatures: " + QuorumDetails); + quorumSignatures = new JSONObject(QuorumDetails); + BuyerLogger.debug("Quorum Signatures length : " + quorumSignatures.length()); + Iterator dids = quorumSignatures.keys(); + while (dids.hasNext()) { + String did = dids.next(); + quorumDID.add(did); + } + for (String quorumDidIpfsHash : quorumDID) { + String quorumWidIpfsHash = Functions.getValues(Functions.DATA_PATH + "DataTable.json", "walletHash", "didHash", quorumDidIpfsHash); + File quorumDataFolder = new File(Functions.DATA_PATH + "/"); + if (!quorumDataFolder.exists()) { + quorumDataFolder.mkdirs(); + IPFSNetwork.getImage(quorumDidIpfsHash, ipfs, Functions.DATA_PATH + quorumDidIpfsHash + "DID.png"); + IPFSNetwork.getImage(quorumWidIpfsHash, ipfs, Functions.DATA_PATH + quorumDidIpfsHash + "PublicShare.png"); + BuyerLogger.debug("Quorum Data " + quorumDidIpfsHash + " Added"); + continue; + } + BuyerLogger.debug("Quorum Data " + quorumDidIpfsHash + " Available"); + } + for (int j = 0; j < quorumSignatures.length(); j++) { + JSONObject jSONObject = new JSONObject(); + jSONObject.put("did", quorumDID.get(j)); + jSONObject.put("signature", quorumSignatures.getString(quorumDID.get(j))); + boolean val = Authenticate.verifySignature(jSONObject.toString()); + if (val) + quorumSignVerifyCount++; + } + BuyerLogger.debug("Verified Quorum Count " + quorumSignVerifyCount); + yesQuorum = (quorumSignVerifyCount >= quorumSignatures.length()); + } + String hash = Functions.calculateHash(nftToken + nftToken + nftTokenChain + amount + eKey + dKey + buyerDidIpfsHash, "SHA3-256"); + JSONObject detailsForVerify = new JSONObject(); + detailsForVerify.put("did", sellerDidIpfsHash); + detailsForVerify.put("hash", hash); + detailsForVerify.put("signature", sellerSignature); + boolean yesSender = Authenticate.verifySignature(detailsForVerify.toString()); + BuyerLogger.debug("Seller Auth Hash" + hash); + BuyerLogger.debug("Quorum Auth : " + yesQuorum + "Seller Auth : " + yesSender); + if (!yesSender || !yesQuorum) { + output.println("420"); + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", tid); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Seller/Quorum not verified"); + BuyerLogger.info("Seller/Quorum not verified"); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); + output.close(); + input.close(); + sk.close(); + ss.close(); + return APIResponse.toString(); + } + IPFSNetwork.repo(ipfs); + BuyerLogger.debug("Seller and Quorum Verified"); + output.println("200"); + String nftUnpinStatus = input.readLine(); + if (nftUnpinStatus.equals("Unpinned NFT")) { + FileWriter fileWriter = new FileWriter(Functions.NFT_TOKENS_PATH ); + fileWriter.write(nftTokenContent); + fileWriter.close(); + IPFSNetwork.add(Functions.NFT_TOKENS_PATH , ipfs); + IPFSNetwork.pin(nftToken, ipfs); + + try { + BuyerLogger.debug("Successfully Pinned NFT Token"); + for (int j = 0; j < rbxTokens.length(); j++) + IPFSNetwork.unpin(String.valueOf(rbxTokens.get(j)), ipfs); + IPFSNetwork.repo(ipfs); + BuyerLogger.debug("Unpinned RBX Tokens"); + output.println("Unpinned RBX"); + String rbxPinData = input.readLine(); + JSONObject rbxPinDetails = new JSONObject(rbxPinData); + String status = rbxPinDetails.getString("status"); + if (status.equals("Failed to pin RBX")) { + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Seller Failed to pin RBX Tokens"); + BuyerLogger.info(" Transaction failed"); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); + output.close(); + input.close(); + sk.close(); + ss.close(); + return APIResponse.toString(); + } + String essentialShare = rbxPinDetails.getString("essentialShare"); + long endTime = System.currentTimeMillis(); + JSONArray currentNftTokenChain = new JSONArray(nftTokenChainContent); + JSONObject newRecord = new JSONObject(); + newRecord.put("sellerDID", sellerDidIpfsHash); + newRecord.put("sellerSign", sellerSignature); + newRecord.put("comment", comment); + newRecord.put("tid", tid); + currentNftTokenChain.put(newRecord); + Functions.writeToFile(Functions.NFT_TOKENCHAIN_PATH, currentNftTokenChain.toString(), Boolean.valueOf(false)); + Iterator keys = quorumSignatures.keys(); + JSONArray quorumList = new JSONArray(); + while (keys.hasNext()) + quorumList.put(keys.next()); + JSONObject nftTransactionRecord = new JSONObject(); + nftTransactionRecord.put("role", "Buyer"); + nftTransactionRecord.put("sellerDID", sellerDidIpfsHash); + nftTransactionRecord.put("buyerDID", buyerDidIpfsHash); + nftTransactionRecord.put("amount", amount); + nftTransactionRecord.put("rbxTokens", rbxTokens); + nftTransactionRecord.put("nftToken", nftToken); + nftTransactionRecord.put("eKey", eKey); + nftTransactionRecord.put("dKey", dKey); + nftTransactionRecord.put("txn", tid); + nftTransactionRecord.put("quorumList", quorumList); + nftTransactionRecord.put("Date", Functions.getCurrentUtcTime()); + nftTransactionRecord.put("totalTime", endTime - startTime); + nftTransactionRecord.put("comment", comment); + nftTransactionRecord.put("essentialShare", essentialShare); + JSONArray nftTransactionHistoryEntry = new JSONArray(); + nftTransactionHistoryEntry.put(nftTransactionRecord); + Functions.updateJSON("add", Functions.WALLET_DATA_PATH + "nftTransactionHistory.json", nftTransactionHistoryEntry.toString()); + int k; + for (k = 0; k < rbxTokens.length(); k++) + Files.deleteIfExists(Paths.get(Functions.TOKENS_PATH, new String[0])); + for (k = 0; k < amount; k++) + Functions.updateJSON("remove", Functions.PAYMENTS_PATH, rbxTokens.getString(k)); + BuyerLogger.info("Transaction ID: " + tid + "Transaction Successful"); + output.println("Send Response"); + APIResponse.put("sellerDID", sellerDidIpfsHash); + APIResponse.put("buyerDID", buyerDidIpfsHash); + APIResponse.put("tid", tid); + APIResponse.put("status", "Success"); + APIResponse.put("tokens", nftToken); + APIResponse.put("comment", comment); + APIResponse.put("message", "NFT Transaction Successful"); + BuyerLogger.info("Transaction Successful"); + } catch (Exception e) { + output.println("Failed pinning on Buyer Node"); + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Failed in pinning NFT token"); + BuyerLogger.info(" Transaction failed", e); + } + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); + output.close(); + input.close(); + sk.close(); + ss.close(); + return APIResponse.toString(); + } + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Seller Failed to unpin"); + BuyerLogger.info(" Transaction failed"); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); + output.close(); + input.close(); + sk.close(); + ss.close(); + return APIResponse.toString(); + } + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Consensus failed at Sender side"); + BuyerLogger.info(" Transaction failed"); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); + output.close(); + input.close(); + sk.close(); + ss.close(); + return APIResponse.toString(); + } catch (Exception e) { + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); + BuyerLogger.error("Exception Occurred", e); + return APIResponse.toString(); + } finally { + try { + ss.close(); + sk.close(); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); + } catch (Exception e) { + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); + BuyerLogger.error("Exception Occurred", e); + } + } + } +} diff --git a/src/com/rubix/NFT/Seller.java b/src/com/rubix/NFT/Seller.java new file mode 100644 index 00000000..b0219a2f --- /dev/null +++ b/src/com/rubix/NFT/Seller.java @@ -0,0 +1,499 @@ +package com.rubix.NFT; + +import com.rubix.AuthenticateNode.PropImage; +import com.rubix.Consensus.InitiatorConsensus; +import com.rubix.Consensus.InitiatorProcedure; +import com.rubix.Resources.Functions; +import com.rubix.Resources.IPFSNetwork; +import io.ipfs.api.IPFS; +import java.awt.image.BufferedImage; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileWriter; +import java.io.InputStreamReader; +import java.io.PrintStream; +import java.net.Socket; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Iterator; +import javax.imageio.ImageIO; +import org.apache.log4j.Logger; +import org.apache.log4j.PropertyConfigurator; +import org.json.JSONArray; +import org.json.JSONObject; + +public class Seller { + private static final Logger SellerLogger = Logger.getLogger(Seller.class); + + private static final String USER_AGENT = "Mozilla/5.0"; + + public static BufferedReader serverInput; + + private static PrintStream output; + + private static BufferedReader input; + + private static Socket sellerSocket; + + private static boolean sellerMutex = false; + + public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception { + JSONArray quorumArray; + JSONObject APIResponse = new JSONObject(); + PropertyConfigurator.configure(Functions.LOGGER_PATH + "log4jWallet.properties"); + JSONObject detailsObject = new JSONObject(data); + String buyerDidIpfsHash = detailsObject.getString("buyerDidIpfsHash"); + String pvt = detailsObject.getString("pvt"); + int amount = detailsObject.getInt("amount"); + int type = detailsObject.getInt("type"); + String comment = detailsObject.getString("comment"); + String eKey = detailsObject.getString("eKey"); + String dKey = detailsObject.getString("dKey"); + String nftTokenIpfsHash = detailsObject.getString("nftToken"); + JSONArray alphaQuorum = new JSONArray(); + JSONArray betaQuorum = new JSONArray(); + JSONArray gammaQuorum = new JSONArray(); + String sellerPeerId = Functions.getPeerID(Functions.DATA_PATH + "DID.json"); + SellerLogger.debug("Seller Peer ID : " + sellerPeerId); + String sellerDidIpfsHash = Functions.getValues(Functions.DATA_PATH + "DataTable.json", "didHash", "peerid", sellerPeerId); + SellerLogger.debug("Seller DID IPFS Hash : " + sellerDidIpfsHash); + SellerLogger.debug("Path is : " + Functions.DATA_PATH + sellerDidIpfsHash); + File folder = new File(Functions.DATA_PATH); + File[] listOfFiles = folder.listFiles(); + for (int i = 0; i < listOfFiles.length; i++) { + if (listOfFiles[i].isFile()) { + System.out.println("File " + listOfFiles[i].getName()); + } else if (listOfFiles[i].isDirectory()) { + System.out.println("Directory " + listOfFiles[i].getName()); + } + } + BufferedImage senderWidImage = ImageIO.read(new File(Functions.DATA_PATH + sellerDidIpfsHash + "/PublicShare.png")); + String senderWidBin = PropImage.img2bin(senderWidImage); + if (sellerMutex) { + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Sender busy. Try again later"); + SellerLogger.warn("Sender busy"); + return APIResponse; + } + sellerMutex = true; + String nftTokenChainIpfsHash = null; + APIResponse = new JSONObject(); + File nfttoken = new File(Functions.NFT_TOKENS_PATH ); + File nfttokenchain = new File(Functions.NFT_TOKENCHAIN_PATH ); + SellerLogger.debug("NFT Token : " + nfttoken + " and NFT TokenChain : " + nfttokenchain); + if (!nfttoken.exists() || !nfttokenchain.exists() ) { + SellerLogger.info("NFT Token Not Verified"); + sellerMutex = false; + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Invalid NFT token"); + return APIResponse; + } + IPFSNetwork.add(Functions.NFT_TOKENS_PATH + Functions.NFT_TOKENS_PATH, ipfs); + nftTokenChainIpfsHash = IPFSNetwork.add(Functions.NFT_TOKENCHAIN_PATH + Functions.NFT_TOKENCHAIN_PATH + ".json", ipfs); + String authSellerByBuyerHash = Functions.calculateHash(nftTokenIpfsHash + nftTokenIpfsHash + nftTokenChainIpfsHash+ amount + eKey + dKey + buyerDidIpfsHash, "SHA3-256"); + String tid = Functions.calculateHash(authSellerByBuyerHash, "SHA3-256"); + SellerLogger.debug("Hash for Seller authentication to Buyer : " + authSellerByBuyerHash); + SellerLogger.debug("TID on seller " + tid); + Functions.writeToFile(Functions.LOGGER_PATH + "tempbeta", tid.concat(sellerDidIpfsHash), Boolean.valueOf(false)); + String betaHash = IPFSNetwork.add(Functions.LOGGER_PATH + "tempbeta", ipfs); + Functions.deleteFile(Functions.LOGGER_PATH + "tempbeta"); + Functions.writeToFile(Functions.LOGGER_PATH + "tempgamma", tid.concat(buyerDidIpfsHash), Boolean.valueOf(false)); + String gammaHash = IPFSNetwork.add(Functions.LOGGER_PATH + "tempgamma", ipfs); + Functions.deleteFile(Functions.LOGGER_PATH + "tempgamma"); + switch (type) { + case 1: + quorumArray = Functions.getQuorum(betaHash, gammaHash, sellerDidIpfsHash, buyerDidIpfsHash, amount); + break; + case 2: + quorumArray = new JSONArray(Functions.readFile(Functions.DATA_PATH + "quorumlist.json")); + break; + case 3: + quorumArray = detailsObject.getJSONArray("quorum"); + break; + default: + SellerLogger.error("Unknown quorum type input, cancelling transaction"); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Unknown quorum type input, cancelling transaction"); + return APIResponse; + } + Functions.QuorumSwarmConnect(quorumArray, ipfs); + int alphaSize = quorumArray.length() - 14; + int j; + for (j = 0; j < alphaSize; j++) + alphaQuorum.put(quorumArray.getString(j)); + for (j = 0; j < 7; j++) { + betaQuorum.put(quorumArray.getString(alphaSize + j)); + gammaQuorum.put(quorumArray.getString(alphaSize + 7 + j)); + } + SellerLogger.debug("alphaquorum " + alphaQuorum + " size " + alphaQuorum.length()); + SellerLogger.debug("betaquorum " + betaQuorum + " size " + betaQuorum.length()); + SellerLogger.debug("gammaquorum " + gammaQuorum + " size " + gammaQuorum.length()); + ArrayList alphaPeersList = Functions.QuorumCheck(alphaQuorum, ipfs, alphaSize); + ArrayList betaPeersList = Functions.QuorumCheck(betaQuorum, ipfs, 7); + ArrayList gammaPeersList = Functions.QuorumCheck(gammaQuorum, ipfs, 7); + SellerLogger.debug("alphaPeersList size " + alphaPeersList.size()); + SellerLogger.debug("betaPeersList size " + betaPeersList.size()); + SellerLogger.debug("gammaPeersList size " + gammaPeersList.size()); + SellerLogger.debug("minQuorumAlpha size " + Functions.minQuorum(alphaSize)); + if (alphaPeersList.size() < Functions.minQuorum(alphaSize) || betaPeersList.size() < 5 || gammaPeersList.size() < 5) { + Functions.updateQuorum(quorumArray, null, false, type); + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Quorum Members not available"); + SellerLogger.warn("Quorum Members not available"); + sellerMutex = false; + return APIResponse; + } + String sellerSign = Functions.getSignFromShares(pvt, authSellerByBuyerHash); + JSONObject sellerDetails2Buyer = new JSONObject(); + sellerDetails2Buyer.put("sign", sellerSign); + sellerDetails2Buyer.put("tid", tid); + sellerDetails2Buyer.put("comment", comment); + JSONObject nftTokenDetails = new JSONObject(); + nftTokenDetails.put("nftToken", nftTokenIpfsHash); + nftTokenDetails.put("nftTokenChain", nftTokenChainIpfsHash); + String message = nftTokenDetails.toString(); + String nftID = Functions.calculateHash(message, "SHA3-256"); + Functions.writeToFile(Functions.LOGGER_PATH + "nftID", nftID, Boolean.valueOf(false)); + String nftIdIpfsHash = IPFSNetwork.addHashOnly(Functions.LOGGER_PATH + "nftID", ipfs); + Functions.deleteFile(Functions.LOGGER_PATH + "nftID"); + SellerLogger.debug("nftID hash " + nftIdIpfsHash + " unique owner " + IPFSNetwork.dhtEmpty(nftIdIpfsHash, ipfs)); + JSONObject assetDetails = new JSONObject(); + assetDetails.put("eKey", eKey); + assetDetails.put("dKey", dKey); + assetDetails.put("amount", amount); + String buyerPeerId = Functions.getValues(Functions.DATA_PATH + "DataTable.json", "peerid", "didHash", buyerDidIpfsHash); + SellerLogger.debug("Swarm connecting to " + buyerPeerId); + IPFSNetwork.swarmConnect(buyerPeerId, ipfs); + SellerLogger.debug("Swarm connected"); + String buyerWidIpfsHash = Functions.getValues(Functions.DATA_PATH + "DataTable.json", "walletHash", "didHash", buyerDidIpfsHash); + Functions.nodeData(buyerDidIpfsHash, buyerWidIpfsHash, ipfs); + IPFSNetwork.forward(buyerPeerId + "NFT", port, buyerPeerId); + SellerLogger.debug("Forwarded to " + buyerPeerId + " on " + port); + sellerSocket = new Socket("127.0.0.1", port); + input = new BufferedReader(new InputStreamReader(sellerSocket.getInputStream())); + output = new PrintStream(sellerSocket.getOutputStream()); + long startTime = System.currentTimeMillis(); + output.println(sellerPeerId); + SellerLogger.debug("PeerID sent to Buyer"); + String peerAuth = input.readLine(); + SellerLogger.debug("PeerAuth received from Buyer. Code: " + peerAuth); + if (!peerAuth.equals("200")) { + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); + SellerLogger.info("Seller data not available in the network"); + output.close(); + input.close(); + sellerSocket.close(); + sellerMutex = false; + Functions.updateQuorum(quorumArray, null, false, type); + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", tid); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Seller data not available in the network"); + return APIResponse; + } + output.println(nftTokenDetails); + SellerLogger.debug("NFT Token details sent to Buyer"); + String nftTokenAuth = input.readLine(); + SellerLogger.debug("nftTokenAuth received from Buyer. Code: " + nftTokenAuth); + if (!nftTokenAuth.equals("200")) { + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); + output.close(); + input.close(); + sellerSocket.close(); + sellerMutex = false; + if (nftTokenAuth.equals("421")) { + SellerLogger.info("Invalid NFT Token"); + APIResponse.put("message", "Invalid NFT Token"); + } else { + SellerLogger.info("NFT ID not unique"); + APIResponse.put("message", "NFT ID not unique"); + } + Functions.updateQuorum(quorumArray, null, false, type); + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", tid); + APIResponse.put("status", "Failed"); + return APIResponse; + } + output.println(assetDetails); + SellerLogger.debug("Sent asset details to Buyer"); + String rbxTokenAuth = input.readLine(); + SellerLogger.debug("Received rbxTokenAuth from Buyer"); + if (rbxTokenAuth.equals("421")) { + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); + output.close(); + input.close(); + sellerSocket.close(); + sellerMutex = false; + SellerLogger.info("Invalid RBX tokens at buyer end"); + APIResponse.put("message", "Invalid RBX tokens at buyer end"); + Functions.updateQuorum(quorumArray, null, false, type); + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", tid); + APIResponse.put("status", "Failed"); + return APIResponse; + } + if (rbxTokenAuth.equals("420")) { + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); + output.close(); + input.close(); + sellerSocket.close(); + sellerMutex = false; + SellerLogger.info("Insufficient RBX tokens at buyer end"); + APIResponse.put("message", "Insufficient RBX tokens at buyer end"); + Functions.updateQuorum(quorumArray, null, false, type); + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", tid); + APIResponse.put("status", "Failed"); + return APIResponse; + } + JSONObject rbxData = new JSONObject(rbxTokenAuth); + String buyerSign = rbxData.getString("authBuyerBySeller"); + JSONObject rbxTokenDetails = rbxData.getJSONObject("rbxTokenDetails"); + JSONArray rbxTokens = rbxTokenDetails.getJSONArray("rbxTokens"); + JSONArray rbxTokenChains = rbxTokenDetails.getJSONArray("rbxTokenChains"); + JSONArray rbxTokenHeader = rbxTokenDetails.getJSONArray("rbxTokenHeader"); + String messageContent = rbxTokenDetails.toString(); + String consensusID = Functions.calculateHash(messageContent, "SHA3-256"); + Functions.writeToFile(Functions.LOGGER_PATH + "consensusID", consensusID, Boolean.valueOf(false)); + String consensusIdIpfsHash = IPFSNetwork.addHashOnly(Functions.LOGGER_PATH + "consensusID", ipfs); + Functions.deleteFile(Functions.LOGGER_PATH + "consensusID"); + int ipfsGetFlag = 0; + ArrayList allRbxTokenContent = new ArrayList<>(); + ArrayList allRbxTokenChainContent = new ArrayList<>(); + for (int k = 0; k < amount; k++) { + String TokenChainContent = IPFSNetwork.get(rbxTokenChains.getString(k), ipfs); + allRbxTokenChainContent.add(TokenChainContent); + String TokenContent = IPFSNetwork.get(rbxTokens.getString(k), ipfs); + allRbxTokenContent.add(TokenContent); + ipfsGetFlag++; + } + IPFSNetwork.repo(ipfs); + if (!IPFSNetwork.dhtEmpty(consensusIdIpfsHash, ipfs)) { + SellerLogger.debug("consensus ID not unique" + consensusIdIpfsHash); + output.println("420"); + APIResponse.put("did", buyerDidIpfsHash); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Consensus ID not unique"); + SellerLogger.info("Consensus ID not unique"); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); + output.close(); + input.close(); + sellerSocket.close(); + return APIResponse; + } + if (ipfsGetFlag != amount) { + output.println("421"); + APIResponse.put("did", buyerDidIpfsHash); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Tokens not verified"); + SellerLogger.info("Tokens not verified"); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); + output.close(); + input.close(); + sellerSocket.close(); + return APIResponse; + } + JSONObject dataObject = new JSONObject(); + dataObject.put("tid", tid); + dataObject.put("message", message); + dataObject.put("messageRbx", messageContent); + dataObject.put("buyerDidIpfsHash", buyerDidIpfsHash); + dataObject.put("pvt", pvt); + dataObject.put("sellerDidIpfsHash", sellerDidIpfsHash); + dataObject.put("nftToken", nftTokenIpfsHash); + dataObject.put("rbxTokens", rbxTokens); + dataObject.put("alphaList", alphaPeersList); + dataObject.put("betaList", betaPeersList); + dataObject.put("gammaList", gammaPeersList); + SellerLogger.debug("dataobject " + dataObject.toString()); + SellerLogger.debug("nftConsensus Setup Begins"); + InitiatorProcedure.nftConsensusSetUp(dataObject.toString(), ipfs, Functions.SELLER_PORT + 225, alphaSize); + SellerLogger.debug("nftConsensus Done"); + SellerLogger.debug("length on seller " + InitiatorConsensus.quorumSignature.length() + " response count " + InitiatorConsensus.quorumResponse); + if (InitiatorConsensus.quorumSignature.length() < Functions.minQuorum(alphaSize) + 2 * Functions.minQuorum(7)) { + SellerLogger.debug("Consensus Failed"); + sellerDetails2Buyer.put("status", "Consensus Failed"); + sellerDetails2Buyer.put("quorumsign", InitiatorConsensus.quorumSignature.toString()); + output.println(sellerDetails2Buyer); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); + output.close(); + input.close(); + sellerSocket.close(); + sellerMutex = false; + Functions.updateQuorum(quorumArray, null, false, type); + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", tid); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Transaction declined by Quorum"); + return APIResponse; + } + SellerLogger.debug("Consensus Reached"); + sellerDetails2Buyer.put("status", "Consensus Reached"); + sellerDetails2Buyer.put("quorumsign", InitiatorConsensus.quorumSignature.toString()); + output.println(sellerDetails2Buyer); + SellerLogger.debug("Sent Seller/Consensus Details to Buyer"); + SellerLogger.debug("Quorum Signatures length " + InitiatorConsensus.quorumSignature.length()); + String signatureAuth = input.readLine(); + long endAuth = System.currentTimeMillis(); + long totalTime = endAuth - startTime; + if (!signatureAuth.equals("200")) { + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); + SellerLogger.info("Authentication Failed"); + output.close(); + input.close(); + sellerSocket.close(); + sellerMutex = false; + Functions.updateQuorum(quorumArray, null, false, type); + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", tid); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Quorum/Seller not authenticated"); + return APIResponse; + } + IPFSNetwork.unpin(nftTokenIpfsHash, ipfs); + IPFSNetwork.repo(ipfs); + SellerLogger.debug("Unpinned NFT Token"); + output.println("Unpinned NFT"); + String rbxUnpinStatus = input.readLine(); + if (!rbxUnpinStatus.equals("Unpinned RBX")) { + SellerLogger.warn("Buyer failed to pin NFT Token"); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); + SellerLogger.info("Buyer failed to pin NFT Token"); + output.close(); + input.close(); + sellerSocket.close(); + sellerMutex = false; + Functions.updateQuorum(quorumArray, null, false, type); + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", tid); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Buyer failed to pin NFT Token"); + return APIResponse; + } + int count = 0; + int m; + for (m = 0; m < amount; m++) { + FileWriter fileWriter = new FileWriter(Functions.TOKENS_PATH + Functions.TOKENS_PATH); + fileWriter.write(allRbxTokenContent.get(m)); + fileWriter.close(); + IPFSNetwork.add(Functions.TOKENS_PATH + Functions.TOKENS_PATH, ipfs); + IPFSNetwork.pin(rbxTokens.getString(m), ipfs); + count++; + } + if (count == amount) { + SellerLogger.debug("Pinned All RBX Tokens"); + for (m = 0; m < amount; m++) { + ArrayList groupTokens = new ArrayList<>(); + for (int i1 = 0; i1 < amount; i1++) { + if (!rbxTokens.getString(m).equals(rbxTokens.getString(i1))) + groupTokens.add(rbxTokens.getString(i1)); + } + JSONArray arrToken = new JSONArray(); + JSONObject objectToken = new JSONObject(); + objectToken.put("tokenHash", rbxTokens.getString(m)); + arrToken.put(objectToken); + JSONArray arr1 = new JSONArray(allRbxTokenChainContent.get(m)); + JSONObject obj2 = new JSONObject(); + obj2.put("buyerSign", buyerSign); + obj2.put("buyerDID", buyerDidIpfsHash); + obj2.put("group", groupTokens); + obj2.put("comment", comment); + obj2.put("tid", tid); + arr1.put(obj2); + Functions.writeToFile(Functions.TOKENCHAIN_PATH + Functions.TOKENCHAIN_PATH + ".json", arr1.toString(), Boolean.valueOf(false)); + } + JSONObject rbxPinData = new JSONObject(); + rbxPinData.put("status", "Pinned RBX"); + rbxPinData.put("essentialShare", InitiatorProcedure.essential); + output.println(rbxPinData.toString()); + } else { + JSONObject rbxPinData = new JSONObject(); + rbxPinData.put("status", "Failed to pin RBX"); + rbxPinData.put("essentialShare", "null"); + output.println(rbxPinData.toString()); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); + output.close(); + input.close(); + sellerSocket.close(); + sellerMutex = false; + Functions.updateQuorum(quorumArray, null, false, type); + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", tid); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Seller Failed to pin RBX"); + SellerLogger.info("Incomplete Transaction"); + return APIResponse; + } + String respAuth = input.readLine(); + if (!respAuth.equals("Send Response")) { + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); + output.close(); + input.close(); + sellerSocket.close(); + sellerMutex = false; + Functions.updateQuorum(quorumArray, null, false, type); + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", tid); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Receiver process not over"); + SellerLogger.info("Incomplete Transaction"); + return APIResponse; + } + Iterator keys = InitiatorConsensus.quorumSignature.keys(); + JSONArray signedQuorumList = new JSONArray(); + while (keys.hasNext()) + signedQuorumList.put(keys.next()); + APIResponse.put("tid", tid); + APIResponse.put("status", "Success"); + APIResponse.put("sellerDID", sellerDidIpfsHash); + APIResponse.put("message", "NFT transferred successfully!"); + APIResponse.put("quorumlist", signedQuorumList); + APIResponse.put("buyerDID", buyerDidIpfsHash); + APIResponse.put("totaltime", totalTime); + Functions.updateQuorum(quorumArray, signedQuorumList, true, type); + JSONObject nftTransactionRecord = new JSONObject(); + nftTransactionRecord.put("role", "Seller"); + nftTransactionRecord.put("sellerDID", sellerDidIpfsHash); + nftTransactionRecord.put("buyerDID", buyerDidIpfsHash); + nftTransactionRecord.put("amount", amount); + nftTransactionRecord.put("rbxTokens", rbxTokens); + nftTransactionRecord.put("nftToken", nftTokenIpfsHash); + nftTransactionRecord.put("eKey", eKey); + nftTransactionRecord.put("dKey", dKey); + nftTransactionRecord.put("txn", tid); + nftTransactionRecord.put("quorumList", signedQuorumList); + nftTransactionRecord.put("Date", Functions.getCurrentUtcTime()); + nftTransactionRecord.put("totalTime", totalTime); + nftTransactionRecord.put("comment", comment); + nftTransactionRecord.put("essentialShare", InitiatorProcedure.essential); + JSONArray nftTransactionHistoryEntry = new JSONArray(); + nftTransactionHistoryEntry.put(nftTransactionRecord); + Functions.updateJSON("add", Functions.WALLET_DATA_PATH + "nftTransactionHistory.json", nftTransactionHistoryEntry.toString()); + Files.deleteIfExists(Paths.get(Functions.NFT_TOKENS_PATH + Functions.NFT_TOKENS_PATH, new String[0])); + for (int n = 0; n < rbxTokens.length(); n++) { + String bank = rbxTokenHeader.getString(n); + String bankFile = Functions.readFile(Functions.PAYMENTS_PATH + Functions.PAYMENTS_PATH + ".json"); + JSONArray bankArray = new JSONArray(bankFile); + JSONObject tokenObject = new JSONObject(); + tokenObject.put("tokenHash", rbxTokens.getString(n)); + bankArray.put(tokenObject); + Functions.writeToFile(Functions.PAYMENTS_PATH + "TokenMap.json", bankArray.toString(), Boolean.valueOf(false)); + } + SellerLogger.info("Transaction Successful"); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); + output.close(); + input.close(); + sellerSocket.close(); + sellerMutex = false; + return APIResponse; + } +} From aa0676b27c8b31f5400467b577f4c1f72194582b Mon Sep 17 00:00:00 2001 From: KiranHRubix Date: Fri, 10 Dec 2021 12:15:10 +0530 Subject: [PATCH 05/49] Updated APIHandler class --- src/com/rubix/Resources/APIHandler.java | 285 ++++++++++++++++++++++++ 1 file changed, 285 insertions(+) diff --git a/src/com/rubix/Resources/APIHandler.java b/src/com/rubix/Resources/APIHandler.java index 6563a971..46a04ebf 100644 --- a/src/com/rubix/Resources/APIHandler.java +++ b/src/com/rubix/Resources/APIHandler.java @@ -18,6 +18,7 @@ import static com.rubix.Resources.Functions.*; import static com.rubix.Resources.IPFSNetwork.executeIPFSCommands; +import static com.rubix.NFT.Seller.*; public class APIHandler { private static final Logger APILogger = Logger.getLogger(APIHandler.class); @@ -97,6 +98,46 @@ public static JSONObject send(String data) throws Exception { } + /** + * Initiates a nft transfer between two nodes + * @param data Data specific to token transfer + * @return Message from the sender with transaction details + * @throws JSONException handles JSON Exceptions + * @throws NoSuchAlgorithmException handles Invalid Algorithms Exceptions + * @throws IOException handles IO Exceptions + */ + + public static JSONObject sendNft(String data) throws Exception { + Functions.pathSet(); + PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); + networkInfo(); + String sellerPeerID = Functions.getPeerID(DATA_PATH + "DID.json"); + String sellerDID = Functions.getValues(DATA_PATH + "DID.json", "didHash", "peerid", sellerPeerID); + JSONObject dataObject = new JSONObject(data); + String buyerDID = dataObject.getString("buyerDidIpfsHash"); + String nftTokenIpfsHash = dataObject.getString("nftToken"); + JSONObject sendMessage = new JSONObject(); + if (buyerDID.length() != 46) { + sendMessage.put("did", sellerDID); + sendMessage.put("tid", "null"); + sendMessage.put("status", "Failed"); + sendMessage.put("message", "Invalid Receiver Did Entered"); + return sendMessage; + } + if (nftTokenIpfsHash.length() != 46) { + sendMessage.put("did", sellerDID); + sendMessage.put("tid", "null"); + sendMessage.put("status", "Failed"); + sendMessage.put("message", "Invalid NFT Token Entered"); + return sendMessage; + } + dataObject.put("pvt", Functions.DATA_PATH + sellerDID + "/PrivateShare.png"); + sendMessage = Send(dataObject.toString(), ipfs, Functions.SELLER_PORT); + APILogger.info(sendMessage); + return sendMessage; + } + + public static JSONObject create(int type) throws Exception { Functions.pathSet(); PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); @@ -155,6 +196,29 @@ public static JSONArray transactionDetails(String txnId) throws JSONException { return resultArray; } + /** + * A call to get details of a nft transaction given its ID + * @param txnId + * @return Transaction Details + * @throws JSONException handles JSON Exceptions + */ + public static JSONObject nftTransactionDetails(String txnId) throws JSONException { + String nftTansactionHistory = readFile(WALLET_DATA_PATH + "nftTransactionHistory.json"); + JSONObject obj = new JSONObject(); + if (nftTansactionHistory.length() == 0) { + obj.put("Message", "No transactions found"); + return obj; + } + JSONArray nftTransArray = new JSONArray(nftTansactionHistory); + for (int i = 0; i < nftTransArray.length(); i++) { + obj = nftTransArray.getJSONObject(i); + if (obj.get("txn").equals(txnId)) + break; + } + APILogger.info("NFT Transaction Details for : " + obj.toString()); + return obj; + } + /** * A call to get the account information * @return Detailed explanation of the account information of the user @@ -197,6 +261,46 @@ public static JSONArray accountInformation() throws JSONException { return resultArray; } + /** + * A call to get the account information on nft + * @return Detailed explanation of the account information of the user + * @throws JSONException handles JSON Exceptions + */ + + public static JSONArray nftInformation() throws JSONException { + int txnAsSeller = 0, txnAsBuyer = 0; + JSONArray resultArray = new JSONArray(); + JSONObject accountDetails = new JSONObject(); + File fileCheck1 = new File(WALLET_DATA_PATH + "nftTransactionHistory.json"); + if (!fileCheck1.exists()) { + accountDetails.put("message", "NFT Transaction History file not found"); + resultArray.put(accountDetails); + return resultArray; + } + String nftTransactionHistory = readFile(WALLET_DATA_PATH + "nftTransactionHistory.json"); + JSONArray nftTransArray = new JSONArray(nftTransactionHistory); + if (nftTransArray.length() != 0) + for (int i = 0; i < nftTransArray.length(); i++) { + JSONObject objectParser = nftTransArray.getJSONObject(i); + if (objectParser.get("role").equals("Seller")) { + txnAsSeller++; + } else { + txnAsBuyer++; + } + } + String sellerPeerID = getPeerID(DATA_PATH + "DID.json"); + String did = getValues(DATA_PATH + "DID.json", "didHash", "peerid", sellerPeerID); + String wid = getValues(DATA_PATH + "DID.json", "walletHash", "peerid", sellerPeerID); + accountDetails.put("did", did); + accountDetails.put("wid", wid); + accountDetails.put("sellerTxn", txnAsSeller); + accountDetails.put("buyerTxn", txnAsBuyer); + accountDetails.put("totalNftTxn", txnAsBuyer + txnAsSeller); + resultArray.put(accountDetails); + return resultArray; + } + + /** * A call to sync all the nodes in the network * @return Message if failed or succeeded @@ -278,6 +382,52 @@ public static JSONArray transactionsByDate(String s, String e) throws JSONExcept return resultArray; } + /** + * A call to get list of nft transactions between two mentioned dates + * @param s Start Date + * @param e End Date + * @return List of transactions + * @throws JSONException handles JSON Exceptions + */ + public static JSONArray nftTransactionsByDate(String s, String e) throws JSONException, ParseException { + JSONArray resultArray = new JSONArray(); + String strDateFormat = "yyyy-MMM-dd HH:mm:ss"; + SimpleDateFormat objSDF = new SimpleDateFormat(strDateFormat); + Date date1 = (new SimpleDateFormat("E MMM dd HH:mm:ss Z yyyy")).parse(s); + String startDateString = objSDF.format(date1); + Date date2 = (new SimpleDateFormat("E MMM dd HH:mm:ss Z yyyy")).parse(e); + String endDateString = objSDF.format(date2); + JSONObject countResult = new JSONObject(); + Date startDate = (new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss")).parse(startDateString); + Date endDate = (new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss")).parse(endDateString); + APILogger.debug("start date is " + startDate); + APILogger.debug("end date is " + endDate); + File fileCheck1 = new File(WALLET_DATA_PATH + "nftTransactionHistory.json"); + if (!fileCheck1.exists()) { + countResult.put("Message", "File not found"); + resultArray.put(countResult); + return resultArray; + } + String transactionHistory = readFile(WALLET_DATA_PATH + "nftTransactionHistory.json"); + JSONArray transArray = new JSONArray(transactionHistory); + if (transArray.length() == 0) { + countResult.put("Message", "No Transactions made yet"); + resultArray.put(countResult); + return resultArray; + } + for (int i = 0; i < transArray.length(); i++) { + String dateFromTxnHistoryString = transArray.getJSONObject(i).get("Date").toString(); + Date dateTH = (new SimpleDateFormat("E MMM dd HH:mm:ss Z yyyy")).parse(dateFromTxnHistoryString); + String dateTHS = objSDF.format(dateTH); + Calendar c = Calendar.getInstance(); + c.setTime(objSDF.parse(dateTHS)); + dateTH = c.getTime(); + if (dateTH.after(startDate) && dateTH.before(endDate)) + resultArray.put(transArray.getJSONObject(i)); + } + return resultArray; + } + /** * A call to get list of last n transactions * @param n Count @@ -317,6 +467,40 @@ public static JSONArray transactionsByCount(int n) throws JSONException { return resultArray; } + /** + * A call to get list of last n nft transactions + * @param n Count + * @return List of transactions + * @throws JSONException handles JSON Exceptions + */ + public static JSONArray nftTransactionsByCount(int n) throws JSONException { + JSONObject countResult = new JSONObject(); + JSONArray resultArray = new JSONArray(); + String path = WALLET_DATA_PATH + "nftTransactionHistory.json"; + File transFile = new File(path); + if (!transFile.exists()) { + transFile.delete(); + countResult.put("Message", "File not found"); + resultArray.put(countResult); + return resultArray; + } + String transactionHistory = readFile(path); + JSONArray transArray = new JSONArray(transactionHistory); + if (transArray.length() == 0) { + countResult.put("Message", "No transactions made yet"); + resultArray.put(countResult); + return resultArray; + } + if (n >= transArray.length()) { + for (int j = transArray.length() - 1; j >= 0; j--) + resultArray.put(transArray.get(j)); + return resultArray; + } + for (int i = 1; i <= n; i++) + resultArray.put(transArray.getJSONObject(transArray.length() - i)); + return resultArray; + } + /** * A call to get list transactions within a range * @param start start index @@ -355,6 +539,40 @@ public static JSONArray transactionsByRange(int start, int end) throws JSONExcep return resultArray; } + + /** + * A call to get list nft transactions within a range + * @param start start index + * @param end end index + * @return List of transactions + * @throws JSONException handles JSON Exceptions + */ + public static JSONArray nftTransactionsByRange(int start, int end) throws JSONException { + JSONObject countResult = new JSONObject(); + JSONArray resultArray = new JSONArray(); + if (start <= 0 || end <= 0) { + countResult.put("Message", "Count can't be null or negative"); + resultArray.put(countResult); + return resultArray; + } + File transactionFile = new File(WALLET_DATA_PATH + "nftTransactionHistory.json"); + if (!transactionFile.exists()) { + resultArray.put(countResult); + return resultArray; + } + String transactionHistory = Functions.readFile(WALLET_DATA_PATH + "nftTransactionHistory.json"); + JSONArray transArray = new JSONArray(transactionHistory); + if (transArray.length() == 0) { + resultArray.put(countResult); + return resultArray; + } + for (int i = start; i < end; i++) { + JSONObject object = transArray.getJSONObject(i); + resultArray.put(object); + } + return resultArray; + } + /** * A call to close all open IPFS streams */ @@ -388,6 +606,30 @@ public static JSONArray transactionsByComment(String comment) throws JSONExcepti return resultArray; } + /** + * A call to get list nft transactions with the mentioned comment + * @param comment Comment + * @return List of transactions + * @throws JSONException handles JSON Exceptions + */ + + public static JSONArray nftTransactionsByComment(String comment) throws JSONException { + String transactionHistory = readFile(WALLET_DATA_PATH + "nftTransactionHistory.json"); + JSONArray transArray = new JSONArray(transactionHistory); + JSONArray resultArray = new JSONArray(); + for (int i = 0; i < transArray.length(); i++) { + JSONObject obj = transArray.getJSONObject(i); + if (obj.get("comment").equals(comment)) + resultArray.put(obj); + } + if (resultArray.length() < 1) { + JSONObject returnObject = new JSONObject(); + returnObject.put("Message", "No transactions found with the comment " + comment); + resultArray.put(returnObject); + } + return resultArray; + } + /** * A call to get list transactions made by the user with the input Did @@ -407,6 +649,23 @@ public static JSONArray transactionsByDID(String did) throws JSONException { return resultArray; } + /** + * A call to get list nft transactions made by the user with the input Did + * @param did DID of the contact + * @return List of transactions committed with the user DID + * @throws JSONException handles JSON Exceptions + */ + public static JSONArray nftTransactionsByDID(String did) throws JSONException { + String transactionHistory = readFile(WALLET_DATA_PATH + "nftTransactionHistory.json"); + JSONArray transArray = new JSONArray(transactionHistory); + JSONArray resultArray = new JSONArray(); + for (int i = 0; i < transArray.length(); i++) { + JSONObject didObject = transArray.getJSONObject(i); + if (didObject.get("sellerDID").equals(did) || didObject.get("buyerDID").equals(did)) + resultArray.put(didObject); + } + return resultArray; + } public static int onlinePeersCount() throws JSONException, IOException, InterruptedException { @@ -535,6 +794,32 @@ public static JSONArray txnPerDay() throws JSONException { return new JSONArray().put(datesTxn); } + /** + * A call to list out number of nft transactions made per day + * @return List of transactions committed on every date + * @throws JSONException handles JSON Exceptions + */ + public static JSONArray nftTxnPerDay() throws JSONException { + String dataTable = readFile(WALLET_DATA_PATH + "nftTransactionHistory.json"); + JSONArray dataArray = new JSONArray(dataTable); + HashSet dateSet = new HashSet<>(); + for (int i = 0; i < dataArray.length(); i++) + dateSet.add(dataArray.getJSONObject(i).getString("Date")); + JSONObject datesTxn = new JSONObject(); + Iterator dateIterator = dateSet.iterator(); + while (dateIterator.hasNext()) { + String date = dateIterator.next(); + int count = 0; + for (int j = 0; j < dataArray.length(); j++) { + JSONObject object = dataArray.getJSONObject(j); + if (date.equals(object.getString("Date"))) + count++; + } + datesTxn.put(date, count); + } + return (new JSONArray()).put(datesTxn); + } + public static JSONObject syncNetworkNodes() throws JSONException, IOException { String dataTable = readFile(DATA_PATH + "DataTable.json"); JSONArray dataArray = new JSONArray(dataTable); From 4f5af24a5feae9318e934c1f3cebc6e7f6bf2e14 Mon Sep 17 00:00:00 2001 From: KiranHRubix Date: Fri, 10 Dec 2021 12:20:13 +0530 Subject: [PATCH 06/49] Created FractionChooser class in Resources --- src/com/rubix/Resources/FractionChooser.java | 88 ++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 src/com/rubix/Resources/FractionChooser.java diff --git a/src/com/rubix/Resources/FractionChooser.java b/src/com/rubix/Resources/FractionChooser.java new file mode 100644 index 00000000..4f328c6c --- /dev/null +++ b/src/com/rubix/Resources/FractionChooser.java @@ -0,0 +1,88 @@ +package com.rubix.Resources; + + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import org.apache.log4j.*; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import static com.rubix.Resources.Functions.*; + +public class FractionChooser { + public static String output; + + public static JSONArray tokenHeader; + + public static Logger FractionChooserLogger = Logger.getLogger(FractionChooser.class); + + public static JSONArray calculate(int amount) { + JSONArray tokensList = new JSONArray(); + tokenHeader = new JSONArray(); + JSONObject tknmap = new JSONObject(); + try { + int index = 0; + LinkedHashMap map = new LinkedHashMap<>(); + LinkedHashMap usedmap = new LinkedHashMap<>(); + List bnk = new ArrayList<>(); + if (amount < 1) { + FractionChooserLogger.warn("Invalid Transaction Amount"); + output = "Please make a valid transaction"; + return tokensList; + } + JSONArray mapList = new JSONArray(readFile(PAYMENTS_PATH + "TokenMap.json")); + int i; + for (i = 0; i < mapList.length(); i++) { + JSONObject tempJsonObject = mapList.getJSONObject(i); + String type = tempJsonObject.getString("type"); + int valueInt = tempJsonObject.getInt("value"); + tknmap.put(String.valueOf(valueInt), type); + String lists = readFile(PAYMENTS_PATH + tempJsonObject.getString("type") + ".json"); + JSONArray tempJsonArray = new JSONArray(lists); + bnk.add(i, tempJsonArray); + int size = tempJsonArray.length(); + map.put(Integer.valueOf(valueInt), Integer.valueOf(size)); + usedmap.put(Integer.valueOf(valueInt), Integer.valueOf(0)); + } + List keyList = new ArrayList(map.keySet()); + for (i = map.size() - 1; i > 0; i--) { + if (((Integer)keyList.get(i)).intValue() <= amount) { + index = i; + break; + } + } + while (amount != 0) { + int valueInt = ((Integer)keyList.get(index)).intValue(); + if (((Integer)map.get(Integer.valueOf(valueInt))).intValue() > 0 && valueInt <= amount) { + amount -= valueInt; + int temp = ((Integer)usedmap.get(Integer.valueOf(valueInt))).intValue(); + int temp1 = ((Integer)map.get(Integer.valueOf(valueInt))).intValue(); + usedmap.put(Integer.valueOf(valueInt), Integer.valueOf(++temp)); + map.put(Integer.valueOf(valueInt), Integer.valueOf(--temp1)); + } else if (index != 0) { + index--; + } else { + FractionChooserLogger.warn("Insufficient Amount in the Wallet. Required " + amount + " currency"); + output = "Balance not sufficient, need " + amount + " more currency"; + return tokensList; + } + if (valueInt > amount && index != 0) + index--; + } + for (i = 0; i < keyList.size(); i++) { + for (int j = 0; j < ((Integer)usedmap.get(keyList.get(i))).intValue(); j++) { + tokensList.put(((JSONArray)bnk.get(i)).getJSONObject(j).getString("tokenHash")); + tokenHeader.put(tknmap.get(String.valueOf(keyList.get(i)))); + } + } + } catch (JSONException e) { + FractionChooserLogger.error("JSON Exception Occurred", (Throwable)e); + e.printStackTrace(); + } + FractionChooserLogger.debug("Tokens chosen to be sent: " + tokensList); + return tokensList; + } +} + From b56c1ce5a15b7f3f1a6c9bacfce1bbbe314ff2bc Mon Sep 17 00:00:00 2001 From: KiranHRubix Date: Fri, 10 Dec 2021 12:55:46 +0530 Subject: [PATCH 07/49] Updates Functions and seller class --- src/com/rubix/NFT/Seller.java | 8 +++---- src/com/rubix/Resources/Functions.java | 31 +++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/com/rubix/NFT/Seller.java b/src/com/rubix/NFT/Seller.java index b0219a2f..ba486429 100644 --- a/src/com/rubix/NFT/Seller.java +++ b/src/com/rubix/NFT/Seller.java @@ -133,9 +133,9 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception SellerLogger.debug("alphaquorum " + alphaQuorum + " size " + alphaQuorum.length()); SellerLogger.debug("betaquorum " + betaQuorum + " size " + betaQuorum.length()); SellerLogger.debug("gammaquorum " + gammaQuorum + " size " + gammaQuorum.length()); - ArrayList alphaPeersList = Functions.QuorumCheck(alphaQuorum, ipfs, alphaSize); - ArrayList betaPeersList = Functions.QuorumCheck(betaQuorum, ipfs, 7); - ArrayList gammaPeersList = Functions.QuorumCheck(gammaQuorum, ipfs, 7); + ArrayList alphaPeersList = Functions.QuorumCheck(alphaQuorum, alphaSize); + ArrayList betaPeersList = Functions.QuorumCheck(betaQuorum, 7); + ArrayList gammaPeersList = Functions.QuorumCheck(gammaQuorum, 7); SellerLogger.debug("alphaPeersList size " + alphaPeersList.size()); SellerLogger.debug("betaPeersList size " + betaPeersList.size()); SellerLogger.debug("gammaPeersList size " + gammaPeersList.size()); @@ -170,7 +170,7 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception assetDetails.put("amount", amount); String buyerPeerId = Functions.getValues(Functions.DATA_PATH + "DataTable.json", "peerid", "didHash", buyerDidIpfsHash); SellerLogger.debug("Swarm connecting to " + buyerPeerId); - IPFSNetwork.swarmConnect(buyerPeerId, ipfs); + IPFSNetwork.swarmConnectP2P(buyerPeerId, ipfs); SellerLogger.debug("Swarm connected"); String buyerWidIpfsHash = Functions.getValues(Functions.DATA_PATH + "DataTable.json", "walletHash", "didHash", buyerDidIpfsHash); Functions.nodeData(buyerDidIpfsHash, buyerWidIpfsHash, ipfs); diff --git a/src/com/rubix/Resources/Functions.java b/src/com/rubix/Resources/Functions.java index b7331468..13d85e88 100644 --- a/src/com/rubix/Resources/Functions.java +++ b/src/com/rubix/Resources/Functions.java @@ -5,6 +5,7 @@ import static com.rubix.Resources.IPFSNetwork.executeIPFSCommands; import static com.rubix.Resources.IPFSNetwork.forwardCheck; import static com.rubix.Resources.IPFSNetwork.listen; +import static com.rubix.Resources.IPFSNetwork.*; import java.awt.image.BufferedImage; import java.io.BufferedReader; @@ -48,10 +49,13 @@ public class Functions { public static String DATA_PATH = ""; public static String TOKENS_PATH = ""; public static String TOKENCHAIN_PATH = ""; + public static String NFT_TOKENS_PATH = ""; + public static String NFT_TOKENCHAIN_PATH = ""; public static String LOGGER_PATH = ""; public static String WALLET_DATA_PATH = ""; public static String PAYMENTS_PATH = ""; public static int RECEIVER_PORT, GOSSIP_SENDER, GOSSIP_RECEIVER, QUORUM_PORT, SENDER2Q1, SENDER2Q2, SENDER2Q3, SENDER2Q4, SENDER2Q5, SENDER2Q6, SENDER2Q7; + public static int BUYER_PORT,SELLER_PORT; public static int QUORUM_COUNT; public static int SEND_PORT; public static int IPFS_PORT; @@ -59,6 +63,7 @@ public class Functions { public static String ADVISORY_IP = ""; public static int APPLICATION_PORT; public static String EXPLORER_IP = ""; + public static String NFT_EXPLORER_IP = ""; public static String USERDID_IP = ""; public static String configPath = ""; public static String dirPath = ""; @@ -98,13 +103,17 @@ public static void pathSet() { DATA_PATH = pathsArray.getJSONObject(0).getString("DATA_PATH"); TOKENS_PATH = pathsArray.getJSONObject(0).getString("TOKENS_PATH"); + NFT_TOKENS_PATH = pathsArray.getJSONObject(0).getString("NFT_TOKENS_PATH"); LOGGER_PATH = pathsArray.getJSONObject(0).getString("LOGGER_PATH"); TOKENCHAIN_PATH = pathsArray.getJSONObject(0).getString("TOKENCHAIN_PATH"); + NFT_TOKENCHAIN_PATH = pathsArray.getJSONObject(0).getString("NFT_TOKENCHAIN_PATH"); WALLET_DATA_PATH = pathsArray.getJSONObject(0).getString("WALLET_DATA_PATH"); PAYMENTS_PATH = pathsArray.getJSONObject(0).getString("PAYMENTS_PATH"); SEND_PORT = pathsArray.getJSONObject(1).getInt("SEND_PORT"); + SELLER_PORT = pathsArray.getJSONObject(1).getInt("SELLER_PORT"); RECEIVER_PORT = pathsArray.getJSONObject(1).getInt("RECEIVER_PORT"); + BUYER_PORT = pathsArray.getJSONObject(1).getInt("BUYER_PORT"); GOSSIP_RECEIVER = pathsArray.getJSONObject(1).getInt("GOSSIP_RECEIVER"); GOSSIP_SENDER = pathsArray.getJSONObject(1).getInt("GOSSIP_SENDER"); QUORUM_PORT = pathsArray.getJSONObject(1).getInt("QUORUM_PORT"); @@ -120,6 +129,7 @@ public static void pathSet() { SYNC_IP = pathsArray.getJSONObject(2).getString("SYNC_IP"); EXPLORER_IP = pathsArray.getJSONObject(2).getString("EXPLORER_IP"); + NFT_EXPLORER_IP = pathsArray.getJSONObject(2).getString("NFT_EXPLORER_IP"); USERDID_IP = pathsArray.getJSONObject(2).getString("USERDID_IP"); ADVISORY_IP=pathsArray.getJSONObject(2).getString("ADVISORY_IP"); @@ -385,6 +395,21 @@ public static String sign(String detailsString) throws IOException, JSONExceptio return intArrayToStr(p1Sign); } + public static void establishConnection(String connectObjectString) { + IPFS ipfs = new IPFS("/ip4/127.0.0.1/tcp/" + IPFS_PORT); + JSONObject connectObject = null; + try { + connectObject = new JSONObject(connectObjectString); + String DID = connectObject.getString("did"); + String appName = DID.concat(connectObject.getString("appName")); + String peerID = getValues(DATA_PATH + "DataTable.json", "peerid", "didHash", DID); + swarmConnectP2P(peerID, ipfs); + forward(appName, SEND_PORT, peerID); + } catch (JSONException e) { + FunctionsLogger.error("JSONException Occurred", (Throwable)e); + } + } + /** * This function will allow for a user to listen on a particular appName * @@ -826,13 +851,17 @@ public static String checkDirectory() throws JSONException { File loggerFolder = new File(LOGGER_PATH); File tokensFolder = new File(TOKENS_PATH); File tokenChainsFolder = new File(TOKENCHAIN_PATH); + File nftTokensFolder = new File(NFT_TOKENS_PATH); + File nftTokenChainsFolder = new File(NFT_TOKENCHAIN_PATH); File walletDataFolder = new File(WALLET_DATA_PATH); - if (!dataFolder.exists() || !loggerFolder.exists() || !tokenChainsFolder.exists() || !tokensFolder.exists() || !walletDataFolder.exists()) { + if (!dataFolder.exists() || !loggerFolder.exists() || !tokenChainsFolder.exists() || !nftTokensFolder.exists() || !nftTokenChainsFolder.exists() || !tokensFolder.exists() || !walletDataFolder.exists()) { dataFolder.delete(); loggerFolder.delete(); tokenChainsFolder.delete(); tokensFolder.delete(); + nftTokenChainsFolder.delete(); + nftTokensFolder.delete(); walletDataFolder.delete(); JSONObject result = new JSONObject(); result.put("message", "User not registered, create your Decentralised Identity!"); From 525ee7a11e59eb88a88e9dcb6fe678ea427ab355 Mon Sep 17 00:00:00 2001 From: KiranHRubix Date: Fri, 10 Dec 2021 13:23:59 +0530 Subject: [PATCH 08/49] Updated IPFSNetwor class --- src/com/rubix/Resources/IPFSNetwork.java | 32 +++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/com/rubix/Resources/IPFSNetwork.java b/src/com/rubix/Resources/IPFSNetwork.java index 72c894ea..e1646de5 100644 --- a/src/com/rubix/Resources/IPFSNetwork.java +++ b/src/com/rubix/Resources/IPFSNetwork.java @@ -65,6 +65,7 @@ public static boolean forwardCheck(String application, int port, String peerid) } public static String checkSwarmConnect() { + IPFSNetworkLogger.debug("check swarm peers request"); String response = executeIPFSCommandsResponse("ipfs swarm peers"); return response; } @@ -188,6 +189,7 @@ public static String swarmConnectProcess(MultiAddress multiAddress) { sb.append(line); sb.append("\n"); } + IPFSNetworkLogger.debug(command + " output: " + command); if (!OS.contains("Windows")) P.waitFor(); br.close(); @@ -277,6 +279,34 @@ public static void pin(String MultiHash, IPFS ipfs) { } } + /** + * This method pin objects to local storage See + * ipfs pin + * add for more + * + * @param MultiHash ipfspath of object to be pinned + * @param ipfs IPFS instance + */ + public static void pinNFT(String MultiHash, IPFS ipfs) { + PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); + String command = " ipfs pin " + MultiHash; + executeIPFSCommands(command); + } + + /** + * This method removes pinned objects from local storage ee + * ipfs pin rm + * for more + * + * @param MultiHash ipfspath of object to be pinned + * @param ipfs IPFS instance + */ + public static void unpinNFT(String MultiHash, IPFS ipfs) { + PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); + String command = " ipfs unpin " + MultiHash; + executeIPFSCommands(command); + } + /** * This method removes pinned objects from local storage ee * ipfs pin rm @@ -406,7 +436,7 @@ public static void getImage(String MultiHash, IPFS ipfs, String path) throws IOE ImageIO.write(bis, "png", new File(path)); } - /** + /* * This method is a plumbing command that will sweep the local set of stored * objects and remove ones that are not pinned in order to reclaim hard disk * space See From 3cbe29f69ebfda9becb3689c947be9449f595168 Mon Sep 17 00:00:00 2001 From: KiranHRubix Date: Thu, 23 Dec 2021 11:51:37 +0530 Subject: [PATCH 09/49] Updated Seller class in NFT module --- src/com/rubix/NFT/Seller.java | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/com/rubix/NFT/Seller.java b/src/com/rubix/NFT/Seller.java index ba486429..f393c9bc 100644 --- a/src/com/rubix/NFT/Seller.java +++ b/src/com/rubix/NFT/Seller.java @@ -48,8 +48,8 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception int amount = detailsObject.getInt("amount"); int type = detailsObject.getInt("type"); String comment = detailsObject.getString("comment"); - String eKey = detailsObject.getString("eKey"); - String dKey = detailsObject.getString("dKey"); + //String eKey = detailsObject.getString("eKey"); + //String dKey = detailsObject.getString("dKey"); String nftTokenIpfsHash = detailsObject.getString("nftToken"); JSONArray alphaQuorum = new JSONArray(); JSONArray betaQuorum = new JSONArray(); @@ -79,10 +79,10 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception return APIResponse; } sellerMutex = true; - String nftTokenChainIpfsHash = null; + //String nftTokenChainIpfsHash = null; APIResponse = new JSONObject(); - File nfttoken = new File(Functions.NFT_TOKENS_PATH ); - File nfttokenchain = new File(Functions.NFT_TOKENCHAIN_PATH ); + File nfttoken = new File(Functions.NFT_TOKENS_PATH+nftTokenIpfsHash); + File nfttokenchain = new File(Functions.NFT_TOKENCHAIN_PATH + nftTokenIpfsHash +".json"); SellerLogger.debug("NFT Token : " + nfttoken + " and NFT TokenChain : " + nfttokenchain); if (!nfttoken.exists() || !nfttokenchain.exists() ) { SellerLogger.info("NFT Token Not Verified"); @@ -93,9 +93,9 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception APIResponse.put("message", "Invalid NFT token"); return APIResponse; } - IPFSNetwork.add(Functions.NFT_TOKENS_PATH + Functions.NFT_TOKENS_PATH, ipfs); - nftTokenChainIpfsHash = IPFSNetwork.add(Functions.NFT_TOKENCHAIN_PATH + Functions.NFT_TOKENCHAIN_PATH + ".json", ipfs); - String authSellerByBuyerHash = Functions.calculateHash(nftTokenIpfsHash + nftTokenIpfsHash + nftTokenChainIpfsHash+ amount + eKey + dKey + buyerDidIpfsHash, "SHA3-256"); + IPFSNetwork.add(Functions.NFT_TOKENS_PATH + nftTokenIpfsHash, ipfs); + String nftTokenChainIpfsHash = IPFSNetwork.add(Functions.NFT_TOKENCHAIN_PATH + nftTokenIpfsHash + ".json", ipfs); + String authSellerByBuyerHash = Functions.calculateHash(nftTokenIpfsHash + nftTokenChainIpfsHash+ amount + buyerDidIpfsHash, "SHA3-256"); String tid = Functions.calculateHash(authSellerByBuyerHash, "SHA3-256"); SellerLogger.debug("Hash for Seller authentication to Buyer : " + authSellerByBuyerHash); SellerLogger.debug("TID on seller " + tid); @@ -165,8 +165,6 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception Functions.deleteFile(Functions.LOGGER_PATH + "nftID"); SellerLogger.debug("nftID hash " + nftIdIpfsHash + " unique owner " + IPFSNetwork.dhtEmpty(nftIdIpfsHash, ipfs)); JSONObject assetDetails = new JSONObject(); - assetDetails.put("eKey", eKey); - assetDetails.put("dKey", dKey); assetDetails.put("amount", amount); String buyerPeerId = Functions.getValues(Functions.DATA_PATH + "DataTable.json", "peerid", "didHash", buyerDidIpfsHash); SellerLogger.debug("Swarm connecting to " + buyerPeerId); @@ -382,10 +380,10 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception int count = 0; int m; for (m = 0; m < amount; m++) { - FileWriter fileWriter = new FileWriter(Functions.TOKENS_PATH + Functions.TOKENS_PATH); + FileWriter fileWriter = new FileWriter(Functions.TOKENS_PATH + allRbxTokenContent.get(m)); fileWriter.write(allRbxTokenContent.get(m)); fileWriter.close(); - IPFSNetwork.add(Functions.TOKENS_PATH + Functions.TOKENS_PATH, ipfs); + IPFSNetwork.add(Functions.TOKENS_PATH + allRbxTokenContent.get(m), ipfs); IPFSNetwork.pin(rbxTokens.getString(m), ipfs); count++; } @@ -409,7 +407,7 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception obj2.put("comment", comment); obj2.put("tid", tid); arr1.put(obj2); - Functions.writeToFile(Functions.TOKENCHAIN_PATH + Functions.TOKENCHAIN_PATH + ".json", arr1.toString(), Boolean.valueOf(false)); + Functions.writeToFile(Functions.TOKENCHAIN_PATH + allRbxTokenChainContent.get(m) + ".json", arr1.toString(), Boolean.valueOf(false)); } JSONObject rbxPinData = new JSONObject(); rbxPinData.put("status", "Pinned RBX"); @@ -478,10 +476,10 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception JSONArray nftTransactionHistoryEntry = new JSONArray(); nftTransactionHistoryEntry.put(nftTransactionRecord); Functions.updateJSON("add", Functions.WALLET_DATA_PATH + "nftTransactionHistory.json", nftTransactionHistoryEntry.toString()); - Files.deleteIfExists(Paths.get(Functions.NFT_TOKENS_PATH + Functions.NFT_TOKENS_PATH, new String[0])); + Files.deleteIfExists(Paths.get(Functions.NFT_TOKENS_PATH + nftTokenIpfsHash, new String[0])); for (int n = 0; n < rbxTokens.length(); n++) { String bank = rbxTokenHeader.getString(n); - String bankFile = Functions.readFile(Functions.PAYMENTS_PATH + Functions.PAYMENTS_PATH + ".json"); + String bankFile = Functions.readFile(Functions.PAYMENTS_PATH + bank + ".json"); JSONArray bankArray = new JSONArray(bankFile); JSONObject tokenObject = new JSONObject(); tokenObject.put("tokenHash", rbxTokens.getString(n)); From a8ebe5257e771a1e425ad44c11a46ec1de03e1a4 Mon Sep 17 00:00:00 2001 From: KiranHRubix Date: Thu, 23 Dec 2021 14:14:49 +0530 Subject: [PATCH 10/49] Updated Buyer class in NFT module --- src/com/rubix/NFT/Buyer.java | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/src/com/rubix/NFT/Buyer.java b/src/com/rubix/NFT/Buyer.java index 64de5405..ee1dbc2b 100644 --- a/src/com/rubix/NFT/Buyer.java +++ b/src/com/rubix/NFT/Buyer.java @@ -134,8 +134,6 @@ public static String receive() { String assetData = input.readLine(); BuyerLogger.debug("Received asset details from Seller"); JSONObject assetDetails = new JSONObject(assetData); - String eKey = assetDetails.getString("eKey"); - String dKey = assetDetails.getString("dKey"); int amount = assetDetails.getInt("amount"); JSONArray rbxTokens = FractionChooser.calculate(amount); JSONArray rbxTokenHeader = FractionChooser.tokenHeader; @@ -155,8 +153,8 @@ public static String receive() { return APIResponse.toString(); } for (int i = 0; i < rbxTokens.length(); i++) { - File rbxtoken = new File(Functions.TOKENS_PATH); - File rbxtokenchain = new File(Functions.TOKENCHAIN_PATH); + File rbxtoken = new File(Functions.TOKENS_PATH+rbxTokens.get(i)); + File rbxtokenchain = new File(Functions.TOKENCHAIN_PATH+rbxTokens.get(i)+".json"); BuyerLogger.debug("" + rbxtoken + " and " + rbxtoken); if (!rbxtoken.exists() || !rbxtokenchain.exists()) { output.println("421"); @@ -172,8 +170,8 @@ public static String receive() { ss.close(); return APIResponse.toString(); } - IPFSNetwork.add(Functions.TOKENS_PATH, ipfs); - String tokenChainHash = IPFSNetwork.add(Functions.TOKENCHAIN_PATH, ipfs); + IPFSNetwork.add(Functions.TOKENS_PATH+rbxTokens.get(i), ipfs); + String tokenChainHash = IPFSNetwork.add(Functions.TOKENCHAIN_PATH+rbxTokens.get(i)+".json", ipfs); rbxTokensChainsPushed.add(tokenChainHash); } JSONObject rbxTokenDetails = new JSONObject(); @@ -181,7 +179,7 @@ public static String receive() { rbxTokenDetails.put("rbxTokenChains", rbxTokensChainsPushed); rbxTokenDetails.put("rbxTokenHeader", rbxTokenHeader); String pvt = Functions.DATA_PATH+ buyerDidIpfsHash + "PrivateShare.png"; - String buyerSign = Functions.getSignFromShares(pvt, Functions.calculateHash("" + rbxTokens + rbxTokens + rbxTokensChainsPushed.toString(), "SHA3-256")); + String buyerSign = Functions.getSignFromShares(pvt, Functions.calculateHash(rbxTokens + rbxTokenHeader + rbxTokensChainsPushed.toString(), "SHA3-256")); JSONObject rbxData = new JSONObject(); rbxData.put("rbxTokenDetails", rbxTokenDetails); rbxData.put("authBuyerBySeller", buyerSign); @@ -256,7 +254,7 @@ public static String receive() { BuyerLogger.debug("Verified Quorum Count " + quorumSignVerifyCount); yesQuorum = (quorumSignVerifyCount >= quorumSignatures.length()); } - String hash = Functions.calculateHash(nftToken + nftToken + nftTokenChain + amount + eKey + dKey + buyerDidIpfsHash, "SHA3-256"); + String hash = Functions.calculateHash(nftToken + nftTokenChain + amount + buyerDidIpfsHash, "SHA3-256"); JSONObject detailsForVerify = new JSONObject(); detailsForVerify.put("did", sellerDidIpfsHash); detailsForVerify.put("hash", hash); @@ -283,10 +281,10 @@ public static String receive() { output.println("200"); String nftUnpinStatus = input.readLine(); if (nftUnpinStatus.equals("Unpinned NFT")) { - FileWriter fileWriter = new FileWriter(Functions.NFT_TOKENS_PATH ); + FileWriter fileWriter = new FileWriter(Functions.NFT_TOKENS_PATH+nftToken); fileWriter.write(nftTokenContent); fileWriter.close(); - IPFSNetwork.add(Functions.NFT_TOKENS_PATH , ipfs); + IPFSNetwork.add(Functions.NFT_TOKENS_PATH + nftToken, ipfs); IPFSNetwork.pin(nftToken, ipfs); try { @@ -321,7 +319,7 @@ public static String receive() { newRecord.put("comment", comment); newRecord.put("tid", tid); currentNftTokenChain.put(newRecord); - Functions.writeToFile(Functions.NFT_TOKENCHAIN_PATH, currentNftTokenChain.toString(), Boolean.valueOf(false)); + Functions.writeToFile(Functions.NFT_TOKENCHAIN_PATH+nftTokenChain+".json", currentNftTokenChain.toString(), Boolean.valueOf(false)); Iterator keys = quorumSignatures.keys(); JSONArray quorumList = new JSONArray(); while (keys.hasNext()) @@ -333,8 +331,6 @@ public static String receive() { nftTransactionRecord.put("amount", amount); nftTransactionRecord.put("rbxTokens", rbxTokens); nftTransactionRecord.put("nftToken", nftToken); - nftTransactionRecord.put("eKey", eKey); - nftTransactionRecord.put("dKey", dKey); nftTransactionRecord.put("txn", tid); nftTransactionRecord.put("quorumList", quorumList); nftTransactionRecord.put("Date", Functions.getCurrentUtcTime()); @@ -346,9 +342,9 @@ public static String receive() { Functions.updateJSON("add", Functions.WALLET_DATA_PATH + "nftTransactionHistory.json", nftTransactionHistoryEntry.toString()); int k; for (k = 0; k < rbxTokens.length(); k++) - Files.deleteIfExists(Paths.get(Functions.TOKENS_PATH, new String[0])); + Files.deleteIfExists(Paths.get(Functions.TOKENS_PATH+rbxTokens.get(i), new String[0])); for (k = 0; k < amount; k++) - Functions.updateJSON("remove", Functions.PAYMENTS_PATH, rbxTokens.getString(k)); + Functions.updateJSON("remove", Functions.PAYMENTS_PATH+rbxTokenHeader.getString(k), rbxTokens.getString(k)); BuyerLogger.info("Transaction ID: " + tid + "Transaction Successful"); output.println("Send Response"); APIResponse.put("sellerDID", sellerDidIpfsHash); From f6c591bde3e515968edebde2559212756692329d Mon Sep 17 00:00:00 2001 From: Nidhin Mahesh A Date: Thu, 23 Dec 2021 16:46:10 +0530 Subject: [PATCH 11/49] +last transaction validated by quorum and credit mapping is shared with sender for validation. + sender will cross match with transaction details and validate credits owned by alpha quorum to participate in this transaction. + quorum is ejected from consensus if credit source could not be verified. Signed-off-by: Nidhin Mahesh A --- .../rubix/AuthenticateNode/Authenticate.java | 6 +- .../rubix/Consensus/InitiatorConsensus.java | 106 ++++-- .../rubix/Consensus/InitiatorProcedure.java | 3 +- src/com/rubix/Consensus/QuorumConsensus.java | 163 +++++--- src/com/rubix/Resources/APIHandler.java | 111 ++++-- src/com/rubix/Resources/Functions.java | 55 +-- src/com/rubix/Resources/IPFSNetwork.java | 47 +-- src/com/rubix/TokenTransfer/ProofCredits.java | 237 ++++++------ .../rubix/TokenTransfer/TokenReceiver.java | 162 ++++---- src/com/rubix/TokenTransfer/TokenSender.java | 352 ++++++++++-------- 10 files changed, 682 insertions(+), 560 deletions(-) diff --git a/src/com/rubix/AuthenticateNode/Authenticate.java b/src/com/rubix/AuthenticateNode/Authenticate.java index c26a8b44..2c04a75c 100644 --- a/src/com/rubix/AuthenticateNode/Authenticate.java +++ b/src/com/rubix/AuthenticateNode/Authenticate.java @@ -3,6 +3,7 @@ import io.ipfs.api.IPFS; import org.apache.log4j.Logger; import org.apache.log4j.PropertyConfigurator; +import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -11,11 +12,13 @@ import java.io.File; import java.io.IOException; +import static com.rubix.Resources.APIHandler.networkInfo; import static com.rubix.Resources.Functions.*; public class Authenticate { public static Logger AuthenticateLogger = Logger.getLogger(Authenticate.class); + public static int verifyCount = 0; /** * This method is used to authenticate a node in Rubix implementing text based two level NLSS. @@ -29,8 +32,8 @@ public class Authenticate { public static boolean verifySignature(String detailString) throws IOException, JSONException { PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); + verifyCount++; IPFS ipfs = new IPFS("/ip4/127.0.0.1/tcp/" + IPFS_PORT); - System.out.println(IPFS_PORT); JSONObject details = new JSONObject(detailString); String decentralizedID = details.getString("did"); String hash = details.getString("hash"); @@ -61,7 +64,6 @@ public static boolean verifySignature(String detailString) throws IOException, J StringBuilder decentralizedIDForAuth = new StringBuilder(); for (int value : positionsLevelZero) decentralizedIDForAuth.append(senderDIDBin.charAt(value)); if (recombinedResult.equals(decentralizedIDForAuth.toString())) { - AuthenticateLogger.info("Verification True"); return true; } else { AuthenticateLogger.info("Verification Failed"); diff --git a/src/com/rubix/Consensus/InitiatorConsensus.java b/src/com/rubix/Consensus/InitiatorConsensus.java index 7a3b20af..6718e089 100644 --- a/src/com/rubix/Consensus/InitiatorConsensus.java +++ b/src/com/rubix/Consensus/InitiatorConsensus.java @@ -25,24 +25,23 @@ public class InitiatorConsensus { private static final Object countLock = new Object(); private static final Object signLock = new Object(); public static ArrayList quorumWithShares = new ArrayList<>(); - public static volatile int[] quorumResponse = {0,0,0}; + public static volatile int[] quorumResponse = {0, 0, 0}; + public static volatile JSONArray finalQuorumSignsArray = new JSONArray(); /** * This method increments the quorumResponse variable */ - private static synchronized boolean voteNCount(int i,int quorumSize) { + private static synchronized boolean voteNCount(int i, int quorumSize) { boolean status; PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); synchronized (countLock) { - if(quorumResponse[i] 0) { + InitiatorConsensusLogger.debug("Entering Credits Security"); + }else + InitiatorConsensusLogger.debug("Old Credits file"); + + +// if (qstContent.length() == 0 && role == "alpha") { +// InitiatorConsensusLogger.warn("Alpha quorum (" + quorumID[j] + ") has no credits"); +// } +// if (cmContent.length() == 0 && role == "alpha") { +// InitiatorConsensusLogger.warn("Alpha quorum (" + quorumID[j] + ") has no credits in credit mapping data"); +// } + + if(creditsArray.length() != 0) { + for (int k = 0; k < creditsArray.length(); k++) { + JSONObject object = creditsArray.getJSONObject(k); + String did = object.getString("did"); + String sign = object.getString("sign"); + String signHash = object.getString("hash"); + + JSONObject hashedCredObject = new JSONObject(); + hashedCredObject.put("did", did); + hashedCredObject.put("hash", signHash); + hashedCredObject.put("signature", sign); + + + if (!(Authenticate.verifySignature(hashedCredObject.toString()))) + InitiatorConsensusLogger.warn("Credit verification failed for Alpha quorum (" + quorumID[j] + ") credits"); + + + if (cmContent != null) { + for (int l = 0; l < cmContent.length(); l++) { + if ((cmContent.getJSONObject(l).getString("hash") == signHash)) { + InitiatorConsensusLogger.warn("Credit verification failed for Alpha quorum (" + quorumID[j] + ") credits - Hash matched in Credits Mapping file"); + } + } + } + + } + } + + + qOut[j].println(detailsToken); qResponse[j] = qIn[j].readLine(); if (qResponse[j].equals("Auth_Failed")) { @@ -150,11 +205,11 @@ public static JSONObject start(String data, IPFS ipfs, int PORT, int index,Stri InitiatorConsensusLogger.debug("waiting for " +quorumSize +" +signs " + role); while (quorumResponse[index] < minQuorum(quorumSize)) {} InitiatorConsensusLogger.debug("between Q1- to Q"+quorumSize+" for index " + index); - quorumSign(didHash, qResponse[j], index,quorumSize,alphaSize); + quorumSign(didHash,hash, qResponse[j], index,quorumSize,alphaSize); quorumWithShares.add(quorumPeersObject.getString(j)); while (quorumSignature.length() < (minQuorum(alphaSize) + 2* minQuorum(7))) {} InitiatorConsensusLogger.debug("sending Qsign of length " + quorumSignature.length() + "at index " + index); - qOut[j].println(quorumSignature); + qOut[j].println(finalQuorumSignsArray.toString()); IPFSNetwork.executeIPFSCommands("ipfs p2p close -t /p2p/" + quorumID[j]); } else { @@ -165,14 +220,13 @@ public static JSONObject start(String data, IPFS ipfs, int PORT, int index,Stri InitiatorConsensusLogger.debug("Quorum Count : " + quorumResponse + "Signature count : " + quorumSignature.length()); } else { InitiatorConsensusLogger.debug("node failed authentication with index " + index + " with role " + role + " with did " + didHash + " and data to verify " + detailsToVerify); - InitiatorConsensusLogger.debug("recheck result is " + Authenticate.verifySignature(detailsToVerify.toString())); IPFSNetwork.executeIPFSCommands("ipfs p2p close -t /p2p/" + quorumID[j]); } } } } catch (IOException | JSONException e) { - IPFSNetwork.executeIPFSCommands("ipfs p2p close -t /p2p/"+ quorumID[j]); - InitiatorConsensusLogger.error("IOException Occurred", e); + IPFSNetwork.executeIPFSCommands("ipfs p2p close -t /p2p/" + quorumID[j]); + InitiatorConsensusLogger.error("IOException Occurred"); e.printStackTrace(); } }); @@ -180,7 +234,7 @@ public static JSONObject start(String data, IPFS ipfs, int PORT, int index,Stri } while(quorumResponse[index] < minQuorum(quorumSize) || quorumSignature.length() < (minQuorum(alphaSize) + 2* minQuorum(7))){} - + repo(ipfs); } catch (JSONException e) { InitiatorConsensusLogger.error("JSON Exception Occurred", e); e.printStackTrace(); diff --git a/src/com/rubix/Consensus/InitiatorProcedure.java b/src/com/rubix/Consensus/InitiatorProcedure.java index 8041f9ea..1dffecd2 100644 --- a/src/com/rubix/Consensus/InitiatorProcedure.java +++ b/src/com/rubix/Consensus/InitiatorProcedure.java @@ -42,7 +42,7 @@ public static void consensusSetUp(String data,IPFS ipfs, int PORT,int alphaSize) JSONArray betaList = dataObject.getJSONArray("betaList"); JSONArray gammaList = dataObject.getJSONArray("gammaList"); String authSenderByQuorumHash="", authQuorumHash=""; - authSenderByQuorumHash = message; + authSenderByQuorumHash = calculateHash(message , "SHA3-256"); authQuorumHash = calculateHash(authSenderByQuorumHash.concat(receiverDidIpfs), "SHA3-256"); InitiatorProcedureLogger.debug("Sender by Quorum Hash" + authSenderByQuorumHash); InitiatorProcedureLogger.debug("Quorum Auth Hash" + authQuorumHash); @@ -122,6 +122,7 @@ public static void consensusSetUp(String data,IPFS ipfs, int PORT,int alphaSize) }); InitiatorConsensus.quorumSignature=new JSONObject(); + InitiatorConsensus.finalQuorumSignsArray = new JSONArray(); alphaThread.start(); betaThread.start(); gammaThread.start(); diff --git a/src/com/rubix/Consensus/QuorumConsensus.java b/src/com/rubix/Consensus/QuorumConsensus.java index b1bb1dcb..4e1fb042 100644 --- a/src/com/rubix/Consensus/QuorumConsensus.java +++ b/src/com/rubix/Consensus/QuorumConsensus.java @@ -1,6 +1,7 @@ package com.rubix.Consensus; import com.rubix.AuthenticateNode.Authenticate; +import com.rubix.AuthenticateNode.PropImage; import com.rubix.Resources.IPFSNetwork; import io.ipfs.api.IPFS; import org.apache.log4j.Logger; @@ -8,7 +9,6 @@ import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; - import java.io.*; import java.net.ServerSocket; import java.net.Socket; @@ -63,11 +63,53 @@ public void run() { serverSocket = new ServerSocket(port); socket = serverSocket.accept(); + BufferedReader dataReq = new BufferedReader(new InputStreamReader(socket.getInputStream())); BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); + PrintStream dataResp = new PrintStream(socket.getOutputStream()); PrintStream out = new PrintStream(socket.getOutputStream()); JSONObject readSenderData; String getData; + String qstReq; + + //? check for incoming request for QST + + qstReq = dataReq.readLine(); + if (qstReq.contains("qstcmrequest")) { + + QuorumConsensusLogger.debug("Sender reqesting QuorumSignedTransactions.json and CreditMapping.json: " + qstReq); + + File creditsMapping = new File(WALLET_DATA_PATH + "CreditMapping.json"); + if(!creditsMapping.exists()) { + QuorumConsensusLogger.debug("File doesn't exist"); + creditsMapping.createNewFile(); + writeToFile(creditsMapping.toString(), "[]", false); + } + JSONArray qstContent = new JSONArray(readFile(WALLET_DATA_PATH + "QuorumSignedTransactions.json")); + JSONObject qstObjectSend; + JSONArray creditsArray = new JSONArray(); + String credits = ""; + if(qstContent.length() > 0) { + qstObjectSend = qstContent.getJSONObject(qstContent.length() - 1); + if(!qstObjectSend.has("minestatus")) { + QuorumConsensusLogger.debug("Entering Credits Security"); + credits = qstObjectSend.getString("credits"); + if (!credits.equals("")) { + String creditContent = IPFSNetwork.get(credits, ipfs); + creditsArray = new JSONArray(creditContent); + } + } + } + + String cmFile = readFile(WALLET_DATA_PATH + "CreditMapping.json"); + JSONArray creditsMappingArray = new JSONArray(cmFile); + JSONObject qResponse = new JSONObject(); + qResponse.put("Credits", creditsArray.toString()); + qResponse.put("CreditMapping", creditsMappingArray.toString()); + + dataResp.println(qResponse.toString()); + } + getData = in.readLine(); if (getData.contains("ping check")) { QuorumConsensusLogger.debug("Ping check from sender: " + getData); @@ -83,8 +125,6 @@ public void run() { receiverDID = readSenderData.getString("RID"); senderPID = getValues(DATA_PATH + "DataTable.json", "peerid", "didHash", senderDidIpfsHash); - receiverPID = getValues(DATA_PATH + "DataTable.json", "peerid", "didHash", receiverDID); - String senderWidIpfsHash = getValues(DATA_PATH + "DataTable.json", "walletHash", "didHash", senderDidIpfsHash); nodeData(senderDidIpfsHash, senderWidIpfsHash, ipfs); @@ -95,50 +135,85 @@ public void run() { detailsToVerify.put("hash", verifySenderHash); detailsToVerify.put("signature", senderPrivatePos); + writeToFile(LOGGER_PATH + "tempverifysenderhash", verifySenderHash, false); + String verifySenderIPFSHash = IPFSNetwork.addHashOnly(LOGGER_PATH + "tempverifysenderhash", ipfs); + deleteFile(LOGGER_PATH + "tempverifysenderhash"); - QuorumConsensusLogger.debug("Checking providers for: " + verifySenderHash); - ArrayList dhtOwnersList = dhtOwnerCheck(verifySenderHash); - QuorumConsensusLogger.debug("Providers: " + dhtOwnersList); - boolean consensusIDcheck = false; - if(dhtOwnersList.size() <= 2 && dhtOwnersList.contains(senderPID)) - consensusIDcheck = true; +// QuorumConsensusLogger.debug("Checking providers for: " + verifySenderHash); +// ArrayList dhtOwnersList = dhtOwnerCheck(verifySenderHash); +// QuorumConsensusLogger.debug("Providers: " + dhtOwnersList); +// boolean consensusIDcheck = false; +// if(dhtOwnersList.size() <= 2 && dhtOwnersList.contains(senderPID)) +// consensusIDcheck = true; + if (Authenticate.verifySignature(detailsToVerify.toString())) { + QuorumConsensusLogger.debug("Quorum Authenticated Sender"); -// writeToFile(LOGGER_PATH + "tempverifysenderhash", verifySenderHash, false); -// String verifySenderIPFSHash = IPFSNetwork.addHashOnly(LOGGER_PATH + "tempverifysenderhash", ipfs); -// deleteFile(LOGGER_PATH + "tempverifysenderhash"); + QuorumConsensusLogger.debug("ConsensusID pass"); + String QuorumSignature = getSignFromShares(DATA_PATH + didHash + "/PrivateShare.png", quorumHash); + out.println(QuorumSignature); + String creditval; + creditval = in.readLine(); + QuorumConsensusLogger.debug("credit value " + creditval); + + if (!creditval.equals("null")) { //commented as per test for multiple consensus threads + + FileWriter shareWriter = new FileWriter(new File(LOGGER_PATH + "mycredit.txt"), true); + shareWriter.write(creditval); + shareWriter.close(); + File readCredit = new File(LOGGER_PATH + "mycredit.txt"); + String credit = add(readCredit.toString(), ipfs); + + // adding credit to credit mapping + JSONArray CreditBody = new JSONArray(creditval); + JSONObject creditMappingObject = new JSONObject(); + JSONArray creditMappingArray = new JSONArray(); + + for (int i = 0; i < CreditBody.length(); i++) { + JSONObject object = CreditBody.getJSONObject(i); + String key = object.getString("did"); + String sign = object.getString("sign"); + String creditHash = calculateHash(sign, "SHA3-256"); + + creditMappingObject.put("did", key); + creditMappingObject.put("sign", sign); + creditMappingObject.put("hash", creditHash); + creditMappingObject.put("tid", transactionID); + + creditMappingArray.put(creditMappingObject); + + writeToFile(WALLET_DATA_PATH + "CreditMapping.json", creditMappingArray.toString(), false); + + } + JSONObject storeDetailsQuorum = new JSONObject(); + storeDetailsQuorum.put("tid", transactionID); + storeDetailsQuorum.put("consensusID", verifySenderHash); + storeDetailsQuorum.put("sign", senderPrivatePos); + storeDetailsQuorum.put("credits", credit); + storeDetailsQuorum.put("senderdid", senderDidIpfsHash); + storeDetailsQuorum.put("recdid", receiverDID); + JSONArray data = new JSONArray(); + data.put(storeDetailsQuorum); + QuorumConsensusLogger.debug("Quorum Share: " + credit); + updateJSON("add", WALLET_DATA_PATH + "QuorumSignedTransactions.json", data.toString()); + deleteFile(LOGGER_PATH + "mycredit.txt"); + writeToFile(LOGGER_PATH + "consenusIDhash", verifySenderHash, false); + String consenusIDhash = IPFSNetwork.add(LOGGER_PATH + "consenusIDhash", ipfs); + deleteFile(LOGGER_PATH + "consenusIDhash"); + QuorumConsensusLogger.debug("added consensus ID " + consenusIDhash); + } else { + JSONObject storeDetailsQuorum = new JSONObject(); + storeDetailsQuorum.put("tid", transactionID); + storeDetailsQuorum.put("consensusID", verifySenderHash); + storeDetailsQuorum.put("sign", senderPrivatePos); + storeDetailsQuorum.put("credits", ""); + storeDetailsQuorum.put("senderdid", senderDidIpfsHash); + storeDetailsQuorum.put("recdid", receiverDID); + JSONArray data = new JSONArray(); + data.put(storeDetailsQuorum); + updateJSON("add", WALLET_DATA_PATH + "QuorumSignedTransactions.json", data.toString()); + } - if (Authenticate.verifySignature(detailsToVerify.toString()) && consensusIDcheck) { - QuorumConsensusLogger.debug("Quorum Authenticated Sender"); - String QuorumSignature = getSignFromShares(DATA_PATH + didHash + "/PrivateShare.png", quorumHash); - out.println(QuorumSignature); - String creditval; - creditval = in.readLine(); - QuorumConsensusLogger.debug("credit value " + creditval); - if (!creditval.equals("null")) { //commented as per test for multiple consensus threads - FileWriter shareWriter = new FileWriter(new File(LOGGER_PATH + "mycredit.txt"), true); - shareWriter.write(creditval); - shareWriter.close(); - File readCredit = new File(LOGGER_PATH + "mycredit.txt"); - String credit = add(readCredit.toString(), ipfs); - JSONObject storeDetailsQuorum = new JSONObject(); - storeDetailsQuorum.put("tid", transactionID); - storeDetailsQuorum.put("consensusID", verifySenderHash); - storeDetailsQuorum.put("minestatus", false); - storeDetailsQuorum.put("sign", senderPrivatePos); - storeDetailsQuorum.put("credits", credit); - storeDetailsQuorum.put("senderdid", senderDidIpfsHash); - storeDetailsQuorum.put("recdid", receiverDID); - JSONArray data = new JSONArray(); - data.put(storeDetailsQuorum); - QuorumConsensusLogger.debug("Quorum Share: " + credit); - updateJSON("add", WALLET_DATA_PATH + "QuorumSignedTransactions.json", data.toString()); - deleteFile(LOGGER_PATH + "mycredit.txt"); - writeToFile(LOGGER_PATH + "consenusIDhash", verifySenderHash, false); - String consenusIDhash = IPFSNetwork.add(LOGGER_PATH + "consenusIDhash", ipfs); - deleteFile(LOGGER_PATH + "consenusIDhash"); - QuorumConsensusLogger.debug("added consensus ID " + consenusIDhash); - } } else { QuorumConsensusLogger.debug("Sender Authentication Failure - Quorum"); out.println("Auth_Failed"); @@ -148,7 +223,7 @@ public void run() { QuorumConsensusLogger.error("IOException Occurred", e); } catch (JSONException e) { QuorumConsensusLogger.error("JSONException Occurred", e); - } catch (NullPointerException | InterruptedException e) { + } catch (NullPointerException e) { QuorumConsensusLogger.error("NullPointer Exception Occurred ",e); } diff --git a/src/com/rubix/Resources/APIHandler.java b/src/com/rubix/Resources/APIHandler.java index 809442fd..7c9d1343 100644 --- a/src/com/rubix/Resources/APIHandler.java +++ b/src/com/rubix/Resources/APIHandler.java @@ -1,14 +1,20 @@ package com.rubix.Resources; -import com.rubix.TokenTransfer.ProofCredits; -import com.rubix.TokenTransfer.TokenSender; -import io.ipfs.api.IPFS; -import io.ipfs.api.Peer; -import org.apache.log4j.Logger; -import org.apache.log4j.PropertyConfigurator; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; +import static com.rubix.Resources.Functions.DATA_PATH; +import static com.rubix.Resources.Functions.IPFS_PORT; +import static com.rubix.Resources.Functions.LOGGER_PATH; +import static com.rubix.Resources.Functions.SEND_PORT; +import static com.rubix.Resources.Functions.SYNC_IP; +import static com.rubix.Resources.Functions.WALLET_DATA_PATH; +import static com.rubix.Resources.Functions.getOsName; +import static com.rubix.Resources.Functions.getPeerID; +import static com.rubix.Resources.Functions.getValues; +import static com.rubix.Resources.Functions.nodeData; +import static com.rubix.Resources.Functions.readFile; +import static com.rubix.Resources.Functions.writeToFile; +import static com.rubix.Resources.IPFSNetwork.add; +import static com.rubix.Resources.IPFSNetwork.executeIPFSCommands; +import static com.rubix.Resources.IPFSNetwork.pin; import java.io.BufferedReader; import java.io.File; @@ -19,10 +25,24 @@ import java.security.NoSuchAlgorithmException; import java.text.ParseException; import java.text.SimpleDateFormat; -import java.util.*; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; -import static com.rubix.Resources.Functions.*; -import static com.rubix.Resources.IPFSNetwork.*; +import com.rubix.TokenTransfer.ProofCredits; +import com.rubix.TokenTransfer.TokenSender; + +import org.apache.log4j.Logger; +import org.apache.log4j.PropertyConfigurator; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import io.ipfs.api.IPFS; +import io.ipfs.api.Peer; public class APIHandler { private static final Logger APILogger = Logger.getLogger(APIHandler.class); @@ -46,30 +66,33 @@ public static JSONObject send(String data) throws Exception { String senderPeerID = getPeerID(DATA_PATH + "DID.json"); String senDID = getValues(DATA_PATH + "DID.json", "didHash", "peerid", senderPeerID); + APILogger.debug("Debug Check 1"); JSONObject dataObject = new JSONObject(data); String recDID = dataObject.getString("receiverDidIpfsHash"); - - String dataTableData = readFile(DATA_PATH + "DataTable.json"); - boolean isObjectValid = false; - JSONArray dataTable = new JSONArray(dataTableData); - // check value matches any of the data in the data table - for (int i = 0; i < dataTable.length(); i++) { - JSONObject dataTableObject = dataTable.getJSONObject(i); - if (dataTableObject.getString("didHash").equals(recDID)) { - isObjectValid = true; - } - } - if(!isObjectValid) - networkInfo(); - + APILogger.debug("Debug Check 2"); + +// String dataTableData = readFile(DATA_PATH + "DataTable.json"); +// boolean isObjectValid = false; +// JSONArray dataTable = new JSONArray(dataTableData); +// // check value matches any of the data in the data table +// for (int i = 0; i < dataTable.length(); i++) { +// JSONObject dataTableObject = dataTable.getJSONObject(i); +// if (dataTableObject.getString("didHash").equals(recDID)) { +// isObjectValid = true; +// } +// } +// if(!isObjectValid) +// networkInfo(); + + APILogger.debug("Debug Check 3"); // String comments = dataObject.getString("comments"); JSONArray tokens = dataObject.getJSONArray("tokens"); // JSONArray tokenHeader = dataObject.getJSONArray("tokenHeader"); // int amount = dataObject.getInt("amount"); - + APILogger.debug("Debug Check 4"); JSONObject sendMessage = new JSONObject(); if (recDID.length() != 46) { sendMessage.put("did", senDID); @@ -94,14 +117,19 @@ public static JSONObject send(String data) throws Exception { // detailsObject.put("tokenHeader", tokenHeader); // detailsObject.put("amount", amount); dataObject.put("pvt", DATA_PATH + senDID + "/PrivateShare.png"); + APILogger.debug("Initiating Transfer"); sendMessage = TokenSender.Send(dataObject.toString(), ipfs, SEND_PORT); -// sendMessage = TokenSender.Send(detailsObject.toString(), ipfs, SEND_PORT); APILogger.info(sendMessage); return sendMessage; } - + /** + * An API call to mine tokens + * @param type Type of quorum Selection + * @return JSONObject with status message + * @throws Exception throws Exception + */ public static JSONObject create(int type) throws Exception { Functions.pathSet(); PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); @@ -150,6 +178,9 @@ public static JSONArray transactionDetails(String txnId) throws JSONException { } JSONArray transArray = new JSONArray(transactionHistory); + for (int i = 0; i < transArray.length(); i++) { + transArray.getJSONObject(i).remove("essentialShare"); + } JSONObject obj = new JSONObject(); for (int i = 0; i < transArray.length(); i++) { obj = transArray.getJSONObject(i); @@ -180,6 +211,9 @@ public static JSONArray accountInformation() throws JSONException { String transactionHistory = readFile(WALLET_DATA_PATH + "TransactionHistory.json"); JSONArray transArray = new JSONArray(transactionHistory); + for (int i = 0; i < transArray.length(); i++) { + transArray.getJSONObject(i).remove("essentialShare"); + } if(!(transArray.length() == 0)){ for (int i = 0; i < transArray.length(); i++) { @@ -280,6 +314,9 @@ public static JSONArray transactionsByDate(String s, String e) throws JSONExcept } String transactionHistory = readFile(WALLET_DATA_PATH + "TransactionHistory.json"); JSONArray transArray = new JSONArray(transactionHistory); + for (int i = 0; i < transArray.length(); i++) { + transArray.getJSONObject(i).remove("essentialShare"); + } if (transArray.length() == 0){ countResult.put("Message", "No Transactions made yet"); resultArray.put(countResult); @@ -321,6 +358,10 @@ public static JSONArray transactionsByCount(int n) throws JSONException { } String transactionHistory = readFile(path); JSONArray transArray = new JSONArray(transactionHistory); + // remove essentialShare from each object of the array + for (int i = 0; i < transArray.length(); i++) { + transArray.getJSONObject(i).remove("essentialShare"); + } if (transArray.length() == 0){ countResult.put("Message", "No transactions made yet"); resultArray.put(countResult); @@ -363,6 +404,12 @@ public static JSONArray transactionsByRange(int start, int end) throws JSONExcep String transactionHistory = readFile(WALLET_DATA_PATH + "TransactionHistory.json"); JSONArray transArray = new JSONArray(transactionHistory); + for (int i = 0; i < transArray.length(); i++) { + transArray.getJSONObject(i).remove("essentialShare"); + } + for (int i = 0; i < transArray.length(); i++) { + transArray.getJSONObject(i).remove("essentialShare"); + } if (transArray.length() == 0){ resultArray.put(countResult); return resultArray; @@ -394,6 +441,9 @@ public static JSONArray transactionsByComment(String comment) throws JSONExcepti String transactionHistory = readFile(WALLET_DATA_PATH + "TransactionHistory.json"); JSONArray transArray = new JSONArray(transactionHistory); + for (int i = 0; i < transArray.length(); i++) { + transArray.getJSONObject(i).remove("essentialShare"); + } JSONObject obj; JSONArray resultArray = new JSONArray(); for (int i = 0; i < transArray.length(); i++) { @@ -420,6 +470,9 @@ public static JSONArray transactionsByComment(String comment) throws JSONExcepti public static JSONArray transactionsByDID(String did) throws JSONException { String transactionHistory = readFile(WALLET_DATA_PATH + "TransactionHistory.json"); JSONArray transArray = new JSONArray(transactionHistory); + for (int i = 0; i < transArray.length(); i++) { + transArray.getJSONObject(i).remove("essentialShare"); + } JSONArray resultArray = new JSONArray(); for (int i = 0; i < transArray.length(); i++) { JSONObject didObject = transArray.getJSONObject(i); diff --git a/src/com/rubix/Resources/Functions.java b/src/com/rubix/Resources/Functions.java index 7788ae6c..7f0021d6 100644 --- a/src/com/rubix/Resources/Functions.java +++ b/src/com/rubix/Resources/Functions.java @@ -1,20 +1,14 @@ package com.rubix.Resources; -import static com.rubix.Resources.IPFSNetwork.checkSwarmConnect; -import static com.rubix.Resources.IPFSNetwork.executeIPFSCommands; -import static com.rubix.Resources.IPFSNetwork.forwardCheck; -import static com.rubix.Resources.IPFSNetwork.listen; +import com.rubix.AuthenticateNode.PropImage; +import io.ipfs.api.*; +import org.apache.log4j.*; +import org.json.*; +import javax.imageio.ImageIO; import java.awt.image.BufferedImage; -import java.io.BufferedReader; -import java.io.DataOutputStream; -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStreamReader; -import java.net.HttpURLConnection; -import java.net.URL; +import java.io.*; +import java.net.*; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; @@ -22,21 +16,10 @@ import java.security.NoSuchAlgorithmException; import java.text.ParseException; import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.Iterator; - -import javax.imageio.ImageIO; - -import com.rubix.AuthenticateNode.PropImage; - -import org.apache.log4j.Logger; -import org.apache.log4j.PropertyConfigurator; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; +import java.util.*; -import io.ipfs.api.IPFS; +import static com.rubix.Resources.APIHandler.*; +import static com.rubix.Resources.IPFSNetwork.*; public class Functions { @@ -585,11 +568,8 @@ public static void QuorumSwarmConnect(JSONArray quorum, IPFS ipfs) { for (int i = 0; i < quorum.length(); i++) { String quorumPeer; try { - FunctionsLogger.debug("Quorum DID: "+ quorum.getString(i)); quorumPeer = getValues(DATA_PATH + "DataTable.json", "peerid", "didHash", quorum.getString(i)); - FunctionsLogger.debug("Quorum PID: "+ quorumPeer); - // Commented by Anuradha K; A new method swamConnectP2P is implemented for swarm connection - // IPFSNetwork.swarmConnect(quorumPeer,ipfs); + IPFSNetwork.swarmConnectP2P(quorumPeer,ipfs); } catch (JSONException e) { @@ -642,7 +622,6 @@ public static int[] getPrivatePosition(int[] positions, int[] privateArray) { public static JSONObject randomPositions(String role, String hash, int numberOfPositions, int[] pvt1) throws JSONException { int u = 0, l = 0, m = 0; - long st = System.currentTimeMillis(); int[] hashCharacters = new int[256]; int[] randomPositions = new int[32]; int[] randPos = new int[256]; @@ -687,8 +666,6 @@ public static JSONObject randomPositions(String role, String hash, int numberOfP JSONObject resultObject = new JSONObject(); resultObject.put("originalPos", originalPos); resultObject.put("posForSign", posForSign); - long et = System.currentTimeMillis(); - FunctionsLogger.debug("Time taken for randomPositions Calculation " + (et - st)); return resultObject; } @@ -725,7 +702,7 @@ public static void deleteFile(String fileName) { FunctionsLogger.error("IOException Occurred", e); e.printStackTrace(); } - FunctionsLogger.debug("File Deletion successful"); + } @@ -767,13 +744,7 @@ public static void deleteFile(String fileName) { public static void launch() { pathSet(); PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); - - try { - executeIPFSCommands("ipfs daemon --enable-gc"); - - } catch (Exception e) { - e.printStackTrace(); - } + executeIPFSCommands("ipfs daemon --enable-gc"); FunctionsLogger.debug("Enabled ipfs GC"); } diff --git a/src/com/rubix/Resources/IPFSNetwork.java b/src/com/rubix/Resources/IPFSNetwork.java index 1d312b37..b948580c 100644 --- a/src/com/rubix/Resources/IPFSNetwork.java +++ b/src/com/rubix/Resources/IPFSNetwork.java @@ -1,30 +1,5 @@ package com.rubix.Resources; -import static com.rubix.Constants.IPFSConstants.bootstrap; -import static com.rubix.Constants.IPFSConstants.daemon; -import static com.rubix.Constants.IPFSConstants.forward; -import static com.rubix.Constants.IPFSConstants.listen; -import static com.rubix.Constants.IPFSConstants.p2p; -import static com.rubix.Constants.IPFSConstants.shutdown; -import static com.rubix.Resources.Functions.BOOTSTRAPS; -import static com.rubix.Resources.Functions.LOGGER_PATH; -import static com.rubix.Resources.Functions.getOsName; - -import java.awt.image.BufferedImage; -import java.io.BufferedReader; -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.List; - -import javax.imageio.ImageIO; - -import org.apache.log4j.Logger; -import org.apache.log4j.PropertyConfigurator; -import org.json.JSONException; - import io.ipfs.api.IPFS; import io.ipfs.api.MerkleNode; import io.ipfs.api.NamedStreamable; @@ -90,7 +65,6 @@ public static boolean forwardCheck(String application, int port, String peerid) } public static String checkSwarmConnect() { - IPFSNetworkLogger.debug("check swarm peers request"); String response = executeIPFSCommandsResponse("ipfs swarm peers"); return response; } @@ -214,7 +188,6 @@ public static String swarmConnectProcess(MultiAddress multiAddress) { sb.append(line); sb.append("\n"); } - IPFSNetworkLogger.debug(command + " output: " + sb.toString()); if (!OS.contains("Windows")) P.waitFor(); br.close(); @@ -357,8 +330,8 @@ public static boolean dhtFindProvs(String MultiHash, String previousOwner, IPFS PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); Multihash dhtMultihash = Multihash.fromBase58(MultiHash); List dhtlist = ipfs.dht.findprovs(dhtMultihash); - - if (dhtlist.size() == 1 && dhtlist.toString().contains(previousOwner)) + IPFSNetworkLogger.debug("Providers: " + dhtlist); + if (dhtlist.size() <= 2 && dhtlist.toString().contains(previousOwner)) return true; return false; } @@ -453,7 +426,6 @@ public static void repo(IPFS ipfs) { } public static String executeIPFSCommandsResponse(String command) { - IPFSNetworkLogger.debug("executeIPFSCommandsResponse for command " + command); PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); String OS = getOsName(); String result; @@ -481,8 +453,7 @@ public static String executeIPFSCommandsResponse(String command) { } if (command.contains(listen) || command.contains(forward) || command.contains("swarm") - || command.contains(p2p) || command.contains(shutdown) || command.contains(bootstrap)) { - IPFSNetworkLogger.debug("executing command " + command); + || command.contains(p2p) || command.contains(shutdown) || command.contains(bootstrap) || command.contains("findprovs")) { p = new ProcessBuilder(commands); process = p.start(); @@ -500,8 +471,7 @@ public static String executeIPFSCommandsResponse(String command) { return result; } else { - IPFSNetworkLogger.debug("unhandled command " + command); - return "wrong command"; + return "wrong command ".concat(command); } } catch (IOException e) { @@ -513,7 +483,7 @@ public static String executeIPFSCommandsResponse(String command) { result = e.toString(); e.printStackTrace(); } - IPFSNetworkLogger.debug("return string "); + return result; } @@ -579,7 +549,6 @@ public static void swarmConnectP2P(String peerid, IPFS ipfs) throws JSONExceptio PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); String bootNode; boolean swarmConnected = false; - IPFSNetworkLogger.debug("swarm connect p2p" + peerid); MultiAddress multiAddress = new MultiAddress("/ipfs/" + peerid); String output = swarmConnectProcess(multiAddress); @@ -592,21 +561,17 @@ public static void swarmConnectP2P(String peerid, IPFS ipfs) throws JSONExceptio if (!swarmConnected) { bootNode = String.valueOf(BOOTSTRAPS.get(i)); bootNode = bootNode.substring(bootNode.length() - 46); - IPFSNetworkLogger.debug("bootnode is " + bootNode); multiAddress = new MultiAddress("/ipfs/" + bootNode + "/p2p-circuit/ipfs/" + peerid); output = swarmConnectProcess(multiAddress); if (!output.contains("success")) { - IPFSNetworkLogger.debug("swarm attempt failed"); + IPFSNetworkLogger.debug("swarm attempt failed with " + peerid); } else { - IPFSNetworkLogger.debug("Connected via bootstrap node: " + bootNode); swarmConnected = true; } } } - } else { - IPFSNetworkLogger.debug("Swarm Connected p2p : " + peerid); } } diff --git a/src/com/rubix/TokenTransfer/ProofCredits.java b/src/com/rubix/TokenTransfer/ProofCredits.java index c4a73851..aaac6514 100644 --- a/src/com/rubix/TokenTransfer/ProofCredits.java +++ b/src/com/rubix/TokenTransfer/ProofCredits.java @@ -1,32 +1,18 @@ package com.rubix.TokenTransfer; -import static com.rubix.Resources.Functions.DATA_PATH; -import static com.rubix.Resources.Functions.EXPLORER_IP; -import static com.rubix.Resources.Functions.LOGGER_PATH; -import static com.rubix.Resources.Functions.PAYMENTS_PATH; -import static com.rubix.Resources.Functions.QuorumCheck; -import static com.rubix.Resources.Functions.QuorumSwarmConnect; -import static com.rubix.Resources.Functions.SEND_PORT; -import static com.rubix.Resources.Functions.SYNC_IP; -import static com.rubix.Resources.Functions.TOKENCHAIN_PATH; -import static com.rubix.Resources.Functions.TOKENS_PATH; -import static com.rubix.Resources.Functions.WALLET_DATA_PATH; -import static com.rubix.Resources.Functions.calculateHash; -import static com.rubix.Resources.Functions.deleteFile; -import static com.rubix.Resources.Functions.getQuorum; -import static com.rubix.Resources.Functions.minQuorum; -import static com.rubix.Resources.Functions.mineUpdate; -import static com.rubix.Resources.Functions.readFile; -import static com.rubix.Resources.Functions.updateJSON; -import static com.rubix.Resources.Functions.updateQuorum; -import static com.rubix.Resources.Functions.writeToFile; -import static com.rubix.Resources.IPFSNetwork.repo; +import com.rubix.Consensus.InitiatorConsensus; +import com.rubix.Consensus.InitiatorProcedure; +import com.rubix.Resources.Functions; +import com.rubix.Resources.IPFSNetwork; +import io.ipfs.api.IPFS; +import org.apache.log4j.Logger; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; -import java.io.BufferedReader; -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.InputStreamReader; +import javax.net.ssl.HttpsURLConnection; +import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import java.text.DateFormat; @@ -37,17 +23,8 @@ import java.util.Iterator; import java.util.List; -import javax.net.ssl.HttpsURLConnection; - -import org.apache.log4j.*; -import org.json.*; - -import com.rubix.Consensus.InitiatorConsensus; -import com.rubix.Consensus.InitiatorProcedure; -import com.rubix.Resources.Functions; -import com.rubix.Resources.IPFSNetwork; - -import io.ipfs.api.*; +import static com.rubix.Resources.Functions.*; +import static com.rubix.Resources.IPFSNetwork.repo; public class ProofCredits { @@ -58,8 +35,8 @@ public class ProofCredits { private static ArrayList alphaPeersList; private static ArrayList betaPeersList; private static ArrayList gammaPeersList; - private static int sizeOfQuorum=0; - private static int alphaSize=0; + private static int sizeOfQuorum = 0; + private static int alphaSize = 0; public static JSONObject create(String data, IPFS ipfs) throws IOException, JSONException { @@ -68,35 +45,49 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON String receiverDidIpfsHash = detailsObject.getString("receiverDidIpfsHash"); String pvt = detailsObject.getString("pvt"); int type = detailsObject.getInt("type"); - int creditUsed=0; - long totalTime=0; + int creditUsed = 0; + long totalTime = 0; JSONArray alphaQuorum = new JSONArray(); - JSONArray betaQuorum=new JSONArray(); - JSONArray gammaQuorum=new JSONArray(); + JSONArray betaQuorum = new JSONArray(); + JSONArray gammaQuorum = new JSONArray(); - int level = 0,tokenNumber = 0,availableCredits = 0, balance=0,creditsRequired=500000,level_credit=0; + int creditsRequired = 50000, level; long starttime = System.currentTimeMillis(); JSONArray resJsonData = new JSONArray(); new JSONObject(); JSONObject resJsonData_credit; + //Clean up old File + String qstFile = readFile(WALLET_DATA_PATH + "QuorumSignedTransactions.json"); + JSONArray qstArray = new JSONArray(qstFile); + File usedCreditsFile = new File(WALLET_DATA_PATH + "MinedCreditsHistory.json"); + if (!usedCreditsFile.exists()) { + writeToFile(String.valueOf(usedCreditsFile), "[]", false); + } + + JSONArray newQstArrayReplace = new JSONArray(); + JSONArray minedArray = new JSONArray(readFile(WALLET_DATA_PATH + "MinedCreditsHistory.json")); + if(qstArray.getJSONObject(0).has("minestatus")) { + for (int i = 0; i < qstArray.length(); i++) { + if (qstArray.getJSONObject(i).has("minestatus")) { + if (qstArray.getJSONObject(i).getBoolean("minestatus")) + minedArray.put(qstArray.getJSONObject(i)); + else { + qstArray.getJSONObject(i).remove("minestatus"); + newQstArrayReplace.put(qstArray.getJSONObject(i)); + } + } - //Reading proofcredits.json - String jsonFilePath = WALLET_DATA_PATH+"QuorumSignedTransactions.json"; - JSONArray records = new JSONArray(readFile(jsonFilePath)); - balance = records.length(); - JSONArray prooftid = new JSONArray(); - for (int i = 0; i < balance; i++) { - JSONObject temp = records.getJSONObject(i); - if(temp.getBoolean("minestatus")==false) { - availableCredits++; - //prooftid.put(temp.getString("tid")); - // records.getJSONObject(i).put("minestatus",true); } + writeToFile(WALLET_DATA_PATH + "QuorumSignedTransactions.json", newQstArrayReplace.toString(), false); + writeToFile(WALLET_DATA_PATH + "MinedCreditsHistory.json", minedArray.toString(), false); } + JSONArray newQstArray = new JSONArray(readFile(WALLET_DATA_PATH + "QuorumSignedTransactions.json")); + int availableCredits = newQstArray.length(); + ProofCreditsLogger.debug("Credits available: " + availableCredits); String GET_URL_credit = SYNC_IP + "/getlevel"; URL URLobj_credit = new URL(GET_URL_credit); HttpURLConnection con_credit = (HttpURLConnection) URLobj_credit.openConnection(); @@ -112,27 +103,20 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON } in_credit.close(); ProofCreditsLogger.debug("response from service " + response_credit.toString()); - - //JSONObject responseJSON=new JSONObject(response.toString()); - //resJsonData= responseJSON.getJSONArray("data"); - //creditUsed = responseJSON.getInt("credits"); - - - resJsonData_credit = new JSONObject(response_credit.toString()); - level_credit = resJsonData_credit.getInt("level"); - creditsRequired =(int) Math.pow(2,(2+level_credit)); - ProofCreditsLogger.debug("credits required " + creditsRequired); + resJsonData_credit = new JSONObject(response_credit.toString()); + int level_credit = resJsonData_credit.getInt("level"); + creditsRequired = (int) Math.pow(2, (2 + level_credit)); + ProofCreditsLogger.debug("credits required " + creditsRequired); } else ProofCreditsLogger.debug("GET request not worked"); - ProofCreditsLogger.debug("credits required " + creditsRequired+ " available credits "+ availableCredits); + ProofCreditsLogger.debug("credits required " + creditsRequired + " available credits " + availableCredits); - if (availableCredits>=creditsRequired) { + if (availableCredits >= creditsRequired) { //String GET_URL = SYNC_IP+"/getInfo?count="+availableCredits; - String GET_URL = SYNC_IP + "/minetoken"; URL URLobj = new URL(GET_URL); HttpURLConnection con = (HttpURLConnection) URLobj.openConnection(); @@ -169,66 +153,66 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON for (int i = 0; i < resJsonData.length(); i++) { token.put(Functions.mineToken(resJsonData.getJSONObject(i).getInt("level"), resJsonData.getJSONObject(i).getInt("token"))); - creditUsed+=(int) Math.pow(2,(2+resJsonData.getJSONObject(i).getInt("level"))); + creditUsed += (int) Math.pow(2, (2 + resJsonData.getJSONObject(i).getInt("level"))); } - if(resJsonData.getJSONObject(0).getInt("level")==1) + if (resJsonData.getJSONObject(0).getInt("level") == 1) creditUsed = 10; + JSONArray prooftid = new JSONArray(); String comments = resJsonData.toString() + prooftid; String authSenderByRecHash = calculateHash(token + receiverDidIpfsHash + comments, "SHA3-256"); String tid = calculateHash(authSenderByRecHash, "SHA3-256"); - writeToFile(LOGGER_PATH+"tempbeta", tid.concat(receiverDidIpfsHash), false); - String betaHash = IPFSNetwork.add(LOGGER_PATH+"tempbeta", ipfs); - deleteFile(LOGGER_PATH+"tempbeta"); + writeToFile(LOGGER_PATH + "tempbeta", tid.concat(receiverDidIpfsHash), false); + String betaHash = IPFSNetwork.add(LOGGER_PATH + "tempbeta", ipfs); + deleteFile(LOGGER_PATH + "tempbeta"); - writeToFile(LOGGER_PATH+"tempgamma", tid.concat(receiverDidIpfsHash), false); - String gammaHash = IPFSNetwork.add(LOGGER_PATH+"tempgamma", ipfs); - deleteFile(LOGGER_PATH+"tempgamma"); + writeToFile(LOGGER_PATH + "tempgamma", tid.concat(receiverDidIpfsHash), false); + String gammaHash = IPFSNetwork.add(LOGGER_PATH + "tempgamma", ipfs); + deleteFile(LOGGER_PATH + "tempgamma"); JSONArray quorumArray; - // JSONArray quorumArray= getQuorum(betaHash,gammaHash,receiverDidIpfsHash,receiverDidIpfsHash,token.length()); - // JSONArray quorumArray = new JSONArray(readFile(DATA_PATH + "quorumlist.json")); + // JSONArray quorumArray= getQuorum(betaHash,gammaHash,receiverDidIpfsHash,receiverDidIpfsHash,token.length()); + // JSONArray quorumArray = new JSONArray(readFile(DATA_PATH + "quorumlist.json")); switch (type) { - case 2: { - quorumArray = new JSONArray(readFile(DATA_PATH + "quorumlist.json")); - break; - } + case 2: { + quorumArray = new JSONArray(readFile(DATA_PATH + "quorumlist.json")); + break; + } default: { - quorumArray= getQuorum(betaHash,gammaHash,receiverDidIpfsHash,receiverDidIpfsHash,token.length()); - } + quorumArray = getQuorum(betaHash, gammaHash, receiverDidIpfsHash, receiverDidIpfsHash, token.length()); + } } - - QuorumSwarmConnect(quorumArray,ipfs); - alphaSize=quorumArray.length()-14; + QuorumSwarmConnect(quorumArray, ipfs); - for(int i=0;i= 3 * minQuorum(7))) { APIResponse.put("did", receiverDidIpfsHash); @@ -260,21 +244,20 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON ProofCreditsLogger.debug("token mined " + token); int counter = 0; - for (int i = 0; i < balance; i++) { - JSONObject temp = records.getJSONObject(i); - if (temp.getBoolean("minestatus") == false && (counter < creditUsed)) { + + for (int i = 0; i < availableCredits; i++) { + JSONObject temp = newQstArray.getJSONObject(i); + if (counter < creditUsed) { prooftid.put(temp.getString("tid")); - records.getJSONObject(i).put("minestatus", true); counter++; } } - for (int i = 0; i < token.length(); i++) { - writeToFile(LOGGER_PATH+"tempToken", token.getString(i), false); - String tokenHash = IPFSNetwork.add(LOGGER_PATH+"tempToken", ipfs); + writeToFile(LOGGER_PATH + "tempToken", token.getString(i), false); + String tokenHash = IPFSNetwork.add(LOGGER_PATH + "tempToken", ipfs); writeToFile(TOKENS_PATH + tokenHash, token.getString(i), false); - deleteFile(LOGGER_PATH+"tempToken"); + deleteFile(LOGGER_PATH + "tempToken"); writeToFile(TOKENCHAIN_PATH + tokenHash + ".json", "[]", false); JSONObject temp = new JSONObject(); temp.put("tokenHash", tokenHash); @@ -283,21 +266,28 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON updateJSON("add", PAYMENTS_PATH + "BNK00.json", tempArray.toString()); } - writeToFile(jsonFilePath,records.toString(),false); -// FileWriter File = new FileWriter(jsonFilePath); -// File.write(records.toString()); -// File.close(); - ProofCreditsLogger.debug("Updated balance of node : " + (balance - creditUsed)); + String creditsHistory = readFile(WALLET_DATA_PATH + "MinedCreditsHistory.json"); + JSONArray creditsHistoryArray = new JSONArray(creditsHistory); + for (int i = 0; i < creditUsed; i++) + creditsHistoryArray.put(newQstArray.getJSONObject(i)); + writeToFile(String.valueOf(usedCreditsFile), creditsHistoryArray.toString(), false); + + + for (int i = 0; i < creditUsed; i++) + newQstArray.remove(i); + writeToFile(WALLET_DATA_PATH + "QuorumSignedTransactions.json", newQstArray.toString(), false); + + ProofCreditsLogger.debug("Updated balance of node : " + (availableCredits - creditUsed)); long endtime = System.currentTimeMillis(); - totalTime=endtime-starttime; + totalTime = endtime - starttime; Iterator keys = InitiatorConsensus.quorumSignature.keys(); JSONArray signedQuorumList = new JSONArray(); while (keys.hasNext()) signedQuorumList.put(keys.next()); - updateQuorum(quorumArray,signedQuorumList,true,type); - mineUpdate(receiverDidIpfsHash,creditUsed); + updateQuorum(quorumArray, signedQuorumList, true, type); + mineUpdate(receiverDidIpfsHash, creditUsed); APIResponse.put("did", receiverDidIpfsHash); APIResponse.put("tid", tid); APIResponse.put("token", token); @@ -305,7 +295,7 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON APIResponse.put("quorumlist", signedQuorumList); APIResponse.put("time", totalTime); APIResponse.put("status", "Success"); - APIResponse.put("message", token.length()+" tokens mined"); + APIResponse.put("message", token.length() + " tokens mined"); DateFormat formatter = new SimpleDateFormat("yyyy/MM/dd"); Date date = new Date(); @@ -314,7 +304,7 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON transactionRecord.put("role", "Sender"); transactionRecord.put("tokens", token); transactionRecord.put("txn", tid); - transactionRecord.put("quorumList",signedQuorumList); + transactionRecord.put("quorumList", signedQuorumList); transactionRecord.put("senderDID", receiverDidIpfsHash); transactionRecord.put("receiverDID", receiverDidIpfsHash); transactionRecord.put("Date", currentTime); @@ -349,14 +339,13 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON dataToSend.put("bank_id", "01"); dataToSend.put("user_did", receiverDidIpfsHash); dataToSend.put("token_id", token); - dataToSend.put("level",level); + dataToSend.put("level", level); dataToSend.put("denomination", 1); String populate = dataToSend.toString(); JSONObject jsonObject = new JSONObject(); jsonObject.put("inputString", populate); String postJsonData = jsonObject.toString(); - // Send post request connection_Explorer.setDoOutput(true); DataOutputStream wr = new DataOutputStream(connection_Explorer.getOutputStream()); @@ -385,7 +374,7 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON List tokenList = new ArrayList<>(); for (int i = 0; i < token.length(); i++) tokenList.add(token.getString(i)); - String urlTxn = EXPLORER_IP+"/CreateOrUpdateRubixTransaction"; + String urlTxn = EXPLORER_IP + "/CreateOrUpdateRubixTransaction"; URL objTxn = new URL(urlTxn); HttpsURLConnection conTxn = (HttpsURLConnection) objTxn.openConnection(); @@ -445,13 +434,11 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON ProofCreditsLogger.warn("error from mine service"); return APIResponse; } - } - else - { + } else { APIResponse.put("did", receiverDidIpfsHash); APIResponse.put("tid", "null"); APIResponse.put("status", "Failed"); - APIResponse.put("message", "Insufficent proofs"); + APIResponse.put("message", "Insufficient proofs"); ProofCreditsLogger.warn("Insufficient proof credits to mine"); return APIResponse; } diff --git a/src/com/rubix/TokenTransfer/TokenReceiver.java b/src/com/rubix/TokenTransfer/TokenReceiver.java index a89c1543..dd133fa1 100644 --- a/src/com/rubix/TokenTransfer/TokenReceiver.java +++ b/src/com/rubix/TokenTransfer/TokenReceiver.java @@ -2,7 +2,6 @@ import com.rubix.AuthenticateNode.Authenticate; import com.rubix.AuthenticateNode.PropImage; -import com.rubix.Resources.Functions; import com.rubix.Resources.IPFSNetwork; import io.ipfs.api.IPFS; import org.apache.log4j.Logger; @@ -17,12 +16,13 @@ import java.net.ServerSocket; import java.net.Socket; import java.text.DateFormat; -import java.text.ParseException; import java.text.SimpleDateFormat; import java.time.LocalDate; import java.util.ArrayList; +import java.util.Arrays; import java.util.Date; import java.util.Iterator; +import java.util.List; import static com.rubix.Resources.Functions.*; import static com.rubix.Resources.IPFSNetwork.*; @@ -55,10 +55,6 @@ public static String receive() { ArrayList quorumDID = new ArrayList<>(); PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); - DateFormat formatter = new SimpleDateFormat("yyyy/MM/dd"); - Date date = new Date(); - LocalDate currentTime = LocalDate.parse(formatter.format(date).replace("/", "-")); - String receiverPeerID = getPeerID(DATA_PATH + "DID.json"); String receiverDidIpfsHash = getValues(DATA_PATH + "DataTable.json", "didHash", "peerid", receiverPeerID); @@ -110,32 +106,24 @@ public static String receive() { ss.close(); return APIResponse.toString(); } - TokenReceiverLogger.debug("Sender details authenticated"); + // TokenReceiverLogger.debug("Sender details authenticated"); output.println("200"); String data = input.readLine(); - TokenReceiverLogger.debug("Token details received: " + data); - JSONArray TokenDetailsArray = new JSONArray(data); - JSONArray tokens = TokenDetailsArray.getJSONObject(0).getJSONArray("token"); - JSONArray tokenChains = TokenDetailsArray.getJSONObject(0).getJSONArray("tokenChain"); - String getCIDipfsHash = TokenDetailsArray.getJSONObject(1).getString("ipfsHash"); - TokenReceiverLogger.debug("Checking providers for: " + getCIDipfsHash); - ArrayList dhtOwnersList = dhtOwnerCheck(getCIDipfsHash); - TokenReceiverLogger.debug("Providers: " + dhtOwnersList); - TokenReceiverLogger.debug("IPFS get of consensusFile: " + getCIDipfsHash); - String consensusID = get(getCIDipfsHash, ipfs); - - + // TokenReceiverLogger.debug("Token details received: "); + JSONObject TokenDetails = new JSONObject(data); + JSONArray tokens = TokenDetails.getJSONArray("token"); + JSONArray tokenChains = TokenDetails.getJSONArray("tokenChain"); + JSONArray tokenHeader = TokenDetails.getJSONArray("tokenHeader"); int tokenCount = tokens.length(); - String senderToken = TokenDetailsArray.getJSONObject(0).toString(); - - String consensusIdCompare = calculateHash(senderToken, "SHA3-256"); -// writeToFile(LOGGER_PATH + "consensusID", consensusID, false); -// String consensusIDIPFSHash = IPFSNetwork.addHashOnly(LOGGER_PATH + "consensusID", ipfs); -// deleteFile(LOGGER_PATH + "consensusID"); - + String senderToken = TokenDetails.toString(); + + String consensusID = calculateHash(senderToken, "SHA3-256"); + writeToFile(LOGGER_PATH+"consensusID", consensusID, false); + String consensusIDIPFSHash = IPFSNetwork.addHashOnly(LOGGER_PATH + "consensusID", ipfs); + deleteFile(LOGGER_PATH+"consensusID"); //Check IPFS get for all Tokens int ipfsGetFlag = 0; @@ -148,59 +136,42 @@ public static String receive() { allTokenContent.add(TokenContent); ipfsGetFlag++; } - if(!consensusID.equals(consensusIdCompare)){ - String errorMessage = "Consensus ID not unique: Hashes do not match - " + "Sent " + consensusID + " Recalculated " + consensusIdCompare; - output.println("420"); - APIResponse.put("did", senderDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", errorMessage); - TokenReceiverLogger.debug(errorMessage); - executeIPFSCommands(" ipfs p2p close -t /p2p/" + senderPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); - } - else if(!(dhtOwnersList.size() <= 2 && dhtOwnersList.contains(senderPeerID))){ - String errorMessage = "Consensus ID not unique: " + dhtOwnersList.size() + " owns the hash " + dhtOwnersList; - output.println("421"); - APIResponse.put("did", senderDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", errorMessage); - TokenReceiverLogger.debug(errorMessage); - executeIPFSCommands(" ipfs p2p close -t /p2p/" + senderPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); + repo(ipfs); + + if (!IPFSNetwork.dhtEmpty(consensusIDIPFSHash, ipfs)) { + TokenReceiverLogger.debug("consensus ID not unique" + consensusIDIPFSHash); + output.println("420"); + APIResponse.put("did", senderDidIpfsHash); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Consensus ID not unique"); + TokenReceiverLogger.info("Consensus ID not unique"); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + senderPeerID); + output.close(); + input.close(); + sk.close(); + ss.close(); + return APIResponse.toString(); } - else if(!(ipfsGetFlag == tokenCount)){ - String errorMessage = "Tokens not verified"; - output.println("422"); - APIResponse.put("did", senderDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", errorMessage); - TokenReceiverLogger.debug(errorMessage); - executeIPFSCommands(" ipfs p2p close -t /p2p/" + senderPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); + if (!(ipfsGetFlag == tokenCount)) { + output.println("421"); + APIResponse.put("did", senderDidIpfsHash); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Tokens not verified"); + TokenReceiverLogger.info("Tokens not verified"); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + senderPeerID); + output.close(); + input.close(); + sk.close(); + ss.close(); + return APIResponse.toString(); } - - repo(ipfs); + output.println("200"); String senderDetails = input.readLine(); - - JSONObject SenderDetails = new JSONObject(senderDetails); String senderSignature = SenderDetails.getString("sign"); String tid = SenderDetails.getString("tid"); @@ -215,18 +186,19 @@ else if(!(ipfsGetFlag == tokenCount)){ TokenReceiverLogger.debug("Consensus Status: " + Status); + TokenReceiverLogger.debug("Verifying Quorum ... "); + TokenReceiverLogger.debug("Please wait, this might take a few seconds"); + if (!Status.equals("Consensus Failed")) { boolean yesQuorum = false; if (Status.equals("Consensus Reached")) { -// String QuorumDetails = input.readLine(); - - TokenReceiverLogger.debug("Quorum Signatures: " + QuorumDetails); + TokenReceiverLogger.debug("Quorum Signatures: " + QuorumDetails); quorumSignatures = new JSONObject(QuorumDetails); int alphaSize = quorumSignatures.length() - 10; - -// String selectQuorumHash = calculateHash(senderToken, "SHA3-256"); - - String verifyQuorumHash = calculateHash(getCIDipfsHash.concat(receiverDidIpfsHash), "SHA3-256"); + String selectQuorumHash = calculateHash(senderToken, "SHA3-256"); + String verifyQuorumHash = calculateHash(selectQuorumHash.concat(receiverDidIpfsHash), "SHA3-256"); + TokenReceiverLogger.debug("1: " + selectQuorumHash); + TokenReceiverLogger.debug("2: " + receiverDidIpfsHash); TokenReceiverLogger.debug("Quorum Hash on Receiver Side " + verifyQuorumHash); TokenReceiverLogger.debug("Quorum Signatures length : " + quorumSignatures.length()); @@ -244,9 +216,7 @@ else if(!(ipfsGetFlag == tokenCount)){ quorumDataFolder.mkdirs(); IPFSNetwork.getImage(quorumDidIpfsHash, ipfs, DATA_PATH + quorumDidIpfsHash + "/DID.png"); IPFSNetwork.getImage(quorumWidIpfsHash, ipfs, DATA_PATH + quorumDidIpfsHash + "/PublicShare.png"); - TokenReceiverLogger.debug("Quorum Data " + quorumDidIpfsHash + " Added"); - } else - TokenReceiverLogger.debug("Quorum Data " + quorumDidIpfsHash + " Available"); + } } for (int i = 0; i < quorumSignatures.length(); i++) { @@ -274,21 +244,20 @@ else if(!(ipfsGetFlag == tokenCount)){ detailsForVerify.put("signature", senderSignature); boolean yesSender = Authenticate.verifySignature(detailsForVerify.toString()); - TokenReceiverLogger.debug("Sender auth hash " + hash); TokenReceiverLogger.debug("Quorum Auth : " + yesQuorum + "Sender Auth : " + yesSender); if (!(yesSender && yesQuorum)) { - output.println("420"); - APIResponse.put("did", senderDidIpfsHash); - APIResponse.put("tid", tid); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Sender / Quorum not verified"); - TokenReceiverLogger.info("Sender / Quorum not verified"); - executeIPFSCommands(" ipfs p2p close -t /p2p/" + senderPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); + output.println("420"); + APIResponse.put("did", senderDidIpfsHash); + APIResponse.put("tid", tid); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Sender / Quorum not verified"); + TokenReceiverLogger.info("Sender / Quorum not verified"); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + senderPeerID); + output.close(); + input.close(); + sk.close(); + ss.close(); + return APIResponse.toString(); } repo(ipfs); @@ -361,6 +330,7 @@ else if(!(ipfsGetFlag == tokenCount)){ APIResponse.put("tid", tid); APIResponse.put("status", "Success"); APIResponse.put("tokens", tokens); + APIResponse.put("tokenHeader", tokenHeader); APIResponse.put("comment", comment); APIResponse.put("message", "Transaction Successful"); TokenReceiverLogger.info(" Transaction Successful"); diff --git a/src/com/rubix/TokenTransfer/TokenSender.java b/src/com/rubix/TokenTransfer/TokenSender.java index d95b8146..dd78a708 100644 --- a/src/com/rubix/TokenTransfer/TokenSender.java +++ b/src/com/rubix/TokenTransfer/TokenSender.java @@ -1,54 +1,81 @@ package com.rubix.TokenTransfer; -import com.rubix.AuthenticateNode.PropImage; -import com.rubix.Consensus.InitiatorConsensus; +import static com.rubix.Resources.Functions.DATA_PATH; +import static com.rubix.Resources.Functions.EXPLORER_IP; +import static com.rubix.Resources.Functions.LOGGER_PATH; +import static com.rubix.Resources.Functions.QuorumCheck; +import static com.rubix.Resources.Functions.QuorumSwarmConnect; +import static com.rubix.Resources.Functions.SEND_PORT; +import static com.rubix.Resources.Functions.TOKENCHAIN_PATH; +import static com.rubix.Resources.Functions.TOKENS_PATH; +import static com.rubix.Resources.Functions.WALLET_DATA_PATH; +import static com.rubix.Resources.Functions.calculateHash; +import static com.rubix.Resources.Functions.deleteFile; +import static com.rubix.Resources.Functions.getCurrentUtcTime; +import static com.rubix.Resources.Functions.getPeerID; +import static com.rubix.Resources.Functions.getQuorum; +import static com.rubix.Resources.Functions.getSignFromShares; +import static com.rubix.Resources.Functions.getValues; +import static com.rubix.Resources.Functions.minQuorum; +import static com.rubix.Resources.Functions.nodeData; +import static com.rubix.Resources.Functions.readFile; +import static com.rubix.Resources.Functions.updateJSON; +import static com.rubix.Resources.Functions.updateQuorum; +import static com.rubix.Resources.Functions.writeToFile; +import static com.rubix.Resources.IPFSNetwork.add; +import static com.rubix.Resources.IPFSNetwork.executeIPFSCommands; +import static com.rubix.Resources.IPFSNetwork.forward; +import static com.rubix.Resources.IPFSNetwork.repo; +import static com.rubix.Resources.IPFSNetwork.swarmConnectP2P; +import static com.rubix.Resources.IPFSNetwork.unpin; + +import java.io.BufferedReader; +import java.io.DataOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintStream; +import java.net.Socket; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import javax.net.ssl.HttpsURLConnection; + +import com.rubix.Consensus.InitiatorConsensus; import com.rubix.Consensus.InitiatorProcedure; -import com.rubix.Consensus.QuorumConsensus; -import com.rubix.Resources.Functions; import com.rubix.Resources.IPFSNetwork; -import io.ipfs.api.IPFS; + import org.apache.log4j.Logger; import org.apache.log4j.PropertyConfigurator; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; -import javax.imageio.ImageIO; -import javax.net.ssl.HttpsURLConnection; -import java.awt.image.BufferedImage; -import java.io.*; -import java.net.HttpURLConnection; -import java.net.Socket; -import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.security.NoSuchAlgorithmException; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.time.LocalDate; -import java.util.*; - -import static com.rubix.Resources.Functions.*; -import static com.rubix.Resources.IPFSNetwork.*; - +import io.ipfs.api.IPFS; public class TokenSender { private static final Logger TokenSenderLogger = Logger.getLogger(TokenSender.class); + private static final Logger eventLogger = Logger.getLogger("eventLogger"); + private static final String USER_AGENT = "Mozilla/5.0"; public static BufferedReader serverInput; private static PrintStream output; private static BufferedReader input; private static Socket senderSocket; private static boolean senderMutex = false; -// private static int heartBeatAlpha=0; -// private static int heartBeatBeta=0; -// private static int heartBeatGamma=0; -// private static int alphaSize=0; -// -// private static ArrayList alphaPeersList; -// private static ArrayList betaPeersList; -// private static ArrayList gammaPeersList; + // private static int heartBeatAlpha=0; + // private static int heartBeatBeta=0; + // private static int heartBeatGamma=0; + // private static int alphaSize=0; + // + // private static ArrayList alphaPeersList; + // private static ArrayList betaPeersList; + // private static ArrayList gammaPeersList; /** * A sender node to transfer tokens @@ -63,7 +90,6 @@ public class TokenSender { */ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception { - JSONObject APIResponse = new JSONObject(); PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); String receiverPeerId; @@ -93,19 +119,10 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception String senderDidIpfsHash = getValues(DATA_PATH + "DataTable.json", "didHash", "peerid", senderPeerID); TokenSenderLogger.debug("sender did ipfs hash" + senderDidIpfsHash); TokenSenderLogger.debug("path is" + DATA_PATH + senderDidIpfsHash); - File folder = new File(DATA_PATH + senderDidIpfsHash); - File[] listOfFiles = folder.listFiles(); - for (int i = 0; i < listOfFiles.length; i++) { - if (listOfFiles[i].isFile()) { - System.out.println("File " + listOfFiles[i].getName()); - } else if (listOfFiles[i].isDirectory()) { - System.out.println("Directory " + listOfFiles[i].getName()); - } - } - - BufferedImage senderWidImage = ImageIO.read(new File(DATA_PATH + senderDidIpfsHash + "/PublicShare.png")); - String senderWidBin = PropImage.img2bin(senderWidImage); + // BufferedImage senderWidImage = ImageIO.read(new File(DATA_PATH + + // senderDidIpfsHash + "/PublicShare.png")); + // String senderWidBin = PropImage.img2bin(senderWidImage); if (senderMutex) { APIResponse.put("did", senderDidIpfsHash); @@ -134,7 +151,7 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception for (int i = 0; i < tokens.length(); i++) { File token = new File(TOKENS_PATH + tokens.get(i)); File tokenchain = new File(TOKENCHAIN_PATH + tokens.get(i) + ".json"); - TokenSenderLogger.debug(token + "and " + tokenchain); + TokenSenderLogger.debug(token + " and " + tokenchain); if (!(token.exists() && tokenchain.exists())) { TokenSenderLogger.info("Tokens Not Verified"); senderMutex = false; @@ -145,12 +162,15 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception return APIResponse; } + // String hash = add(TOKENS_PATH + tokens.get(i), ipfs); + // pin(hash, ipfs); add(TOKENS_PATH + tokens.get(i), ipfs); String tokenChainHash = add(TOKENCHAIN_PATH + tokens.get(i) + ".json", ipfs); allTokensChainsPushed.add(tokenChainHash); } - String authSenderByRecHash = calculateHash(tokens.toString() + allTokensChainsPushed.toString() + receiverDidIpfsHash + comment, "SHA3-256"); + String authSenderByRecHash = calculateHash( + tokens.toString() + allTokensChainsPushed.toString() + receiverDidIpfsHash + comment, "SHA3-256"); String tid = calculateHash(authSenderByRecHash, "SHA3-256"); TokenSenderLogger.debug("Sender by Receiver Hash " + authSenderByRecHash); TokenSenderLogger.debug("TID on sender " + tid); @@ -163,7 +183,7 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception String gammaHash = IPFSNetwork.add(LOGGER_PATH + "tempgamma", ipfs); deleteFile(LOGGER_PATH + "tempgamma"); - + long startTime = System.currentTimeMillis(); switch (type) { case 1: { quorumArray = getQuorum(betaHash, gammaHash, senderDidIpfsHash, receiverDidIpfsHash, tokens.length()); @@ -186,8 +206,15 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception } } + long endTime = System.currentTimeMillis(); + long totalTime = endTime - startTime; + eventLogger.debug("Get Quorum List " + totalTime); + startTime = System.currentTimeMillis(); QuorumSwarmConnect(quorumArray, ipfs); + endTime = System.currentTimeMillis(); + totalTime = endTime - startTime; + eventLogger.debug("Swarm Connect " + totalTime); alphaSize = quorumArray.length() - 14; @@ -203,34 +230,49 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception TokenSenderLogger.debug("betaquorum " + betaQuorum + " size " + betaQuorum.length()); TokenSenderLogger.debug("gammaquorum " + gammaQuorum + " size " + gammaQuorum.length()); + // Commented by Anuradha K; A new method checkQuorum is implemented to check + // Quorum + /* + * alphaPeersList=QuorumCheck(alphaQuorum,ipfs,alphaSize); betaPeersList= + * QuorumCheck(betaQuorum,ipfs,7); + * gammaPeersList=QuorumCheck(gammaQuorum,ipfs,7); + */ + startTime = System.currentTimeMillis(); alphaPeersList = QuorumCheck(alphaQuorum, alphaSize); betaPeersList = QuorumCheck(betaQuorum, 7); gammaPeersList = QuorumCheck(gammaQuorum, 7); -// for(int i=0;i= minQuorum(7))) { + // if (!(InitiatorProcedure.alphaReply.length() >= minQuorum(7))) { TokenSenderLogger.debug("Consensus Failed"); senderDetails2Receiver.put("status", "Consensus Failed"); senderDetails2Receiver.put("quorumsign", InitiatorConsensus.quorumSignature.toString()); @@ -408,9 +447,9 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception // output.println(InitiatorConsensus.quorumSignature); String signatureAuth = input.readLine(); - - long endAuth = System.currentTimeMillis(); - long totalTime = endAuth - startTime; + TokenSenderLogger.info("signatureAuth : " + signatureAuth); + endTime = System.currentTimeMillis(); + totalTime = endTime - startTime; if (!signatureAuth.equals("200")) { executeIPFSCommands(" ipfs p2p close -t /p2p/" + receiverPeerId); TokenSenderLogger.info("Authentication Failed"); @@ -430,14 +469,13 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception for (int i = 0; i < tokens.length(); i++) unpin(String.valueOf(tokens.get(i)), ipfs); - unpin(consensusIDIPFSHash, ipfs); - + // unpin(consensusIDIPFSHash, ipfs); repo(ipfs); TokenSenderLogger.debug("Unpinned Tokens"); output.println("Unpinned"); - String confirmation = input.readLine(); + if (!confirmation.equals("Successfully Pinned")) { TokenSenderLogger.warn("Multiple Owners for the token"); executeIPFSCommands(" ipfs p2p close -t /p2p/" + receiverPeerId); @@ -500,17 +538,17 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception transactionRecord.put("comment", comment); transactionRecord.put("essentialShare", InitiatorProcedure.essential); - JSONArray transactionHistoryEntry = new JSONArray(); transactionHistoryEntry.put(transactionRecord); + updateJSON("add", WALLET_DATA_PATH + "TransactionHistory.json", transactionHistoryEntry.toString()); for (int i = 0; i < tokens.length(); i++) Files.deleteIfExists(Paths.get(TOKENS_PATH + tokens.get(i))); - - //Populating data to explorer + // Populating data to explorer if (!EXPLORER_IP.contains("127.0.0.1")) { + startTime = System.currentTimeMillis(); List tokenList = new ArrayList<>(); for (int i = 0; i < tokens.length(); i++) tokenList.add(tokens.getString(i)); @@ -561,49 +599,55 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception } in.close(); + endTime = System.currentTimeMillis(); TokenSenderLogger.debug(response.toString()); } -// -// if (type==1) { -// String urlQuorumUpdate = SYNC_IP+"/updateQuorum"; -// URL objQuorumUpdate = new URL(urlQuorumUpdate); -// HttpURLConnection conQuorumUpdate = (HttpURLConnection) objQuorumUpdate.openConnection(); -// -// conQuorumUpdate.setRequestMethod("POST"); -// conQuorumUpdate.setRequestProperty("Accept-Language", "en-US,en;q=0.5"); -// conQuorumUpdate.setRequestProperty("Accept", "application/json"); -// conQuorumUpdate.setRequestProperty("Content-Type", "application/json"); -// conQuorumUpdate.setRequestProperty("Authorization", "null"); -// -// JSONObject dataToSendQuorumUpdate = new JSONObject(); -// dataToSendQuorumUpdate.put("completequorum", quorumArray); -// dataToSendQuorumUpdate.put("signedquorum",signedQuorumList); -// String populateQuorumUpdate = dataToSendQuorumUpdate.toString(); -// -// conQuorumUpdate.setDoOutput(true); -// DataOutputStream wrQuorumUpdate = new DataOutputStream(conQuorumUpdate.getOutputStream()); -// wrQuorumUpdate.writeBytes(populateQuorumUpdate); -// wrQuorumUpdate.flush(); -// wrQuorumUpdate.close(); -// -// int responseCodeQuorumUpdate = conQuorumUpdate.getResponseCode(); -// TokenSenderLogger.debug("Sending 'POST' request to URL : " + urlQuorumUpdate); -// TokenSenderLogger.debug("Post Data : " + populateQuorumUpdate); -// TokenSenderLogger.debug("Response Code : " + responseCodeQuorumUpdate); -// -// BufferedReader inQuorumUpdate = new BufferedReader( -// new InputStreamReader(conQuorumUpdate.getInputStream())); -// String outputQuorumUpdate; -// StringBuffer responseQuorumUpdate = new StringBuffer(); -// while ((outputQuorumUpdate = inQuorumUpdate.readLine()) != null) { -// responseQuorumUpdate.append(outputQuorumUpdate); -// } -// inQuorumUpdate.close(); -// -// } + // + // if (type==1) { + // String urlQuorumUpdate = SYNC_IP+"/updateQuorum"; + // URL objQuorumUpdate = new URL(urlQuorumUpdate); + // HttpURLConnection conQuorumUpdate = (HttpURLConnection) + // objQuorumUpdate.openConnection(); + // + // conQuorumUpdate.setRequestMethod("POST"); + // conQuorumUpdate.setRequestProperty("Accept-Language", "en-US,en;q=0.5"); + // conQuorumUpdate.setRequestProperty("Accept", "application/json"); + // conQuorumUpdate.setRequestProperty("Content-Type", "application/json"); + // conQuorumUpdate.setRequestProperty("Authorization", "null"); + // + // JSONObject dataToSendQuorumUpdate = new JSONObject(); + // dataToSendQuorumUpdate.put("completequorum", quorumArray); + // dataToSendQuorumUpdate.put("signedquorum",signedQuorumList); + // String populateQuorumUpdate = dataToSendQuorumUpdate.toString(); + // + // conQuorumUpdate.setDoOutput(true); + // DataOutputStream wrQuorumUpdate = new + // DataOutputStream(conQuorumUpdate.getOutputStream()); + // wrQuorumUpdate.writeBytes(populateQuorumUpdate); + // wrQuorumUpdate.flush(); + // wrQuorumUpdate.close(); + // + // int responseCodeQuorumUpdate = conQuorumUpdate.getResponseCode(); + // TokenSenderLogger.debug("Sending 'POST' request to URL : " + + // urlQuorumUpdate); + // TokenSenderLogger.debug("Post Data : " + populateQuorumUpdate); + // TokenSenderLogger.debug("Response Code : " + responseCodeQuorumUpdate); + // + // BufferedReader inQuorumUpdate = new BufferedReader( + // new InputStreamReader(conQuorumUpdate.getInputStream())); + // String outputQuorumUpdate; + // StringBuffer responseQuorumUpdate = new StringBuffer(); + // while ((outputQuorumUpdate = inQuorumUpdate.readLine()) != null) { + // responseQuorumUpdate.append(outputQuorumUpdate); + // } + // inQuorumUpdate.close(); + // + // } TokenSenderLogger.info("Transaction Successful"); + // System.out.println("Verify Count: " + Authenticate.verifyCount); + // Authenticate.verifyCount = 0; executeIPFSCommands(" ipfs p2p close -t /p2p/" + receiverPeerId); output.close(); input.close(); From 7a550990b5c730ea8f10ffcf3cff03fb0ce1f329 Mon Sep 17 00:00:00 2001 From: Gokul P S Date: Thu, 23 Dec 2021 17:20:35 +0530 Subject: [PATCH 12/49] Check if the sender is available for transcation --- src/com/rubix/TokenTransfer/TokenSender.java | 117 +++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/src/com/rubix/TokenTransfer/TokenSender.java b/src/com/rubix/TokenTransfer/TokenSender.java index d95b8146..9581b8b2 100644 --- a/src/com/rubix/TokenTransfer/TokenSender.java +++ b/src/com/rubix/TokenTransfer/TokenSender.java @@ -61,6 +61,123 @@ public class TokenSender { * @throws JSONException handles JSON Exceptions * @throws NoSuchAlgorithmException handles No Such Algorithm Exceptions */ + + + public static boolean PingPong(){ + + boolean flag = false; + boolean integrityCheck=true; + String temp, peerID, transactionID, verifySenderHash, receiverDID, receiverPID, appName, senderPrivatePos, senderDidIpfsHash="", senderPID = ""; + ServerSocket serverSocket = null; + Socket socket = null; + try { + + peerID = getPeerID(DATA_PATH + "DID.json"); + String didHash = getValues(DATA_PATH + "DataTable.json", "didHash", "peerid", peerID); + appName = peerID.concat(role); + + listen(appName, port); + + TokenSenderLogger.debug("Quorum Listening on " + port + " appname "+appName); + serverSocket = new ServerSocket(port); + socket = serverSocket.accept(); + + BufferedReader dataReq = new BufferedReader(new InputStreamReader(socket.getInputStream())); + BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); + PrintStream dataResp = new PrintStream(socket.getOutputStream()); + PrintStream out = new PrintStream(socket.getOutputStream()); + + JSONObject readSenderData; + String getData; + String qstReq; + + //? check for incoming request for QST + + qstReq = dataReq.readLine(); + if (qstReq.contains("qstcmrequest")) { + + TokenSenderLogger.debug("Sender reqesting QuorumSignedTransactions.json and CreditMapping.json: " + qstReq); + + JSONArray qstContent = new JSONArray(readFile(WALLET_DATA_PATH + "QuorumSignedTransactions.json")); + JSONObject qstObjectSend; + JSONArray creditsArray = new JSONArray(); + String credits = ""; + if(qstContent.length() > 0) { + qstObjectSend = qstContent.getJSONObject(qstContent.length() - 1); + if(qstObjectSend.has("minestatus")) { + credits = qstObjectSend.getString("credits"); + if (!credits.equals("")) { + String creditContent = IPFSNetwork.get(credits, ipfs); + creditsArray = new JSONArray(creditContent); + } + } + } + + String cmFile = readFile(WALLET_DATA_PATH + "CreditMapping.json"); + JSONArray creditsMappingArray = new JSONArray(cmFile); + JSONObject qResponse = new JSONObject(); + qResponse.put("Credits", creditsArray.toString()); + qResponse.put("CreditMapping", creditsMappingArray.toString()); + + dataResp.println(qResponse.toString()); + } + + getData = in.readLine(); + if (getData.contains("ping check")) { + TokenSenderLogger.debug("Ping check from sender: " + getData); + out.println("pong response"); + } + else { + TokenSenderLogger.debug("Received Details from initiator: " + getData); + readSenderData = new JSONObject(getData); + senderPrivatePos = readSenderData.getString("sign"); + senderDidIpfsHash = readSenderData.getString("senderDID"); + transactionID = readSenderData.getString("Tid"); + verifySenderHash = readSenderData.getString("Hash"); + receiverDID = readSenderData.getString("RID"); + + senderPID = getValues(DATA_PATH + "DataTable.json", "peerid", "didHash", senderDidIpfsHash); + receiverPID = getValues(DATA_PATH + "DataTable.json", "peerid", "didHash", receiverDID); + + String senderWidIpfsHash = getValues(DATA_PATH + "DataTable.json", "walletHash", "didHash", senderDidIpfsHash); + + nodeData(senderDidIpfsHash, senderWidIpfsHash, ipfs); + String quorumHash = calculateHash(verifySenderHash.concat(receiverDID), "SHA3-256"); + + + TokenSenderLogger.debug("Checking providers for: " + verifySenderHash); + ArrayList dhtOwnersList = dhtOwnerCheck(verifySenderHash); + TokenSenderLogger.debug("Providers: " + dhtOwnersList); + boolean consensusIDcheck = false; + if(dhtOwnersList.size() <= 2 && dhtOwnersList.contains(senderPID)) + consensusIDcheck = true; + } + } catch (IOException e) { + TokenSenderLogger.error("IOException Occurred", e); + } catch (JSONException e) { + TokenSenderLogger.error("JSONException Occurred", e); + } catch (NullPointerException | InterruptedException e) { + TokenSenderLogger.error("NullPointer Exception Occurred ",e); + } + + finally{ + try { + socket.close(); + serverSocket.close(); + executeIPFSCommands(" ipfs p2p close -t /p2p/" + senderPID); + } catch (IOException e) { + executeIPFSCommands(" ipfs p2p close -t /p2p/" + senderPID); + TokenSenderLogger.error("IOException Occurred", e); + } + + } + + + + return flag; + } + + public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception { From 7e404086f048ecd737b3334d65375d961d845267 Mon Sep 17 00:00:00 2001 From: KiranHRubix Date: Tue, 28 Dec 2021 13:02:25 +0530 Subject: [PATCH 13/49] removed ekey and dkey in seller class --- src/com/rubix/NFT/Seller.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/com/rubix/NFT/Seller.java b/src/com/rubix/NFT/Seller.java index f393c9bc..359f9245 100644 --- a/src/com/rubix/NFT/Seller.java +++ b/src/com/rubix/NFT/Seller.java @@ -465,8 +465,8 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception nftTransactionRecord.put("amount", amount); nftTransactionRecord.put("rbxTokens", rbxTokens); nftTransactionRecord.put("nftToken", nftTokenIpfsHash); - nftTransactionRecord.put("eKey", eKey); - nftTransactionRecord.put("dKey", dKey); + //nftTransactionRecord.put("eKey", eKey); + //nftTransactionRecord.put("dKey", dKey); nftTransactionRecord.put("txn", tid); nftTransactionRecord.put("quorumList", signedQuorumList); nftTransactionRecord.put("Date", Functions.getCurrentUtcTime()); From 340ed0915174df0a561c6e6182612982a4c43f9e Mon Sep 17 00:00:00 2001 From: KiranHRubix Date: Tue, 28 Dec 2021 13:06:01 +0530 Subject: [PATCH 14/49] updated Buyer class --- src/com/rubix/NFT/Buyer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/com/rubix/NFT/Buyer.java b/src/com/rubix/NFT/Buyer.java index ee1dbc2b..3d7cbec8 100644 --- a/src/com/rubix/NFT/Buyer.java +++ b/src/com/rubix/NFT/Buyer.java @@ -179,7 +179,7 @@ public static String receive() { rbxTokenDetails.put("rbxTokenChains", rbxTokensChainsPushed); rbxTokenDetails.put("rbxTokenHeader", rbxTokenHeader); String pvt = Functions.DATA_PATH+ buyerDidIpfsHash + "PrivateShare.png"; - String buyerSign = Functions.getSignFromShares(pvt, Functions.calculateHash(rbxTokens + rbxTokenHeader + rbxTokensChainsPushed.toString(), "SHA3-256")); + String buyerSign = Functions.getSignFromShares(pvt, Functions.calculateHash(rbxTokens.toString() + rbxTokenHeader.toString() + rbxTokensChainsPushed.toString(), "SHA3-256")); JSONObject rbxData = new JSONObject(); rbxData.put("rbxTokenDetails", rbxTokenDetails); rbxData.put("authBuyerBySeller", buyerSign); @@ -342,7 +342,7 @@ public static String receive() { Functions.updateJSON("add", Functions.WALLET_DATA_PATH + "nftTransactionHistory.json", nftTransactionHistoryEntry.toString()); int k; for (k = 0; k < rbxTokens.length(); k++) - Files.deleteIfExists(Paths.get(Functions.TOKENS_PATH+rbxTokens.get(i), new String[0])); + Files.deleteIfExists(Paths.get(Functions.TOKENS_PATH+rbxTokens.get(k), new String[0])); for (k = 0; k < amount; k++) Functions.updateJSON("remove", Functions.PAYMENTS_PATH+rbxTokenHeader.getString(k), rbxTokens.getString(k)); BuyerLogger.info("Transaction ID: " + tid + "Transaction Successful"); From 930e6f1b516f0f323d261ba2b64184dbeea1ef0f Mon Sep 17 00:00:00 2001 From: Nidhin Mahesh A Date: Wed, 16 Feb 2022 16:46:17 +0530 Subject: [PATCH 15/49] updated code Signed-off-by: Nidhin Mahesh A --- .../rubix/AuthenticateNode/Authenticate.java | 68 +- .../rubix/Consensus/InitiatorConsensus.java | 249 ++---- .../rubix/Consensus/InitiatorProcedure.java | 51 +- src/com/rubix/Consensus/QuorumConsensus.java | 192 +--- src/com/rubix/Mining/ProofCredits.java | 102 +-- src/com/rubix/Ping/PingCheck.java | 97 +++ src/com/rubix/Ping/PingReceive.java | 91 ++ src/com/rubix/Ping/QuorumPingReceive.java | 96 ++ src/com/rubix/Resources/APIHandler.java | 822 +++++++++--------- src/com/rubix/Resources/Functions.java | 619 ++++++++----- src/com/rubix/Resources/IPFSNetwork.java | 7 +- .../rubix/TokenTransfer/TokenReceiver.java | 174 ++-- src/com/rubix/TokenTransfer/TokenSender.java | 80 +- 13 files changed, 1368 insertions(+), 1280 deletions(-) create mode 100644 src/com/rubix/Ping/PingCheck.java create mode 100644 src/com/rubix/Ping/PingReceive.java create mode 100644 src/com/rubix/Ping/QuorumPingReceive.java diff --git a/src/com/rubix/AuthenticateNode/Authenticate.java b/src/com/rubix/AuthenticateNode/Authenticate.java index 5218b56c..0631faa0 100644 --- a/src/com/rubix/AuthenticateNode/Authenticate.java +++ b/src/com/rubix/AuthenticateNode/Authenticate.java @@ -1,79 +1,43 @@ package com.rubix.AuthenticateNode; -import static com.rubix.Resources.Functions.DATA_PATH; -import static com.rubix.Resources.Functions.IPFS_PORT; -import static com.rubix.Resources.Functions.LOGGER_PATH; -import static com.rubix.Resources.Functions.getValues; -import static com.rubix.Resources.Functions.nodeData; -import static com.rubix.Resources.Functions.randomPositions; -import static com.rubix.Resources.Functions.strToIntArray; -import static com.rubix.Resources.Functions.syncDataTable; +import io.ipfs.api.IPFS; +import org.apache.log4j.Logger; +import org.apache.log4j.PropertyConfigurator; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; -import javax.imageio.ImageIO; - -import org.apache.log4j.Logger; -import org.apache.log4j.PropertyConfigurator; -import org.json.JSONException; -import org.json.JSONObject; +import static com.rubix.Resources.APIHandler.networkInfo; +import static com.rubix.Resources.Functions.*; -import io.ipfs.api.IPFS; public class Authenticate { public static Logger AuthenticateLogger = Logger.getLogger(Authenticate.class); public static int verifyCount = 0; /** - * This method is used to authenticate a node in Rubix implementing text based - * two level NLSS. - *

- * It is customized for 32 positions verification. The position can be changed - * by + * This method is used to authenticate a node in Rubix implementing text based two level NLSS. + *

It is customized for 32 positions verification. The position can be changed by * modifying the numberofpositions for integer array sizes accordingly - * * @param detailString Details for verification * @return boolean returns true if verified and false if not verified - * @throws IOException handles IO Exception + * @throws IOException handles IO Exception * @throws JSONException handles JSON Exception */ public static boolean verifySignature(String detailString) throws IOException, JSONException { PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); - verifyCount++; IPFS ipfs = new IPFS("/ip4/127.0.0.1/tcp/" + IPFS_PORT); JSONObject details = new JSONObject(detailString); String decentralizedID = details.getString("did"); String hash = details.getString("hash"); - - String quorumSign; - String tokenSign; - String TIDSign; - JSONObject signs = new JSONObject(); - - if (details.optJSONObject(quorumSign) != null) { - - JSONObject signatureObject = details.getJSONObject("signatures"); - quorumSign = signatureObject.getString("QuorumSign"); - tokenSign = signatureObject.getString("TokenSign"); - TIDSign = signatureObject.getString("TIDSign"); - - signs.put(tokenSign, false); - signs.put(quorumSign, false); - signs.put(TIDSign, false); - - } else { - // make all three params in JSONObject signs as true - signs.put(quorumSign, false); - signs.put(tokenSign, true); - signs.put(TIDSign, true); - - quorumSign = details.getString("signature"); - } - + String signature = details.getString("signature"); syncDataTable(decentralizedID, null); String walletIdIpfsHash = getValues(DATA_PATH + "DataTable.json", "walletHash", "didHash", decentralizedID); nodeData(decentralizedID, walletIdIpfsHash, ipfs); @@ -87,7 +51,7 @@ public static boolean verifySignature(String detailString) throws IOException, J int[] SenderSign = strToIntArray(signature); JSONObject P = randomPositions("verifier", hash, 32, SenderSign); int[] posForSign = (int[]) P.get("posForSign"); - int[] originalPos = (int[]) P.get("originalPos"); + int[] originalPos =(int[]) P.get("originalPos"); for (int positionsLevelTwoTrail : posForSign) senderWalletID.append(walletID.charAt(positionsLevelTwoTrail)); @@ -98,8 +62,7 @@ public static boolean verifySignature(String detailString) throws IOException, J positionsLevelZero[k] = ((originalPos[k]) / 8); StringBuilder decentralizedIDForAuth = new StringBuilder(); - for (int value : positionsLevelZero) - decentralizedIDForAuth.append(senderDIDBin.charAt(value)); + for (int value : positionsLevelZero) decentralizedIDForAuth.append(senderDIDBin.charAt(value)); if (recombinedResult.equals(decentralizedIDForAuth.toString())) { return true; } else { @@ -110,3 +73,4 @@ public static boolean verifySignature(String detailString) throws IOException, J } } + diff --git a/src/com/rubix/Consensus/InitiatorConsensus.java b/src/com/rubix/Consensus/InitiatorConsensus.java index d030dcfa..e5ab5055 100644 --- a/src/com/rubix/Consensus/InitiatorConsensus.java +++ b/src/com/rubix/Consensus/InitiatorConsensus.java @@ -1,19 +1,15 @@ package com.rubix.Consensus; -import static com.rubix.Resources.Functions.DATA_PATH; -import static com.rubix.Resources.Functions.LOGGER_PATH; -import static com.rubix.Resources.Functions.QUORUM_COUNT; -import static com.rubix.Resources.Functions.checkTokenOwnershiByDID; -import static com.rubix.Resources.Functions.getValues; -import static com.rubix.Resources.Functions.minQuorum; -import static com.rubix.Resources.Functions.nodeData; -import static com.rubix.Resources.Functions.syncDataTable; -import static com.rubix.Resources.IPFSNetwork.forward; -import static com.rubix.Resources.IPFSNetwork.repo; -import static com.rubix.Resources.IPFSNetwork.swarmConnectP2P; +import com.rubix.AuthenticateNode.Authenticate; +import com.rubix.Resources.IPFSNetwork; +import io.ipfs.api.IPFS; +import org.apache.log4j.Logger; +import org.apache.log4j.PropertyConfigurator; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; import java.io.BufferedReader; -import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; @@ -21,27 +17,20 @@ import java.net.SocketException; import java.util.ArrayList; -import com.rubix.AuthenticateNode.Authenticate; -import com.rubix.Resources.Functions; -import com.rubix.Resources.IPFSNetwork; +import static com.rubix.Resources.Functions.*; +import static com.rubix.Resources.IPFSNetwork.*; -import org.apache.log4j.Logger; -import org.apache.log4j.PropertyConfigurator; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import io.ipfs.api.IPFS; public class InitiatorConsensus { public static Logger InitiatorConsensusLogger = Logger.getLogger(InitiatorConsensus.class); + public static volatile JSONObject quorumSignature = new JSONObject(); private static final Object countLock = new Object(); private static final Object signLock = new Object(); public static ArrayList quorumWithShares = new ArrayList<>(); - public static volatile int[] quorumResponse = { 0, 0, 0 }; + public static volatile int[] quorumResponse = {0, 0, 0}; public static volatile JSONArray finalQuorumSignsArray = new JSONArray(); /** @@ -59,8 +48,7 @@ private static synchronized boolean voteNCount(int i, int quorumSize) { synchronized (countLock) { if (quorumResponse[i] < minQuorum(quorumSize)) { quorumResponse[i]++; - InitiatorConsensusLogger.debug("quorum response added index " + i + " is " + quorumResponse[i] - + " quorumsize " + minQuorum(quorumSize)); + InitiatorConsensusLogger.debug("quorum response added index " + i + " is " + quorumResponse[i] + " quorumsize " + minQuorum(quorumSize)); status = true; } else { status = false; @@ -70,40 +58,18 @@ private static synchronized boolean voteNCount(int i, int quorumSize) { return status; } - /** - * This method increments the quorumResponse variable - */ - private static synchronized boolean selectStakingQuorum(String DID) { - boolean status; - PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); - synchronized (countLock) { - if (quorumResponse[i] < minQuorum(quorumSize)) { - quorumResponse[i]++; - InitiatorConsensusLogger.debug("quorum response added index " + i + " is " + quorumResponse[i] - + " quorumsize " + minQuorum(quorumSize)); - status = true; - } else { - status = false; - InitiatorConsensusLogger.debug("Staking Reached"); - } - } - return status; - } /** - * This method stores all the quorum signatures until required count for - * consensus + * This method stores all the quorum signatures until required count for consensus * * @param quorumDID DID of the Quorum * @param quorumSignResponse Signature of the Quorum */ - private static synchronized void quorumSign(String quorumDID, String hash, String quorumSignResponse, int index, - int quorumSize, int alphaSize) { + private static synchronized void quorumSign(String quorumDID, String hash, String quorumSignResponse, int index, int quorumSize, int alphaSize) { PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); synchronized (signLock) { try { - if (quorumSignature.length() < (minQuorum(alphaSize) + 2 * minQuorum(7)) - && quorumResponse[index] <= minQuorum(quorumSize)) { + if (quorumSignature.length() < (minQuorum(alphaSize) + 2 * minQuorum(7)) && quorumResponse[index] <= minQuorum(quorumSize)) { JSONObject jsonObject = new JSONObject(); jsonObject.put("did", quorumDID); jsonObject.put("signature", quorumSignResponse); @@ -120,6 +86,7 @@ private static synchronized void quorumSign(String quorumDID, String hash, Strin } } + /** * This method runs the consensus * 1. Contact quorum with sender signatures and details @@ -129,14 +96,12 @@ private static synchronized void quorumSign(String quorumDID, String hash, Strin * @param ipfs IPFS instance * @param PORT Port for forwarding to Quorum */ - public static JSONObject start(String data, IPFS ipfs, int PORT, int index, String role, - JSONArray quorumPeersObject, int alphaSize, int quorumSize, String operation) throws JSONException { + public static JSONObject start(String data, IPFS ipfs, int PORT, int index, String role, JSONArray quorumPeersObject, int alphaSize, int quorumSize, String operation) throws JSONException { String[] qResponse = new String[QUORUM_COUNT]; Socket[] qSocket = new Socket[QUORUM_COUNT]; PrintStream[] qOut = new PrintStream[QUORUM_COUNT]; BufferedReader[] qIn = new BufferedReader[QUORUM_COUNT]; String[] quorumID = new String[QUORUM_COUNT]; - String[] signedAlphaQuorumID = new String[minQuorum(7)]; PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); JSONObject dataObject = new JSONObject(data); String hash = dataObject.getString("hash"); @@ -166,17 +131,13 @@ public static JSONObject start(String data, IPFS ipfs, int PORT, int index, Stri try { swarmConnectP2P(quorumID[j], ipfs); syncDataTable(null, quorumID[j]); - String quorumDidIpfsHash = getValues(DATA_PATH + "DataTable.json", "didHash", "peerid", - quorumID[j]); - - String quorumWidIpfsHash = getValues(DATA_PATH + "DataTable.json", "walletHash", "peerid", - quorumID[j]); + String quorumDidIpfsHash = getValues(DATA_PATH + "DataTable.json", "didHash", "peerid", quorumID[j]); + String quorumWidIpfsHash = getValues(DATA_PATH + "DataTable.json", "walletHash", "peerid", quorumID[j]); nodeData(quorumDidIpfsHash, quorumWidIpfsHash, ipfs); String appName = quorumID[j].concat(role); InitiatorConsensusLogger.debug("quourm ID " + quorumID[j] + " appname " + appName); forward(appName, PORT + j, quorumID[j]); - InitiatorConsensusLogger.debug( - "Connected to " + quorumID[j] + "on port " + (PORT + j) + "with AppName" + appName); + InitiatorConsensusLogger.debug("Connected to " + quorumID[j] + "on port " + (PORT + j) + "with AppName" + appName); qSocket[j] = new Socket("127.0.0.1", PORT + j); qSocket[j].setSoTimeout(socketTimeOut); @@ -186,9 +147,8 @@ public static JSONObject start(String data, IPFS ipfs, int PORT, int index, Stri qOut[j].println(operation); if (operation.equals("new-credits-mining")) { - - // ? QST + credit info JSONObject qstDetails = dataObject.getJSONObject("qstDetails"); + //Verify QST Credits qOut[j].println(qstDetails.toString()); try { qResponse[j] = qIn[j].readLine(); @@ -196,74 +156,53 @@ public static JSONObject start(String data, IPFS ipfs, int PORT, int index, Stri InitiatorConsensusLogger.warn("Quorum " + quorumID[j] + " is unable to Respond!"); IPFSNetwork.executeIPFSCommands("ipfs p2p close -t /p2p/" + quorumID[j]); } - if (qResponse[j] != null) { + if(qResponse[j] != null) { if (qResponse[j].equals("Verified")) { - - // ! let all quorum mems know who is staking and use it in signature - detailsToken.put("stakingQuorumPeerID", quorumID[0]); qOut[j].println(detailsToken); try { qResponse[j] = qIn[j].readLine(); } catch (SocketException e) { - InitiatorConsensusLogger - .warn("Quorum " + quorumID[j] + " is unable to Respond!"); + InitiatorConsensusLogger.warn("Quorum " + quorumID[j] + " is unable to Respond!"); IPFSNetwork.executeIPFSCommands("ipfs p2p close -t /p2p/" + quorumID[j]); } - if (qResponse[j] != null) { + if(qResponse[j] != null) { if (qResponse[j].equals("Auth_Failed")) { IPFSNetwork.executeIPFSCommands("ipfs p2p close -t /p2p/" + quorumID[j]); } else { - InitiatorConsensusLogger.trace( - "Signature Received from Q" + j + "(" + quorumID[j] + ") : " - + qResponse[j]); + InitiatorConsensusLogger.debug("Signature Received from " + quorumID[j] + " " + qResponse[j]); if (quorumResponse[index] > minQuorum(quorumSize)) { qOut[j].println("null"); - IPFSNetwork - .executeIPFSCommands("ipfs p2p close -t /p2p/" + quorumID[j]); + IPFSNetwork.executeIPFSCommands("ipfs p2p close -t /p2p/" + quorumID[j]); } else { - String didHash = getValues(DATA_PATH + "DataTable.json", "didHash", - "peerid", quorumID[j]); + String didHash = getValues(DATA_PATH + "DataTable.json", "didHash", "peerid", quorumID[j]); JSONObject detailsToVerify = new JSONObject(); detailsToVerify.put("did", didHash); detailsToVerify.put("hash", hash); detailsToVerify.put("signature", qResponse[j]); if (Authenticate.verifySignature(detailsToVerify.toString())) { - InitiatorConsensusLogger - .debug(role + " node authenticated at index " + index); + InitiatorConsensusLogger.debug(role + " node authenticated at index " + index); boolean voteStatus = voteNCount(index, quorumSize); if (quorumResponse[index] <= minQuorum(quorumSize) && voteStatus) { - InitiatorConsensusLogger.debug( - "waiting for " + quorumSize + " +signs " + role); + InitiatorConsensusLogger.debug("waiting for " + quorumSize + " +signs " + role); while (quorumResponse[index] < minQuorum(quorumSize)) { } - InitiatorConsensusLogger.debug("between Q1- to Q" + quorumSize - + " for index " + index); - quorumSign(didHash, hash, qResponse[j], index, quorumSize, - alphaSize); + InitiatorConsensusLogger.debug("between Q1- to Q" + quorumSize + " for index " + index); + quorumSign(didHash, hash, qResponse[j], index, quorumSize, alphaSize); quorumWithShares.add(quorumPeersObject.getString(j)); - while (quorumSignature - .length() < (minQuorum(alphaSize) + 2 * minQuorum(7))) { + while (quorumSignature.length() < (minQuorum(alphaSize) + 2 * minQuorum(7))) { } - InitiatorConsensusLogger.debug("sending Qsign of length " - + quorumSignature.length() + "at index " + index); + InitiatorConsensusLogger.debug("sending Qsign of length " + quorumSignature.length() + "at index " + index); qOut[j].println(finalQuorumSignsArray.toString()); - IPFSNetwork.executeIPFSCommands( - "ipfs p2p close -t /p2p/" + quorumID[j]); + IPFSNetwork.executeIPFSCommands("ipfs p2p close -t /p2p/" + quorumID[j]); } else { InitiatorConsensusLogger.debug("sending null for slow quorum "); qOut[j].println("null"); - IPFSNetwork.executeIPFSCommands( - "ipfs p2p close -t /p2p/" + quorumID[j]); + IPFSNetwork.executeIPFSCommands("ipfs p2p close -t /p2p/" + quorumID[j]); } - InitiatorConsensusLogger.debug("Quorum Count : " + quorumResponse - + "Signature count : " + quorumSignature.length()); + InitiatorConsensusLogger.debug("Quorum Count : " + quorumResponse + "Signature count : " + quorumSignature.length()); } else { - InitiatorConsensusLogger - .debug("node failed authentication with index " + index - + " with role " + role + " with did " + didHash - + " and data to verify " + detailsToVerify); - IPFSNetwork.executeIPFSCommands( - "ipfs p2p close -t /p2p/" + quorumID[j]); + InitiatorConsensusLogger.debug("node failed authentication with index " + index + " with role " + role + " with did " + didHash + " and data to verify " + detailsToVerify); + IPFSNetwork.executeIPFSCommands("ipfs p2p close -t /p2p/" + quorumID[j]); } } } @@ -272,17 +211,14 @@ public static JSONObject start(String data, IPFS ipfs, int PORT, int index, Stri InitiatorConsensusLogger.debug("Credit Verification failed: Duplicates found"); IPFSNetwork.executeIPFSCommands("ipfs p2p close -t /p2p/" + quorumID[j]); } else if (qResponse[j].equals("441")) { - InitiatorConsensusLogger - .debug("Credit Verification failed: Signature(s) verification failed"); + InitiatorConsensusLogger.debug("Credit Verification failed: Signature(s) verification failed"); IPFSNetwork.executeIPFSCommands("ipfs p2p close -t /p2p/" + quorumID[j]); } else if (qResponse[j].equals("442")) { InitiatorConsensusLogger.debug("Credit Verification failed: Credits hash mismatch"); IPFSNetwork.executeIPFSCommands("ipfs p2p close -t /p2p/" + quorumID[j]); - } else if (qResponse[j].equals("443")) { - InitiatorConsensusLogger.debug("Failed to initialize credit verification"); - IPFSNetwork.executeIPFSCommands("ipfs p2p close -t /p2p/" + quorumID[j]); } } + } qOut[j].println(detailsToken); @@ -299,35 +235,29 @@ public static JSONObject start(String data, IPFS ipfs, int PORT, int index, Stri InitiatorConsensusLogger.debug("Sender Authentication Failure at " + quorumID[j]); IPFSNetwork.executeIPFSCommands("ipfs p2p close -t /p2p/" + quorumID[j]); } else { - InitiatorConsensusLogger - .debug("Signature Received from " + quorumID[j] + " " + qResponse[j]); + InitiatorConsensusLogger.debug("Signature Received from " + quorumID[j] + " " + qResponse[j]); if (quorumResponse[index] > minQuorum(quorumSize)) { qOut[j].println("null"); IPFSNetwork.executeIPFSCommands("ipfs p2p close -t /p2p/" + quorumID[j]); } else { - String didHash = getValues(DATA_PATH + "DataTable.json", "didHash", "peerid", - quorumID[j]); + String didHash = getValues(DATA_PATH + "DataTable.json", "didHash", "peerid", quorumID[j]); JSONObject detailsToVerify = new JSONObject(); detailsToVerify.put("did", didHash); detailsToVerify.put("hash", hash); - detailsToVerify.put("signatures", qResponse[j]); + detailsToVerify.put("signature", qResponse[j]); if (Authenticate.verifySignature(detailsToVerify.toString())) { InitiatorConsensusLogger.debug(role + " node authenticated at index " + index); boolean voteStatus = voteNCount(index, quorumSize); if (quorumResponse[index] <= minQuorum(quorumSize) && voteStatus) { - InitiatorConsensusLogger - .debug("waiting for " + quorumSize + " +signs " + role); + InitiatorConsensusLogger.debug("waiting for " + quorumSize + " +signs " + role); while (quorumResponse[index] < minQuorum(quorumSize)) { } - InitiatorConsensusLogger - .debug("between Q1- to Q" + quorumSize + " for index " + index); + InitiatorConsensusLogger.debug("between Q1- to Q" + quorumSize + " for index " + index); quorumSign(didHash, hash, qResponse[j], index, quorumSize, alphaSize); quorumWithShares.add(quorumPeersObject.getString(j)); - while (quorumSignature - .length() < (minQuorum(alphaSize) + 2 * minQuorum(7))) { + while (quorumSignature.length() < (minQuorum(alphaSize) + 2 * minQuorum(7))) { } - InitiatorConsensusLogger.debug("sending Qsign of length " - + quorumSignature.length() + "at index " + index); + InitiatorConsensusLogger.debug("sending Qsign of length " + quorumSignature.length() + "at index " + index); qOut[j].println(finalQuorumSignsArray.toString()); IPFSNetwork.executeIPFSCommands("ipfs p2p close -t /p2p/" + quorumID[j]); } else { @@ -335,12 +265,9 @@ public static JSONObject start(String data, IPFS ipfs, int PORT, int index, Stri qOut[j].println("null"); IPFSNetwork.executeIPFSCommands("ipfs p2p close -t /p2p/" + quorumID[j]); } - InitiatorConsensusLogger.debug("Quorum Count : " + quorumResponse - + "Signature count : " + quorumSignature.length()); + InitiatorConsensusLogger.debug("Quorum Count : " + quorumResponse + "Signature count : " + quorumSignature.length()); } else { - InitiatorConsensusLogger.debug("node failed authentication with index " + index - + " with role " + role + " with did " + didHash + " and data to verify " - + detailsToVerify); + InitiatorConsensusLogger.debug("node failed authentication with index " + index + " with role " + role + " with did " + didHash + " and data to verify " + detailsToVerify); IPFSNetwork.executeIPFSCommands("ipfs p2p close -t /p2p/" + quorumID[j]); } } @@ -356,81 +283,7 @@ public static JSONObject start(String data, IPFS ipfs, int PORT, int index, Stri quorumThreads[j].start(); } - if (operation.equals("new-credits-mining")) { - Thread[] stakingThreads = new Thread[signedAlphaQuorumID.length]; - // ? one of the validators stake 1 RBT and send the stake ID to the miner. - // choose a quorum member from 1 to 5 who have signed the transaction - for (int p = 0; p < signedAlphaQuorumID.length; p++) { - int s = p; - stakingThreads[p] = new Thread(() -> { - try { - InitiatorConsensusLogger.debug( - "Contacting Signed Alpha Quorum ID : " + signedAlphaQuorumID[s] - + " for staking. Index " - + s); - - qSocket[s] = new Socket("127.0.0.1", PORT + s); - qSocket[s].setSoTimeout(socketTimeOut); - qIn[s] = new BufferedReader(new InputStreamReader(qSocket[s].getInputStream())); - qOut[s] = new PrintStream(qSocket[s].getOutputStream()); - - qOut[s].println("stake-token"); - try { - qResponse[s] = qIn[s].readLine(); - String stakingQuorumDID = getValues(DATA_PATH + "DataTable.json", "didHash", - "peerid", signedAlphaQuorumID[s]); - if (checkTokenOwnershiByDID(qResponse[s], stakingQuorumDID)) { - if (true) { - - // ! generate stake ID and send to staking quorum - - InitiatorConsensusLogger.debug("Staking Successful at index " + s); - } else { - - InitiatorConsensusLogger.debug("sending null for slow quorum "); - qOut[s].println("null"); - IPFSNetwork.executeIPFSCommands( - "ipfs p2p close -t /p2p/" + signedAlphaQuorumID[s]); - - } - - } else { - - InitiatorConsensusLogger.debug("sending null for slow quorum "); - qOut[s].println("null"); - IPFSNetwork.executeIPFSCommands( - "ipfs p2p close -t /p2p/" + signedAlphaQuorumID[s]); - - } - } catch (SocketException e) { - InitiatorConsensusLogger - .warn("Alpha Quorum (for Staking)" + signedAlphaQuorumID[s] - + " is unable to Respond!"); - IPFSNetwork.executeIPFSCommands("ipfs p2p close -t /p2p/" + signedAlphaQuorumID[s]); - } - - } catch (Exception e) { - InitiatorConsensusLogger.error("Exception Occurred"); - e.printStackTrace(); - } - }); - stakingThreads[s].start(); - } - // check the balance - // if balance is sufficient then stake the token - // else send a null to Qa(j) - // if Qa(j) sends a null then close the connection - // else send the stake ID to Qa(j) - // pin the stake ID (initiator) and keep it in a file for future use - File stakesFolder = new File(Functions.WALLET_DATA_PATH.concat("/Stakes")); - if (!stakesFolder.exists()) - stakesFolder.mkdirs(); - // send mining fee to Qa(j) - 0.02 RBT - // close the connection - } - - while (quorumResponse[index] < minQuorum(quorumSize) - || quorumSignature.length() < (minQuorum(alphaSize) + 2 * minQuorum(7))) { + while (quorumResponse[index] < minQuorum(quorumSize) || quorumSignature.length() < (minQuorum(alphaSize) + 2 * minQuorum(7))) { } repo(ipfs); } catch (JSONException e) { diff --git a/src/com/rubix/Consensus/InitiatorProcedure.java b/src/com/rubix/Consensus/InitiatorProcedure.java index 142364e4..05109f68 100644 --- a/src/com/rubix/Consensus/InitiatorProcedure.java +++ b/src/com/rubix/Consensus/InitiatorProcedure.java @@ -1,23 +1,18 @@ package com.rubix.Consensus; -import static com.rubix.Resources.Functions.LOGGER_PATH; -import static com.rubix.Resources.Functions.calculateHash; -import static com.rubix.Resources.Functions.getSignFromShares; -import static com.rubix.Resources.Functions.minQuorum; - -import java.io.IOException; - import com.rubix.Constants.ConsensusConstants; import com.rubix.SplitandStore.SeperateShares; import com.rubix.SplitandStore.Split; - +import io.ipfs.api.IPFS; import org.apache.log4j.Logger; import org.apache.log4j.PropertyConfigurator; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; -import io.ipfs.api.IPFS; +import java.io.IOException; + +import static com.rubix.Resources.Functions.*; public class InitiatorProcedure { public static String essential; @@ -29,13 +24,11 @@ public class InitiatorProcedure { /** * This function sets up the initials before the consensus - * * @param data Data required for hashing and signing * @param ipfs IPFS instance * @param PORT port for forwarding to quorum */ - public static void consensusSetUp(String data, IPFS ipfs, int PORT, int alphaSize, String operation) - throws JSONException { + public static void consensusSetUp(String data,IPFS ipfs, int PORT,int alphaSize, String operation) throws JSONException { PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); JSONObject dataObject = new JSONObject(data); @@ -44,13 +37,12 @@ public static void consensusSetUp(String data, IPFS ipfs, int PORT, int alphaSiz String receiverDidIpfs = dataObject.getString("receiverDidIpfs"); String pvt = dataObject.getString("pvt"); String senderDidIpfs = dataObject.getString("senderDidIpfs"); - String initHash = dataObject.getString("initHash"); String token = dataObject.getString("token"); JSONArray alphaList = dataObject.getJSONArray("alphaList"); JSONArray betaList = dataObject.getJSONArray("betaList"); JSONArray gammaList = dataObject.getJSONArray("gammaList"); - String authSenderByQuorumHash = calculateHash(message, "SHA3-256"); + String authSenderByQuorumHash = calculateHash(message , "SHA3-256"); String authQuorumHash = calculateHash(authSenderByQuorumHash.concat(receiverDidIpfs), "SHA3-256"); try { @@ -78,8 +70,6 @@ public static void consensusSetUp(String data, IPFS ipfs, int PORT, int alphaSiz senderSignQ = getSignFromShares(pvt, authSenderByQuorumHash); data1.put("sign", senderSignQ); data1.put("senderDID", senderDidIpfs); - data1.put("initHash", initHash); - data1.put("token", token); data1.put(ConsensusConstants.TRANSACTION_ID, tid); data1.put(ConsensusConstants.HASH, authSenderByQuorumHash); data1.put(ConsensusConstants.RECEIVERID, receiverDidIpfs); @@ -100,49 +90,44 @@ public static void consensusSetUp(String data, IPFS ipfs, int PORT, int alphaSiz InitiatorProcedureLogger.debug("Invoking Consensus"); JSONObject dataSend = new JSONObject(); - dataSend.put("hash", authQuorumHash); - dataSend.put("details", detailsForQuorum); + dataSend.put("hash",authQuorumHash); + dataSend.put("details",detailsForQuorum); - if (operation.equals("new-credits-mining")) { + if(operation.equals("new-credits-mining")) { JSONObject qstDetails = dataObject.getJSONObject("qstDetails"); dataSend.put("qstDetails", qstDetails); } - Thread alphaThread = new Thread(() -> { + Thread alphaThread = new Thread(()->{ try { - alphaReply = InitiatorConsensus.start(dataSend.toString(), ipfs, PORT, 0, "alpha", alphaList, alphaSize, - alphaSize, operation); + alphaReply = InitiatorConsensus.start(dataSend.toString(),ipfs,PORT,0,"alpha",alphaList,alphaSize,alphaSize, operation); } catch (JSONException e) { e.printStackTrace(); } }); - Thread betaThread = new Thread(() -> { + Thread betaThread = new Thread(()->{ try { - betaReply = InitiatorConsensus.start(dataSend.toString(), ipfs, PORT + 100, 1, "beta", betaList, - alphaSize, 7, operation); + betaReply = InitiatorConsensus.start(dataSend.toString(),ipfs,PORT+100,1,"beta",betaList,alphaSize,7, operation); } catch (JSONException e) { e.printStackTrace(); } }); - Thread gammaThread = new Thread(() -> { + Thread gammaThread = new Thread(()->{ try { - gammaReply = InitiatorConsensus.start(dataSend.toString(), ipfs, PORT + 107, 2, "gamma", gammaList, - alphaSize, 7, operation); + gammaReply = InitiatorConsensus.start(dataSend.toString(),ipfs,PORT+107,2,"gamma",gammaList,alphaSize,7, operation); } catch (JSONException e) { e.printStackTrace(); } }); - InitiatorConsensus.quorumSignature = new JSONObject(); + InitiatorConsensus.quorumSignature=new JSONObject(); InitiatorConsensus.finalQuorumSignsArray = new JSONArray(); alphaThread.start(); betaThread.start(); gammaThread.start(); - while (InitiatorConsensus.quorumSignature.length() < (minQuorum(alphaSize) + 2 * minQuorum(7))) { - } - InitiatorProcedureLogger - .debug("ABG Consensus completed with length " + InitiatorConsensus.quorumSignature.length()); + while (InitiatorConsensus.quorumSignature.length() < (minQuorum(alphaSize) + 2* minQuorum(7))) {} + InitiatorProcedureLogger.debug("ABG Consensus completed with length " +InitiatorConsensus.quorumSignature.length()); } } diff --git a/src/com/rubix/Consensus/QuorumConsensus.java b/src/com/rubix/Consensus/QuorumConsensus.java index f581e1d3..5e51dc2a 100644 --- a/src/com/rubix/Consensus/QuorumConsensus.java +++ b/src/com/rubix/Consensus/QuorumConsensus.java @@ -1,65 +1,37 @@ package com.rubix.Consensus; -import static com.rubix.Resources.Functions.DATA_PATH; -import static com.rubix.Resources.Functions.IPFS_PORT; -import static com.rubix.Resources.Functions.LOGGER_PATH; -import static com.rubix.Resources.Functions.SYNC_IP; -import static com.rubix.Resources.Functions.WALLET_DATA_PATH; -import static com.rubix.Resources.Functions.calculateHash; -import static com.rubix.Resources.Functions.deleteFile; -import static com.rubix.Resources.Functions.getPeerID; -import static com.rubix.Resources.Functions.getSignFromShares; -import static com.rubix.Resources.Functions.getValues; -import static com.rubix.Resources.Functions.initHash; -import static com.rubix.Resources.Functions.nodeData; -import static com.rubix.Resources.Functions.syncDataTable; -import static com.rubix.Resources.Functions.updateJSON; -import static com.rubix.Resources.Functions.writeToFile; -import static com.rubix.Resources.IPFSNetwork.add; -import static com.rubix.Resources.IPFSNetwork.executeIPFSCommands; -import static com.rubix.Resources.IPFSNetwork.listen; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.PrintStream; -import java.net.HttpURLConnection; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.SocketException; -import java.net.URL; -import java.text.ParseException; -import java.util.HashSet; - import com.rubix.AuthenticateNode.Authenticate; import com.rubix.Resources.Functions; import com.rubix.Resources.IPFSNetwork; - +import io.ipfs.api.IPFS; import org.apache.log4j.Logger; import org.apache.log4j.PropertyConfigurator; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; -import io.ipfs.api.IPFS; +import java.io.*; +import java.net.*; +import java.text.ParseException; +import java.util.HashSet; + +import static com.rubix.Resources.Functions.*; +import static com.rubix.Resources.IPFSNetwork.*; public class QuorumConsensus implements Runnable { + public static Logger QuorumConsensusLogger = Logger.getLogger(QuorumConsensus.class); + /** * This method is used to run a thread for Quorum Members - *

- * This involves - *

    - *
  1. Verify sender signature
  2. + *

    This involves

    1. Verify sender signature
    2. *
    3. Signing the transaction
    4. - *
    5. Receiving share from sender
    6. - *
    + *
  3. Receiving share from sender
*/ + int port; IPFS ipfs; String role; @@ -74,10 +46,7 @@ public QuorumConsensus(String role, int port) { public void run() { while (true) { PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); - String peerID, transactionID, verifySenderHash, receiverDID, appName, initHash, senderPrivatePos, token, - stakingQuorumDID, - stakedToken, - senderDidIpfsHash = "", senderPID = ""; + String peerID, transactionID, verifySenderHash, receiverDID, appName, senderPrivatePos, senderDidIpfsHash = "", senderPID = ""; ServerSocket serverSocket = null; Socket socket = null; try { @@ -99,53 +68,29 @@ public void run() { JSONObject readSenderData; String operation = null; - try { + try{ operation = in.readLine(); - } catch (SocketException e) { + }catch (SocketException e){ QuorumConsensusLogger.debug("Sender Input Stream Null - Operation"); socket.close(); serverSocket.close(); executeIPFSCommands(" ipfs p2p close -t /p2p/" + senderPID); } - - if (operation.equals("stake-token")) { - - String stakeDetails; - - // ! send token ID choosen - out.println("null"); - - try { - stakeDetails = in.readLine(); - } catch (SocketException e) { - QuorumConsensusLogger.debug("Sender Input Stream Null - New stake ID Details"); - socket.close(); - serverSocket.close(); - executeIPFSCommands(" ipfs p2p close -t /p2p/" + senderPID); - } - JSONObject stakeDetailsJSON = new JSONObject(stakeDetails); - generateStakeIDByToken(stakeDetailsJSON.getString("stakeID"), stakeDetailsJSON.getString("minedToken")); - out.println("OK") - // ! wait for 0.02 RBT - - } - if (operation.equals("new-credits-mining")) { - QuorumConsensusLogger.debug("New Credits"); String getNewCreditsData = null; - try { + try{ getNewCreditsData = in.readLine(); - } catch (SocketException e) { + }catch (SocketException e){ QuorumConsensusLogger.debug("Sender Input Stream Null - New Credits Details"); socket.close(); serverSocket.close(); executeIPFSCommands(" ipfs p2p close -t /p2p/" + senderPID); } - // Verify QST Credits + //Verify QST Credits JSONObject qstObject = new JSONObject(getNewCreditsData); - // Get level of token from advisory node + //Get level of token from advisory node int creditsRequired = 0; JSONObject resJsonData_credit = new JSONObject(); String GET_URL_credit = SYNC_IP + "/getlevel"; @@ -155,8 +100,7 @@ public void run() { int responseCode_credit = con_credit.getResponseCode(); System.out.println("GET Response Code :: " + responseCode_credit); if (responseCode_credit == HttpURLConnection.HTTP_OK) { - BufferedReader in_credit = new BufferedReader( - new InputStreamReader(con_credit.getInputStream())); + BufferedReader in_credit = new BufferedReader(new InputStreamReader(con_credit.getInputStream())); String inputLine_credit; StringBuffer response_credit = new StringBuffer(); while ((inputLine_credit = in_credit.readLine()) != null) { @@ -172,19 +116,18 @@ public void run() { } else QuorumConsensusLogger.debug("GET request not worked"); - // Level 1 Verification: Verify hash of n objects + + //Level 1 Verification: Verify hash of n objects JSONArray qstArray = qstObject.getJSONArray("qstArray"); JSONArray creditsArray = qstObject.getJSONArray("credits"); boolean flag = true; for (int i = 0; i < creditsRequired; i++) { QuorumConsensusLogger.debug("Credit object: " + creditsArray.getJSONObject(i).toString()); - QuorumConsensusLogger.debug( - "Credit Hash: " + calculateHash(creditsArray.getJSONObject(i).toString(), "SHA3-256")); + QuorumConsensusLogger.debug("Credit Hash: " + calculateHash(creditsArray.getJSONObject(i).toString(), "SHA3-256")); String reHash = calculateHash(qstArray.getJSONObject(i).getString("credits"), "SHA3-256"); if (!reHash.equals(qstArray.getJSONObject(i).getString("creditHash"))) { - QuorumConsensusLogger.debug("Recalculation " + reHash + " - " - + qstArray.getJSONObject(i).getString("creditHash")); + QuorumConsensusLogger.debug("Recalculation " + reHash + " - " + qstArray.getJSONObject(i).getString("creditHash")); flag = false; } } @@ -209,8 +152,7 @@ public void run() { QuorumConsensusLogger.debug("Mining Verified"); out.println("Verified"); } else { - QuorumConsensusLogger - .debug("HashSet: " + hashSet.size() + " QST Size " + qstArray.length()); + QuorumConsensusLogger.debug("HashSet: " + hashSet.size() + " QST Size " + qstArray.length()); QuorumConsensusLogger.debug("Mining Not Verified: Duplicates Found"); out.println("440"); socket.close(); @@ -233,9 +175,9 @@ public void run() { QuorumConsensusLogger.debug("Old Credits Mining / Whole RBT Token Transfer"); String getRecData = null; - try { + try{ getRecData = in.readLine(); - } catch (SocketException e) { + }catch (SocketException e){ QuorumConsensusLogger.debug("Sender Input Stream Null - Ping Check / Receiver Details"); socket.close(); serverSocket.close(); @@ -256,38 +198,13 @@ public void run() { verifySenderHash = readSenderData.getString("Hash"); receiverDID = readSenderData.getString("RID"); - // ! additional info for the mining verification - initHash = readSenderData.getString("initHash"); - token = readSenderData.getString("token"); - stakedToken = readSenderData.getString("stakedToken"); - String stakingQuorumPeerID = readSenderData.getString("stakingQuorumPeerID"); - stakingQuorumDID = getValues(DATA_PATH + "DataTable.json", "didHash", "peerid", - stakingQuorumPeerID); - - // ! match initiator initHash with quorum. if didn't match, reject - - if (!initHash.equals(initHash())) { - QuorumConsensusLogger.debug("Initiator Hash Mismatch"); - out.println("443"); - socket.close(); - serverSocket.close(); - executeIPFSCommands(" ipfs p2p close -t /p2p/" + senderPID); - } - syncDataTable(senderDidIpfsHash, null); senderPID = getValues(DATA_PATH + "DataTable.json", "peerid", "didHash", senderDidIpfsHash); - String senderWidIpfsHash = getValues(DATA_PATH + "DataTable.json", "walletHash", "didHash", - senderDidIpfsHash); + String senderWidIpfsHash = getValues(DATA_PATH + "DataTable.json", "walletHash", "didHash", senderDidIpfsHash); nodeData(senderDidIpfsHash, senderWidIpfsHash, ipfs); - - // ! check if each quorum member is signing on the quorumHash (which now is - // sender + receiver hash) - // concat of sender hash and rec hash) - - String quorumHash = calculateHash(token + transactionID + stakingQuorumDID, "SHA3-256"); - String stakeHash = calculateHash(token + stakedToken, "SHA3-256"); + String quorumHash = calculateHash(verifySenderHash.concat(receiverDID), "SHA3-256"); QuorumConsensusLogger.debug("1: " + verifySenderHash); QuorumConsensusLogger.debug("2: " + receiverDID); @@ -299,46 +216,27 @@ public void run() { detailsToVerify.put("signature", senderPrivatePos); writeToFile(LOGGER_PATH + "tempverifysenderhash", verifySenderHash, false); - String verifySenderIPFSHash = IPFSNetwork.addHashOnly(LOGGER_PATH + "tempverifysenderhash", - ipfs); + String verifySenderIPFSHash = IPFSNetwork.addHashOnly(LOGGER_PATH + "tempverifysenderhash", ipfs); deleteFile(LOGGER_PATH + "tempverifysenderhash"); - // QuorumConsensusLogger.debug("Checking providers for: " + verifySenderHash); - // ArrayList dhtOwnersList = dhtOwnerCheck(verifySenderHash); - // QuorumConsensusLogger.debug("Providers: " + dhtOwnersList); - // boolean consensusIDcheck = false; - // if(dhtOwnersList.size() <= 2 && dhtOwnersList.contains(senderPID)) - // consensusIDcheck = true; +// QuorumConsensusLogger.debug("Checking providers for: " + verifySenderHash); +// ArrayList dhtOwnersList = dhtOwnerCheck(verifySenderHash); +// QuorumConsensusLogger.debug("Providers: " + dhtOwnersList); +// boolean consensusIDcheck = false; +// if(dhtOwnersList.size() <= 2 && dhtOwnersList.contains(senderPID)) +// consensusIDcheck = true; if (Authenticate.verifySignature(detailsToVerify.toString())) { QuorumConsensusLogger.debug("Quorum Authenticated Sender"); QuorumConsensusLogger.debug("ConsensusID pass"); - - // json obj called quorumSignss - JSONObject quorumSigns = new JSONObject(); - - // ! 1st sign: TID - String QuorumSignatureOne = getSignFromShares(DATA_PATH + didHash + "/PrivateShare.png", - transactionID); - quorumSigns.put("TIDSign", QuorumSignatureOne); - // ? - // ! 2st sign: Token - String QuorumSignatureTwo = getSignFromShares(DATA_PATH + didHash + "/PrivateShare.png", - token); - quorumSigns.put("TokenSign", QuorumSignatureTwo); - - // ! 3th sign: Token + TID - String QuorumSignatureFive = getSignFromShares(DATA_PATH + didHash + "/PrivateShare.png", - quorumHash); - quorumSigns.put("QuorumSign", QuorumSignatureFive); - - out.println(quorumSigns); + String QuorumSignature = getSignFromShares(DATA_PATH + didHash + "/PrivateShare.png", quorumHash); + out.println(QuorumSignature); String creditSignatures = null; - try { + try{ creditSignatures = in.readLine(); - } catch (SocketException e) { + }catch (SocketException e){ QuorumConsensusLogger.debug("Sender Input Stream Null - Credits"); socket.close(); serverSocket.close(); @@ -346,8 +244,7 @@ public void run() { } QuorumConsensusLogger.debug("credit Signature " + creditSignatures); - if (!creditSignatures.equals("null")) { // commented as per test for multiple consensus - // threads + if (!creditSignatures.equals("null")) { //commented as per test for multiple consensus threads FileWriter shareWriter = new FileWriter(new File(LOGGER_PATH + "mycredit.txt"), true); shareWriter.write(creditSignatures); @@ -355,8 +252,7 @@ public void run() { File readCredit = new File(LOGGER_PATH + "mycredit.txt"); String credit = add(readCredit.toString(), ipfs); - File creditFile = new File( - WALLET_DATA_PATH.concat("/Credits/").concat(credit).concat(".json")); + File creditFile = new File(WALLET_DATA_PATH.concat("/Credits/").concat(credit).concat(".json")); if (!creditFile.exists()) creditFile.createNewFile(); writeToFile(creditFile.toString(), creditSignatures, false); @@ -388,8 +284,6 @@ public void run() { out.println("Auth_Failed"); } - // ! moving staked token to bottom of BNK00 file. - } } else { QuorumConsensusLogger.debug("Quorum - " + didHash + " is unable to respond!" + getRecData); diff --git a/src/com/rubix/Mining/ProofCredits.java b/src/com/rubix/Mining/ProofCredits.java index e4ce6292..38ba80e2 100644 --- a/src/com/rubix/Mining/ProofCredits.java +++ b/src/com/rubix/Mining/ProofCredits.java @@ -1,35 +1,17 @@ package com.rubix.Mining; -import static com.rubix.Resources.Functions.DATA_PATH; -import static com.rubix.Resources.Functions.EXPLORER_IP; -import static com.rubix.Resources.Functions.LOGGER_PATH; -import static com.rubix.Resources.Functions.PAYMENTS_PATH; -import static com.rubix.Resources.Functions.QuorumCheck; -import static com.rubix.Resources.Functions.QuorumSwarmConnect; -import static com.rubix.Resources.Functions.SEND_PORT; -import static com.rubix.Resources.Functions.SYNC_IP; -import static com.rubix.Resources.Functions.TOKENCHAIN_PATH; -import static com.rubix.Resources.Functions.TOKENS_PATH; -import static com.rubix.Resources.Functions.WALLET_DATA_PATH; -import static com.rubix.Resources.Functions.calculateHash; -import static com.rubix.Resources.Functions.deleteFile; -import static com.rubix.Resources.Functions.getQuorum; -import static com.rubix.Resources.Functions.initHash; -import static com.rubix.Resources.Functions.minQuorum; -import static com.rubix.Resources.Functions.mineUpdate; -import static com.rubix.Resources.Functions.readFile; -import static com.rubix.Resources.Functions.updateJSON; -import static com.rubix.Resources.Functions.updateQuorum; -import static com.rubix.Resources.Functions.writeToFile; -import static com.rubix.Resources.IPFSNetwork.add; -import static com.rubix.Resources.IPFSNetwork.pin; -import static com.rubix.Resources.IPFSNetwork.repo; - -import java.io.BufferedReader; -import java.io.DataOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; +import com.rubix.Consensus.InitiatorConsensus; +import com.rubix.Consensus.InitiatorProcedure; +import com.rubix.Resources.Functions; +import com.rubix.Resources.IPFSNetwork; +import io.ipfs.api.IPFS; +import org.apache.log4j.Logger; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import javax.net.ssl.HttpsURLConnection; +import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import java.text.DateFormat; @@ -40,22 +22,13 @@ import java.util.Iterator; import java.util.List; -import javax.net.ssl.HttpsURLConnection; - -import com.rubix.Consensus.InitiatorConsensus; -import com.rubix.Consensus.InitiatorProcedure; -import com.rubix.Resources.Functions; -import com.rubix.Resources.IPFSNetwork; - -import org.apache.log4j.Logger; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; +import static com.rubix.Resources.Functions.*; +import static com.rubix.Resources.IPFSNetwork.*; -import io.ipfs.api.IPFS; public class ProofCredits { + public static Logger ProofCreditsLogger = Logger.getLogger(ProofCredits.class); private static ArrayList alphaPeersList; private static ArrayList betaPeersList; @@ -77,6 +50,7 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON JSONArray betaQuorum = new JSONArray(); JSONArray gammaQuorum = new JSONArray(); + int creditsRequired = 50000, level; long starttime = System.currentTimeMillis(); JSONArray resJsonData = new JSONArray(); @@ -110,8 +84,10 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON } else ProofCreditsLogger.debug("GET request not worked"); + ProofCreditsLogger.debug("credits required " + creditsRequired + " available credits " + availableCredits); + if (availableCredits >= creditsRequired) { boolean oldCreditsFlag = false; @@ -121,7 +97,8 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON ProofCreditsLogger.debug("Credits Old: " + oldCreditsFlag); - // String GET_URL = SYNC_IP+"/getInfo?count="+availableCredits; + + //String GET_URL = SYNC_IP+"/getInfo?count="+availableCredits; String GET_URL = SYNC_IP + "/minetoken"; URL URLobj = new URL(GET_URL); HttpURLConnection con = (HttpURLConnection) URLobj.openConnection(); @@ -142,16 +119,16 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON } else ProofCreditsLogger.debug("GET request not worked"); - // Check if node can mine token + + //Check if node can mine token if (resJsonData.length() > 0) { - // Calling Mine token function + //Calling Mine token function JSONArray token = new JSONArray(); level = resJsonData.getJSONObject(0).getInt("level"); for (int i = 0; i < resJsonData.length(); i++) { - token.put(Functions.mineToken(resJsonData.getJSONObject(i).getInt("level"), - resJsonData.getJSONObject(i).getInt("token"))); + token.put(Functions.mineToken(resJsonData.getJSONObject(i).getInt("level"), resJsonData.getJSONObject(i).getInt("token"))); creditUsed += (int) Math.pow(2, (2 + resJsonData.getJSONObject(i).getInt("level"))); @@ -181,8 +158,7 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON break; } default: { - quorumArray = getQuorum(betaHash, gammaHash, receiverDidIpfsHash, receiverDidIpfsHash, - token.length()); + quorumArray = getQuorum(betaHash, gammaHash, receiverDidIpfsHash, receiverDidIpfsHash, token.length()); } } @@ -202,14 +178,14 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON ProofCreditsLogger.debug("betaquorum " + betaQuorum + " size " + betaQuorum.length()); ProofCreditsLogger.debug("gammaquorum " + gammaQuorum + " size " + gammaQuorum.length()); + alphaPeersList = QuorumCheck(alphaQuorum, alphaSize); betaPeersList = QuorumCheck(betaQuorum, 7); gammaPeersList = QuorumCheck(gammaQuorum, 7); // quorumPeersList = QuorumCheck(quorumArray, ipfs); - if (alphaPeersList.size() < minQuorum(alphaSize) || betaPeersList.size() < 5 - || gammaPeersList.size() < 5) { + if (alphaPeersList.size() < minQuorum(alphaSize) || betaPeersList.size() < 5 || gammaPeersList.size() < 5) { updateQuorum(quorumArray, null, false, type); APIResponse.put("did", receiverDidIpfsHash); APIResponse.put("tid", "null"); @@ -222,19 +198,17 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON JSONArray signedQuorumList = new JSONArray(); if (!oldCreditsFlag) { ProofCreditsLogger.debug("New Credits"); - // Send QST for verification + //Send QST for verification String qstContent = readFile(WALLET_DATA_PATH.concat("QuorumSignedTransactions.json")); JSONArray qstArray = new JSONArray(qstContent); int count = 0; JSONArray creditSignsArray = new JSONArray(); for (int k = 0; k < qstArray.length(); k++) { - String creditIpfs = add(WALLET_DATA_PATH.concat("/Credits/") - .concat(qstArray.getJSONObject(k).getString("credits")).concat(".json"), ipfs); + String creditIpfs = add(WALLET_DATA_PATH.concat("/Credits/").concat(qstArray.getJSONObject(k).getString("credits")).concat(".json"), ipfs); pin(creditIpfs, ipfs); - String filePath = WALLET_DATA_PATH.concat("/Credits/") - .concat(qstArray.getJSONObject(k).getString("credits")).concat(".json"); + String filePath = WALLET_DATA_PATH.concat("/Credits/").concat(qstArray.getJSONObject(k).getString("credits")).concat(".json"); File creditFile = new File(filePath); if (creditFile.exists()) { count++; @@ -244,10 +218,10 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON for (int i = 0; i < creditArray.length(); i++) creditSignsArray.put(creditArray.getJSONObject(i)); } else - ProofCreditsLogger - .debug(qstArray.getJSONObject(k).getString("credits").concat(" file not found")); + ProofCreditsLogger.debug(qstArray.getJSONObject(k).getString("credits").concat(" file not found")); } + JSONObject qstObject = new JSONObject(); if (count == qstArray.length()) { qstObject.put("qstArray", qstArray); @@ -272,11 +246,9 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON dataObject.put("alphaList", alphaPeersList); dataObject.put("betaList", betaPeersList); dataObject.put("gammaList", gammaPeersList); - dataObject.put("initHash", initHash()); dataObject.put("qstDetails", qstObject); - InitiatorProcedure.consensusSetUp(dataObject.toString(), ipfs, SEND_PORT + 3, alphaSize, - "new-credits-mining"); + InitiatorProcedure.consensusSetUp(dataObject.toString(), ipfs, SEND_PORT + 3, alphaSize, "new-credits-mining"); if (!(InitiatorConsensus.quorumSignature.length() >= 3 * minQuorum(7))) { APIResponse.put("did", receiverDidIpfsHash); @@ -298,8 +270,7 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON } for (int i = 0; i < creditUsed; i++) - deleteFile(WALLET_DATA_PATH.concat("/Credits/") - .concat(qstArray.getJSONObject(i).getString("credits")).concat(".json")); + deleteFile(WALLET_DATA_PATH.concat("/Credits/").concat(qstArray.getJSONObject(i).getString("credits")).concat(".json")); } } else { @@ -352,6 +323,7 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON updateJSON("add", PAYMENTS_PATH + "BNK00.json", tempArray.toString()); } + File minedCH = new File(WALLET_DATA_PATH + "MinedCreditsHistory.json"); if (!minedCH.exists()) { minedCH.createNewFile(); @@ -407,12 +379,14 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON transactionRecord.put("totalTime", totalTime); transactionRecord.put("comment", "minedtxn"); + JSONArray transactionHistoryEntry = new JSONArray(); transactionHistoryEntry.put(transactionRecord); updateJSON("add", WALLET_DATA_PATH + "TransactionHistory.json", transactionHistoryEntry.toString()); if (!EXPLORER_IP.contains("127.0.0.1")) { + String url = EXPLORER_IP.concat("/CreateOrUpdateRubixToken"); URL obj = new URL(url); HttpsURLConnection connection_Explorer = (HttpsURLConnection) obj.openConnection(); @@ -533,3 +507,5 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON return APIResponse; } } + + diff --git a/src/com/rubix/Ping/PingCheck.java b/src/com/rubix/Ping/PingCheck.java new file mode 100644 index 00000000..c8f8ef1e --- /dev/null +++ b/src/com/rubix/Ping/PingCheck.java @@ -0,0 +1,97 @@ +package com.rubix.Ping; + +import io.ipfs.api.IPFS; +import org.apache.log4j.Logger; +import org.apache.log4j.PropertyConfigurator; +import org.json.JSONException; +import org.json.JSONObject; +import java.io.*; +import java.net.Socket; +import java.net.SocketException; + +import static com.rubix.Resources.Functions.*; +import static com.rubix.Resources.IPFSNetwork.*; +import static com.rubix.Resources.IPFSNetwork.executeIPFSCommands; + +public class PingCheck { + private static final Logger PingSenderLogger = Logger.getLogger(PingCheck.class); + public static IPFS ipfs = new IPFS("/ip4/127.0.0.1/tcp/" + IPFS_PORT); + public static BufferedReader serverInput; + + + public static JSONObject Ping(String peerID, int port) throws IOException, JSONException { + repo(ipfs); + PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); + + JSONObject APIResponse = new JSONObject(); + if (!peerID.equals("")) { + PingSenderLogger.debug("Swarm connecting to " + peerID); + swarmConnectP2P(peerID, ipfs); + PingSenderLogger.debug("Swarm connected"); + } else { + APIResponse.put("message", "Receiver Peer ID null"); + PingSenderLogger.warn("Receiver Peer ID null"); + return APIResponse; + } + + String receiverWidIpfsHash = getValues(DATA_PATH + "DataTable.json", "walletHash", "peerid", peerID); + String receiverDidIpfsHash = getValues(DATA_PATH + "DataTable.json", "didHash", "peerid", peerID); + if (!receiverWidIpfsHash.equals("")) { + nodeData(receiverDidIpfsHash, receiverWidIpfsHash, ipfs); + } else { + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Receiver WID null"); + PingSenderLogger.warn("Receiver WID null"); + return APIResponse; + } + + PingSenderLogger.debug("Sender IPFS forwarding to DID: " + receiverDidIpfsHash + " PeerID: " + peerID); + String appName = peerID.concat("Ping"); + forward(appName, port, peerID); + PingSenderLogger.debug("Forwarded to " + appName + " on " + port); + Socket senderSocket = new Socket("127.0.0.1", port); + + BufferedReader input = new BufferedReader(new InputStreamReader(senderSocket.getInputStream())); + PrintStream output = new PrintStream(senderSocket.getOutputStream()); + + output.println("PingCheck"); + PingSenderLogger.debug("Sent PingCheck request"); + + String pongResponse; + try { + pongResponse = input.readLine(); + } catch (SocketException e) { + PingSenderLogger.warn("Receiver " + receiverDidIpfsHash + " is unable to Respond! - Ping Check"); + executeIPFSCommands(" ipfs p2p close -t /p2p/" + peerID); + output.close(); + input.close(); + senderSocket.close(); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Receiver " + receiverDidIpfsHash + "is unable to respond! - Sender Auth"); + + return APIResponse; + } + + + if (pongResponse != null && (!pongResponse.equals("Pong"))) { + executeIPFSCommands(" ipfs p2p close -t /p2p/" + peerID); + PingSenderLogger.info("Pong response not received"); + output.close(); + input.close(); + senderSocket.close(); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Pong response not received"); + + }else { + PingSenderLogger.info("Ping Successful"); + executeIPFSCommands(" ipfs p2p close -t /p2p/" + peerID); + output.close(); + input.close(); + senderSocket.close(); + APIResponse.put("status", "Success"); + APIResponse.put("message", "Ping Check Success"); + + } + return APIResponse; + } +} diff --git a/src/com/rubix/Ping/PingReceive.java b/src/com/rubix/Ping/PingReceive.java new file mode 100644 index 00000000..3ec8ee01 --- /dev/null +++ b/src/com/rubix/Ping/PingReceive.java @@ -0,0 +1,91 @@ +package com.rubix.Ping; +import io.ipfs.api.IPFS; +import org.apache.log4j.Logger; +import org.apache.log4j.PropertyConfigurator; +import org.json.JSONException; +import org.json.JSONObject; +import java.io.*; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketException; +import static com.rubix.Resources.Functions.*; +import static com.rubix.Resources.IPFSNetwork.*; +import static com.rubix.Resources.IPFSNetwork.executeIPFSCommands; + +public class PingReceive { + public static Logger PingReceiverLogger = Logger.getLogger(PingReceive.class); + + private static final JSONObject APIResponse = new JSONObject(); + private static final IPFS ipfs = new IPFS("/ip4/127.0.0.1/tcp/" + IPFS_PORT); + + /** + * Receiver Node: To receive a valid token from an authentic sender + * + * @return Transaction Details (JSONObject) + * @throws IOException handles IO Exceptions + * @throws JSONException handles JSON Exceptions + */ + public static String receive(int port) { + pathSet(); + ServerSocket ss ; + Socket sk ; + + try { + repo(ipfs); + + + PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); + + String receiverPeerID = getPeerID(DATA_PATH + "DID.json"); + String appName = receiverPeerID.concat("Ping"); + listen(appName, port); + ss = new ServerSocket(port); + PingReceiverLogger.debug("Ping Receiver Listening on " + port + " appname " + appName); + + sk = ss.accept(); + PingReceiverLogger.debug("Data Incoming..."); + BufferedReader input = new BufferedReader(new InputStreamReader(sk.getInputStream())); + PrintStream output = new PrintStream(sk.getOutputStream()); + + String pingRequest; + try { + pingRequest = input.readLine(); + } catch (SocketException e) { + PingReceiverLogger.warn("Sender Stream Null - PingCheck"); + APIResponse.put("did", ""); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Sender Stream Null - PingCheck"); + + output.close(); + input.close(); + sk.close(); + ss.close(); + return APIResponse.toString(); + + } + PingReceiverLogger.debug("Ping Request Received: " + pingRequest); + if(pingRequest != null && pingRequest.contains("PingCheck")) { + output.println("Pong"); + + APIResponse.put("status", "Success"); + APIResponse.put("message", "Pong Sent"); + PingReceiverLogger.info("Pong Sent"); + + }else{ + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Pong Failed"); + PingReceiverLogger.info("Pong Failed"); + } + executeIPFSCommands(" ipfs p2p close -t /p2p/" + pingRequest); + output.close(); + input.close(); + sk.close(); + ss.close(); + + } catch (IOException e) { + e.printStackTrace(); + } + return APIResponse.toString(); + } +} diff --git a/src/com/rubix/Ping/QuorumPingReceive.java b/src/com/rubix/Ping/QuorumPingReceive.java new file mode 100644 index 00000000..ec1a88ca --- /dev/null +++ b/src/com/rubix/Ping/QuorumPingReceive.java @@ -0,0 +1,96 @@ +package com.rubix.Ping; + +import io.ipfs.api.IPFS; +import org.apache.log4j.Logger; +import org.apache.log4j.PropertyConfigurator; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintStream; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketException; + +import static com.rubix.Resources.Functions.*; +import static com.rubix.Resources.IPFSNetwork.*; + +public class QuorumPingReceive { + public static Logger QuorumPingReceiverLogger = Logger.getLogger(QuorumPingReceive.class); + + private static final JSONObject APIResponse = new JSONObject(); + private static final IPFS ipfs = new IPFS("/ip4/127.0.0.1/tcp/" + IPFS_PORT); + + /** + * Receiver Node: To receive a valid token from an authentic sender + * + * @return Transaction Details (JSONObject) + * @throws IOException handles IO Exceptions + * @throws JSONException handles JSON Exceptions + */ + public static String receive(int port) { + pathSet(); + ServerSocket ss ; + Socket sk ; + + try { + repo(ipfs); + + + PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); + + String receiverPeerID = getPeerID(DATA_PATH + "DID.json"); + String appName = receiverPeerID.concat("Ping"); + listen(appName, port); + ss = new ServerSocket(port); + QuorumPingReceiverLogger.debug("Ping Quorum Listening on " + port + " appname " + appName); + + sk = ss.accept(); + QuorumPingReceiverLogger.debug("Data Incoming..."); + BufferedReader input = new BufferedReader(new InputStreamReader(sk.getInputStream())); + PrintStream output = new PrintStream(sk.getOutputStream()); + + String pingRequest; + try { + pingRequest = input.readLine(); + } catch (SocketException e) { + QuorumPingReceiverLogger.warn("Sender Stream Null - PingCheck"); + APIResponse.put("did", ""); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Sender Stream Null - PingCheck"); + + output.close(); + input.close(); + sk.close(); + ss.close(); + return APIResponse.toString(); + + } + QuorumPingReceiverLogger.debug("Ping Request Received: " + pingRequest); + if(pingRequest != null && pingRequest.contains("PingCheck")) { + output.println("Pong"); + + APIResponse.put("status", "Success"); + APIResponse.put("message", "Pong Sent"); + QuorumPingReceiverLogger.info("Pong Sent"); + + }else{ + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Pong Failed"); + QuorumPingReceiverLogger.info("Pong Failed"); + } + executeIPFSCommands(" ipfs p2p close -t /p2p/" + pingRequest); + output.close(); + input.close(); + sk.close(); + ss.close(); + + } catch (IOException e) { + e.printStackTrace(); + } + return APIResponse.toString(); + } +} diff --git a/src/com/rubix/Resources/APIHandler.java b/src/com/rubix/Resources/APIHandler.java index 14e22c13..8320ae79 100644 --- a/src/com/rubix/Resources/APIHandler.java +++ b/src/com/rubix/Resources/APIHandler.java @@ -1,21 +1,10 @@ package com.rubix.Resources; -import static com.rubix.Resources.Functions.DATA_PATH; -import static com.rubix.Resources.Functions.IPFS_PORT; -import static com.rubix.Resources.Functions.LOGGER_PATH; -import static com.rubix.Resources.Functions.SEND_PORT; -import static com.rubix.Resources.Functions.SYNC_IP; -import static com.rubix.Resources.Functions.WALLET_DATA_PATH; -import static com.rubix.Resources.Functions.getOsName; -import static com.rubix.Resources.Functions.getPeerID; -import static com.rubix.Resources.Functions.getValues; -import static com.rubix.Resources.Functions.nodeData; -import static com.rubix.Resources.Functions.readFile; -import static com.rubix.Resources.Functions.writeToFile; -import static com.rubix.Resources.IPFSNetwork.add; -import static com.rubix.Resources.IPFSNetwork.executeIPFSCommands; -import static com.rubix.Resources.IPFSNetwork.pin; - +import com.rubix.Mining.ProofCredits; +import com.rubix.TokenTransfer.TokenSender; +import io.ipfs.api.*; +import org.apache.log4j.*; +import org.json.*; import java.io.BufferedReader; import java.io.File; import java.io.IOException; @@ -25,24 +14,10 @@ import java.security.NoSuchAlgorithmException; import java.text.ParseException; import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Date; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; - -import com.rubix.Mining.ProofCredits; -import com.rubix.TokenTransfer.TokenSender; - -import org.apache.log4j.Logger; -import org.apache.log4j.PropertyConfigurator; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; +import java.util.*; -import io.ipfs.api.IPFS; -import io.ipfs.api.Peer; +import static com.rubix.Resources.Functions.*; +import static com.rubix.Resources.IPFSNetwork.*; public class APIHandler { private static final Logger APILogger = Logger.getLogger(APIHandler.class); @@ -51,14 +26,15 @@ public class APIHandler { /** * Initiates a transfer between two nodes - * * @param data Data specific to token transfer * @return Message from the sender with transaction details - * @throws JSONException handles JSON Exceptions + * @throws JSONException handles JSON Exceptions * @throws NoSuchAlgorithmException handles Invalid Algorithms Exceptions - * @throws IOException handles IO Exceptions + * @throws IOException handles IO Exceptions */ + + public static JSONObject send(String data) throws Exception { Functions.pathSet(); PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); @@ -66,6 +42,7 @@ public static JSONObject send(String data) throws Exception { String senderPeerID = getPeerID(DATA_PATH + "DID.json"); String senDID = getValues(DATA_PATH + "DID.json", "didHash", "peerid", senderPeerID); + JSONObject dataObject = new JSONObject(data); String recDID = dataObject.getString("receiverDidIpfsHash"); @@ -78,7 +55,7 @@ public static JSONObject send(String data) throws Exception { isObjectValid = true; } } - if (!isObjectValid) + if(!isObjectValid) networkInfo(); JSONObject sendMessage = new JSONObject(); @@ -91,7 +68,7 @@ public static JSONObject send(String data) throws Exception { } dataObject.put("pvt", DATA_PATH + senDID + "/PrivateShare.png"); - sendMessage = TokenSender.Send(dataObject.toString(), ipfs, SEND_PORT); + sendMessage = TokenSender.Send(dataObject.toString(), ipfs, SEND_PORT); APILogger.info(sendMessage); return sendMessage; @@ -99,7 +76,6 @@ public static JSONObject send(String data) throws Exception { /** * An API call to mine tokens - * * @param type Type of quorum Selection * @return JSONObject with status message * @throws Exception throws Exception @@ -121,7 +97,7 @@ public static JSONObject create(int type) throws Exception { isObjectValid = true; } } - if (!isObjectValid) + if(!isObjectValid) networkInfo(); JSONObject sendMessage = new JSONObject(); @@ -129,55 +105,216 @@ public static JSONObject create(int type) throws Exception { detailsObject.put("receiverDidIpfsHash", senDID); detailsObject.put("pvt", DATA_PATH + senDID + "/PrivateShare.png"); detailsObject.put("type", type); - sendMessage = ProofCredits.create(detailsObject.toString(), ipfs); + sendMessage = ProofCredits.create(detailsObject.toString(), ipfs); APILogger.info(sendMessage); return sendMessage; } + + + /** - * A call to get details of a transaction given its ID - * - * @param txnId - * @return Transaction Details - * @throws JSONException handles JSON Exceptions + * A method to add and host your DID ans Public share to ipfs + * @files DID.json, DataTable.json, DID.png, PublicShare.png */ - public static JSONArray transactionDetails(String txnId) throws JSONException { - String transactionHistory = readFile(WALLET_DATA_PATH + "TransactionHistory.json"); - JSONObject countResult = new JSONObject(); + public static void addPublicData(){ + String peerID = getPeerID(DATA_PATH + "DID.json"); + String didHash = getValues(DATA_PATH + "DataTable.json", "didHash", "peerid", peerID); + String walletHash = getValues(DATA_PATH + "DataTable.json", "walletHash", "peerid", peerID); + + add(DATA_PATH.concat(didHash).concat("/DID.png"), ipfs); + pin(didHash, ipfs); + + add(DATA_PATH.concat(didHash).concat("/PublicShare.png"), ipfs); + pin(walletHash, ipfs); + + } + + /** + * A call to sync all the nodes in the network + * @return Message if failed or succeeded + * @throws IOException + * @files DataTable.json + */ + public static String networkInfo() throws IOException, JSONException { + StringBuilder result = new StringBuilder(); JSONArray resultArray = new JSONArray(); - if (transactionHistory.length() == 0) { - countResult.put("Message", "No transactions found"); - resultArray.put(countResult); - return resultArray; + JSONObject jsonObject = new JSONObject(); + int syncFlag = 0; + URL url = new URL(SYNC_IP + "/get"); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("GET"); + BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream())); + String line; + + while ((line = rd.readLine()) != null) { + result.append(line); + syncFlag = 1; } - JSONArray transArray = new JSONArray(transactionHistory); - JSONObject obj = new JSONObject(); - for (int i = 0; i < transArray.length(); i++) { - obj = transArray.getJSONObject(i); - if (obj.get("txn").equals(txnId)) { - obj.remove("essentialShare"); + rd.close(); + + writeToFile(DATA_PATH + "DataTable.json", result.toString(), false); + if (syncFlag == 1) { + jsonObject.put("message", "Synced Successfully!"); + } else { + jsonObject.put("message", "Not synced! Try again after sometime."); + } + resultArray.put(jsonObject); + return resultArray.toString(); + } - if (obj.has("amount")) - obj.put("amount", obj.getDouble("amount")); - else { - JSONArray tokensArray = (JSONArray) obj.get("tokens"); - obj.put("amount", tokensArray.length()); - } - resultArray.put(obj); + + /** + * Method to query the credits information + * @files QuorumSignedTransactions.json, MinedCreditsHistory.json + */ + public static JSONObject creditsInfo(){ + String qstFile = WALLET_DATA_PATH.concat("QuorumSignedTransactions.json"); + String mineFile = WALLET_DATA_PATH.concat("MinedCreditsHistory.json"); + + File quorumFile = new File(qstFile); + File minedFile = new File(mineFile); + + int spentCredits = 0; + int unspentCredits = 0; + if(quorumFile.exists()){ + String qFile = readFile(qstFile); + JSONArray qArray = new JSONArray(qFile); + unspentCredits = qArray.length(); + } + if(minedFile.exists()){ + String mFile = readFile(mineFile); + JSONArray mArray = new JSONArray(mFile); + spentCredits = mArray.length(); + } + + JSONObject returnObject = new JSONObject(); + returnObject.put("spentCredits",spentCredits); + returnObject.put("unspentCredits",unspentCredits); + + return returnObject; + } + + /** + * A call to close all open IPFS streams + */ + public static void closeStreams(){ + executeIPFSCommands("ipfs p2p close --all"); + } + + public static int onlinePeersCount() throws JSONException, IOException, InterruptedException { + JSONArray peersArray = peersOnlineStatus(); + int count = 0; + for (int i = 0; i < peersArray.length(); i++){ + if(peersArray.getJSONObject(i).getString("onlineStatus").contains("online")) + count++; + } + return count; + } + + + public static ArrayList swarmPeersList() throws IOException, InterruptedException { + String OS = getOsName(); + String[] command = new String[3]; + if(OS.contains("Mac") || OS.contains("Linux")){ + command[0] = "bash"; + command[1] = "-c"; + } + else if(OS.contains("Windows")){ + command[0] = "cmd.exe"; + command[1] = "/c"; + } + command[2] = "export PATH=/usr/local/bin:$PATH && ipfs swarm peers"; + + Process P = Runtime.getRuntime().exec(command); + BufferedReader br = new BufferedReader(new InputStreamReader(P.getInputStream())); + + ArrayList peersArray = new ArrayList(); + String line; + while((line = br.readLine()) != null) { + peersArray.add(line); + } + if (!OS.contains("Windows")) + P.waitFor(); + br.close(); + P.destroy(); + + ArrayList peersIdentities = new ArrayList(); + if(peersArray.size() != 0){ + List k = ipfs.swarm.peers(); + for(int i = 0; i < k.size(); i++) + peersIdentities.add(k.get(i).toString().substring(0, 46)); + + return peersIdentities; + } + return peersArray; + } + /** + * A call to get the online/offline status of your contacts + * @return List indicating online status of each DID contact + * @throws JSONException handles JSON Exceptions + * @throws IOException handles IO Exceptions + */ + public static JSONArray peersOnlineStatus() throws JSONException, IOException, InterruptedException { + ArrayList peersArray = swarmPeersList(); + String dataTable = readFile(DATA_PATH + "DataTable.json"); + JSONArray dataArray = new JSONArray(dataTable); + JSONArray onlinePeers = new JSONArray(); + + for(int i = 0; i < dataArray.length(); i++){ + JSONObject peerObject = dataArray.getJSONObject(i); + String peerID = peerObject.getString("peerid"); + if(peersArray.contains(peerID)){ + JSONObject onlinePeersObject = new JSONObject(); + onlinePeersObject.put("did", getValues(DATA_PATH + "DataTable.json", "didHash", "peerid", peerID)); + onlinePeersObject.put("onlineStatus", "online"); + onlinePeers.put(onlinePeersObject); + } + else{ + JSONObject onlinePeersObject = new JSONObject(); + onlinePeersObject.put("did", getValues(DATA_PATH + "DataTable.json", "didHash", "peerid", peerID)); + onlinePeersObject.put("onlineStatus", "offline"); + onlinePeers.put(onlinePeersObject); } } - APILogger.info("Transaction Details for : " + obj.toString()); - return resultArray; + + return onlinePeers; + } + + /** + * A call to list out all contacts in the user wallet + * @return A list of user wallet contacts + * @throws JSONException handles JSON Exceptions + */ + public static JSONArray contacts() throws JSONException { + String dataTable = readFile(DATA_PATH + "DataTable.json"); + JSONArray dataArray = new JSONArray(dataTable); + JSONArray didArray = new JSONArray(); + for (int i = 0; i < dataArray.length(); i++){ + didArray.put(dataArray.getJSONObject(i).getString("didHash")); + } + return didArray; + } + + + public static JSONObject syncNetworkNodes() throws JSONException, IOException { + String dataTable = readFile(DATA_PATH + "DataTable.json"); + JSONArray dataArray = new JSONArray(dataTable); + + for (int i = 0; i < dataArray.length(); i++) + nodeData(dataArray.getJSONObject(i).getString("didHash"), dataArray.getJSONObject(i).getString("walletHash"), ipfs); + + return new JSONObject("{\"message\":\"Synced all nodes\"}"); } /** * A call to get the account information - * * @return Detailed explanation of the account information of the user * @throws JSONException handles JSON Exceptions + * @files TransactionHistory.json, DID.json */ public static JSONArray accountInformation() throws JSONException { int txnAsSender = 0, txnAsReceiver = 0; @@ -195,13 +332,12 @@ public static JSONArray accountInformation() throws JSONException { String transactionHistory = readFile(WALLET_DATA_PATH + "TransactionHistory.json"); JSONArray transArray = new JSONArray(transactionHistory); - if (!(transArray.length() == 0)) { + if(!(transArray.length() == 0)){ for (int i = 0; i < transArray.length(); i++) { objectParser = transArray.getJSONObject(i); if (objectParser.get("role").equals("Sender")) txnAsSender++; - else - txnAsReceiver++; + else txnAsReceiver++; } } @@ -212,83 +348,107 @@ public static JSONArray accountInformation() throws JSONException { accountDetails.put("wid", wid); accountDetails.put("senderTxn", txnAsSender); accountDetails.put("receiverTxn", txnAsReceiver); - accountDetails.put("totalTxn", txnAsSender + txnAsReceiver); + accountDetails.put("totalTxn", txnAsSender+txnAsReceiver); resultArray.put(accountDetails); return resultArray; } /** - * A method to add and host your DID ans Public share to ipfs + * A call to list out number of transactions made per day + * @return List of transactions committed on every date + * @throws JSONException handles JSON Exceptions + * @files TransactionHistory.json */ - public static void addPublicData() { - String peerID = getPeerID(DATA_PATH + "DID.json"); - String didHash = getValues(DATA_PATH + "DataTable.json", "didHash", "peerid", peerID); - String walletHash = getValues(DATA_PATH + "DataTable.json", "walletHash", "peerid", peerID); + public static JSONArray txnPerDay() throws JSONException { + String dataTableFileContent = readFile(WALLET_DATA_PATH + "TransactionHistory.json"); + JSONArray dataTable = new JSONArray(dataTableFileContent); + HashSet dateSet = new HashSet<>(); + for(int i = 0; i < dataTable.length(); i++) + dateSet.add(dataTable.getJSONObject(i).getString("Date")); - add(DATA_PATH.concat(didHash).concat("/DID.png"), ipfs); - pin(didHash, ipfs); + JSONObject datesTxn = new JSONObject(); + Iterator dateIterator = dateSet.iterator(); + while (dateIterator.hasNext()){ + String date = dateIterator.next(); + int count = 0; + for(int i = 0; i < dataTable.length(); i++){ + JSONObject obj = dataTable.getJSONObject(i); - add(DATA_PATH.concat(didHash).concat("/PublicShare.png"), ipfs); - pin(walletHash, ipfs); + if(date.equals(obj.getString("Date"))){ + count++; + } + } + datesTxn.put(date, count); + + } + return new JSONArray().put(datesTxn); } /** - * A call to sync all the nodes in the network - * - * @return Message if failed or succeeded - * @throws IOException + * A call to get details of a transaction given its ID + * @param txnId Transaction ID + * @return Transaction Details + * @throws JSONException handles JSON Exceptions + * @files TransactionHistory.json */ - public static String networkInfo() throws IOException, JSONException { - StringBuilder result = new StringBuilder(); + public static JSONArray transactionDetails(String txnId) throws JSONException { + String transactionHistory = readFile(WALLET_DATA_PATH + "TransactionHistory.json"); + JSONObject countResult = new JSONObject(); JSONArray resultArray = new JSONArray(); - JSONObject jsonObject = new JSONObject(); - int syncFlag = 0; - URL url = new URL(SYNC_IP + "/get"); - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setRequestMethod("GET"); - BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream())); - String line; - - while ((line = rd.readLine()) != null) { - result.append(line); - syncFlag = 1; + if (transactionHistory.length() == 0){ + countResult.put("Message", "No transactions found"); + resultArray.put(countResult); + return resultArray; } - rd.close(); + JSONArray transactionArray = new JSONArray(transactionHistory); + JSONObject transactionObject = new JSONObject(); + for (int i = 0; i < transactionArray.length(); i++) { + transactionObject = transactionArray.getJSONObject(i); + if (transactionObject.get("txn").equals(txnId)) { + transactionObject.remove("essentialShare"); + + if(transactionObject.has("amount-received")){ + transactionObject.put("amount", transactionObject.getDouble("amount-received")); + }else if(transactionObject.has("amount-spent")){ + transactionObject.put("amount", transactionObject.getDouble("amount-spent")); + } + else if(transactionObject.has("amount")) + transactionObject.put("amount", transactionObject.getDouble("amount")); + else{ + JSONArray tokensArray = (JSONArray)transactionObject.get("tokens"); + transactionObject.put("amount", tokensArray.length()); + } + + resultArray.put(transactionObject); + } - writeToFile(DATA_PATH + "DataTable.json", result.toString(), false); - if (syncFlag == 1) { - jsonObject.put("message", "Synced Successfully!"); - } else { - jsonObject.put("message", "Not synced! Try again after sometime."); } - resultArray.put(jsonObject); - return resultArray.toString(); + APILogger.info("Transaction Details for : " + transactionObject.toString()); + return resultArray; } /** * A call to get list transactions between two mentioned dates - * * @param s Start Date * @param e End Date * @return List of transactions * @throws JSONException handles JSON Exceptions + * @files TransactionHistory.json */ public static JSONArray transactionsByDate(String s, String e) throws JSONException, ParseException { JSONArray resultArray = new JSONArray(); - String strDateFormat = "yyyy-MMM-dd HH:mm:ss"; // Date format is Specified + String strDateFormat = "yyyy-MMM-dd HH:mm:ss"; //Date format is Specified SimpleDateFormat objSDF = new SimpleDateFormat(strDateFormat); - Date date1 = new SimpleDateFormat("E MMM dd HH:mm:ss Z yyyy").parse(s); - String startDateString = objSDF.format(date1); - Date date2 = new SimpleDateFormat("E MMM dd HH:mm:ss Z yyyy").parse(e); - String endDateString = objSDF.format(date2); + Date date1=new SimpleDateFormat("E MMM dd HH:mm:ss Z yyyy").parse(s); + String startDateString= objSDF.format(date1); + Date date2=new SimpleDateFormat("E MMM dd HH:mm:ss Z yyyy").parse(e); + String endDateString= objSDF.format(date2); JSONObject countResult = new JSONObject(); Date startDate = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss").parse(startDateString); Date endDate = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss").parse(endDateString); - APILogger.debug("start date is " + startDate); - APILogger.debug("end date is " + endDate); File fileCheck1 = new File(WALLET_DATA_PATH + "TransactionHistory.json"); if (!fileCheck1.exists()) { countResult.put("Message", "File not found"); @@ -297,32 +457,38 @@ public static JSONArray transactionsByDate(String s, String e) throws JSONExcept } String transactionHistory = readFile(WALLET_DATA_PATH + "TransactionHistory.json"); JSONArray transArray = new JSONArray(transactionHistory); - APILogger.debug(transArray.length()); - if (transArray.length() == 0) { + if (transArray.length() == 0){ countResult.put("Message", "No Transactions made yet"); resultArray.put(countResult); return resultArray; } - JSONObject obj; - for (int i = 0; i < transArray.length(); i++) { - obj = transArray.getJSONObject(i); - String dateFromTxnHistoryString = obj.get("Date").toString(); - Date dateTH = new SimpleDateFormat("E MMM dd HH:mm:ss Z yyyy").parse(dateFromTxnHistoryString); - String dateTHS = objSDF.format(dateTH); - Calendar c = Calendar.getInstance(); - c.setTime(objSDF.parse(dateTHS)); - dateTH = c.getTime(); - if (dateTH.after(startDate) && dateTH.before(endDate)) { - obj.remove("essentialShare"); - - if (obj.has("amount")) - obj.put("amount", obj.getDouble("amount")); - else { - JSONArray tokensArray = (JSONArray) obj.get("tokens"); - obj.put("amount", tokensArray.length()); + JSONObject transactionObject; + for (int i=0;i= transArray.length()) { - for (int i = transArray.length() - 1; i >= 0; i--) { - obj = transArray.getJSONObject(i); - obj.remove("essentialShare"); - if (obj.has("amount")) - obj.put("amount", obj.getDouble("amount")); - else { - JSONArray tokensArray = (JSONArray) obj.get("tokens"); - obj.put("amount", tokensArray.length()); + for (int i = transArray.length()-1; i>=0; i--) { + transactionObject = transArray.getJSONObject(i); + transactionObject.remove("essentialShare"); + if(transactionObject.has("amount-received")){ + transactionObject.put("amount", transactionObject.getDouble("amount-received")); + }else if(transactionObject.has("amount-spent")){ + transactionObject.put("amount", transactionObject.getDouble("amount-spent")); + } + else if(transactionObject.has("amount")) + transactionObject.put("amount", transactionObject.getDouble("amount")); + else{ + JSONArray tokensArray = (JSONArray)transactionObject.get("tokens"); + transactionObject.put("amount", tokensArray.length()); } - resultArray.put(obj); + resultArray.put(transactionObject); } return resultArray; } - for (int i = 1; i <= n; i++) { + for( int i = 1; i <= n; i++) { - obj = transArray.getJSONObject(transArray.length() - i); - obj.remove("essentialShare"); - if (obj.has("amount")) - obj.put("amount", obj.getDouble("amount")); - else { - JSONArray tokensArray = (JSONArray) obj.get("tokens"); - obj.put("amount", tokensArray.length()); + transactionObject = transArray.getJSONObject(transArray.length() - i); + transactionObject.remove("essentialShare"); + if(transactionObject.has("amount-received")){ + transactionObject.put("amount", transactionObject.getDouble("amount-received")); + }else if(transactionObject.has("amount-spent")){ + transactionObject.put("amount", transactionObject.getDouble("amount-spent")); + } + else if(transactionObject.has("amount")) + transactionObject.put("amount", transactionObject.getDouble("amount")); + else{ + JSONArray tokensArray = (JSONArray)transactionObject.get("tokens"); + transactionObject.put("amount", tokensArray.length()); } - resultArray.put(obj); + resultArray.put(transactionObject); } return resultArray; } /** * A call to get list transactions within a range - * * @param start start index - * @param end end index + * @param end end index * @return List of transactions * @throws JSONException handles JSON Exceptions + * @files TransactionHistory.json */ public static JSONArray transactionsByRange(int start, int end) throws JSONException { JSONObject countResult = new JSONObject(); JSONArray resultArray = new JSONArray(); - if (start <= 0 || end <= 0) { + if (start < 0 || end <= 0) { countResult.put("Message", "Count can't be null or negative"); resultArray.put(countResult); return resultArray; } - if (start > end) { + if(start > end){ countResult.put("Message", "Invalid ranges"); resultArray.put(countResult); return resultArray; @@ -420,133 +596,104 @@ public static JSONArray transactionsByRange(int start, int end) throws JSONExcep String transactionHistory = readFile(WALLET_DATA_PATH + "TransactionHistory.json"); JSONArray transArray = new JSONArray(transactionHistory); - if (transArray.length() == 0) { + if (transArray.length() == 0){ resultArray.put(countResult); return resultArray; } - if (!(end < transArray.length())) { + + if(!(end < transArray.length())) { for (int i = start; i < transArray.length(); i++) { - JSONObject obj = transArray.getJSONObject(i); - obj.remove("essentialShare"); - if (obj.has("amount")) - obj.put("amount", obj.getDouble("amount")); - else { - JSONArray tokensArray = (JSONArray) obj.get("tokens"); - obj.put("amount", tokensArray.length()); + JSONObject transactionObject = transArray.getJSONObject(i); + transactionObject.remove("essentialShare"); + if(transactionObject.has("amount-received")){ + transactionObject.put("amount", transactionObject.getDouble("amount-received")); + }else if(transactionObject.has("amount-spent")){ + transactionObject.put("amount", transactionObject.getDouble("amount-spent")); + } + else if(transactionObject.has("amount")) + transactionObject.put("amount", transactionObject.getDouble("amount")); + else{ + JSONArray tokensArray = (JSONArray)transactionObject.get("tokens"); + transactionObject.put("amount", tokensArray.length()); } - resultArray.put(obj); + resultArray.put(transactionObject); } - } else { - if (start == end) { - JSONObject obj = transArray.getJSONObject(start); - obj.remove("essentialShare"); - if (obj.has("amount")) - obj.put("amount", obj.getDouble("amount")); - else { - JSONArray tokensArray = (JSONArray) obj.get("tokens"); - obj.put("amount", tokensArray.length()); + }else{ + if(start == end){ + JSONObject transactionObject = transArray.getJSONObject(start); + transactionObject.remove("essentialShare"); + if(transactionObject.has("amount-received")){ + transactionObject.put("amount", transactionObject.getDouble("amount-received")); + }else if(transactionObject.has("amount-spent")){ + transactionObject.put("amount", transactionObject.getDouble("amount-spent")); + } + else if(transactionObject.has("amount")) + transactionObject.put("amount", transactionObject.getDouble("amount")); + else{ + JSONArray tokensArray = (JSONArray)transactionObject.get("tokens"); + transactionObject.put("amount", tokensArray.length()); } - resultArray.put(obj); + resultArray.put(transactionObject); } - for (int i = start; i < end; i++) { - JSONObject obj = transArray.getJSONObject(i); - obj.remove("essentialShare"); - if (obj.has("amount")) - obj.put("amount", obj.getDouble("amount")); - else { - JSONArray tokensArray = (JSONArray) obj.get("tokens"); - obj.put("amount", tokensArray.length()); + else { + for (int i = start; i <= end; i++) { + JSONObject transactionObject = transArray.getJSONObject(i); + transactionObject.remove("essentialShare"); + if (transactionObject.has("amount-received")) { + transactionObject.put("amount", transactionObject.getDouble("amount-received")); + } else if (transactionObject.has("amount-spent")) { + transactionObject.put("amount", transactionObject.getDouble("amount-spent")); + } else if (transactionObject.has("amount")) + transactionObject.put("amount", transactionObject.getDouble("amount")); + else { + JSONArray tokensArray = (JSONArray) transactionObject.get("tokens"); + transactionObject.put("amount", tokensArray.length()); + } + resultArray.put(transactionObject); } - - resultArray.put(obj); } } return resultArray; } - /** - * @throws JSONException - * - */ - public static JSONObject creditsInfo() throws JSONException { - // String thFile = WALLET_DATA_PATH.concat("TransactionHistory.json"); - String qstFile = WALLET_DATA_PATH.concat("QuorumSignedTransactions.json"); - String mineFile = WALLET_DATA_PATH.concat("MinedCreditsHistory.json"); - - // File txnFile = new File(thFile); - File quorumFile = new File(qstFile); - File minedFile = new File(mineFile); - - // int txnCount = 0; - // if(txnFile.exists()){ - // String transactionFile = - // readFile(WALLET_DATA_PATH.concat("TransactionHistory.json")); - // JSONArray txnArray = new JSONArray(transactionFile); - // txnCount = txnArray.length(); - // - // } - int spentCredits = 0; - int unspentCredits = 0; - if (quorumFile.exists()) { - String qFile = readFile(qstFile); - JSONArray qArray = new JSONArray(qFile); - unspentCredits = qArray.length(); - } - if (minedFile.exists()) { - String mFile = readFile(mineFile); - JSONArray mArray = new JSONArray(mFile); - spentCredits = mArray.length(); - } - - JSONObject returnObject = new JSONObject(); - // returnObject.put("txnCount",txnCount); - returnObject.put("spentCredits", spentCredits); - returnObject.put("unspentCredits", unspentCredits); - - return returnObject; - } - - /** - * A call to close all open IPFS streams - */ - public static void closeStreams() { - executeIPFSCommands("ipfs p2p close --all"); - } - /** * A call to get list transactions with the mentioned comment - * * @param comment Comment * @return List of transactions * @throws JSONException handles JSON Exceptions + * @files TransactionHistory.json */ public static JSONArray transactionsByComment(String comment) throws JSONException { String transactionHistory = readFile(WALLET_DATA_PATH + "TransactionHistory.json"); JSONArray transArray = new JSONArray(transactionHistory); - JSONObject obj; + JSONObject transactionObject; JSONArray resultArray = new JSONArray(); for (int i = 0; i < transArray.length(); i++) { - obj = transArray.getJSONObject(i); - - if (obj.get("comment").equals(comment)) { - obj.remove("essentialShare"); - if (obj.has("amount")) - obj.put("amount", obj.getDouble("amount")); - else { - JSONArray tokensArray = (JSONArray) obj.get("tokens"); - obj.put("amount", tokensArray.length()); + transactionObject = transArray.getJSONObject(i); + + if (transactionObject.get("comment").equals(comment)) { + transactionObject.remove("essentialShare"); + if(transactionObject.has("amount-received")){ + transactionObject.put("amount", transactionObject.getDouble("amount-received")); + }else if(transactionObject.has("amount-spent")){ + transactionObject.put("amount", transactionObject.getDouble("amount-spent")); } - - resultArray.put(obj); + else if(transactionObject.has("amount")) + transactionObject.put("amount", transactionObject.getDouble("amount")); + else{ + JSONArray tokensArray = (JSONArray)transactionObject.get("tokens"); + transactionObject.put("amount", tokensArray.length()); + } + resultArray.put(transactionObject); } } - if (resultArray.length() < 1) { + if(resultArray.length() < 1){ JSONObject returnObject = new JSONObject(); returnObject.put("Message", "No transactions found with the comment " + comment); resultArray.put(returnObject); @@ -555,172 +702,39 @@ public static JSONArray transactionsByComment(String comment) throws JSONExcepti return resultArray; } + /** * A call to get list transactions made by the user with the input Did - * * @param did DID of the contact * @return List of transactions committed with the user DID * @throws JSONException handles JSON Exceptions + * @files TransactionHistory.json */ public static JSONArray transactionsByDID(String did) throws JSONException { String transactionHistory = readFile(WALLET_DATA_PATH + "TransactionHistory.json"); JSONArray transArray = new JSONArray(transactionHistory); JSONArray resultArray = new JSONArray(); for (int i = 0; i < transArray.length(); i++) { - JSONObject obj = transArray.getJSONObject(i); - obj.remove("essentialShare"); + JSONObject transactionObject = transArray.getJSONObject(i); + transactionObject.remove("essentialShare"); + + if (transactionObject.get("senderDID").equals(did) || transactionObject.get("receiverDID").equals(did)) { + if (transactionObject.has("amount-received")) { + transactionObject.put("amount", transactionObject.getDouble("amount-received")); + } else if (transactionObject.has("amount-spent")) { + transactionObject.put("amount", transactionObject.getDouble("amount-spent")); + } else if (transactionObject.has("amount")) + transactionObject.put("amount", transactionObject.getDouble("amount")); + else { + JSONArray tokensArray = (JSONArray) transactionObject.get("tokens"); + transactionObject.put("amount", tokensArray.length()); + } - if (obj.has("amount")) - obj.put("amount", obj.getDouble("amount")); - else { - JSONArray tokensArray = (JSONArray) obj.get("tokens"); - obj.put("amount", tokensArray.length()); + resultArray.put(transactionObject); } - - resultArray.put(obj); - - if (obj.get("senderDID").equals(did) || obj.get("receiverDID").equals(did)) - resultArray.put(obj); } return resultArray; } - public static int onlinePeersCount() throws JSONException, IOException, InterruptedException { - JSONArray peersArray = peersOnlineStatus(); - int count = 0; - for (int i = 0; i < peersArray.length(); i++) { - if (peersArray.getJSONObject(i).getString("onlineStatus").contains("online")) - count++; - } - return count; - } - - public static ArrayList swarmPeersList() throws IOException, InterruptedException { - String OS = getOsName(); - String[] command = new String[3]; - if (OS.contains("Mac") || OS.contains("Linux")) { - command[0] = "bash"; - command[1] = "-c"; - } else if (OS.contains("Windows")) { - command[0] = "cmd.exe"; - command[1] = "/c"; - } - command[2] = "export PATH=/usr/local/bin:$PATH && ipfs swarm peers"; - - Process P = Runtime.getRuntime().exec(command); - BufferedReader br = new BufferedReader(new InputStreamReader(P.getInputStream())); - - ArrayList peersArray = new ArrayList(); - String line; - while ((line = br.readLine()) != null) { - peersArray.add(line); - } - if (!OS.contains("Windows")) - P.waitFor(); - br.close(); - P.destroy(); - - ArrayList peersIdentities = new ArrayList(); - if (peersArray.size() != 0) { - List k = ipfs.swarm.peers(); - for (int i = 0; i < k.size(); i++) - peersIdentities.add(k.get(i).toString().substring(0, 46)); - - return peersIdentities; - } - return peersArray; - } - - /** - * A call to get the online/offline status of your contacts - * - * @return List indicating online status of each DID contact - * @throws JSONException handles JSON Exceptions - * @throws IOException handles IO Exceptions - */ - public static JSONArray peersOnlineStatus() throws JSONException, IOException, InterruptedException { - ArrayList peersArray = swarmPeersList(); - String dataTable = readFile(DATA_PATH + "DataTable.json"); - JSONArray dataArray = new JSONArray(dataTable); - JSONArray onlinePeers = new JSONArray(); - - for (int i = 0; i < dataArray.length(); i++) { - JSONObject peerObject = dataArray.getJSONObject(i); - String peerID = peerObject.getString("peerid"); - if (peersArray.contains(peerID)) { - JSONObject onlinePeersObject = new JSONObject(); - onlinePeersObject.put("did", getValues(DATA_PATH + "DataTable.json", "didHash", "peerid", peerID)); - onlinePeersObject.put("onlineStatus", "online"); - onlinePeers.put(onlinePeersObject); - } else { - JSONObject onlinePeersObject = new JSONObject(); - onlinePeersObject.put("did", getValues(DATA_PATH + "DataTable.json", "didHash", "peerid", peerID)); - onlinePeersObject.put("onlineStatus", "offline"); - onlinePeers.put(onlinePeersObject); - } - - } - - return onlinePeers; - } - - /** - * A call to list out all contacts in the user wallet - * - * @return A list of user wallet contacts - * @throws JSONException handles JSON Exceptions - */ - public static JSONArray contacts() throws JSONException { - String dataTable = readFile(DATA_PATH + "DataTable.json"); - JSONArray dataArray = new JSONArray(dataTable); - JSONArray didArray = new JSONArray(); - for (int i = 0; i < dataArray.length(); i++) { - didArray.put(dataArray.getJSONObject(i).getString("didHash")); - } - return didArray; - } - - /** - * A call to list out number of transactions made per day - * - * @return List of transactions committed on every date - * @throws JSONException handles JSON Exceptions - */ - public static JSONArray txnPerDay() throws JSONException { - String dataTable = readFile(WALLET_DATA_PATH + "TransactionHistory.json"); - JSONArray dataArray = new JSONArray(dataTable); - HashSet dateSet = new HashSet<>(); - for (int i = 0; i < dataArray.length(); i++) - dateSet.add(dataArray.getJSONObject(i).getString("Date")); - - JSONObject datesTxn = new JSONObject(); - Iterator dateIterator = dateSet.iterator(); - while (dateIterator.hasNext()) { - String date = dateIterator.next(); - int count = 0; - for (int i = 0; i < dataArray.length(); i++) { - JSONObject obj = dataArray.getJSONObject(i); - - if (date.equals(obj.getString("Date"))) { - count++; - } - } - datesTxn.put(date, count); - - } - - return new JSONArray().put(datesTxn); - } - - public static JSONObject syncNetworkNodes() throws JSONException, IOException { - String dataTable = readFile(DATA_PATH + "DataTable.json"); - JSONArray dataArray = new JSONArray(dataTable); - - for (int i = 0; i < dataArray.length(); i++) - nodeData(dataArray.getJSONObject(i).getString("didHash"), - dataArray.getJSONObject(i).getString("walletHash"), ipfs); - - return new JSONObject("{\"message\":\"Synced all nodes\"}"); - } } diff --git a/src/com/rubix/Resources/Functions.java b/src/com/rubix/Resources/Functions.java index e03ff34c..5d9eda11 100644 --- a/src/com/rubix/Resources/Functions.java +++ b/src/com/rubix/Resources/Functions.java @@ -1,23 +1,22 @@ package com.rubix.Resources; -import static com.rubix.Resources.APIHandler.addPublicData; -import static com.rubix.Resources.IPFSNetwork.checkSwarmConnect; -import static com.rubix.Resources.IPFSNetwork.dhtOwnerCheck; -import static com.rubix.Resources.IPFSNetwork.executeIPFSCommands; -import static com.rubix.Resources.IPFSNetwork.forwardCheck; -import static com.rubix.Resources.IPFSNetwork.listen; +import com.rubix.AuthenticateNode.PropImage; +import com.rubix.Ping.PingCheck; +import io.ipfs.api.IPFS; +import io.ipfs.multiaddr.MultiAddress; +import org.apache.log4j.Logger; +import org.apache.log4j.PropertyConfigurator; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import javax.imageio.ImageIO; import java.awt.image.BufferedImage; -import java.io.BufferedReader; -import java.io.DataOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStreamReader; +import java.io.*; import java.math.RoundingMode; import java.net.HttpURLConnection; +import java.net.Socket; +import java.net.SocketException; import java.net.URL; import java.nio.charset.StandardCharsets; import java.nio.file.Files; @@ -31,17 +30,9 @@ import java.util.Date; import java.util.Iterator; -import javax.imageio.ImageIO; - -import com.rubix.AuthenticateNode.PropImage; - -import org.apache.log4j.Logger; -import org.apache.log4j.PropertyConfigurator; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; +import static com.rubix.Resources.APIHandler.addPublicData; +import static com.rubix.Resources.IPFSNetwork.*; -import io.ipfs.api.IPFS; public class Functions { @@ -52,8 +43,7 @@ public class Functions { public static String LOGGER_PATH = ""; public static String WALLET_DATA_PATH = ""; public static String PAYMENTS_PATH = ""; - public static int RECEIVER_PORT, GOSSIP_SENDER, GOSSIP_RECEIVER, QUORUM_PORT, SENDER2Q1, SENDER2Q2, SENDER2Q3, - SENDER2Q4, SENDER2Q5, SENDER2Q6, SENDER2Q7; + public static int RECEIVER_PORT, GOSSIP_SENDER, GOSSIP_RECEIVER, QUORUM_PORT, SENDER2Q1, SENDER2Q2, SENDER2Q3, SENDER2Q4, SENDER2Q5, SENDER2Q6, SENDER2Q7; public static int QUORUM_COUNT; public static int SEND_PORT; public static int IPFS_PORT; @@ -70,37 +60,6 @@ public class Functions { public static Logger FunctionsLogger = Logger.getLogger(Functions.class); - public static String buildVersion() throws IOException { - String initPath = Functions.class.getProtectionDomain().getCodeSource().getLocation().getPath(); - initPath = initPath.split("\\.jar")[0]; - initPath = initPath + ".jar"; - String initHash = calculateFileHash(initPath, "MD5"); - return initHash; - } - - public static String calculateFileHash(String filePath, String algorithm) { - String hash = ""; - try { - MessageDigest digest = MessageDigest.getInstance(algorithm); - System.out.println("File path: " + filePath); - System.out.println("File Hashing..."); - FileInputStream fis = new FileInputStream(filePath); - System.out.println("File read OK"); - byte[] dataBytes = new byte[1024]; - int nread = 0; - while ((nread = fis.read(dataBytes)) != -1) { - digest.update(dataBytes, 0, nread); - } - byte[] hashBytes = digest.digest(); - hash = bytesToHex(hashBytes); - fis.close(); - } catch (NoSuchAlgorithmException | IOException e) { - FunctionsLogger.error("Invalid Cryptographic Algorithm", e); - e.printStackTrace(); - } - return hash; - } - public static void setDir() { String OSName = getOsName(); if (OSName.contains("Windows")) @@ -163,11 +122,13 @@ public static void pathSet() { BOOTSTRAPS = pathsArray.getJSONArray(5); + } catch (JSONException e) { e.printStackTrace(); } } + public static void nodeData(String did, String wid, IPFS ipfs) throws IOException { PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); File dataFolder = new File(DATA_PATH + did + "/"); @@ -241,9 +202,9 @@ public static String getSystemUser() { return lineID; } + /** - * This method calculates different types of hashes as mentioned in the passed - * parameters for the mentioned message + * This method calculates different types of hashes as mentioned in the passed parameters for the mentioned message * * @param message Input string to be hashed * @param algorithm Specification of the algorithm used for hashing @@ -310,13 +271,13 @@ public static String bytesToHex(byte[] inputHash) { StringBuilder outputHexString = new StringBuilder(); for (byte b : inputHash) { String hex = Integer.toHexString(0xff & b); - if (hex.length() == 1) - outputHexString.append('0'); + if (hex.length() == 1) outputHexString.append('0'); outputHexString.append(hex); } return outputHexString.toString(); } + /** * This method returns the content of the file passed to it * @@ -338,15 +299,14 @@ public static String readFile(String filePath) { return fileContent.toString(); } + /** * This method writes the mentioned data into the file passed to it - * This also allows to take a decision on whether or not to append the data to - * the already existing content in the file + * This also allows to take a decision on whether or not to append the data to the already existing content in the file * * @param filePath Location of the file to be read and written into * @param data Data to be added - * @param appendStatus Decides whether or not to append the new data into the - * already existing data + * @param appendStatus Decides whether or not to append the new data into the already existing data */ public synchronized static void writeToFile(String filePath, String data, Boolean appendStatus) { @@ -387,6 +347,7 @@ public static String getSignFromShares(String filePath, String hash) throws IOEx return p1; } + /** * This function will sign on JSON data with private share * @@ -431,28 +392,6 @@ public static void listenThread(JSONObject connectObject) { } - /** - * This function check if the token is pinned by the given DID - * - * @param token ID and DID of owner of the token to be checked - * @return boolean value - */ - public static boolean checkTokenOwnershiByDID(String tokenID, String DID) { - boolean ownStatus = false; - String peerID = getValues(DATA_PATH + "DataTable.json", "peerid", - "didHash", DID); - try { - ArrayList owners = dhtOwnerCheck(tokenID); - if (owners.contains(peerID)) { - ownStatus = true; - } - - } catch (InterruptedException | JSONException | IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return ownStatus; - } /** * This function converts any integer to its binary form @@ -540,8 +479,7 @@ public static void updateJSON(String operation, String filePath, String data) { } /** - * This method gets you a required data from a JSON file with a tag to be - * compared with + * This method gets you a required data from a JSON file with a tag to be compared with * * @param filePath Location of the JSON file * @param get Data to be fetched from the file @@ -578,8 +516,7 @@ public static String getOsName() { } /** - * This function calculates the minimum number of quorum peers required for - * consensus to work + * This function calculates the minimum number of quorum peers required for consensus to work * * @return Minimum number of quorum count for consensus to work */ @@ -588,8 +525,7 @@ public static int minQuorum() { } /** - * This function calculates the minimum number of quorum peers required for - * consensus to work + * This function calculates the minimum number of quorum peers required for consensus to work * * @return Minimum number of quorum count for consensus to work */ @@ -597,6 +533,7 @@ public static int minQuorum(int count) { return (((count - 1) / 3) * 2) + 1; } + /** * This method checks if Quorum is available for consensus * @@ -635,6 +572,7 @@ public static ArrayList QuorumCheck(JSONArray quorum, int size) { * @param ipfs ipfs instance */ + public static void QuorumSwarmConnect(JSONArray quorum, IPFS ipfs) { PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); @@ -653,6 +591,7 @@ public static void QuorumSwarmConnect(JSONArray quorum, IPFS ipfs) { } + /** * This method identifies the Peer ID of the system by IPFS during installation * @@ -660,6 +599,7 @@ public static void QuorumSwarmConnect(JSONArray quorum, IPFS ipfs) { * @return Your system's Peer ID assigned by IPFS */ + public static String getPeerID(String filePath) { PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); JSONArray fileContentArray; @@ -677,6 +617,7 @@ public static String getPeerID(String filePath) { return peerid; } + public static int[] getPrivatePosition(int[] positions, int[] privateArray) { int[] PrivatePosition = new int[positions.length]; for (int k = 0; k < positions.length; k++) { @@ -687,8 +628,7 @@ public static int[] getPrivatePosition(int[] positions, int[] privateArray) { return PrivatePosition; } - public static JSONObject randomPositions(String role, String hash, int numberOfPositions, int[] pvt1) - throws JSONException { + public static JSONObject randomPositions(String role, String hash, int numberOfPositions, int[] pvt1) throws JSONException { int u = 0, l = 0, m = 0; int[] hashCharacters = new int[256]; @@ -745,19 +685,18 @@ public static JSONObject randomPositions(String role, String hash, int numberOfP * @param positionsCount Number of positions required * @return Extended array of positions */ - // public static int[] finalPositions(int[] randomPositions, int positionsCount) - // { - // int[] finalPositions = new int[positionsCount * 64]; - // int u = 0; - // for (int k = 0; k < positionsCount; k++) { - // for (int p = 0; p < 64; p++) { - // finalPositions[u] = randomPositions[k]; - // randomPositions[k]++; - // u++; - // } - // } - // return finalPositions; - // } +// public static int[] finalPositions(int[] randomPositions, int positionsCount) { +// int[] finalPositions = new int[positionsCount * 64]; +// int u = 0; +// for (int k = 0; k < positionsCount; k++) { +// for (int p = 0; p < 64; p++) { +// finalPositions[u] = randomPositions[k]; +// randomPositions[k]++; +// u++; +// } +// } +// return finalPositions; +// } /** * This function deletes the mentioned file @@ -775,43 +714,41 @@ public static void deleteFile(String fileName) { } - // /** - // * This functions picks the required number of quorum members from the - // mentioned file - // * - // * @param filePath Location of the file - // * @param hash Data from which positions are chosen - // * @return List of chosen members from the file - // */ - // public static ArrayList quorumChooser(String filePath, String hash) { - // PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); - // ArrayList quorumList = new ArrayList(); - // try { - // String fileContent = readFile(filePath); - // JSONArray blockHeight = new JSONArray(fileContent); - // - // int[] hashCharacters = new int[256]; - // var randomPositions = new ArrayList(); - // HashSet positionSet = new HashSet<>(); - // for (int k = 0; positionSet.size() != 7; k++) { - // hashCharacters[k] = Character.getNumericValue(hash.charAt(k)); - // randomPositions.add((((2402 + hashCharacters[k]) * 2709) + ((k + 2709) + - // hashCharacters[(k)])) % blockHeight.length()); - // positionSet.add(randomPositions.get(k)); - // } - // - // for (Integer integer : positionSet) - // quorumList.add(blockHeight.getJSONObject(integer).getString("peer-id")); - // } catch (JSONException e) { - // FunctionsLogger.error("JSON Exception Occurred", e); - // e.printStackTrace(); - // } - // return quorumList; - // } + +// /** +// * This functions picks the required number of quorum members from the mentioned file +// * +// * @param filePath Location of the file +// * @param hash Data from which positions are chosen +// * @return List of chosen members from the file +// */ +// public static ArrayList quorumChooser(String filePath, String hash) { +// PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); +// ArrayList quorumList = new ArrayList(); +// try { +// String fileContent = readFile(filePath); +// JSONArray blockHeight = new JSONArray(fileContent); +// +// int[] hashCharacters = new int[256]; +// var randomPositions = new ArrayList(); +// HashSet positionSet = new HashSet<>(); +// for (int k = 0; positionSet.size() != 7; k++) { +// hashCharacters[k] = Character.getNumericValue(hash.charAt(k)); +// randomPositions.add((((2402 + hashCharacters[k]) * 2709) + ((k + 2709) + hashCharacters[(k)])) % blockHeight.length()); +// positionSet.add(randomPositions.get(k)); +// } +// +// for (Integer integer : positionSet) +// quorumList.add(blockHeight.getJSONObject(integer).getString("peer-id")); +// } catch (JSONException e) { +// FunctionsLogger.error("JSON Exception Occurred", e); +// e.printStackTrace(); +// } +// return quorumList; +// } /** - * This function is to be initially called to setup the environment of your - * project + * This function is to be initially called to setup the environment of your project */ public static void launch() { pathSet(); @@ -857,8 +794,7 @@ public static String checkDirectory() throws JSONException { File tokenChainsFolder = new File(TOKENCHAIN_PATH); File walletDataFolder = new File(WALLET_DATA_PATH); - if (!dataFolder.exists() || !loggerFolder.exists() || !tokenChainsFolder.exists() || !tokensFolder.exists() - || !walletDataFolder.exists()) { + if (!dataFolder.exists() || !loggerFolder.exists() || !tokenChainsFolder.exists() || !tokensFolder.exists() || !walletDataFolder.exists()) { dataFolder.delete(); loggerFolder.delete(); tokenChainsFolder.delete(); @@ -935,6 +871,7 @@ public static String mineToken(int level, int tokenNumber) { return token; } + public static String toBinary(int x, int len) { if (len > 0) { return String.format("%" + len + "s", @@ -971,6 +908,7 @@ public static Date getCurrentUtcTime() throws ParseException { return localDateFormat.parse(simpleDateFormat.format(new Date())); } + /** * This method is used to update quorum credits in server * @@ -981,8 +919,8 @@ public static Date getCurrentUtcTime() throws ParseException { * @return mined token */ - public static void updateQuorum(JSONArray quorumArray, JSONArray signedQuorumList, boolean status, int type) - throws IOException, JSONException { + + public static void updateQuorum(JSONArray quorumArray, JSONArray signedQuorumList, boolean status, int type) throws IOException, JSONException { if (type == 1) { String urlQuorumUpdate = ADVISORY_IP + "/updateQuorum"; @@ -1024,6 +962,7 @@ public static void updateQuorum(JSONArray quorumArray, JSONArray signedQuorumLis } } + /** * This method is used get getquorum from advisory node * @@ -1035,8 +974,8 @@ public static void updateQuorum(JSONArray quorumArray, JSONArray signedQuorumLis * @return JSONArray of quorum nodes */ - public static JSONArray getQuorum(String betaHash, String gammaHash, String senderDidIpfsHash, - String receiverDidIpfsHash, int tokenslength) throws IOException, JSONException { + + public static JSONArray getQuorum(String betaHash, String gammaHash, String senderDidIpfsHash, String receiverDidIpfsHash, int tokenslength) throws IOException, JSONException { JSONArray quorumArray; String urlQuorumPick = ADVISORY_IP + "/getQuorum"; URL objQuorumPick = new URL(urlQuorumPick); @@ -1126,14 +1065,6 @@ public static void mineUpdate(String didHash, int credits) throws IOException, J } - public static String initHash() throws IOException { - String initPath = Functions.class.getProtectionDomain().getCodeSource().getLocation().getPath(); - initPath = initPath.split("\\.jar")[0]; - initPath = initPath + ".jar"; - String initHash = calculateFileHash(initPath, "SHA3-256"); - return initHash; - } - public static int checkHeartBeat(String peerId, String appName) { if (forwardCheck(appName, QUORUM_PORT, peerId)) { @@ -1172,66 +1103,7 @@ public static void syncDataTable(String did, String peerId) { } } - /** - * This function will release the port in linux based machines if the port is - * already in use - */ - public static void releasePorts(int port) { - String processStr; - Process processId; - try { - processId = Runtime.getRuntime().exec("lsof -ti :" + port); - long currentPid = ProcessHandle.current().pid(); - BufferedReader br = new BufferedReader( - new InputStreamReader(processId.getInputStream())); - - processId = Runtime.getRuntime().exec("pgrep ipfs"); - BufferedReader ipfsPidBr = new BufferedReader(new InputStreamReader(processId.getInputStream())); - - processStr = br.readLine(); - while (processStr != null - && (String.valueOf(currentPid) != processStr || (ipfsPidBr.readLine() != processStr))) { - FunctionsLogger.debug("Port " + port + " is in using, killing PID " + processStr); - processId = Runtime.getRuntime().exec("kill -9 " + processStr); - - } - processId.waitFor(); - processId.destroy(); - - } catch (Exception e) { - FunctionsLogger.error("Exception Occured at releasePort", e); - e.printStackTrace(); - } - } - - public static void portStatusWindows(int port) { - String processStr; - Process p; - try { - Runtime rt = Runtime.getRuntime(); - Process proc = rt.exec("cmd /c netstat -ano | findstr " + port); - long currentPid = ProcessHandle.current().pid(); - BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream())); - processStr = stdInput.readLine(); - if (processStr != null && String.valueOf(currentPid) != processStr) { - int index = processStr.lastIndexOf(" "); - String sc = processStr.substring(index, processStr.length()); - // System.out.println("Port "+port+" is locked by PID "+sc+". Kindly close this - // port and retry transcation"); - if (sc != String.valueOf(currentPid)) { - FunctionsLogger.debug("Port " + port + " is locked by PID " + sc); - } else { - FunctionsLogger.debug("Port " + port + " is locked by current jar with PID " + sc); - } - - } - } catch (Exception e) { - FunctionsLogger.error("Exception occured at portStatusWindows", e); - e.printStackTrace(); - } - } - - public static void removeToken() throws JSONException { + public static void removeToken() { String bnkFile = readFile(PAYMENTS_PATH.concat("BNK00.json")); JSONArray bnkArray = new JSONArray(bnkFile); JSONObject removeToken = bnkArray.getJSONObject(0); @@ -1257,7 +1129,7 @@ public static void removeToken() throws JSONException { } - public static void tokenBank() throws JSONException { + public static void tokenBank() { pathSet(); String bank = readFile(PAYMENTS_PATH.concat("BNK00.json")); JSONArray bankArray = new JSONArray(bank); @@ -1321,11 +1193,9 @@ public static Double getPartsBalance() throws JSONException { Double availableParts = 0.000D, senderCount = 0.000D, receiverCount = 0.000D; for (int k = 0; k < tokenChainArray.length(); k++) { if (tokenChainArray.getJSONObject(k).has("role")) { - if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") - && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { + if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { senderCount += tokenChainArray.getJSONObject(k).getDouble("amount"); - } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") - && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { + } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { receiverCount += tokenChainArray.getJSONObject(k).getDouble("amount"); } } @@ -1338,6 +1208,7 @@ public static Double getPartsBalance() throws JSONException { parts = formatAmount(parts); balance = balance + parts; + int count = 0; File shiftedFile = new File(PAYMENTS_PATH.concat("ShiftedTokens.json")); if (shiftedFile.exists()) { @@ -1347,6 +1218,7 @@ public static Double getPartsBalance() throws JSONException { for (int i = 0; i < shiftedArray.length(); i++) arrayTokens.add(shiftedArray.getString(i)); + for (int i = 0; i < partTokensArray.length(); i++) { if (!arrayTokens.contains(partTokensArray.getJSONObject(i).getString("tokenHash"))) count++; @@ -1374,11 +1246,9 @@ public static Double checkTokenPartBalance(String tokenHash) throws JSONExceptio Double senderCount = 0.000D, receiverCount = 0.000D; for (int k = 0; k < tokenChainArray.length(); k++) { if (tokenChainArray.getJSONObject(k).has("role")) { - if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") - && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { + if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { senderCount += tokenChainArray.getJSONObject(k).getDouble("amount"); - } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") - && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { + } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { receiverCount += tokenChainArray.getJSONObject(k).getDouble("amount"); } } @@ -1395,6 +1265,7 @@ public static Double checkTokenPartBalance(String tokenHash) throws JSONExceptio return availableParts; } + public static Double getBalance() throws JSONException { pathSet(); Double balance = 0.000D; @@ -1413,6 +1284,7 @@ public static Double getBalance() throws JSONException { balance = balance + value; } + File partsFile = new File(PAYMENTS_PATH + "PartsToken.json"); if (partsFile.exists()) { String PART_TOKEN_CHAIN_PATH = TOKENCHAIN_PATH.concat("/PARTS/"); @@ -1431,11 +1303,9 @@ public static Double getBalance() throws JSONException { Double availableParts = 0.000D, senderCount = 0.000D, receiverCount = 0.000D; for (int k = 0; k < tokenChainArray.length(); k++) { if (tokenChainArray.getJSONObject(k).has("role")) { - if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") - && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { + if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { senderCount += tokenChainArray.getJSONObject(k).getDouble("amount"); - } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") - && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { + } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { receiverCount += tokenChainArray.getJSONObject(k).getDouble("amount"); } } @@ -1458,6 +1328,7 @@ public static Double getBalance() throws JSONException { for (int i = 0; i < shiftedArray.length(); i++) arrayTokens.add(shiftedArray.getString(i)); + for (int i = 0; i < partTokensArray.length(); i++) { if (!arrayTokens.contains(partTokensArray.getJSONObject(i).getString("tokenHash"))) count++; @@ -1468,10 +1339,12 @@ public static Double getBalance() throws JSONException { balance = balance - count; } + balance = formatAmount(balance); return balance; } + public static Double partTokenBalance(String tokenHash) throws JSONException { pathSet(); @@ -1485,11 +1358,9 @@ public static Double partTokenBalance(String tokenHash) throws JSONException { Double senderCount = 0.000D, receiverCount = 0.000D; for (int k = 0; k < tokenChainArray.length(); k++) { if (tokenChainArray.getJSONObject(k).has("role")) { - if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") - && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { + if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { senderCount += tokenChainArray.getJSONObject(k).getDouble("amount"); - } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") - && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { + } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { receiverCount += tokenChainArray.getJSONObject(k).getDouble("amount"); } } @@ -1518,12 +1389,11 @@ public static Double formatAmount(Double amount) { } - public static void clearParts() throws JSONException { + public static void clearParts() { String partsFile = readFile(PAYMENTS_PATH.concat("PartsToken.json")); JSONArray partsArray = new JSONArray(partsFile); for (int i = 0; i < partsArray.length(); i++) { - if (partTokenBalance(partsArray.getJSONObject(i).getString("tokenHash")) <= 0.000 - || partTokenBalance(partsArray.getJSONObject(i).getString("tokenHash")) > 1.000) { + if (partTokenBalance(partsArray.getJSONObject(i).getString("tokenHash")) <= 0.000 || partTokenBalance(partsArray.getJSONObject(i).getString("tokenHash")) > 1.000) { deleteFile(TOKENS_PATH.concat("PARTS/").concat(partsArray.getJSONObject(i).getString("tokenHash"))); partsArray.remove(i); } @@ -1550,5 +1420,280 @@ public static void backgroundChecks() { addPublicData(); } + public static String sanityMessage; + public static boolean sanityCheck(String peerid, IPFS ipfs, int port) throws IOException { + FunctionsLogger.info("Entering SanityCheck"); + boolean sanityCheckErrorFlag = true; + if (sanityCheckErrorFlag && checkIPFSStatus(peerid, ipfs)) { + FunctionsLogger.debug("IPFS is working in " + peerid); + FunctionsLogger.debug("IPFS check true"); + } else { + sanityCheckErrorFlag = false; + FunctionsLogger.debug("IPFS is not working in " + peerid); + FunctionsLogger.debug("IPFS check false"); + sanityMessage = "IPFS is not working in " + peerid; + } + + if (sanityCheckErrorFlag) { + if (bootstrapConnect(peerid, ipfs)) { + FunctionsLogger.debug("Bootstrap connected for " + peerid); + FunctionsLogger.debug("Bootstrap check true"); + } else { + sanityCheckErrorFlag = false; + FunctionsLogger.debug("Bootstrap connection unsuccessful for " + peerid); + FunctionsLogger.debug("Bootstrap check false"); + sanityMessage = "Bootstrap connection unsuccessful for " + peerid; + } + } + + if (sanityCheckErrorFlag) { + if (ping(peerid, port)) { + FunctionsLogger.debug("Jar is running as expected in " + peerid); + FunctionsLogger.debug("Jar check true"); + } else { + sanityCheckErrorFlag = false; + FunctionsLogger.debug("Jar is not running in " + peerid); + FunctionsLogger.debug("Jar check false"); + sanityMessage = "Jar is not running in " + peerid; + } + } + if (sanityCheckErrorFlag) { + if (portCheckAndKill(port)) { + FunctionsLogger.debug("Ports are available for transcations in " + peerid); + FunctionsLogger.debug("Ports check true"); + } else { + sanityCheckErrorFlag = false; + FunctionsLogger.debug("Ports are not available for " + peerid); + FunctionsLogger.debug("Ports check false"); + sanityMessage = "Ports are not available for " + peerid; + } + } + + + return sanityCheckErrorFlag; + } + public static boolean checkIPFSStatus(String peerid, IPFS ipfs) { + FunctionsLogger.info("Entering checkIPFSStatus"); + boolean swarmConnectedStatus = false; + try { + MultiAddress multiAddress = new MultiAddress("/ipfs/" + peerid); + FunctionsLogger.info("MultiAdrress concated " + multiAddress + "|||"); + boolean output = swarmConnectP2P(peerid, ipfs); + + if (output) { + swarmConnectedStatus = true; + FunctionsLogger.debug("Swarm is already connected"); + } else { + swarmConnectedStatus = false; + FunctionsLogger.debug("Swarm is not connected"); + } + } catch (Exception e) { + FunctionsLogger.error("Check Swarm Connect is failed", e); + + } + FunctionsLogger.info("checkIPFSStatus return value is " + swarmConnectedStatus); + return swarmConnectedStatus; + } + + + public static boolean ping(String peerid, int port) throws IOException { + JSONObject pingCheck = PingCheck.Ping(peerid, port); + if (pingCheck.getString("status").contains("Failed")) { + return false; + } else + return true; + + } + +// public static String getPing(int port) { +// try { +// +// String didContent = readFile(DATA_PATH + "DID.json"); +// JSONArray didArray = new JSONArray(didContent); +// String myPeerID = didArray.getJSONObject(0).getString("peerid"); +// +// listen(myPeerID.concat("Ping"), port); +// ServerSocket ss = new ServerSocket(port); +// FunctionsLogger.info("Get Ping Listening on port " + port + " appname " + myPeerID.concat("Ping")); +// Socket socket = ss.accept(); +// BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream())); +// PrintStream output = new PrintStream(socket.getOutputStream()); +// FunctionsLogger.info("getPing- waiting response from server"); +// String peerID = input.readLine(); +// if (peerID != null && peerID.contains("Qm")) { +// FunctionsLogger.info("getPing - Received message from server"); +// output.println("Ping received"); +// FunctionsLogger.debug("Ping received from sender"); +// +// output.close(); +// input.close(); +// socket.close(); +// ss.close(); +// executeIPFSCommands(" ipfs p2p close -t /p2p/" + peerID); +// FunctionsLogger.info("If - Closing Sockets"); +// return "Ping received from sender and Pong sent"; +// } +// else{ +// output.close(); +// input.close(); +// socket.close(); +// ss.close(); +// FunctionsLogger.info("Else - Closing Sockets"); +// return "Ping received from sender but not PeerID"; +// } +// +// } catch (Exception e) { +// FunctionsLogger.error("Error in client side communication", e); +// return "Error in client side communication"; +// } +// } + + public static boolean bootstrapConnect(String peerid, IPFS ipfs) { + FunctionsLogger.info("bootstrapConnect- entering function"); + String bootNode; + boolean bootstrapConnected = false; + + MultiAddress multiAddress = new MultiAddress("/ipfs/" + peerid); + FunctionsLogger.info("bootstrapConnect- multiaddress is " + multiAddress.toString()); + + String output = swarmConnectProcess(multiAddress); + try { + for (int i = 0; i < BOOTSTRAPS.length(); i++) { + FunctionsLogger.info("bootstrapConnect- Bootstrap length is " + BOOTSTRAPS.length()); + + if (!bootstrapConnected) { + FunctionsLogger.info("bootstrapConnect- Connecting to bootstrp " + i); + bootNode = String.valueOf(BOOTSTRAPS.get(i)); + bootNode = bootNode.substring(bootNode.length() - 46); + FunctionsLogger.info("bootstrapConnect- trying to connect with " + bootNode); + + multiAddress = new MultiAddress("/ipfs/" + bootNode); + output = swarmConnectProcess(multiAddress); + FunctionsLogger.info("bootstrapConnect- connection status to " + bootNode + " is " + output); + if (output.contains("success")) { + FunctionsLogger.info("bootstrapConnect- trying to swarm connect"); + multiAddress = new MultiAddress("/ipfs/" + bootNode + "/p2p-circuit/ipfs/" + peerid); + output = swarmConnectProcess(multiAddress); + FunctionsLogger.info("bootstrapConnect- Swarmconnect status is " + output); + if (!output.contains("success")) { + IPFSNetworkLogger.debug("swarm attempt failed with " + peerid); + } else { + IPFSNetworkLogger.debug("swarm Connected : " + peerid); + bootstrapConnected = true; + } + } else { + IPFSNetworkLogger.debug("bootstrap connection failed! " + bootNode); + } + + } + } + + } catch (Exception e) { + FunctionsLogger.error("Error occured during IPFS Swarm connect with bootstrap", e); + + } + + if (bootstrapConnected) { + return true; + } else { + return false; + } + + } + + public static boolean portCheckAndKill(int port) { + PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); + boolean portStatus = false; + + try { + if (getOsName() != "Windows") { + portStatus = releasePorts(port); + } else { + portStatusWindows(port); + portStatus = portStatusWindows(port); + } + } catch (Exception e) { + FunctionsLogger.error("Error occured during port checking ", e); + } + return portStatus; + + } + + /** + * This function will release the port in linux based machines if the port is already in use + */ + public static boolean releasePorts(int port) { + FunctionsLogger.info("releasePorts- "); + boolean releasedPort = false; + String processStr; + Process processId; + try { + processId = Runtime.getRuntime().exec("lsof -ti :" + port); + long currentPid = ProcessHandle.current().pid(); + BufferedReader br = new BufferedReader( + new InputStreamReader(processId.getInputStream())); + FunctionsLogger.info("releasePorts- process " + br.readLine() + " is occupied in " + port); + processId = Runtime.getRuntime().exec("pgrep ipfs"); + BufferedReader ipfsPidBr = new BufferedReader(new InputStreamReader(processId.getInputStream())); + + processStr = br.readLine(); + FunctionsLogger.info("releasePorts- Process string is " + processStr); + if (processStr != null) { + FunctionsLogger.info("releasePorts- Processstr is not null"); + if (String.valueOf(currentPid) != processStr && ipfsPidBr.readLine() != processStr) { + FunctionsLogger.info("releasePorts- jar is running on " + currentPid + " and IPFS is occupied in " + ipfsPidBr.readLine()); + FunctionsLogger.debug("Port " + port + " is in using, killing PID " + processStr); + processId = Runtime.getRuntime().exec("kill -9 " + processStr); + FunctionsLogger.info("releasePorts- killing " + processStr); + + } + } + releasedPort = true; + FunctionsLogger.info("releasePorts- status is " + releasedPort); + processId.waitFor(); + FunctionsLogger.info("releasePorts- Waitng for process"); + processId.destroy(); + FunctionsLogger.info("releasePorts- destorying process after waiting"); + } catch (Exception e) { + FunctionsLogger.error("Exception Occured at releasePort", e); + e.printStackTrace(); + } + return releasedPort; + } + + public static boolean portStatusWindows(int port) { + FunctionsLogger.info("Starting portStatusWindows"); + boolean releasedPort = false; + String processStr; + Process p; + try { + Runtime rt = Runtime.getRuntime(); + Process proc = rt.exec("cmd /c netstat -ano | findstr " + port); + FunctionsLogger.info("Checking port status"); + long currentPid = ProcessHandle.current().pid(); + BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream())); + processStr = stdInput.readLine(); + FunctionsLogger.info("Process id found for port is " + processStr + " current jar pid is " + currentPid); + if (processStr != null && String.valueOf(currentPid) != processStr) { + int index = processStr.lastIndexOf(" "); + String sc = processStr.substring(index, processStr.length()); + //System.out.println("Port "+port+" is locked by PID "+sc+". Kindly close this port and retry transcation"); + if (sc != String.valueOf(currentPid)) { + FunctionsLogger.debug("Port " + port + " is locked by PID " + sc); + } else { + FunctionsLogger.debug("Port " + port + " is locked by current jar with PID " + sc); + } + } else { + releasedPort = true; + FunctionsLogger.info("Port is unlocked"); + } + } catch (Exception e) { + FunctionsLogger.error("Exception occured at portStatusWindows", e); + e.printStackTrace(); + } + return releasedPort; + } + } + diff --git a/src/com/rubix/Resources/IPFSNetwork.java b/src/com/rubix/Resources/IPFSNetwork.java index 2921d551..728d6c2c 100644 --- a/src/com/rubix/Resources/IPFSNetwork.java +++ b/src/com/rubix/Resources/IPFSNetwork.java @@ -544,7 +544,7 @@ public static void executeIPFSCommands(String command) { } } - public static void swarmConnectP2P(String peerid, IPFS ipfs) throws JSONException { + public static boolean swarmConnectP2P(String peerid, IPFS ipfs) throws JSONException { PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); String bootNode; boolean swarmConnected = false; @@ -569,17 +569,22 @@ public static void swarmConnectP2P(String peerid, IPFS ipfs) throws JSONExceptio output = swarmConnectProcess(multiAddress); if (!output.contains("success")) { IPFSNetworkLogger.debug("swarm attempt failed with " + peerid); + swarmConnected = false; } else { IPFSNetworkLogger.debug("swarm Connected : " + peerid); swarmConnected = true; } } else { IPFSNetworkLogger.debug("bootstrap connection failed! " + bootNode); + swarmConnected = false; } } } + }else { + swarmConnected = true; } + return swarmConnected; } diff --git a/src/com/rubix/TokenTransfer/TokenReceiver.java b/src/com/rubix/TokenTransfer/TokenReceiver.java index 3707abf2..2625dd68 100644 --- a/src/com/rubix/TokenTransfer/TokenReceiver.java +++ b/src/com/rubix/TokenTransfer/TokenReceiver.java @@ -1,61 +1,28 @@ package com.rubix.TokenTransfer; -import static com.rubix.Resources.Functions.DATA_PATH; -import static com.rubix.Resources.Functions.FunctionsLogger; -import static com.rubix.Resources.Functions.IPFS_PORT; -import static com.rubix.Resources.Functions.LOGGER_PATH; -import static com.rubix.Resources.Functions.PAYMENTS_PATH; -import static com.rubix.Resources.Functions.RECEIVER_PORT; -import static com.rubix.Resources.Functions.TOKENCHAIN_PATH; -import static com.rubix.Resources.Functions.TOKENS_PATH; -import static com.rubix.Resources.Functions.WALLET_DATA_PATH; -import static com.rubix.Resources.Functions.calculateHash; -import static com.rubix.Resources.Functions.deleteFile; -import static com.rubix.Resources.Functions.formatAmount; -import static com.rubix.Resources.Functions.getCurrentUtcTime; -import static com.rubix.Resources.Functions.getPeerID; -import static com.rubix.Resources.Functions.getValues; -import static com.rubix.Resources.Functions.nodeData; -import static com.rubix.Resources.Functions.pathSet; -import static com.rubix.Resources.Functions.readFile; -import static com.rubix.Resources.Functions.syncDataTable; -import static com.rubix.Resources.Functions.updateJSON; -import static com.rubix.Resources.Functions.writeToFile; -import static com.rubix.Resources.IPFSNetwork.add; -import static com.rubix.Resources.IPFSNetwork.executeIPFSCommands; -import static com.rubix.Resources.IPFSNetwork.get; -import static com.rubix.Resources.IPFSNetwork.listen; -import static com.rubix.Resources.IPFSNetwork.pin; -import static com.rubix.Resources.IPFSNetwork.repo; -import static com.rubix.Resources.IPFSNetwork.swarmConnectP2P; - -import java.awt.image.BufferedImage; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.PrintStream; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.SocketException; -import java.util.ArrayList; -import java.util.Iterator; - -import javax.imageio.ImageIO; - import com.rubix.AuthenticateNode.Authenticate; import com.rubix.AuthenticateNode.PropImage; import com.rubix.Resources.Functions; import com.rubix.Resources.IPFSNetwork; - +import io.ipfs.api.IPFS; import org.apache.log4j.Logger; import org.apache.log4j.PropertyConfigurator; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; -import io.ipfs.api.IPFS; +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.*; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketException; +import java.util.ArrayList; +import java.util.Iterator; + +import static com.rubix.Resources.Functions.*; +import static com.rubix.Resources.IPFSNetwork.*; + public class TokenReceiver { public static Logger TokenReceiverLogger = Logger.getLogger(TokenReceiver.class); @@ -108,6 +75,7 @@ public static String receive() { TokenReceiverLogger.debug("Receiver Listening on " + RECEIVER_PORT + " appname " + receiverPeerID); sk = ss.accept(); + TokenReceiverLogger.debug("Data Incoming..."); BufferedReader input = new BufferedReader(new InputStreamReader(sk.getInputStream())); PrintStream output = new PrintStream(sk.getOutputStream()); long startTime = System.currentTimeMillis(); @@ -128,8 +96,7 @@ public static String receive() { return APIResponse.toString(); } - syncDataTable(null, senderPeerID); - + TokenReceiverLogger.debug("Data Received: " + senderPeerID); swarmConnectP2P(senderPeerID, ipfs); String senderDidIpfsHash = getValues(DATA_PATH + "DataTable.json", "didHash", "peerid", senderPeerID); @@ -150,6 +117,7 @@ public static String receive() { return APIResponse.toString(); } + nodeData(senderDidIpfsHash, senderWidIpfsHash, ipfs); File senderDIDFile = new File(DATA_PATH + senderDidIpfsHash + "/DID.png"); if (!senderDIDFile.exists()) { @@ -159,7 +127,7 @@ public static String receive() { APIResponse.put("status", "Failed"); APIResponse.put("message", "Sender details not available"); TokenReceiverLogger.info("Sender details not available"); - /* executeIPFSCommands(" ipfs p2p close -t /p2p/" + senderPeerID); */ + /* executeIPFSCommands(" ipfs p2p close -t /p2p/" + senderPeerID);*/ output.close(); input.close(); @@ -201,7 +169,7 @@ public static String receive() { JSONObject amountLedger = tokenObject.getJSONObject("amountLedger"); TokenReceiverLogger.debug("Amount Ledger: " + amountLedger); int intPart = wholeTokens.length(); - Double decimalPart = formatAmount(amount - intPart); + Double decimalPart = formatAmount(amount-intPart); JSONArray doubleSpentToken = new JSONArray(); boolean tokenOwners = true; ArrayList ownersArray = new ArrayList(); @@ -215,8 +183,7 @@ public static String receive() { if (ownersArray.size() > 2) { for (int j = 0; j < previousSendersArray.length(); j++) { - if (previousSendersArray.getJSONObject(j).getString("token") - .equals(wholeTokens.getString(i))) + if (previousSendersArray.getJSONObject(j).getString("token").equals(wholeTokens.getString(i))) ownersReceived = previousSendersArray.getJSONObject(j).getJSONArray("sender"); } @@ -277,8 +244,7 @@ public static String receive() { return APIResponse.toString(); } - // Check IPFS get and Stake ID (signed when participated as quorum in mining) - // for all Tokens + //Check IPFS get for all Tokens int ipfsGetFlag = 0; ArrayList allTokenContent = new ArrayList<>(); ArrayList allTokenChainContent = new ArrayList<>(); @@ -286,20 +252,6 @@ public static String receive() { String TokenChainContent = get(wholeTokenChains.getString(i), ipfs); allTokenChainContent.add(TokenChainContent); String TokenContent = get(wholeTokens.getString(i), ipfs); - - // ! yet to verify if we are going to use stake ID or quorum pinning token on - - // ? Steps - // ? generate stake ID for the token hash - // ? check if stake ID exists in the network for the token hash (someone must - // have staked this token for participating in mining) - // ? stake ID should be signed by the staking node to avoid malicious node - // staking tokens they dont own - // ? get mined token from stake ID - // ? if the mined token has token chain content > credits required to mine that - // token, then stake ID is not considered and token is accepted by reciever - // ? ignore the token and continue with the transaction - allTokenContent.add(TokenContent); ipfsGetFlag++; } @@ -331,7 +283,7 @@ public static String receive() { } boolean chainFlag = true; - for (int i = 0; i < partTokenChainContent.length(); i++) { + for(int i = 0; i < partTokenChainContent.length(); i++) { JSONArray tokenChainContent = partTokenChainContent.getJSONArray(i); for (int j = 0; j < tokenChainContent.length(); j++) { String previousHash = tokenChainContent.getJSONObject(j).getString("previousHash"); @@ -341,17 +293,14 @@ public static String receive() { if (j == 0) { rePreviousHash = ""; String rePrev = calculateHash(new JSONObject().toString(), "SHA3-256"); - reNextHash = calculateHash(tokenChainContent.getJSONObject(j + 1).getString("tid"), - "SHA3-256"); + reNextHash = calculateHash(tokenChainContent.getJSONObject(j + 1).getString("tid"), "SHA3-256"); - if (!((rePreviousHash.equals(previousHash) || rePrev.equals(previousHash)) - && reNextHash.equals(nextHash))) { + if (!((rePreviousHash.equals(previousHash) || rePrev.equals(previousHash)) && reNextHash.equals(nextHash))) { chainFlag = false; } } else if (j == tokenChainContent.length() - 1) { - rePreviousHash = calculateHash(tokenChainContent.getJSONObject(j - 1).getString("tid"), - "SHA3-256"); + rePreviousHash = calculateHash(tokenChainContent.getJSONObject(j - 1).getString("tid"), "SHA3-256"); reNextHash = ""; if (!(rePreviousHash.equals(previousHash) && reNextHash.equals(nextHash))) { @@ -359,10 +308,8 @@ public static String receive() { } } else { - rePreviousHash = calculateHash(tokenChainContent.getJSONObject(j - 1).getString("tid"), - "SHA3-256"); - reNextHash = calculateHash(tokenChainContent.getJSONObject(j + 1).getString("tid"), - "SHA3-256"); + rePreviousHash = calculateHash(tokenChainContent.getJSONObject(j - 1).getString("tid"), "SHA3-256"); + reNextHash = calculateHash(tokenChainContent.getJSONObject(j + 1).getString("tid"), "SHA3-256"); if (!(rePreviousHash.equals(previousHash) && reNextHash.equals(nextHash))) { chainFlag = false; @@ -389,16 +336,14 @@ public static String receive() { } boolean partsAvailable = true; - for (int i = 0; i < partTokenChainContent.length(); i++) { + for(int i = 0; i < partTokenChainContent.length(); i++){ Double senderCount = 0.000D, receiverCount = 0.000D; JSONArray tokenChainContent = partTokenChainContent.getJSONArray(i); for (int k = 0; k < tokenChainContent.length(); k++) { if (tokenChainContent.getJSONObject(k).has("role")) { - if (tokenChainContent.getJSONObject(k).getString("role").equals("Sender") - && tokenChainContent.getJSONObject(k).getString("sender").equals(senderDidIpfsHash)) { + if (tokenChainContent.getJSONObject(k).getString("role").equals("Sender") && tokenChainContent.getJSONObject(k).getString("sender").equals(senderDidIpfsHash)) { senderCount += tokenChainContent.getJSONObject(k).getDouble("amount"); - } else if (tokenChainContent.getJSONObject(k).getString("role").equals("Receiver") - && tokenChainContent.getJSONObject(k).getString("receiver").equals(senderDidIpfsHash)) { + } else if (tokenChainContent.getJSONObject(k).getString("role").equals("Receiver") && tokenChainContent.getJSONObject(k).getString("receiver").equals(senderDidIpfsHash)) { receiverCount += tokenChainContent.getJSONObject(k).getDouble("amount"); } } @@ -411,13 +356,13 @@ public static String receive() { availableParts += amountLedger.getDouble(partTokens.getString(i)); availableParts = formatAmount(availableParts); - if (availableParts > 1.000D) { + if(availableParts > 1.000D) { TokenReceiverLogger.debug("Token wholly spent: " + partTokens.getString(i)); TokenReceiverLogger.debug("Parts: " + availableParts); } } - if (!partsAvailable) { + if (!partsAvailable) { String errorMessage = "Token wholly spent already"; output.println("424"); APIResponse.put("did", senderDidIpfsHash); @@ -431,9 +376,10 @@ public static String receive() { sk.close(); ss.close(); return APIResponse.toString(); - } else + }else output.println("200"); + String senderDetails; try { senderDetails = input.readLine(); @@ -461,6 +407,7 @@ public static String receive() { BufferedImage senderWidImage = ImageIO.read(new File(DATA_PATH + senderDidIpfsHash + "/PublicShare.png")); SenWalletBin = PropImage.img2bin(senderWidImage); + TokenReceiverLogger.debug("Verifying Quorum ... "); TokenReceiverLogger.debug("Please wait, this might take a few seconds"); @@ -479,8 +426,7 @@ public static String receive() { for (String quorumDidIpfsHash : quorumDID) { syncDataTable(quorumDidIpfsHash, null); - String quorumWidIpfsHash = getValues(DATA_PATH + "DataTable.json", "walletHash", "didHash", - quorumDidIpfsHash); + String quorumWidIpfsHash = getValues(DATA_PATH + "DataTable.json", "walletHash", "didHash", quorumDidIpfsHash); nodeData(quorumDidIpfsHash, quorumWidIpfsHash, ipfs); } @@ -502,10 +448,7 @@ public static String receive() { for (int i = 0; i < intPart; i++) wholeTokenChainHash.put(wholeTokenChains.getString(i)); - String hash = calculateHash( - wholeTokens.toString() + wholeTokenChainHash.toString() + partTokens.toString() - + partTokenChainsHash.toString() + receiverDidIpfsHash + senderDidIpfsHash + comment, - "SHA3-256"); + String hash = calculateHash(wholeTokens.toString() + wholeTokenChainHash.toString() + partTokens.toString() + partTokenChainsHash.toString() + receiverDidIpfsHash + senderDidIpfsHash + comment, "SHA3-256"); TokenReceiverLogger.debug("Hash to verify Sender: " + hash); JSONObject detailsForVerify = new JSONObject(); detailsForVerify.put("did", senderDidIpfsHash); @@ -622,7 +565,8 @@ public static String receive() { writeToFile(TOKENCHAIN_PATH + wholeTokens.getString(i) + ".json", arr1.toString(), false); } - for (int i = 0; i < partTokens.length(); i++) { + + for(int i = 0; i < partTokens.length(); i++){ JSONObject chequeObject = new JSONObject(); chequeObject.put("sender", senderDidIpfsHash); chequeObject.put("receiver", receiverDidIpfsHash); @@ -636,6 +580,7 @@ public static String receive() { String chequeHash = IPFSNetwork.add(LOGGER_PATH.concat(partTokens.getString(i)), ipfs); deleteFile(LOGGER_PATH.concat(partTokens.getString(i))); + JSONObject newPartObject = new JSONObject(); newPartObject.put("senderSign", senderSignature); newPartObject.put("sender", senderDidIpfsHash); @@ -643,41 +588,42 @@ public static String receive() { newPartObject.put("comment", comment); newPartObject.put("tid", tid); newPartObject.put("nextHash", ""); - if (partTokenChainContent.getJSONArray(i).length() == 0) + if(partTokenChainContent.getJSONArray(i).length() == 0) newPartObject.put("previousHash", ""); else - newPartObject.put("previousHash", - calculateHash(partTokenChainContent.getJSONArray(i) - .getJSONObject(partTokenChainContent.getJSONArray(i).length() - 1) - .getString("tid"), "SHA3-256")); + newPartObject.put("previousHash", calculateHash(partTokenChainContent.getJSONArray(i).getJSONObject(partTokenChainContent.getJSONArray(i).length() - 1).getString("tid"), "SHA3-256")); + newPartObject.put("amount", partAmount); newPartObject.put("cheque", chequeHash); newPartObject.put("role", "Receiver"); - File chainFile = new File( - PART_TOKEN_CHAIN_PATH.concat(partTokens.getString(i)).concat(".json")); + File chainFile = new File(PART_TOKEN_CHAIN_PATH.concat(partTokens.getString(i)).concat(".json")); if (chainFile.exists()) { String readChain = readFile(PART_TOKEN_CHAIN_PATH + partTokens.getString(i) + ".json"); JSONArray readChainArray = new JSONArray(readChain); - readChainArray.put(partTokenChainContent.getJSONArray(i) - .getJSONObject(partTokenChainContent.getJSONArray(i).length() - 1)); + readChainArray.put(partTokenChainContent.getJSONArray(i).getJSONObject(partTokenChainContent.getJSONArray(i).length() - 1)); readChainArray.put(newPartObject); - writeToFile(PART_TOKEN_CHAIN_PATH + partTokens.getString(i) + ".json", - readChainArray.toString(), false); + writeToFile(PART_TOKEN_CHAIN_PATH + partTokens.getString(i) + ".json", readChainArray.toString(), false); + } else { partTokenChainContent.getJSONArray(i).put(newPartObject); - writeToFile(PART_TOKEN_CHAIN_PATH + partTokens.getString(i) + ".json", - partTokenChainContent.getJSONArray(i).toString(), false); + writeToFile(PART_TOKEN_CHAIN_PATH + partTokens.getString(i) + ".json", partTokenChainContent.getJSONArray(i).toString(), false); } } + JSONArray allTokens = new JSONArray(); + for(int i = 0; i < wholeTokens.length(); i++) + allTokens.put(wholeTokens.getString(i)); + for(int i = 0; i < partTokens.length(); i++) + allTokens.put(partTokens.getString(i)); + JSONObject transactionRecord = new JSONObject(); transactionRecord.put("role", "Receiver"); - transactionRecord.put("tokens", wholeTokens); + transactionRecord.put("tokens", allTokens); transactionRecord.put("txn", tid); transactionRecord.put("quorumList", quorumSignatures.keys()); transactionRecord.put("senderDID", senderDidIpfsHash); @@ -691,8 +637,7 @@ public static String receive() { JSONArray transactionHistoryEntry = new JSONArray(); transactionHistoryEntry.put(transactionRecord); - updateJSON("add", WALLET_DATA_PATH + "TransactionHistory.json", - transactionHistoryEntry.toString()); + updateJSON("add", WALLET_DATA_PATH + "TransactionHistory.json", transactionHistoryEntry.toString()); for (int i = 0; i < wholeTokens.length(); i++) { String bankFile = readFile(PAYMENTS_PATH.concat("BNK00.json")); @@ -707,14 +652,13 @@ public static String receive() { String partsFile = readFile(PAYMENTS_PATH.concat("PartsToken.json")); JSONArray partsReadArray = new JSONArray(partsFile); - for (int i = 0; i < partTokens.length(); i++) { + for(int i = 0; i < partTokens.length(); i++){ boolean writeParts = true; - for (int j = 0; j < partsReadArray.length(); j++) { - if (partsReadArray.getJSONObject(j).getString("tokenHash") - .equals(partTokens.getString(i))) + for(int j = 0; j < partsReadArray.length(); j++){ + if(partsReadArray.getJSONObject(j).getString("tokenHash").equals(partTokens.getString(i))) writeParts = false; } - if (writeParts) { + if(writeParts) { JSONObject partObject = new JSONObject(); partObject.put("tokenHash", partTokens.getString(i)); partsReadArray.put(partObject); diff --git a/src/com/rubix/TokenTransfer/TokenSender.java b/src/com/rubix/TokenTransfer/TokenSender.java index efc01e02..2ebedd31 100644 --- a/src/com/rubix/TokenTransfer/TokenSender.java +++ b/src/com/rubix/TokenTransfer/TokenSender.java @@ -53,20 +53,31 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception JSONObject APIResponse = new JSONObject(); PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); - String receiverPeerId; JSONObject detailsObject = new JSONObject(data); String receiverDidIpfsHash = detailsObject.getString("receiverDidIpfsHash"); + String receiverPeerId = getValues(DATA_PATH + "DataTable.json", "peerid", "didHash", receiverDidIpfsHash); String pvt = detailsObject.getString("pvt"); double requestedAmount = detailsObject.getDouble("amount"); int type = detailsObject.getInt("type"); String comment = detailsObject.getString("comment"); APIResponse = new JSONObject(); + int intPart = (int) requestedAmount, wholeAmount; String senderPeerID = getPeerID(DATA_PATH + "DID.json"); TokenSenderLogger.debug("sender peer id" + senderPeerID); String senderDidIpfsHash = getValues(DATA_PATH + "DataTable.json", "didHash", "peerid", senderPeerID); TokenSenderLogger.debug("sender did ipfs hash" + senderDidIpfsHash); + boolean sanityCheck = sanityCheck(receiverPeerId, ipfs, port+10); + if(!sanityCheck){ + APIResponse.put("did", senderDidIpfsHash); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + APIResponse.put("message", sanityMessage); + TokenSenderLogger.warn(sanityMessage); + return APIResponse; + } + if (senderMutex) { APIResponse.put("did", senderDidIpfsHash); APIResponse.put("tid", "null"); @@ -92,7 +103,7 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception writeToFile(partTokensFile.toString(), "[]", false); } - int intPart = (int) requestedAmount, wholeAmount; + TokenSenderLogger.debug("Requested Part: " +requestedAmount); TokenSenderLogger.debug("Int Part: " +intPart); String bankFile = readFile(PAYMENTS_PATH.concat("BNK00.json")); @@ -287,7 +298,13 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception TokenSenderLogger.debug("TID on sender " + tid); - JSONArray quorumArray; + + JSONArray allTokens = new JSONArray(); + for(int i = 0; i < wholeTokens.length(); i++) + allTokens.put(wholeTokens.getString(i)); + for(int i = 0; i < partTokens.length(); i++) + allTokens.put(partTokens.getString(i)); + JSONArray alphaQuorum = new JSONArray(); JSONArray betaQuorum = new JSONArray(); JSONArray gammaQuorum = new JSONArray(); @@ -297,7 +314,7 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception ArrayList betaPeersList; ArrayList gammaPeersList; - long startTime = System.currentTimeMillis(); + JSONArray quorumArray; switch (type) { case 1: { writeToFile(LOGGER_PATH + "tempbeta", tid.concat(senderDidIpfsHash), false); @@ -308,7 +325,7 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception String gammaHash = IPFSNetwork.add(LOGGER_PATH + "tempgamma", ipfs); deleteFile(LOGGER_PATH + "tempgamma"); - quorumArray = getQuorum(betaHash, gammaHash, senderDidIpfsHash, receiverDidIpfsHash, wholeTokens.length()); + quorumArray = getQuorum(betaHash, gammaHash, senderDidIpfsHash, receiverDidIpfsHash, allTokens.length()); break; } @@ -329,18 +346,37 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception } } - TokenSenderLogger.debug("1"); - TokenSenderLogger.debug("Whole tokens: " + wholeTokens); - TokenSenderLogger.debug("Part tokens: " + partTokens); - long endTime = System.currentTimeMillis(); - long totalTime = endTime - startTime; - eventLogger.debug("Get Quorum List " + totalTime); + int alphaCheck = 0, betaCheck = 0, gammaCheck = 0; + JSONArray sanityFailedQuorum = new JSONArray(); + for(int i = 0; i < quorumArray.length(); i++){ + String quorumPeerID = getValues(DATA_PATH + "DataTable.json", "peerid", "didHash", quorumArray.getString(i)); + boolean quorumSanityCheck = sanityCheck(quorumPeerID, ipfs, port+11); + + if(!quorumSanityCheck){ + sanityFailedQuorum.put(quorumPeerID); + if(i <= 6) + alphaCheck++; + if(i >= 7 && i <= 13) + betaCheck++; + if(i >= 14 && i <= 20) + gammaCheck++; + } + } + + if(alphaCheck > 2 || betaCheck > 2 || gammaCheck > 2){ + APIResponse.put("did", senderDidIpfsHash); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + String message = "Quorum: ".concat(sanityFailedQuorum.toString()).concat(" "); + APIResponse.put("message", message.concat(sanityMessage)); + TokenSenderLogger.warn("Quorum: ".concat(message.concat(sanityMessage))); + return APIResponse; + } + + long startTime, endTime, totalTime; - startTime = System.currentTimeMillis(); QuorumSwarmConnect(quorumArray, ipfs); - endTime = System.currentTimeMillis(); - totalTime = endTime - startTime; - eventLogger.debug("Swarm Connect " + totalTime); + alphaSize = quorumArray.length() - 14; @@ -374,7 +410,7 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception syncDataTable(receiverDidIpfsHash, null); - receiverPeerId = getValues(DATA_PATH + "DataTable.json", "peerid", "didHash", receiverDidIpfsHash); +// receiverPeerId = getValues(DATA_PATH + "DataTable.json", "peerid", "didHash", receiverDidIpfsHash); if (!receiverPeerId.equals("")) { TokenSenderLogger.debug("Swarm connecting to " + receiverPeerId); @@ -756,18 +792,6 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception updateQuorum(quorumArray, signedQuorumList, true, type); - - JSONArray allTokens = new JSONArray(); - for(int i = 0; i < wholeTokens.length(); i++) - allTokens.put(wholeTokens.getString(i)); - for(int i = 0; i < partTokens.length(); i++) - allTokens.put(partTokens.getString(i)); - - TokenSenderLogger.debug("4"); - TokenSenderLogger.debug("All tokens: " + allTokens); - TokenSenderLogger.debug("Whole tokens: " + wholeTokens); - TokenSenderLogger.debug("Part tokens: " + partTokens); - JSONObject transactionRecord = new JSONObject(); transactionRecord.put("role", "Sender"); transactionRecord.put("tokens", allTokens); From 8a08fe91af6d7b4fb31a70773febad14b4dd2c97 Mon Sep 17 00:00:00 2001 From: Nidhin Mahesh A Date: Tue, 22 Feb 2022 11:28:05 +0530 Subject: [PATCH 16/49] fixed response error codes Signed-off-by: Nidhin Mahesh A --- .../rubix/TokenTransfer/TokenReceiver.java | 155 ++++++++++++------ 1 file changed, 101 insertions(+), 54 deletions(-) diff --git a/src/com/rubix/TokenTransfer/TokenReceiver.java b/src/com/rubix/TokenTransfer/TokenReceiver.java index 2625dd68..8f22637e 100644 --- a/src/com/rubix/TokenTransfer/TokenReceiver.java +++ b/src/com/rubix/TokenTransfer/TokenReceiver.java @@ -1,28 +1,61 @@ package com.rubix.TokenTransfer; +import static com.rubix.Resources.Functions.DATA_PATH; +import static com.rubix.Resources.Functions.FunctionsLogger; +import static com.rubix.Resources.Functions.IPFS_PORT; +import static com.rubix.Resources.Functions.LOGGER_PATH; +import static com.rubix.Resources.Functions.PAYMENTS_PATH; +import static com.rubix.Resources.Functions.RECEIVER_PORT; +import static com.rubix.Resources.Functions.TOKENCHAIN_PATH; +import static com.rubix.Resources.Functions.TOKENS_PATH; +import static com.rubix.Resources.Functions.WALLET_DATA_PATH; +import static com.rubix.Resources.Functions.calculateHash; +import static com.rubix.Resources.Functions.deleteFile; +import static com.rubix.Resources.Functions.formatAmount; +import static com.rubix.Resources.Functions.getCurrentUtcTime; +import static com.rubix.Resources.Functions.getPeerID; +import static com.rubix.Resources.Functions.getValues; +import static com.rubix.Resources.Functions.nodeData; +import static com.rubix.Resources.Functions.pathSet; +import static com.rubix.Resources.Functions.readFile; +import static com.rubix.Resources.Functions.syncDataTable; +import static com.rubix.Resources.Functions.updateJSON; +import static com.rubix.Resources.Functions.writeToFile; +import static com.rubix.Resources.IPFSNetwork.add; +import static com.rubix.Resources.IPFSNetwork.executeIPFSCommands; +import static com.rubix.Resources.IPFSNetwork.get; +import static com.rubix.Resources.IPFSNetwork.listen; +import static com.rubix.Resources.IPFSNetwork.pin; +import static com.rubix.Resources.IPFSNetwork.repo; +import static com.rubix.Resources.IPFSNetwork.swarmConnectP2P; + +import java.awt.image.BufferedImage; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintStream; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketException; +import java.util.ArrayList; +import java.util.Iterator; + +import javax.imageio.ImageIO; + import com.rubix.AuthenticateNode.Authenticate; import com.rubix.AuthenticateNode.PropImage; import com.rubix.Resources.Functions; import com.rubix.Resources.IPFSNetwork; -import io.ipfs.api.IPFS; + import org.apache.log4j.Logger; import org.apache.log4j.PropertyConfigurator; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; -import javax.imageio.ImageIO; -import java.awt.image.BufferedImage; -import java.io.*; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.SocketException; -import java.util.ArrayList; -import java.util.Iterator; - -import static com.rubix.Resources.Functions.*; -import static com.rubix.Resources.IPFSNetwork.*; - +import io.ipfs.api.IPFS; public class TokenReceiver { public static Logger TokenReceiverLogger = Logger.getLogger(TokenReceiver.class); @@ -117,7 +150,6 @@ public static String receive() { return APIResponse.toString(); } - nodeData(senderDidIpfsHash, senderWidIpfsHash, ipfs); File senderDIDFile = new File(DATA_PATH + senderDidIpfsHash + "/DID.png"); if (!senderDIDFile.exists()) { @@ -127,7 +159,7 @@ public static String receive() { APIResponse.put("status", "Failed"); APIResponse.put("message", "Sender details not available"); TokenReceiverLogger.info("Sender details not available"); - /* executeIPFSCommands(" ipfs p2p close -t /p2p/" + senderPeerID);*/ + /* executeIPFSCommands(" ipfs p2p close -t /p2p/" + senderPeerID); */ output.close(); input.close(); @@ -169,7 +201,7 @@ public static String receive() { JSONObject amountLedger = tokenObject.getJSONObject("amountLedger"); TokenReceiverLogger.debug("Amount Ledger: " + amountLedger); int intPart = wholeTokens.length(); - Double decimalPart = formatAmount(amount-intPart); + Double decimalPart = formatAmount(amount - intPart); JSONArray doubleSpentToken = new JSONArray(); boolean tokenOwners = true; ArrayList ownersArray = new ArrayList(); @@ -183,7 +215,8 @@ public static String receive() { if (ownersArray.size() > 2) { for (int j = 0; j < previousSendersArray.length(); j++) { - if (previousSendersArray.getJSONObject(j).getString("token").equals(wholeTokens.getString(i))) + if (previousSendersArray.getJSONObject(j).getString("token") + .equals(wholeTokens.getString(i))) ownersReceived = previousSendersArray.getJSONObject(j).getJSONArray("sender"); } @@ -208,7 +241,7 @@ public static String receive() { owners.put(ownersArray.get(i).toString()); TokenReceiverLogger.debug("Multiple Owners for " + doubleSpentToken); TokenReceiverLogger.debug("Owners: " + owners); - output.println("200"); + output.println("420"); output.println(doubleSpentToken.toString()); output.println(owners.toString()); APIResponse.put("did", senderDidIpfsHash); @@ -231,7 +264,7 @@ public static String receive() { if (!IPFSNetwork.dhtEmpty(consensusIDIPFSHash, ipfs)) { TokenReceiverLogger.debug("consensus ID not unique" + consensusIDIPFSHash); - output.println("200"); + output.println("421"); APIResponse.put("did", senderDidIpfsHash); APIResponse.put("tid", "null"); APIResponse.put("status", "Failed"); @@ -244,7 +277,7 @@ public static String receive() { return APIResponse.toString(); } - //Check IPFS get for all Tokens + // Check IPFS get for all Tokens int ipfsGetFlag = 0; ArrayList allTokenContent = new ArrayList<>(); ArrayList allTokenChainContent = new ArrayList<>(); @@ -283,7 +316,7 @@ public static String receive() { } boolean chainFlag = true; - for(int i = 0; i < partTokenChainContent.length(); i++) { + for (int i = 0; i < partTokenChainContent.length(); i++) { JSONArray tokenChainContent = partTokenChainContent.getJSONArray(i); for (int j = 0; j < tokenChainContent.length(); j++) { String previousHash = tokenChainContent.getJSONObject(j).getString("previousHash"); @@ -293,14 +326,17 @@ public static String receive() { if (j == 0) { rePreviousHash = ""; String rePrev = calculateHash(new JSONObject().toString(), "SHA3-256"); - reNextHash = calculateHash(tokenChainContent.getJSONObject(j + 1).getString("tid"), "SHA3-256"); + reNextHash = calculateHash(tokenChainContent.getJSONObject(j + 1).getString("tid"), + "SHA3-256"); - if (!((rePreviousHash.equals(previousHash) || rePrev.equals(previousHash)) && reNextHash.equals(nextHash))) { + if (!((rePreviousHash.equals(previousHash) || rePrev.equals(previousHash)) + && reNextHash.equals(nextHash))) { chainFlag = false; } } else if (j == tokenChainContent.length() - 1) { - rePreviousHash = calculateHash(tokenChainContent.getJSONObject(j - 1).getString("tid"), "SHA3-256"); + rePreviousHash = calculateHash(tokenChainContent.getJSONObject(j - 1).getString("tid"), + "SHA3-256"); reNextHash = ""; if (!(rePreviousHash.equals(previousHash) && reNextHash.equals(nextHash))) { @@ -308,8 +344,10 @@ public static String receive() { } } else { - rePreviousHash = calculateHash(tokenChainContent.getJSONObject(j - 1).getString("tid"), "SHA3-256"); - reNextHash = calculateHash(tokenChainContent.getJSONObject(j + 1).getString("tid"), "SHA3-256"); + rePreviousHash = calculateHash(tokenChainContent.getJSONObject(j - 1).getString("tid"), + "SHA3-256"); + reNextHash = calculateHash(tokenChainContent.getJSONObject(j + 1).getString("tid"), + "SHA3-256"); if (!(rePreviousHash.equals(previousHash) && reNextHash.equals(nextHash))) { chainFlag = false; @@ -336,14 +374,16 @@ public static String receive() { } boolean partsAvailable = true; - for(int i = 0; i < partTokenChainContent.length(); i++){ + for (int i = 0; i < partTokenChainContent.length(); i++) { Double senderCount = 0.000D, receiverCount = 0.000D; JSONArray tokenChainContent = partTokenChainContent.getJSONArray(i); for (int k = 0; k < tokenChainContent.length(); k++) { if (tokenChainContent.getJSONObject(k).has("role")) { - if (tokenChainContent.getJSONObject(k).getString("role").equals("Sender") && tokenChainContent.getJSONObject(k).getString("sender").equals(senderDidIpfsHash)) { + if (tokenChainContent.getJSONObject(k).getString("role").equals("Sender") + && tokenChainContent.getJSONObject(k).getString("sender").equals(senderDidIpfsHash)) { senderCount += tokenChainContent.getJSONObject(k).getDouble("amount"); - } else if (tokenChainContent.getJSONObject(k).getString("role").equals("Receiver") && tokenChainContent.getJSONObject(k).getString("receiver").equals(senderDidIpfsHash)) { + } else if (tokenChainContent.getJSONObject(k).getString("role").equals("Receiver") + && tokenChainContent.getJSONObject(k).getString("receiver").equals(senderDidIpfsHash)) { receiverCount += tokenChainContent.getJSONObject(k).getDouble("amount"); } } @@ -356,13 +396,13 @@ public static String receive() { availableParts += amountLedger.getDouble(partTokens.getString(i)); availableParts = formatAmount(availableParts); - if(availableParts > 1.000D) { + if (availableParts > 1.000D) { TokenReceiverLogger.debug("Token wholly spent: " + partTokens.getString(i)); TokenReceiverLogger.debug("Parts: " + availableParts); } } - if (!partsAvailable) { + if (!partsAvailable) { String errorMessage = "Token wholly spent already"; output.println("424"); APIResponse.put("did", senderDidIpfsHash); @@ -376,10 +416,9 @@ public static String receive() { sk.close(); ss.close(); return APIResponse.toString(); - }else + } else output.println("200"); - String senderDetails; try { senderDetails = input.readLine(); @@ -407,7 +446,6 @@ public static String receive() { BufferedImage senderWidImage = ImageIO.read(new File(DATA_PATH + senderDidIpfsHash + "/PublicShare.png")); SenWalletBin = PropImage.img2bin(senderWidImage); - TokenReceiverLogger.debug("Verifying Quorum ... "); TokenReceiverLogger.debug("Please wait, this might take a few seconds"); @@ -426,7 +464,8 @@ public static String receive() { for (String quorumDidIpfsHash : quorumDID) { syncDataTable(quorumDidIpfsHash, null); - String quorumWidIpfsHash = getValues(DATA_PATH + "DataTable.json", "walletHash", "didHash", quorumDidIpfsHash); + String quorumWidIpfsHash = getValues(DATA_PATH + "DataTable.json", "walletHash", "didHash", + quorumDidIpfsHash); nodeData(quorumDidIpfsHash, quorumWidIpfsHash, ipfs); } @@ -448,7 +487,10 @@ public static String receive() { for (int i = 0; i < intPart; i++) wholeTokenChainHash.put(wholeTokenChains.getString(i)); - String hash = calculateHash(wholeTokens.toString() + wholeTokenChainHash.toString() + partTokens.toString() + partTokenChainsHash.toString() + receiverDidIpfsHash + senderDidIpfsHash + comment, "SHA3-256"); + String hash = calculateHash( + wholeTokens.toString() + wholeTokenChainHash.toString() + partTokens.toString() + + partTokenChainsHash.toString() + receiverDidIpfsHash + senderDidIpfsHash + comment, + "SHA3-256"); TokenReceiverLogger.debug("Hash to verify Sender: " + hash); JSONObject detailsForVerify = new JSONObject(); detailsForVerify.put("did", senderDidIpfsHash); @@ -565,8 +607,7 @@ public static String receive() { writeToFile(TOKENCHAIN_PATH + wholeTokens.getString(i) + ".json", arr1.toString(), false); } - - for(int i = 0; i < partTokens.length(); i++){ + for (int i = 0; i < partTokens.length(); i++) { JSONObject chequeObject = new JSONObject(); chequeObject.put("sender", senderDidIpfsHash); chequeObject.put("receiver", receiverDidIpfsHash); @@ -580,7 +621,6 @@ public static String receive() { String chequeHash = IPFSNetwork.add(LOGGER_PATH.concat(partTokens.getString(i)), ipfs); deleteFile(LOGGER_PATH.concat(partTokens.getString(i))); - JSONObject newPartObject = new JSONObject(); newPartObject.put("senderSign", senderSignature); newPartObject.put("sender", senderDidIpfsHash); @@ -588,37 +628,42 @@ public static String receive() { newPartObject.put("comment", comment); newPartObject.put("tid", tid); newPartObject.put("nextHash", ""); - if(partTokenChainContent.getJSONArray(i).length() == 0) + if (partTokenChainContent.getJSONArray(i).length() == 0) newPartObject.put("previousHash", ""); else - newPartObject.put("previousHash", calculateHash(partTokenChainContent.getJSONArray(i).getJSONObject(partTokenChainContent.getJSONArray(i).length() - 1).getString("tid"), "SHA3-256")); - + newPartObject.put("previousHash", + calculateHash(partTokenChainContent.getJSONArray(i) + .getJSONObject(partTokenChainContent.getJSONArray(i).length() - 1) + .getString("tid"), "SHA3-256")); newPartObject.put("amount", partAmount); newPartObject.put("cheque", chequeHash); newPartObject.put("role", "Receiver"); - File chainFile = new File(PART_TOKEN_CHAIN_PATH.concat(partTokens.getString(i)).concat(".json")); + File chainFile = new File( + PART_TOKEN_CHAIN_PATH.concat(partTokens.getString(i)).concat(".json")); if (chainFile.exists()) { String readChain = readFile(PART_TOKEN_CHAIN_PATH + partTokens.getString(i) + ".json"); JSONArray readChainArray = new JSONArray(readChain); - readChainArray.put(partTokenChainContent.getJSONArray(i).getJSONObject(partTokenChainContent.getJSONArray(i).length() - 1)); + readChainArray.put(partTokenChainContent.getJSONArray(i) + .getJSONObject(partTokenChainContent.getJSONArray(i).length() - 1)); readChainArray.put(newPartObject); - writeToFile(PART_TOKEN_CHAIN_PATH + partTokens.getString(i) + ".json", readChainArray.toString(), false); - + writeToFile(PART_TOKEN_CHAIN_PATH + partTokens.getString(i) + ".json", + readChainArray.toString(), false); } else { partTokenChainContent.getJSONArray(i).put(newPartObject); - writeToFile(PART_TOKEN_CHAIN_PATH + partTokens.getString(i) + ".json", partTokenChainContent.getJSONArray(i).toString(), false); + writeToFile(PART_TOKEN_CHAIN_PATH + partTokens.getString(i) + ".json", + partTokenChainContent.getJSONArray(i).toString(), false); } } JSONArray allTokens = new JSONArray(); - for(int i = 0; i < wholeTokens.length(); i++) + for (int i = 0; i < wholeTokens.length(); i++) allTokens.put(wholeTokens.getString(i)); - for(int i = 0; i < partTokens.length(); i++) + for (int i = 0; i < partTokens.length(); i++) allTokens.put(partTokens.getString(i)); JSONObject transactionRecord = new JSONObject(); @@ -637,7 +682,8 @@ public static String receive() { JSONArray transactionHistoryEntry = new JSONArray(); transactionHistoryEntry.put(transactionRecord); - updateJSON("add", WALLET_DATA_PATH + "TransactionHistory.json", transactionHistoryEntry.toString()); + updateJSON("add", WALLET_DATA_PATH + "TransactionHistory.json", + transactionHistoryEntry.toString()); for (int i = 0; i < wholeTokens.length(); i++) { String bankFile = readFile(PAYMENTS_PATH.concat("BNK00.json")); @@ -652,13 +698,14 @@ public static String receive() { String partsFile = readFile(PAYMENTS_PATH.concat("PartsToken.json")); JSONArray partsReadArray = new JSONArray(partsFile); - for(int i = 0; i < partTokens.length(); i++){ + for (int i = 0; i < partTokens.length(); i++) { boolean writeParts = true; - for(int j = 0; j < partsReadArray.length(); j++){ - if(partsReadArray.getJSONObject(j).getString("tokenHash").equals(partTokens.getString(i))) + for (int j = 0; j < partsReadArray.length(); j++) { + if (partsReadArray.getJSONObject(j).getString("tokenHash") + .equals(partTokens.getString(i))) writeParts = false; } - if(writeParts) { + if (writeParts) { JSONObject partObject = new JSONObject(); partObject.put("tokenHash", partTokens.getString(i)); partsReadArray.put(partObject); From d0bbee6604f69ee4b7e70cf404123c65b5c65656 Mon Sep 17 00:00:00 2001 From: Gokul P S Date: Mon, 28 Feb 2022 14:33:05 +0530 Subject: [PATCH 17/49] Branch to fix sanity port check issue in windows --- src/com/rubix/Resources/Functions.java | 376 ++++++++++++++----------- 1 file changed, 204 insertions(+), 172 deletions(-) diff --git a/src/com/rubix/Resources/Functions.java b/src/com/rubix/Resources/Functions.java index 5d9eda11..7798a374 100644 --- a/src/com/rubix/Resources/Functions.java +++ b/src/com/rubix/Resources/Functions.java @@ -1,22 +1,24 @@ package com.rubix.Resources; -import com.rubix.AuthenticateNode.PropImage; -import com.rubix.Ping.PingCheck; -import io.ipfs.api.IPFS; -import io.ipfs.multiaddr.MultiAddress; -import org.apache.log4j.Logger; -import org.apache.log4j.PropertyConfigurator; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; +import static com.rubix.Resources.APIHandler.addPublicData; +import static com.rubix.Resources.IPFSNetwork.IPFSNetworkLogger; +import static com.rubix.Resources.IPFSNetwork.checkSwarmConnect; +import static com.rubix.Resources.IPFSNetwork.executeIPFSCommands; +import static com.rubix.Resources.IPFSNetwork.forwardCheck; +import static com.rubix.Resources.IPFSNetwork.listen; +import static com.rubix.Resources.IPFSNetwork.swarmConnectP2P; +import static com.rubix.Resources.IPFSNetwork.swarmConnectProcess; -import javax.imageio.ImageIO; import java.awt.image.BufferedImage; -import java.io.*; +import java.io.BufferedReader; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStreamReader; import java.math.RoundingMode; import java.net.HttpURLConnection; -import java.net.Socket; -import java.net.SocketException; import java.net.URL; import java.nio.charset.StandardCharsets; import java.nio.file.Files; @@ -29,10 +31,21 @@ import java.util.ArrayList; import java.util.Date; import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.Set; -import static com.rubix.Resources.APIHandler.addPublicData; -import static com.rubix.Resources.IPFSNetwork.*; +import javax.imageio.ImageIO; +import com.rubix.AuthenticateNode.PropImage; +import com.rubix.Ping.PingCheck; + +import org.apache.log4j.PropertyConfigurator; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import io.ipfs.api.IPFS; +import io.ipfs.multiaddr.MultiAddress; public class Functions { @@ -43,7 +56,8 @@ public class Functions { public static String LOGGER_PATH = ""; public static String WALLET_DATA_PATH = ""; public static String PAYMENTS_PATH = ""; - public static int RECEIVER_PORT, GOSSIP_SENDER, GOSSIP_RECEIVER, QUORUM_PORT, SENDER2Q1, SENDER2Q2, SENDER2Q3, SENDER2Q4, SENDER2Q5, SENDER2Q6, SENDER2Q7; + public static int RECEIVER_PORT, GOSSIP_SENDER, GOSSIP_RECEIVER, QUORUM_PORT, SENDER2Q1, SENDER2Q2, SENDER2Q3, + SENDER2Q4, SENDER2Q5, SENDER2Q6, SENDER2Q7; public static int QUORUM_COUNT; public static int SEND_PORT; public static int IPFS_PORT; @@ -122,13 +136,11 @@ public static void pathSet() { BOOTSTRAPS = pathsArray.getJSONArray(5); - } catch (JSONException e) { e.printStackTrace(); } } - public static void nodeData(String did, String wid, IPFS ipfs) throws IOException { PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); File dataFolder = new File(DATA_PATH + did + "/"); @@ -202,9 +214,9 @@ public static String getSystemUser() { return lineID; } - /** - * This method calculates different types of hashes as mentioned in the passed parameters for the mentioned message + * This method calculates different types of hashes as mentioned in the passed + * parameters for the mentioned message * * @param message Input string to be hashed * @param algorithm Specification of the algorithm used for hashing @@ -271,13 +283,13 @@ public static String bytesToHex(byte[] inputHash) { StringBuilder outputHexString = new StringBuilder(); for (byte b : inputHash) { String hex = Integer.toHexString(0xff & b); - if (hex.length() == 1) outputHexString.append('0'); + if (hex.length() == 1) + outputHexString.append('0'); outputHexString.append(hex); } return outputHexString.toString(); } - /** * This method returns the content of the file passed to it * @@ -299,14 +311,15 @@ public static String readFile(String filePath) { return fileContent.toString(); } - /** * This method writes the mentioned data into the file passed to it - * This also allows to take a decision on whether or not to append the data to the already existing content in the file + * This also allows to take a decision on whether or not to append the data to + * the already existing content in the file * * @param filePath Location of the file to be read and written into * @param data Data to be added - * @param appendStatus Decides whether or not to append the new data into the already existing data + * @param appendStatus Decides whether or not to append the new data into the + * already existing data */ public synchronized static void writeToFile(String filePath, String data, Boolean appendStatus) { @@ -347,7 +360,6 @@ public static String getSignFromShares(String filePath, String hash) throws IOEx return p1; } - /** * This function will sign on JSON data with private share * @@ -392,7 +404,6 @@ public static void listenThread(JSONObject connectObject) { } - /** * This function converts any integer to its binary form * @@ -479,7 +490,8 @@ public static void updateJSON(String operation, String filePath, String data) { } /** - * This method gets you a required data from a JSON file with a tag to be compared with + * This method gets you a required data from a JSON file with a tag to be + * compared with * * @param filePath Location of the JSON file * @param get Data to be fetched from the file @@ -516,7 +528,8 @@ public static String getOsName() { } /** - * This function calculates the minimum number of quorum peers required for consensus to work + * This function calculates the minimum number of quorum peers required for + * consensus to work * * @return Minimum number of quorum count for consensus to work */ @@ -525,7 +538,8 @@ public static int minQuorum() { } /** - * This function calculates the minimum number of quorum peers required for consensus to work + * This function calculates the minimum number of quorum peers required for + * consensus to work * * @return Minimum number of quorum count for consensus to work */ @@ -533,7 +547,6 @@ public static int minQuorum(int count) { return (((count - 1) / 3) * 2) + 1; } - /** * This method checks if Quorum is available for consensus * @@ -572,7 +585,6 @@ public static ArrayList QuorumCheck(JSONArray quorum, int size) { * @param ipfs ipfs instance */ - public static void QuorumSwarmConnect(JSONArray quorum, IPFS ipfs) { PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); @@ -591,7 +603,6 @@ public static void QuorumSwarmConnect(JSONArray quorum, IPFS ipfs) { } - /** * This method identifies the Peer ID of the system by IPFS during installation * @@ -599,7 +610,6 @@ public static void QuorumSwarmConnect(JSONArray quorum, IPFS ipfs) { * @return Your system's Peer ID assigned by IPFS */ - public static String getPeerID(String filePath) { PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); JSONArray fileContentArray; @@ -617,7 +627,6 @@ public static String getPeerID(String filePath) { return peerid; } - public static int[] getPrivatePosition(int[] positions, int[] privateArray) { int[] PrivatePosition = new int[positions.length]; for (int k = 0; k < positions.length; k++) { @@ -628,7 +637,8 @@ public static int[] getPrivatePosition(int[] positions, int[] privateArray) { return PrivatePosition; } - public static JSONObject randomPositions(String role, String hash, int numberOfPositions, int[] pvt1) throws JSONException { + public static JSONObject randomPositions(String role, String hash, int numberOfPositions, int[] pvt1) + throws JSONException { int u = 0, l = 0, m = 0; int[] hashCharacters = new int[256]; @@ -685,18 +695,19 @@ public static JSONObject randomPositions(String role, String hash, int numberOfP * @param positionsCount Number of positions required * @return Extended array of positions */ -// public static int[] finalPositions(int[] randomPositions, int positionsCount) { -// int[] finalPositions = new int[positionsCount * 64]; -// int u = 0; -// for (int k = 0; k < positionsCount; k++) { -// for (int p = 0; p < 64; p++) { -// finalPositions[u] = randomPositions[k]; -// randomPositions[k]++; -// u++; -// } -// } -// return finalPositions; -// } + // public static int[] finalPositions(int[] randomPositions, int positionsCount) + // { + // int[] finalPositions = new int[positionsCount * 64]; + // int u = 0; + // for (int k = 0; k < positionsCount; k++) { + // for (int p = 0; p < 64; p++) { + // finalPositions[u] = randomPositions[k]; + // randomPositions[k]++; + // u++; + // } + // } + // return finalPositions; + // } /** * This function deletes the mentioned file @@ -714,41 +725,43 @@ public static void deleteFile(String fileName) { } - -// /** -// * This functions picks the required number of quorum members from the mentioned file -// * -// * @param filePath Location of the file -// * @param hash Data from which positions are chosen -// * @return List of chosen members from the file -// */ -// public static ArrayList quorumChooser(String filePath, String hash) { -// PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); -// ArrayList quorumList = new ArrayList(); -// try { -// String fileContent = readFile(filePath); -// JSONArray blockHeight = new JSONArray(fileContent); -// -// int[] hashCharacters = new int[256]; -// var randomPositions = new ArrayList(); -// HashSet positionSet = new HashSet<>(); -// for (int k = 0; positionSet.size() != 7; k++) { -// hashCharacters[k] = Character.getNumericValue(hash.charAt(k)); -// randomPositions.add((((2402 + hashCharacters[k]) * 2709) + ((k + 2709) + hashCharacters[(k)])) % blockHeight.length()); -// positionSet.add(randomPositions.get(k)); -// } -// -// for (Integer integer : positionSet) -// quorumList.add(blockHeight.getJSONObject(integer).getString("peer-id")); -// } catch (JSONException e) { -// FunctionsLogger.error("JSON Exception Occurred", e); -// e.printStackTrace(); -// } -// return quorumList; -// } + // /** + // * This functions picks the required number of quorum members from the + // mentioned file + // * + // * @param filePath Location of the file + // * @param hash Data from which positions are chosen + // * @return List of chosen members from the file + // */ + // public static ArrayList quorumChooser(String filePath, String hash) { + // PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); + // ArrayList quorumList = new ArrayList(); + // try { + // String fileContent = readFile(filePath); + // JSONArray blockHeight = new JSONArray(fileContent); + // + // int[] hashCharacters = new int[256]; + // var randomPositions = new ArrayList(); + // HashSet positionSet = new HashSet<>(); + // for (int k = 0; positionSet.size() != 7; k++) { + // hashCharacters[k] = Character.getNumericValue(hash.charAt(k)); + // randomPositions.add((((2402 + hashCharacters[k]) * 2709) + ((k + 2709) + + // hashCharacters[(k)])) % blockHeight.length()); + // positionSet.add(randomPositions.get(k)); + // } + // + // for (Integer integer : positionSet) + // quorumList.add(blockHeight.getJSONObject(integer).getString("peer-id")); + // } catch (JSONException e) { + // FunctionsLogger.error("JSON Exception Occurred", e); + // e.printStackTrace(); + // } + // return quorumList; + // } /** - * This function is to be initially called to setup the environment of your project + * This function is to be initially called to setup the environment of your + * project */ public static void launch() { pathSet(); @@ -794,7 +807,8 @@ public static String checkDirectory() throws JSONException { File tokenChainsFolder = new File(TOKENCHAIN_PATH); File walletDataFolder = new File(WALLET_DATA_PATH); - if (!dataFolder.exists() || !loggerFolder.exists() || !tokenChainsFolder.exists() || !tokensFolder.exists() || !walletDataFolder.exists()) { + if (!dataFolder.exists() || !loggerFolder.exists() || !tokenChainsFolder.exists() || !tokensFolder.exists() + || !walletDataFolder.exists()) { dataFolder.delete(); loggerFolder.delete(); tokenChainsFolder.delete(); @@ -871,7 +885,6 @@ public static String mineToken(int level, int tokenNumber) { return token; } - public static String toBinary(int x, int len) { if (len > 0) { return String.format("%" + len + "s", @@ -908,7 +921,6 @@ public static Date getCurrentUtcTime() throws ParseException { return localDateFormat.parse(simpleDateFormat.format(new Date())); } - /** * This method is used to update quorum credits in server * @@ -919,8 +931,8 @@ public static Date getCurrentUtcTime() throws ParseException { * @return mined token */ - - public static void updateQuorum(JSONArray quorumArray, JSONArray signedQuorumList, boolean status, int type) throws IOException, JSONException { + public static void updateQuorum(JSONArray quorumArray, JSONArray signedQuorumList, boolean status, int type) + throws IOException, JSONException { if (type == 1) { String urlQuorumUpdate = ADVISORY_IP + "/updateQuorum"; @@ -962,7 +974,6 @@ public static void updateQuorum(JSONArray quorumArray, JSONArray signedQuorumLis } } - /** * This method is used get getquorum from advisory node * @@ -974,8 +985,8 @@ public static void updateQuorum(JSONArray quorumArray, JSONArray signedQuorumLis * @return JSONArray of quorum nodes */ - - public static JSONArray getQuorum(String betaHash, String gammaHash, String senderDidIpfsHash, String receiverDidIpfsHash, int tokenslength) throws IOException, JSONException { + public static JSONArray getQuorum(String betaHash, String gammaHash, String senderDidIpfsHash, + String receiverDidIpfsHash, int tokenslength) throws IOException, JSONException { JSONArray quorumArray; String urlQuorumPick = ADVISORY_IP + "/getQuorum"; URL objQuorumPick = new URL(urlQuorumPick); @@ -1193,9 +1204,11 @@ public static Double getPartsBalance() throws JSONException { Double availableParts = 0.000D, senderCount = 0.000D, receiverCount = 0.000D; for (int k = 0; k < tokenChainArray.length(); k++) { if (tokenChainArray.getJSONObject(k).has("role")) { - if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { + if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") + && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { senderCount += tokenChainArray.getJSONObject(k).getDouble("amount"); - } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { + } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") + && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { receiverCount += tokenChainArray.getJSONObject(k).getDouble("amount"); } } @@ -1208,7 +1221,6 @@ public static Double getPartsBalance() throws JSONException { parts = formatAmount(parts); balance = balance + parts; - int count = 0; File shiftedFile = new File(PAYMENTS_PATH.concat("ShiftedTokens.json")); if (shiftedFile.exists()) { @@ -1218,7 +1230,6 @@ public static Double getPartsBalance() throws JSONException { for (int i = 0; i < shiftedArray.length(); i++) arrayTokens.add(shiftedArray.getString(i)); - for (int i = 0; i < partTokensArray.length(); i++) { if (!arrayTokens.contains(partTokensArray.getJSONObject(i).getString("tokenHash"))) count++; @@ -1246,9 +1257,11 @@ public static Double checkTokenPartBalance(String tokenHash) throws JSONExceptio Double senderCount = 0.000D, receiverCount = 0.000D; for (int k = 0; k < tokenChainArray.length(); k++) { if (tokenChainArray.getJSONObject(k).has("role")) { - if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { + if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") + && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { senderCount += tokenChainArray.getJSONObject(k).getDouble("amount"); - } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { + } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") + && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { receiverCount += tokenChainArray.getJSONObject(k).getDouble("amount"); } } @@ -1265,7 +1278,6 @@ public static Double checkTokenPartBalance(String tokenHash) throws JSONExceptio return availableParts; } - public static Double getBalance() throws JSONException { pathSet(); Double balance = 0.000D; @@ -1284,7 +1296,6 @@ public static Double getBalance() throws JSONException { balance = balance + value; } - File partsFile = new File(PAYMENTS_PATH + "PartsToken.json"); if (partsFile.exists()) { String PART_TOKEN_CHAIN_PATH = TOKENCHAIN_PATH.concat("/PARTS/"); @@ -1303,9 +1314,11 @@ public static Double getBalance() throws JSONException { Double availableParts = 0.000D, senderCount = 0.000D, receiverCount = 0.000D; for (int k = 0; k < tokenChainArray.length(); k++) { if (tokenChainArray.getJSONObject(k).has("role")) { - if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { + if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") + && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { senderCount += tokenChainArray.getJSONObject(k).getDouble("amount"); - } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { + } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") + && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { receiverCount += tokenChainArray.getJSONObject(k).getDouble("amount"); } } @@ -1328,7 +1341,6 @@ public static Double getBalance() throws JSONException { for (int i = 0; i < shiftedArray.length(); i++) arrayTokens.add(shiftedArray.getString(i)); - for (int i = 0; i < partTokensArray.length(); i++) { if (!arrayTokens.contains(partTokensArray.getJSONObject(i).getString("tokenHash"))) count++; @@ -1339,12 +1351,10 @@ public static Double getBalance() throws JSONException { balance = balance - count; } - balance = formatAmount(balance); return balance; } - public static Double partTokenBalance(String tokenHash) throws JSONException { pathSet(); @@ -1358,9 +1368,11 @@ public static Double partTokenBalance(String tokenHash) throws JSONException { Double senderCount = 0.000D, receiverCount = 0.000D; for (int k = 0; k < tokenChainArray.length(); k++) { if (tokenChainArray.getJSONObject(k).has("role")) { - if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { + if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") + && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { senderCount += tokenChainArray.getJSONObject(k).getDouble("amount"); - } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { + } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") + && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { receiverCount += tokenChainArray.getJSONObject(k).getDouble("amount"); } } @@ -1393,7 +1405,8 @@ public static void clearParts() { String partsFile = readFile(PAYMENTS_PATH.concat("PartsToken.json")); JSONArray partsArray = new JSONArray(partsFile); for (int i = 0; i < partsArray.length(); i++) { - if (partTokenBalance(partsArray.getJSONObject(i).getString("tokenHash")) <= 0.000 || partTokenBalance(partsArray.getJSONObject(i).getString("tokenHash")) > 1.000) { + if (partTokenBalance(partsArray.getJSONObject(i).getString("tokenHash")) <= 0.000 + || partTokenBalance(partsArray.getJSONObject(i).getString("tokenHash")) > 1.000) { deleteFile(TOKENS_PATH.concat("PARTS/").concat(partsArray.getJSONObject(i).getString("tokenHash"))); partsArray.remove(i); } @@ -1420,7 +1433,9 @@ public static void backgroundChecks() { addPublicData(); } + public static String sanityMessage; + public static boolean sanityCheck(String peerid, IPFS ipfs, int port) throws IOException { FunctionsLogger.info("Entering SanityCheck"); boolean sanityCheckErrorFlag = true; @@ -1469,9 +1484,9 @@ public static boolean sanityCheck(String peerid, IPFS ipfs, int port) throws IOE } } - return sanityCheckErrorFlag; } + public static boolean checkIPFSStatus(String peerid, IPFS ipfs) { FunctionsLogger.info("Entering checkIPFSStatus"); boolean swarmConnectedStatus = false; @@ -1479,7 +1494,7 @@ public static boolean checkIPFSStatus(String peerid, IPFS ipfs) { MultiAddress multiAddress = new MultiAddress("/ipfs/" + peerid); FunctionsLogger.info("MultiAdrress concated " + multiAddress + "|||"); boolean output = swarmConnectP2P(peerid, ipfs); - + if (output) { swarmConnectedStatus = true; FunctionsLogger.debug("Swarm is already connected"); @@ -1495,7 +1510,6 @@ public static boolean checkIPFSStatus(String peerid, IPFS ipfs) { return swarmConnectedStatus; } - public static boolean ping(String peerid, int port) throws IOException { JSONObject pingCheck = PingCheck.Ping(peerid, port); if (pingCheck.getString("status").contains("Failed")) { @@ -1505,48 +1519,50 @@ public static boolean ping(String peerid, int port) throws IOException { } -// public static String getPing(int port) { -// try { -// -// String didContent = readFile(DATA_PATH + "DID.json"); -// JSONArray didArray = new JSONArray(didContent); -// String myPeerID = didArray.getJSONObject(0).getString("peerid"); -// -// listen(myPeerID.concat("Ping"), port); -// ServerSocket ss = new ServerSocket(port); -// FunctionsLogger.info("Get Ping Listening on port " + port + " appname " + myPeerID.concat("Ping")); -// Socket socket = ss.accept(); -// BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream())); -// PrintStream output = new PrintStream(socket.getOutputStream()); -// FunctionsLogger.info("getPing- waiting response from server"); -// String peerID = input.readLine(); -// if (peerID != null && peerID.contains("Qm")) { -// FunctionsLogger.info("getPing - Received message from server"); -// output.println("Ping received"); -// FunctionsLogger.debug("Ping received from sender"); -// -// output.close(); -// input.close(); -// socket.close(); -// ss.close(); -// executeIPFSCommands(" ipfs p2p close -t /p2p/" + peerID); -// FunctionsLogger.info("If - Closing Sockets"); -// return "Ping received from sender and Pong sent"; -// } -// else{ -// output.close(); -// input.close(); -// socket.close(); -// ss.close(); -// FunctionsLogger.info("Else - Closing Sockets"); -// return "Ping received from sender but not PeerID"; -// } -// -// } catch (Exception e) { -// FunctionsLogger.error("Error in client side communication", e); -// return "Error in client side communication"; -// } -// } + // public static String getPing(int port) { + // try { + // + // String didContent = readFile(DATA_PATH + "DID.json"); + // JSONArray didArray = new JSONArray(didContent); + // String myPeerID = didArray.getJSONObject(0).getString("peerid"); + // + // listen(myPeerID.concat("Ping"), port); + // ServerSocket ss = new ServerSocket(port); + // FunctionsLogger.info("Get Ping Listening on port " + port + " appname " + + // myPeerID.concat("Ping")); + // Socket socket = ss.accept(); + // BufferedReader input = new BufferedReader(new + // InputStreamReader(socket.getInputStream())); + // PrintStream output = new PrintStream(socket.getOutputStream()); + // FunctionsLogger.info("getPing- waiting response from server"); + // String peerID = input.readLine(); + // if (peerID != null && peerID.contains("Qm")) { + // FunctionsLogger.info("getPing - Received message from server"); + // output.println("Ping received"); + // FunctionsLogger.debug("Ping received from sender"); + // + // output.close(); + // input.close(); + // socket.close(); + // ss.close(); + // executeIPFSCommands(" ipfs p2p close -t /p2p/" + peerID); + // FunctionsLogger.info("If - Closing Sockets"); + // return "Ping received from sender and Pong sent"; + // } + // else{ + // output.close(); + // input.close(); + // socket.close(); + // ss.close(); + // FunctionsLogger.info("Else - Closing Sockets"); + // return "Ping received from sender but not PeerID"; + // } + // + // } catch (Exception e) { + // FunctionsLogger.error("Error in client side communication", e); + // return "Error in client side communication"; + // } + // } public static boolean bootstrapConnect(String peerid, IPFS ipfs) { FunctionsLogger.info("bootstrapConnect- entering function"); @@ -1620,7 +1636,8 @@ public static boolean portCheckAndKill(int port) { } /** - * This function will release the port in linux based machines if the port is already in use + * This function will release the port in linux based machines if the port is + * already in use */ public static boolean releasePorts(int port) { FunctionsLogger.info("releasePorts- "); @@ -1641,7 +1658,8 @@ public static boolean releasePorts(int port) { if (processStr != null) { FunctionsLogger.info("releasePorts- Processstr is not null"); if (String.valueOf(currentPid) != processStr && ipfsPidBr.readLine() != processStr) { - FunctionsLogger.info("releasePorts- jar is running on " + currentPid + " and IPFS is occupied in " + ipfsPidBr.readLine()); + FunctionsLogger.info("releasePorts- jar is running on " + currentPid + " and IPFS is occupied in " + + ipfsPidBr.readLine()); FunctionsLogger.debug("Port " + port + " is in using, killing PID " + processStr); processId = Runtime.getRuntime().exec("kill -9 " + processStr); FunctionsLogger.info("releasePorts- killing " + processStr); @@ -1664,36 +1682,50 @@ public static boolean releasePorts(int port) { public static boolean portStatusWindows(int port) { FunctionsLogger.info("Starting portStatusWindows"); boolean releasedPort = false; - String processStr; + String portProcessStr; Process p; + ArrayList pidTree = new ArrayList(); + ArrayList portPidTree = new ArrayList(); try { Runtime rt = Runtime.getRuntime(); - Process proc = rt.exec("cmd /c netstat -ano | findstr " + port); - FunctionsLogger.info("Checking port status"); - long currentPid = ProcessHandle.current().pid(); - BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream())); - processStr = stdInput.readLine(); - FunctionsLogger.info("Process id found for port is " + processStr + " current jar pid is " + currentPid); - if (processStr != null && String.valueOf(currentPid) != processStr) { - int index = processStr.lastIndexOf(" "); - String sc = processStr.substring(index, processStr.length()); - //System.out.println("Port "+port+" is locked by PID "+sc+". Kindly close this port and retry transcation"); - if (sc != String.valueOf(currentPid)) { - FunctionsLogger.debug("Port " + port + " is locked by PID " + sc); - } else { - FunctionsLogger.debug("Port " + port + " is locked by current jar with PID " + sc); - } + Process getJarPid = rt.exec("cmd /c netstat -ano | findstr 1898"); + BufferedReader getJarPidBR = new BufferedReader(new InputStreamReader(getJarPid.getInputStream())); + String getJarPidline; + while ((getJarPidline = getJarPidBR.readLine()) != null) { + String[] getJarPidTree = getJarPidline.split("\\s+"); + int temp = Integer.parseInt(getJarPidTree[getJarPidTree.length - 1]); + pidTree.add(temp); + } + + FunctionsLogger.info("PIDs occupied by Rubix.jar are " + pidTree); + + Set pidSet = new LinkedHashSet(pidTree); + FunctionsLogger.info("Pid occupied by port 1898 is pidSet" + pidSet); + Process getPortPid = rt.exec("cmd /c netstat -ano | findstr " + port); + BufferedReader getPortPidBr = new BufferedReader(new InputStreamReader(getPortPid.getInputStream())); + String getPortPidLine; + while ((getPortPidLine = getPortPidBr.readLine()) != null) { + String[] getPortPidTree = getPortPidLine.split("\\s+"); + int temp = Integer.parseInt(getPortPidTree[getPortPidTree.length - 1]); + portPidTree.add(temp); + } + + Set pidToKill = new LinkedHashSet(portPidTree); + FunctionsLogger.info("Pid used by port " + port + "is " + pidToKill); + pidToKill.removeAll(pidSet); + pidToKill.remove(0); + FunctionsLogger.info("Pid using port " + port + " but not in 1898" + pidToKill); + if (pidToKill.size() > 0) { + System.out.println("Port " + port + " is occupied by PIDs" + pidToKill); } else { releasedPort = true; - FunctionsLogger.info("Port is unlocked"); } + } catch (Exception e) { FunctionsLogger.error("Exception occured at portStatusWindows", e); - e.printStackTrace(); } return releasedPort; - } + } } - From 73f8278e3cabe1cc0c1f0753717320fda4f3dc16 Mon Sep 17 00:00:00 2001 From: Gokul P S Date: Mon, 28 Feb 2022 14:34:12 +0530 Subject: [PATCH 18/49] . From ccbcdb3f989b19ee676d4a4a6b329de16a077c22 Mon Sep 17 00:00:00 2001 From: Nidhin Mahesh A Date: Fri, 4 Mar 2022 11:36:55 +0530 Subject: [PATCH 19/49] rm token pin check Signed-off-by: Nidhin Mahesh A --- .../rubix/TokenTransfer/TokenReceiver.java | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/com/rubix/TokenTransfer/TokenReceiver.java b/src/com/rubix/TokenTransfer/TokenReceiver.java index 8f22637e..ad617728 100644 --- a/src/com/rubix/TokenTransfer/TokenReceiver.java +++ b/src/com/rubix/TokenTransfer/TokenReceiver.java @@ -241,19 +241,20 @@ public static String receive() { owners.put(ownersArray.get(i).toString()); TokenReceiverLogger.debug("Multiple Owners for " + doubleSpentToken); TokenReceiverLogger.debug("Owners: " + owners); - output.println("420"); - output.println(doubleSpentToken.toString()); - output.println(owners.toString()); - APIResponse.put("did", senderDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Multiple Owners for " + doubleSpentToken + " " + owners); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + senderPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); + // output.println("420"); + // output.println(doubleSpentToken.toString()); + // output.println(owners.toString()); + // APIResponse.put("did", senderDidIpfsHash); + // APIResponse.put("tid", "null"); + // APIResponse.put("status", "Failed"); + // APIResponse.put("message", "Multiple Owners for " + doubleSpentToken + " " + + // owners); + // IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + senderPeerID); + // output.close(); + // input.close(); + // sk.close(); + // ss.close(); + // return APIResponse.toString(); } String senderToken = TokenDetails.toString(); From 0984f2d3651c0fe17595e162c5317472797c6864 Mon Sep 17 00:00:00 2001 From: Nidhin Mahesh A Date: Fri, 4 Mar 2022 11:53:16 +0530 Subject: [PATCH 20/49] rm pin check 2/2 Signed-off-by: Nidhin Mahesh A --- .../rubix/TokenTransfer/TokenReceiver.java | 112 +++++++++--------- 1 file changed, 57 insertions(+), 55 deletions(-) diff --git a/src/com/rubix/TokenTransfer/TokenReceiver.java b/src/com/rubix/TokenTransfer/TokenReceiver.java index ad617728..d22af2c2 100644 --- a/src/com/rubix/TokenTransfer/TokenReceiver.java +++ b/src/com/rubix/TokenTransfer/TokenReceiver.java @@ -201,61 +201,63 @@ public static String receive() { JSONObject amountLedger = tokenObject.getJSONObject("amountLedger"); TokenReceiverLogger.debug("Amount Ledger: " + amountLedger); int intPart = wholeTokens.length(); - Double decimalPart = formatAmount(amount - intPart); - JSONArray doubleSpentToken = new JSONArray(); - boolean tokenOwners = true; - ArrayList ownersArray = new ArrayList(); - ArrayList previousSender = new ArrayList(); - JSONArray ownersReceived = new JSONArray(); - for (int i = 0; i < wholeTokens.length(); ++i) { - try { - TokenReceiverLogger.debug("Checking owners for " + wholeTokens.getString(i) + " Please wait..."); - ownersArray = IPFSNetwork.dhtOwnerCheck(wholeTokens.getString(i)); - - if (ownersArray.size() > 2) { - - for (int j = 0; j < previousSendersArray.length(); j++) { - if (previousSendersArray.getJSONObject(j).getString("token") - .equals(wholeTokens.getString(i))) - ownersReceived = previousSendersArray.getJSONObject(j).getJSONArray("sender"); - } - - for (int j = 0; j < ownersReceived.length(); j++) { - previousSender.add(ownersReceived.getString(j)); - } - TokenReceiverLogger.debug("Previous Owners: " + previousSender); - - for (int j = 0; j < ownersArray.size(); j++) { - if (!previousSender.contains(ownersArray.get(j).toString())) - tokenOwners = false; - } - } - } catch (IOException e) { - - TokenReceiverLogger.debug("Ipfs dht find did not execute"); - } - } - if (!tokenOwners) { - JSONArray owners = new JSONArray(); - for (int i = 0; i < ownersArray.size(); i++) - owners.put(ownersArray.get(i).toString()); - TokenReceiverLogger.debug("Multiple Owners for " + doubleSpentToken); - TokenReceiverLogger.debug("Owners: " + owners); - // output.println("420"); - // output.println(doubleSpentToken.toString()); - // output.println(owners.toString()); - // APIResponse.put("did", senderDidIpfsHash); - // APIResponse.put("tid", "null"); - // APIResponse.put("status", "Failed"); - // APIResponse.put("message", "Multiple Owners for " + doubleSpentToken + " " + - // owners); - // IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + senderPeerID); - // output.close(); - // input.close(); - // sk.close(); - // ss.close(); - // return APIResponse.toString(); - } + // Double decimalPart = formatAmount(amount - intPart); + // JSONArray doubleSpentToken = new JSONArray(); + // boolean tokenOwners = true; + // ArrayList ownersArray = new ArrayList(); + // ArrayList previousSender = new ArrayList(); + // JSONArray ownersReceived = new JSONArray(); + // for (int i = 0; i < wholeTokens.length(); ++i) { + // try { + // TokenReceiverLogger.debug("Checking owners for " + wholeTokens.getString(i) + + // " Please wait..."); + // ownersArray = IPFSNetwork.dhtOwnerCheck(wholeTokens.getString(i)); + + // if (ownersArray.size() > 2) { + + // for (int j = 0; j < previousSendersArray.length(); j++) { + // if (previousSendersArray.getJSONObject(j).getString("token") + // .equals(wholeTokens.getString(i))) + // ownersReceived = + // previousSendersArray.getJSONObject(j).getJSONArray("sender"); + // } + + // for (int j = 0; j < ownersReceived.length(); j++) { + // previousSender.add(ownersReceived.getString(j)); + // } + // TokenReceiverLogger.debug("Previous Owners: " + previousSender); + + // for (int j = 0; j < ownersArray.size(); j++) { + // if (!previousSender.contains(ownersArray.get(j).toString())) + // tokenOwners = false; + // } + // } + // } catch (IOException e) { + + // TokenReceiverLogger.debug("Ipfs dht find did not execute"); + // } + // } + // if (!tokenOwners) { + // JSONArray owners = new JSONArray(); + // for (int i = 0; i < ownersArray.size(); i++) + // owners.put(ownersArray.get(i).toString()); + // TokenReceiverLogger.debug("Multiple Owners for " + doubleSpentToken); + // TokenReceiverLogger.debug("Owners: " + owners); + // output.println("420"); + // output.println(doubleSpentToken.toString()); + // output.println(owners.toString()); + // APIResponse.put("did", senderDidIpfsHash); + // APIResponse.put("tid", "null"); + // APIResponse.put("status", "Failed"); + // APIResponse.put("message", "Multiple Owners for " + doubleSpentToken + " " + + // owners); + // IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + senderPeerID); + // output.close(); + // input.close(); + // sk.close(); + // ss.close(); + // return APIResponse.toString(); + // } String senderToken = TokenDetails.toString(); String consensusID = calculateHash(senderToken, "SHA3-256"); From 89d95255f6a600ec3e3d0128f78bd902cf86e506 Mon Sep 17 00:00:00 2001 From: Nidhin Mahesh A Date: Wed, 9 Mar 2022 12:34:28 +0530 Subject: [PATCH 21/49] update rec checks Signed-off-by: Nidhin Mahesh A --- .../rubix/AuthenticateNode/Authenticate.java | 3 +- src/com/rubix/NFT/Buyer.java | 411 --------------- src/com/rubix/NFT/Seller.java | 497 ------------------ src/com/rubix/Resources/FractionChooser.java | 88 ---- src/com/rubix/Resources/Functions.java | 376 ++++++------- src/com/rubix/Resources/IPFSNetwork.java | 10 +- .../rubix/TokenTransfer/TokenReceiver.java | 158 ++---- src/com/rubix/TokenTransfer/TokenSender.java | 6 +- 8 files changed, 235 insertions(+), 1314 deletions(-) delete mode 100644 src/com/rubix/NFT/Buyer.java delete mode 100644 src/com/rubix/NFT/Seller.java delete mode 100644 src/com/rubix/Resources/FractionChooser.java diff --git a/src/com/rubix/AuthenticateNode/Authenticate.java b/src/com/rubix/AuthenticateNode/Authenticate.java index bfaabd59..0631faa0 100644 --- a/src/com/rubix/AuthenticateNode/Authenticate.java +++ b/src/com/rubix/AuthenticateNode/Authenticate.java @@ -62,8 +62,7 @@ public static boolean verifySignature(String detailString) throws IOException, J positionsLevelZero[k] = ((originalPos[k]) / 8); StringBuilder decentralizedIDForAuth = new StringBuilder(); - for (int value : positionsLevelZero) - decentralizedIDForAuth.append(senderDIDBin.charAt(value)); + for (int value : positionsLevelZero) decentralizedIDForAuth.append(senderDIDBin.charAt(value)); if (recombinedResult.equals(decentralizedIDForAuth.toString())) { return true; } else { diff --git a/src/com/rubix/NFT/Buyer.java b/src/com/rubix/NFT/Buyer.java deleted file mode 100644 index 3d7cbec8..00000000 --- a/src/com/rubix/NFT/Buyer.java +++ /dev/null @@ -1,411 +0,0 @@ -package com.rubix.NFT; - - -import com.rubix.AuthenticateNode.Authenticate; -import com.rubix.Resources.FractionChooser; -import com.rubix.Resources.Functions; -import com.rubix.Resources.IPFSNetwork; -import io.ipfs.api.IPFS; -import java.awt.image.BufferedImage; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileWriter; -import java.io.InputStreamReader; -import java.io.PrintStream; -import java.net.ServerSocket; -import java.net.Socket; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Iterator; -import javax.imageio.ImageIO; -import org.apache.log4j.Logger; -import org.apache.log4j.PropertyConfigurator; -import org.json.JSONArray; -import org.json.JSONObject; - -public class Buyer { - public static Logger BuyerLogger = Logger.getLogger(Buyer.class); - - private static final JSONObject APIResponse = new JSONObject(); - - private static final IPFS ipfs = new IPFS("/ip4/127.0.0.1/tcp/" + Functions.IPFS_PORT); - - public static String receive() { - Functions.pathSet(); - ServerSocket ss = null; - Socket sk = null; - String sellerPeerID = null; - try { - int quorumSignVerifyCount = 0; - JSONObject quorumSignatures = null; - ArrayList quorumDID = new ArrayList<>(); - PropertyConfigurator.configure(Functions.LOGGER_PATH + "log4jWallet.properties"); - String buyerPeerID = Functions.getPeerID(Functions.DATA_PATH + "DID.json"); - String buyerDidIpfsHash = Functions.getValues(Functions.DATA_PATH + "DataTable.json", "didHash", "peerid", buyerPeerID); - IPFSNetwork.listen(buyerPeerID + "NFT", Functions.BUYER_PORT); - ss = new ServerSocket(Functions.BUYER_PORT); - BuyerLogger.debug("Listening on " + Functions.BUYER_PORT + " with app name " + buyerPeerID + "NFT"); - sk = ss.accept(); - BufferedReader input = new BufferedReader(new InputStreamReader(sk.getInputStream())); - PrintStream output = new PrintStream(sk.getOutputStream()); - long startTime = System.currentTimeMillis(); - sellerPeerID = input.readLine(); - BuyerLogger.debug("Seller PeerID received"); - String sellerDidIpfsHash = Functions.getValues(Functions.DATA_PATH + "DataTable.json", "didHash", "peerid", sellerPeerID); - String sellerWidIpfsHash = Functions.getValues(Functions.DATA_PATH + "DataTable.json", "walletHash", "peerid", sellerPeerID); - if (!sellerDidIpfsHash.contains("Qm") || !sellerWidIpfsHash.contains("Qm")) { - output.println("420"); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Invalid Seller DID."); - BuyerLogger.info("Seller details not available in datatable"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); - } - Functions.nodeData(sellerDidIpfsHash, sellerWidIpfsHash, ipfs); - File sellerDIDFile = new File(Functions.DATA_PATH + sellerDidIpfsHash + "DID.png"); - if (!sellerDIDFile.exists()) { - output.println("420"); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Seller details not available in network , please sync"); - BuyerLogger.info("Sender details not available"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); - } - output.println("200"); - BuyerLogger.debug("PeerAuth sent to Seller"); - String nftData = input.readLine(); - BuyerLogger.debug("NFT Token details received from Seller"); - JSONObject nftTokenDetails = new JSONObject(nftData); - String nftToken = nftTokenDetails.getString("nftToken"); - String nftTokenChain = nftTokenDetails.getString("nftTokenChain"); - String message = nftTokenDetails.toString(); - String nftID = Functions.calculateHash(message, "SHA3-256"); - Functions.writeToFile(Functions.LOGGER_PATH + "nftID", nftID, Boolean.valueOf(false)); - String nftIdIpfsHash = IPFSNetwork.addHashOnly(Functions.LOGGER_PATH + "nftID", ipfs); - Functions.deleteFile(Functions.LOGGER_PATH + "nftID"); - String nftTokenChainContent = IPFSNetwork.get(nftTokenChain, ipfs); - String nftTokenContent = IPFSNetwork.get(nftToken, ipfs); - BuyerLogger.debug("NFT token content extracted"); - IPFSNetwork.repo(ipfs); - if (!IPFSNetwork.dhtEmpty(nftIdIpfsHash, ipfs)) { - BuyerLogger.debug("NFT ID not unique" + nftIdIpfsHash); - output.println("420"); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "NFT ID not unique"); - BuyerLogger.info("NFT ID not unique"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); - } - if (nftTokenContent.equals("")) { - output.println("421"); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Invalid NFT Token"); - BuyerLogger.info("Invalid NFT Token"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); - } - output.println("200"); - BuyerLogger.debug("NftTokenAuth: 200. Sent to Seller"); - String assetData = input.readLine(); - BuyerLogger.debug("Received asset details from Seller"); - JSONObject assetDetails = new JSONObject(assetData); - int amount = assetDetails.getInt("amount"); - JSONArray rbxTokens = FractionChooser.calculate(amount); - JSONArray rbxTokenHeader = FractionChooser.tokenHeader; - ArrayList rbxTokensChainsPushed = new ArrayList<>(); - if (rbxTokens.length() == 0) { - output.println("420"); - BuyerLogger.debug("Insufficient balance with buyer"); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Insufficient balance"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); - } - for (int i = 0; i < rbxTokens.length(); i++) { - File rbxtoken = new File(Functions.TOKENS_PATH+rbxTokens.get(i)); - File rbxtokenchain = new File(Functions.TOKENCHAIN_PATH+rbxTokens.get(i)+".json"); - BuyerLogger.debug("" + rbxtoken + " and " + rbxtoken); - if (!rbxtoken.exists() || !rbxtokenchain.exists()) { - output.println("421"); - BuyerLogger.info("Tokens Not Verified"); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Invalid token(s)"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); - } - IPFSNetwork.add(Functions.TOKENS_PATH+rbxTokens.get(i), ipfs); - String tokenChainHash = IPFSNetwork.add(Functions.TOKENCHAIN_PATH+rbxTokens.get(i)+".json", ipfs); - rbxTokensChainsPushed.add(tokenChainHash); - } - JSONObject rbxTokenDetails = new JSONObject(); - rbxTokenDetails.put("rbxTokens", rbxTokens); - rbxTokenDetails.put("rbxTokenChains", rbxTokensChainsPushed); - rbxTokenDetails.put("rbxTokenHeader", rbxTokenHeader); - String pvt = Functions.DATA_PATH+ buyerDidIpfsHash + "PrivateShare.png"; - String buyerSign = Functions.getSignFromShares(pvt, Functions.calculateHash(rbxTokens.toString() + rbxTokenHeader.toString() + rbxTokensChainsPushed.toString(), "SHA3-256")); - JSONObject rbxData = new JSONObject(); - rbxData.put("rbxTokenDetails", rbxTokenDetails); - rbxData.put("authBuyerBySeller", buyerSign); - output.println(rbxData); - BuyerLogger.debug("Sent rbxData and Buyer sign for authentication to seller."); - String rbxTokensAuth = input.readLine(); - if (rbxTokensAuth.equals("421")) { - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "RBX tokens not verified at seller node"); - BuyerLogger.info("RBX tokens not verified at sender node"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); - } - if (rbxTokensAuth.equals("420")) { - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Consensus ID not Unique"); - BuyerLogger.info("Consensus ID not Unique"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); - } - BuyerLogger.debug("consensus/seller details received from Seller"); - JSONObject consensusDetails = new JSONObject(rbxTokensAuth); - String sellerSignature = consensusDetails.getString("sign"); - String tid = consensusDetails.getString("tid"); - String comment = consensusDetails.getString("comment"); - String Status = consensusDetails.getString("status"); - String QuorumDetails = consensusDetails.getString("quorumsign"); - BuyerLogger.debug("Consensus Status: " + Status); - if (!Status.equals("Consensus Failed")) { - boolean yesQuorum = false; - if (Status.equals("Consensus Reached")) { - BuyerLogger.debug("Quorum Signatures: " + QuorumDetails); - quorumSignatures = new JSONObject(QuorumDetails); - BuyerLogger.debug("Quorum Signatures length : " + quorumSignatures.length()); - Iterator dids = quorumSignatures.keys(); - while (dids.hasNext()) { - String did = dids.next(); - quorumDID.add(did); - } - for (String quorumDidIpfsHash : quorumDID) { - String quorumWidIpfsHash = Functions.getValues(Functions.DATA_PATH + "DataTable.json", "walletHash", "didHash", quorumDidIpfsHash); - File quorumDataFolder = new File(Functions.DATA_PATH + "/"); - if (!quorumDataFolder.exists()) { - quorumDataFolder.mkdirs(); - IPFSNetwork.getImage(quorumDidIpfsHash, ipfs, Functions.DATA_PATH + quorumDidIpfsHash + "DID.png"); - IPFSNetwork.getImage(quorumWidIpfsHash, ipfs, Functions.DATA_PATH + quorumDidIpfsHash + "PublicShare.png"); - BuyerLogger.debug("Quorum Data " + quorumDidIpfsHash + " Added"); - continue; - } - BuyerLogger.debug("Quorum Data " + quorumDidIpfsHash + " Available"); - } - for (int j = 0; j < quorumSignatures.length(); j++) { - JSONObject jSONObject = new JSONObject(); - jSONObject.put("did", quorumDID.get(j)); - jSONObject.put("signature", quorumSignatures.getString(quorumDID.get(j))); - boolean val = Authenticate.verifySignature(jSONObject.toString()); - if (val) - quorumSignVerifyCount++; - } - BuyerLogger.debug("Verified Quorum Count " + quorumSignVerifyCount); - yesQuorum = (quorumSignVerifyCount >= quorumSignatures.length()); - } - String hash = Functions.calculateHash(nftToken + nftTokenChain + amount + buyerDidIpfsHash, "SHA3-256"); - JSONObject detailsForVerify = new JSONObject(); - detailsForVerify.put("did", sellerDidIpfsHash); - detailsForVerify.put("hash", hash); - detailsForVerify.put("signature", sellerSignature); - boolean yesSender = Authenticate.verifySignature(detailsForVerify.toString()); - BuyerLogger.debug("Seller Auth Hash" + hash); - BuyerLogger.debug("Quorum Auth : " + yesQuorum + "Seller Auth : " + yesSender); - if (!yesSender || !yesQuorum) { - output.println("420"); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", tid); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Seller/Quorum not verified"); - BuyerLogger.info("Seller/Quorum not verified"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); - } - IPFSNetwork.repo(ipfs); - BuyerLogger.debug("Seller and Quorum Verified"); - output.println("200"); - String nftUnpinStatus = input.readLine(); - if (nftUnpinStatus.equals("Unpinned NFT")) { - FileWriter fileWriter = new FileWriter(Functions.NFT_TOKENS_PATH+nftToken); - fileWriter.write(nftTokenContent); - fileWriter.close(); - IPFSNetwork.add(Functions.NFT_TOKENS_PATH + nftToken, ipfs); - IPFSNetwork.pin(nftToken, ipfs); - - try { - BuyerLogger.debug("Successfully Pinned NFT Token"); - for (int j = 0; j < rbxTokens.length(); j++) - IPFSNetwork.unpin(String.valueOf(rbxTokens.get(j)), ipfs); - IPFSNetwork.repo(ipfs); - BuyerLogger.debug("Unpinned RBX Tokens"); - output.println("Unpinned RBX"); - String rbxPinData = input.readLine(); - JSONObject rbxPinDetails = new JSONObject(rbxPinData); - String status = rbxPinDetails.getString("status"); - if (status.equals("Failed to pin RBX")) { - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Seller Failed to pin RBX Tokens"); - BuyerLogger.info(" Transaction failed"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); - } - String essentialShare = rbxPinDetails.getString("essentialShare"); - long endTime = System.currentTimeMillis(); - JSONArray currentNftTokenChain = new JSONArray(nftTokenChainContent); - JSONObject newRecord = new JSONObject(); - newRecord.put("sellerDID", sellerDidIpfsHash); - newRecord.put("sellerSign", sellerSignature); - newRecord.put("comment", comment); - newRecord.put("tid", tid); - currentNftTokenChain.put(newRecord); - Functions.writeToFile(Functions.NFT_TOKENCHAIN_PATH+nftTokenChain+".json", currentNftTokenChain.toString(), Boolean.valueOf(false)); - Iterator keys = quorumSignatures.keys(); - JSONArray quorumList = new JSONArray(); - while (keys.hasNext()) - quorumList.put(keys.next()); - JSONObject nftTransactionRecord = new JSONObject(); - nftTransactionRecord.put("role", "Buyer"); - nftTransactionRecord.put("sellerDID", sellerDidIpfsHash); - nftTransactionRecord.put("buyerDID", buyerDidIpfsHash); - nftTransactionRecord.put("amount", amount); - nftTransactionRecord.put("rbxTokens", rbxTokens); - nftTransactionRecord.put("nftToken", nftToken); - nftTransactionRecord.put("txn", tid); - nftTransactionRecord.put("quorumList", quorumList); - nftTransactionRecord.put("Date", Functions.getCurrentUtcTime()); - nftTransactionRecord.put("totalTime", endTime - startTime); - nftTransactionRecord.put("comment", comment); - nftTransactionRecord.put("essentialShare", essentialShare); - JSONArray nftTransactionHistoryEntry = new JSONArray(); - nftTransactionHistoryEntry.put(nftTransactionRecord); - Functions.updateJSON("add", Functions.WALLET_DATA_PATH + "nftTransactionHistory.json", nftTransactionHistoryEntry.toString()); - int k; - for (k = 0; k < rbxTokens.length(); k++) - Files.deleteIfExists(Paths.get(Functions.TOKENS_PATH+rbxTokens.get(k), new String[0])); - for (k = 0; k < amount; k++) - Functions.updateJSON("remove", Functions.PAYMENTS_PATH+rbxTokenHeader.getString(k), rbxTokens.getString(k)); - BuyerLogger.info("Transaction ID: " + tid + "Transaction Successful"); - output.println("Send Response"); - APIResponse.put("sellerDID", sellerDidIpfsHash); - APIResponse.put("buyerDID", buyerDidIpfsHash); - APIResponse.put("tid", tid); - APIResponse.put("status", "Success"); - APIResponse.put("tokens", nftToken); - APIResponse.put("comment", comment); - APIResponse.put("message", "NFT Transaction Successful"); - BuyerLogger.info("Transaction Successful"); - } catch (Exception e) { - output.println("Failed pinning on Buyer Node"); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Failed in pinning NFT token"); - BuyerLogger.info(" Transaction failed", e); - } - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); - } - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Seller Failed to unpin"); - BuyerLogger.info(" Transaction failed"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); - } - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Consensus failed at Sender side"); - BuyerLogger.info(" Transaction failed"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); - } catch (Exception e) { - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - BuyerLogger.error("Exception Occurred", e); - return APIResponse.toString(); - } finally { - try { - ss.close(); - sk.close(); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - } catch (Exception e) { - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - BuyerLogger.error("Exception Occurred", e); - } - } - } -} diff --git a/src/com/rubix/NFT/Seller.java b/src/com/rubix/NFT/Seller.java deleted file mode 100644 index 359f9245..00000000 --- a/src/com/rubix/NFT/Seller.java +++ /dev/null @@ -1,497 +0,0 @@ -package com.rubix.NFT; - -import com.rubix.AuthenticateNode.PropImage; -import com.rubix.Consensus.InitiatorConsensus; -import com.rubix.Consensus.InitiatorProcedure; -import com.rubix.Resources.Functions; -import com.rubix.Resources.IPFSNetwork; -import io.ipfs.api.IPFS; -import java.awt.image.BufferedImage; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileWriter; -import java.io.InputStreamReader; -import java.io.PrintStream; -import java.net.Socket; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Iterator; -import javax.imageio.ImageIO; -import org.apache.log4j.Logger; -import org.apache.log4j.PropertyConfigurator; -import org.json.JSONArray; -import org.json.JSONObject; - -public class Seller { - private static final Logger SellerLogger = Logger.getLogger(Seller.class); - - private static final String USER_AGENT = "Mozilla/5.0"; - - public static BufferedReader serverInput; - - private static PrintStream output; - - private static BufferedReader input; - - private static Socket sellerSocket; - - private static boolean sellerMutex = false; - - public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception { - JSONArray quorumArray; - JSONObject APIResponse = new JSONObject(); - PropertyConfigurator.configure(Functions.LOGGER_PATH + "log4jWallet.properties"); - JSONObject detailsObject = new JSONObject(data); - String buyerDidIpfsHash = detailsObject.getString("buyerDidIpfsHash"); - String pvt = detailsObject.getString("pvt"); - int amount = detailsObject.getInt("amount"); - int type = detailsObject.getInt("type"); - String comment = detailsObject.getString("comment"); - //String eKey = detailsObject.getString("eKey"); - //String dKey = detailsObject.getString("dKey"); - String nftTokenIpfsHash = detailsObject.getString("nftToken"); - JSONArray alphaQuorum = new JSONArray(); - JSONArray betaQuorum = new JSONArray(); - JSONArray gammaQuorum = new JSONArray(); - String sellerPeerId = Functions.getPeerID(Functions.DATA_PATH + "DID.json"); - SellerLogger.debug("Seller Peer ID : " + sellerPeerId); - String sellerDidIpfsHash = Functions.getValues(Functions.DATA_PATH + "DataTable.json", "didHash", "peerid", sellerPeerId); - SellerLogger.debug("Seller DID IPFS Hash : " + sellerDidIpfsHash); - SellerLogger.debug("Path is : " + Functions.DATA_PATH + sellerDidIpfsHash); - File folder = new File(Functions.DATA_PATH); - File[] listOfFiles = folder.listFiles(); - for (int i = 0; i < listOfFiles.length; i++) { - if (listOfFiles[i].isFile()) { - System.out.println("File " + listOfFiles[i].getName()); - } else if (listOfFiles[i].isDirectory()) { - System.out.println("Directory " + listOfFiles[i].getName()); - } - } - BufferedImage senderWidImage = ImageIO.read(new File(Functions.DATA_PATH + sellerDidIpfsHash + "/PublicShare.png")); - String senderWidBin = PropImage.img2bin(senderWidImage); - if (sellerMutex) { - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Sender busy. Try again later"); - SellerLogger.warn("Sender busy"); - return APIResponse; - } - sellerMutex = true; - //String nftTokenChainIpfsHash = null; - APIResponse = new JSONObject(); - File nfttoken = new File(Functions.NFT_TOKENS_PATH+nftTokenIpfsHash); - File nfttokenchain = new File(Functions.NFT_TOKENCHAIN_PATH + nftTokenIpfsHash +".json"); - SellerLogger.debug("NFT Token : " + nfttoken + " and NFT TokenChain : " + nfttokenchain); - if (!nfttoken.exists() || !nfttokenchain.exists() ) { - SellerLogger.info("NFT Token Not Verified"); - sellerMutex = false; - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Invalid NFT token"); - return APIResponse; - } - IPFSNetwork.add(Functions.NFT_TOKENS_PATH + nftTokenIpfsHash, ipfs); - String nftTokenChainIpfsHash = IPFSNetwork.add(Functions.NFT_TOKENCHAIN_PATH + nftTokenIpfsHash + ".json", ipfs); - String authSellerByBuyerHash = Functions.calculateHash(nftTokenIpfsHash + nftTokenChainIpfsHash+ amount + buyerDidIpfsHash, "SHA3-256"); - String tid = Functions.calculateHash(authSellerByBuyerHash, "SHA3-256"); - SellerLogger.debug("Hash for Seller authentication to Buyer : " + authSellerByBuyerHash); - SellerLogger.debug("TID on seller " + tid); - Functions.writeToFile(Functions.LOGGER_PATH + "tempbeta", tid.concat(sellerDidIpfsHash), Boolean.valueOf(false)); - String betaHash = IPFSNetwork.add(Functions.LOGGER_PATH + "tempbeta", ipfs); - Functions.deleteFile(Functions.LOGGER_PATH + "tempbeta"); - Functions.writeToFile(Functions.LOGGER_PATH + "tempgamma", tid.concat(buyerDidIpfsHash), Boolean.valueOf(false)); - String gammaHash = IPFSNetwork.add(Functions.LOGGER_PATH + "tempgamma", ipfs); - Functions.deleteFile(Functions.LOGGER_PATH + "tempgamma"); - switch (type) { - case 1: - quorumArray = Functions.getQuorum(betaHash, gammaHash, sellerDidIpfsHash, buyerDidIpfsHash, amount); - break; - case 2: - quorumArray = new JSONArray(Functions.readFile(Functions.DATA_PATH + "quorumlist.json")); - break; - case 3: - quorumArray = detailsObject.getJSONArray("quorum"); - break; - default: - SellerLogger.error("Unknown quorum type input, cancelling transaction"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Unknown quorum type input, cancelling transaction"); - return APIResponse; - } - Functions.QuorumSwarmConnect(quorumArray, ipfs); - int alphaSize = quorumArray.length() - 14; - int j; - for (j = 0; j < alphaSize; j++) - alphaQuorum.put(quorumArray.getString(j)); - for (j = 0; j < 7; j++) { - betaQuorum.put(quorumArray.getString(alphaSize + j)); - gammaQuorum.put(quorumArray.getString(alphaSize + 7 + j)); - } - SellerLogger.debug("alphaquorum " + alphaQuorum + " size " + alphaQuorum.length()); - SellerLogger.debug("betaquorum " + betaQuorum + " size " + betaQuorum.length()); - SellerLogger.debug("gammaquorum " + gammaQuorum + " size " + gammaQuorum.length()); - ArrayList alphaPeersList = Functions.QuorumCheck(alphaQuorum, alphaSize); - ArrayList betaPeersList = Functions.QuorumCheck(betaQuorum, 7); - ArrayList gammaPeersList = Functions.QuorumCheck(gammaQuorum, 7); - SellerLogger.debug("alphaPeersList size " + alphaPeersList.size()); - SellerLogger.debug("betaPeersList size " + betaPeersList.size()); - SellerLogger.debug("gammaPeersList size " + gammaPeersList.size()); - SellerLogger.debug("minQuorumAlpha size " + Functions.minQuorum(alphaSize)); - if (alphaPeersList.size() < Functions.minQuorum(alphaSize) || betaPeersList.size() < 5 || gammaPeersList.size() < 5) { - Functions.updateQuorum(quorumArray, null, false, type); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Quorum Members not available"); - SellerLogger.warn("Quorum Members not available"); - sellerMutex = false; - return APIResponse; - } - String sellerSign = Functions.getSignFromShares(pvt, authSellerByBuyerHash); - JSONObject sellerDetails2Buyer = new JSONObject(); - sellerDetails2Buyer.put("sign", sellerSign); - sellerDetails2Buyer.put("tid", tid); - sellerDetails2Buyer.put("comment", comment); - JSONObject nftTokenDetails = new JSONObject(); - nftTokenDetails.put("nftToken", nftTokenIpfsHash); - nftTokenDetails.put("nftTokenChain", nftTokenChainIpfsHash); - String message = nftTokenDetails.toString(); - String nftID = Functions.calculateHash(message, "SHA3-256"); - Functions.writeToFile(Functions.LOGGER_PATH + "nftID", nftID, Boolean.valueOf(false)); - String nftIdIpfsHash = IPFSNetwork.addHashOnly(Functions.LOGGER_PATH + "nftID", ipfs); - Functions.deleteFile(Functions.LOGGER_PATH + "nftID"); - SellerLogger.debug("nftID hash " + nftIdIpfsHash + " unique owner " + IPFSNetwork.dhtEmpty(nftIdIpfsHash, ipfs)); - JSONObject assetDetails = new JSONObject(); - assetDetails.put("amount", amount); - String buyerPeerId = Functions.getValues(Functions.DATA_PATH + "DataTable.json", "peerid", "didHash", buyerDidIpfsHash); - SellerLogger.debug("Swarm connecting to " + buyerPeerId); - IPFSNetwork.swarmConnectP2P(buyerPeerId, ipfs); - SellerLogger.debug("Swarm connected"); - String buyerWidIpfsHash = Functions.getValues(Functions.DATA_PATH + "DataTable.json", "walletHash", "didHash", buyerDidIpfsHash); - Functions.nodeData(buyerDidIpfsHash, buyerWidIpfsHash, ipfs); - IPFSNetwork.forward(buyerPeerId + "NFT", port, buyerPeerId); - SellerLogger.debug("Forwarded to " + buyerPeerId + " on " + port); - sellerSocket = new Socket("127.0.0.1", port); - input = new BufferedReader(new InputStreamReader(sellerSocket.getInputStream())); - output = new PrintStream(sellerSocket.getOutputStream()); - long startTime = System.currentTimeMillis(); - output.println(sellerPeerId); - SellerLogger.debug("PeerID sent to Buyer"); - String peerAuth = input.readLine(); - SellerLogger.debug("PeerAuth received from Buyer. Code: " + peerAuth); - if (!peerAuth.equals("200")) { - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); - SellerLogger.info("Seller data not available in the network"); - output.close(); - input.close(); - sellerSocket.close(); - sellerMutex = false; - Functions.updateQuorum(quorumArray, null, false, type); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", tid); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Seller data not available in the network"); - return APIResponse; - } - output.println(nftTokenDetails); - SellerLogger.debug("NFT Token details sent to Buyer"); - String nftTokenAuth = input.readLine(); - SellerLogger.debug("nftTokenAuth received from Buyer. Code: " + nftTokenAuth); - if (!nftTokenAuth.equals("200")) { - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); - output.close(); - input.close(); - sellerSocket.close(); - sellerMutex = false; - if (nftTokenAuth.equals("421")) { - SellerLogger.info("Invalid NFT Token"); - APIResponse.put("message", "Invalid NFT Token"); - } else { - SellerLogger.info("NFT ID not unique"); - APIResponse.put("message", "NFT ID not unique"); - } - Functions.updateQuorum(quorumArray, null, false, type); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", tid); - APIResponse.put("status", "Failed"); - return APIResponse; - } - output.println(assetDetails); - SellerLogger.debug("Sent asset details to Buyer"); - String rbxTokenAuth = input.readLine(); - SellerLogger.debug("Received rbxTokenAuth from Buyer"); - if (rbxTokenAuth.equals("421")) { - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); - output.close(); - input.close(); - sellerSocket.close(); - sellerMutex = false; - SellerLogger.info("Invalid RBX tokens at buyer end"); - APIResponse.put("message", "Invalid RBX tokens at buyer end"); - Functions.updateQuorum(quorumArray, null, false, type); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", tid); - APIResponse.put("status", "Failed"); - return APIResponse; - } - if (rbxTokenAuth.equals("420")) { - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); - output.close(); - input.close(); - sellerSocket.close(); - sellerMutex = false; - SellerLogger.info("Insufficient RBX tokens at buyer end"); - APIResponse.put("message", "Insufficient RBX tokens at buyer end"); - Functions.updateQuorum(quorumArray, null, false, type); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", tid); - APIResponse.put("status", "Failed"); - return APIResponse; - } - JSONObject rbxData = new JSONObject(rbxTokenAuth); - String buyerSign = rbxData.getString("authBuyerBySeller"); - JSONObject rbxTokenDetails = rbxData.getJSONObject("rbxTokenDetails"); - JSONArray rbxTokens = rbxTokenDetails.getJSONArray("rbxTokens"); - JSONArray rbxTokenChains = rbxTokenDetails.getJSONArray("rbxTokenChains"); - JSONArray rbxTokenHeader = rbxTokenDetails.getJSONArray("rbxTokenHeader"); - String messageContent = rbxTokenDetails.toString(); - String consensusID = Functions.calculateHash(messageContent, "SHA3-256"); - Functions.writeToFile(Functions.LOGGER_PATH + "consensusID", consensusID, Boolean.valueOf(false)); - String consensusIdIpfsHash = IPFSNetwork.addHashOnly(Functions.LOGGER_PATH + "consensusID", ipfs); - Functions.deleteFile(Functions.LOGGER_PATH + "consensusID"); - int ipfsGetFlag = 0; - ArrayList allRbxTokenContent = new ArrayList<>(); - ArrayList allRbxTokenChainContent = new ArrayList<>(); - for (int k = 0; k < amount; k++) { - String TokenChainContent = IPFSNetwork.get(rbxTokenChains.getString(k), ipfs); - allRbxTokenChainContent.add(TokenChainContent); - String TokenContent = IPFSNetwork.get(rbxTokens.getString(k), ipfs); - allRbxTokenContent.add(TokenContent); - ipfsGetFlag++; - } - IPFSNetwork.repo(ipfs); - if (!IPFSNetwork.dhtEmpty(consensusIdIpfsHash, ipfs)) { - SellerLogger.debug("consensus ID not unique" + consensusIdIpfsHash); - output.println("420"); - APIResponse.put("did", buyerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Consensus ID not unique"); - SellerLogger.info("Consensus ID not unique"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); - output.close(); - input.close(); - sellerSocket.close(); - return APIResponse; - } - if (ipfsGetFlag != amount) { - output.println("421"); - APIResponse.put("did", buyerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Tokens not verified"); - SellerLogger.info("Tokens not verified"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); - output.close(); - input.close(); - sellerSocket.close(); - return APIResponse; - } - JSONObject dataObject = new JSONObject(); - dataObject.put("tid", tid); - dataObject.put("message", message); - dataObject.put("messageRbx", messageContent); - dataObject.put("buyerDidIpfsHash", buyerDidIpfsHash); - dataObject.put("pvt", pvt); - dataObject.put("sellerDidIpfsHash", sellerDidIpfsHash); - dataObject.put("nftToken", nftTokenIpfsHash); - dataObject.put("rbxTokens", rbxTokens); - dataObject.put("alphaList", alphaPeersList); - dataObject.put("betaList", betaPeersList); - dataObject.put("gammaList", gammaPeersList); - SellerLogger.debug("dataobject " + dataObject.toString()); - SellerLogger.debug("nftConsensus Setup Begins"); - InitiatorProcedure.nftConsensusSetUp(dataObject.toString(), ipfs, Functions.SELLER_PORT + 225, alphaSize); - SellerLogger.debug("nftConsensus Done"); - SellerLogger.debug("length on seller " + InitiatorConsensus.quorumSignature.length() + " response count " + InitiatorConsensus.quorumResponse); - if (InitiatorConsensus.quorumSignature.length() < Functions.minQuorum(alphaSize) + 2 * Functions.minQuorum(7)) { - SellerLogger.debug("Consensus Failed"); - sellerDetails2Buyer.put("status", "Consensus Failed"); - sellerDetails2Buyer.put("quorumsign", InitiatorConsensus.quorumSignature.toString()); - output.println(sellerDetails2Buyer); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); - output.close(); - input.close(); - sellerSocket.close(); - sellerMutex = false; - Functions.updateQuorum(quorumArray, null, false, type); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", tid); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Transaction declined by Quorum"); - return APIResponse; - } - SellerLogger.debug("Consensus Reached"); - sellerDetails2Buyer.put("status", "Consensus Reached"); - sellerDetails2Buyer.put("quorumsign", InitiatorConsensus.quorumSignature.toString()); - output.println(sellerDetails2Buyer); - SellerLogger.debug("Sent Seller/Consensus Details to Buyer"); - SellerLogger.debug("Quorum Signatures length " + InitiatorConsensus.quorumSignature.length()); - String signatureAuth = input.readLine(); - long endAuth = System.currentTimeMillis(); - long totalTime = endAuth - startTime; - if (!signatureAuth.equals("200")) { - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); - SellerLogger.info("Authentication Failed"); - output.close(); - input.close(); - sellerSocket.close(); - sellerMutex = false; - Functions.updateQuorum(quorumArray, null, false, type); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", tid); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Quorum/Seller not authenticated"); - return APIResponse; - } - IPFSNetwork.unpin(nftTokenIpfsHash, ipfs); - IPFSNetwork.repo(ipfs); - SellerLogger.debug("Unpinned NFT Token"); - output.println("Unpinned NFT"); - String rbxUnpinStatus = input.readLine(); - if (!rbxUnpinStatus.equals("Unpinned RBX")) { - SellerLogger.warn("Buyer failed to pin NFT Token"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); - SellerLogger.info("Buyer failed to pin NFT Token"); - output.close(); - input.close(); - sellerSocket.close(); - sellerMutex = false; - Functions.updateQuorum(quorumArray, null, false, type); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", tid); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Buyer failed to pin NFT Token"); - return APIResponse; - } - int count = 0; - int m; - for (m = 0; m < amount; m++) { - FileWriter fileWriter = new FileWriter(Functions.TOKENS_PATH + allRbxTokenContent.get(m)); - fileWriter.write(allRbxTokenContent.get(m)); - fileWriter.close(); - IPFSNetwork.add(Functions.TOKENS_PATH + allRbxTokenContent.get(m), ipfs); - IPFSNetwork.pin(rbxTokens.getString(m), ipfs); - count++; - } - if (count == amount) { - SellerLogger.debug("Pinned All RBX Tokens"); - for (m = 0; m < amount; m++) { - ArrayList groupTokens = new ArrayList<>(); - for (int i1 = 0; i1 < amount; i1++) { - if (!rbxTokens.getString(m).equals(rbxTokens.getString(i1))) - groupTokens.add(rbxTokens.getString(i1)); - } - JSONArray arrToken = new JSONArray(); - JSONObject objectToken = new JSONObject(); - objectToken.put("tokenHash", rbxTokens.getString(m)); - arrToken.put(objectToken); - JSONArray arr1 = new JSONArray(allRbxTokenChainContent.get(m)); - JSONObject obj2 = new JSONObject(); - obj2.put("buyerSign", buyerSign); - obj2.put("buyerDID", buyerDidIpfsHash); - obj2.put("group", groupTokens); - obj2.put("comment", comment); - obj2.put("tid", tid); - arr1.put(obj2); - Functions.writeToFile(Functions.TOKENCHAIN_PATH + allRbxTokenChainContent.get(m) + ".json", arr1.toString(), Boolean.valueOf(false)); - } - JSONObject rbxPinData = new JSONObject(); - rbxPinData.put("status", "Pinned RBX"); - rbxPinData.put("essentialShare", InitiatorProcedure.essential); - output.println(rbxPinData.toString()); - } else { - JSONObject rbxPinData = new JSONObject(); - rbxPinData.put("status", "Failed to pin RBX"); - rbxPinData.put("essentialShare", "null"); - output.println(rbxPinData.toString()); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); - output.close(); - input.close(); - sellerSocket.close(); - sellerMutex = false; - Functions.updateQuorum(quorumArray, null, false, type); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", tid); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Seller Failed to pin RBX"); - SellerLogger.info("Incomplete Transaction"); - return APIResponse; - } - String respAuth = input.readLine(); - if (!respAuth.equals("Send Response")) { - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); - output.close(); - input.close(); - sellerSocket.close(); - sellerMutex = false; - Functions.updateQuorum(quorumArray, null, false, type); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", tid); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Receiver process not over"); - SellerLogger.info("Incomplete Transaction"); - return APIResponse; - } - Iterator keys = InitiatorConsensus.quorumSignature.keys(); - JSONArray signedQuorumList = new JSONArray(); - while (keys.hasNext()) - signedQuorumList.put(keys.next()); - APIResponse.put("tid", tid); - APIResponse.put("status", "Success"); - APIResponse.put("sellerDID", sellerDidIpfsHash); - APIResponse.put("message", "NFT transferred successfully!"); - APIResponse.put("quorumlist", signedQuorumList); - APIResponse.put("buyerDID", buyerDidIpfsHash); - APIResponse.put("totaltime", totalTime); - Functions.updateQuorum(quorumArray, signedQuorumList, true, type); - JSONObject nftTransactionRecord = new JSONObject(); - nftTransactionRecord.put("role", "Seller"); - nftTransactionRecord.put("sellerDID", sellerDidIpfsHash); - nftTransactionRecord.put("buyerDID", buyerDidIpfsHash); - nftTransactionRecord.put("amount", amount); - nftTransactionRecord.put("rbxTokens", rbxTokens); - nftTransactionRecord.put("nftToken", nftTokenIpfsHash); - //nftTransactionRecord.put("eKey", eKey); - //nftTransactionRecord.put("dKey", dKey); - nftTransactionRecord.put("txn", tid); - nftTransactionRecord.put("quorumList", signedQuorumList); - nftTransactionRecord.put("Date", Functions.getCurrentUtcTime()); - nftTransactionRecord.put("totalTime", totalTime); - nftTransactionRecord.put("comment", comment); - nftTransactionRecord.put("essentialShare", InitiatorProcedure.essential); - JSONArray nftTransactionHistoryEntry = new JSONArray(); - nftTransactionHistoryEntry.put(nftTransactionRecord); - Functions.updateJSON("add", Functions.WALLET_DATA_PATH + "nftTransactionHistory.json", nftTransactionHistoryEntry.toString()); - Files.deleteIfExists(Paths.get(Functions.NFT_TOKENS_PATH + nftTokenIpfsHash, new String[0])); - for (int n = 0; n < rbxTokens.length(); n++) { - String bank = rbxTokenHeader.getString(n); - String bankFile = Functions.readFile(Functions.PAYMENTS_PATH + bank + ".json"); - JSONArray bankArray = new JSONArray(bankFile); - JSONObject tokenObject = new JSONObject(); - tokenObject.put("tokenHash", rbxTokens.getString(n)); - bankArray.put(tokenObject); - Functions.writeToFile(Functions.PAYMENTS_PATH + "TokenMap.json", bankArray.toString(), Boolean.valueOf(false)); - } - SellerLogger.info("Transaction Successful"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); - output.close(); - input.close(); - sellerSocket.close(); - sellerMutex = false; - return APIResponse; - } -} diff --git a/src/com/rubix/Resources/FractionChooser.java b/src/com/rubix/Resources/FractionChooser.java deleted file mode 100644 index 4f328c6c..00000000 --- a/src/com/rubix/Resources/FractionChooser.java +++ /dev/null @@ -1,88 +0,0 @@ -package com.rubix.Resources; - - -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import org.apache.log4j.*; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import static com.rubix.Resources.Functions.*; - -public class FractionChooser { - public static String output; - - public static JSONArray tokenHeader; - - public static Logger FractionChooserLogger = Logger.getLogger(FractionChooser.class); - - public static JSONArray calculate(int amount) { - JSONArray tokensList = new JSONArray(); - tokenHeader = new JSONArray(); - JSONObject tknmap = new JSONObject(); - try { - int index = 0; - LinkedHashMap map = new LinkedHashMap<>(); - LinkedHashMap usedmap = new LinkedHashMap<>(); - List bnk = new ArrayList<>(); - if (amount < 1) { - FractionChooserLogger.warn("Invalid Transaction Amount"); - output = "Please make a valid transaction"; - return tokensList; - } - JSONArray mapList = new JSONArray(readFile(PAYMENTS_PATH + "TokenMap.json")); - int i; - for (i = 0; i < mapList.length(); i++) { - JSONObject tempJsonObject = mapList.getJSONObject(i); - String type = tempJsonObject.getString("type"); - int valueInt = tempJsonObject.getInt("value"); - tknmap.put(String.valueOf(valueInt), type); - String lists = readFile(PAYMENTS_PATH + tempJsonObject.getString("type") + ".json"); - JSONArray tempJsonArray = new JSONArray(lists); - bnk.add(i, tempJsonArray); - int size = tempJsonArray.length(); - map.put(Integer.valueOf(valueInt), Integer.valueOf(size)); - usedmap.put(Integer.valueOf(valueInt), Integer.valueOf(0)); - } - List keyList = new ArrayList(map.keySet()); - for (i = map.size() - 1; i > 0; i--) { - if (((Integer)keyList.get(i)).intValue() <= amount) { - index = i; - break; - } - } - while (amount != 0) { - int valueInt = ((Integer)keyList.get(index)).intValue(); - if (((Integer)map.get(Integer.valueOf(valueInt))).intValue() > 0 && valueInt <= amount) { - amount -= valueInt; - int temp = ((Integer)usedmap.get(Integer.valueOf(valueInt))).intValue(); - int temp1 = ((Integer)map.get(Integer.valueOf(valueInt))).intValue(); - usedmap.put(Integer.valueOf(valueInt), Integer.valueOf(++temp)); - map.put(Integer.valueOf(valueInt), Integer.valueOf(--temp1)); - } else if (index != 0) { - index--; - } else { - FractionChooserLogger.warn("Insufficient Amount in the Wallet. Required " + amount + " currency"); - output = "Balance not sufficient, need " + amount + " more currency"; - return tokensList; - } - if (valueInt > amount && index != 0) - index--; - } - for (i = 0; i < keyList.size(); i++) { - for (int j = 0; j < ((Integer)usedmap.get(keyList.get(i))).intValue(); j++) { - tokensList.put(((JSONArray)bnk.get(i)).getJSONObject(j).getString("tokenHash")); - tokenHeader.put(tknmap.get(String.valueOf(keyList.get(i)))); - } - } - } catch (JSONException e) { - FractionChooserLogger.error("JSON Exception Occurred", (Throwable)e); - e.printStackTrace(); - } - FractionChooserLogger.debug("Tokens chosen to be sent: " + tokensList); - return tokensList; - } -} - diff --git a/src/com/rubix/Resources/Functions.java b/src/com/rubix/Resources/Functions.java index 7798a374..b542d6b3 100644 --- a/src/com/rubix/Resources/Functions.java +++ b/src/com/rubix/Resources/Functions.java @@ -1,24 +1,22 @@ package com.rubix.Resources; -import static com.rubix.Resources.APIHandler.addPublicData; -import static com.rubix.Resources.IPFSNetwork.IPFSNetworkLogger; -import static com.rubix.Resources.IPFSNetwork.checkSwarmConnect; -import static com.rubix.Resources.IPFSNetwork.executeIPFSCommands; -import static com.rubix.Resources.IPFSNetwork.forwardCheck; -import static com.rubix.Resources.IPFSNetwork.listen; -import static com.rubix.Resources.IPFSNetwork.swarmConnectP2P; -import static com.rubix.Resources.IPFSNetwork.swarmConnectProcess; +import com.rubix.AuthenticateNode.PropImage; +import com.rubix.Ping.PingCheck; +import io.ipfs.api.IPFS; +import io.ipfs.multiaddr.MultiAddress; +import org.apache.log4j.Logger; +import org.apache.log4j.PropertyConfigurator; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import javax.imageio.ImageIO; import java.awt.image.BufferedImage; -import java.io.BufferedReader; -import java.io.DataOutputStream; -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStreamReader; +import java.io.*; import java.math.RoundingMode; import java.net.HttpURLConnection; +import java.net.Socket; +import java.net.SocketException; import java.net.URL; import java.nio.charset.StandardCharsets; import java.nio.file.Files; @@ -31,21 +29,10 @@ import java.util.ArrayList; import java.util.Date; import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.Set; - -import javax.imageio.ImageIO; - -import com.rubix.AuthenticateNode.PropImage; -import com.rubix.Ping.PingCheck; -import org.apache.log4j.PropertyConfigurator; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; +import static com.rubix.Resources.APIHandler.addPublicData; +import static com.rubix.Resources.IPFSNetwork.*; -import io.ipfs.api.IPFS; -import io.ipfs.multiaddr.MultiAddress; public class Functions { @@ -56,8 +43,7 @@ public class Functions { public static String LOGGER_PATH = ""; public static String WALLET_DATA_PATH = ""; public static String PAYMENTS_PATH = ""; - public static int RECEIVER_PORT, GOSSIP_SENDER, GOSSIP_RECEIVER, QUORUM_PORT, SENDER2Q1, SENDER2Q2, SENDER2Q3, - SENDER2Q4, SENDER2Q5, SENDER2Q6, SENDER2Q7; + public static int RECEIVER_PORT, GOSSIP_SENDER, GOSSIP_RECEIVER, QUORUM_PORT, SENDER2Q1, SENDER2Q2, SENDER2Q3, SENDER2Q4, SENDER2Q5, SENDER2Q6, SENDER2Q7; public static int QUORUM_COUNT; public static int SEND_PORT; public static int IPFS_PORT; @@ -136,11 +122,13 @@ public static void pathSet() { BOOTSTRAPS = pathsArray.getJSONArray(5); + } catch (JSONException e) { e.printStackTrace(); } } + public static void nodeData(String did, String wid, IPFS ipfs) throws IOException { PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); File dataFolder = new File(DATA_PATH + did + "/"); @@ -214,9 +202,9 @@ public static String getSystemUser() { return lineID; } + /** - * This method calculates different types of hashes as mentioned in the passed - * parameters for the mentioned message + * This method calculates different types of hashes as mentioned in the passed parameters for the mentioned message * * @param message Input string to be hashed * @param algorithm Specification of the algorithm used for hashing @@ -283,13 +271,13 @@ public static String bytesToHex(byte[] inputHash) { StringBuilder outputHexString = new StringBuilder(); for (byte b : inputHash) { String hex = Integer.toHexString(0xff & b); - if (hex.length() == 1) - outputHexString.append('0'); + if (hex.length() == 1) outputHexString.append('0'); outputHexString.append(hex); } return outputHexString.toString(); } + /** * This method returns the content of the file passed to it * @@ -311,15 +299,14 @@ public static String readFile(String filePath) { return fileContent.toString(); } + /** * This method writes the mentioned data into the file passed to it - * This also allows to take a decision on whether or not to append the data to - * the already existing content in the file + * This also allows to take a decision on whether or not to append the data to the already existing content in the file * * @param filePath Location of the file to be read and written into * @param data Data to be added - * @param appendStatus Decides whether or not to append the new data into the - * already existing data + * @param appendStatus Decides whether or not to append the new data into the already existing data */ public synchronized static void writeToFile(String filePath, String data, Boolean appendStatus) { @@ -360,6 +347,7 @@ public static String getSignFromShares(String filePath, String hash) throws IOEx return p1; } + /** * This function will sign on JSON data with private share * @@ -404,6 +392,7 @@ public static void listenThread(JSONObject connectObject) { } + /** * This function converts any integer to its binary form * @@ -490,8 +479,7 @@ public static void updateJSON(String operation, String filePath, String data) { } /** - * This method gets you a required data from a JSON file with a tag to be - * compared with + * This method gets you a required data from a JSON file with a tag to be compared with * * @param filePath Location of the JSON file * @param get Data to be fetched from the file @@ -528,8 +516,7 @@ public static String getOsName() { } /** - * This function calculates the minimum number of quorum peers required for - * consensus to work + * This function calculates the minimum number of quorum peers required for consensus to work * * @return Minimum number of quorum count for consensus to work */ @@ -538,8 +525,7 @@ public static int minQuorum() { } /** - * This function calculates the minimum number of quorum peers required for - * consensus to work + * This function calculates the minimum number of quorum peers required for consensus to work * * @return Minimum number of quorum count for consensus to work */ @@ -547,6 +533,7 @@ public static int minQuorum(int count) { return (((count - 1) / 3) * 2) + 1; } + /** * This method checks if Quorum is available for consensus * @@ -585,6 +572,7 @@ public static ArrayList QuorumCheck(JSONArray quorum, int size) { * @param ipfs ipfs instance */ + public static void QuorumSwarmConnect(JSONArray quorum, IPFS ipfs) { PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); @@ -603,6 +591,7 @@ public static void QuorumSwarmConnect(JSONArray quorum, IPFS ipfs) { } + /** * This method identifies the Peer ID of the system by IPFS during installation * @@ -610,6 +599,7 @@ public static void QuorumSwarmConnect(JSONArray quorum, IPFS ipfs) { * @return Your system's Peer ID assigned by IPFS */ + public static String getPeerID(String filePath) { PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); JSONArray fileContentArray; @@ -627,6 +617,7 @@ public static String getPeerID(String filePath) { return peerid; } + public static int[] getPrivatePosition(int[] positions, int[] privateArray) { int[] PrivatePosition = new int[positions.length]; for (int k = 0; k < positions.length; k++) { @@ -637,8 +628,7 @@ public static int[] getPrivatePosition(int[] positions, int[] privateArray) { return PrivatePosition; } - public static JSONObject randomPositions(String role, String hash, int numberOfPositions, int[] pvt1) - throws JSONException { + public static JSONObject randomPositions(String role, String hash, int numberOfPositions, int[] pvt1) throws JSONException { int u = 0, l = 0, m = 0; int[] hashCharacters = new int[256]; @@ -695,19 +685,18 @@ public static JSONObject randomPositions(String role, String hash, int numberOfP * @param positionsCount Number of positions required * @return Extended array of positions */ - // public static int[] finalPositions(int[] randomPositions, int positionsCount) - // { - // int[] finalPositions = new int[positionsCount * 64]; - // int u = 0; - // for (int k = 0; k < positionsCount; k++) { - // for (int p = 0; p < 64; p++) { - // finalPositions[u] = randomPositions[k]; - // randomPositions[k]++; - // u++; - // } - // } - // return finalPositions; - // } +// public static int[] finalPositions(int[] randomPositions, int positionsCount) { +// int[] finalPositions = new int[positionsCount * 64]; +// int u = 0; +// for (int k = 0; k < positionsCount; k++) { +// for (int p = 0; p < 64; p++) { +// finalPositions[u] = randomPositions[k]; +// randomPositions[k]++; +// u++; +// } +// } +// return finalPositions; +// } /** * This function deletes the mentioned file @@ -725,43 +714,41 @@ public static void deleteFile(String fileName) { } - // /** - // * This functions picks the required number of quorum members from the - // mentioned file - // * - // * @param filePath Location of the file - // * @param hash Data from which positions are chosen - // * @return List of chosen members from the file - // */ - // public static ArrayList quorumChooser(String filePath, String hash) { - // PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); - // ArrayList quorumList = new ArrayList(); - // try { - // String fileContent = readFile(filePath); - // JSONArray blockHeight = new JSONArray(fileContent); - // - // int[] hashCharacters = new int[256]; - // var randomPositions = new ArrayList(); - // HashSet positionSet = new HashSet<>(); - // for (int k = 0; positionSet.size() != 7; k++) { - // hashCharacters[k] = Character.getNumericValue(hash.charAt(k)); - // randomPositions.add((((2402 + hashCharacters[k]) * 2709) + ((k + 2709) + - // hashCharacters[(k)])) % blockHeight.length()); - // positionSet.add(randomPositions.get(k)); - // } - // - // for (Integer integer : positionSet) - // quorumList.add(blockHeight.getJSONObject(integer).getString("peer-id")); - // } catch (JSONException e) { - // FunctionsLogger.error("JSON Exception Occurred", e); - // e.printStackTrace(); - // } - // return quorumList; - // } + +// /** +// * This functions picks the required number of quorum members from the mentioned file +// * +// * @param filePath Location of the file +// * @param hash Data from which positions are chosen +// * @return List of chosen members from the file +// */ +// public static ArrayList quorumChooser(String filePath, String hash) { +// PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); +// ArrayList quorumList = new ArrayList(); +// try { +// String fileContent = readFile(filePath); +// JSONArray blockHeight = new JSONArray(fileContent); +// +// int[] hashCharacters = new int[256]; +// var randomPositions = new ArrayList(); +// HashSet positionSet = new HashSet<>(); +// for (int k = 0; positionSet.size() != 7; k++) { +// hashCharacters[k] = Character.getNumericValue(hash.charAt(k)); +// randomPositions.add((((2402 + hashCharacters[k]) * 2709) + ((k + 2709) + hashCharacters[(k)])) % blockHeight.length()); +// positionSet.add(randomPositions.get(k)); +// } +// +// for (Integer integer : positionSet) +// quorumList.add(blockHeight.getJSONObject(integer).getString("peer-id")); +// } catch (JSONException e) { +// FunctionsLogger.error("JSON Exception Occurred", e); +// e.printStackTrace(); +// } +// return quorumList; +// } /** - * This function is to be initially called to setup the environment of your - * project + * This function is to be initially called to setup the environment of your project */ public static void launch() { pathSet(); @@ -807,8 +794,7 @@ public static String checkDirectory() throws JSONException { File tokenChainsFolder = new File(TOKENCHAIN_PATH); File walletDataFolder = new File(WALLET_DATA_PATH); - if (!dataFolder.exists() || !loggerFolder.exists() || !tokenChainsFolder.exists() || !tokensFolder.exists() - || !walletDataFolder.exists()) { + if (!dataFolder.exists() || !loggerFolder.exists() || !tokenChainsFolder.exists() || !tokensFolder.exists() || !walletDataFolder.exists()) { dataFolder.delete(); loggerFolder.delete(); tokenChainsFolder.delete(); @@ -885,6 +871,7 @@ public static String mineToken(int level, int tokenNumber) { return token; } + public static String toBinary(int x, int len) { if (len > 0) { return String.format("%" + len + "s", @@ -921,6 +908,7 @@ public static Date getCurrentUtcTime() throws ParseException { return localDateFormat.parse(simpleDateFormat.format(new Date())); } + /** * This method is used to update quorum credits in server * @@ -931,8 +919,8 @@ public static Date getCurrentUtcTime() throws ParseException { * @return mined token */ - public static void updateQuorum(JSONArray quorumArray, JSONArray signedQuorumList, boolean status, int type) - throws IOException, JSONException { + + public static void updateQuorum(JSONArray quorumArray, JSONArray signedQuorumList, boolean status, int type) throws IOException, JSONException { if (type == 1) { String urlQuorumUpdate = ADVISORY_IP + "/updateQuorum"; @@ -974,6 +962,7 @@ public static void updateQuorum(JSONArray quorumArray, JSONArray signedQuorumLis } } + /** * This method is used get getquorum from advisory node * @@ -985,8 +974,8 @@ public static void updateQuorum(JSONArray quorumArray, JSONArray signedQuorumLis * @return JSONArray of quorum nodes */ - public static JSONArray getQuorum(String betaHash, String gammaHash, String senderDidIpfsHash, - String receiverDidIpfsHash, int tokenslength) throws IOException, JSONException { + + public static JSONArray getQuorum(String betaHash, String gammaHash, String senderDidIpfsHash, String receiverDidIpfsHash, int tokenslength) throws IOException, JSONException { JSONArray quorumArray; String urlQuorumPick = ADVISORY_IP + "/getQuorum"; URL objQuorumPick = new URL(urlQuorumPick); @@ -1204,11 +1193,9 @@ public static Double getPartsBalance() throws JSONException { Double availableParts = 0.000D, senderCount = 0.000D, receiverCount = 0.000D; for (int k = 0; k < tokenChainArray.length(); k++) { if (tokenChainArray.getJSONObject(k).has("role")) { - if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") - && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { + if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { senderCount += tokenChainArray.getJSONObject(k).getDouble("amount"); - } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") - && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { + } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { receiverCount += tokenChainArray.getJSONObject(k).getDouble("amount"); } } @@ -1221,6 +1208,7 @@ public static Double getPartsBalance() throws JSONException { parts = formatAmount(parts); balance = balance + parts; + int count = 0; File shiftedFile = new File(PAYMENTS_PATH.concat("ShiftedTokens.json")); if (shiftedFile.exists()) { @@ -1230,6 +1218,7 @@ public static Double getPartsBalance() throws JSONException { for (int i = 0; i < shiftedArray.length(); i++) arrayTokens.add(shiftedArray.getString(i)); + for (int i = 0; i < partTokensArray.length(); i++) { if (!arrayTokens.contains(partTokensArray.getJSONObject(i).getString("tokenHash"))) count++; @@ -1257,11 +1246,9 @@ public static Double checkTokenPartBalance(String tokenHash) throws JSONExceptio Double senderCount = 0.000D, receiverCount = 0.000D; for (int k = 0; k < tokenChainArray.length(); k++) { if (tokenChainArray.getJSONObject(k).has("role")) { - if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") - && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { + if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { senderCount += tokenChainArray.getJSONObject(k).getDouble("amount"); - } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") - && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { + } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { receiverCount += tokenChainArray.getJSONObject(k).getDouble("amount"); } } @@ -1278,6 +1265,7 @@ public static Double checkTokenPartBalance(String tokenHash) throws JSONExceptio return availableParts; } + public static Double getBalance() throws JSONException { pathSet(); Double balance = 0.000D; @@ -1296,6 +1284,7 @@ public static Double getBalance() throws JSONException { balance = balance + value; } + File partsFile = new File(PAYMENTS_PATH + "PartsToken.json"); if (partsFile.exists()) { String PART_TOKEN_CHAIN_PATH = TOKENCHAIN_PATH.concat("/PARTS/"); @@ -1314,11 +1303,9 @@ public static Double getBalance() throws JSONException { Double availableParts = 0.000D, senderCount = 0.000D, receiverCount = 0.000D; for (int k = 0; k < tokenChainArray.length(); k++) { if (tokenChainArray.getJSONObject(k).has("role")) { - if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") - && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { + if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { senderCount += tokenChainArray.getJSONObject(k).getDouble("amount"); - } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") - && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { + } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { receiverCount += tokenChainArray.getJSONObject(k).getDouble("amount"); } } @@ -1341,6 +1328,7 @@ public static Double getBalance() throws JSONException { for (int i = 0; i < shiftedArray.length(); i++) arrayTokens.add(shiftedArray.getString(i)); + for (int i = 0; i < partTokensArray.length(); i++) { if (!arrayTokens.contains(partTokensArray.getJSONObject(i).getString("tokenHash"))) count++; @@ -1351,10 +1339,12 @@ public static Double getBalance() throws JSONException { balance = balance - count; } + balance = formatAmount(balance); return balance; } + public static Double partTokenBalance(String tokenHash) throws JSONException { pathSet(); @@ -1368,11 +1358,9 @@ public static Double partTokenBalance(String tokenHash) throws JSONException { Double senderCount = 0.000D, receiverCount = 0.000D; for (int k = 0; k < tokenChainArray.length(); k++) { if (tokenChainArray.getJSONObject(k).has("role")) { - if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") - && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { + if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { senderCount += tokenChainArray.getJSONObject(k).getDouble("amount"); - } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") - && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { + } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { receiverCount += tokenChainArray.getJSONObject(k).getDouble("amount"); } } @@ -1405,8 +1393,7 @@ public static void clearParts() { String partsFile = readFile(PAYMENTS_PATH.concat("PartsToken.json")); JSONArray partsArray = new JSONArray(partsFile); for (int i = 0; i < partsArray.length(); i++) { - if (partTokenBalance(partsArray.getJSONObject(i).getString("tokenHash")) <= 0.000 - || partTokenBalance(partsArray.getJSONObject(i).getString("tokenHash")) > 1.000) { + if (partTokenBalance(partsArray.getJSONObject(i).getString("tokenHash")) <= 0.000 || partTokenBalance(partsArray.getJSONObject(i).getString("tokenHash")) > 1.000) { deleteFile(TOKENS_PATH.concat("PARTS/").concat(partsArray.getJSONObject(i).getString("tokenHash"))); partsArray.remove(i); } @@ -1433,9 +1420,7 @@ public static void backgroundChecks() { addPublicData(); } - public static String sanityMessage; - public static boolean sanityCheck(String peerid, IPFS ipfs, int port) throws IOException { FunctionsLogger.info("Entering SanityCheck"); boolean sanityCheckErrorFlag = true; @@ -1484,9 +1469,9 @@ public static boolean sanityCheck(String peerid, IPFS ipfs, int port) throws IOE } } + return sanityCheckErrorFlag; } - public static boolean checkIPFSStatus(String peerid, IPFS ipfs) { FunctionsLogger.info("Entering checkIPFSStatus"); boolean swarmConnectedStatus = false; @@ -1494,7 +1479,7 @@ public static boolean checkIPFSStatus(String peerid, IPFS ipfs) { MultiAddress multiAddress = new MultiAddress("/ipfs/" + peerid); FunctionsLogger.info("MultiAdrress concated " + multiAddress + "|||"); boolean output = swarmConnectP2P(peerid, ipfs); - + FunctionsLogger.info("Swarm connect process response is " + output); if (output) { swarmConnectedStatus = true; FunctionsLogger.debug("Swarm is already connected"); @@ -1510,6 +1495,7 @@ public static boolean checkIPFSStatus(String peerid, IPFS ipfs) { return swarmConnectedStatus; } + public static boolean ping(String peerid, int port) throws IOException { JSONObject pingCheck = PingCheck.Ping(peerid, port); if (pingCheck.getString("status").contains("Failed")) { @@ -1519,50 +1505,48 @@ public static boolean ping(String peerid, int port) throws IOException { } - // public static String getPing(int port) { - // try { - // - // String didContent = readFile(DATA_PATH + "DID.json"); - // JSONArray didArray = new JSONArray(didContent); - // String myPeerID = didArray.getJSONObject(0).getString("peerid"); - // - // listen(myPeerID.concat("Ping"), port); - // ServerSocket ss = new ServerSocket(port); - // FunctionsLogger.info("Get Ping Listening on port " + port + " appname " + - // myPeerID.concat("Ping")); - // Socket socket = ss.accept(); - // BufferedReader input = new BufferedReader(new - // InputStreamReader(socket.getInputStream())); - // PrintStream output = new PrintStream(socket.getOutputStream()); - // FunctionsLogger.info("getPing- waiting response from server"); - // String peerID = input.readLine(); - // if (peerID != null && peerID.contains("Qm")) { - // FunctionsLogger.info("getPing - Received message from server"); - // output.println("Ping received"); - // FunctionsLogger.debug("Ping received from sender"); - // - // output.close(); - // input.close(); - // socket.close(); - // ss.close(); - // executeIPFSCommands(" ipfs p2p close -t /p2p/" + peerID); - // FunctionsLogger.info("If - Closing Sockets"); - // return "Ping received from sender and Pong sent"; - // } - // else{ - // output.close(); - // input.close(); - // socket.close(); - // ss.close(); - // FunctionsLogger.info("Else - Closing Sockets"); - // return "Ping received from sender but not PeerID"; - // } - // - // } catch (Exception e) { - // FunctionsLogger.error("Error in client side communication", e); - // return "Error in client side communication"; - // } - // } +// public static String getPing(int port) { +// try { +// +// String didContent = readFile(DATA_PATH + "DID.json"); +// JSONArray didArray = new JSONArray(didContent); +// String myPeerID = didArray.getJSONObject(0).getString("peerid"); +// +// listen(myPeerID.concat("Ping"), port); +// ServerSocket ss = new ServerSocket(port); +// FunctionsLogger.info("Get Ping Listening on port " + port + " appname " + myPeerID.concat("Ping")); +// Socket socket = ss.accept(); +// BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream())); +// PrintStream output = new PrintStream(socket.getOutputStream()); +// FunctionsLogger.info("getPing- waiting response from server"); +// String peerID = input.readLine(); +// if (peerID != null && peerID.contains("Qm")) { +// FunctionsLogger.info("getPing - Received message from server"); +// output.println("Ping received"); +// FunctionsLogger.debug("Ping received from sender"); +// +// output.close(); +// input.close(); +// socket.close(); +// ss.close(); +// executeIPFSCommands(" ipfs p2p close -t /p2p/" + peerID); +// FunctionsLogger.info("If - Closing Sockets"); +// return "Ping received from sender and Pong sent"; +// } +// else{ +// output.close(); +// input.close(); +// socket.close(); +// ss.close(); +// FunctionsLogger.info("Else - Closing Sockets"); +// return "Ping received from sender but not PeerID"; +// } +// +// } catch (Exception e) { +// FunctionsLogger.error("Error in client side communication", e); +// return "Error in client side communication"; +// } +// } public static boolean bootstrapConnect(String peerid, IPFS ipfs) { FunctionsLogger.info("bootstrapConnect- entering function"); @@ -1636,8 +1620,7 @@ public static boolean portCheckAndKill(int port) { } /** - * This function will release the port in linux based machines if the port is - * already in use + * This function will release the port in linux based machines if the port is already in use */ public static boolean releasePorts(int port) { FunctionsLogger.info("releasePorts- "); @@ -1658,8 +1641,7 @@ public static boolean releasePorts(int port) { if (processStr != null) { FunctionsLogger.info("releasePorts- Processstr is not null"); if (String.valueOf(currentPid) != processStr && ipfsPidBr.readLine() != processStr) { - FunctionsLogger.info("releasePorts- jar is running on " + currentPid + " and IPFS is occupied in " - + ipfsPidBr.readLine()); + FunctionsLogger.info("releasePorts- jar is running on " + currentPid + " and IPFS is occupied in " + ipfsPidBr.readLine()); FunctionsLogger.debug("Port " + port + " is in using, killing PID " + processStr); processId = Runtime.getRuntime().exec("kill -9 " + processStr); FunctionsLogger.info("releasePorts- killing " + processStr); @@ -1682,50 +1664,36 @@ public static boolean releasePorts(int port) { public static boolean portStatusWindows(int port) { FunctionsLogger.info("Starting portStatusWindows"); boolean releasedPort = false; - String portProcessStr; + String processStr; Process p; - ArrayList pidTree = new ArrayList(); - ArrayList portPidTree = new ArrayList(); try { Runtime rt = Runtime.getRuntime(); - Process getJarPid = rt.exec("cmd /c netstat -ano | findstr 1898"); - BufferedReader getJarPidBR = new BufferedReader(new InputStreamReader(getJarPid.getInputStream())); - String getJarPidline; - while ((getJarPidline = getJarPidBR.readLine()) != null) { - String[] getJarPidTree = getJarPidline.split("\\s+"); - int temp = Integer.parseInt(getJarPidTree[getJarPidTree.length - 1]); - pidTree.add(temp); - } - - FunctionsLogger.info("PIDs occupied by Rubix.jar are " + pidTree); - - Set pidSet = new LinkedHashSet(pidTree); - FunctionsLogger.info("Pid occupied by port 1898 is pidSet" + pidSet); - Process getPortPid = rt.exec("cmd /c netstat -ano | findstr " + port); - BufferedReader getPortPidBr = new BufferedReader(new InputStreamReader(getPortPid.getInputStream())); - String getPortPidLine; - while ((getPortPidLine = getPortPidBr.readLine()) != null) { - String[] getPortPidTree = getPortPidLine.split("\\s+"); - int temp = Integer.parseInt(getPortPidTree[getPortPidTree.length - 1]); - portPidTree.add(temp); - } - - Set pidToKill = new LinkedHashSet(portPidTree); - FunctionsLogger.info("Pid used by port " + port + "is " + pidToKill); - pidToKill.removeAll(pidSet); - pidToKill.remove(0); - FunctionsLogger.info("Pid using port " + port + " but not in 1898" + pidToKill); - if (pidToKill.size() > 0) { - System.out.println("Port " + port + " is occupied by PIDs" + pidToKill); + Process proc = rt.exec("cmd /c netstat -ano | findstr " + port); + FunctionsLogger.info("Checking port status"); + long currentPid = ProcessHandle.current().pid(); + BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream())); + processStr = stdInput.readLine(); + FunctionsLogger.info("Process id found for port is " + processStr + " current jar pid is " + currentPid); + if (processStr != null && String.valueOf(currentPid) != processStr) { + int index = processStr.lastIndexOf(" "); + String sc = processStr.substring(index, processStr.length()); + //System.out.println("Port "+port+" is locked by PID "+sc+". Kindly close this port and retry transcation"); + if (sc != String.valueOf(currentPid)) { + FunctionsLogger.debug("Port " + port + " is locked by PID " + sc); + } else { + FunctionsLogger.debug("Port " + port + " is locked by current jar with PID " + sc); + } } else { releasedPort = true; + FunctionsLogger.info("Port is unlocked"); } - } catch (Exception e) { FunctionsLogger.error("Exception occured at portStatusWindows", e); + e.printStackTrace(); } return releasedPort; - } + } + diff --git a/src/com/rubix/Resources/IPFSNetwork.java b/src/com/rubix/Resources/IPFSNetwork.java index 728d6c2c..8de18094 100644 --- a/src/com/rubix/Resources/IPFSNetwork.java +++ b/src/com/rubix/Resources/IPFSNetwork.java @@ -569,23 +569,21 @@ public static boolean swarmConnectP2P(String peerid, IPFS ipfs) throws JSONExcep output = swarmConnectProcess(multiAddress); if (!output.contains("success")) { IPFSNetworkLogger.debug("swarm attempt failed with " + peerid); - swarmConnected = false; } else { IPFSNetworkLogger.debug("swarm Connected : " + peerid); swarmConnected = true; } } else { IPFSNetworkLogger.debug("bootstrap connection failed! " + bootNode); - swarmConnected = false; } } } - }else { - swarmConnected = true; } - return swarmConnected; - + if(output.contains("success")) + return true; + else + return false; } } diff --git a/src/com/rubix/TokenTransfer/TokenReceiver.java b/src/com/rubix/TokenTransfer/TokenReceiver.java index 8f22637e..0b02049c 100644 --- a/src/com/rubix/TokenTransfer/TokenReceiver.java +++ b/src/com/rubix/TokenTransfer/TokenReceiver.java @@ -1,61 +1,28 @@ package com.rubix.TokenTransfer; -import static com.rubix.Resources.Functions.DATA_PATH; -import static com.rubix.Resources.Functions.FunctionsLogger; -import static com.rubix.Resources.Functions.IPFS_PORT; -import static com.rubix.Resources.Functions.LOGGER_PATH; -import static com.rubix.Resources.Functions.PAYMENTS_PATH; -import static com.rubix.Resources.Functions.RECEIVER_PORT; -import static com.rubix.Resources.Functions.TOKENCHAIN_PATH; -import static com.rubix.Resources.Functions.TOKENS_PATH; -import static com.rubix.Resources.Functions.WALLET_DATA_PATH; -import static com.rubix.Resources.Functions.calculateHash; -import static com.rubix.Resources.Functions.deleteFile; -import static com.rubix.Resources.Functions.formatAmount; -import static com.rubix.Resources.Functions.getCurrentUtcTime; -import static com.rubix.Resources.Functions.getPeerID; -import static com.rubix.Resources.Functions.getValues; -import static com.rubix.Resources.Functions.nodeData; -import static com.rubix.Resources.Functions.pathSet; -import static com.rubix.Resources.Functions.readFile; -import static com.rubix.Resources.Functions.syncDataTable; -import static com.rubix.Resources.Functions.updateJSON; -import static com.rubix.Resources.Functions.writeToFile; -import static com.rubix.Resources.IPFSNetwork.add; -import static com.rubix.Resources.IPFSNetwork.executeIPFSCommands; -import static com.rubix.Resources.IPFSNetwork.get; -import static com.rubix.Resources.IPFSNetwork.listen; -import static com.rubix.Resources.IPFSNetwork.pin; -import static com.rubix.Resources.IPFSNetwork.repo; -import static com.rubix.Resources.IPFSNetwork.swarmConnectP2P; - -import java.awt.image.BufferedImage; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.PrintStream; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.SocketException; -import java.util.ArrayList; -import java.util.Iterator; - -import javax.imageio.ImageIO; - import com.rubix.AuthenticateNode.Authenticate; import com.rubix.AuthenticateNode.PropImage; import com.rubix.Resources.Functions; import com.rubix.Resources.IPFSNetwork; - +import io.ipfs.api.IPFS; import org.apache.log4j.Logger; import org.apache.log4j.PropertyConfigurator; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; -import io.ipfs.api.IPFS; +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.*; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketException; +import java.util.ArrayList; +import java.util.Iterator; + +import static com.rubix.Resources.Functions.*; +import static com.rubix.Resources.IPFSNetwork.*; + public class TokenReceiver { public static Logger TokenReceiverLogger = Logger.getLogger(TokenReceiver.class); @@ -150,6 +117,7 @@ public static String receive() { return APIResponse.toString(); } + nodeData(senderDidIpfsHash, senderWidIpfsHash, ipfs); File senderDIDFile = new File(DATA_PATH + senderDidIpfsHash + "/DID.png"); if (!senderDIDFile.exists()) { @@ -159,7 +127,7 @@ public static String receive() { APIResponse.put("status", "Failed"); APIResponse.put("message", "Sender details not available"); TokenReceiverLogger.info("Sender details not available"); - /* executeIPFSCommands(" ipfs p2p close -t /p2p/" + senderPeerID); */ + /* executeIPFSCommands(" ipfs p2p close -t /p2p/" + senderPeerID);*/ output.close(); input.close(); @@ -201,9 +169,9 @@ public static String receive() { JSONObject amountLedger = tokenObject.getJSONObject("amountLedger"); TokenReceiverLogger.debug("Amount Ledger: " + amountLedger); int intPart = wholeTokens.length(); - Double decimalPart = formatAmount(amount - intPart); + Double decimalPart = formatAmount(amount-intPart); JSONArray doubleSpentToken = new JSONArray(); - boolean tokenOwners = true; + /*boolean tokenOwners = true; ArrayList ownersArray = new ArrayList(); ArrayList previousSender = new ArrayList(); JSONArray ownersReceived = new JSONArray(); @@ -215,8 +183,7 @@ public static String receive() { if (ownersArray.size() > 2) { for (int j = 0; j < previousSendersArray.length(); j++) { - if (previousSendersArray.getJSONObject(j).getString("token") - .equals(wholeTokens.getString(i))) + if (previousSendersArray.getJSONObject(j).getString("token").equals(wholeTokens.getString(i))) ownersReceived = previousSendersArray.getJSONObject(j).getJSONArray("sender"); } @@ -254,7 +221,7 @@ public static String receive() { sk.close(); ss.close(); return APIResponse.toString(); - } + }*/ String senderToken = TokenDetails.toString(); String consensusID = calculateHash(senderToken, "SHA3-256"); @@ -262,7 +229,7 @@ public static String receive() { String consensusIDIPFSHash = IPFSNetwork.addHashOnly(LOGGER_PATH + "consensusID", ipfs); deleteFile(LOGGER_PATH + "consensusID"); - if (!IPFSNetwork.dhtEmpty(consensusIDIPFSHash, ipfs)) { + /*if (!IPFSNetwork.dhtEmpty(consensusIDIPFSHash, ipfs)) { TokenReceiverLogger.debug("consensus ID not unique" + consensusIDIPFSHash); output.println("421"); APIResponse.put("did", senderDidIpfsHash); @@ -275,9 +242,9 @@ public static String receive() { sk.close(); ss.close(); return APIResponse.toString(); - } + }*/ - // Check IPFS get for all Tokens + //Check IPFS get for all Tokens int ipfsGetFlag = 0; ArrayList allTokenContent = new ArrayList<>(); ArrayList allTokenChainContent = new ArrayList<>(); @@ -316,7 +283,7 @@ public static String receive() { } boolean chainFlag = true; - for (int i = 0; i < partTokenChainContent.length(); i++) { + for(int i = 0; i < partTokenChainContent.length(); i++) { JSONArray tokenChainContent = partTokenChainContent.getJSONArray(i); for (int j = 0; j < tokenChainContent.length(); j++) { String previousHash = tokenChainContent.getJSONObject(j).getString("previousHash"); @@ -326,17 +293,14 @@ public static String receive() { if (j == 0) { rePreviousHash = ""; String rePrev = calculateHash(new JSONObject().toString(), "SHA3-256"); - reNextHash = calculateHash(tokenChainContent.getJSONObject(j + 1).getString("tid"), - "SHA3-256"); + reNextHash = calculateHash(tokenChainContent.getJSONObject(j + 1).getString("tid"), "SHA3-256"); - if (!((rePreviousHash.equals(previousHash) || rePrev.equals(previousHash)) - && reNextHash.equals(nextHash))) { + if (!((rePreviousHash.equals(previousHash) || rePrev.equals(previousHash)) && reNextHash.equals(nextHash))) { chainFlag = false; } } else if (j == tokenChainContent.length() - 1) { - rePreviousHash = calculateHash(tokenChainContent.getJSONObject(j - 1).getString("tid"), - "SHA3-256"); + rePreviousHash = calculateHash(tokenChainContent.getJSONObject(j - 1).getString("tid"), "SHA3-256"); reNextHash = ""; if (!(rePreviousHash.equals(previousHash) && reNextHash.equals(nextHash))) { @@ -344,10 +308,8 @@ public static String receive() { } } else { - rePreviousHash = calculateHash(tokenChainContent.getJSONObject(j - 1).getString("tid"), - "SHA3-256"); - reNextHash = calculateHash(tokenChainContent.getJSONObject(j + 1).getString("tid"), - "SHA3-256"); + rePreviousHash = calculateHash(tokenChainContent.getJSONObject(j - 1).getString("tid"), "SHA3-256"); + reNextHash = calculateHash(tokenChainContent.getJSONObject(j + 1).getString("tid"), "SHA3-256"); if (!(rePreviousHash.equals(previousHash) && reNextHash.equals(nextHash))) { chainFlag = false; @@ -374,16 +336,14 @@ public static String receive() { } boolean partsAvailable = true; - for (int i = 0; i < partTokenChainContent.length(); i++) { + for(int i = 0; i < partTokenChainContent.length(); i++){ Double senderCount = 0.000D, receiverCount = 0.000D; JSONArray tokenChainContent = partTokenChainContent.getJSONArray(i); for (int k = 0; k < tokenChainContent.length(); k++) { if (tokenChainContent.getJSONObject(k).has("role")) { - if (tokenChainContent.getJSONObject(k).getString("role").equals("Sender") - && tokenChainContent.getJSONObject(k).getString("sender").equals(senderDidIpfsHash)) { + if (tokenChainContent.getJSONObject(k).getString("role").equals("Sender") && tokenChainContent.getJSONObject(k).getString("sender").equals(senderDidIpfsHash)) { senderCount += tokenChainContent.getJSONObject(k).getDouble("amount"); - } else if (tokenChainContent.getJSONObject(k).getString("role").equals("Receiver") - && tokenChainContent.getJSONObject(k).getString("receiver").equals(senderDidIpfsHash)) { + } else if (tokenChainContent.getJSONObject(k).getString("role").equals("Receiver") && tokenChainContent.getJSONObject(k).getString("receiver").equals(senderDidIpfsHash)) { receiverCount += tokenChainContent.getJSONObject(k).getDouble("amount"); } } @@ -396,13 +356,13 @@ public static String receive() { availableParts += amountLedger.getDouble(partTokens.getString(i)); availableParts = formatAmount(availableParts); - if (availableParts > 1.000D) { + if(availableParts > 1.000D) { TokenReceiverLogger.debug("Token wholly spent: " + partTokens.getString(i)); TokenReceiverLogger.debug("Parts: " + availableParts); } } - if (!partsAvailable) { + if (!partsAvailable) { String errorMessage = "Token wholly spent already"; output.println("424"); APIResponse.put("did", senderDidIpfsHash); @@ -416,9 +376,10 @@ public static String receive() { sk.close(); ss.close(); return APIResponse.toString(); - } else + }else output.println("200"); + String senderDetails; try { senderDetails = input.readLine(); @@ -446,6 +407,7 @@ public static String receive() { BufferedImage senderWidImage = ImageIO.read(new File(DATA_PATH + senderDidIpfsHash + "/PublicShare.png")); SenWalletBin = PropImage.img2bin(senderWidImage); + TokenReceiverLogger.debug("Verifying Quorum ... "); TokenReceiverLogger.debug("Please wait, this might take a few seconds"); @@ -464,8 +426,7 @@ public static String receive() { for (String quorumDidIpfsHash : quorumDID) { syncDataTable(quorumDidIpfsHash, null); - String quorumWidIpfsHash = getValues(DATA_PATH + "DataTable.json", "walletHash", "didHash", - quorumDidIpfsHash); + String quorumWidIpfsHash = getValues(DATA_PATH + "DataTable.json", "walletHash", "didHash", quorumDidIpfsHash); nodeData(quorumDidIpfsHash, quorumWidIpfsHash, ipfs); } @@ -487,10 +448,7 @@ public static String receive() { for (int i = 0; i < intPart; i++) wholeTokenChainHash.put(wholeTokenChains.getString(i)); - String hash = calculateHash( - wholeTokens.toString() + wholeTokenChainHash.toString() + partTokens.toString() - + partTokenChainsHash.toString() + receiverDidIpfsHash + senderDidIpfsHash + comment, - "SHA3-256"); + String hash = calculateHash(wholeTokens.toString() + wholeTokenChainHash.toString() + partTokens.toString() + partTokenChainsHash.toString() + receiverDidIpfsHash + senderDidIpfsHash + comment, "SHA3-256"); TokenReceiverLogger.debug("Hash to verify Sender: " + hash); JSONObject detailsForVerify = new JSONObject(); detailsForVerify.put("did", senderDidIpfsHash); @@ -607,7 +565,7 @@ public static String receive() { writeToFile(TOKENCHAIN_PATH + wholeTokens.getString(i) + ".json", arr1.toString(), false); } - for (int i = 0; i < partTokens.length(); i++) { + for(int i = 0; i < partTokens.length(); i++){ JSONObject chequeObject = new JSONObject(); chequeObject.put("sender", senderDidIpfsHash); chequeObject.put("receiver", receiverDidIpfsHash); @@ -621,6 +579,7 @@ public static String receive() { String chequeHash = IPFSNetwork.add(LOGGER_PATH.concat(partTokens.getString(i)), ipfs); deleteFile(LOGGER_PATH.concat(partTokens.getString(i))); + JSONObject newPartObject = new JSONObject(); newPartObject.put("senderSign", senderSignature); newPartObject.put("sender", senderDidIpfsHash); @@ -628,42 +587,37 @@ public static String receive() { newPartObject.put("comment", comment); newPartObject.put("tid", tid); newPartObject.put("nextHash", ""); - if (partTokenChainContent.getJSONArray(i).length() == 0) + if(partTokenChainContent.getJSONArray(i).length() == 0) newPartObject.put("previousHash", ""); else - newPartObject.put("previousHash", - calculateHash(partTokenChainContent.getJSONArray(i) - .getJSONObject(partTokenChainContent.getJSONArray(i).length() - 1) - .getString("tid"), "SHA3-256")); + newPartObject.put("previousHash", calculateHash(partTokenChainContent.getJSONArray(i).getJSONObject(partTokenChainContent.getJSONArray(i).length() - 1).getString("tid"), "SHA3-256")); + newPartObject.put("amount", partAmount); newPartObject.put("cheque", chequeHash); newPartObject.put("role", "Receiver"); - File chainFile = new File( - PART_TOKEN_CHAIN_PATH.concat(partTokens.getString(i)).concat(".json")); + File chainFile = new File(PART_TOKEN_CHAIN_PATH.concat(partTokens.getString(i)).concat(".json")); if (chainFile.exists()) { String readChain = readFile(PART_TOKEN_CHAIN_PATH + partTokens.getString(i) + ".json"); JSONArray readChainArray = new JSONArray(readChain); - readChainArray.put(partTokenChainContent.getJSONArray(i) - .getJSONObject(partTokenChainContent.getJSONArray(i).length() - 1)); + readChainArray.put(partTokenChainContent.getJSONArray(i).getJSONObject(partTokenChainContent.getJSONArray(i).length() - 1)); readChainArray.put(newPartObject); - writeToFile(PART_TOKEN_CHAIN_PATH + partTokens.getString(i) + ".json", - readChainArray.toString(), false); + writeToFile(PART_TOKEN_CHAIN_PATH + partTokens.getString(i) + ".json", readChainArray.toString(), false); + } else { partTokenChainContent.getJSONArray(i).put(newPartObject); - writeToFile(PART_TOKEN_CHAIN_PATH + partTokens.getString(i) + ".json", - partTokenChainContent.getJSONArray(i).toString(), false); + writeToFile(PART_TOKEN_CHAIN_PATH + partTokens.getString(i) + ".json", partTokenChainContent.getJSONArray(i).toString(), false); } } JSONArray allTokens = new JSONArray(); - for (int i = 0; i < wholeTokens.length(); i++) + for(int i = 0; i < wholeTokens.length(); i++) allTokens.put(wholeTokens.getString(i)); - for (int i = 0; i < partTokens.length(); i++) + for(int i = 0; i < partTokens.length(); i++) allTokens.put(partTokens.getString(i)); JSONObject transactionRecord = new JSONObject(); @@ -682,8 +636,7 @@ public static String receive() { JSONArray transactionHistoryEntry = new JSONArray(); transactionHistoryEntry.put(transactionRecord); - updateJSON("add", WALLET_DATA_PATH + "TransactionHistory.json", - transactionHistoryEntry.toString()); + updateJSON("add", WALLET_DATA_PATH + "TransactionHistory.json", transactionHistoryEntry.toString()); for (int i = 0; i < wholeTokens.length(); i++) { String bankFile = readFile(PAYMENTS_PATH.concat("BNK00.json")); @@ -698,14 +651,13 @@ public static String receive() { String partsFile = readFile(PAYMENTS_PATH.concat("PartsToken.json")); JSONArray partsReadArray = new JSONArray(partsFile); - for (int i = 0; i < partTokens.length(); i++) { + for(int i = 0; i < partTokens.length(); i++){ boolean writeParts = true; - for (int j = 0; j < partsReadArray.length(); j++) { - if (partsReadArray.getJSONObject(j).getString("tokenHash") - .equals(partTokens.getString(i))) + for(int j = 0; j < partsReadArray.length(); j++){ + if(partsReadArray.getJSONObject(j).getString("tokenHash").equals(partTokens.getString(i))) writeParts = false; } - if (writeParts) { + if(writeParts) { JSONObject partObject = new JSONObject(); partObject.put("tokenHash", partTokens.getString(i)); partsReadArray.put(partObject); diff --git a/src/com/rubix/TokenTransfer/TokenSender.java b/src/com/rubix/TokenTransfer/TokenSender.java index 2ebedd31..6935efad 100644 --- a/src/com/rubix/TokenTransfer/TokenSender.java +++ b/src/com/rubix/TokenTransfer/TokenSender.java @@ -583,17 +583,17 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception TokenSenderLogger.info("Multiple Owners for " + doubleSpent); APIResponse.put("message", "Multiple Owners for " + doubleSpent); APIResponse.put("Owners", ownersArray); - removeToken(); +// removeToken(); break; case "421": TokenSenderLogger.info("Consensus ID not unique"); APIResponse.put("message", "Consensus ID not unique"); - removeToken(); +// removeToken(); break; case "422": TokenSenderLogger.info("Tokens Not Verified"); APIResponse.put("message", "Tokens Not Verified"); - removeToken(); +// removeToken(); break; case "423": TokenSenderLogger.info("Broken Cheque Chain"); From c6469f7f3357192c6535f3ea5ebbb466425948ec Mon Sep 17 00:00:00 2001 From: Gokul P S Date: Fri, 11 Mar 2022 13:00:37 +0530 Subject: [PATCH 22/49] Revert "update rec checks" This reverts commit 89d95255f6a600ec3e3d0128f78bd902cf86e506. --- .../rubix/AuthenticateNode/Authenticate.java | 3 +- src/com/rubix/NFT/Buyer.java | 411 +++++++++++++++ src/com/rubix/NFT/Seller.java | 497 ++++++++++++++++++ src/com/rubix/Resources/FractionChooser.java | 88 ++++ src/com/rubix/Resources/Functions.java | 376 +++++++------ src/com/rubix/Resources/IPFSNetwork.java | 10 +- .../rubix/TokenTransfer/TokenReceiver.java | 158 ++++-- src/com/rubix/TokenTransfer/TokenSender.java | 6 +- 8 files changed, 1314 insertions(+), 235 deletions(-) create mode 100644 src/com/rubix/NFT/Buyer.java create mode 100644 src/com/rubix/NFT/Seller.java create mode 100644 src/com/rubix/Resources/FractionChooser.java diff --git a/src/com/rubix/AuthenticateNode/Authenticate.java b/src/com/rubix/AuthenticateNode/Authenticate.java index 0631faa0..bfaabd59 100644 --- a/src/com/rubix/AuthenticateNode/Authenticate.java +++ b/src/com/rubix/AuthenticateNode/Authenticate.java @@ -62,7 +62,8 @@ public static boolean verifySignature(String detailString) throws IOException, J positionsLevelZero[k] = ((originalPos[k]) / 8); StringBuilder decentralizedIDForAuth = new StringBuilder(); - for (int value : positionsLevelZero) decentralizedIDForAuth.append(senderDIDBin.charAt(value)); + for (int value : positionsLevelZero) + decentralizedIDForAuth.append(senderDIDBin.charAt(value)); if (recombinedResult.equals(decentralizedIDForAuth.toString())) { return true; } else { diff --git a/src/com/rubix/NFT/Buyer.java b/src/com/rubix/NFT/Buyer.java new file mode 100644 index 00000000..3d7cbec8 --- /dev/null +++ b/src/com/rubix/NFT/Buyer.java @@ -0,0 +1,411 @@ +package com.rubix.NFT; + + +import com.rubix.AuthenticateNode.Authenticate; +import com.rubix.Resources.FractionChooser; +import com.rubix.Resources.Functions; +import com.rubix.Resources.IPFSNetwork; +import io.ipfs.api.IPFS; +import java.awt.image.BufferedImage; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileWriter; +import java.io.InputStreamReader; +import java.io.PrintStream; +import java.net.ServerSocket; +import java.net.Socket; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Iterator; +import javax.imageio.ImageIO; +import org.apache.log4j.Logger; +import org.apache.log4j.PropertyConfigurator; +import org.json.JSONArray; +import org.json.JSONObject; + +public class Buyer { + public static Logger BuyerLogger = Logger.getLogger(Buyer.class); + + private static final JSONObject APIResponse = new JSONObject(); + + private static final IPFS ipfs = new IPFS("/ip4/127.0.0.1/tcp/" + Functions.IPFS_PORT); + + public static String receive() { + Functions.pathSet(); + ServerSocket ss = null; + Socket sk = null; + String sellerPeerID = null; + try { + int quorumSignVerifyCount = 0; + JSONObject quorumSignatures = null; + ArrayList quorumDID = new ArrayList<>(); + PropertyConfigurator.configure(Functions.LOGGER_PATH + "log4jWallet.properties"); + String buyerPeerID = Functions.getPeerID(Functions.DATA_PATH + "DID.json"); + String buyerDidIpfsHash = Functions.getValues(Functions.DATA_PATH + "DataTable.json", "didHash", "peerid", buyerPeerID); + IPFSNetwork.listen(buyerPeerID + "NFT", Functions.BUYER_PORT); + ss = new ServerSocket(Functions.BUYER_PORT); + BuyerLogger.debug("Listening on " + Functions.BUYER_PORT + " with app name " + buyerPeerID + "NFT"); + sk = ss.accept(); + BufferedReader input = new BufferedReader(new InputStreamReader(sk.getInputStream())); + PrintStream output = new PrintStream(sk.getOutputStream()); + long startTime = System.currentTimeMillis(); + sellerPeerID = input.readLine(); + BuyerLogger.debug("Seller PeerID received"); + String sellerDidIpfsHash = Functions.getValues(Functions.DATA_PATH + "DataTable.json", "didHash", "peerid", sellerPeerID); + String sellerWidIpfsHash = Functions.getValues(Functions.DATA_PATH + "DataTable.json", "walletHash", "peerid", sellerPeerID); + if (!sellerDidIpfsHash.contains("Qm") || !sellerWidIpfsHash.contains("Qm")) { + output.println("420"); + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Invalid Seller DID."); + BuyerLogger.info("Seller details not available in datatable"); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); + output.close(); + input.close(); + sk.close(); + ss.close(); + return APIResponse.toString(); + } + Functions.nodeData(sellerDidIpfsHash, sellerWidIpfsHash, ipfs); + File sellerDIDFile = new File(Functions.DATA_PATH + sellerDidIpfsHash + "DID.png"); + if (!sellerDIDFile.exists()) { + output.println("420"); + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Seller details not available in network , please sync"); + BuyerLogger.info("Sender details not available"); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); + output.close(); + input.close(); + sk.close(); + ss.close(); + return APIResponse.toString(); + } + output.println("200"); + BuyerLogger.debug("PeerAuth sent to Seller"); + String nftData = input.readLine(); + BuyerLogger.debug("NFT Token details received from Seller"); + JSONObject nftTokenDetails = new JSONObject(nftData); + String nftToken = nftTokenDetails.getString("nftToken"); + String nftTokenChain = nftTokenDetails.getString("nftTokenChain"); + String message = nftTokenDetails.toString(); + String nftID = Functions.calculateHash(message, "SHA3-256"); + Functions.writeToFile(Functions.LOGGER_PATH + "nftID", nftID, Boolean.valueOf(false)); + String nftIdIpfsHash = IPFSNetwork.addHashOnly(Functions.LOGGER_PATH + "nftID", ipfs); + Functions.deleteFile(Functions.LOGGER_PATH + "nftID"); + String nftTokenChainContent = IPFSNetwork.get(nftTokenChain, ipfs); + String nftTokenContent = IPFSNetwork.get(nftToken, ipfs); + BuyerLogger.debug("NFT token content extracted"); + IPFSNetwork.repo(ipfs); + if (!IPFSNetwork.dhtEmpty(nftIdIpfsHash, ipfs)) { + BuyerLogger.debug("NFT ID not unique" + nftIdIpfsHash); + output.println("420"); + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "NFT ID not unique"); + BuyerLogger.info("NFT ID not unique"); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); + output.close(); + input.close(); + sk.close(); + ss.close(); + return APIResponse.toString(); + } + if (nftTokenContent.equals("")) { + output.println("421"); + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Invalid NFT Token"); + BuyerLogger.info("Invalid NFT Token"); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); + output.close(); + input.close(); + sk.close(); + ss.close(); + return APIResponse.toString(); + } + output.println("200"); + BuyerLogger.debug("NftTokenAuth: 200. Sent to Seller"); + String assetData = input.readLine(); + BuyerLogger.debug("Received asset details from Seller"); + JSONObject assetDetails = new JSONObject(assetData); + int amount = assetDetails.getInt("amount"); + JSONArray rbxTokens = FractionChooser.calculate(amount); + JSONArray rbxTokenHeader = FractionChooser.tokenHeader; + ArrayList rbxTokensChainsPushed = new ArrayList<>(); + if (rbxTokens.length() == 0) { + output.println("420"); + BuyerLogger.debug("Insufficient balance with buyer"); + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Insufficient balance"); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); + output.close(); + input.close(); + sk.close(); + ss.close(); + return APIResponse.toString(); + } + for (int i = 0; i < rbxTokens.length(); i++) { + File rbxtoken = new File(Functions.TOKENS_PATH+rbxTokens.get(i)); + File rbxtokenchain = new File(Functions.TOKENCHAIN_PATH+rbxTokens.get(i)+".json"); + BuyerLogger.debug("" + rbxtoken + " and " + rbxtoken); + if (!rbxtoken.exists() || !rbxtokenchain.exists()) { + output.println("421"); + BuyerLogger.info("Tokens Not Verified"); + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Invalid token(s)"); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); + output.close(); + input.close(); + sk.close(); + ss.close(); + return APIResponse.toString(); + } + IPFSNetwork.add(Functions.TOKENS_PATH+rbxTokens.get(i), ipfs); + String tokenChainHash = IPFSNetwork.add(Functions.TOKENCHAIN_PATH+rbxTokens.get(i)+".json", ipfs); + rbxTokensChainsPushed.add(tokenChainHash); + } + JSONObject rbxTokenDetails = new JSONObject(); + rbxTokenDetails.put("rbxTokens", rbxTokens); + rbxTokenDetails.put("rbxTokenChains", rbxTokensChainsPushed); + rbxTokenDetails.put("rbxTokenHeader", rbxTokenHeader); + String pvt = Functions.DATA_PATH+ buyerDidIpfsHash + "PrivateShare.png"; + String buyerSign = Functions.getSignFromShares(pvt, Functions.calculateHash(rbxTokens.toString() + rbxTokenHeader.toString() + rbxTokensChainsPushed.toString(), "SHA3-256")); + JSONObject rbxData = new JSONObject(); + rbxData.put("rbxTokenDetails", rbxTokenDetails); + rbxData.put("authBuyerBySeller", buyerSign); + output.println(rbxData); + BuyerLogger.debug("Sent rbxData and Buyer sign for authentication to seller."); + String rbxTokensAuth = input.readLine(); + if (rbxTokensAuth.equals("421")) { + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "RBX tokens not verified at seller node"); + BuyerLogger.info("RBX tokens not verified at sender node"); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); + output.close(); + input.close(); + sk.close(); + ss.close(); + return APIResponse.toString(); + } + if (rbxTokensAuth.equals("420")) { + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Consensus ID not Unique"); + BuyerLogger.info("Consensus ID not Unique"); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); + output.close(); + input.close(); + sk.close(); + ss.close(); + return APIResponse.toString(); + } + BuyerLogger.debug("consensus/seller details received from Seller"); + JSONObject consensusDetails = new JSONObject(rbxTokensAuth); + String sellerSignature = consensusDetails.getString("sign"); + String tid = consensusDetails.getString("tid"); + String comment = consensusDetails.getString("comment"); + String Status = consensusDetails.getString("status"); + String QuorumDetails = consensusDetails.getString("quorumsign"); + BuyerLogger.debug("Consensus Status: " + Status); + if (!Status.equals("Consensus Failed")) { + boolean yesQuorum = false; + if (Status.equals("Consensus Reached")) { + BuyerLogger.debug("Quorum Signatures: " + QuorumDetails); + quorumSignatures = new JSONObject(QuorumDetails); + BuyerLogger.debug("Quorum Signatures length : " + quorumSignatures.length()); + Iterator dids = quorumSignatures.keys(); + while (dids.hasNext()) { + String did = dids.next(); + quorumDID.add(did); + } + for (String quorumDidIpfsHash : quorumDID) { + String quorumWidIpfsHash = Functions.getValues(Functions.DATA_PATH + "DataTable.json", "walletHash", "didHash", quorumDidIpfsHash); + File quorumDataFolder = new File(Functions.DATA_PATH + "/"); + if (!quorumDataFolder.exists()) { + quorumDataFolder.mkdirs(); + IPFSNetwork.getImage(quorumDidIpfsHash, ipfs, Functions.DATA_PATH + quorumDidIpfsHash + "DID.png"); + IPFSNetwork.getImage(quorumWidIpfsHash, ipfs, Functions.DATA_PATH + quorumDidIpfsHash + "PublicShare.png"); + BuyerLogger.debug("Quorum Data " + quorumDidIpfsHash + " Added"); + continue; + } + BuyerLogger.debug("Quorum Data " + quorumDidIpfsHash + " Available"); + } + for (int j = 0; j < quorumSignatures.length(); j++) { + JSONObject jSONObject = new JSONObject(); + jSONObject.put("did", quorumDID.get(j)); + jSONObject.put("signature", quorumSignatures.getString(quorumDID.get(j))); + boolean val = Authenticate.verifySignature(jSONObject.toString()); + if (val) + quorumSignVerifyCount++; + } + BuyerLogger.debug("Verified Quorum Count " + quorumSignVerifyCount); + yesQuorum = (quorumSignVerifyCount >= quorumSignatures.length()); + } + String hash = Functions.calculateHash(nftToken + nftTokenChain + amount + buyerDidIpfsHash, "SHA3-256"); + JSONObject detailsForVerify = new JSONObject(); + detailsForVerify.put("did", sellerDidIpfsHash); + detailsForVerify.put("hash", hash); + detailsForVerify.put("signature", sellerSignature); + boolean yesSender = Authenticate.verifySignature(detailsForVerify.toString()); + BuyerLogger.debug("Seller Auth Hash" + hash); + BuyerLogger.debug("Quorum Auth : " + yesQuorum + "Seller Auth : " + yesSender); + if (!yesSender || !yesQuorum) { + output.println("420"); + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", tid); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Seller/Quorum not verified"); + BuyerLogger.info("Seller/Quorum not verified"); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); + output.close(); + input.close(); + sk.close(); + ss.close(); + return APIResponse.toString(); + } + IPFSNetwork.repo(ipfs); + BuyerLogger.debug("Seller and Quorum Verified"); + output.println("200"); + String nftUnpinStatus = input.readLine(); + if (nftUnpinStatus.equals("Unpinned NFT")) { + FileWriter fileWriter = new FileWriter(Functions.NFT_TOKENS_PATH+nftToken); + fileWriter.write(nftTokenContent); + fileWriter.close(); + IPFSNetwork.add(Functions.NFT_TOKENS_PATH + nftToken, ipfs); + IPFSNetwork.pin(nftToken, ipfs); + + try { + BuyerLogger.debug("Successfully Pinned NFT Token"); + for (int j = 0; j < rbxTokens.length(); j++) + IPFSNetwork.unpin(String.valueOf(rbxTokens.get(j)), ipfs); + IPFSNetwork.repo(ipfs); + BuyerLogger.debug("Unpinned RBX Tokens"); + output.println("Unpinned RBX"); + String rbxPinData = input.readLine(); + JSONObject rbxPinDetails = new JSONObject(rbxPinData); + String status = rbxPinDetails.getString("status"); + if (status.equals("Failed to pin RBX")) { + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Seller Failed to pin RBX Tokens"); + BuyerLogger.info(" Transaction failed"); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); + output.close(); + input.close(); + sk.close(); + ss.close(); + return APIResponse.toString(); + } + String essentialShare = rbxPinDetails.getString("essentialShare"); + long endTime = System.currentTimeMillis(); + JSONArray currentNftTokenChain = new JSONArray(nftTokenChainContent); + JSONObject newRecord = new JSONObject(); + newRecord.put("sellerDID", sellerDidIpfsHash); + newRecord.put("sellerSign", sellerSignature); + newRecord.put("comment", comment); + newRecord.put("tid", tid); + currentNftTokenChain.put(newRecord); + Functions.writeToFile(Functions.NFT_TOKENCHAIN_PATH+nftTokenChain+".json", currentNftTokenChain.toString(), Boolean.valueOf(false)); + Iterator keys = quorumSignatures.keys(); + JSONArray quorumList = new JSONArray(); + while (keys.hasNext()) + quorumList.put(keys.next()); + JSONObject nftTransactionRecord = new JSONObject(); + nftTransactionRecord.put("role", "Buyer"); + nftTransactionRecord.put("sellerDID", sellerDidIpfsHash); + nftTransactionRecord.put("buyerDID", buyerDidIpfsHash); + nftTransactionRecord.put("amount", amount); + nftTransactionRecord.put("rbxTokens", rbxTokens); + nftTransactionRecord.put("nftToken", nftToken); + nftTransactionRecord.put("txn", tid); + nftTransactionRecord.put("quorumList", quorumList); + nftTransactionRecord.put("Date", Functions.getCurrentUtcTime()); + nftTransactionRecord.put("totalTime", endTime - startTime); + nftTransactionRecord.put("comment", comment); + nftTransactionRecord.put("essentialShare", essentialShare); + JSONArray nftTransactionHistoryEntry = new JSONArray(); + nftTransactionHistoryEntry.put(nftTransactionRecord); + Functions.updateJSON("add", Functions.WALLET_DATA_PATH + "nftTransactionHistory.json", nftTransactionHistoryEntry.toString()); + int k; + for (k = 0; k < rbxTokens.length(); k++) + Files.deleteIfExists(Paths.get(Functions.TOKENS_PATH+rbxTokens.get(k), new String[0])); + for (k = 0; k < amount; k++) + Functions.updateJSON("remove", Functions.PAYMENTS_PATH+rbxTokenHeader.getString(k), rbxTokens.getString(k)); + BuyerLogger.info("Transaction ID: " + tid + "Transaction Successful"); + output.println("Send Response"); + APIResponse.put("sellerDID", sellerDidIpfsHash); + APIResponse.put("buyerDID", buyerDidIpfsHash); + APIResponse.put("tid", tid); + APIResponse.put("status", "Success"); + APIResponse.put("tokens", nftToken); + APIResponse.put("comment", comment); + APIResponse.put("message", "NFT Transaction Successful"); + BuyerLogger.info("Transaction Successful"); + } catch (Exception e) { + output.println("Failed pinning on Buyer Node"); + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Failed in pinning NFT token"); + BuyerLogger.info(" Transaction failed", e); + } + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); + output.close(); + input.close(); + sk.close(); + ss.close(); + return APIResponse.toString(); + } + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Seller Failed to unpin"); + BuyerLogger.info(" Transaction failed"); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); + output.close(); + input.close(); + sk.close(); + ss.close(); + return APIResponse.toString(); + } + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Consensus failed at Sender side"); + BuyerLogger.info(" Transaction failed"); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); + output.close(); + input.close(); + sk.close(); + ss.close(); + return APIResponse.toString(); + } catch (Exception e) { + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); + BuyerLogger.error("Exception Occurred", e); + return APIResponse.toString(); + } finally { + try { + ss.close(); + sk.close(); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); + } catch (Exception e) { + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); + BuyerLogger.error("Exception Occurred", e); + } + } + } +} diff --git a/src/com/rubix/NFT/Seller.java b/src/com/rubix/NFT/Seller.java new file mode 100644 index 00000000..359f9245 --- /dev/null +++ b/src/com/rubix/NFT/Seller.java @@ -0,0 +1,497 @@ +package com.rubix.NFT; + +import com.rubix.AuthenticateNode.PropImage; +import com.rubix.Consensus.InitiatorConsensus; +import com.rubix.Consensus.InitiatorProcedure; +import com.rubix.Resources.Functions; +import com.rubix.Resources.IPFSNetwork; +import io.ipfs.api.IPFS; +import java.awt.image.BufferedImage; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileWriter; +import java.io.InputStreamReader; +import java.io.PrintStream; +import java.net.Socket; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Iterator; +import javax.imageio.ImageIO; +import org.apache.log4j.Logger; +import org.apache.log4j.PropertyConfigurator; +import org.json.JSONArray; +import org.json.JSONObject; + +public class Seller { + private static final Logger SellerLogger = Logger.getLogger(Seller.class); + + private static final String USER_AGENT = "Mozilla/5.0"; + + public static BufferedReader serverInput; + + private static PrintStream output; + + private static BufferedReader input; + + private static Socket sellerSocket; + + private static boolean sellerMutex = false; + + public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception { + JSONArray quorumArray; + JSONObject APIResponse = new JSONObject(); + PropertyConfigurator.configure(Functions.LOGGER_PATH + "log4jWallet.properties"); + JSONObject detailsObject = new JSONObject(data); + String buyerDidIpfsHash = detailsObject.getString("buyerDidIpfsHash"); + String pvt = detailsObject.getString("pvt"); + int amount = detailsObject.getInt("amount"); + int type = detailsObject.getInt("type"); + String comment = detailsObject.getString("comment"); + //String eKey = detailsObject.getString("eKey"); + //String dKey = detailsObject.getString("dKey"); + String nftTokenIpfsHash = detailsObject.getString("nftToken"); + JSONArray alphaQuorum = new JSONArray(); + JSONArray betaQuorum = new JSONArray(); + JSONArray gammaQuorum = new JSONArray(); + String sellerPeerId = Functions.getPeerID(Functions.DATA_PATH + "DID.json"); + SellerLogger.debug("Seller Peer ID : " + sellerPeerId); + String sellerDidIpfsHash = Functions.getValues(Functions.DATA_PATH + "DataTable.json", "didHash", "peerid", sellerPeerId); + SellerLogger.debug("Seller DID IPFS Hash : " + sellerDidIpfsHash); + SellerLogger.debug("Path is : " + Functions.DATA_PATH + sellerDidIpfsHash); + File folder = new File(Functions.DATA_PATH); + File[] listOfFiles = folder.listFiles(); + for (int i = 0; i < listOfFiles.length; i++) { + if (listOfFiles[i].isFile()) { + System.out.println("File " + listOfFiles[i].getName()); + } else if (listOfFiles[i].isDirectory()) { + System.out.println("Directory " + listOfFiles[i].getName()); + } + } + BufferedImage senderWidImage = ImageIO.read(new File(Functions.DATA_PATH + sellerDidIpfsHash + "/PublicShare.png")); + String senderWidBin = PropImage.img2bin(senderWidImage); + if (sellerMutex) { + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Sender busy. Try again later"); + SellerLogger.warn("Sender busy"); + return APIResponse; + } + sellerMutex = true; + //String nftTokenChainIpfsHash = null; + APIResponse = new JSONObject(); + File nfttoken = new File(Functions.NFT_TOKENS_PATH+nftTokenIpfsHash); + File nfttokenchain = new File(Functions.NFT_TOKENCHAIN_PATH + nftTokenIpfsHash +".json"); + SellerLogger.debug("NFT Token : " + nfttoken + " and NFT TokenChain : " + nfttokenchain); + if (!nfttoken.exists() || !nfttokenchain.exists() ) { + SellerLogger.info("NFT Token Not Verified"); + sellerMutex = false; + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Invalid NFT token"); + return APIResponse; + } + IPFSNetwork.add(Functions.NFT_TOKENS_PATH + nftTokenIpfsHash, ipfs); + String nftTokenChainIpfsHash = IPFSNetwork.add(Functions.NFT_TOKENCHAIN_PATH + nftTokenIpfsHash + ".json", ipfs); + String authSellerByBuyerHash = Functions.calculateHash(nftTokenIpfsHash + nftTokenChainIpfsHash+ amount + buyerDidIpfsHash, "SHA3-256"); + String tid = Functions.calculateHash(authSellerByBuyerHash, "SHA3-256"); + SellerLogger.debug("Hash for Seller authentication to Buyer : " + authSellerByBuyerHash); + SellerLogger.debug("TID on seller " + tid); + Functions.writeToFile(Functions.LOGGER_PATH + "tempbeta", tid.concat(sellerDidIpfsHash), Boolean.valueOf(false)); + String betaHash = IPFSNetwork.add(Functions.LOGGER_PATH + "tempbeta", ipfs); + Functions.deleteFile(Functions.LOGGER_PATH + "tempbeta"); + Functions.writeToFile(Functions.LOGGER_PATH + "tempgamma", tid.concat(buyerDidIpfsHash), Boolean.valueOf(false)); + String gammaHash = IPFSNetwork.add(Functions.LOGGER_PATH + "tempgamma", ipfs); + Functions.deleteFile(Functions.LOGGER_PATH + "tempgamma"); + switch (type) { + case 1: + quorumArray = Functions.getQuorum(betaHash, gammaHash, sellerDidIpfsHash, buyerDidIpfsHash, amount); + break; + case 2: + quorumArray = new JSONArray(Functions.readFile(Functions.DATA_PATH + "quorumlist.json")); + break; + case 3: + quorumArray = detailsObject.getJSONArray("quorum"); + break; + default: + SellerLogger.error("Unknown quorum type input, cancelling transaction"); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Unknown quorum type input, cancelling transaction"); + return APIResponse; + } + Functions.QuorumSwarmConnect(quorumArray, ipfs); + int alphaSize = quorumArray.length() - 14; + int j; + for (j = 0; j < alphaSize; j++) + alphaQuorum.put(quorumArray.getString(j)); + for (j = 0; j < 7; j++) { + betaQuorum.put(quorumArray.getString(alphaSize + j)); + gammaQuorum.put(quorumArray.getString(alphaSize + 7 + j)); + } + SellerLogger.debug("alphaquorum " + alphaQuorum + " size " + alphaQuorum.length()); + SellerLogger.debug("betaquorum " + betaQuorum + " size " + betaQuorum.length()); + SellerLogger.debug("gammaquorum " + gammaQuorum + " size " + gammaQuorum.length()); + ArrayList alphaPeersList = Functions.QuorumCheck(alphaQuorum, alphaSize); + ArrayList betaPeersList = Functions.QuorumCheck(betaQuorum, 7); + ArrayList gammaPeersList = Functions.QuorumCheck(gammaQuorum, 7); + SellerLogger.debug("alphaPeersList size " + alphaPeersList.size()); + SellerLogger.debug("betaPeersList size " + betaPeersList.size()); + SellerLogger.debug("gammaPeersList size " + gammaPeersList.size()); + SellerLogger.debug("minQuorumAlpha size " + Functions.minQuorum(alphaSize)); + if (alphaPeersList.size() < Functions.minQuorum(alphaSize) || betaPeersList.size() < 5 || gammaPeersList.size() < 5) { + Functions.updateQuorum(quorumArray, null, false, type); + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Quorum Members not available"); + SellerLogger.warn("Quorum Members not available"); + sellerMutex = false; + return APIResponse; + } + String sellerSign = Functions.getSignFromShares(pvt, authSellerByBuyerHash); + JSONObject sellerDetails2Buyer = new JSONObject(); + sellerDetails2Buyer.put("sign", sellerSign); + sellerDetails2Buyer.put("tid", tid); + sellerDetails2Buyer.put("comment", comment); + JSONObject nftTokenDetails = new JSONObject(); + nftTokenDetails.put("nftToken", nftTokenIpfsHash); + nftTokenDetails.put("nftTokenChain", nftTokenChainIpfsHash); + String message = nftTokenDetails.toString(); + String nftID = Functions.calculateHash(message, "SHA3-256"); + Functions.writeToFile(Functions.LOGGER_PATH + "nftID", nftID, Boolean.valueOf(false)); + String nftIdIpfsHash = IPFSNetwork.addHashOnly(Functions.LOGGER_PATH + "nftID", ipfs); + Functions.deleteFile(Functions.LOGGER_PATH + "nftID"); + SellerLogger.debug("nftID hash " + nftIdIpfsHash + " unique owner " + IPFSNetwork.dhtEmpty(nftIdIpfsHash, ipfs)); + JSONObject assetDetails = new JSONObject(); + assetDetails.put("amount", amount); + String buyerPeerId = Functions.getValues(Functions.DATA_PATH + "DataTable.json", "peerid", "didHash", buyerDidIpfsHash); + SellerLogger.debug("Swarm connecting to " + buyerPeerId); + IPFSNetwork.swarmConnectP2P(buyerPeerId, ipfs); + SellerLogger.debug("Swarm connected"); + String buyerWidIpfsHash = Functions.getValues(Functions.DATA_PATH + "DataTable.json", "walletHash", "didHash", buyerDidIpfsHash); + Functions.nodeData(buyerDidIpfsHash, buyerWidIpfsHash, ipfs); + IPFSNetwork.forward(buyerPeerId + "NFT", port, buyerPeerId); + SellerLogger.debug("Forwarded to " + buyerPeerId + " on " + port); + sellerSocket = new Socket("127.0.0.1", port); + input = new BufferedReader(new InputStreamReader(sellerSocket.getInputStream())); + output = new PrintStream(sellerSocket.getOutputStream()); + long startTime = System.currentTimeMillis(); + output.println(sellerPeerId); + SellerLogger.debug("PeerID sent to Buyer"); + String peerAuth = input.readLine(); + SellerLogger.debug("PeerAuth received from Buyer. Code: " + peerAuth); + if (!peerAuth.equals("200")) { + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); + SellerLogger.info("Seller data not available in the network"); + output.close(); + input.close(); + sellerSocket.close(); + sellerMutex = false; + Functions.updateQuorum(quorumArray, null, false, type); + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", tid); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Seller data not available in the network"); + return APIResponse; + } + output.println(nftTokenDetails); + SellerLogger.debug("NFT Token details sent to Buyer"); + String nftTokenAuth = input.readLine(); + SellerLogger.debug("nftTokenAuth received from Buyer. Code: " + nftTokenAuth); + if (!nftTokenAuth.equals("200")) { + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); + output.close(); + input.close(); + sellerSocket.close(); + sellerMutex = false; + if (nftTokenAuth.equals("421")) { + SellerLogger.info("Invalid NFT Token"); + APIResponse.put("message", "Invalid NFT Token"); + } else { + SellerLogger.info("NFT ID not unique"); + APIResponse.put("message", "NFT ID not unique"); + } + Functions.updateQuorum(quorumArray, null, false, type); + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", tid); + APIResponse.put("status", "Failed"); + return APIResponse; + } + output.println(assetDetails); + SellerLogger.debug("Sent asset details to Buyer"); + String rbxTokenAuth = input.readLine(); + SellerLogger.debug("Received rbxTokenAuth from Buyer"); + if (rbxTokenAuth.equals("421")) { + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); + output.close(); + input.close(); + sellerSocket.close(); + sellerMutex = false; + SellerLogger.info("Invalid RBX tokens at buyer end"); + APIResponse.put("message", "Invalid RBX tokens at buyer end"); + Functions.updateQuorum(quorumArray, null, false, type); + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", tid); + APIResponse.put("status", "Failed"); + return APIResponse; + } + if (rbxTokenAuth.equals("420")) { + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); + output.close(); + input.close(); + sellerSocket.close(); + sellerMutex = false; + SellerLogger.info("Insufficient RBX tokens at buyer end"); + APIResponse.put("message", "Insufficient RBX tokens at buyer end"); + Functions.updateQuorum(quorumArray, null, false, type); + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", tid); + APIResponse.put("status", "Failed"); + return APIResponse; + } + JSONObject rbxData = new JSONObject(rbxTokenAuth); + String buyerSign = rbxData.getString("authBuyerBySeller"); + JSONObject rbxTokenDetails = rbxData.getJSONObject("rbxTokenDetails"); + JSONArray rbxTokens = rbxTokenDetails.getJSONArray("rbxTokens"); + JSONArray rbxTokenChains = rbxTokenDetails.getJSONArray("rbxTokenChains"); + JSONArray rbxTokenHeader = rbxTokenDetails.getJSONArray("rbxTokenHeader"); + String messageContent = rbxTokenDetails.toString(); + String consensusID = Functions.calculateHash(messageContent, "SHA3-256"); + Functions.writeToFile(Functions.LOGGER_PATH + "consensusID", consensusID, Boolean.valueOf(false)); + String consensusIdIpfsHash = IPFSNetwork.addHashOnly(Functions.LOGGER_PATH + "consensusID", ipfs); + Functions.deleteFile(Functions.LOGGER_PATH + "consensusID"); + int ipfsGetFlag = 0; + ArrayList allRbxTokenContent = new ArrayList<>(); + ArrayList allRbxTokenChainContent = new ArrayList<>(); + for (int k = 0; k < amount; k++) { + String TokenChainContent = IPFSNetwork.get(rbxTokenChains.getString(k), ipfs); + allRbxTokenChainContent.add(TokenChainContent); + String TokenContent = IPFSNetwork.get(rbxTokens.getString(k), ipfs); + allRbxTokenContent.add(TokenContent); + ipfsGetFlag++; + } + IPFSNetwork.repo(ipfs); + if (!IPFSNetwork.dhtEmpty(consensusIdIpfsHash, ipfs)) { + SellerLogger.debug("consensus ID not unique" + consensusIdIpfsHash); + output.println("420"); + APIResponse.put("did", buyerDidIpfsHash); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Consensus ID not unique"); + SellerLogger.info("Consensus ID not unique"); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); + output.close(); + input.close(); + sellerSocket.close(); + return APIResponse; + } + if (ipfsGetFlag != amount) { + output.println("421"); + APIResponse.put("did", buyerDidIpfsHash); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Tokens not verified"); + SellerLogger.info("Tokens not verified"); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); + output.close(); + input.close(); + sellerSocket.close(); + return APIResponse; + } + JSONObject dataObject = new JSONObject(); + dataObject.put("tid", tid); + dataObject.put("message", message); + dataObject.put("messageRbx", messageContent); + dataObject.put("buyerDidIpfsHash", buyerDidIpfsHash); + dataObject.put("pvt", pvt); + dataObject.put("sellerDidIpfsHash", sellerDidIpfsHash); + dataObject.put("nftToken", nftTokenIpfsHash); + dataObject.put("rbxTokens", rbxTokens); + dataObject.put("alphaList", alphaPeersList); + dataObject.put("betaList", betaPeersList); + dataObject.put("gammaList", gammaPeersList); + SellerLogger.debug("dataobject " + dataObject.toString()); + SellerLogger.debug("nftConsensus Setup Begins"); + InitiatorProcedure.nftConsensusSetUp(dataObject.toString(), ipfs, Functions.SELLER_PORT + 225, alphaSize); + SellerLogger.debug("nftConsensus Done"); + SellerLogger.debug("length on seller " + InitiatorConsensus.quorumSignature.length() + " response count " + InitiatorConsensus.quorumResponse); + if (InitiatorConsensus.quorumSignature.length() < Functions.minQuorum(alphaSize) + 2 * Functions.minQuorum(7)) { + SellerLogger.debug("Consensus Failed"); + sellerDetails2Buyer.put("status", "Consensus Failed"); + sellerDetails2Buyer.put("quorumsign", InitiatorConsensus.quorumSignature.toString()); + output.println(sellerDetails2Buyer); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); + output.close(); + input.close(); + sellerSocket.close(); + sellerMutex = false; + Functions.updateQuorum(quorumArray, null, false, type); + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", tid); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Transaction declined by Quorum"); + return APIResponse; + } + SellerLogger.debug("Consensus Reached"); + sellerDetails2Buyer.put("status", "Consensus Reached"); + sellerDetails2Buyer.put("quorumsign", InitiatorConsensus.quorumSignature.toString()); + output.println(sellerDetails2Buyer); + SellerLogger.debug("Sent Seller/Consensus Details to Buyer"); + SellerLogger.debug("Quorum Signatures length " + InitiatorConsensus.quorumSignature.length()); + String signatureAuth = input.readLine(); + long endAuth = System.currentTimeMillis(); + long totalTime = endAuth - startTime; + if (!signatureAuth.equals("200")) { + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); + SellerLogger.info("Authentication Failed"); + output.close(); + input.close(); + sellerSocket.close(); + sellerMutex = false; + Functions.updateQuorum(quorumArray, null, false, type); + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", tid); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Quorum/Seller not authenticated"); + return APIResponse; + } + IPFSNetwork.unpin(nftTokenIpfsHash, ipfs); + IPFSNetwork.repo(ipfs); + SellerLogger.debug("Unpinned NFT Token"); + output.println("Unpinned NFT"); + String rbxUnpinStatus = input.readLine(); + if (!rbxUnpinStatus.equals("Unpinned RBX")) { + SellerLogger.warn("Buyer failed to pin NFT Token"); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); + SellerLogger.info("Buyer failed to pin NFT Token"); + output.close(); + input.close(); + sellerSocket.close(); + sellerMutex = false; + Functions.updateQuorum(quorumArray, null, false, type); + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", tid); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Buyer failed to pin NFT Token"); + return APIResponse; + } + int count = 0; + int m; + for (m = 0; m < amount; m++) { + FileWriter fileWriter = new FileWriter(Functions.TOKENS_PATH + allRbxTokenContent.get(m)); + fileWriter.write(allRbxTokenContent.get(m)); + fileWriter.close(); + IPFSNetwork.add(Functions.TOKENS_PATH + allRbxTokenContent.get(m), ipfs); + IPFSNetwork.pin(rbxTokens.getString(m), ipfs); + count++; + } + if (count == amount) { + SellerLogger.debug("Pinned All RBX Tokens"); + for (m = 0; m < amount; m++) { + ArrayList groupTokens = new ArrayList<>(); + for (int i1 = 0; i1 < amount; i1++) { + if (!rbxTokens.getString(m).equals(rbxTokens.getString(i1))) + groupTokens.add(rbxTokens.getString(i1)); + } + JSONArray arrToken = new JSONArray(); + JSONObject objectToken = new JSONObject(); + objectToken.put("tokenHash", rbxTokens.getString(m)); + arrToken.put(objectToken); + JSONArray arr1 = new JSONArray(allRbxTokenChainContent.get(m)); + JSONObject obj2 = new JSONObject(); + obj2.put("buyerSign", buyerSign); + obj2.put("buyerDID", buyerDidIpfsHash); + obj2.put("group", groupTokens); + obj2.put("comment", comment); + obj2.put("tid", tid); + arr1.put(obj2); + Functions.writeToFile(Functions.TOKENCHAIN_PATH + allRbxTokenChainContent.get(m) + ".json", arr1.toString(), Boolean.valueOf(false)); + } + JSONObject rbxPinData = new JSONObject(); + rbxPinData.put("status", "Pinned RBX"); + rbxPinData.put("essentialShare", InitiatorProcedure.essential); + output.println(rbxPinData.toString()); + } else { + JSONObject rbxPinData = new JSONObject(); + rbxPinData.put("status", "Failed to pin RBX"); + rbxPinData.put("essentialShare", "null"); + output.println(rbxPinData.toString()); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); + output.close(); + input.close(); + sellerSocket.close(); + sellerMutex = false; + Functions.updateQuorum(quorumArray, null, false, type); + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", tid); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Seller Failed to pin RBX"); + SellerLogger.info("Incomplete Transaction"); + return APIResponse; + } + String respAuth = input.readLine(); + if (!respAuth.equals("Send Response")) { + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); + output.close(); + input.close(); + sellerSocket.close(); + sellerMutex = false; + Functions.updateQuorum(quorumArray, null, false, type); + APIResponse.put("did", sellerDidIpfsHash); + APIResponse.put("tid", tid); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Receiver process not over"); + SellerLogger.info("Incomplete Transaction"); + return APIResponse; + } + Iterator keys = InitiatorConsensus.quorumSignature.keys(); + JSONArray signedQuorumList = new JSONArray(); + while (keys.hasNext()) + signedQuorumList.put(keys.next()); + APIResponse.put("tid", tid); + APIResponse.put("status", "Success"); + APIResponse.put("sellerDID", sellerDidIpfsHash); + APIResponse.put("message", "NFT transferred successfully!"); + APIResponse.put("quorumlist", signedQuorumList); + APIResponse.put("buyerDID", buyerDidIpfsHash); + APIResponse.put("totaltime", totalTime); + Functions.updateQuorum(quorumArray, signedQuorumList, true, type); + JSONObject nftTransactionRecord = new JSONObject(); + nftTransactionRecord.put("role", "Seller"); + nftTransactionRecord.put("sellerDID", sellerDidIpfsHash); + nftTransactionRecord.put("buyerDID", buyerDidIpfsHash); + nftTransactionRecord.put("amount", amount); + nftTransactionRecord.put("rbxTokens", rbxTokens); + nftTransactionRecord.put("nftToken", nftTokenIpfsHash); + //nftTransactionRecord.put("eKey", eKey); + //nftTransactionRecord.put("dKey", dKey); + nftTransactionRecord.put("txn", tid); + nftTransactionRecord.put("quorumList", signedQuorumList); + nftTransactionRecord.put("Date", Functions.getCurrentUtcTime()); + nftTransactionRecord.put("totalTime", totalTime); + nftTransactionRecord.put("comment", comment); + nftTransactionRecord.put("essentialShare", InitiatorProcedure.essential); + JSONArray nftTransactionHistoryEntry = new JSONArray(); + nftTransactionHistoryEntry.put(nftTransactionRecord); + Functions.updateJSON("add", Functions.WALLET_DATA_PATH + "nftTransactionHistory.json", nftTransactionHistoryEntry.toString()); + Files.deleteIfExists(Paths.get(Functions.NFT_TOKENS_PATH + nftTokenIpfsHash, new String[0])); + for (int n = 0; n < rbxTokens.length(); n++) { + String bank = rbxTokenHeader.getString(n); + String bankFile = Functions.readFile(Functions.PAYMENTS_PATH + bank + ".json"); + JSONArray bankArray = new JSONArray(bankFile); + JSONObject tokenObject = new JSONObject(); + tokenObject.put("tokenHash", rbxTokens.getString(n)); + bankArray.put(tokenObject); + Functions.writeToFile(Functions.PAYMENTS_PATH + "TokenMap.json", bankArray.toString(), Boolean.valueOf(false)); + } + SellerLogger.info("Transaction Successful"); + IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); + output.close(); + input.close(); + sellerSocket.close(); + sellerMutex = false; + return APIResponse; + } +} diff --git a/src/com/rubix/Resources/FractionChooser.java b/src/com/rubix/Resources/FractionChooser.java new file mode 100644 index 00000000..4f328c6c --- /dev/null +++ b/src/com/rubix/Resources/FractionChooser.java @@ -0,0 +1,88 @@ +package com.rubix.Resources; + + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import org.apache.log4j.*; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import static com.rubix.Resources.Functions.*; + +public class FractionChooser { + public static String output; + + public static JSONArray tokenHeader; + + public static Logger FractionChooserLogger = Logger.getLogger(FractionChooser.class); + + public static JSONArray calculate(int amount) { + JSONArray tokensList = new JSONArray(); + tokenHeader = new JSONArray(); + JSONObject tknmap = new JSONObject(); + try { + int index = 0; + LinkedHashMap map = new LinkedHashMap<>(); + LinkedHashMap usedmap = new LinkedHashMap<>(); + List bnk = new ArrayList<>(); + if (amount < 1) { + FractionChooserLogger.warn("Invalid Transaction Amount"); + output = "Please make a valid transaction"; + return tokensList; + } + JSONArray mapList = new JSONArray(readFile(PAYMENTS_PATH + "TokenMap.json")); + int i; + for (i = 0; i < mapList.length(); i++) { + JSONObject tempJsonObject = mapList.getJSONObject(i); + String type = tempJsonObject.getString("type"); + int valueInt = tempJsonObject.getInt("value"); + tknmap.put(String.valueOf(valueInt), type); + String lists = readFile(PAYMENTS_PATH + tempJsonObject.getString("type") + ".json"); + JSONArray tempJsonArray = new JSONArray(lists); + bnk.add(i, tempJsonArray); + int size = tempJsonArray.length(); + map.put(Integer.valueOf(valueInt), Integer.valueOf(size)); + usedmap.put(Integer.valueOf(valueInt), Integer.valueOf(0)); + } + List keyList = new ArrayList(map.keySet()); + for (i = map.size() - 1; i > 0; i--) { + if (((Integer)keyList.get(i)).intValue() <= amount) { + index = i; + break; + } + } + while (amount != 0) { + int valueInt = ((Integer)keyList.get(index)).intValue(); + if (((Integer)map.get(Integer.valueOf(valueInt))).intValue() > 0 && valueInt <= amount) { + amount -= valueInt; + int temp = ((Integer)usedmap.get(Integer.valueOf(valueInt))).intValue(); + int temp1 = ((Integer)map.get(Integer.valueOf(valueInt))).intValue(); + usedmap.put(Integer.valueOf(valueInt), Integer.valueOf(++temp)); + map.put(Integer.valueOf(valueInt), Integer.valueOf(--temp1)); + } else if (index != 0) { + index--; + } else { + FractionChooserLogger.warn("Insufficient Amount in the Wallet. Required " + amount + " currency"); + output = "Balance not sufficient, need " + amount + " more currency"; + return tokensList; + } + if (valueInt > amount && index != 0) + index--; + } + for (i = 0; i < keyList.size(); i++) { + for (int j = 0; j < ((Integer)usedmap.get(keyList.get(i))).intValue(); j++) { + tokensList.put(((JSONArray)bnk.get(i)).getJSONObject(j).getString("tokenHash")); + tokenHeader.put(tknmap.get(String.valueOf(keyList.get(i)))); + } + } + } catch (JSONException e) { + FractionChooserLogger.error("JSON Exception Occurred", (Throwable)e); + e.printStackTrace(); + } + FractionChooserLogger.debug("Tokens chosen to be sent: " + tokensList); + return tokensList; + } +} + diff --git a/src/com/rubix/Resources/Functions.java b/src/com/rubix/Resources/Functions.java index b542d6b3..7798a374 100644 --- a/src/com/rubix/Resources/Functions.java +++ b/src/com/rubix/Resources/Functions.java @@ -1,22 +1,24 @@ package com.rubix.Resources; -import com.rubix.AuthenticateNode.PropImage; -import com.rubix.Ping.PingCheck; -import io.ipfs.api.IPFS; -import io.ipfs.multiaddr.MultiAddress; -import org.apache.log4j.Logger; -import org.apache.log4j.PropertyConfigurator; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; +import static com.rubix.Resources.APIHandler.addPublicData; +import static com.rubix.Resources.IPFSNetwork.IPFSNetworkLogger; +import static com.rubix.Resources.IPFSNetwork.checkSwarmConnect; +import static com.rubix.Resources.IPFSNetwork.executeIPFSCommands; +import static com.rubix.Resources.IPFSNetwork.forwardCheck; +import static com.rubix.Resources.IPFSNetwork.listen; +import static com.rubix.Resources.IPFSNetwork.swarmConnectP2P; +import static com.rubix.Resources.IPFSNetwork.swarmConnectProcess; -import javax.imageio.ImageIO; import java.awt.image.BufferedImage; -import java.io.*; +import java.io.BufferedReader; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStreamReader; import java.math.RoundingMode; import java.net.HttpURLConnection; -import java.net.Socket; -import java.net.SocketException; import java.net.URL; import java.nio.charset.StandardCharsets; import java.nio.file.Files; @@ -29,10 +31,21 @@ import java.util.ArrayList; import java.util.Date; import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.Set; -import static com.rubix.Resources.APIHandler.addPublicData; -import static com.rubix.Resources.IPFSNetwork.*; +import javax.imageio.ImageIO; +import com.rubix.AuthenticateNode.PropImage; +import com.rubix.Ping.PingCheck; + +import org.apache.log4j.PropertyConfigurator; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import io.ipfs.api.IPFS; +import io.ipfs.multiaddr.MultiAddress; public class Functions { @@ -43,7 +56,8 @@ public class Functions { public static String LOGGER_PATH = ""; public static String WALLET_DATA_PATH = ""; public static String PAYMENTS_PATH = ""; - public static int RECEIVER_PORT, GOSSIP_SENDER, GOSSIP_RECEIVER, QUORUM_PORT, SENDER2Q1, SENDER2Q2, SENDER2Q3, SENDER2Q4, SENDER2Q5, SENDER2Q6, SENDER2Q7; + public static int RECEIVER_PORT, GOSSIP_SENDER, GOSSIP_RECEIVER, QUORUM_PORT, SENDER2Q1, SENDER2Q2, SENDER2Q3, + SENDER2Q4, SENDER2Q5, SENDER2Q6, SENDER2Q7; public static int QUORUM_COUNT; public static int SEND_PORT; public static int IPFS_PORT; @@ -122,13 +136,11 @@ public static void pathSet() { BOOTSTRAPS = pathsArray.getJSONArray(5); - } catch (JSONException e) { e.printStackTrace(); } } - public static void nodeData(String did, String wid, IPFS ipfs) throws IOException { PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); File dataFolder = new File(DATA_PATH + did + "/"); @@ -202,9 +214,9 @@ public static String getSystemUser() { return lineID; } - /** - * This method calculates different types of hashes as mentioned in the passed parameters for the mentioned message + * This method calculates different types of hashes as mentioned in the passed + * parameters for the mentioned message * * @param message Input string to be hashed * @param algorithm Specification of the algorithm used for hashing @@ -271,13 +283,13 @@ public static String bytesToHex(byte[] inputHash) { StringBuilder outputHexString = new StringBuilder(); for (byte b : inputHash) { String hex = Integer.toHexString(0xff & b); - if (hex.length() == 1) outputHexString.append('0'); + if (hex.length() == 1) + outputHexString.append('0'); outputHexString.append(hex); } return outputHexString.toString(); } - /** * This method returns the content of the file passed to it * @@ -299,14 +311,15 @@ public static String readFile(String filePath) { return fileContent.toString(); } - /** * This method writes the mentioned data into the file passed to it - * This also allows to take a decision on whether or not to append the data to the already existing content in the file + * This also allows to take a decision on whether or not to append the data to + * the already existing content in the file * * @param filePath Location of the file to be read and written into * @param data Data to be added - * @param appendStatus Decides whether or not to append the new data into the already existing data + * @param appendStatus Decides whether or not to append the new data into the + * already existing data */ public synchronized static void writeToFile(String filePath, String data, Boolean appendStatus) { @@ -347,7 +360,6 @@ public static String getSignFromShares(String filePath, String hash) throws IOEx return p1; } - /** * This function will sign on JSON data with private share * @@ -392,7 +404,6 @@ public static void listenThread(JSONObject connectObject) { } - /** * This function converts any integer to its binary form * @@ -479,7 +490,8 @@ public static void updateJSON(String operation, String filePath, String data) { } /** - * This method gets you a required data from a JSON file with a tag to be compared with + * This method gets you a required data from a JSON file with a tag to be + * compared with * * @param filePath Location of the JSON file * @param get Data to be fetched from the file @@ -516,7 +528,8 @@ public static String getOsName() { } /** - * This function calculates the minimum number of quorum peers required for consensus to work + * This function calculates the minimum number of quorum peers required for + * consensus to work * * @return Minimum number of quorum count for consensus to work */ @@ -525,7 +538,8 @@ public static int minQuorum() { } /** - * This function calculates the minimum number of quorum peers required for consensus to work + * This function calculates the minimum number of quorum peers required for + * consensus to work * * @return Minimum number of quorum count for consensus to work */ @@ -533,7 +547,6 @@ public static int minQuorum(int count) { return (((count - 1) / 3) * 2) + 1; } - /** * This method checks if Quorum is available for consensus * @@ -572,7 +585,6 @@ public static ArrayList QuorumCheck(JSONArray quorum, int size) { * @param ipfs ipfs instance */ - public static void QuorumSwarmConnect(JSONArray quorum, IPFS ipfs) { PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); @@ -591,7 +603,6 @@ public static void QuorumSwarmConnect(JSONArray quorum, IPFS ipfs) { } - /** * This method identifies the Peer ID of the system by IPFS during installation * @@ -599,7 +610,6 @@ public static void QuorumSwarmConnect(JSONArray quorum, IPFS ipfs) { * @return Your system's Peer ID assigned by IPFS */ - public static String getPeerID(String filePath) { PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); JSONArray fileContentArray; @@ -617,7 +627,6 @@ public static String getPeerID(String filePath) { return peerid; } - public static int[] getPrivatePosition(int[] positions, int[] privateArray) { int[] PrivatePosition = new int[positions.length]; for (int k = 0; k < positions.length; k++) { @@ -628,7 +637,8 @@ public static int[] getPrivatePosition(int[] positions, int[] privateArray) { return PrivatePosition; } - public static JSONObject randomPositions(String role, String hash, int numberOfPositions, int[] pvt1) throws JSONException { + public static JSONObject randomPositions(String role, String hash, int numberOfPositions, int[] pvt1) + throws JSONException { int u = 0, l = 0, m = 0; int[] hashCharacters = new int[256]; @@ -685,18 +695,19 @@ public static JSONObject randomPositions(String role, String hash, int numberOfP * @param positionsCount Number of positions required * @return Extended array of positions */ -// public static int[] finalPositions(int[] randomPositions, int positionsCount) { -// int[] finalPositions = new int[positionsCount * 64]; -// int u = 0; -// for (int k = 0; k < positionsCount; k++) { -// for (int p = 0; p < 64; p++) { -// finalPositions[u] = randomPositions[k]; -// randomPositions[k]++; -// u++; -// } -// } -// return finalPositions; -// } + // public static int[] finalPositions(int[] randomPositions, int positionsCount) + // { + // int[] finalPositions = new int[positionsCount * 64]; + // int u = 0; + // for (int k = 0; k < positionsCount; k++) { + // for (int p = 0; p < 64; p++) { + // finalPositions[u] = randomPositions[k]; + // randomPositions[k]++; + // u++; + // } + // } + // return finalPositions; + // } /** * This function deletes the mentioned file @@ -714,41 +725,43 @@ public static void deleteFile(String fileName) { } - -// /** -// * This functions picks the required number of quorum members from the mentioned file -// * -// * @param filePath Location of the file -// * @param hash Data from which positions are chosen -// * @return List of chosen members from the file -// */ -// public static ArrayList quorumChooser(String filePath, String hash) { -// PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); -// ArrayList quorumList = new ArrayList(); -// try { -// String fileContent = readFile(filePath); -// JSONArray blockHeight = new JSONArray(fileContent); -// -// int[] hashCharacters = new int[256]; -// var randomPositions = new ArrayList(); -// HashSet positionSet = new HashSet<>(); -// for (int k = 0; positionSet.size() != 7; k++) { -// hashCharacters[k] = Character.getNumericValue(hash.charAt(k)); -// randomPositions.add((((2402 + hashCharacters[k]) * 2709) + ((k + 2709) + hashCharacters[(k)])) % blockHeight.length()); -// positionSet.add(randomPositions.get(k)); -// } -// -// for (Integer integer : positionSet) -// quorumList.add(blockHeight.getJSONObject(integer).getString("peer-id")); -// } catch (JSONException e) { -// FunctionsLogger.error("JSON Exception Occurred", e); -// e.printStackTrace(); -// } -// return quorumList; -// } + // /** + // * This functions picks the required number of quorum members from the + // mentioned file + // * + // * @param filePath Location of the file + // * @param hash Data from which positions are chosen + // * @return List of chosen members from the file + // */ + // public static ArrayList quorumChooser(String filePath, String hash) { + // PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); + // ArrayList quorumList = new ArrayList(); + // try { + // String fileContent = readFile(filePath); + // JSONArray blockHeight = new JSONArray(fileContent); + // + // int[] hashCharacters = new int[256]; + // var randomPositions = new ArrayList(); + // HashSet positionSet = new HashSet<>(); + // for (int k = 0; positionSet.size() != 7; k++) { + // hashCharacters[k] = Character.getNumericValue(hash.charAt(k)); + // randomPositions.add((((2402 + hashCharacters[k]) * 2709) + ((k + 2709) + + // hashCharacters[(k)])) % blockHeight.length()); + // positionSet.add(randomPositions.get(k)); + // } + // + // for (Integer integer : positionSet) + // quorumList.add(blockHeight.getJSONObject(integer).getString("peer-id")); + // } catch (JSONException e) { + // FunctionsLogger.error("JSON Exception Occurred", e); + // e.printStackTrace(); + // } + // return quorumList; + // } /** - * This function is to be initially called to setup the environment of your project + * This function is to be initially called to setup the environment of your + * project */ public static void launch() { pathSet(); @@ -794,7 +807,8 @@ public static String checkDirectory() throws JSONException { File tokenChainsFolder = new File(TOKENCHAIN_PATH); File walletDataFolder = new File(WALLET_DATA_PATH); - if (!dataFolder.exists() || !loggerFolder.exists() || !tokenChainsFolder.exists() || !tokensFolder.exists() || !walletDataFolder.exists()) { + if (!dataFolder.exists() || !loggerFolder.exists() || !tokenChainsFolder.exists() || !tokensFolder.exists() + || !walletDataFolder.exists()) { dataFolder.delete(); loggerFolder.delete(); tokenChainsFolder.delete(); @@ -871,7 +885,6 @@ public static String mineToken(int level, int tokenNumber) { return token; } - public static String toBinary(int x, int len) { if (len > 0) { return String.format("%" + len + "s", @@ -908,7 +921,6 @@ public static Date getCurrentUtcTime() throws ParseException { return localDateFormat.parse(simpleDateFormat.format(new Date())); } - /** * This method is used to update quorum credits in server * @@ -919,8 +931,8 @@ public static Date getCurrentUtcTime() throws ParseException { * @return mined token */ - - public static void updateQuorum(JSONArray quorumArray, JSONArray signedQuorumList, boolean status, int type) throws IOException, JSONException { + public static void updateQuorum(JSONArray quorumArray, JSONArray signedQuorumList, boolean status, int type) + throws IOException, JSONException { if (type == 1) { String urlQuorumUpdate = ADVISORY_IP + "/updateQuorum"; @@ -962,7 +974,6 @@ public static void updateQuorum(JSONArray quorumArray, JSONArray signedQuorumLis } } - /** * This method is used get getquorum from advisory node * @@ -974,8 +985,8 @@ public static void updateQuorum(JSONArray quorumArray, JSONArray signedQuorumLis * @return JSONArray of quorum nodes */ - - public static JSONArray getQuorum(String betaHash, String gammaHash, String senderDidIpfsHash, String receiverDidIpfsHash, int tokenslength) throws IOException, JSONException { + public static JSONArray getQuorum(String betaHash, String gammaHash, String senderDidIpfsHash, + String receiverDidIpfsHash, int tokenslength) throws IOException, JSONException { JSONArray quorumArray; String urlQuorumPick = ADVISORY_IP + "/getQuorum"; URL objQuorumPick = new URL(urlQuorumPick); @@ -1193,9 +1204,11 @@ public static Double getPartsBalance() throws JSONException { Double availableParts = 0.000D, senderCount = 0.000D, receiverCount = 0.000D; for (int k = 0; k < tokenChainArray.length(); k++) { if (tokenChainArray.getJSONObject(k).has("role")) { - if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { + if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") + && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { senderCount += tokenChainArray.getJSONObject(k).getDouble("amount"); - } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { + } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") + && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { receiverCount += tokenChainArray.getJSONObject(k).getDouble("amount"); } } @@ -1208,7 +1221,6 @@ public static Double getPartsBalance() throws JSONException { parts = formatAmount(parts); balance = balance + parts; - int count = 0; File shiftedFile = new File(PAYMENTS_PATH.concat("ShiftedTokens.json")); if (shiftedFile.exists()) { @@ -1218,7 +1230,6 @@ public static Double getPartsBalance() throws JSONException { for (int i = 0; i < shiftedArray.length(); i++) arrayTokens.add(shiftedArray.getString(i)); - for (int i = 0; i < partTokensArray.length(); i++) { if (!arrayTokens.contains(partTokensArray.getJSONObject(i).getString("tokenHash"))) count++; @@ -1246,9 +1257,11 @@ public static Double checkTokenPartBalance(String tokenHash) throws JSONExceptio Double senderCount = 0.000D, receiverCount = 0.000D; for (int k = 0; k < tokenChainArray.length(); k++) { if (tokenChainArray.getJSONObject(k).has("role")) { - if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { + if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") + && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { senderCount += tokenChainArray.getJSONObject(k).getDouble("amount"); - } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { + } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") + && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { receiverCount += tokenChainArray.getJSONObject(k).getDouble("amount"); } } @@ -1265,7 +1278,6 @@ public static Double checkTokenPartBalance(String tokenHash) throws JSONExceptio return availableParts; } - public static Double getBalance() throws JSONException { pathSet(); Double balance = 0.000D; @@ -1284,7 +1296,6 @@ public static Double getBalance() throws JSONException { balance = balance + value; } - File partsFile = new File(PAYMENTS_PATH + "PartsToken.json"); if (partsFile.exists()) { String PART_TOKEN_CHAIN_PATH = TOKENCHAIN_PATH.concat("/PARTS/"); @@ -1303,9 +1314,11 @@ public static Double getBalance() throws JSONException { Double availableParts = 0.000D, senderCount = 0.000D, receiverCount = 0.000D; for (int k = 0; k < tokenChainArray.length(); k++) { if (tokenChainArray.getJSONObject(k).has("role")) { - if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { + if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") + && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { senderCount += tokenChainArray.getJSONObject(k).getDouble("amount"); - } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { + } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") + && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { receiverCount += tokenChainArray.getJSONObject(k).getDouble("amount"); } } @@ -1328,7 +1341,6 @@ public static Double getBalance() throws JSONException { for (int i = 0; i < shiftedArray.length(); i++) arrayTokens.add(shiftedArray.getString(i)); - for (int i = 0; i < partTokensArray.length(); i++) { if (!arrayTokens.contains(partTokensArray.getJSONObject(i).getString("tokenHash"))) count++; @@ -1339,12 +1351,10 @@ public static Double getBalance() throws JSONException { balance = balance - count; } - balance = formatAmount(balance); return balance; } - public static Double partTokenBalance(String tokenHash) throws JSONException { pathSet(); @@ -1358,9 +1368,11 @@ public static Double partTokenBalance(String tokenHash) throws JSONException { Double senderCount = 0.000D, receiverCount = 0.000D; for (int k = 0; k < tokenChainArray.length(); k++) { if (tokenChainArray.getJSONObject(k).has("role")) { - if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { + if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") + && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { senderCount += tokenChainArray.getJSONObject(k).getDouble("amount"); - } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { + } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") + && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { receiverCount += tokenChainArray.getJSONObject(k).getDouble("amount"); } } @@ -1393,7 +1405,8 @@ public static void clearParts() { String partsFile = readFile(PAYMENTS_PATH.concat("PartsToken.json")); JSONArray partsArray = new JSONArray(partsFile); for (int i = 0; i < partsArray.length(); i++) { - if (partTokenBalance(partsArray.getJSONObject(i).getString("tokenHash")) <= 0.000 || partTokenBalance(partsArray.getJSONObject(i).getString("tokenHash")) > 1.000) { + if (partTokenBalance(partsArray.getJSONObject(i).getString("tokenHash")) <= 0.000 + || partTokenBalance(partsArray.getJSONObject(i).getString("tokenHash")) > 1.000) { deleteFile(TOKENS_PATH.concat("PARTS/").concat(partsArray.getJSONObject(i).getString("tokenHash"))); partsArray.remove(i); } @@ -1420,7 +1433,9 @@ public static void backgroundChecks() { addPublicData(); } + public static String sanityMessage; + public static boolean sanityCheck(String peerid, IPFS ipfs, int port) throws IOException { FunctionsLogger.info("Entering SanityCheck"); boolean sanityCheckErrorFlag = true; @@ -1469,9 +1484,9 @@ public static boolean sanityCheck(String peerid, IPFS ipfs, int port) throws IOE } } - return sanityCheckErrorFlag; } + public static boolean checkIPFSStatus(String peerid, IPFS ipfs) { FunctionsLogger.info("Entering checkIPFSStatus"); boolean swarmConnectedStatus = false; @@ -1479,7 +1494,7 @@ public static boolean checkIPFSStatus(String peerid, IPFS ipfs) { MultiAddress multiAddress = new MultiAddress("/ipfs/" + peerid); FunctionsLogger.info("MultiAdrress concated " + multiAddress + "|||"); boolean output = swarmConnectP2P(peerid, ipfs); - FunctionsLogger.info("Swarm connect process response is " + output); + if (output) { swarmConnectedStatus = true; FunctionsLogger.debug("Swarm is already connected"); @@ -1495,7 +1510,6 @@ public static boolean checkIPFSStatus(String peerid, IPFS ipfs) { return swarmConnectedStatus; } - public static boolean ping(String peerid, int port) throws IOException { JSONObject pingCheck = PingCheck.Ping(peerid, port); if (pingCheck.getString("status").contains("Failed")) { @@ -1505,48 +1519,50 @@ public static boolean ping(String peerid, int port) throws IOException { } -// public static String getPing(int port) { -// try { -// -// String didContent = readFile(DATA_PATH + "DID.json"); -// JSONArray didArray = new JSONArray(didContent); -// String myPeerID = didArray.getJSONObject(0).getString("peerid"); -// -// listen(myPeerID.concat("Ping"), port); -// ServerSocket ss = new ServerSocket(port); -// FunctionsLogger.info("Get Ping Listening on port " + port + " appname " + myPeerID.concat("Ping")); -// Socket socket = ss.accept(); -// BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream())); -// PrintStream output = new PrintStream(socket.getOutputStream()); -// FunctionsLogger.info("getPing- waiting response from server"); -// String peerID = input.readLine(); -// if (peerID != null && peerID.contains("Qm")) { -// FunctionsLogger.info("getPing - Received message from server"); -// output.println("Ping received"); -// FunctionsLogger.debug("Ping received from sender"); -// -// output.close(); -// input.close(); -// socket.close(); -// ss.close(); -// executeIPFSCommands(" ipfs p2p close -t /p2p/" + peerID); -// FunctionsLogger.info("If - Closing Sockets"); -// return "Ping received from sender and Pong sent"; -// } -// else{ -// output.close(); -// input.close(); -// socket.close(); -// ss.close(); -// FunctionsLogger.info("Else - Closing Sockets"); -// return "Ping received from sender but not PeerID"; -// } -// -// } catch (Exception e) { -// FunctionsLogger.error("Error in client side communication", e); -// return "Error in client side communication"; -// } -// } + // public static String getPing(int port) { + // try { + // + // String didContent = readFile(DATA_PATH + "DID.json"); + // JSONArray didArray = new JSONArray(didContent); + // String myPeerID = didArray.getJSONObject(0).getString("peerid"); + // + // listen(myPeerID.concat("Ping"), port); + // ServerSocket ss = new ServerSocket(port); + // FunctionsLogger.info("Get Ping Listening on port " + port + " appname " + + // myPeerID.concat("Ping")); + // Socket socket = ss.accept(); + // BufferedReader input = new BufferedReader(new + // InputStreamReader(socket.getInputStream())); + // PrintStream output = new PrintStream(socket.getOutputStream()); + // FunctionsLogger.info("getPing- waiting response from server"); + // String peerID = input.readLine(); + // if (peerID != null && peerID.contains("Qm")) { + // FunctionsLogger.info("getPing - Received message from server"); + // output.println("Ping received"); + // FunctionsLogger.debug("Ping received from sender"); + // + // output.close(); + // input.close(); + // socket.close(); + // ss.close(); + // executeIPFSCommands(" ipfs p2p close -t /p2p/" + peerID); + // FunctionsLogger.info("If - Closing Sockets"); + // return "Ping received from sender and Pong sent"; + // } + // else{ + // output.close(); + // input.close(); + // socket.close(); + // ss.close(); + // FunctionsLogger.info("Else - Closing Sockets"); + // return "Ping received from sender but not PeerID"; + // } + // + // } catch (Exception e) { + // FunctionsLogger.error("Error in client side communication", e); + // return "Error in client side communication"; + // } + // } public static boolean bootstrapConnect(String peerid, IPFS ipfs) { FunctionsLogger.info("bootstrapConnect- entering function"); @@ -1620,7 +1636,8 @@ public static boolean portCheckAndKill(int port) { } /** - * This function will release the port in linux based machines if the port is already in use + * This function will release the port in linux based machines if the port is + * already in use */ public static boolean releasePorts(int port) { FunctionsLogger.info("releasePorts- "); @@ -1641,7 +1658,8 @@ public static boolean releasePorts(int port) { if (processStr != null) { FunctionsLogger.info("releasePorts- Processstr is not null"); if (String.valueOf(currentPid) != processStr && ipfsPidBr.readLine() != processStr) { - FunctionsLogger.info("releasePorts- jar is running on " + currentPid + " and IPFS is occupied in " + ipfsPidBr.readLine()); + FunctionsLogger.info("releasePorts- jar is running on " + currentPid + " and IPFS is occupied in " + + ipfsPidBr.readLine()); FunctionsLogger.debug("Port " + port + " is in using, killing PID " + processStr); processId = Runtime.getRuntime().exec("kill -9 " + processStr); FunctionsLogger.info("releasePorts- killing " + processStr); @@ -1664,36 +1682,50 @@ public static boolean releasePorts(int port) { public static boolean portStatusWindows(int port) { FunctionsLogger.info("Starting portStatusWindows"); boolean releasedPort = false; - String processStr; + String portProcessStr; Process p; + ArrayList pidTree = new ArrayList(); + ArrayList portPidTree = new ArrayList(); try { Runtime rt = Runtime.getRuntime(); - Process proc = rt.exec("cmd /c netstat -ano | findstr " + port); - FunctionsLogger.info("Checking port status"); - long currentPid = ProcessHandle.current().pid(); - BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream())); - processStr = stdInput.readLine(); - FunctionsLogger.info("Process id found for port is " + processStr + " current jar pid is " + currentPid); - if (processStr != null && String.valueOf(currentPid) != processStr) { - int index = processStr.lastIndexOf(" "); - String sc = processStr.substring(index, processStr.length()); - //System.out.println("Port "+port+" is locked by PID "+sc+". Kindly close this port and retry transcation"); - if (sc != String.valueOf(currentPid)) { - FunctionsLogger.debug("Port " + port + " is locked by PID " + sc); - } else { - FunctionsLogger.debug("Port " + port + " is locked by current jar with PID " + sc); - } + Process getJarPid = rt.exec("cmd /c netstat -ano | findstr 1898"); + BufferedReader getJarPidBR = new BufferedReader(new InputStreamReader(getJarPid.getInputStream())); + String getJarPidline; + while ((getJarPidline = getJarPidBR.readLine()) != null) { + String[] getJarPidTree = getJarPidline.split("\\s+"); + int temp = Integer.parseInt(getJarPidTree[getJarPidTree.length - 1]); + pidTree.add(temp); + } + + FunctionsLogger.info("PIDs occupied by Rubix.jar are " + pidTree); + + Set pidSet = new LinkedHashSet(pidTree); + FunctionsLogger.info("Pid occupied by port 1898 is pidSet" + pidSet); + Process getPortPid = rt.exec("cmd /c netstat -ano | findstr " + port); + BufferedReader getPortPidBr = new BufferedReader(new InputStreamReader(getPortPid.getInputStream())); + String getPortPidLine; + while ((getPortPidLine = getPortPidBr.readLine()) != null) { + String[] getPortPidTree = getPortPidLine.split("\\s+"); + int temp = Integer.parseInt(getPortPidTree[getPortPidTree.length - 1]); + portPidTree.add(temp); + } + + Set pidToKill = new LinkedHashSet(portPidTree); + FunctionsLogger.info("Pid used by port " + port + "is " + pidToKill); + pidToKill.removeAll(pidSet); + pidToKill.remove(0); + FunctionsLogger.info("Pid using port " + port + " but not in 1898" + pidToKill); + if (pidToKill.size() > 0) { + System.out.println("Port " + port + " is occupied by PIDs" + pidToKill); } else { releasedPort = true; - FunctionsLogger.info("Port is unlocked"); } + } catch (Exception e) { FunctionsLogger.error("Exception occured at portStatusWindows", e); - e.printStackTrace(); } return releasedPort; - } + } } - diff --git a/src/com/rubix/Resources/IPFSNetwork.java b/src/com/rubix/Resources/IPFSNetwork.java index 8de18094..728d6c2c 100644 --- a/src/com/rubix/Resources/IPFSNetwork.java +++ b/src/com/rubix/Resources/IPFSNetwork.java @@ -569,21 +569,23 @@ public static boolean swarmConnectP2P(String peerid, IPFS ipfs) throws JSONExcep output = swarmConnectProcess(multiAddress); if (!output.contains("success")) { IPFSNetworkLogger.debug("swarm attempt failed with " + peerid); + swarmConnected = false; } else { IPFSNetworkLogger.debug("swarm Connected : " + peerid); swarmConnected = true; } } else { IPFSNetworkLogger.debug("bootstrap connection failed! " + bootNode); + swarmConnected = false; } } } + }else { + swarmConnected = true; } - if(output.contains("success")) - return true; - else - return false; + return swarmConnected; + } } diff --git a/src/com/rubix/TokenTransfer/TokenReceiver.java b/src/com/rubix/TokenTransfer/TokenReceiver.java index 0b02049c..8f22637e 100644 --- a/src/com/rubix/TokenTransfer/TokenReceiver.java +++ b/src/com/rubix/TokenTransfer/TokenReceiver.java @@ -1,28 +1,61 @@ package com.rubix.TokenTransfer; +import static com.rubix.Resources.Functions.DATA_PATH; +import static com.rubix.Resources.Functions.FunctionsLogger; +import static com.rubix.Resources.Functions.IPFS_PORT; +import static com.rubix.Resources.Functions.LOGGER_PATH; +import static com.rubix.Resources.Functions.PAYMENTS_PATH; +import static com.rubix.Resources.Functions.RECEIVER_PORT; +import static com.rubix.Resources.Functions.TOKENCHAIN_PATH; +import static com.rubix.Resources.Functions.TOKENS_PATH; +import static com.rubix.Resources.Functions.WALLET_DATA_PATH; +import static com.rubix.Resources.Functions.calculateHash; +import static com.rubix.Resources.Functions.deleteFile; +import static com.rubix.Resources.Functions.formatAmount; +import static com.rubix.Resources.Functions.getCurrentUtcTime; +import static com.rubix.Resources.Functions.getPeerID; +import static com.rubix.Resources.Functions.getValues; +import static com.rubix.Resources.Functions.nodeData; +import static com.rubix.Resources.Functions.pathSet; +import static com.rubix.Resources.Functions.readFile; +import static com.rubix.Resources.Functions.syncDataTable; +import static com.rubix.Resources.Functions.updateJSON; +import static com.rubix.Resources.Functions.writeToFile; +import static com.rubix.Resources.IPFSNetwork.add; +import static com.rubix.Resources.IPFSNetwork.executeIPFSCommands; +import static com.rubix.Resources.IPFSNetwork.get; +import static com.rubix.Resources.IPFSNetwork.listen; +import static com.rubix.Resources.IPFSNetwork.pin; +import static com.rubix.Resources.IPFSNetwork.repo; +import static com.rubix.Resources.IPFSNetwork.swarmConnectP2P; + +import java.awt.image.BufferedImage; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintStream; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketException; +import java.util.ArrayList; +import java.util.Iterator; + +import javax.imageio.ImageIO; + import com.rubix.AuthenticateNode.Authenticate; import com.rubix.AuthenticateNode.PropImage; import com.rubix.Resources.Functions; import com.rubix.Resources.IPFSNetwork; -import io.ipfs.api.IPFS; + import org.apache.log4j.Logger; import org.apache.log4j.PropertyConfigurator; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; -import javax.imageio.ImageIO; -import java.awt.image.BufferedImage; -import java.io.*; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.SocketException; -import java.util.ArrayList; -import java.util.Iterator; - -import static com.rubix.Resources.Functions.*; -import static com.rubix.Resources.IPFSNetwork.*; - +import io.ipfs.api.IPFS; public class TokenReceiver { public static Logger TokenReceiverLogger = Logger.getLogger(TokenReceiver.class); @@ -117,7 +150,6 @@ public static String receive() { return APIResponse.toString(); } - nodeData(senderDidIpfsHash, senderWidIpfsHash, ipfs); File senderDIDFile = new File(DATA_PATH + senderDidIpfsHash + "/DID.png"); if (!senderDIDFile.exists()) { @@ -127,7 +159,7 @@ public static String receive() { APIResponse.put("status", "Failed"); APIResponse.put("message", "Sender details not available"); TokenReceiverLogger.info("Sender details not available"); - /* executeIPFSCommands(" ipfs p2p close -t /p2p/" + senderPeerID);*/ + /* executeIPFSCommands(" ipfs p2p close -t /p2p/" + senderPeerID); */ output.close(); input.close(); @@ -169,9 +201,9 @@ public static String receive() { JSONObject amountLedger = tokenObject.getJSONObject("amountLedger"); TokenReceiverLogger.debug("Amount Ledger: " + amountLedger); int intPart = wholeTokens.length(); - Double decimalPart = formatAmount(amount-intPart); + Double decimalPart = formatAmount(amount - intPart); JSONArray doubleSpentToken = new JSONArray(); - /*boolean tokenOwners = true; + boolean tokenOwners = true; ArrayList ownersArray = new ArrayList(); ArrayList previousSender = new ArrayList(); JSONArray ownersReceived = new JSONArray(); @@ -183,7 +215,8 @@ public static String receive() { if (ownersArray.size() > 2) { for (int j = 0; j < previousSendersArray.length(); j++) { - if (previousSendersArray.getJSONObject(j).getString("token").equals(wholeTokens.getString(i))) + if (previousSendersArray.getJSONObject(j).getString("token") + .equals(wholeTokens.getString(i))) ownersReceived = previousSendersArray.getJSONObject(j).getJSONArray("sender"); } @@ -221,7 +254,7 @@ public static String receive() { sk.close(); ss.close(); return APIResponse.toString(); - }*/ + } String senderToken = TokenDetails.toString(); String consensusID = calculateHash(senderToken, "SHA3-256"); @@ -229,7 +262,7 @@ public static String receive() { String consensusIDIPFSHash = IPFSNetwork.addHashOnly(LOGGER_PATH + "consensusID", ipfs); deleteFile(LOGGER_PATH + "consensusID"); - /*if (!IPFSNetwork.dhtEmpty(consensusIDIPFSHash, ipfs)) { + if (!IPFSNetwork.dhtEmpty(consensusIDIPFSHash, ipfs)) { TokenReceiverLogger.debug("consensus ID not unique" + consensusIDIPFSHash); output.println("421"); APIResponse.put("did", senderDidIpfsHash); @@ -242,9 +275,9 @@ public static String receive() { sk.close(); ss.close(); return APIResponse.toString(); - }*/ + } - //Check IPFS get for all Tokens + // Check IPFS get for all Tokens int ipfsGetFlag = 0; ArrayList allTokenContent = new ArrayList<>(); ArrayList allTokenChainContent = new ArrayList<>(); @@ -283,7 +316,7 @@ public static String receive() { } boolean chainFlag = true; - for(int i = 0; i < partTokenChainContent.length(); i++) { + for (int i = 0; i < partTokenChainContent.length(); i++) { JSONArray tokenChainContent = partTokenChainContent.getJSONArray(i); for (int j = 0; j < tokenChainContent.length(); j++) { String previousHash = tokenChainContent.getJSONObject(j).getString("previousHash"); @@ -293,14 +326,17 @@ public static String receive() { if (j == 0) { rePreviousHash = ""; String rePrev = calculateHash(new JSONObject().toString(), "SHA3-256"); - reNextHash = calculateHash(tokenChainContent.getJSONObject(j + 1).getString("tid"), "SHA3-256"); + reNextHash = calculateHash(tokenChainContent.getJSONObject(j + 1).getString("tid"), + "SHA3-256"); - if (!((rePreviousHash.equals(previousHash) || rePrev.equals(previousHash)) && reNextHash.equals(nextHash))) { + if (!((rePreviousHash.equals(previousHash) || rePrev.equals(previousHash)) + && reNextHash.equals(nextHash))) { chainFlag = false; } } else if (j == tokenChainContent.length() - 1) { - rePreviousHash = calculateHash(tokenChainContent.getJSONObject(j - 1).getString("tid"), "SHA3-256"); + rePreviousHash = calculateHash(tokenChainContent.getJSONObject(j - 1).getString("tid"), + "SHA3-256"); reNextHash = ""; if (!(rePreviousHash.equals(previousHash) && reNextHash.equals(nextHash))) { @@ -308,8 +344,10 @@ public static String receive() { } } else { - rePreviousHash = calculateHash(tokenChainContent.getJSONObject(j - 1).getString("tid"), "SHA3-256"); - reNextHash = calculateHash(tokenChainContent.getJSONObject(j + 1).getString("tid"), "SHA3-256"); + rePreviousHash = calculateHash(tokenChainContent.getJSONObject(j - 1).getString("tid"), + "SHA3-256"); + reNextHash = calculateHash(tokenChainContent.getJSONObject(j + 1).getString("tid"), + "SHA3-256"); if (!(rePreviousHash.equals(previousHash) && reNextHash.equals(nextHash))) { chainFlag = false; @@ -336,14 +374,16 @@ public static String receive() { } boolean partsAvailable = true; - for(int i = 0; i < partTokenChainContent.length(); i++){ + for (int i = 0; i < partTokenChainContent.length(); i++) { Double senderCount = 0.000D, receiverCount = 0.000D; JSONArray tokenChainContent = partTokenChainContent.getJSONArray(i); for (int k = 0; k < tokenChainContent.length(); k++) { if (tokenChainContent.getJSONObject(k).has("role")) { - if (tokenChainContent.getJSONObject(k).getString("role").equals("Sender") && tokenChainContent.getJSONObject(k).getString("sender").equals(senderDidIpfsHash)) { + if (tokenChainContent.getJSONObject(k).getString("role").equals("Sender") + && tokenChainContent.getJSONObject(k).getString("sender").equals(senderDidIpfsHash)) { senderCount += tokenChainContent.getJSONObject(k).getDouble("amount"); - } else if (tokenChainContent.getJSONObject(k).getString("role").equals("Receiver") && tokenChainContent.getJSONObject(k).getString("receiver").equals(senderDidIpfsHash)) { + } else if (tokenChainContent.getJSONObject(k).getString("role").equals("Receiver") + && tokenChainContent.getJSONObject(k).getString("receiver").equals(senderDidIpfsHash)) { receiverCount += tokenChainContent.getJSONObject(k).getDouble("amount"); } } @@ -356,13 +396,13 @@ public static String receive() { availableParts += amountLedger.getDouble(partTokens.getString(i)); availableParts = formatAmount(availableParts); - if(availableParts > 1.000D) { + if (availableParts > 1.000D) { TokenReceiverLogger.debug("Token wholly spent: " + partTokens.getString(i)); TokenReceiverLogger.debug("Parts: " + availableParts); } } - if (!partsAvailable) { + if (!partsAvailable) { String errorMessage = "Token wholly spent already"; output.println("424"); APIResponse.put("did", senderDidIpfsHash); @@ -376,10 +416,9 @@ public static String receive() { sk.close(); ss.close(); return APIResponse.toString(); - }else + } else output.println("200"); - String senderDetails; try { senderDetails = input.readLine(); @@ -407,7 +446,6 @@ public static String receive() { BufferedImage senderWidImage = ImageIO.read(new File(DATA_PATH + senderDidIpfsHash + "/PublicShare.png")); SenWalletBin = PropImage.img2bin(senderWidImage); - TokenReceiverLogger.debug("Verifying Quorum ... "); TokenReceiverLogger.debug("Please wait, this might take a few seconds"); @@ -426,7 +464,8 @@ public static String receive() { for (String quorumDidIpfsHash : quorumDID) { syncDataTable(quorumDidIpfsHash, null); - String quorumWidIpfsHash = getValues(DATA_PATH + "DataTable.json", "walletHash", "didHash", quorumDidIpfsHash); + String quorumWidIpfsHash = getValues(DATA_PATH + "DataTable.json", "walletHash", "didHash", + quorumDidIpfsHash); nodeData(quorumDidIpfsHash, quorumWidIpfsHash, ipfs); } @@ -448,7 +487,10 @@ public static String receive() { for (int i = 0; i < intPart; i++) wholeTokenChainHash.put(wholeTokenChains.getString(i)); - String hash = calculateHash(wholeTokens.toString() + wholeTokenChainHash.toString() + partTokens.toString() + partTokenChainsHash.toString() + receiverDidIpfsHash + senderDidIpfsHash + comment, "SHA3-256"); + String hash = calculateHash( + wholeTokens.toString() + wholeTokenChainHash.toString() + partTokens.toString() + + partTokenChainsHash.toString() + receiverDidIpfsHash + senderDidIpfsHash + comment, + "SHA3-256"); TokenReceiverLogger.debug("Hash to verify Sender: " + hash); JSONObject detailsForVerify = new JSONObject(); detailsForVerify.put("did", senderDidIpfsHash); @@ -565,7 +607,7 @@ public static String receive() { writeToFile(TOKENCHAIN_PATH + wholeTokens.getString(i) + ".json", arr1.toString(), false); } - for(int i = 0; i < partTokens.length(); i++){ + for (int i = 0; i < partTokens.length(); i++) { JSONObject chequeObject = new JSONObject(); chequeObject.put("sender", senderDidIpfsHash); chequeObject.put("receiver", receiverDidIpfsHash); @@ -579,7 +621,6 @@ public static String receive() { String chequeHash = IPFSNetwork.add(LOGGER_PATH.concat(partTokens.getString(i)), ipfs); deleteFile(LOGGER_PATH.concat(partTokens.getString(i))); - JSONObject newPartObject = new JSONObject(); newPartObject.put("senderSign", senderSignature); newPartObject.put("sender", senderDidIpfsHash); @@ -587,37 +628,42 @@ public static String receive() { newPartObject.put("comment", comment); newPartObject.put("tid", tid); newPartObject.put("nextHash", ""); - if(partTokenChainContent.getJSONArray(i).length() == 0) + if (partTokenChainContent.getJSONArray(i).length() == 0) newPartObject.put("previousHash", ""); else - newPartObject.put("previousHash", calculateHash(partTokenChainContent.getJSONArray(i).getJSONObject(partTokenChainContent.getJSONArray(i).length() - 1).getString("tid"), "SHA3-256")); - + newPartObject.put("previousHash", + calculateHash(partTokenChainContent.getJSONArray(i) + .getJSONObject(partTokenChainContent.getJSONArray(i).length() - 1) + .getString("tid"), "SHA3-256")); newPartObject.put("amount", partAmount); newPartObject.put("cheque", chequeHash); newPartObject.put("role", "Receiver"); - File chainFile = new File(PART_TOKEN_CHAIN_PATH.concat(partTokens.getString(i)).concat(".json")); + File chainFile = new File( + PART_TOKEN_CHAIN_PATH.concat(partTokens.getString(i)).concat(".json")); if (chainFile.exists()) { String readChain = readFile(PART_TOKEN_CHAIN_PATH + partTokens.getString(i) + ".json"); JSONArray readChainArray = new JSONArray(readChain); - readChainArray.put(partTokenChainContent.getJSONArray(i).getJSONObject(partTokenChainContent.getJSONArray(i).length() - 1)); + readChainArray.put(partTokenChainContent.getJSONArray(i) + .getJSONObject(partTokenChainContent.getJSONArray(i).length() - 1)); readChainArray.put(newPartObject); - writeToFile(PART_TOKEN_CHAIN_PATH + partTokens.getString(i) + ".json", readChainArray.toString(), false); - + writeToFile(PART_TOKEN_CHAIN_PATH + partTokens.getString(i) + ".json", + readChainArray.toString(), false); } else { partTokenChainContent.getJSONArray(i).put(newPartObject); - writeToFile(PART_TOKEN_CHAIN_PATH + partTokens.getString(i) + ".json", partTokenChainContent.getJSONArray(i).toString(), false); + writeToFile(PART_TOKEN_CHAIN_PATH + partTokens.getString(i) + ".json", + partTokenChainContent.getJSONArray(i).toString(), false); } } JSONArray allTokens = new JSONArray(); - for(int i = 0; i < wholeTokens.length(); i++) + for (int i = 0; i < wholeTokens.length(); i++) allTokens.put(wholeTokens.getString(i)); - for(int i = 0; i < partTokens.length(); i++) + for (int i = 0; i < partTokens.length(); i++) allTokens.put(partTokens.getString(i)); JSONObject transactionRecord = new JSONObject(); @@ -636,7 +682,8 @@ public static String receive() { JSONArray transactionHistoryEntry = new JSONArray(); transactionHistoryEntry.put(transactionRecord); - updateJSON("add", WALLET_DATA_PATH + "TransactionHistory.json", transactionHistoryEntry.toString()); + updateJSON("add", WALLET_DATA_PATH + "TransactionHistory.json", + transactionHistoryEntry.toString()); for (int i = 0; i < wholeTokens.length(); i++) { String bankFile = readFile(PAYMENTS_PATH.concat("BNK00.json")); @@ -651,13 +698,14 @@ public static String receive() { String partsFile = readFile(PAYMENTS_PATH.concat("PartsToken.json")); JSONArray partsReadArray = new JSONArray(partsFile); - for(int i = 0; i < partTokens.length(); i++){ + for (int i = 0; i < partTokens.length(); i++) { boolean writeParts = true; - for(int j = 0; j < partsReadArray.length(); j++){ - if(partsReadArray.getJSONObject(j).getString("tokenHash").equals(partTokens.getString(i))) + for (int j = 0; j < partsReadArray.length(); j++) { + if (partsReadArray.getJSONObject(j).getString("tokenHash") + .equals(partTokens.getString(i))) writeParts = false; } - if(writeParts) { + if (writeParts) { JSONObject partObject = new JSONObject(); partObject.put("tokenHash", partTokens.getString(i)); partsReadArray.put(partObject); diff --git a/src/com/rubix/TokenTransfer/TokenSender.java b/src/com/rubix/TokenTransfer/TokenSender.java index 6935efad..2ebedd31 100644 --- a/src/com/rubix/TokenTransfer/TokenSender.java +++ b/src/com/rubix/TokenTransfer/TokenSender.java @@ -583,17 +583,17 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception TokenSenderLogger.info("Multiple Owners for " + doubleSpent); APIResponse.put("message", "Multiple Owners for " + doubleSpent); APIResponse.put("Owners", ownersArray); -// removeToken(); + removeToken(); break; case "421": TokenSenderLogger.info("Consensus ID not unique"); APIResponse.put("message", "Consensus ID not unique"); -// removeToken(); + removeToken(); break; case "422": TokenSenderLogger.info("Tokens Not Verified"); APIResponse.put("message", "Tokens Not Verified"); -// removeToken(); + removeToken(); break; case "423": TokenSenderLogger.info("Broken Cheque Chain"); From 43b3153f691e1e19fc9ef1318d436197e337ef6f Mon Sep 17 00:00:00 2001 From: Kiran H Date: Fri, 11 Mar 2022 14:10:32 +0530 Subject: [PATCH 23/49] removed old NFT code --- src/com/rubix/NFT/Buyer.java | 411 ---------------------------- src/com/rubix/NFT/Seller.java | 497 ---------------------------------- 2 files changed, 908 deletions(-) delete mode 100644 src/com/rubix/NFT/Buyer.java delete mode 100644 src/com/rubix/NFT/Seller.java diff --git a/src/com/rubix/NFT/Buyer.java b/src/com/rubix/NFT/Buyer.java deleted file mode 100644 index 3d7cbec8..00000000 --- a/src/com/rubix/NFT/Buyer.java +++ /dev/null @@ -1,411 +0,0 @@ -package com.rubix.NFT; - - -import com.rubix.AuthenticateNode.Authenticate; -import com.rubix.Resources.FractionChooser; -import com.rubix.Resources.Functions; -import com.rubix.Resources.IPFSNetwork; -import io.ipfs.api.IPFS; -import java.awt.image.BufferedImage; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileWriter; -import java.io.InputStreamReader; -import java.io.PrintStream; -import java.net.ServerSocket; -import java.net.Socket; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Iterator; -import javax.imageio.ImageIO; -import org.apache.log4j.Logger; -import org.apache.log4j.PropertyConfigurator; -import org.json.JSONArray; -import org.json.JSONObject; - -public class Buyer { - public static Logger BuyerLogger = Logger.getLogger(Buyer.class); - - private static final JSONObject APIResponse = new JSONObject(); - - private static final IPFS ipfs = new IPFS("/ip4/127.0.0.1/tcp/" + Functions.IPFS_PORT); - - public static String receive() { - Functions.pathSet(); - ServerSocket ss = null; - Socket sk = null; - String sellerPeerID = null; - try { - int quorumSignVerifyCount = 0; - JSONObject quorumSignatures = null; - ArrayList quorumDID = new ArrayList<>(); - PropertyConfigurator.configure(Functions.LOGGER_PATH + "log4jWallet.properties"); - String buyerPeerID = Functions.getPeerID(Functions.DATA_PATH + "DID.json"); - String buyerDidIpfsHash = Functions.getValues(Functions.DATA_PATH + "DataTable.json", "didHash", "peerid", buyerPeerID); - IPFSNetwork.listen(buyerPeerID + "NFT", Functions.BUYER_PORT); - ss = new ServerSocket(Functions.BUYER_PORT); - BuyerLogger.debug("Listening on " + Functions.BUYER_PORT + " with app name " + buyerPeerID + "NFT"); - sk = ss.accept(); - BufferedReader input = new BufferedReader(new InputStreamReader(sk.getInputStream())); - PrintStream output = new PrintStream(sk.getOutputStream()); - long startTime = System.currentTimeMillis(); - sellerPeerID = input.readLine(); - BuyerLogger.debug("Seller PeerID received"); - String sellerDidIpfsHash = Functions.getValues(Functions.DATA_PATH + "DataTable.json", "didHash", "peerid", sellerPeerID); - String sellerWidIpfsHash = Functions.getValues(Functions.DATA_PATH + "DataTable.json", "walletHash", "peerid", sellerPeerID); - if (!sellerDidIpfsHash.contains("Qm") || !sellerWidIpfsHash.contains("Qm")) { - output.println("420"); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Invalid Seller DID."); - BuyerLogger.info("Seller details not available in datatable"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); - } - Functions.nodeData(sellerDidIpfsHash, sellerWidIpfsHash, ipfs); - File sellerDIDFile = new File(Functions.DATA_PATH + sellerDidIpfsHash + "DID.png"); - if (!sellerDIDFile.exists()) { - output.println("420"); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Seller details not available in network , please sync"); - BuyerLogger.info("Sender details not available"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); - } - output.println("200"); - BuyerLogger.debug("PeerAuth sent to Seller"); - String nftData = input.readLine(); - BuyerLogger.debug("NFT Token details received from Seller"); - JSONObject nftTokenDetails = new JSONObject(nftData); - String nftToken = nftTokenDetails.getString("nftToken"); - String nftTokenChain = nftTokenDetails.getString("nftTokenChain"); - String message = nftTokenDetails.toString(); - String nftID = Functions.calculateHash(message, "SHA3-256"); - Functions.writeToFile(Functions.LOGGER_PATH + "nftID", nftID, Boolean.valueOf(false)); - String nftIdIpfsHash = IPFSNetwork.addHashOnly(Functions.LOGGER_PATH + "nftID", ipfs); - Functions.deleteFile(Functions.LOGGER_PATH + "nftID"); - String nftTokenChainContent = IPFSNetwork.get(nftTokenChain, ipfs); - String nftTokenContent = IPFSNetwork.get(nftToken, ipfs); - BuyerLogger.debug("NFT token content extracted"); - IPFSNetwork.repo(ipfs); - if (!IPFSNetwork.dhtEmpty(nftIdIpfsHash, ipfs)) { - BuyerLogger.debug("NFT ID not unique" + nftIdIpfsHash); - output.println("420"); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "NFT ID not unique"); - BuyerLogger.info("NFT ID not unique"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); - } - if (nftTokenContent.equals("")) { - output.println("421"); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Invalid NFT Token"); - BuyerLogger.info("Invalid NFT Token"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); - } - output.println("200"); - BuyerLogger.debug("NftTokenAuth: 200. Sent to Seller"); - String assetData = input.readLine(); - BuyerLogger.debug("Received asset details from Seller"); - JSONObject assetDetails = new JSONObject(assetData); - int amount = assetDetails.getInt("amount"); - JSONArray rbxTokens = FractionChooser.calculate(amount); - JSONArray rbxTokenHeader = FractionChooser.tokenHeader; - ArrayList rbxTokensChainsPushed = new ArrayList<>(); - if (rbxTokens.length() == 0) { - output.println("420"); - BuyerLogger.debug("Insufficient balance with buyer"); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Insufficient balance"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); - } - for (int i = 0; i < rbxTokens.length(); i++) { - File rbxtoken = new File(Functions.TOKENS_PATH+rbxTokens.get(i)); - File rbxtokenchain = new File(Functions.TOKENCHAIN_PATH+rbxTokens.get(i)+".json"); - BuyerLogger.debug("" + rbxtoken + " and " + rbxtoken); - if (!rbxtoken.exists() || !rbxtokenchain.exists()) { - output.println("421"); - BuyerLogger.info("Tokens Not Verified"); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Invalid token(s)"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); - } - IPFSNetwork.add(Functions.TOKENS_PATH+rbxTokens.get(i), ipfs); - String tokenChainHash = IPFSNetwork.add(Functions.TOKENCHAIN_PATH+rbxTokens.get(i)+".json", ipfs); - rbxTokensChainsPushed.add(tokenChainHash); - } - JSONObject rbxTokenDetails = new JSONObject(); - rbxTokenDetails.put("rbxTokens", rbxTokens); - rbxTokenDetails.put("rbxTokenChains", rbxTokensChainsPushed); - rbxTokenDetails.put("rbxTokenHeader", rbxTokenHeader); - String pvt = Functions.DATA_PATH+ buyerDidIpfsHash + "PrivateShare.png"; - String buyerSign = Functions.getSignFromShares(pvt, Functions.calculateHash(rbxTokens.toString() + rbxTokenHeader.toString() + rbxTokensChainsPushed.toString(), "SHA3-256")); - JSONObject rbxData = new JSONObject(); - rbxData.put("rbxTokenDetails", rbxTokenDetails); - rbxData.put("authBuyerBySeller", buyerSign); - output.println(rbxData); - BuyerLogger.debug("Sent rbxData and Buyer sign for authentication to seller."); - String rbxTokensAuth = input.readLine(); - if (rbxTokensAuth.equals("421")) { - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "RBX tokens not verified at seller node"); - BuyerLogger.info("RBX tokens not verified at sender node"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); - } - if (rbxTokensAuth.equals("420")) { - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Consensus ID not Unique"); - BuyerLogger.info("Consensus ID not Unique"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); - } - BuyerLogger.debug("consensus/seller details received from Seller"); - JSONObject consensusDetails = new JSONObject(rbxTokensAuth); - String sellerSignature = consensusDetails.getString("sign"); - String tid = consensusDetails.getString("tid"); - String comment = consensusDetails.getString("comment"); - String Status = consensusDetails.getString("status"); - String QuorumDetails = consensusDetails.getString("quorumsign"); - BuyerLogger.debug("Consensus Status: " + Status); - if (!Status.equals("Consensus Failed")) { - boolean yesQuorum = false; - if (Status.equals("Consensus Reached")) { - BuyerLogger.debug("Quorum Signatures: " + QuorumDetails); - quorumSignatures = new JSONObject(QuorumDetails); - BuyerLogger.debug("Quorum Signatures length : " + quorumSignatures.length()); - Iterator dids = quorumSignatures.keys(); - while (dids.hasNext()) { - String did = dids.next(); - quorumDID.add(did); - } - for (String quorumDidIpfsHash : quorumDID) { - String quorumWidIpfsHash = Functions.getValues(Functions.DATA_PATH + "DataTable.json", "walletHash", "didHash", quorumDidIpfsHash); - File quorumDataFolder = new File(Functions.DATA_PATH + "/"); - if (!quorumDataFolder.exists()) { - quorumDataFolder.mkdirs(); - IPFSNetwork.getImage(quorumDidIpfsHash, ipfs, Functions.DATA_PATH + quorumDidIpfsHash + "DID.png"); - IPFSNetwork.getImage(quorumWidIpfsHash, ipfs, Functions.DATA_PATH + quorumDidIpfsHash + "PublicShare.png"); - BuyerLogger.debug("Quorum Data " + quorumDidIpfsHash + " Added"); - continue; - } - BuyerLogger.debug("Quorum Data " + quorumDidIpfsHash + " Available"); - } - for (int j = 0; j < quorumSignatures.length(); j++) { - JSONObject jSONObject = new JSONObject(); - jSONObject.put("did", quorumDID.get(j)); - jSONObject.put("signature", quorumSignatures.getString(quorumDID.get(j))); - boolean val = Authenticate.verifySignature(jSONObject.toString()); - if (val) - quorumSignVerifyCount++; - } - BuyerLogger.debug("Verified Quorum Count " + quorumSignVerifyCount); - yesQuorum = (quorumSignVerifyCount >= quorumSignatures.length()); - } - String hash = Functions.calculateHash(nftToken + nftTokenChain + amount + buyerDidIpfsHash, "SHA3-256"); - JSONObject detailsForVerify = new JSONObject(); - detailsForVerify.put("did", sellerDidIpfsHash); - detailsForVerify.put("hash", hash); - detailsForVerify.put("signature", sellerSignature); - boolean yesSender = Authenticate.verifySignature(detailsForVerify.toString()); - BuyerLogger.debug("Seller Auth Hash" + hash); - BuyerLogger.debug("Quorum Auth : " + yesQuorum + "Seller Auth : " + yesSender); - if (!yesSender || !yesQuorum) { - output.println("420"); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", tid); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Seller/Quorum not verified"); - BuyerLogger.info("Seller/Quorum not verified"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); - } - IPFSNetwork.repo(ipfs); - BuyerLogger.debug("Seller and Quorum Verified"); - output.println("200"); - String nftUnpinStatus = input.readLine(); - if (nftUnpinStatus.equals("Unpinned NFT")) { - FileWriter fileWriter = new FileWriter(Functions.NFT_TOKENS_PATH+nftToken); - fileWriter.write(nftTokenContent); - fileWriter.close(); - IPFSNetwork.add(Functions.NFT_TOKENS_PATH + nftToken, ipfs); - IPFSNetwork.pin(nftToken, ipfs); - - try { - BuyerLogger.debug("Successfully Pinned NFT Token"); - for (int j = 0; j < rbxTokens.length(); j++) - IPFSNetwork.unpin(String.valueOf(rbxTokens.get(j)), ipfs); - IPFSNetwork.repo(ipfs); - BuyerLogger.debug("Unpinned RBX Tokens"); - output.println("Unpinned RBX"); - String rbxPinData = input.readLine(); - JSONObject rbxPinDetails = new JSONObject(rbxPinData); - String status = rbxPinDetails.getString("status"); - if (status.equals("Failed to pin RBX")) { - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Seller Failed to pin RBX Tokens"); - BuyerLogger.info(" Transaction failed"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); - } - String essentialShare = rbxPinDetails.getString("essentialShare"); - long endTime = System.currentTimeMillis(); - JSONArray currentNftTokenChain = new JSONArray(nftTokenChainContent); - JSONObject newRecord = new JSONObject(); - newRecord.put("sellerDID", sellerDidIpfsHash); - newRecord.put("sellerSign", sellerSignature); - newRecord.put("comment", comment); - newRecord.put("tid", tid); - currentNftTokenChain.put(newRecord); - Functions.writeToFile(Functions.NFT_TOKENCHAIN_PATH+nftTokenChain+".json", currentNftTokenChain.toString(), Boolean.valueOf(false)); - Iterator keys = quorumSignatures.keys(); - JSONArray quorumList = new JSONArray(); - while (keys.hasNext()) - quorumList.put(keys.next()); - JSONObject nftTransactionRecord = new JSONObject(); - nftTransactionRecord.put("role", "Buyer"); - nftTransactionRecord.put("sellerDID", sellerDidIpfsHash); - nftTransactionRecord.put("buyerDID", buyerDidIpfsHash); - nftTransactionRecord.put("amount", amount); - nftTransactionRecord.put("rbxTokens", rbxTokens); - nftTransactionRecord.put("nftToken", nftToken); - nftTransactionRecord.put("txn", tid); - nftTransactionRecord.put("quorumList", quorumList); - nftTransactionRecord.put("Date", Functions.getCurrentUtcTime()); - nftTransactionRecord.put("totalTime", endTime - startTime); - nftTransactionRecord.put("comment", comment); - nftTransactionRecord.put("essentialShare", essentialShare); - JSONArray nftTransactionHistoryEntry = new JSONArray(); - nftTransactionHistoryEntry.put(nftTransactionRecord); - Functions.updateJSON("add", Functions.WALLET_DATA_PATH + "nftTransactionHistory.json", nftTransactionHistoryEntry.toString()); - int k; - for (k = 0; k < rbxTokens.length(); k++) - Files.deleteIfExists(Paths.get(Functions.TOKENS_PATH+rbxTokens.get(k), new String[0])); - for (k = 0; k < amount; k++) - Functions.updateJSON("remove", Functions.PAYMENTS_PATH+rbxTokenHeader.getString(k), rbxTokens.getString(k)); - BuyerLogger.info("Transaction ID: " + tid + "Transaction Successful"); - output.println("Send Response"); - APIResponse.put("sellerDID", sellerDidIpfsHash); - APIResponse.put("buyerDID", buyerDidIpfsHash); - APIResponse.put("tid", tid); - APIResponse.put("status", "Success"); - APIResponse.put("tokens", nftToken); - APIResponse.put("comment", comment); - APIResponse.put("message", "NFT Transaction Successful"); - BuyerLogger.info("Transaction Successful"); - } catch (Exception e) { - output.println("Failed pinning on Buyer Node"); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Failed in pinning NFT token"); - BuyerLogger.info(" Transaction failed", e); - } - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); - } - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Seller Failed to unpin"); - BuyerLogger.info(" Transaction failed"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); - } - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Consensus failed at Sender side"); - BuyerLogger.info(" Transaction failed"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); - } catch (Exception e) { - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - BuyerLogger.error("Exception Occurred", e); - return APIResponse.toString(); - } finally { - try { - ss.close(); - sk.close(); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - } catch (Exception e) { - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - BuyerLogger.error("Exception Occurred", e); - } - } - } -} diff --git a/src/com/rubix/NFT/Seller.java b/src/com/rubix/NFT/Seller.java deleted file mode 100644 index 359f9245..00000000 --- a/src/com/rubix/NFT/Seller.java +++ /dev/null @@ -1,497 +0,0 @@ -package com.rubix.NFT; - -import com.rubix.AuthenticateNode.PropImage; -import com.rubix.Consensus.InitiatorConsensus; -import com.rubix.Consensus.InitiatorProcedure; -import com.rubix.Resources.Functions; -import com.rubix.Resources.IPFSNetwork; -import io.ipfs.api.IPFS; -import java.awt.image.BufferedImage; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileWriter; -import java.io.InputStreamReader; -import java.io.PrintStream; -import java.net.Socket; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Iterator; -import javax.imageio.ImageIO; -import org.apache.log4j.Logger; -import org.apache.log4j.PropertyConfigurator; -import org.json.JSONArray; -import org.json.JSONObject; - -public class Seller { - private static final Logger SellerLogger = Logger.getLogger(Seller.class); - - private static final String USER_AGENT = "Mozilla/5.0"; - - public static BufferedReader serverInput; - - private static PrintStream output; - - private static BufferedReader input; - - private static Socket sellerSocket; - - private static boolean sellerMutex = false; - - public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception { - JSONArray quorumArray; - JSONObject APIResponse = new JSONObject(); - PropertyConfigurator.configure(Functions.LOGGER_PATH + "log4jWallet.properties"); - JSONObject detailsObject = new JSONObject(data); - String buyerDidIpfsHash = detailsObject.getString("buyerDidIpfsHash"); - String pvt = detailsObject.getString("pvt"); - int amount = detailsObject.getInt("amount"); - int type = detailsObject.getInt("type"); - String comment = detailsObject.getString("comment"); - //String eKey = detailsObject.getString("eKey"); - //String dKey = detailsObject.getString("dKey"); - String nftTokenIpfsHash = detailsObject.getString("nftToken"); - JSONArray alphaQuorum = new JSONArray(); - JSONArray betaQuorum = new JSONArray(); - JSONArray gammaQuorum = new JSONArray(); - String sellerPeerId = Functions.getPeerID(Functions.DATA_PATH + "DID.json"); - SellerLogger.debug("Seller Peer ID : " + sellerPeerId); - String sellerDidIpfsHash = Functions.getValues(Functions.DATA_PATH + "DataTable.json", "didHash", "peerid", sellerPeerId); - SellerLogger.debug("Seller DID IPFS Hash : " + sellerDidIpfsHash); - SellerLogger.debug("Path is : " + Functions.DATA_PATH + sellerDidIpfsHash); - File folder = new File(Functions.DATA_PATH); - File[] listOfFiles = folder.listFiles(); - for (int i = 0; i < listOfFiles.length; i++) { - if (listOfFiles[i].isFile()) { - System.out.println("File " + listOfFiles[i].getName()); - } else if (listOfFiles[i].isDirectory()) { - System.out.println("Directory " + listOfFiles[i].getName()); - } - } - BufferedImage senderWidImage = ImageIO.read(new File(Functions.DATA_PATH + sellerDidIpfsHash + "/PublicShare.png")); - String senderWidBin = PropImage.img2bin(senderWidImage); - if (sellerMutex) { - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Sender busy. Try again later"); - SellerLogger.warn("Sender busy"); - return APIResponse; - } - sellerMutex = true; - //String nftTokenChainIpfsHash = null; - APIResponse = new JSONObject(); - File nfttoken = new File(Functions.NFT_TOKENS_PATH+nftTokenIpfsHash); - File nfttokenchain = new File(Functions.NFT_TOKENCHAIN_PATH + nftTokenIpfsHash +".json"); - SellerLogger.debug("NFT Token : " + nfttoken + " and NFT TokenChain : " + nfttokenchain); - if (!nfttoken.exists() || !nfttokenchain.exists() ) { - SellerLogger.info("NFT Token Not Verified"); - sellerMutex = false; - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Invalid NFT token"); - return APIResponse; - } - IPFSNetwork.add(Functions.NFT_TOKENS_PATH + nftTokenIpfsHash, ipfs); - String nftTokenChainIpfsHash = IPFSNetwork.add(Functions.NFT_TOKENCHAIN_PATH + nftTokenIpfsHash + ".json", ipfs); - String authSellerByBuyerHash = Functions.calculateHash(nftTokenIpfsHash + nftTokenChainIpfsHash+ amount + buyerDidIpfsHash, "SHA3-256"); - String tid = Functions.calculateHash(authSellerByBuyerHash, "SHA3-256"); - SellerLogger.debug("Hash for Seller authentication to Buyer : " + authSellerByBuyerHash); - SellerLogger.debug("TID on seller " + tid); - Functions.writeToFile(Functions.LOGGER_PATH + "tempbeta", tid.concat(sellerDidIpfsHash), Boolean.valueOf(false)); - String betaHash = IPFSNetwork.add(Functions.LOGGER_PATH + "tempbeta", ipfs); - Functions.deleteFile(Functions.LOGGER_PATH + "tempbeta"); - Functions.writeToFile(Functions.LOGGER_PATH + "tempgamma", tid.concat(buyerDidIpfsHash), Boolean.valueOf(false)); - String gammaHash = IPFSNetwork.add(Functions.LOGGER_PATH + "tempgamma", ipfs); - Functions.deleteFile(Functions.LOGGER_PATH + "tempgamma"); - switch (type) { - case 1: - quorumArray = Functions.getQuorum(betaHash, gammaHash, sellerDidIpfsHash, buyerDidIpfsHash, amount); - break; - case 2: - quorumArray = new JSONArray(Functions.readFile(Functions.DATA_PATH + "quorumlist.json")); - break; - case 3: - quorumArray = detailsObject.getJSONArray("quorum"); - break; - default: - SellerLogger.error("Unknown quorum type input, cancelling transaction"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Unknown quorum type input, cancelling transaction"); - return APIResponse; - } - Functions.QuorumSwarmConnect(quorumArray, ipfs); - int alphaSize = quorumArray.length() - 14; - int j; - for (j = 0; j < alphaSize; j++) - alphaQuorum.put(quorumArray.getString(j)); - for (j = 0; j < 7; j++) { - betaQuorum.put(quorumArray.getString(alphaSize + j)); - gammaQuorum.put(quorumArray.getString(alphaSize + 7 + j)); - } - SellerLogger.debug("alphaquorum " + alphaQuorum + " size " + alphaQuorum.length()); - SellerLogger.debug("betaquorum " + betaQuorum + " size " + betaQuorum.length()); - SellerLogger.debug("gammaquorum " + gammaQuorum + " size " + gammaQuorum.length()); - ArrayList alphaPeersList = Functions.QuorumCheck(alphaQuorum, alphaSize); - ArrayList betaPeersList = Functions.QuorumCheck(betaQuorum, 7); - ArrayList gammaPeersList = Functions.QuorumCheck(gammaQuorum, 7); - SellerLogger.debug("alphaPeersList size " + alphaPeersList.size()); - SellerLogger.debug("betaPeersList size " + betaPeersList.size()); - SellerLogger.debug("gammaPeersList size " + gammaPeersList.size()); - SellerLogger.debug("minQuorumAlpha size " + Functions.minQuorum(alphaSize)); - if (alphaPeersList.size() < Functions.minQuorum(alphaSize) || betaPeersList.size() < 5 || gammaPeersList.size() < 5) { - Functions.updateQuorum(quorumArray, null, false, type); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Quorum Members not available"); - SellerLogger.warn("Quorum Members not available"); - sellerMutex = false; - return APIResponse; - } - String sellerSign = Functions.getSignFromShares(pvt, authSellerByBuyerHash); - JSONObject sellerDetails2Buyer = new JSONObject(); - sellerDetails2Buyer.put("sign", sellerSign); - sellerDetails2Buyer.put("tid", tid); - sellerDetails2Buyer.put("comment", comment); - JSONObject nftTokenDetails = new JSONObject(); - nftTokenDetails.put("nftToken", nftTokenIpfsHash); - nftTokenDetails.put("nftTokenChain", nftTokenChainIpfsHash); - String message = nftTokenDetails.toString(); - String nftID = Functions.calculateHash(message, "SHA3-256"); - Functions.writeToFile(Functions.LOGGER_PATH + "nftID", nftID, Boolean.valueOf(false)); - String nftIdIpfsHash = IPFSNetwork.addHashOnly(Functions.LOGGER_PATH + "nftID", ipfs); - Functions.deleteFile(Functions.LOGGER_PATH + "nftID"); - SellerLogger.debug("nftID hash " + nftIdIpfsHash + " unique owner " + IPFSNetwork.dhtEmpty(nftIdIpfsHash, ipfs)); - JSONObject assetDetails = new JSONObject(); - assetDetails.put("amount", amount); - String buyerPeerId = Functions.getValues(Functions.DATA_PATH + "DataTable.json", "peerid", "didHash", buyerDidIpfsHash); - SellerLogger.debug("Swarm connecting to " + buyerPeerId); - IPFSNetwork.swarmConnectP2P(buyerPeerId, ipfs); - SellerLogger.debug("Swarm connected"); - String buyerWidIpfsHash = Functions.getValues(Functions.DATA_PATH + "DataTable.json", "walletHash", "didHash", buyerDidIpfsHash); - Functions.nodeData(buyerDidIpfsHash, buyerWidIpfsHash, ipfs); - IPFSNetwork.forward(buyerPeerId + "NFT", port, buyerPeerId); - SellerLogger.debug("Forwarded to " + buyerPeerId + " on " + port); - sellerSocket = new Socket("127.0.0.1", port); - input = new BufferedReader(new InputStreamReader(sellerSocket.getInputStream())); - output = new PrintStream(sellerSocket.getOutputStream()); - long startTime = System.currentTimeMillis(); - output.println(sellerPeerId); - SellerLogger.debug("PeerID sent to Buyer"); - String peerAuth = input.readLine(); - SellerLogger.debug("PeerAuth received from Buyer. Code: " + peerAuth); - if (!peerAuth.equals("200")) { - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); - SellerLogger.info("Seller data not available in the network"); - output.close(); - input.close(); - sellerSocket.close(); - sellerMutex = false; - Functions.updateQuorum(quorumArray, null, false, type); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", tid); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Seller data not available in the network"); - return APIResponse; - } - output.println(nftTokenDetails); - SellerLogger.debug("NFT Token details sent to Buyer"); - String nftTokenAuth = input.readLine(); - SellerLogger.debug("nftTokenAuth received from Buyer. Code: " + nftTokenAuth); - if (!nftTokenAuth.equals("200")) { - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); - output.close(); - input.close(); - sellerSocket.close(); - sellerMutex = false; - if (nftTokenAuth.equals("421")) { - SellerLogger.info("Invalid NFT Token"); - APIResponse.put("message", "Invalid NFT Token"); - } else { - SellerLogger.info("NFT ID not unique"); - APIResponse.put("message", "NFT ID not unique"); - } - Functions.updateQuorum(quorumArray, null, false, type); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", tid); - APIResponse.put("status", "Failed"); - return APIResponse; - } - output.println(assetDetails); - SellerLogger.debug("Sent asset details to Buyer"); - String rbxTokenAuth = input.readLine(); - SellerLogger.debug("Received rbxTokenAuth from Buyer"); - if (rbxTokenAuth.equals("421")) { - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); - output.close(); - input.close(); - sellerSocket.close(); - sellerMutex = false; - SellerLogger.info("Invalid RBX tokens at buyer end"); - APIResponse.put("message", "Invalid RBX tokens at buyer end"); - Functions.updateQuorum(quorumArray, null, false, type); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", tid); - APIResponse.put("status", "Failed"); - return APIResponse; - } - if (rbxTokenAuth.equals("420")) { - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); - output.close(); - input.close(); - sellerSocket.close(); - sellerMutex = false; - SellerLogger.info("Insufficient RBX tokens at buyer end"); - APIResponse.put("message", "Insufficient RBX tokens at buyer end"); - Functions.updateQuorum(quorumArray, null, false, type); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", tid); - APIResponse.put("status", "Failed"); - return APIResponse; - } - JSONObject rbxData = new JSONObject(rbxTokenAuth); - String buyerSign = rbxData.getString("authBuyerBySeller"); - JSONObject rbxTokenDetails = rbxData.getJSONObject("rbxTokenDetails"); - JSONArray rbxTokens = rbxTokenDetails.getJSONArray("rbxTokens"); - JSONArray rbxTokenChains = rbxTokenDetails.getJSONArray("rbxTokenChains"); - JSONArray rbxTokenHeader = rbxTokenDetails.getJSONArray("rbxTokenHeader"); - String messageContent = rbxTokenDetails.toString(); - String consensusID = Functions.calculateHash(messageContent, "SHA3-256"); - Functions.writeToFile(Functions.LOGGER_PATH + "consensusID", consensusID, Boolean.valueOf(false)); - String consensusIdIpfsHash = IPFSNetwork.addHashOnly(Functions.LOGGER_PATH + "consensusID", ipfs); - Functions.deleteFile(Functions.LOGGER_PATH + "consensusID"); - int ipfsGetFlag = 0; - ArrayList allRbxTokenContent = new ArrayList<>(); - ArrayList allRbxTokenChainContent = new ArrayList<>(); - for (int k = 0; k < amount; k++) { - String TokenChainContent = IPFSNetwork.get(rbxTokenChains.getString(k), ipfs); - allRbxTokenChainContent.add(TokenChainContent); - String TokenContent = IPFSNetwork.get(rbxTokens.getString(k), ipfs); - allRbxTokenContent.add(TokenContent); - ipfsGetFlag++; - } - IPFSNetwork.repo(ipfs); - if (!IPFSNetwork.dhtEmpty(consensusIdIpfsHash, ipfs)) { - SellerLogger.debug("consensus ID not unique" + consensusIdIpfsHash); - output.println("420"); - APIResponse.put("did", buyerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Consensus ID not unique"); - SellerLogger.info("Consensus ID not unique"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); - output.close(); - input.close(); - sellerSocket.close(); - return APIResponse; - } - if (ipfsGetFlag != amount) { - output.println("421"); - APIResponse.put("did", buyerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Tokens not verified"); - SellerLogger.info("Tokens not verified"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); - output.close(); - input.close(); - sellerSocket.close(); - return APIResponse; - } - JSONObject dataObject = new JSONObject(); - dataObject.put("tid", tid); - dataObject.put("message", message); - dataObject.put("messageRbx", messageContent); - dataObject.put("buyerDidIpfsHash", buyerDidIpfsHash); - dataObject.put("pvt", pvt); - dataObject.put("sellerDidIpfsHash", sellerDidIpfsHash); - dataObject.put("nftToken", nftTokenIpfsHash); - dataObject.put("rbxTokens", rbxTokens); - dataObject.put("alphaList", alphaPeersList); - dataObject.put("betaList", betaPeersList); - dataObject.put("gammaList", gammaPeersList); - SellerLogger.debug("dataobject " + dataObject.toString()); - SellerLogger.debug("nftConsensus Setup Begins"); - InitiatorProcedure.nftConsensusSetUp(dataObject.toString(), ipfs, Functions.SELLER_PORT + 225, alphaSize); - SellerLogger.debug("nftConsensus Done"); - SellerLogger.debug("length on seller " + InitiatorConsensus.quorumSignature.length() + " response count " + InitiatorConsensus.quorumResponse); - if (InitiatorConsensus.quorumSignature.length() < Functions.minQuorum(alphaSize) + 2 * Functions.minQuorum(7)) { - SellerLogger.debug("Consensus Failed"); - sellerDetails2Buyer.put("status", "Consensus Failed"); - sellerDetails2Buyer.put("quorumsign", InitiatorConsensus.quorumSignature.toString()); - output.println(sellerDetails2Buyer); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); - output.close(); - input.close(); - sellerSocket.close(); - sellerMutex = false; - Functions.updateQuorum(quorumArray, null, false, type); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", tid); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Transaction declined by Quorum"); - return APIResponse; - } - SellerLogger.debug("Consensus Reached"); - sellerDetails2Buyer.put("status", "Consensus Reached"); - sellerDetails2Buyer.put("quorumsign", InitiatorConsensus.quorumSignature.toString()); - output.println(sellerDetails2Buyer); - SellerLogger.debug("Sent Seller/Consensus Details to Buyer"); - SellerLogger.debug("Quorum Signatures length " + InitiatorConsensus.quorumSignature.length()); - String signatureAuth = input.readLine(); - long endAuth = System.currentTimeMillis(); - long totalTime = endAuth - startTime; - if (!signatureAuth.equals("200")) { - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); - SellerLogger.info("Authentication Failed"); - output.close(); - input.close(); - sellerSocket.close(); - sellerMutex = false; - Functions.updateQuorum(quorumArray, null, false, type); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", tid); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Quorum/Seller not authenticated"); - return APIResponse; - } - IPFSNetwork.unpin(nftTokenIpfsHash, ipfs); - IPFSNetwork.repo(ipfs); - SellerLogger.debug("Unpinned NFT Token"); - output.println("Unpinned NFT"); - String rbxUnpinStatus = input.readLine(); - if (!rbxUnpinStatus.equals("Unpinned RBX")) { - SellerLogger.warn("Buyer failed to pin NFT Token"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); - SellerLogger.info("Buyer failed to pin NFT Token"); - output.close(); - input.close(); - sellerSocket.close(); - sellerMutex = false; - Functions.updateQuorum(quorumArray, null, false, type); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", tid); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Buyer failed to pin NFT Token"); - return APIResponse; - } - int count = 0; - int m; - for (m = 0; m < amount; m++) { - FileWriter fileWriter = new FileWriter(Functions.TOKENS_PATH + allRbxTokenContent.get(m)); - fileWriter.write(allRbxTokenContent.get(m)); - fileWriter.close(); - IPFSNetwork.add(Functions.TOKENS_PATH + allRbxTokenContent.get(m), ipfs); - IPFSNetwork.pin(rbxTokens.getString(m), ipfs); - count++; - } - if (count == amount) { - SellerLogger.debug("Pinned All RBX Tokens"); - for (m = 0; m < amount; m++) { - ArrayList groupTokens = new ArrayList<>(); - for (int i1 = 0; i1 < amount; i1++) { - if (!rbxTokens.getString(m).equals(rbxTokens.getString(i1))) - groupTokens.add(rbxTokens.getString(i1)); - } - JSONArray arrToken = new JSONArray(); - JSONObject objectToken = new JSONObject(); - objectToken.put("tokenHash", rbxTokens.getString(m)); - arrToken.put(objectToken); - JSONArray arr1 = new JSONArray(allRbxTokenChainContent.get(m)); - JSONObject obj2 = new JSONObject(); - obj2.put("buyerSign", buyerSign); - obj2.put("buyerDID", buyerDidIpfsHash); - obj2.put("group", groupTokens); - obj2.put("comment", comment); - obj2.put("tid", tid); - arr1.put(obj2); - Functions.writeToFile(Functions.TOKENCHAIN_PATH + allRbxTokenChainContent.get(m) + ".json", arr1.toString(), Boolean.valueOf(false)); - } - JSONObject rbxPinData = new JSONObject(); - rbxPinData.put("status", "Pinned RBX"); - rbxPinData.put("essentialShare", InitiatorProcedure.essential); - output.println(rbxPinData.toString()); - } else { - JSONObject rbxPinData = new JSONObject(); - rbxPinData.put("status", "Failed to pin RBX"); - rbxPinData.put("essentialShare", "null"); - output.println(rbxPinData.toString()); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); - output.close(); - input.close(); - sellerSocket.close(); - sellerMutex = false; - Functions.updateQuorum(quorumArray, null, false, type); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", tid); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Seller Failed to pin RBX"); - SellerLogger.info("Incomplete Transaction"); - return APIResponse; - } - String respAuth = input.readLine(); - if (!respAuth.equals("Send Response")) { - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); - output.close(); - input.close(); - sellerSocket.close(); - sellerMutex = false; - Functions.updateQuorum(quorumArray, null, false, type); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", tid); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Receiver process not over"); - SellerLogger.info("Incomplete Transaction"); - return APIResponse; - } - Iterator keys = InitiatorConsensus.quorumSignature.keys(); - JSONArray signedQuorumList = new JSONArray(); - while (keys.hasNext()) - signedQuorumList.put(keys.next()); - APIResponse.put("tid", tid); - APIResponse.put("status", "Success"); - APIResponse.put("sellerDID", sellerDidIpfsHash); - APIResponse.put("message", "NFT transferred successfully!"); - APIResponse.put("quorumlist", signedQuorumList); - APIResponse.put("buyerDID", buyerDidIpfsHash); - APIResponse.put("totaltime", totalTime); - Functions.updateQuorum(quorumArray, signedQuorumList, true, type); - JSONObject nftTransactionRecord = new JSONObject(); - nftTransactionRecord.put("role", "Seller"); - nftTransactionRecord.put("sellerDID", sellerDidIpfsHash); - nftTransactionRecord.put("buyerDID", buyerDidIpfsHash); - nftTransactionRecord.put("amount", amount); - nftTransactionRecord.put("rbxTokens", rbxTokens); - nftTransactionRecord.put("nftToken", nftTokenIpfsHash); - //nftTransactionRecord.put("eKey", eKey); - //nftTransactionRecord.put("dKey", dKey); - nftTransactionRecord.put("txn", tid); - nftTransactionRecord.put("quorumList", signedQuorumList); - nftTransactionRecord.put("Date", Functions.getCurrentUtcTime()); - nftTransactionRecord.put("totalTime", totalTime); - nftTransactionRecord.put("comment", comment); - nftTransactionRecord.put("essentialShare", InitiatorProcedure.essential); - JSONArray nftTransactionHistoryEntry = new JSONArray(); - nftTransactionHistoryEntry.put(nftTransactionRecord); - Functions.updateJSON("add", Functions.WALLET_DATA_PATH + "nftTransactionHistory.json", nftTransactionHistoryEntry.toString()); - Files.deleteIfExists(Paths.get(Functions.NFT_TOKENS_PATH + nftTokenIpfsHash, new String[0])); - for (int n = 0; n < rbxTokens.length(); n++) { - String bank = rbxTokenHeader.getString(n); - String bankFile = Functions.readFile(Functions.PAYMENTS_PATH + bank + ".json"); - JSONArray bankArray = new JSONArray(bankFile); - JSONObject tokenObject = new JSONObject(); - tokenObject.put("tokenHash", rbxTokens.getString(n)); - bankArray.put(tokenObject); - Functions.writeToFile(Functions.PAYMENTS_PATH + "TokenMap.json", bankArray.toString(), Boolean.valueOf(false)); - } - SellerLogger.info("Transaction Successful"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); - output.close(); - input.close(); - sellerSocket.close(); - sellerMutex = false; - return APIResponse; - } -} From 1f5311c96a6fb5db391fd7b0b73f57e297412337 Mon Sep 17 00:00:00 2001 From: Kiran H Date: Fri, 11 Mar 2022 14:13:16 +0530 Subject: [PATCH 24/49] added exception handling --- src/com/rubix/Ping/PingReceive.java | 2 + src/com/rubix/Ping/QuorumPingReceive.java | 2 + src/com/rubix/Resources/APIHandler.java | 32 ++++--- src/com/rubix/Resources/Functions.java | 103 ++++++++++++++-------- 4 files changed, 89 insertions(+), 50 deletions(-) diff --git a/src/com/rubix/Ping/PingReceive.java b/src/com/rubix/Ping/PingReceive.java index 3ec8ee01..86840e46 100644 --- a/src/com/rubix/Ping/PingReceive.java +++ b/src/com/rubix/Ping/PingReceive.java @@ -85,6 +85,8 @@ public static String receive(int port) { } catch (IOException e) { e.printStackTrace(); + } catch (JSONException e) { + e.printStackTrace(); } return APIResponse.toString(); } diff --git a/src/com/rubix/Ping/QuorumPingReceive.java b/src/com/rubix/Ping/QuorumPingReceive.java index ec1a88ca..898ed0d1 100644 --- a/src/com/rubix/Ping/QuorumPingReceive.java +++ b/src/com/rubix/Ping/QuorumPingReceive.java @@ -90,6 +90,8 @@ public static String receive(int port) { } catch (IOException e) { e.printStackTrace(); + } catch (JSONException e) { + e.printStackTrace(); } return APIResponse.toString(); } diff --git a/src/com/rubix/Resources/APIHandler.java b/src/com/rubix/Resources/APIHandler.java index 8320ae79..7151e760 100644 --- a/src/com/rubix/Resources/APIHandler.java +++ b/src/com/rubix/Resources/APIHandler.java @@ -176,24 +176,28 @@ public static JSONObject creditsInfo(){ File quorumFile = new File(qstFile); File minedFile = new File(mineFile); - + JSONObject returnObject = new JSONObject(); int spentCredits = 0; int unspentCredits = 0; - if(quorumFile.exists()){ - String qFile = readFile(qstFile); - JSONArray qArray = new JSONArray(qFile); - unspentCredits = qArray.length(); - } - if(minedFile.exists()){ - String mFile = readFile(mineFile); - JSONArray mArray = new JSONArray(mFile); - spentCredits = mArray.length(); + try { + if(quorumFile.exists()){ + String qFile = readFile(qstFile); + JSONArray qArray = new JSONArray(qFile); + unspentCredits = qArray.length(); + } + if(minedFile.exists()){ + String mFile = readFile(mineFile); + JSONArray mArray = new JSONArray(mFile); + spentCredits = mArray.length(); + } + + + returnObject.put("spentCredits",spentCredits); + returnObject.put("unspentCredits",unspentCredits); + } catch (JSONException e) { + //TODO: handle exception } - JSONObject returnObject = new JSONObject(); - returnObject.put("spentCredits",spentCredits); - returnObject.put("unspentCredits",unspentCredits); - return returnObject; } diff --git a/src/com/rubix/Resources/Functions.java b/src/com/rubix/Resources/Functions.java index 5d9eda11..ed86349a 100644 --- a/src/com/rubix/Resources/Functions.java +++ b/src/com/rubix/Resources/Functions.java @@ -29,6 +29,8 @@ import java.util.ArrayList; import java.util.Date; import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.Set; import static com.rubix.Resources.APIHandler.addPublicData; import static com.rubix.Resources.IPFSNetwork.*; @@ -1105,7 +1107,8 @@ public static void syncDataTable(String did, String peerId) { public static void removeToken() { String bnkFile = readFile(PAYMENTS_PATH.concat("BNK00.json")); - JSONArray bnkArray = new JSONArray(bnkFile); + try { + JSONArray bnkArray = new JSONArray(bnkFile); JSONObject removeToken = bnkArray.getJSONObject(0); bnkArray.remove(0); writeToFile(PAYMENTS_PATH.concat("BNK00.json"), bnkArray.toString(), false); @@ -1126,13 +1129,17 @@ public static void removeToken() { removeArray.put(removeToken); writeToFile(PAYMENTS_PATH.concat("DoubleSpent.json"), removeArray.toString(), false); } + } catch (JSONException e) { + //TODO: handle exception + } } public static void tokenBank() { pathSet(); String bank = readFile(PAYMENTS_PATH.concat("BNK00.json")); - JSONArray bankArray = new JSONArray(bank); + try { + JSONArray bankArray = new JSONArray(bank); ArrayList bankDuplicates = new ArrayList<>(); for (int i = 0; i < bankArray.length(); i++) { @@ -1164,6 +1171,9 @@ public static void tokenBank() { if (!bankDuplicates.contains(tokenFiles.get(i).toString())) deleteFile(TOKENS_PATH.concat(tokenFiles.get(i).toString())); } + } catch (JSONException e) { + //TODO: handle exception + } } @@ -1391,7 +1401,8 @@ public static Double formatAmount(Double amount) { public static void clearParts() { String partsFile = readFile(PAYMENTS_PATH.concat("PartsToken.json")); - JSONArray partsArray = new JSONArray(partsFile); + try { + JSONArray partsArray = new JSONArray(partsFile); for (int i = 0; i < partsArray.length(); i++) { if (partTokenBalance(partsArray.getJSONObject(i).getString("tokenHash")) <= 0.000 || partTokenBalance(partsArray.getJSONObject(i).getString("tokenHash")) > 1.000) { deleteFile(TOKENS_PATH.concat("PARTS/").concat(partsArray.getJSONObject(i).getString("tokenHash"))); @@ -1399,20 +1410,15 @@ public static void clearParts() { } } writeToFile(PAYMENTS_PATH.concat("PartsToken.json"), partsArray.toString(), false); + } catch (JSONException e) { + //TODO: handle exception + } } public static void backgroundChecks() { - try { - Functions.tokenBank(); - } catch (JSONException e) { - e.printStackTrace(); - } + Functions.tokenBank(); - try { - Functions.clearParts(); - } catch (JSONException e) { - e.printStackTrace(); - } + Functions.clearParts(); IPFS ipfs = new IPFS("/ip4/127.0.0.1/tcp/" + IPFS_PORT); IPFSNetwork.repo(ipfs); @@ -1479,7 +1485,7 @@ public static boolean checkIPFSStatus(String peerid, IPFS ipfs) { MultiAddress multiAddress = new MultiAddress("/ipfs/" + peerid); FunctionsLogger.info("MultiAdrress concated " + multiAddress + "|||"); boolean output = swarmConnectP2P(peerid, ipfs); - + FunctionsLogger.info("Swarm connect process response is " + output); if (output) { swarmConnectedStatus = true; FunctionsLogger.debug("Swarm is already connected"); @@ -1496,12 +1502,20 @@ public static boolean checkIPFSStatus(String peerid, IPFS ipfs) { } - public static boolean ping(String peerid, int port) throws IOException { - JSONObject pingCheck = PingCheck.Ping(peerid, port); + public static boolean ping(String peerid, int port) { + boolean result=false; + try { + JSONObject pingCheck = PingCheck.Ping(peerid, port); if (pingCheck.getString("status").contains("Failed")) { - return false; + result = false; } else - return true; + result = true; + } catch (JSONException e) { + //TODO: handle exception + } catch (IOException e) { + //TODO: handle exception + } + return result; } @@ -1664,36 +1678,53 @@ public static boolean releasePorts(int port) { public static boolean portStatusWindows(int port) { FunctionsLogger.info("Starting portStatusWindows"); boolean releasedPort = false; - String processStr; + String portProcessStr; Process p; + ArrayList pidTree = new ArrayList(); + ArrayList portPidTree = new ArrayList(); try { Runtime rt = Runtime.getRuntime(); - Process proc = rt.exec("cmd /c netstat -ano | findstr " + port); - FunctionsLogger.info("Checking port status"); - long currentPid = ProcessHandle.current().pid(); - BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream())); - processStr = stdInput.readLine(); - FunctionsLogger.info("Process id found for port is " + processStr + " current jar pid is " + currentPid); - if (processStr != null && String.valueOf(currentPid) != processStr) { - int index = processStr.lastIndexOf(" "); - String sc = processStr.substring(index, processStr.length()); - //System.out.println("Port "+port+" is locked by PID "+sc+". Kindly close this port and retry transcation"); - if (sc != String.valueOf(currentPid)) { - FunctionsLogger.debug("Port " + port + " is locked by PID " + sc); - } else { - FunctionsLogger.debug("Port " + port + " is locked by current jar with PID " + sc); - } + Process getJarPid = rt.exec("cmd /c netstat -ano | findstr 1898"); + BufferedReader getJarPidBR = new BufferedReader(new InputStreamReader(getJarPid.getInputStream())); + String getJarPidline; + while ((getJarPidline = getJarPidBR.readLine()) != null) { + String[] getJarPidTree = getJarPidline.split("\\s+"); + int temp = Integer.parseInt(getJarPidTree[getJarPidTree.length - 1]); + pidTree.add(temp); + } + + FunctionsLogger.info("PIDs occupied by Rubix.jar are " + pidTree); + + Set pidSet = new LinkedHashSet(pidTree); + FunctionsLogger.info("Pid occupied by port 1898 is pidSet" + pidSet); + Process getPortPid = rt.exec("cmd /c netstat -ano | findstr " + port); + BufferedReader getPortPidBr = new BufferedReader(new InputStreamReader(getPortPid.getInputStream())); + String getPortPidLine; + while ((getPortPidLine = getPortPidBr.readLine()) != null) { + String[] getPortPidTree = getPortPidLine.split("\\s+"); + int temp = Integer.parseInt(getPortPidTree[getPortPidTree.length - 1]); + portPidTree.add(temp); + } + + Set pidToKill = new LinkedHashSet(portPidTree); + FunctionsLogger.info("Pid used by port " + port + "is " + pidToKill); + pidToKill.removeAll(pidSet); + pidToKill.remove(0); + FunctionsLogger.info("Pid using port " + port + " but not in 1898" + pidToKill); + if (pidToKill.size() > 0) { + System.out.println("Port " + port + " is occupied by PIDs" + pidToKill); } else { releasedPort = true; - FunctionsLogger.info("Port is unlocked"); } + } catch (Exception e) { FunctionsLogger.error("Exception occured at portStatusWindows", e); - e.printStackTrace(); } return releasedPort; + } + } From 6b9d6d1142d075d376f17d83c17b7fc36c1329ec Mon Sep 17 00:00:00 2001 From: Kiran H Date: Fri, 11 Mar 2022 15:57:48 +0530 Subject: [PATCH 25/49] check os update --- src/com/rubix/Resources/Functions.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/rubix/Resources/Functions.java b/src/com/rubix/Resources/Functions.java index 7798a374..f6a88756 100644 --- a/src/com/rubix/Resources/Functions.java +++ b/src/com/rubix/Resources/Functions.java @@ -1622,7 +1622,7 @@ public static boolean portCheckAndKill(int port) { boolean portStatus = false; try { - if (getOsName() != "Windows") { + if (getOsName().toLowerCase().contains("windows")) { portStatus = releasePorts(port); } else { portStatusWindows(port); From 17b110b955797e5400a13ada1d66b99d530386c8 Mon Sep 17 00:00:00 2001 From: Kiran H Date: Fri, 11 Mar 2022 15:58:29 +0530 Subject: [PATCH 26/49] removed old NFT --- src/com/rubix/NFT/Buyer.java | 411 ---------------------------- src/com/rubix/NFT/Seller.java | 497 ---------------------------------- 2 files changed, 908 deletions(-) delete mode 100644 src/com/rubix/NFT/Buyer.java delete mode 100644 src/com/rubix/NFT/Seller.java diff --git a/src/com/rubix/NFT/Buyer.java b/src/com/rubix/NFT/Buyer.java deleted file mode 100644 index 3d7cbec8..00000000 --- a/src/com/rubix/NFT/Buyer.java +++ /dev/null @@ -1,411 +0,0 @@ -package com.rubix.NFT; - - -import com.rubix.AuthenticateNode.Authenticate; -import com.rubix.Resources.FractionChooser; -import com.rubix.Resources.Functions; -import com.rubix.Resources.IPFSNetwork; -import io.ipfs.api.IPFS; -import java.awt.image.BufferedImage; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileWriter; -import java.io.InputStreamReader; -import java.io.PrintStream; -import java.net.ServerSocket; -import java.net.Socket; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Iterator; -import javax.imageio.ImageIO; -import org.apache.log4j.Logger; -import org.apache.log4j.PropertyConfigurator; -import org.json.JSONArray; -import org.json.JSONObject; - -public class Buyer { - public static Logger BuyerLogger = Logger.getLogger(Buyer.class); - - private static final JSONObject APIResponse = new JSONObject(); - - private static final IPFS ipfs = new IPFS("/ip4/127.0.0.1/tcp/" + Functions.IPFS_PORT); - - public static String receive() { - Functions.pathSet(); - ServerSocket ss = null; - Socket sk = null; - String sellerPeerID = null; - try { - int quorumSignVerifyCount = 0; - JSONObject quorumSignatures = null; - ArrayList quorumDID = new ArrayList<>(); - PropertyConfigurator.configure(Functions.LOGGER_PATH + "log4jWallet.properties"); - String buyerPeerID = Functions.getPeerID(Functions.DATA_PATH + "DID.json"); - String buyerDidIpfsHash = Functions.getValues(Functions.DATA_PATH + "DataTable.json", "didHash", "peerid", buyerPeerID); - IPFSNetwork.listen(buyerPeerID + "NFT", Functions.BUYER_PORT); - ss = new ServerSocket(Functions.BUYER_PORT); - BuyerLogger.debug("Listening on " + Functions.BUYER_PORT + " with app name " + buyerPeerID + "NFT"); - sk = ss.accept(); - BufferedReader input = new BufferedReader(new InputStreamReader(sk.getInputStream())); - PrintStream output = new PrintStream(sk.getOutputStream()); - long startTime = System.currentTimeMillis(); - sellerPeerID = input.readLine(); - BuyerLogger.debug("Seller PeerID received"); - String sellerDidIpfsHash = Functions.getValues(Functions.DATA_PATH + "DataTable.json", "didHash", "peerid", sellerPeerID); - String sellerWidIpfsHash = Functions.getValues(Functions.DATA_PATH + "DataTable.json", "walletHash", "peerid", sellerPeerID); - if (!sellerDidIpfsHash.contains("Qm") || !sellerWidIpfsHash.contains("Qm")) { - output.println("420"); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Invalid Seller DID."); - BuyerLogger.info("Seller details not available in datatable"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); - } - Functions.nodeData(sellerDidIpfsHash, sellerWidIpfsHash, ipfs); - File sellerDIDFile = new File(Functions.DATA_PATH + sellerDidIpfsHash + "DID.png"); - if (!sellerDIDFile.exists()) { - output.println("420"); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Seller details not available in network , please sync"); - BuyerLogger.info("Sender details not available"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); - } - output.println("200"); - BuyerLogger.debug("PeerAuth sent to Seller"); - String nftData = input.readLine(); - BuyerLogger.debug("NFT Token details received from Seller"); - JSONObject nftTokenDetails = new JSONObject(nftData); - String nftToken = nftTokenDetails.getString("nftToken"); - String nftTokenChain = nftTokenDetails.getString("nftTokenChain"); - String message = nftTokenDetails.toString(); - String nftID = Functions.calculateHash(message, "SHA3-256"); - Functions.writeToFile(Functions.LOGGER_PATH + "nftID", nftID, Boolean.valueOf(false)); - String nftIdIpfsHash = IPFSNetwork.addHashOnly(Functions.LOGGER_PATH + "nftID", ipfs); - Functions.deleteFile(Functions.LOGGER_PATH + "nftID"); - String nftTokenChainContent = IPFSNetwork.get(nftTokenChain, ipfs); - String nftTokenContent = IPFSNetwork.get(nftToken, ipfs); - BuyerLogger.debug("NFT token content extracted"); - IPFSNetwork.repo(ipfs); - if (!IPFSNetwork.dhtEmpty(nftIdIpfsHash, ipfs)) { - BuyerLogger.debug("NFT ID not unique" + nftIdIpfsHash); - output.println("420"); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "NFT ID not unique"); - BuyerLogger.info("NFT ID not unique"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); - } - if (nftTokenContent.equals("")) { - output.println("421"); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Invalid NFT Token"); - BuyerLogger.info("Invalid NFT Token"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); - } - output.println("200"); - BuyerLogger.debug("NftTokenAuth: 200. Sent to Seller"); - String assetData = input.readLine(); - BuyerLogger.debug("Received asset details from Seller"); - JSONObject assetDetails = new JSONObject(assetData); - int amount = assetDetails.getInt("amount"); - JSONArray rbxTokens = FractionChooser.calculate(amount); - JSONArray rbxTokenHeader = FractionChooser.tokenHeader; - ArrayList rbxTokensChainsPushed = new ArrayList<>(); - if (rbxTokens.length() == 0) { - output.println("420"); - BuyerLogger.debug("Insufficient balance with buyer"); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Insufficient balance"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); - } - for (int i = 0; i < rbxTokens.length(); i++) { - File rbxtoken = new File(Functions.TOKENS_PATH+rbxTokens.get(i)); - File rbxtokenchain = new File(Functions.TOKENCHAIN_PATH+rbxTokens.get(i)+".json"); - BuyerLogger.debug("" + rbxtoken + " and " + rbxtoken); - if (!rbxtoken.exists() || !rbxtokenchain.exists()) { - output.println("421"); - BuyerLogger.info("Tokens Not Verified"); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Invalid token(s)"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); - } - IPFSNetwork.add(Functions.TOKENS_PATH+rbxTokens.get(i), ipfs); - String tokenChainHash = IPFSNetwork.add(Functions.TOKENCHAIN_PATH+rbxTokens.get(i)+".json", ipfs); - rbxTokensChainsPushed.add(tokenChainHash); - } - JSONObject rbxTokenDetails = new JSONObject(); - rbxTokenDetails.put("rbxTokens", rbxTokens); - rbxTokenDetails.put("rbxTokenChains", rbxTokensChainsPushed); - rbxTokenDetails.put("rbxTokenHeader", rbxTokenHeader); - String pvt = Functions.DATA_PATH+ buyerDidIpfsHash + "PrivateShare.png"; - String buyerSign = Functions.getSignFromShares(pvt, Functions.calculateHash(rbxTokens.toString() + rbxTokenHeader.toString() + rbxTokensChainsPushed.toString(), "SHA3-256")); - JSONObject rbxData = new JSONObject(); - rbxData.put("rbxTokenDetails", rbxTokenDetails); - rbxData.put("authBuyerBySeller", buyerSign); - output.println(rbxData); - BuyerLogger.debug("Sent rbxData and Buyer sign for authentication to seller."); - String rbxTokensAuth = input.readLine(); - if (rbxTokensAuth.equals("421")) { - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "RBX tokens not verified at seller node"); - BuyerLogger.info("RBX tokens not verified at sender node"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); - } - if (rbxTokensAuth.equals("420")) { - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Consensus ID not Unique"); - BuyerLogger.info("Consensus ID not Unique"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); - } - BuyerLogger.debug("consensus/seller details received from Seller"); - JSONObject consensusDetails = new JSONObject(rbxTokensAuth); - String sellerSignature = consensusDetails.getString("sign"); - String tid = consensusDetails.getString("tid"); - String comment = consensusDetails.getString("comment"); - String Status = consensusDetails.getString("status"); - String QuorumDetails = consensusDetails.getString("quorumsign"); - BuyerLogger.debug("Consensus Status: " + Status); - if (!Status.equals("Consensus Failed")) { - boolean yesQuorum = false; - if (Status.equals("Consensus Reached")) { - BuyerLogger.debug("Quorum Signatures: " + QuorumDetails); - quorumSignatures = new JSONObject(QuorumDetails); - BuyerLogger.debug("Quorum Signatures length : " + quorumSignatures.length()); - Iterator dids = quorumSignatures.keys(); - while (dids.hasNext()) { - String did = dids.next(); - quorumDID.add(did); - } - for (String quorumDidIpfsHash : quorumDID) { - String quorumWidIpfsHash = Functions.getValues(Functions.DATA_PATH + "DataTable.json", "walletHash", "didHash", quorumDidIpfsHash); - File quorumDataFolder = new File(Functions.DATA_PATH + "/"); - if (!quorumDataFolder.exists()) { - quorumDataFolder.mkdirs(); - IPFSNetwork.getImage(quorumDidIpfsHash, ipfs, Functions.DATA_PATH + quorumDidIpfsHash + "DID.png"); - IPFSNetwork.getImage(quorumWidIpfsHash, ipfs, Functions.DATA_PATH + quorumDidIpfsHash + "PublicShare.png"); - BuyerLogger.debug("Quorum Data " + quorumDidIpfsHash + " Added"); - continue; - } - BuyerLogger.debug("Quorum Data " + quorumDidIpfsHash + " Available"); - } - for (int j = 0; j < quorumSignatures.length(); j++) { - JSONObject jSONObject = new JSONObject(); - jSONObject.put("did", quorumDID.get(j)); - jSONObject.put("signature", quorumSignatures.getString(quorumDID.get(j))); - boolean val = Authenticate.verifySignature(jSONObject.toString()); - if (val) - quorumSignVerifyCount++; - } - BuyerLogger.debug("Verified Quorum Count " + quorumSignVerifyCount); - yesQuorum = (quorumSignVerifyCount >= quorumSignatures.length()); - } - String hash = Functions.calculateHash(nftToken + nftTokenChain + amount + buyerDidIpfsHash, "SHA3-256"); - JSONObject detailsForVerify = new JSONObject(); - detailsForVerify.put("did", sellerDidIpfsHash); - detailsForVerify.put("hash", hash); - detailsForVerify.put("signature", sellerSignature); - boolean yesSender = Authenticate.verifySignature(detailsForVerify.toString()); - BuyerLogger.debug("Seller Auth Hash" + hash); - BuyerLogger.debug("Quorum Auth : " + yesQuorum + "Seller Auth : " + yesSender); - if (!yesSender || !yesQuorum) { - output.println("420"); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", tid); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Seller/Quorum not verified"); - BuyerLogger.info("Seller/Quorum not verified"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); - } - IPFSNetwork.repo(ipfs); - BuyerLogger.debug("Seller and Quorum Verified"); - output.println("200"); - String nftUnpinStatus = input.readLine(); - if (nftUnpinStatus.equals("Unpinned NFT")) { - FileWriter fileWriter = new FileWriter(Functions.NFT_TOKENS_PATH+nftToken); - fileWriter.write(nftTokenContent); - fileWriter.close(); - IPFSNetwork.add(Functions.NFT_TOKENS_PATH + nftToken, ipfs); - IPFSNetwork.pin(nftToken, ipfs); - - try { - BuyerLogger.debug("Successfully Pinned NFT Token"); - for (int j = 0; j < rbxTokens.length(); j++) - IPFSNetwork.unpin(String.valueOf(rbxTokens.get(j)), ipfs); - IPFSNetwork.repo(ipfs); - BuyerLogger.debug("Unpinned RBX Tokens"); - output.println("Unpinned RBX"); - String rbxPinData = input.readLine(); - JSONObject rbxPinDetails = new JSONObject(rbxPinData); - String status = rbxPinDetails.getString("status"); - if (status.equals("Failed to pin RBX")) { - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Seller Failed to pin RBX Tokens"); - BuyerLogger.info(" Transaction failed"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); - } - String essentialShare = rbxPinDetails.getString("essentialShare"); - long endTime = System.currentTimeMillis(); - JSONArray currentNftTokenChain = new JSONArray(nftTokenChainContent); - JSONObject newRecord = new JSONObject(); - newRecord.put("sellerDID", sellerDidIpfsHash); - newRecord.put("sellerSign", sellerSignature); - newRecord.put("comment", comment); - newRecord.put("tid", tid); - currentNftTokenChain.put(newRecord); - Functions.writeToFile(Functions.NFT_TOKENCHAIN_PATH+nftTokenChain+".json", currentNftTokenChain.toString(), Boolean.valueOf(false)); - Iterator keys = quorumSignatures.keys(); - JSONArray quorumList = new JSONArray(); - while (keys.hasNext()) - quorumList.put(keys.next()); - JSONObject nftTransactionRecord = new JSONObject(); - nftTransactionRecord.put("role", "Buyer"); - nftTransactionRecord.put("sellerDID", sellerDidIpfsHash); - nftTransactionRecord.put("buyerDID", buyerDidIpfsHash); - nftTransactionRecord.put("amount", amount); - nftTransactionRecord.put("rbxTokens", rbxTokens); - nftTransactionRecord.put("nftToken", nftToken); - nftTransactionRecord.put("txn", tid); - nftTransactionRecord.put("quorumList", quorumList); - nftTransactionRecord.put("Date", Functions.getCurrentUtcTime()); - nftTransactionRecord.put("totalTime", endTime - startTime); - nftTransactionRecord.put("comment", comment); - nftTransactionRecord.put("essentialShare", essentialShare); - JSONArray nftTransactionHistoryEntry = new JSONArray(); - nftTransactionHistoryEntry.put(nftTransactionRecord); - Functions.updateJSON("add", Functions.WALLET_DATA_PATH + "nftTransactionHistory.json", nftTransactionHistoryEntry.toString()); - int k; - for (k = 0; k < rbxTokens.length(); k++) - Files.deleteIfExists(Paths.get(Functions.TOKENS_PATH+rbxTokens.get(k), new String[0])); - for (k = 0; k < amount; k++) - Functions.updateJSON("remove", Functions.PAYMENTS_PATH+rbxTokenHeader.getString(k), rbxTokens.getString(k)); - BuyerLogger.info("Transaction ID: " + tid + "Transaction Successful"); - output.println("Send Response"); - APIResponse.put("sellerDID", sellerDidIpfsHash); - APIResponse.put("buyerDID", buyerDidIpfsHash); - APIResponse.put("tid", tid); - APIResponse.put("status", "Success"); - APIResponse.put("tokens", nftToken); - APIResponse.put("comment", comment); - APIResponse.put("message", "NFT Transaction Successful"); - BuyerLogger.info("Transaction Successful"); - } catch (Exception e) { - output.println("Failed pinning on Buyer Node"); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Failed in pinning NFT token"); - BuyerLogger.info(" Transaction failed", e); - } - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); - } - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Seller Failed to unpin"); - BuyerLogger.info(" Transaction failed"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); - } - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Consensus failed at Sender side"); - BuyerLogger.info(" Transaction failed"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); - } catch (Exception e) { - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - BuyerLogger.error("Exception Occurred", e); - return APIResponse.toString(); - } finally { - try { - ss.close(); - sk.close(); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - } catch (Exception e) { - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + sellerPeerID); - BuyerLogger.error("Exception Occurred", e); - } - } - } -} diff --git a/src/com/rubix/NFT/Seller.java b/src/com/rubix/NFT/Seller.java deleted file mode 100644 index 359f9245..00000000 --- a/src/com/rubix/NFT/Seller.java +++ /dev/null @@ -1,497 +0,0 @@ -package com.rubix.NFT; - -import com.rubix.AuthenticateNode.PropImage; -import com.rubix.Consensus.InitiatorConsensus; -import com.rubix.Consensus.InitiatorProcedure; -import com.rubix.Resources.Functions; -import com.rubix.Resources.IPFSNetwork; -import io.ipfs.api.IPFS; -import java.awt.image.BufferedImage; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileWriter; -import java.io.InputStreamReader; -import java.io.PrintStream; -import java.net.Socket; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Iterator; -import javax.imageio.ImageIO; -import org.apache.log4j.Logger; -import org.apache.log4j.PropertyConfigurator; -import org.json.JSONArray; -import org.json.JSONObject; - -public class Seller { - private static final Logger SellerLogger = Logger.getLogger(Seller.class); - - private static final String USER_AGENT = "Mozilla/5.0"; - - public static BufferedReader serverInput; - - private static PrintStream output; - - private static BufferedReader input; - - private static Socket sellerSocket; - - private static boolean sellerMutex = false; - - public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception { - JSONArray quorumArray; - JSONObject APIResponse = new JSONObject(); - PropertyConfigurator.configure(Functions.LOGGER_PATH + "log4jWallet.properties"); - JSONObject detailsObject = new JSONObject(data); - String buyerDidIpfsHash = detailsObject.getString("buyerDidIpfsHash"); - String pvt = detailsObject.getString("pvt"); - int amount = detailsObject.getInt("amount"); - int type = detailsObject.getInt("type"); - String comment = detailsObject.getString("comment"); - //String eKey = detailsObject.getString("eKey"); - //String dKey = detailsObject.getString("dKey"); - String nftTokenIpfsHash = detailsObject.getString("nftToken"); - JSONArray alphaQuorum = new JSONArray(); - JSONArray betaQuorum = new JSONArray(); - JSONArray gammaQuorum = new JSONArray(); - String sellerPeerId = Functions.getPeerID(Functions.DATA_PATH + "DID.json"); - SellerLogger.debug("Seller Peer ID : " + sellerPeerId); - String sellerDidIpfsHash = Functions.getValues(Functions.DATA_PATH + "DataTable.json", "didHash", "peerid", sellerPeerId); - SellerLogger.debug("Seller DID IPFS Hash : " + sellerDidIpfsHash); - SellerLogger.debug("Path is : " + Functions.DATA_PATH + sellerDidIpfsHash); - File folder = new File(Functions.DATA_PATH); - File[] listOfFiles = folder.listFiles(); - for (int i = 0; i < listOfFiles.length; i++) { - if (listOfFiles[i].isFile()) { - System.out.println("File " + listOfFiles[i].getName()); - } else if (listOfFiles[i].isDirectory()) { - System.out.println("Directory " + listOfFiles[i].getName()); - } - } - BufferedImage senderWidImage = ImageIO.read(new File(Functions.DATA_PATH + sellerDidIpfsHash + "/PublicShare.png")); - String senderWidBin = PropImage.img2bin(senderWidImage); - if (sellerMutex) { - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Sender busy. Try again later"); - SellerLogger.warn("Sender busy"); - return APIResponse; - } - sellerMutex = true; - //String nftTokenChainIpfsHash = null; - APIResponse = new JSONObject(); - File nfttoken = new File(Functions.NFT_TOKENS_PATH+nftTokenIpfsHash); - File nfttokenchain = new File(Functions.NFT_TOKENCHAIN_PATH + nftTokenIpfsHash +".json"); - SellerLogger.debug("NFT Token : " + nfttoken + " and NFT TokenChain : " + nfttokenchain); - if (!nfttoken.exists() || !nfttokenchain.exists() ) { - SellerLogger.info("NFT Token Not Verified"); - sellerMutex = false; - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Invalid NFT token"); - return APIResponse; - } - IPFSNetwork.add(Functions.NFT_TOKENS_PATH + nftTokenIpfsHash, ipfs); - String nftTokenChainIpfsHash = IPFSNetwork.add(Functions.NFT_TOKENCHAIN_PATH + nftTokenIpfsHash + ".json", ipfs); - String authSellerByBuyerHash = Functions.calculateHash(nftTokenIpfsHash + nftTokenChainIpfsHash+ amount + buyerDidIpfsHash, "SHA3-256"); - String tid = Functions.calculateHash(authSellerByBuyerHash, "SHA3-256"); - SellerLogger.debug("Hash for Seller authentication to Buyer : " + authSellerByBuyerHash); - SellerLogger.debug("TID on seller " + tid); - Functions.writeToFile(Functions.LOGGER_PATH + "tempbeta", tid.concat(sellerDidIpfsHash), Boolean.valueOf(false)); - String betaHash = IPFSNetwork.add(Functions.LOGGER_PATH + "tempbeta", ipfs); - Functions.deleteFile(Functions.LOGGER_PATH + "tempbeta"); - Functions.writeToFile(Functions.LOGGER_PATH + "tempgamma", tid.concat(buyerDidIpfsHash), Boolean.valueOf(false)); - String gammaHash = IPFSNetwork.add(Functions.LOGGER_PATH + "tempgamma", ipfs); - Functions.deleteFile(Functions.LOGGER_PATH + "tempgamma"); - switch (type) { - case 1: - quorumArray = Functions.getQuorum(betaHash, gammaHash, sellerDidIpfsHash, buyerDidIpfsHash, amount); - break; - case 2: - quorumArray = new JSONArray(Functions.readFile(Functions.DATA_PATH + "quorumlist.json")); - break; - case 3: - quorumArray = detailsObject.getJSONArray("quorum"); - break; - default: - SellerLogger.error("Unknown quorum type input, cancelling transaction"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Unknown quorum type input, cancelling transaction"); - return APIResponse; - } - Functions.QuorumSwarmConnect(quorumArray, ipfs); - int alphaSize = quorumArray.length() - 14; - int j; - for (j = 0; j < alphaSize; j++) - alphaQuorum.put(quorumArray.getString(j)); - for (j = 0; j < 7; j++) { - betaQuorum.put(quorumArray.getString(alphaSize + j)); - gammaQuorum.put(quorumArray.getString(alphaSize + 7 + j)); - } - SellerLogger.debug("alphaquorum " + alphaQuorum + " size " + alphaQuorum.length()); - SellerLogger.debug("betaquorum " + betaQuorum + " size " + betaQuorum.length()); - SellerLogger.debug("gammaquorum " + gammaQuorum + " size " + gammaQuorum.length()); - ArrayList alphaPeersList = Functions.QuorumCheck(alphaQuorum, alphaSize); - ArrayList betaPeersList = Functions.QuorumCheck(betaQuorum, 7); - ArrayList gammaPeersList = Functions.QuorumCheck(gammaQuorum, 7); - SellerLogger.debug("alphaPeersList size " + alphaPeersList.size()); - SellerLogger.debug("betaPeersList size " + betaPeersList.size()); - SellerLogger.debug("gammaPeersList size " + gammaPeersList.size()); - SellerLogger.debug("minQuorumAlpha size " + Functions.minQuorum(alphaSize)); - if (alphaPeersList.size() < Functions.minQuorum(alphaSize) || betaPeersList.size() < 5 || gammaPeersList.size() < 5) { - Functions.updateQuorum(quorumArray, null, false, type); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Quorum Members not available"); - SellerLogger.warn("Quorum Members not available"); - sellerMutex = false; - return APIResponse; - } - String sellerSign = Functions.getSignFromShares(pvt, authSellerByBuyerHash); - JSONObject sellerDetails2Buyer = new JSONObject(); - sellerDetails2Buyer.put("sign", sellerSign); - sellerDetails2Buyer.put("tid", tid); - sellerDetails2Buyer.put("comment", comment); - JSONObject nftTokenDetails = new JSONObject(); - nftTokenDetails.put("nftToken", nftTokenIpfsHash); - nftTokenDetails.put("nftTokenChain", nftTokenChainIpfsHash); - String message = nftTokenDetails.toString(); - String nftID = Functions.calculateHash(message, "SHA3-256"); - Functions.writeToFile(Functions.LOGGER_PATH + "nftID", nftID, Boolean.valueOf(false)); - String nftIdIpfsHash = IPFSNetwork.addHashOnly(Functions.LOGGER_PATH + "nftID", ipfs); - Functions.deleteFile(Functions.LOGGER_PATH + "nftID"); - SellerLogger.debug("nftID hash " + nftIdIpfsHash + " unique owner " + IPFSNetwork.dhtEmpty(nftIdIpfsHash, ipfs)); - JSONObject assetDetails = new JSONObject(); - assetDetails.put("amount", amount); - String buyerPeerId = Functions.getValues(Functions.DATA_PATH + "DataTable.json", "peerid", "didHash", buyerDidIpfsHash); - SellerLogger.debug("Swarm connecting to " + buyerPeerId); - IPFSNetwork.swarmConnectP2P(buyerPeerId, ipfs); - SellerLogger.debug("Swarm connected"); - String buyerWidIpfsHash = Functions.getValues(Functions.DATA_PATH + "DataTable.json", "walletHash", "didHash", buyerDidIpfsHash); - Functions.nodeData(buyerDidIpfsHash, buyerWidIpfsHash, ipfs); - IPFSNetwork.forward(buyerPeerId + "NFT", port, buyerPeerId); - SellerLogger.debug("Forwarded to " + buyerPeerId + " on " + port); - sellerSocket = new Socket("127.0.0.1", port); - input = new BufferedReader(new InputStreamReader(sellerSocket.getInputStream())); - output = new PrintStream(sellerSocket.getOutputStream()); - long startTime = System.currentTimeMillis(); - output.println(sellerPeerId); - SellerLogger.debug("PeerID sent to Buyer"); - String peerAuth = input.readLine(); - SellerLogger.debug("PeerAuth received from Buyer. Code: " + peerAuth); - if (!peerAuth.equals("200")) { - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); - SellerLogger.info("Seller data not available in the network"); - output.close(); - input.close(); - sellerSocket.close(); - sellerMutex = false; - Functions.updateQuorum(quorumArray, null, false, type); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", tid); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Seller data not available in the network"); - return APIResponse; - } - output.println(nftTokenDetails); - SellerLogger.debug("NFT Token details sent to Buyer"); - String nftTokenAuth = input.readLine(); - SellerLogger.debug("nftTokenAuth received from Buyer. Code: " + nftTokenAuth); - if (!nftTokenAuth.equals("200")) { - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); - output.close(); - input.close(); - sellerSocket.close(); - sellerMutex = false; - if (nftTokenAuth.equals("421")) { - SellerLogger.info("Invalid NFT Token"); - APIResponse.put("message", "Invalid NFT Token"); - } else { - SellerLogger.info("NFT ID not unique"); - APIResponse.put("message", "NFT ID not unique"); - } - Functions.updateQuorum(quorumArray, null, false, type); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", tid); - APIResponse.put("status", "Failed"); - return APIResponse; - } - output.println(assetDetails); - SellerLogger.debug("Sent asset details to Buyer"); - String rbxTokenAuth = input.readLine(); - SellerLogger.debug("Received rbxTokenAuth from Buyer"); - if (rbxTokenAuth.equals("421")) { - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); - output.close(); - input.close(); - sellerSocket.close(); - sellerMutex = false; - SellerLogger.info("Invalid RBX tokens at buyer end"); - APIResponse.put("message", "Invalid RBX tokens at buyer end"); - Functions.updateQuorum(quorumArray, null, false, type); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", tid); - APIResponse.put("status", "Failed"); - return APIResponse; - } - if (rbxTokenAuth.equals("420")) { - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); - output.close(); - input.close(); - sellerSocket.close(); - sellerMutex = false; - SellerLogger.info("Insufficient RBX tokens at buyer end"); - APIResponse.put("message", "Insufficient RBX tokens at buyer end"); - Functions.updateQuorum(quorumArray, null, false, type); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", tid); - APIResponse.put("status", "Failed"); - return APIResponse; - } - JSONObject rbxData = new JSONObject(rbxTokenAuth); - String buyerSign = rbxData.getString("authBuyerBySeller"); - JSONObject rbxTokenDetails = rbxData.getJSONObject("rbxTokenDetails"); - JSONArray rbxTokens = rbxTokenDetails.getJSONArray("rbxTokens"); - JSONArray rbxTokenChains = rbxTokenDetails.getJSONArray("rbxTokenChains"); - JSONArray rbxTokenHeader = rbxTokenDetails.getJSONArray("rbxTokenHeader"); - String messageContent = rbxTokenDetails.toString(); - String consensusID = Functions.calculateHash(messageContent, "SHA3-256"); - Functions.writeToFile(Functions.LOGGER_PATH + "consensusID", consensusID, Boolean.valueOf(false)); - String consensusIdIpfsHash = IPFSNetwork.addHashOnly(Functions.LOGGER_PATH + "consensusID", ipfs); - Functions.deleteFile(Functions.LOGGER_PATH + "consensusID"); - int ipfsGetFlag = 0; - ArrayList allRbxTokenContent = new ArrayList<>(); - ArrayList allRbxTokenChainContent = new ArrayList<>(); - for (int k = 0; k < amount; k++) { - String TokenChainContent = IPFSNetwork.get(rbxTokenChains.getString(k), ipfs); - allRbxTokenChainContent.add(TokenChainContent); - String TokenContent = IPFSNetwork.get(rbxTokens.getString(k), ipfs); - allRbxTokenContent.add(TokenContent); - ipfsGetFlag++; - } - IPFSNetwork.repo(ipfs); - if (!IPFSNetwork.dhtEmpty(consensusIdIpfsHash, ipfs)) { - SellerLogger.debug("consensus ID not unique" + consensusIdIpfsHash); - output.println("420"); - APIResponse.put("did", buyerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Consensus ID not unique"); - SellerLogger.info("Consensus ID not unique"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); - output.close(); - input.close(); - sellerSocket.close(); - return APIResponse; - } - if (ipfsGetFlag != amount) { - output.println("421"); - APIResponse.put("did", buyerDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Tokens not verified"); - SellerLogger.info("Tokens not verified"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); - output.close(); - input.close(); - sellerSocket.close(); - return APIResponse; - } - JSONObject dataObject = new JSONObject(); - dataObject.put("tid", tid); - dataObject.put("message", message); - dataObject.put("messageRbx", messageContent); - dataObject.put("buyerDidIpfsHash", buyerDidIpfsHash); - dataObject.put("pvt", pvt); - dataObject.put("sellerDidIpfsHash", sellerDidIpfsHash); - dataObject.put("nftToken", nftTokenIpfsHash); - dataObject.put("rbxTokens", rbxTokens); - dataObject.put("alphaList", alphaPeersList); - dataObject.put("betaList", betaPeersList); - dataObject.put("gammaList", gammaPeersList); - SellerLogger.debug("dataobject " + dataObject.toString()); - SellerLogger.debug("nftConsensus Setup Begins"); - InitiatorProcedure.nftConsensusSetUp(dataObject.toString(), ipfs, Functions.SELLER_PORT + 225, alphaSize); - SellerLogger.debug("nftConsensus Done"); - SellerLogger.debug("length on seller " + InitiatorConsensus.quorumSignature.length() + " response count " + InitiatorConsensus.quorumResponse); - if (InitiatorConsensus.quorumSignature.length() < Functions.minQuorum(alphaSize) + 2 * Functions.minQuorum(7)) { - SellerLogger.debug("Consensus Failed"); - sellerDetails2Buyer.put("status", "Consensus Failed"); - sellerDetails2Buyer.put("quorumsign", InitiatorConsensus.quorumSignature.toString()); - output.println(sellerDetails2Buyer); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); - output.close(); - input.close(); - sellerSocket.close(); - sellerMutex = false; - Functions.updateQuorum(quorumArray, null, false, type); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", tid); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Transaction declined by Quorum"); - return APIResponse; - } - SellerLogger.debug("Consensus Reached"); - sellerDetails2Buyer.put("status", "Consensus Reached"); - sellerDetails2Buyer.put("quorumsign", InitiatorConsensus.quorumSignature.toString()); - output.println(sellerDetails2Buyer); - SellerLogger.debug("Sent Seller/Consensus Details to Buyer"); - SellerLogger.debug("Quorum Signatures length " + InitiatorConsensus.quorumSignature.length()); - String signatureAuth = input.readLine(); - long endAuth = System.currentTimeMillis(); - long totalTime = endAuth - startTime; - if (!signatureAuth.equals("200")) { - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); - SellerLogger.info("Authentication Failed"); - output.close(); - input.close(); - sellerSocket.close(); - sellerMutex = false; - Functions.updateQuorum(quorumArray, null, false, type); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", tid); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Quorum/Seller not authenticated"); - return APIResponse; - } - IPFSNetwork.unpin(nftTokenIpfsHash, ipfs); - IPFSNetwork.repo(ipfs); - SellerLogger.debug("Unpinned NFT Token"); - output.println("Unpinned NFT"); - String rbxUnpinStatus = input.readLine(); - if (!rbxUnpinStatus.equals("Unpinned RBX")) { - SellerLogger.warn("Buyer failed to pin NFT Token"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); - SellerLogger.info("Buyer failed to pin NFT Token"); - output.close(); - input.close(); - sellerSocket.close(); - sellerMutex = false; - Functions.updateQuorum(quorumArray, null, false, type); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", tid); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Buyer failed to pin NFT Token"); - return APIResponse; - } - int count = 0; - int m; - for (m = 0; m < amount; m++) { - FileWriter fileWriter = new FileWriter(Functions.TOKENS_PATH + allRbxTokenContent.get(m)); - fileWriter.write(allRbxTokenContent.get(m)); - fileWriter.close(); - IPFSNetwork.add(Functions.TOKENS_PATH + allRbxTokenContent.get(m), ipfs); - IPFSNetwork.pin(rbxTokens.getString(m), ipfs); - count++; - } - if (count == amount) { - SellerLogger.debug("Pinned All RBX Tokens"); - for (m = 0; m < amount; m++) { - ArrayList groupTokens = new ArrayList<>(); - for (int i1 = 0; i1 < amount; i1++) { - if (!rbxTokens.getString(m).equals(rbxTokens.getString(i1))) - groupTokens.add(rbxTokens.getString(i1)); - } - JSONArray arrToken = new JSONArray(); - JSONObject objectToken = new JSONObject(); - objectToken.put("tokenHash", rbxTokens.getString(m)); - arrToken.put(objectToken); - JSONArray arr1 = new JSONArray(allRbxTokenChainContent.get(m)); - JSONObject obj2 = new JSONObject(); - obj2.put("buyerSign", buyerSign); - obj2.put("buyerDID", buyerDidIpfsHash); - obj2.put("group", groupTokens); - obj2.put("comment", comment); - obj2.put("tid", tid); - arr1.put(obj2); - Functions.writeToFile(Functions.TOKENCHAIN_PATH + allRbxTokenChainContent.get(m) + ".json", arr1.toString(), Boolean.valueOf(false)); - } - JSONObject rbxPinData = new JSONObject(); - rbxPinData.put("status", "Pinned RBX"); - rbxPinData.put("essentialShare", InitiatorProcedure.essential); - output.println(rbxPinData.toString()); - } else { - JSONObject rbxPinData = new JSONObject(); - rbxPinData.put("status", "Failed to pin RBX"); - rbxPinData.put("essentialShare", "null"); - output.println(rbxPinData.toString()); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); - output.close(); - input.close(); - sellerSocket.close(); - sellerMutex = false; - Functions.updateQuorum(quorumArray, null, false, type); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", tid); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Seller Failed to pin RBX"); - SellerLogger.info("Incomplete Transaction"); - return APIResponse; - } - String respAuth = input.readLine(); - if (!respAuth.equals("Send Response")) { - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); - output.close(); - input.close(); - sellerSocket.close(); - sellerMutex = false; - Functions.updateQuorum(quorumArray, null, false, type); - APIResponse.put("did", sellerDidIpfsHash); - APIResponse.put("tid", tid); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Receiver process not over"); - SellerLogger.info("Incomplete Transaction"); - return APIResponse; - } - Iterator keys = InitiatorConsensus.quorumSignature.keys(); - JSONArray signedQuorumList = new JSONArray(); - while (keys.hasNext()) - signedQuorumList.put(keys.next()); - APIResponse.put("tid", tid); - APIResponse.put("status", "Success"); - APIResponse.put("sellerDID", sellerDidIpfsHash); - APIResponse.put("message", "NFT transferred successfully!"); - APIResponse.put("quorumlist", signedQuorumList); - APIResponse.put("buyerDID", buyerDidIpfsHash); - APIResponse.put("totaltime", totalTime); - Functions.updateQuorum(quorumArray, signedQuorumList, true, type); - JSONObject nftTransactionRecord = new JSONObject(); - nftTransactionRecord.put("role", "Seller"); - nftTransactionRecord.put("sellerDID", sellerDidIpfsHash); - nftTransactionRecord.put("buyerDID", buyerDidIpfsHash); - nftTransactionRecord.put("amount", amount); - nftTransactionRecord.put("rbxTokens", rbxTokens); - nftTransactionRecord.put("nftToken", nftTokenIpfsHash); - //nftTransactionRecord.put("eKey", eKey); - //nftTransactionRecord.put("dKey", dKey); - nftTransactionRecord.put("txn", tid); - nftTransactionRecord.put("quorumList", signedQuorumList); - nftTransactionRecord.put("Date", Functions.getCurrentUtcTime()); - nftTransactionRecord.put("totalTime", totalTime); - nftTransactionRecord.put("comment", comment); - nftTransactionRecord.put("essentialShare", InitiatorProcedure.essential); - JSONArray nftTransactionHistoryEntry = new JSONArray(); - nftTransactionHistoryEntry.put(nftTransactionRecord); - Functions.updateJSON("add", Functions.WALLET_DATA_PATH + "nftTransactionHistory.json", nftTransactionHistoryEntry.toString()); - Files.deleteIfExists(Paths.get(Functions.NFT_TOKENS_PATH + nftTokenIpfsHash, new String[0])); - for (int n = 0; n < rbxTokens.length(); n++) { - String bank = rbxTokenHeader.getString(n); - String bankFile = Functions.readFile(Functions.PAYMENTS_PATH + bank + ".json"); - JSONArray bankArray = new JSONArray(bankFile); - JSONObject tokenObject = new JSONObject(); - tokenObject.put("tokenHash", rbxTokens.getString(n)); - bankArray.put(tokenObject); - Functions.writeToFile(Functions.PAYMENTS_PATH + "TokenMap.json", bankArray.toString(), Boolean.valueOf(false)); - } - SellerLogger.info("Transaction Successful"); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + buyerPeerId); - output.close(); - input.close(); - sellerSocket.close(); - sellerMutex = false; - return APIResponse; - } -} From ebeac72344a19d1bed09b32521c4d4814544eadf Mon Sep 17 00:00:00 2001 From: Kiran H Date: Fri, 11 Mar 2022 16:02:55 +0530 Subject: [PATCH 27/49] added exception handling --- src/com/rubix/Ping/PingReceive.java | 2 + src/com/rubix/Ping/QuorumPingReceive.java | 2 + src/com/rubix/Resources/APIHandler.java | 32 +- src/com/rubix/Resources/Functions.java | 369 +++++++++++----------- 4 files changed, 206 insertions(+), 199 deletions(-) diff --git a/src/com/rubix/Ping/PingReceive.java b/src/com/rubix/Ping/PingReceive.java index 3ec8ee01..86840e46 100644 --- a/src/com/rubix/Ping/PingReceive.java +++ b/src/com/rubix/Ping/PingReceive.java @@ -85,6 +85,8 @@ public static String receive(int port) { } catch (IOException e) { e.printStackTrace(); + } catch (JSONException e) { + e.printStackTrace(); } return APIResponse.toString(); } diff --git a/src/com/rubix/Ping/QuorumPingReceive.java b/src/com/rubix/Ping/QuorumPingReceive.java index ec1a88ca..898ed0d1 100644 --- a/src/com/rubix/Ping/QuorumPingReceive.java +++ b/src/com/rubix/Ping/QuorumPingReceive.java @@ -90,6 +90,8 @@ public static String receive(int port) { } catch (IOException e) { e.printStackTrace(); + } catch (JSONException e) { + e.printStackTrace(); } return APIResponse.toString(); } diff --git a/src/com/rubix/Resources/APIHandler.java b/src/com/rubix/Resources/APIHandler.java index 8320ae79..7151e760 100644 --- a/src/com/rubix/Resources/APIHandler.java +++ b/src/com/rubix/Resources/APIHandler.java @@ -176,24 +176,28 @@ public static JSONObject creditsInfo(){ File quorumFile = new File(qstFile); File minedFile = new File(mineFile); - + JSONObject returnObject = new JSONObject(); int spentCredits = 0; int unspentCredits = 0; - if(quorumFile.exists()){ - String qFile = readFile(qstFile); - JSONArray qArray = new JSONArray(qFile); - unspentCredits = qArray.length(); - } - if(minedFile.exists()){ - String mFile = readFile(mineFile); - JSONArray mArray = new JSONArray(mFile); - spentCredits = mArray.length(); + try { + if(quorumFile.exists()){ + String qFile = readFile(qstFile); + JSONArray qArray = new JSONArray(qFile); + unspentCredits = qArray.length(); + } + if(minedFile.exists()){ + String mFile = readFile(mineFile); + JSONArray mArray = new JSONArray(mFile); + spentCredits = mArray.length(); + } + + + returnObject.put("spentCredits",spentCredits); + returnObject.put("unspentCredits",unspentCredits); + } catch (JSONException e) { + //TODO: handle exception } - JSONObject returnObject = new JSONObject(); - returnObject.put("spentCredits",spentCredits); - returnObject.put("unspentCredits",unspentCredits); - return returnObject; } diff --git a/src/com/rubix/Resources/Functions.java b/src/com/rubix/Resources/Functions.java index f6a88756..ac62ec92 100644 --- a/src/com/rubix/Resources/Functions.java +++ b/src/com/rubix/Resources/Functions.java @@ -1,24 +1,22 @@ package com.rubix.Resources; -import static com.rubix.Resources.APIHandler.addPublicData; -import static com.rubix.Resources.IPFSNetwork.IPFSNetworkLogger; -import static com.rubix.Resources.IPFSNetwork.checkSwarmConnect; -import static com.rubix.Resources.IPFSNetwork.executeIPFSCommands; -import static com.rubix.Resources.IPFSNetwork.forwardCheck; -import static com.rubix.Resources.IPFSNetwork.listen; -import static com.rubix.Resources.IPFSNetwork.swarmConnectP2P; -import static com.rubix.Resources.IPFSNetwork.swarmConnectProcess; +import com.rubix.AuthenticateNode.PropImage; +import com.rubix.Ping.PingCheck; +import io.ipfs.api.IPFS; +import io.ipfs.multiaddr.MultiAddress; +import org.apache.log4j.Logger; +import org.apache.log4j.PropertyConfigurator; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import javax.imageio.ImageIO; import java.awt.image.BufferedImage; -import java.io.BufferedReader; -import java.io.DataOutputStream; -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStreamReader; +import java.io.*; import java.math.RoundingMode; import java.net.HttpURLConnection; +import java.net.Socket; +import java.net.SocketException; import java.net.URL; import java.nio.charset.StandardCharsets; import java.nio.file.Files; @@ -34,18 +32,9 @@ import java.util.LinkedHashSet; import java.util.Set; -import javax.imageio.ImageIO; - -import com.rubix.AuthenticateNode.PropImage; -import com.rubix.Ping.PingCheck; - -import org.apache.log4j.PropertyConfigurator; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; +import static com.rubix.Resources.APIHandler.addPublicData; +import static com.rubix.Resources.IPFSNetwork.*; -import io.ipfs.api.IPFS; -import io.ipfs.multiaddr.MultiAddress; public class Functions { @@ -56,8 +45,7 @@ public class Functions { public static String LOGGER_PATH = ""; public static String WALLET_DATA_PATH = ""; public static String PAYMENTS_PATH = ""; - public static int RECEIVER_PORT, GOSSIP_SENDER, GOSSIP_RECEIVER, QUORUM_PORT, SENDER2Q1, SENDER2Q2, SENDER2Q3, - SENDER2Q4, SENDER2Q5, SENDER2Q6, SENDER2Q7; + public static int RECEIVER_PORT, GOSSIP_SENDER, GOSSIP_RECEIVER, QUORUM_PORT, SENDER2Q1, SENDER2Q2, SENDER2Q3, SENDER2Q4, SENDER2Q5, SENDER2Q6, SENDER2Q7; public static int QUORUM_COUNT; public static int SEND_PORT; public static int IPFS_PORT; @@ -136,11 +124,13 @@ public static void pathSet() { BOOTSTRAPS = pathsArray.getJSONArray(5); + } catch (JSONException e) { e.printStackTrace(); } } + public static void nodeData(String did, String wid, IPFS ipfs) throws IOException { PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); File dataFolder = new File(DATA_PATH + did + "/"); @@ -214,9 +204,9 @@ public static String getSystemUser() { return lineID; } + /** - * This method calculates different types of hashes as mentioned in the passed - * parameters for the mentioned message + * This method calculates different types of hashes as mentioned in the passed parameters for the mentioned message * * @param message Input string to be hashed * @param algorithm Specification of the algorithm used for hashing @@ -283,13 +273,13 @@ public static String bytesToHex(byte[] inputHash) { StringBuilder outputHexString = new StringBuilder(); for (byte b : inputHash) { String hex = Integer.toHexString(0xff & b); - if (hex.length() == 1) - outputHexString.append('0'); + if (hex.length() == 1) outputHexString.append('0'); outputHexString.append(hex); } return outputHexString.toString(); } + /** * This method returns the content of the file passed to it * @@ -311,15 +301,14 @@ public static String readFile(String filePath) { return fileContent.toString(); } + /** * This method writes the mentioned data into the file passed to it - * This also allows to take a decision on whether or not to append the data to - * the already existing content in the file + * This also allows to take a decision on whether or not to append the data to the already existing content in the file * * @param filePath Location of the file to be read and written into * @param data Data to be added - * @param appendStatus Decides whether or not to append the new data into the - * already existing data + * @param appendStatus Decides whether or not to append the new data into the already existing data */ public synchronized static void writeToFile(String filePath, String data, Boolean appendStatus) { @@ -360,6 +349,7 @@ public static String getSignFromShares(String filePath, String hash) throws IOEx return p1; } + /** * This function will sign on JSON data with private share * @@ -404,6 +394,7 @@ public static void listenThread(JSONObject connectObject) { } + /** * This function converts any integer to its binary form * @@ -490,8 +481,7 @@ public static void updateJSON(String operation, String filePath, String data) { } /** - * This method gets you a required data from a JSON file with a tag to be - * compared with + * This method gets you a required data from a JSON file with a tag to be compared with * * @param filePath Location of the JSON file * @param get Data to be fetched from the file @@ -528,8 +518,7 @@ public static String getOsName() { } /** - * This function calculates the minimum number of quorum peers required for - * consensus to work + * This function calculates the minimum number of quorum peers required for consensus to work * * @return Minimum number of quorum count for consensus to work */ @@ -538,8 +527,7 @@ public static int minQuorum() { } /** - * This function calculates the minimum number of quorum peers required for - * consensus to work + * This function calculates the minimum number of quorum peers required for consensus to work * * @return Minimum number of quorum count for consensus to work */ @@ -547,6 +535,7 @@ public static int minQuorum(int count) { return (((count - 1) / 3) * 2) + 1; } + /** * This method checks if Quorum is available for consensus * @@ -585,6 +574,7 @@ public static ArrayList QuorumCheck(JSONArray quorum, int size) { * @param ipfs ipfs instance */ + public static void QuorumSwarmConnect(JSONArray quorum, IPFS ipfs) { PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); @@ -603,6 +593,7 @@ public static void QuorumSwarmConnect(JSONArray quorum, IPFS ipfs) { } + /** * This method identifies the Peer ID of the system by IPFS during installation * @@ -610,6 +601,7 @@ public static void QuorumSwarmConnect(JSONArray quorum, IPFS ipfs) { * @return Your system's Peer ID assigned by IPFS */ + public static String getPeerID(String filePath) { PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); JSONArray fileContentArray; @@ -627,6 +619,7 @@ public static String getPeerID(String filePath) { return peerid; } + public static int[] getPrivatePosition(int[] positions, int[] privateArray) { int[] PrivatePosition = new int[positions.length]; for (int k = 0; k < positions.length; k++) { @@ -637,8 +630,7 @@ public static int[] getPrivatePosition(int[] positions, int[] privateArray) { return PrivatePosition; } - public static JSONObject randomPositions(String role, String hash, int numberOfPositions, int[] pvt1) - throws JSONException { + public static JSONObject randomPositions(String role, String hash, int numberOfPositions, int[] pvt1) throws JSONException { int u = 0, l = 0, m = 0; int[] hashCharacters = new int[256]; @@ -695,19 +687,18 @@ public static JSONObject randomPositions(String role, String hash, int numberOfP * @param positionsCount Number of positions required * @return Extended array of positions */ - // public static int[] finalPositions(int[] randomPositions, int positionsCount) - // { - // int[] finalPositions = new int[positionsCount * 64]; - // int u = 0; - // for (int k = 0; k < positionsCount; k++) { - // for (int p = 0; p < 64; p++) { - // finalPositions[u] = randomPositions[k]; - // randomPositions[k]++; - // u++; - // } - // } - // return finalPositions; - // } +// public static int[] finalPositions(int[] randomPositions, int positionsCount) { +// int[] finalPositions = new int[positionsCount * 64]; +// int u = 0; +// for (int k = 0; k < positionsCount; k++) { +// for (int p = 0; p < 64; p++) { +// finalPositions[u] = randomPositions[k]; +// randomPositions[k]++; +// u++; +// } +// } +// return finalPositions; +// } /** * This function deletes the mentioned file @@ -725,43 +716,41 @@ public static void deleteFile(String fileName) { } - // /** - // * This functions picks the required number of quorum members from the - // mentioned file - // * - // * @param filePath Location of the file - // * @param hash Data from which positions are chosen - // * @return List of chosen members from the file - // */ - // public static ArrayList quorumChooser(String filePath, String hash) { - // PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); - // ArrayList quorumList = new ArrayList(); - // try { - // String fileContent = readFile(filePath); - // JSONArray blockHeight = new JSONArray(fileContent); - // - // int[] hashCharacters = new int[256]; - // var randomPositions = new ArrayList(); - // HashSet positionSet = new HashSet<>(); - // for (int k = 0; positionSet.size() != 7; k++) { - // hashCharacters[k] = Character.getNumericValue(hash.charAt(k)); - // randomPositions.add((((2402 + hashCharacters[k]) * 2709) + ((k + 2709) + - // hashCharacters[(k)])) % blockHeight.length()); - // positionSet.add(randomPositions.get(k)); - // } - // - // for (Integer integer : positionSet) - // quorumList.add(blockHeight.getJSONObject(integer).getString("peer-id")); - // } catch (JSONException e) { - // FunctionsLogger.error("JSON Exception Occurred", e); - // e.printStackTrace(); - // } - // return quorumList; - // } + +// /** +// * This functions picks the required number of quorum members from the mentioned file +// * +// * @param filePath Location of the file +// * @param hash Data from which positions are chosen +// * @return List of chosen members from the file +// */ +// public static ArrayList quorumChooser(String filePath, String hash) { +// PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); +// ArrayList quorumList = new ArrayList(); +// try { +// String fileContent = readFile(filePath); +// JSONArray blockHeight = new JSONArray(fileContent); +// +// int[] hashCharacters = new int[256]; +// var randomPositions = new ArrayList(); +// HashSet positionSet = new HashSet<>(); +// for (int k = 0; positionSet.size() != 7; k++) { +// hashCharacters[k] = Character.getNumericValue(hash.charAt(k)); +// randomPositions.add((((2402 + hashCharacters[k]) * 2709) + ((k + 2709) + hashCharacters[(k)])) % blockHeight.length()); +// positionSet.add(randomPositions.get(k)); +// } +// +// for (Integer integer : positionSet) +// quorumList.add(blockHeight.getJSONObject(integer).getString("peer-id")); +// } catch (JSONException e) { +// FunctionsLogger.error("JSON Exception Occurred", e); +// e.printStackTrace(); +// } +// return quorumList; +// } /** - * This function is to be initially called to setup the environment of your - * project + * This function is to be initially called to setup the environment of your project */ public static void launch() { pathSet(); @@ -807,8 +796,7 @@ public static String checkDirectory() throws JSONException { File tokenChainsFolder = new File(TOKENCHAIN_PATH); File walletDataFolder = new File(WALLET_DATA_PATH); - if (!dataFolder.exists() || !loggerFolder.exists() || !tokenChainsFolder.exists() || !tokensFolder.exists() - || !walletDataFolder.exists()) { + if (!dataFolder.exists() || !loggerFolder.exists() || !tokenChainsFolder.exists() || !tokensFolder.exists() || !walletDataFolder.exists()) { dataFolder.delete(); loggerFolder.delete(); tokenChainsFolder.delete(); @@ -885,6 +873,7 @@ public static String mineToken(int level, int tokenNumber) { return token; } + public static String toBinary(int x, int len) { if (len > 0) { return String.format("%" + len + "s", @@ -921,6 +910,7 @@ public static Date getCurrentUtcTime() throws ParseException { return localDateFormat.parse(simpleDateFormat.format(new Date())); } + /** * This method is used to update quorum credits in server * @@ -931,8 +921,8 @@ public static Date getCurrentUtcTime() throws ParseException { * @return mined token */ - public static void updateQuorum(JSONArray quorumArray, JSONArray signedQuorumList, boolean status, int type) - throws IOException, JSONException { + + public static void updateQuorum(JSONArray quorumArray, JSONArray signedQuorumList, boolean status, int type) throws IOException, JSONException { if (type == 1) { String urlQuorumUpdate = ADVISORY_IP + "/updateQuorum"; @@ -974,6 +964,7 @@ public static void updateQuorum(JSONArray quorumArray, JSONArray signedQuorumLis } } + /** * This method is used get getquorum from advisory node * @@ -985,8 +976,8 @@ public static void updateQuorum(JSONArray quorumArray, JSONArray signedQuorumLis * @return JSONArray of quorum nodes */ - public static JSONArray getQuorum(String betaHash, String gammaHash, String senderDidIpfsHash, - String receiverDidIpfsHash, int tokenslength) throws IOException, JSONException { + + public static JSONArray getQuorum(String betaHash, String gammaHash, String senderDidIpfsHash, String receiverDidIpfsHash, int tokenslength) throws IOException, JSONException { JSONArray quorumArray; String urlQuorumPick = ADVISORY_IP + "/getQuorum"; URL objQuorumPick = new URL(urlQuorumPick); @@ -1116,7 +1107,8 @@ public static void syncDataTable(String did, String peerId) { public static void removeToken() { String bnkFile = readFile(PAYMENTS_PATH.concat("BNK00.json")); - JSONArray bnkArray = new JSONArray(bnkFile); + try { + JSONArray bnkArray = new JSONArray(bnkFile); JSONObject removeToken = bnkArray.getJSONObject(0); bnkArray.remove(0); writeToFile(PAYMENTS_PATH.concat("BNK00.json"), bnkArray.toString(), false); @@ -1137,13 +1129,17 @@ public static void removeToken() { removeArray.put(removeToken); writeToFile(PAYMENTS_PATH.concat("DoubleSpent.json"), removeArray.toString(), false); } + } catch (JSONException e) { + //TODO: handle exception + } } public static void tokenBank() { pathSet(); String bank = readFile(PAYMENTS_PATH.concat("BNK00.json")); - JSONArray bankArray = new JSONArray(bank); + try { + JSONArray bankArray = new JSONArray(bank); ArrayList bankDuplicates = new ArrayList<>(); for (int i = 0; i < bankArray.length(); i++) { @@ -1175,6 +1171,9 @@ public static void tokenBank() { if (!bankDuplicates.contains(tokenFiles.get(i).toString())) deleteFile(TOKENS_PATH.concat(tokenFiles.get(i).toString())); } + } catch (JSONException e) { + //TODO: handle exception + } } @@ -1204,11 +1203,9 @@ public static Double getPartsBalance() throws JSONException { Double availableParts = 0.000D, senderCount = 0.000D, receiverCount = 0.000D; for (int k = 0; k < tokenChainArray.length(); k++) { if (tokenChainArray.getJSONObject(k).has("role")) { - if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") - && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { + if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { senderCount += tokenChainArray.getJSONObject(k).getDouble("amount"); - } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") - && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { + } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { receiverCount += tokenChainArray.getJSONObject(k).getDouble("amount"); } } @@ -1221,6 +1218,7 @@ public static Double getPartsBalance() throws JSONException { parts = formatAmount(parts); balance = balance + parts; + int count = 0; File shiftedFile = new File(PAYMENTS_PATH.concat("ShiftedTokens.json")); if (shiftedFile.exists()) { @@ -1230,6 +1228,7 @@ public static Double getPartsBalance() throws JSONException { for (int i = 0; i < shiftedArray.length(); i++) arrayTokens.add(shiftedArray.getString(i)); + for (int i = 0; i < partTokensArray.length(); i++) { if (!arrayTokens.contains(partTokensArray.getJSONObject(i).getString("tokenHash"))) count++; @@ -1257,11 +1256,9 @@ public static Double checkTokenPartBalance(String tokenHash) throws JSONExceptio Double senderCount = 0.000D, receiverCount = 0.000D; for (int k = 0; k < tokenChainArray.length(); k++) { if (tokenChainArray.getJSONObject(k).has("role")) { - if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") - && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { + if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { senderCount += tokenChainArray.getJSONObject(k).getDouble("amount"); - } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") - && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { + } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { receiverCount += tokenChainArray.getJSONObject(k).getDouble("amount"); } } @@ -1278,6 +1275,7 @@ public static Double checkTokenPartBalance(String tokenHash) throws JSONExceptio return availableParts; } + public static Double getBalance() throws JSONException { pathSet(); Double balance = 0.000D; @@ -1296,6 +1294,7 @@ public static Double getBalance() throws JSONException { balance = balance + value; } + File partsFile = new File(PAYMENTS_PATH + "PartsToken.json"); if (partsFile.exists()) { String PART_TOKEN_CHAIN_PATH = TOKENCHAIN_PATH.concat("/PARTS/"); @@ -1314,11 +1313,9 @@ public static Double getBalance() throws JSONException { Double availableParts = 0.000D, senderCount = 0.000D, receiverCount = 0.000D; for (int k = 0; k < tokenChainArray.length(); k++) { if (tokenChainArray.getJSONObject(k).has("role")) { - if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") - && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { + if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { senderCount += tokenChainArray.getJSONObject(k).getDouble("amount"); - } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") - && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { + } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { receiverCount += tokenChainArray.getJSONObject(k).getDouble("amount"); } } @@ -1341,6 +1338,7 @@ public static Double getBalance() throws JSONException { for (int i = 0; i < shiftedArray.length(); i++) arrayTokens.add(shiftedArray.getString(i)); + for (int i = 0; i < partTokensArray.length(); i++) { if (!arrayTokens.contains(partTokensArray.getJSONObject(i).getString("tokenHash"))) count++; @@ -1351,10 +1349,12 @@ public static Double getBalance() throws JSONException { balance = balance - count; } + balance = formatAmount(balance); return balance; } + public static Double partTokenBalance(String tokenHash) throws JSONException { pathSet(); @@ -1368,11 +1368,9 @@ public static Double partTokenBalance(String tokenHash) throws JSONException { Double senderCount = 0.000D, receiverCount = 0.000D; for (int k = 0; k < tokenChainArray.length(); k++) { if (tokenChainArray.getJSONObject(k).has("role")) { - if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") - && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { + if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { senderCount += tokenChainArray.getJSONObject(k).getDouble("amount"); - } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") - && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { + } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { receiverCount += tokenChainArray.getJSONObject(k).getDouble("amount"); } } @@ -1403,29 +1401,24 @@ public static Double formatAmount(Double amount) { public static void clearParts() { String partsFile = readFile(PAYMENTS_PATH.concat("PartsToken.json")); - JSONArray partsArray = new JSONArray(partsFile); + try { + JSONArray partsArray = new JSONArray(partsFile); for (int i = 0; i < partsArray.length(); i++) { - if (partTokenBalance(partsArray.getJSONObject(i).getString("tokenHash")) <= 0.000 - || partTokenBalance(partsArray.getJSONObject(i).getString("tokenHash")) > 1.000) { + if (partTokenBalance(partsArray.getJSONObject(i).getString("tokenHash")) <= 0.000 || partTokenBalance(partsArray.getJSONObject(i).getString("tokenHash")) > 1.000) { deleteFile(TOKENS_PATH.concat("PARTS/").concat(partsArray.getJSONObject(i).getString("tokenHash"))); partsArray.remove(i); } } writeToFile(PAYMENTS_PATH.concat("PartsToken.json"), partsArray.toString(), false); + } catch (JSONException e) { + //TODO: handle exception + } } public static void backgroundChecks() { - try { - Functions.tokenBank(); - } catch (JSONException e) { - e.printStackTrace(); - } + Functions.tokenBank(); - try { - Functions.clearParts(); - } catch (JSONException e) { - e.printStackTrace(); - } + Functions.clearParts(); IPFS ipfs = new IPFS("/ip4/127.0.0.1/tcp/" + IPFS_PORT); IPFSNetwork.repo(ipfs); @@ -1433,9 +1426,7 @@ public static void backgroundChecks() { addPublicData(); } - public static String sanityMessage; - public static boolean sanityCheck(String peerid, IPFS ipfs, int port) throws IOException { FunctionsLogger.info("Entering SanityCheck"); boolean sanityCheckErrorFlag = true; @@ -1484,9 +1475,9 @@ public static boolean sanityCheck(String peerid, IPFS ipfs, int port) throws IOE } } + return sanityCheckErrorFlag; } - public static boolean checkIPFSStatus(String peerid, IPFS ipfs) { FunctionsLogger.info("Entering checkIPFSStatus"); boolean swarmConnectedStatus = false; @@ -1494,7 +1485,7 @@ public static boolean checkIPFSStatus(String peerid, IPFS ipfs) { MultiAddress multiAddress = new MultiAddress("/ipfs/" + peerid); FunctionsLogger.info("MultiAdrress concated " + multiAddress + "|||"); boolean output = swarmConnectP2P(peerid, ipfs); - + FunctionsLogger.info("Swarm connect process response is " + output); if (output) { swarmConnectedStatus = true; FunctionsLogger.debug("Swarm is already connected"); @@ -1510,59 +1501,66 @@ public static boolean checkIPFSStatus(String peerid, IPFS ipfs) { return swarmConnectedStatus; } - public static boolean ping(String peerid, int port) throws IOException { - JSONObject pingCheck = PingCheck.Ping(peerid, port); + + public static boolean ping(String peerid, int port) { + boolean result=false; + try { + JSONObject pingCheck = PingCheck.Ping(peerid, port); if (pingCheck.getString("status").contains("Failed")) { - return false; + result = false; } else - return true; + result = true; + } catch (JSONException e) { + //TODO: handle exception + } catch (IOException e) { + //TODO: handle exception + } + return result; } - // public static String getPing(int port) { - // try { - // - // String didContent = readFile(DATA_PATH + "DID.json"); - // JSONArray didArray = new JSONArray(didContent); - // String myPeerID = didArray.getJSONObject(0).getString("peerid"); - // - // listen(myPeerID.concat("Ping"), port); - // ServerSocket ss = new ServerSocket(port); - // FunctionsLogger.info("Get Ping Listening on port " + port + " appname " + - // myPeerID.concat("Ping")); - // Socket socket = ss.accept(); - // BufferedReader input = new BufferedReader(new - // InputStreamReader(socket.getInputStream())); - // PrintStream output = new PrintStream(socket.getOutputStream()); - // FunctionsLogger.info("getPing- waiting response from server"); - // String peerID = input.readLine(); - // if (peerID != null && peerID.contains("Qm")) { - // FunctionsLogger.info("getPing - Received message from server"); - // output.println("Ping received"); - // FunctionsLogger.debug("Ping received from sender"); - // - // output.close(); - // input.close(); - // socket.close(); - // ss.close(); - // executeIPFSCommands(" ipfs p2p close -t /p2p/" + peerID); - // FunctionsLogger.info("If - Closing Sockets"); - // return "Ping received from sender and Pong sent"; - // } - // else{ - // output.close(); - // input.close(); - // socket.close(); - // ss.close(); - // FunctionsLogger.info("Else - Closing Sockets"); - // return "Ping received from sender but not PeerID"; - // } - // - // } catch (Exception e) { - // FunctionsLogger.error("Error in client side communication", e); - // return "Error in client side communication"; - // } - // } +// public static String getPing(int port) { +// try { +// +// String didContent = readFile(DATA_PATH + "DID.json"); +// JSONArray didArray = new JSONArray(didContent); +// String myPeerID = didArray.getJSONObject(0).getString("peerid"); +// +// listen(myPeerID.concat("Ping"), port); +// ServerSocket ss = new ServerSocket(port); +// FunctionsLogger.info("Get Ping Listening on port " + port + " appname " + myPeerID.concat("Ping")); +// Socket socket = ss.accept(); +// BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream())); +// PrintStream output = new PrintStream(socket.getOutputStream()); +// FunctionsLogger.info("getPing- waiting response from server"); +// String peerID = input.readLine(); +// if (peerID != null && peerID.contains("Qm")) { +// FunctionsLogger.info("getPing - Received message from server"); +// output.println("Ping received"); +// FunctionsLogger.debug("Ping received from sender"); +// +// output.close(); +// input.close(); +// socket.close(); +// ss.close(); +// executeIPFSCommands(" ipfs p2p close -t /p2p/" + peerID); +// FunctionsLogger.info("If - Closing Sockets"); +// return "Ping received from sender and Pong sent"; +// } +// else{ +// output.close(); +// input.close(); +// socket.close(); +// ss.close(); +// FunctionsLogger.info("Else - Closing Sockets"); +// return "Ping received from sender but not PeerID"; +// } +// +// } catch (Exception e) { +// FunctionsLogger.error("Error in client side communication", e); +// return "Error in client side communication"; +// } +// } public static boolean bootstrapConnect(String peerid, IPFS ipfs) { FunctionsLogger.info("bootstrapConnect- entering function"); @@ -1636,8 +1634,7 @@ public static boolean portCheckAndKill(int port) { } /** - * This function will release the port in linux based machines if the port is - * already in use + * This function will release the port in linux based machines if the port is already in use */ public static boolean releasePorts(int port) { FunctionsLogger.info("releasePorts- "); @@ -1658,8 +1655,7 @@ public static boolean releasePorts(int port) { if (processStr != null) { FunctionsLogger.info("releasePorts- Processstr is not null"); if (String.valueOf(currentPid) != processStr && ipfsPidBr.readLine() != processStr) { - FunctionsLogger.info("releasePorts- jar is running on " + currentPid + " and IPFS is occupied in " - + ipfsPidBr.readLine()); + FunctionsLogger.info("releasePorts- jar is running on " + currentPid + " and IPFS is occupied in " + ipfsPidBr.readLine()); FunctionsLogger.debug("Port " + port + " is in using, killing PID " + processStr); processId = Runtime.getRuntime().exec("kill -9 " + processStr); FunctionsLogger.info("releasePorts- killing " + processStr); @@ -1728,4 +1724,7 @@ public static boolean portStatusWindows(int port) { } + + } + From 5d66f4be4ba269fca8441e2164b754247b9dbb27 Mon Sep 17 00:00:00 2001 From: Gokul P S Date: Fri, 11 Mar 2022 16:22:36 +0530 Subject: [PATCH 28/49] Logical updates to fetch Win64 Sanity --- src/com/rubix/Resources/Functions.java | 441 +++++++++++++------------ 1 file changed, 227 insertions(+), 214 deletions(-) diff --git a/src/com/rubix/Resources/Functions.java b/src/com/rubix/Resources/Functions.java index ac62ec92..f69aff0d 100644 --- a/src/com/rubix/Resources/Functions.java +++ b/src/com/rubix/Resources/Functions.java @@ -1,22 +1,24 @@ package com.rubix.Resources; -import com.rubix.AuthenticateNode.PropImage; -import com.rubix.Ping.PingCheck; -import io.ipfs.api.IPFS; -import io.ipfs.multiaddr.MultiAddress; -import org.apache.log4j.Logger; -import org.apache.log4j.PropertyConfigurator; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; +import static com.rubix.Resources.APIHandler.addPublicData; +import static com.rubix.Resources.IPFSNetwork.IPFSNetworkLogger; +import static com.rubix.Resources.IPFSNetwork.checkSwarmConnect; +import static com.rubix.Resources.IPFSNetwork.executeIPFSCommands; +import static com.rubix.Resources.IPFSNetwork.forwardCheck; +import static com.rubix.Resources.IPFSNetwork.listen; +import static com.rubix.Resources.IPFSNetwork.swarmConnectP2P; +import static com.rubix.Resources.IPFSNetwork.swarmConnectProcess; -import javax.imageio.ImageIO; import java.awt.image.BufferedImage; -import java.io.*; +import java.io.BufferedReader; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStreamReader; import java.math.RoundingMode; import java.net.HttpURLConnection; -import java.net.Socket; -import java.net.SocketException; import java.net.URL; import java.nio.charset.StandardCharsets; import java.nio.file.Files; @@ -32,9 +34,18 @@ import java.util.LinkedHashSet; import java.util.Set; -import static com.rubix.Resources.APIHandler.addPublicData; -import static com.rubix.Resources.IPFSNetwork.*; +import javax.imageio.ImageIO; + +import com.rubix.AuthenticateNode.PropImage; +import com.rubix.Ping.PingCheck; +import org.apache.log4j.PropertyConfigurator; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import io.ipfs.api.IPFS; +import io.ipfs.multiaddr.MultiAddress; public class Functions { @@ -45,7 +56,8 @@ public class Functions { public static String LOGGER_PATH = ""; public static String WALLET_DATA_PATH = ""; public static String PAYMENTS_PATH = ""; - public static int RECEIVER_PORT, GOSSIP_SENDER, GOSSIP_RECEIVER, QUORUM_PORT, SENDER2Q1, SENDER2Q2, SENDER2Q3, SENDER2Q4, SENDER2Q5, SENDER2Q6, SENDER2Q7; + public static int RECEIVER_PORT, GOSSIP_SENDER, GOSSIP_RECEIVER, QUORUM_PORT, SENDER2Q1, SENDER2Q2, SENDER2Q3, + SENDER2Q4, SENDER2Q5, SENDER2Q6, SENDER2Q7; public static int QUORUM_COUNT; public static int SEND_PORT; public static int IPFS_PORT; @@ -124,13 +136,11 @@ public static void pathSet() { BOOTSTRAPS = pathsArray.getJSONArray(5); - } catch (JSONException e) { e.printStackTrace(); } } - public static void nodeData(String did, String wid, IPFS ipfs) throws IOException { PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); File dataFolder = new File(DATA_PATH + did + "/"); @@ -204,9 +214,9 @@ public static String getSystemUser() { return lineID; } - /** - * This method calculates different types of hashes as mentioned in the passed parameters for the mentioned message + * This method calculates different types of hashes as mentioned in the passed + * parameters for the mentioned message * * @param message Input string to be hashed * @param algorithm Specification of the algorithm used for hashing @@ -273,13 +283,13 @@ public static String bytesToHex(byte[] inputHash) { StringBuilder outputHexString = new StringBuilder(); for (byte b : inputHash) { String hex = Integer.toHexString(0xff & b); - if (hex.length() == 1) outputHexString.append('0'); + if (hex.length() == 1) + outputHexString.append('0'); outputHexString.append(hex); } return outputHexString.toString(); } - /** * This method returns the content of the file passed to it * @@ -301,14 +311,15 @@ public static String readFile(String filePath) { return fileContent.toString(); } - /** * This method writes the mentioned data into the file passed to it - * This also allows to take a decision on whether or not to append the data to the already existing content in the file + * This also allows to take a decision on whether or not to append the data to + * the already existing content in the file * * @param filePath Location of the file to be read and written into * @param data Data to be added - * @param appendStatus Decides whether or not to append the new data into the already existing data + * @param appendStatus Decides whether or not to append the new data into the + * already existing data */ public synchronized static void writeToFile(String filePath, String data, Boolean appendStatus) { @@ -349,7 +360,6 @@ public static String getSignFromShares(String filePath, String hash) throws IOEx return p1; } - /** * This function will sign on JSON data with private share * @@ -394,7 +404,6 @@ public static void listenThread(JSONObject connectObject) { } - /** * This function converts any integer to its binary form * @@ -481,7 +490,8 @@ public static void updateJSON(String operation, String filePath, String data) { } /** - * This method gets you a required data from a JSON file with a tag to be compared with + * This method gets you a required data from a JSON file with a tag to be + * compared with * * @param filePath Location of the JSON file * @param get Data to be fetched from the file @@ -518,7 +528,8 @@ public static String getOsName() { } /** - * This function calculates the minimum number of quorum peers required for consensus to work + * This function calculates the minimum number of quorum peers required for + * consensus to work * * @return Minimum number of quorum count for consensus to work */ @@ -527,7 +538,8 @@ public static int minQuorum() { } /** - * This function calculates the minimum number of quorum peers required for consensus to work + * This function calculates the minimum number of quorum peers required for + * consensus to work * * @return Minimum number of quorum count for consensus to work */ @@ -535,7 +547,6 @@ public static int minQuorum(int count) { return (((count - 1) / 3) * 2) + 1; } - /** * This method checks if Quorum is available for consensus * @@ -574,7 +585,6 @@ public static ArrayList QuorumCheck(JSONArray quorum, int size) { * @param ipfs ipfs instance */ - public static void QuorumSwarmConnect(JSONArray quorum, IPFS ipfs) { PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); @@ -593,7 +603,6 @@ public static void QuorumSwarmConnect(JSONArray quorum, IPFS ipfs) { } - /** * This method identifies the Peer ID of the system by IPFS during installation * @@ -601,7 +610,6 @@ public static void QuorumSwarmConnect(JSONArray quorum, IPFS ipfs) { * @return Your system's Peer ID assigned by IPFS */ - public static String getPeerID(String filePath) { PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); JSONArray fileContentArray; @@ -619,7 +627,6 @@ public static String getPeerID(String filePath) { return peerid; } - public static int[] getPrivatePosition(int[] positions, int[] privateArray) { int[] PrivatePosition = new int[positions.length]; for (int k = 0; k < positions.length; k++) { @@ -630,7 +637,8 @@ public static int[] getPrivatePosition(int[] positions, int[] privateArray) { return PrivatePosition; } - public static JSONObject randomPositions(String role, String hash, int numberOfPositions, int[] pvt1) throws JSONException { + public static JSONObject randomPositions(String role, String hash, int numberOfPositions, int[] pvt1) + throws JSONException { int u = 0, l = 0, m = 0; int[] hashCharacters = new int[256]; @@ -687,18 +695,19 @@ public static JSONObject randomPositions(String role, String hash, int numberOfP * @param positionsCount Number of positions required * @return Extended array of positions */ -// public static int[] finalPositions(int[] randomPositions, int positionsCount) { -// int[] finalPositions = new int[positionsCount * 64]; -// int u = 0; -// for (int k = 0; k < positionsCount; k++) { -// for (int p = 0; p < 64; p++) { -// finalPositions[u] = randomPositions[k]; -// randomPositions[k]++; -// u++; -// } -// } -// return finalPositions; -// } + // public static int[] finalPositions(int[] randomPositions, int positionsCount) + // { + // int[] finalPositions = new int[positionsCount * 64]; + // int u = 0; + // for (int k = 0; k < positionsCount; k++) { + // for (int p = 0; p < 64; p++) { + // finalPositions[u] = randomPositions[k]; + // randomPositions[k]++; + // u++; + // } + // } + // return finalPositions; + // } /** * This function deletes the mentioned file @@ -716,41 +725,43 @@ public static void deleteFile(String fileName) { } - -// /** -// * This functions picks the required number of quorum members from the mentioned file -// * -// * @param filePath Location of the file -// * @param hash Data from which positions are chosen -// * @return List of chosen members from the file -// */ -// public static ArrayList quorumChooser(String filePath, String hash) { -// PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); -// ArrayList quorumList = new ArrayList(); -// try { -// String fileContent = readFile(filePath); -// JSONArray blockHeight = new JSONArray(fileContent); -// -// int[] hashCharacters = new int[256]; -// var randomPositions = new ArrayList(); -// HashSet positionSet = new HashSet<>(); -// for (int k = 0; positionSet.size() != 7; k++) { -// hashCharacters[k] = Character.getNumericValue(hash.charAt(k)); -// randomPositions.add((((2402 + hashCharacters[k]) * 2709) + ((k + 2709) + hashCharacters[(k)])) % blockHeight.length()); -// positionSet.add(randomPositions.get(k)); -// } -// -// for (Integer integer : positionSet) -// quorumList.add(blockHeight.getJSONObject(integer).getString("peer-id")); -// } catch (JSONException e) { -// FunctionsLogger.error("JSON Exception Occurred", e); -// e.printStackTrace(); -// } -// return quorumList; -// } + // /** + // * This functions picks the required number of quorum members from the + // mentioned file + // * + // * @param filePath Location of the file + // * @param hash Data from which positions are chosen + // * @return List of chosen members from the file + // */ + // public static ArrayList quorumChooser(String filePath, String hash) { + // PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); + // ArrayList quorumList = new ArrayList(); + // try { + // String fileContent = readFile(filePath); + // JSONArray blockHeight = new JSONArray(fileContent); + // + // int[] hashCharacters = new int[256]; + // var randomPositions = new ArrayList(); + // HashSet positionSet = new HashSet<>(); + // for (int k = 0; positionSet.size() != 7; k++) { + // hashCharacters[k] = Character.getNumericValue(hash.charAt(k)); + // randomPositions.add((((2402 + hashCharacters[k]) * 2709) + ((k + 2709) + + // hashCharacters[(k)])) % blockHeight.length()); + // positionSet.add(randomPositions.get(k)); + // } + // + // for (Integer integer : positionSet) + // quorumList.add(blockHeight.getJSONObject(integer).getString("peer-id")); + // } catch (JSONException e) { + // FunctionsLogger.error("JSON Exception Occurred", e); + // e.printStackTrace(); + // } + // return quorumList; + // } /** - * This function is to be initially called to setup the environment of your project + * This function is to be initially called to setup the environment of your + * project */ public static void launch() { pathSet(); @@ -796,7 +807,8 @@ public static String checkDirectory() throws JSONException { File tokenChainsFolder = new File(TOKENCHAIN_PATH); File walletDataFolder = new File(WALLET_DATA_PATH); - if (!dataFolder.exists() || !loggerFolder.exists() || !tokenChainsFolder.exists() || !tokensFolder.exists() || !walletDataFolder.exists()) { + if (!dataFolder.exists() || !loggerFolder.exists() || !tokenChainsFolder.exists() || !tokensFolder.exists() + || !walletDataFolder.exists()) { dataFolder.delete(); loggerFolder.delete(); tokenChainsFolder.delete(); @@ -873,7 +885,6 @@ public static String mineToken(int level, int tokenNumber) { return token; } - public static String toBinary(int x, int len) { if (len > 0) { return String.format("%" + len + "s", @@ -910,7 +921,6 @@ public static Date getCurrentUtcTime() throws ParseException { return localDateFormat.parse(simpleDateFormat.format(new Date())); } - /** * This method is used to update quorum credits in server * @@ -921,8 +931,8 @@ public static Date getCurrentUtcTime() throws ParseException { * @return mined token */ - - public static void updateQuorum(JSONArray quorumArray, JSONArray signedQuorumList, boolean status, int type) throws IOException, JSONException { + public static void updateQuorum(JSONArray quorumArray, JSONArray signedQuorumList, boolean status, int type) + throws IOException, JSONException { if (type == 1) { String urlQuorumUpdate = ADVISORY_IP + "/updateQuorum"; @@ -964,7 +974,6 @@ public static void updateQuorum(JSONArray quorumArray, JSONArray signedQuorumLis } } - /** * This method is used get getquorum from advisory node * @@ -976,8 +985,8 @@ public static void updateQuorum(JSONArray quorumArray, JSONArray signedQuorumLis * @return JSONArray of quorum nodes */ - - public static JSONArray getQuorum(String betaHash, String gammaHash, String senderDidIpfsHash, String receiverDidIpfsHash, int tokenslength) throws IOException, JSONException { + public static JSONArray getQuorum(String betaHash, String gammaHash, String senderDidIpfsHash, + String receiverDidIpfsHash, int tokenslength) throws IOException, JSONException { JSONArray quorumArray; String urlQuorumPick = ADVISORY_IP + "/getQuorum"; URL objQuorumPick = new URL(urlQuorumPick); @@ -1109,28 +1118,28 @@ public static void removeToken() { String bnkFile = readFile(PAYMENTS_PATH.concat("BNK00.json")); try { JSONArray bnkArray = new JSONArray(bnkFile); - JSONObject removeToken = bnkArray.getJSONObject(0); - bnkArray.remove(0); - writeToFile(PAYMENTS_PATH.concat("BNK00.json"), bnkArray.toString(), false); + JSONObject removeToken = bnkArray.getJSONObject(0); + bnkArray.remove(0); + writeToFile(PAYMENTS_PATH.concat("BNK00.json"), bnkArray.toString(), false); - File doubleSpentFile = new File(PAYMENTS_PATH.concat("DoubleSpent.json")); - if (!doubleSpentFile.exists()) { - try { - doubleSpentFile.createNewFile(); - } catch (IOException e) { - FunctionsLogger.debug("File couldn't be created"); + File doubleSpentFile = new File(PAYMENTS_PATH.concat("DoubleSpent.json")); + if (!doubleSpentFile.exists()) { + try { + doubleSpentFile.createNewFile(); + } catch (IOException e) { + FunctionsLogger.debug("File couldn't be created"); + } + JSONArray removeArray = new JSONArray(); + removeArray.put(removeToken); + writeToFile(PAYMENTS_PATH.concat("DoubleSpent.json"), removeArray.toString(), false); + } else { + String removeFile = readFile(PAYMENTS_PATH.concat("DoubleSpent.json")); + JSONArray removeArray = new JSONArray(removeFile); + removeArray.put(removeToken); + writeToFile(PAYMENTS_PATH.concat("DoubleSpent.json"), removeArray.toString(), false); } - JSONArray removeArray = new JSONArray(); - removeArray.put(removeToken); - writeToFile(PAYMENTS_PATH.concat("DoubleSpent.json"), removeArray.toString(), false); - } else { - String removeFile = readFile(PAYMENTS_PATH.concat("DoubleSpent.json")); - JSONArray removeArray = new JSONArray(removeFile); - removeArray.put(removeToken); - writeToFile(PAYMENTS_PATH.concat("DoubleSpent.json"), removeArray.toString(), false); - } } catch (JSONException e) { - //TODO: handle exception + // TODO: handle exception } } @@ -1141,38 +1150,38 @@ public static void tokenBank() { try { JSONArray bankArray = new JSONArray(bank); - ArrayList bankDuplicates = new ArrayList<>(); - for (int i = 0; i < bankArray.length(); i++) { - if (!bankDuplicates.contains(bankArray.getJSONObject(i).getString("tokenHash"))) - bankDuplicates.add(bankArray.getJSONObject(i).getString("tokenHash")); - } + ArrayList bankDuplicates = new ArrayList<>(); + for (int i = 0; i < bankArray.length(); i++) { + if (!bankDuplicates.contains(bankArray.getJSONObject(i).getString("tokenHash"))) + bankDuplicates.add(bankArray.getJSONObject(i).getString("tokenHash")); + } - if (bankDuplicates.size() < bankArray.length()) { - FunctionsLogger.debug("Duplicates Found. Cleaning up ..."); + if (bankDuplicates.size() < bankArray.length()) { + FunctionsLogger.debug("Duplicates Found. Cleaning up ..."); - JSONArray newBank = new JSONArray(); - for (int i = 0; i < bankDuplicates.size(); i++) { - JSONObject tokenObject = new JSONObject(); - tokenObject.put("tokenHash", bankDuplicates.get(i)); - newBank.put(tokenObject); + JSONArray newBank = new JSONArray(); + for (int i = 0; i < bankDuplicates.size(); i++) { + JSONObject tokenObject = new JSONObject(); + tokenObject.put("tokenHash", bankDuplicates.get(i)); + newBank.put(tokenObject); + } + writeToFile(PAYMENTS_PATH.concat("BNK00.json"), newBank.toString(), false); } - writeToFile(PAYMENTS_PATH.concat("BNK00.json"), newBank.toString(), false); - } - File tokensPath = new File(TOKENS_PATH); - String contents[] = tokensPath.list(); - ArrayList tokenFiles = new ArrayList(); - for (int i = 0; i < contents.length; i++) { - if (!contents[i].contains("PARTS")) - tokenFiles.add(contents[i]); - } + File tokensPath = new File(TOKENS_PATH); + String contents[] = tokensPath.list(); + ArrayList tokenFiles = new ArrayList(); + for (int i = 0; i < contents.length; i++) { + if (!contents[i].contains("PARTS")) + tokenFiles.add(contents[i]); + } - for (int i = 0; i < tokenFiles.size(); i++) { - if (!bankDuplicates.contains(tokenFiles.get(i).toString())) - deleteFile(TOKENS_PATH.concat(tokenFiles.get(i).toString())); - } + for (int i = 0; i < tokenFiles.size(); i++) { + if (!bankDuplicates.contains(tokenFiles.get(i).toString())) + deleteFile(TOKENS_PATH.concat(tokenFiles.get(i).toString())); + } } catch (JSONException e) { - //TODO: handle exception + // TODO: handle exception } } @@ -1203,9 +1212,11 @@ public static Double getPartsBalance() throws JSONException { Double availableParts = 0.000D, senderCount = 0.000D, receiverCount = 0.000D; for (int k = 0; k < tokenChainArray.length(); k++) { if (tokenChainArray.getJSONObject(k).has("role")) { - if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { + if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") + && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { senderCount += tokenChainArray.getJSONObject(k).getDouble("amount"); - } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { + } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") + && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { receiverCount += tokenChainArray.getJSONObject(k).getDouble("amount"); } } @@ -1218,7 +1229,6 @@ public static Double getPartsBalance() throws JSONException { parts = formatAmount(parts); balance = balance + parts; - int count = 0; File shiftedFile = new File(PAYMENTS_PATH.concat("ShiftedTokens.json")); if (shiftedFile.exists()) { @@ -1228,7 +1238,6 @@ public static Double getPartsBalance() throws JSONException { for (int i = 0; i < shiftedArray.length(); i++) arrayTokens.add(shiftedArray.getString(i)); - for (int i = 0; i < partTokensArray.length(); i++) { if (!arrayTokens.contains(partTokensArray.getJSONObject(i).getString("tokenHash"))) count++; @@ -1256,9 +1265,11 @@ public static Double checkTokenPartBalance(String tokenHash) throws JSONExceptio Double senderCount = 0.000D, receiverCount = 0.000D; for (int k = 0; k < tokenChainArray.length(); k++) { if (tokenChainArray.getJSONObject(k).has("role")) { - if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { + if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") + && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { senderCount += tokenChainArray.getJSONObject(k).getDouble("amount"); - } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { + } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") + && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { receiverCount += tokenChainArray.getJSONObject(k).getDouble("amount"); } } @@ -1275,7 +1286,6 @@ public static Double checkTokenPartBalance(String tokenHash) throws JSONExceptio return availableParts; } - public static Double getBalance() throws JSONException { pathSet(); Double balance = 0.000D; @@ -1294,7 +1304,6 @@ public static Double getBalance() throws JSONException { balance = balance + value; } - File partsFile = new File(PAYMENTS_PATH + "PartsToken.json"); if (partsFile.exists()) { String PART_TOKEN_CHAIN_PATH = TOKENCHAIN_PATH.concat("/PARTS/"); @@ -1313,9 +1322,11 @@ public static Double getBalance() throws JSONException { Double availableParts = 0.000D, senderCount = 0.000D, receiverCount = 0.000D; for (int k = 0; k < tokenChainArray.length(); k++) { if (tokenChainArray.getJSONObject(k).has("role")) { - if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { + if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") + && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { senderCount += tokenChainArray.getJSONObject(k).getDouble("amount"); - } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { + } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") + && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { receiverCount += tokenChainArray.getJSONObject(k).getDouble("amount"); } } @@ -1338,7 +1349,6 @@ public static Double getBalance() throws JSONException { for (int i = 0; i < shiftedArray.length(); i++) arrayTokens.add(shiftedArray.getString(i)); - for (int i = 0; i < partTokensArray.length(); i++) { if (!arrayTokens.contains(partTokensArray.getJSONObject(i).getString("tokenHash"))) count++; @@ -1349,12 +1359,10 @@ public static Double getBalance() throws JSONException { balance = balance - count; } - balance = formatAmount(balance); return balance; } - public static Double partTokenBalance(String tokenHash) throws JSONException { pathSet(); @@ -1368,9 +1376,11 @@ public static Double partTokenBalance(String tokenHash) throws JSONException { Double senderCount = 0.000D, receiverCount = 0.000D; for (int k = 0; k < tokenChainArray.length(); k++) { if (tokenChainArray.getJSONObject(k).has("role")) { - if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { + if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") + && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { senderCount += tokenChainArray.getJSONObject(k).getDouble("amount"); - } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { + } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") + && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { receiverCount += tokenChainArray.getJSONObject(k).getDouble("amount"); } } @@ -1403,15 +1413,16 @@ public static void clearParts() { String partsFile = readFile(PAYMENTS_PATH.concat("PartsToken.json")); try { JSONArray partsArray = new JSONArray(partsFile); - for (int i = 0; i < partsArray.length(); i++) { - if (partTokenBalance(partsArray.getJSONObject(i).getString("tokenHash")) <= 0.000 || partTokenBalance(partsArray.getJSONObject(i).getString("tokenHash")) > 1.000) { - deleteFile(TOKENS_PATH.concat("PARTS/").concat(partsArray.getJSONObject(i).getString("tokenHash"))); - partsArray.remove(i); + for (int i = 0; i < partsArray.length(); i++) { + if (partTokenBalance(partsArray.getJSONObject(i).getString("tokenHash")) <= 0.000 + || partTokenBalance(partsArray.getJSONObject(i).getString("tokenHash")) > 1.000) { + deleteFile(TOKENS_PATH.concat("PARTS/").concat(partsArray.getJSONObject(i).getString("tokenHash"))); + partsArray.remove(i); + } } - } - writeToFile(PAYMENTS_PATH.concat("PartsToken.json"), partsArray.toString(), false); + writeToFile(PAYMENTS_PATH.concat("PartsToken.json"), partsArray.toString(), false); } catch (JSONException e) { - //TODO: handle exception + // TODO: handle exception } } @@ -1426,7 +1437,9 @@ public static void backgroundChecks() { addPublicData(); } + public static String sanityMessage; + public static boolean sanityCheck(String peerid, IPFS ipfs, int port) throws IOException { FunctionsLogger.info("Entering SanityCheck"); boolean sanityCheckErrorFlag = true; @@ -1475,9 +1488,9 @@ public static boolean sanityCheck(String peerid, IPFS ipfs, int port) throws IOE } } - return sanityCheckErrorFlag; } + public static boolean checkIPFSStatus(String peerid, IPFS ipfs) { FunctionsLogger.info("Entering checkIPFSStatus"); boolean swarmConnectedStatus = false; @@ -1501,66 +1514,67 @@ public static boolean checkIPFSStatus(String peerid, IPFS ipfs) { return swarmConnectedStatus; } - public static boolean ping(String peerid, int port) { - boolean result=false; + boolean result = false; try { JSONObject pingCheck = PingCheck.Ping(peerid, port); - if (pingCheck.getString("status").contains("Failed")) { - result = false; - } else - result = true; + if (pingCheck.getString("status").contains("Failed")) { + result = false; + } else + result = true; } catch (JSONException e) { - //TODO: handle exception + // TODO: handle exception } catch (IOException e) { - //TODO: handle exception + // TODO: handle exception } - return result; + return result; } -// public static String getPing(int port) { -// try { -// -// String didContent = readFile(DATA_PATH + "DID.json"); -// JSONArray didArray = new JSONArray(didContent); -// String myPeerID = didArray.getJSONObject(0).getString("peerid"); -// -// listen(myPeerID.concat("Ping"), port); -// ServerSocket ss = new ServerSocket(port); -// FunctionsLogger.info("Get Ping Listening on port " + port + " appname " + myPeerID.concat("Ping")); -// Socket socket = ss.accept(); -// BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream())); -// PrintStream output = new PrintStream(socket.getOutputStream()); -// FunctionsLogger.info("getPing- waiting response from server"); -// String peerID = input.readLine(); -// if (peerID != null && peerID.contains("Qm")) { -// FunctionsLogger.info("getPing - Received message from server"); -// output.println("Ping received"); -// FunctionsLogger.debug("Ping received from sender"); -// -// output.close(); -// input.close(); -// socket.close(); -// ss.close(); -// executeIPFSCommands(" ipfs p2p close -t /p2p/" + peerID); -// FunctionsLogger.info("If - Closing Sockets"); -// return "Ping received from sender and Pong sent"; -// } -// else{ -// output.close(); -// input.close(); -// socket.close(); -// ss.close(); -// FunctionsLogger.info("Else - Closing Sockets"); -// return "Ping received from sender but not PeerID"; -// } -// -// } catch (Exception e) { -// FunctionsLogger.error("Error in client side communication", e); -// return "Error in client side communication"; -// } -// } + // public static String getPing(int port) { + // try { + // + // String didContent = readFile(DATA_PATH + "DID.json"); + // JSONArray didArray = new JSONArray(didContent); + // String myPeerID = didArray.getJSONObject(0).getString("peerid"); + // + // listen(myPeerID.concat("Ping"), port); + // ServerSocket ss = new ServerSocket(port); + // FunctionsLogger.info("Get Ping Listening on port " + port + " appname " + + // myPeerID.concat("Ping")); + // Socket socket = ss.accept(); + // BufferedReader input = new BufferedReader(new + // InputStreamReader(socket.getInputStream())); + // PrintStream output = new PrintStream(socket.getOutputStream()); + // FunctionsLogger.info("getPing- waiting response from server"); + // String peerID = input.readLine(); + // if (peerID != null && peerID.contains("Qm")) { + // FunctionsLogger.info("getPing - Received message from server"); + // output.println("Ping received"); + // FunctionsLogger.debug("Ping received from sender"); + // + // output.close(); + // input.close(); + // socket.close(); + // ss.close(); + // executeIPFSCommands(" ipfs p2p close -t /p2p/" + peerID); + // FunctionsLogger.info("If - Closing Sockets"); + // return "Ping received from sender and Pong sent"; + // } + // else{ + // output.close(); + // input.close(); + // socket.close(); + // ss.close(); + // FunctionsLogger.info("Else - Closing Sockets"); + // return "Ping received from sender but not PeerID"; + // } + // + // } catch (Exception e) { + // FunctionsLogger.error("Error in client side communication", e); + // return "Error in client side communication"; + // } + // } public static boolean bootstrapConnect(String peerid, IPFS ipfs) { FunctionsLogger.info("bootstrapConnect- entering function"); @@ -1620,7 +1634,7 @@ public static boolean portCheckAndKill(int port) { boolean portStatus = false; try { - if (getOsName().toLowerCase().contains("windows")) { + if (!getOsName().toLowerCase().contains("windows")) { portStatus = releasePorts(port); } else { portStatusWindows(port); @@ -1634,7 +1648,8 @@ public static boolean portCheckAndKill(int port) { } /** - * This function will release the port in linux based machines if the port is already in use + * This function will release the port in linux based machines if the port is + * already in use */ public static boolean releasePorts(int port) { FunctionsLogger.info("releasePorts- "); @@ -1655,7 +1670,8 @@ public static boolean releasePorts(int port) { if (processStr != null) { FunctionsLogger.info("releasePorts- Processstr is not null"); if (String.valueOf(currentPid) != processStr && ipfsPidBr.readLine() != processStr) { - FunctionsLogger.info("releasePorts- jar is running on " + currentPid + " and IPFS is occupied in " + ipfsPidBr.readLine()); + FunctionsLogger.info("releasePorts- jar is running on " + currentPid + " and IPFS is occupied in " + + ipfsPidBr.readLine()); FunctionsLogger.debug("Port " + port + " is in using, killing PID " + processStr); processId = Runtime.getRuntime().exec("kill -9 " + processStr); FunctionsLogger.info("releasePorts- killing " + processStr); @@ -1724,7 +1740,4 @@ public static boolean portStatusWindows(int port) { } - - } - From 26729a8adec00002b66bdd8a40df8131703788e7 Mon Sep 17 00:00:00 2001 From: aparnaullas-rubix Date: Fri, 18 Mar 2022 16:23:25 +0300 Subject: [PATCH 29/49] Adding genesis information after mining and token ownership check at the receiver side --- .../rubix/AuthenticateNode/Authenticate.class | Bin 3140 -> 4035 bytes .../rubix/AuthenticateNode/SecretShare.class | Bin 23619 -> 15740 bytes .../rubix/AuthenticateNode/SplitShares.class | Bin 2940 -> 1744 bytes .../rubix/Consensus/InitiatorConsensus.class | Bin 7266 -> 11608 bytes .../rubix/Consensus/InitiatorProcedure.class | Bin 4211 -> 6221 bytes .../com/rubix/Consensus/QuorumConsensus.class | Bin 4680 -> 13168 bytes .../rubix/Constants/ConsensusConstants.class | Bin 515 -> 469 bytes .../com/rubix/Constants/IPFSConstants.class | Bin 1193 -> 1149 bytes .../RubiX/com/rubix/Resources/Functions.class | Bin 13126 -> 42020 bytes .../com/rubix/Resources/IPFSNetwork.class | Bin 7152 -> 12293 bytes .../com/rubix/SplitandStore/Recombine.class | Bin 2390 -> 2178 bytes .../rubix/SplitandStore/SeperateShares.class | Bin 824 -> 822 bytes .../RubiX/com/rubix/SplitandStore/Split.class | Bin 3173 -> 3198 bytes src/com/rubix/Consensus/QuorumConsensus.java | 6 - src/com/rubix/Mining/ProofCredits.java | 96 +++-- src/com/rubix/Resources/Functions.java | 351 ++++++++--------- .../rubix/TokenTransfer/TokenReceiver.java | 370 ++++++++++-------- src/com/rubix/TokenTransfer/TokenSender.java | 68 +++- 18 files changed, 507 insertions(+), 384 deletions(-) diff --git a/out/production/RubiX/com/rubix/AuthenticateNode/Authenticate.class b/out/production/RubiX/com/rubix/AuthenticateNode/Authenticate.class index 27d1a54271859879c7cdd78193031de16ebbeb20..f0c4a8c3779c72606ac9591cac554fea4c934686 100644 GIT binary patch literal 4035 zcmbVO>t7Vt8Geon%v0M;uZy^V ze@`-F*;am^fUm86M4+mN+JmS?oq}}&>sJw`B7}N@K-$cg6>n|pUo^2NW8`vO?W@`n zfIx$aYShSCScL+=KwZCOn@0;%z3AFd$VMrN_x?(Vfth8<93oey~mwGUicP%^J)jlQ=Ja9H?X7iR~=M>ya!#zJO zM~^3N?I_qN&?KXEGUwR(;i1IQC3~9~$;IFlMei?InUv`U(28~iZ31^M+CFIJoPwJ) zb9!IFPI{VE+>b3xVSnP_!2^RQ2D*n2$?)7RwJV4Y=nA6C5L48s;sI1Dlr=Iqm$lyXgg+PGG;!Sb)Br~<}EW9L<@GScnC3p8Y7!E z?UX>rQqAR1S74IzI z9alw<^ed1ot(giAFm}wYm7U13kSsku&^P4AK_;GSJN0ebcSRrI-!?s;%<3|KaTSLp zegpF4iGjr6u(Y^eI(kr|bSRjyQ~g79jEt-?W;@UqE&(qMsy?o8+HNMSG(kcibXOY~V8(+?7^U+<0g zMzeN0h||~+#2K7ZaF#VCPoCASDI;x4R*_>oq2h6Tk_mH7gF%dzjN!hNS1wcIOul$e z-(Q%RFkLg{-KI-V;3)-93bZV;%F^e;dt_uic;{7o8c#C|)>L}?xMd4$FR5Ei{t8j_ z`!;EO80gcr!$u3@K~sR1WvdBiBNZv_#RiH{#=8Lm)ctcw>3$gGp=b6oiv$TIt? zim&18EIU4MxAEi(1y-U?1uqG#k+xqXQ9G`cwrnFqLnSAFQ^mLNZBk&8q3Nd3D$+ua zoI$x?p4|ZQ1iz zehtR_c$M5VA{z(Uo$wKC?lXu$vQaI5s^ThsMqey@!dXQEn+i2$=6R>gS5=Z(<>OUR zI+6&yqtcuelg0d}%p_YS*T`6p6YjkPU6D-UsW|0I79r>4_{^9t>&?Trz&%AktcGXW zcm=ac7wg<&EU2BSzNaaRq-Q zzC1!&B?8h=ujP>JB2d4SE28ou?q#FqWB0lS0ok{47LZ*VM<2fd1i8PKzqWCd|7tZc z5A`}U-*q%z%CR*0-Lzfb)BOWP<{U#B8%5*yu}9ZidsB?58^H! z4B&3uL!lqyyoO^l?vr*@Jwhv~KrAevWpoCc=dpDT+qDO0v1=Ax^Z4)#8mk_oZ42lf zm1nd*?$6-REFR&3IUMa@Kw^|;eB{VhZEzODN4IJp;}EObs*TC9x`Q4*S``0SNqn*> zUNg0H$2_c9O-H0=%RHtQaN1KcgVM+fplzDtA=3n{jXO^7}L;~_` zP->sU`PkY>^*o-5soLiwRiWmHI*;dLwUJuw%d_~(+qe*0$N4u(^Sa2o(OAQcPR-X@ ze;FGh4dMD|XDG5Z5)6lC@$xLbbL@P*2-k_^vXgJ`Xi7U?b=E5hoj&;1tD? zjuY&VpTrhCL$)+pXg)mvPBK&@>kYXf5{fXZ- H`1Ah&ZK4(} literal 3140 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 literal 23619 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 D^IyVb diff --git a/out/production/RubiX/com/rubix/AuthenticateNode/SplitShares.class b/out/production/RubiX/com/rubix/AuthenticateNode/SplitShares.class index f4b1264a2e07425b6dca2c25a075c9f1149a8189..0f1b1c0b0a93933f82ddef5e130da6f981e83313 100644 GIT binary patch literal 1744 zcmah}ZBrXn6n-utY_eSg1Zb^RgaS38$QH!58j1ofnz|)Oked2ZH=E0Hnayt8>}vHl z`9(8BIx^!A@JDre?%g2K7EC7DbI(05&pGEg`}d1K{{nCi2O0(#Za6{H4CA_ZX0FH4 zA@?KU*b(0j8r-b5JP}n7?U1)M3^I%y*+1E)XZx;MsULACVi@hSu>#lSA;VQG2wl@| z+0G$1y}(^LGLx$k!=Pv#v>Ec22uvxGnJ~*cTUB`%@n(x*!cuACNOGq8xUs#r+1uwL-Z!t-itZ(3YgfvVjkhPGU|r=Z*ml z84Vv%rLUoij=LzyO2?(~Jp)zjuePGgVCWNeiy8>&Rw)tRp#U~8 z1}zoWz*iuWYoh5c*9Gm&^8exJ<8+TZ8op+jxgcBFkEm8B((xE`^6wi1-{L!lOHRm7 zd!Y7>iX3imhu%k_?TKHh`1=f#Ny_s&L+G7=GRQ5@zlu(+ev+SI?xG2u!ld!&RYm(P zA?H5Q_qJP<)WbCKBt@@NjaWt-OHx*nlb#vLJG#9@@&F7v6Z@2&xTow!FsjZ(GJ2-S zVhrQtF+ryvDVqGO=h<^y?%>)9CTk~{s^zbDG5ZG!$9Vr3OI>`}!R-^=t#$En2dn80 z)>0jOdV&qo-0$GQ?-XPJpV9wi6>@~qjAE9Uy-4Y9Q?k#M1t>ACOfS7jPe%Imd>7@j z5JO5itXz!501xp68S1d`h!Sm+JV-YcRYi@elHD1be~vG$6Fjcn?4tH);TTVTBXxo+ nr%a{^-F0frj0!%LxZ!&|CA&1~e}GM4b0pW{kS9Y!Mc^+1s9mX} literal 2940 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 diff --git a/out/production/RubiX/com/rubix/Consensus/InitiatorProcedure.class b/out/production/RubiX/com/rubix/Consensus/InitiatorProcedure.class index bda14d24d196c619c3eb86ee2511cb9ad4e6bc4c..93ce6eab2aaac24f69fbccf887f93d7f7a1552f1 100644 GIT binary patch literal 6221 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 literal 4211 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 G*8c&uN_o2g literal 4680 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 diff --git a/out/production/RubiX/com/rubix/Constants/ConsensusConstants.class b/out/production/RubiX/com/rubix/Constants/ConsensusConstants.class index dc8c209664c36ede48a8964cf836d7ae849d25c1..12a23be2a729fdffd3ee38700823779d32d3725d 100644 GIT binary patch delta 265 zcmYk0y-vbl7=@p&KeW~=MFsyR7osj*8GyuK6IdWY!(N4GiNQhQs)-jsdMQjM4koPb z-j4CmiRI)xdCz-tKAc}W`uY3%23nkYScZDOs@FUmLo`ia)A%W!J;Z~%>EwQ%R~!8; zgMFKg4Nmv!rt1@~UHbB92!=@~>5Yff$?3=9lr402oy%nah}3=-@Nk`sL_oTL~TxC2A|gF=1deLRChI2fcE z8CX0VgFQGHWEdH^f?S7UAWZ*#Ja{~EXNPKP}p9hK0%fRRk)C_b9kQ4wK rp%0`Pfi$bub_T|cU^4}QBpX-EBMZr<8%B<2L6=U*aum2;eaS*<-wzJ$pk^V_o^M-F zAx|w9^&~kRHabzwKV*8cW;-pPFa3ej_ALx_ytd0@LY|q5??+)2*sPJTYpj=U*kNPa zYkuK}y2D1YQhLX6f{<*n+H^fPS|K|(v`(duzbuI%77Ze7NOyiP; zA>odC7IH!%WyqX`jF22dh^q=|LtNwJLdf;GYIihK_l82oL`?VU_J%d&tU}h1w=E1x zdUt$7%_$5T>Q1j$BS@}ZHQc;{GTi+hM|E;ROFDX}Fl4w#$E}hxNs9`@hA3JXk-Lt? z6naHr#L!QBdDK^kX9}Z+cy3`#@(hvB`xHHI)R&-jg;OTzWiOj%2=Pim8=}Ou`AeX- zG01earEnTawp4OGXRFhyIKi%6X*y<;{HopDvjf+hk3J@g;%62Kloj4$jGjgfmtIem z{=2-~#BAB`1XX9mnvHCiB=RtILk{&po(Qa@FojitGV`gx8gpIX8FNG6 zIdfCs1@ooA7IRzR6>~@6HS>)?h51%sm$@gf&wMBFo>>(*V17vAFo};EglBbKyL;qo zkd@sk@G2 z)q_aN)?7F61J8^t!f*BBQo3PU9k;)e*@&0ZTc+P~o%Yvw^`;g3b87XjWqE#78ZFZ~ zgEbAqbMuE95}R(r(vYv%jF);q_|v z7h}_P{J?Yq-`LsTs-8YkCZb$#$9tu#ZqKV*Tee#HALAmYsl&is4LTpO$Wa%Ybsa^_ z^fijK=yi%ZuCbOBa7I6CH8%qVZv8XXHPMQ5Z2(Zt&rVsR= diff --git a/out/production/RubiX/com/rubix/Resources/Functions.class b/out/production/RubiX/com/rubix/Resources/Functions.class index c6dc4ee9beddad8bf6b9be7e88f4420f8450137c..a628e4d328b002815c4082544fd2abf078ab0272 100644 GIT binary patch literal 42020 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 WHAdMGnjn=b10(BpV2#DZx&r`sYtxnh literal 13126 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 B@Oc0L diff --git a/out/production/RubiX/com/rubix/Resources/IPFSNetwork.class b/out/production/RubiX/com/rubix/Resources/IPFSNetwork.class index c19d656e82d8286903b75e6169af9fb3f8814efb..f78bdc5bfad66ee54af06b51f81802f04ee41a81 100644 GIT binary patch literal 12293 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 literal 7152 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 eFNTkC?c;j%_s93X zU+?~X>kfcJcw2%?V0+QHkTP3^>bt3YqgJ)FdMR%irkw!krD3^6ppf_un<&@UYiWNOoGs=4wQtho#0eP%gtJbU5O9JkAVot!5 zF-m#>L4+hI0-K*=svwLm0e@MyI&KEy*@w|&YFe{7ns};bKLj=?@WRK4vrK2Eb)le} zr?f&%7wFC!MXffcnN@qeD)fyxfd=44kAh8*8LU;QHU)NM|Fc?5)o*r6C$J@ccFO)s ztO+@9nbmrERKixK{V6^x$^=$*Veav+AQ!B zD5KbA*JrnYy4GYhzr>u3L4h8p5l(BhnrGcI*nK!4VZT8CV~uvA9n__aQ9oZTw@i)wui&7a zm%q3wW2Z*ZV}Bj8gJu_Rjb|SB(+N$+xIi>MG%zx-HxbM0MN_w8oEKBqEWH#v7_*s< z*i4yqSwFSj9cp`Ijw+bIq=2`i7h2_Y+Do#HQWIs1ng9n&7R!# z$J=oy5Nc?bYKB&->GiTz5fG#j$N5~~vp|xf(W+Z?;>qNuk1(j&qnUZ`dmTB)osGpx zmh|Gh(_&OCXiW}ZC~s-Scc!(5Gj|fm8^}8iK2f!YGyLF!N!rn|(@Dmwi)8jZ6S*Nn z;$usI1mE_@-z{z;@HHY|ap6KYzkSYD02>{NO~J8VHB0er8+v!$fV$p9c1)DE0yg6r zD*DljEp20W0v>dcZ~Qi*XRc%0P3*XVMEAfllFJyriL@=hfzg=_xR>@sWYtsoHgM1z zk<-3j?;X`=ulz)O1>9+A35R#7Qqpr3l4l7X_wKce_Xi$XeFUY~uS%ZW68tuB=N2WQ zN^RO}E4SR~pgXNNr2FlCo7J}%q>AU9>T7(AJ~bGTuaYI8Ds2`5vM7S4k8pkOPRmO; z9E7tr-o=IN92ksolC0W%DHq%4SOr;uwxjJudVz%sD>^tW9;;zEL0|bZRNY` zh}iY$ewj5IT*hIRXc?~%4S&hHx}Br?06U1gSm_92*noZ>RT4cIreutj&tNO2cssVx zhxgbMi(FsEAU>ql6%N!V7{U^@KgS5Z;pK1}d+`JI;V$;$9uD9~>ik58U-2q_!*TqM zEdIc>aAQXJkrf+pQbgH{{m6?^oN~_pO8bm)jCTBpaoSGVJwbGw$c31Qk!PAY^wW9< zIrc?TbmIhfy%-i@oTSXhvHc6PL=t|%Jn}>`#)OA{rr1{*+{bG~0cP_B=C~VVPM_g4 zk-}*A;B}%9V;;g8qA=cIIGZ!!QE-ueeuk=@b& literal 2390 zcma)7OK%%h6#i~z>=`?@<31*C+K{Gg3VAe1(}zprwlsBH8tTMtohFn}l8G~_r*UR1 zdt4DDq%OK*!GaA138{)e*&$$&NTrko5(@-khg1n9R{R8{B9-u6J8lwO72?d?bI#oJ zo$oyE%nyIxe+VFs=^#Ql6vSa1k+-87;z6j=qT*NpFXQ-D?mHR8DZC|I3wUc zVLP^WNkdD}Cc*^K8Ft^O+(pUe;|ArLKjMccVC<_5sB z3o9^dWv6bL`7(1=XUq~8eXsN?GQ?~Q7R*?yZ3+6)JHD~jd zbHmFqp^LocdEF#H)-5|8vDIXHgl+I$IhUN`b6>^IZjg#VFyoesS?jzlI}mwV%syF* z5W+B zQkcz*1hj(Wmv>0H9xowJq3*f0s%`Il2C|0NWv|{8=vXhk?c8$bthHlQrGMVc@)#~? zc#HK-x$a!KAP^dM9IKejo28P)obGPqu!d0`iwiu)d8^b>bxhPv`bNtp$FYTiweev! zm&D`-gzB6mHs-blku>x9jO|$o4O0U9>+*XRH-Wb2@53H6@&zgX6!2ss!g~|7ey)P6 zuX_dJO9~B$^6sw~6>Om#s&2qmY@-&yb{Mos=eq<`xb}4~qv1g?rJQV)(jwZrTbH3k z58gwtr&UQWLF;K%({~!g((3O$U(iFTL}`OY+0VPiNIG^AeJ_c=Nc{jw%INLf8^As^ zBSvnFg&k<&s^KN`?xKj~;E)~DWsrY=EMdNwMz4{XvtLZ~HR zXeu)fNI^;8(U|j!5^q%Ep-rGe^0`C}7>(+5ypdkhhQIJJ_8N^*{T_jWMyLuzK}l1Y zmJp2<#QREIH<-a9PAl=S8jn=4qxvGFsTJL>U9?J;yE+e?!oA=lWu;)6v9%k*ES#??O4%WMewLQ*}vbe{g#iRZX z4&q%5;5NU$@8bwQ#8G_05Aza^;d6d}S1^cgkid61f$zEJN2KrzM(_xu_?2h*4_v}y zT*fNW!iO;t=8Jk8#>H+-ROa9=d-#aB?c@@s#{lEU*mw4oEOwErl=f97LP{N!8la0- z?B_fw2#XjeCdOH477=vvsSi6v5M8wSIaPn6o05i~ah3VSn0JQ&r%=vh51I8+3Nphb z?u~IqZ{t%Qo)}MuoWIYoeU%RyIf1o*RmgGV+pb~)nosllx5~ZG+0-CJ>VNDB`Fu~9 znrLb9>AqE_8LkCo^tHG$dX)g4ph<}Rk6AW_O_E1^0FzvUJRsL_9dEF;gVc5E30^1u E0gNyT#Q*>R diff --git a/out/production/RubiX/com/rubix/SplitandStore/SeperateShares.class b/out/production/RubiX/com/rubix/SplitandStore/SeperateShares.class index e241e653954ab2325dd20676d94667ddd8fa11ef..a42c7d262ce89319a69d7b1fb50b5c78b9d4aa9a 100644 GIT binary patch delta 459 zcmX9)Ju?GQ6g_vd`(Cm_7KxPzA&7{P%rFzfpwUpEU>N0w48owuXes=G%>DqQ($XXb zqtmGM8kHY`vlQ>#d+yh{_dTela^AilUjQs%Lcy=t{ zw=PighbM>iML{S(z9lf1PWP%dLWo3RK{XaGl}4w)^+nv64F{0`;!z~fPPlA7!P#k{Yt9Ol)h)V` zRv|r=$f#ly-P>165^C}#VIJK4d?l?W+&gxMVEfmGdy#^T9Oq9{DbQX1pN&4G$*6*U z4E*gfiwr%3`6&$Yv|!I7vW%ICV-&*};fXH$Mj2C_3NqsdDQJx`5sf^b!y7v|aGYuW GO5qoHY&*jM delta 458 zcmX9&O)o=H5Iyrg?ron}iauIj)mCXMZIhBF6>MyfU_prGL!+&xEE-!D{y@DSAhEG! z(+c7T_yLx-mi88yTQ`|AGv}T;Gi~uGmfn7zUI7#_Ye6C=5x1ZrrXZnUN+KySO%RLK zMzy(2&{OGMg0XUXRBqKTeFUm;ta){cd)G7{3T!vs!;=m7Y{xyQmnA|HVef+yrVStb zt*;Tw#tc$6(#W&|=|MuU=AOIxy4yI;ZynUihfOa`DQ}(P7l=XdS?XyZHP2{qm*-5J z%}fXM(EaXV6kSq>&9(h6Kmfhm`O$|UGivx9de^iR^o>?ttj(aWXgovP??7KL^`dY@ z_SG>ew}?6sGc#6jM6L~E?@G|!?`Onp!@Oq~9X;NSHhd9d&n)}T@kX_GmA!{ChJFn2 zJwOSA2ys@G!<;(1gdwgpRu)(rR$j;^DowrXEgv ztf1NX=YP-t8a{Y(Ok$MVJO@r78OG%BEv zW%5qJaZgdSw{J$kKVF=(!)QfBLz}?fCx{w|qFo@AwcSlKM|u;F{Tk0(mC9(}6D@}z z&}l$}E)YpL1^dj3>?HEhCY#;oIG>x>e`E9tIBH-B#{_~_sbm-C z1fFlUuo;jY78;?T?>#tf-~{5V9Jg5K7kH|7SEpXUh=#8SJiDWY&eok;8ZQ>+oouyi zvA_+CqMH?!Y2a9dhjG%tDSVaw=Iuh(&3Q#Sr3j}DyohlUGOYX4%&fn6s&8Dw83B1| zN<&Z;*vke22x|B`Yt0K<)phc*)8(?YlyE9;7*p66#x#-|UKMD69M`FWYqND!KF%_p zRNWMk29d#-!Z`yeoTppX9D})~x;E4GdKfeKhK7rzKXzig$n0zuP8zQ>>y=z}eqL37 zXCo(`x5`nLs4{lhz#F(iV{AHQY>QV7bLu+R3|J~?x>ImxR4M7m2psGkIx>9ZMBjdI zQtY3!3pV4<%H5x;W?0FU`D$MEy=`C~S+>laJzM3z>!mm-d=;0oMZChbz{RN(%oM8y zcZeA%@FNObi(EH}a1?eyVX0A8)hTsUeFz0zd$FWWb$}SH;0*(Iwpow+*1WNw_iP;y zOQp>r(Z8F(*e=;SMJ=r<*UDU!lbwG)W==@g*wDKj63LfhX;wL_zilbR+t_JJaMo! z#A4i)V4(jl_HGwx@kER|1G?}9GKTO)bk~Igf1@W+TKVK%^rUa&>2*AN7Xuy7uOYUE z;dOjDs`sy9EcaeG;XAd8ll?tw_*&fWJGqKp(;q0kiO4`tRL^x^^CeedG+=*{w0zvZ zEJb%zU#b0J*(Z9Go|W2tJ?@X{@qqqYyp;Au_4mSQ&7Vx`T+yKV@RUlEg#;hZey#vl zGgB%Zcrx9S5AI5DGNA2X*y_PZOOu1me$dDN2louqZw5ZXgdAyo1htv|fekZ|Q|LRG z^u8tZB` zwPU8<)xwPu`Wi01kLfjB9ZYt$)k(%qQeB~crS`$HE=*mizT=Ar2f7E}#BpCdyo$ZI zF=>X6nIRhB79312hlLq7Df5@*kXQ~1GpNKqUB%Egfws>VP_;I&u~O^2jgF4lHO#42 z@O$0!0LKVNu@CJyK+JP&ib3qfFfk)+iV3zwl1*`exGSVP=tqg~Upt1yEgTp3a6){@ z$LwPy#HW}Rf8;yxCnUvRIrjg_{UKhHKAe{!T#ymW$bMXuX9y>WOXISktmfw~;5##~UBTA|XHWGK+!-m1G7* zLIL`izUm(xB@SP zYV@^<&$GFMuf{pQjY;fa>a1~yZ{yl&@_$qHFHoEOFM;6T|2}@e+pEXskP0vV{A|cu R+?(H-51QVYA9}PO{RcS3ojd>l literal 3173 zcmdT`O>7&-75-*+$z85iB4ul1E4CE1wG;iMqGcykD>;sBwQgk7W*jPZWyP^qJ-SKy%xFjP_!tLOMxOlf*xET>^Hl#MMa9+YXQy9 zdvCt?=FR(~{`l2{Z2&oh77pUHg-N`U!Wq1JfYKQYKfn)_?1F(Y15OGD@FN4SS+Eo~ zgIPsgv~US|MO`*-6AW^Kibx%NBSeO+^p7v{gc!uoo$Tb0dCMfePo%d_r zmFC)_SD$kitCSqb2PL<9&8_>2ZwvLX;x`1I%a?++Y`wYYzmqMlSN+hfm5X6e_hN3E zcQ%w*z!}c3xOd!a)vYaOi(%cbEl;a!Wo<%0&>gWtrb))AMYq$s6RR{sznVQ)ue*2i zej}t!@eZLrp>l;Etr6ChmwU_;c!`+kt)-w@3)M|Et~IV@o)k~052eY_TU%FLOi=R7 z?nmEUfBf*#{d_vzarta5^p?H)^cgzZT@2mQ>ScF5ikg8p1ngxmoH+GzlnFjDF+36_ z!zu>Ndda)stB6}sD96=VJ}I}vvqOal*srmB}Xq<)ZnowX8D-E-HbEv#Tw z;K)K0p<4{(&AEy<)bL7mFC6k4Q$s@F(3-pI%>=cQ8(#Or3aJL`GGw%$->(Qeau++v z#KjTYeK{+0UAaRNML+bW4bZ#ed)~L7Zvul)$KhKX zt_L}F1yZVsNNJ?mjQk!Zm*pFOo#vDDd{w~sE0~xb& z^tM*G2fIz{1)f!N`i2zuTAyra{BD~$J!9q)=5JxlYZ>!HYhKd|^Ey|8E6HW(g?W=J zlT;sa#d)eIAbFiD!L<)iBQWt_fHWUlOnx&^VRo)I_6HKQ+sCP{&L?$xO4?BH$gcX3 z`~P^7?dVS8W0-QP`w7+K=wsVXqN2pVLQ2b}SO;UK0f5$EP8E(tZQI?P3XrW#U*WL9p(a{P zNy5M+86gC4*nEVp781~7p&E%T@h7C8U?`x_fcfN)2=pS;fl#CN$#Fzjz@e6!qMayS zxCfQ`H_j(oFgua-Y#(HcBfP_$0`c8DZW*jQ47B*>uc7u{`oEca1Y1Ss>7n57#`p03 u_;-W9BPv>K2e#Y&C~iByIS-lSDas_K5pcJNUBgdMW9ytHZ<0U9b^brV`G_(A diff --git a/src/com/rubix/Consensus/QuorumConsensus.java b/src/com/rubix/Consensus/QuorumConsensus.java index 5e51dc2a..db0336a6 100644 --- a/src/com/rubix/Consensus/QuorumConsensus.java +++ b/src/com/rubix/Consensus/QuorumConsensus.java @@ -219,12 +219,6 @@ public void run() { String verifySenderIPFSHash = IPFSNetwork.addHashOnly(LOGGER_PATH + "tempverifysenderhash", ipfs); deleteFile(LOGGER_PATH + "tempverifysenderhash"); -// QuorumConsensusLogger.debug("Checking providers for: " + verifySenderHash); -// ArrayList dhtOwnersList = dhtOwnerCheck(verifySenderHash); -// QuorumConsensusLogger.debug("Providers: " + dhtOwnersList); -// boolean consensusIDcheck = false; -// if(dhtOwnersList.size() <= 2 && dhtOwnersList.contains(senderPID)) -// consensusIDcheck = true; if (Authenticate.verifySignature(detailsToVerify.toString())) { QuorumConsensusLogger.debug("Quorum Authenticated Sender"); diff --git a/src/com/rubix/Mining/ProofCredits.java b/src/com/rubix/Mining/ProofCredits.java index 38ba80e2..65052caf 100644 --- a/src/com/rubix/Mining/ProofCredits.java +++ b/src/com/rubix/Mining/ProofCredits.java @@ -1,5 +1,6 @@ package com.rubix.Mining; +import com.rubix.AuthenticateNode.PropImage; import com.rubix.Consensus.InitiatorConsensus; import com.rubix.Consensus.InitiatorProcedure; import com.rubix.Resources.Functions; @@ -10,7 +11,9 @@ import org.json.JSONException; import org.json.JSONObject; +import javax.imageio.ImageIO; import javax.net.ssl.HttpsURLConnection; +import java.awt.image.BufferedImage; import java.io.*; import java.net.HttpURLConnection; import java.net.URL; @@ -40,7 +43,7 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON repo(ipfs); JSONObject APIResponse = new JSONObject(); JSONObject detailsObject = new JSONObject(data); - String receiverDidIpfsHash = detailsObject.getString("receiverDidIpfsHash"); + String DID = detailsObject.getString("receiverDidIpfsHash"); String pvt = detailsObject.getString("pvt"); int type = detailsObject.getInt("type"); int creditUsed = 0; @@ -140,14 +143,14 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON JSONArray prooftid = new JSONArray(); String comments = resJsonData.toString() + prooftid; - String authSenderByRecHash = calculateHash(token + receiverDidIpfsHash + comments, "SHA3-256"); + String authSenderByRecHash = calculateHash(token + DID + comments, "SHA3-256"); String tid = calculateHash(authSenderByRecHash, "SHA3-256"); - writeToFile(LOGGER_PATH + "tempbeta", tid.concat(receiverDidIpfsHash), false); + writeToFile(LOGGER_PATH + "tempbeta", tid.concat(DID), false); String betaHash = IPFSNetwork.add(LOGGER_PATH + "tempbeta", ipfs); deleteFile(LOGGER_PATH + "tempbeta"); - writeToFile(LOGGER_PATH + "tempgamma", tid.concat(receiverDidIpfsHash), false); + writeToFile(LOGGER_PATH + "tempgamma", tid.concat(DID), false); String gammaHash = IPFSNetwork.add(LOGGER_PATH + "tempgamma", ipfs); deleteFile(LOGGER_PATH + "tempgamma"); @@ -158,7 +161,7 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON break; } default: { - quorumArray = getQuorum(betaHash, gammaHash, receiverDidIpfsHash, receiverDidIpfsHash, token.length()); + quorumArray = getQuorum(betaHash, gammaHash, DID, DID, token.length()); } } @@ -187,7 +190,7 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON if (alphaPeersList.size() < minQuorum(alphaSize) || betaPeersList.size() < 5 || gammaPeersList.size() < 5) { updateQuorum(quorumArray, null, false, type); - APIResponse.put("did", receiverDidIpfsHash); + APIResponse.put("did", DID); APIResponse.put("tid", "null"); APIResponse.put("status", "Failed"); APIResponse.put("message", "Quorum Members not available"); @@ -228,7 +231,7 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON qstObject.put("credits", creditSignsArray); } else { updateQuorum(quorumArray, null, false, type); - APIResponse.put("did", receiverDidIpfsHash); + APIResponse.put("did", DID); APIResponse.put("tid", "null"); APIResponse.put("status", "Failed"); APIResponse.put("message", "Credit File(s) missing"); @@ -239,9 +242,9 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON JSONObject dataObject = new JSONObject(); dataObject.put("tid", tid); dataObject.put("message", comments); - dataObject.put("receiverDidIpfs", receiverDidIpfsHash); + dataObject.put("receiverDidIpfs", DID); dataObject.put("pvt", pvt); - dataObject.put("senderDidIpfs", receiverDidIpfsHash); + dataObject.put("senderDidIpfs", DID); dataObject.put("token", token.toString()); dataObject.put("alphaList", alphaPeersList); dataObject.put("betaList", betaPeersList); @@ -251,7 +254,7 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON InitiatorProcedure.consensusSetUp(dataObject.toString(), ipfs, SEND_PORT + 3, alphaSize, "new-credits-mining"); if (!(InitiatorConsensus.quorumSignature.length() >= 3 * minQuorum(7))) { - APIResponse.put("did", receiverDidIpfsHash); + APIResponse.put("did", DID); APIResponse.put("tid", "null"); APIResponse.put("status", "Failed"); APIResponse.put("message", "Consensus failed"); @@ -279,9 +282,9 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON JSONObject dataObject = new JSONObject(); dataObject.put("tid", tid); dataObject.put("message", comments); - dataObject.put("receiverDidIpfs", receiverDidIpfsHash); + dataObject.put("receiverDidIpfs", DID); dataObject.put("pvt", pvt); - dataObject.put("senderDidIpfs", receiverDidIpfsHash); + dataObject.put("senderDidIpfs", DID); dataObject.put("token", token.toString()); dataObject.put("alphaList", alphaPeersList); dataObject.put("betaList", betaPeersList); @@ -290,7 +293,7 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON InitiatorProcedure.consensusSetUp(dataObject.toString(), ipfs, SEND_PORT + 3, alphaSize, ""); if (!(InitiatorConsensus.quorumSignature.length() >= 3 * minQuorum(7))) { - APIResponse.put("did", receiverDidIpfsHash); + APIResponse.put("did", DID); APIResponse.put("tid", "null"); APIResponse.put("status", "Failed"); APIResponse.put("message", "Consensus failed"); @@ -315,7 +318,54 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON String tokenHash = IPFSNetwork.add(LOGGER_PATH + "tempToken", ipfs); writeToFile(TOKENS_PATH + tokenHash, token.getString(i), false); deleteFile(LOGGER_PATH + "tempToken"); - writeToFile(TOKENCHAIN_PATH + tokenHash + ".json", "[]", false); + + + FileWriter shareWriter = new FileWriter(new File(LOGGER_PATH + "mycredit.txt"), true); + shareWriter.write(InitiatorConsensus.quorumSignature.toString()); + shareWriter.close(); + File readCredit = new File(LOGGER_PATH + "mycredit.txt"); + String credit = add(readCredit.toString(), ipfs); + + File creditFile = new File(WALLET_DATA_PATH.concat("/Credits/").concat(credit).concat(".json")); + if (!creditFile.exists()) + creditFile.createNewFile(); + writeToFile(creditFile.toString(), InitiatorConsensus.quorumSignature.toString(), false); + + String tokens = tokenHash; + String hashString = tokens.concat(DID); + String hashForPositions = calculateHash(hashString, "SHA3-256"); + + BufferedImage privateImage = ImageIO.read(new File(DATA_PATH.concat(DID).concat("/PrivateShare.png"))); + String firstPrivate = PropImage.img2bin(privateImage); + int[] privateIntegerArray1 = strToIntArray(firstPrivate); + String privateBinary = Functions.intArrayToStr(privateIntegerArray1); + String positions = ""; + for(int j = 0; j < privateIntegerArray1.length; j+=49152){ + positions+=privateBinary.charAt(j); + } + String ownerIdentity = hashForPositions.concat(positions); + String ownerIdentityHash = calculateHash(ownerIdentity, "SHA3-256"); + + ProofCreditsLogger.debug("Ownership Here"); + ProofCreditsLogger.debug("tokens: " + tokenHash); + ProofCreditsLogger.debug("hashString: " + hashString); + ProofCreditsLogger.debug("hashForPositions: " + hashForPositions); + ProofCreditsLogger.debug("p1: " + positions); + ProofCreditsLogger.debug("ownerIdentity: " + ownerIdentity); + ProofCreditsLogger.debug("ownerIdentityHash: " + ownerIdentityHash); + JSONArray tokenChainArray = new JSONArray(); + JSONObject tokenChainGenesisObject = new JSONObject(); + tokenChainGenesisObject.put("quorumSignatures", credit); + tokenChainGenesisObject.put("sender", DID); + tokenChainGenesisObject.put("comment", "Mining-Genesis"); + tokenChainGenesisObject.put("tid", tid); + tokenChainGenesisObject.put("owner", ownerIdentityHash); + tokenChainGenesisObject.put("blockNumber", 0); + tokenChainGenesisObject.put("nextHash", calculateHash(tid, "SHA3-256")); + tokenChainGenesisObject.put("previousHash", ""); + tokenChainArray.put(tokenChainGenesisObject); + + writeToFile(TOKENCHAIN_PATH + tokenHash + ".json", tokenChainArray.toString(), false); JSONObject temp = new JSONObject(); temp.put("tokenHash", tokenHash); JSONArray tempArray = new JSONArray(); @@ -355,8 +405,8 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON signedQuorumList.put(keys.next()); updateQuorum(quorumArray, signedQuorumList, true, type); - mineUpdate(receiverDidIpfsHash, creditUsed); - APIResponse.put("did", receiverDidIpfsHash); + mineUpdate(DID, creditUsed); + APIResponse.put("did", DID); APIResponse.put("tid", tid); APIResponse.put("token", token); APIResponse.put("creditsused", creditUsed); @@ -373,8 +423,8 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON transactionRecord.put("tokens", token); transactionRecord.put("txn", tid); transactionRecord.put("quorumList", signedQuorumList); - transactionRecord.put("senderDID", receiverDidIpfsHash); - transactionRecord.put("receiverDID", receiverDidIpfsHash); + transactionRecord.put("senderDID", DID); + transactionRecord.put("receiverDID", DID); transactionRecord.put("Date", currentTime); transactionRecord.put("totalTime", totalTime); transactionRecord.put("comment", "minedtxn"); @@ -401,7 +451,7 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON // Serialization JSONObject dataToSend = new JSONObject(); dataToSend.put("bank_id", "01"); - dataToSend.put("user_did", receiverDidIpfsHash); + dataToSend.put("user_did", DID); dataToSend.put("token_id", token); dataToSend.put("level", level); dataToSend.put("denomination", 1); @@ -452,8 +502,8 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON // Serialization JSONObject dataToSend = new JSONObject(); dataToSend.put("transaction_id", tid); - dataToSend.put("sender_did", receiverDidIpfsHash); - dataToSend.put("receiver_did", receiverDidIpfsHash); + dataToSend.put("sender_did", DID); + dataToSend.put("receiver_did", DID); dataToSend.put("token_id", tokenList); dataToSend.put("token_time", (int) totalTime); dataToSend.put("amount", tokenList.size()); @@ -488,7 +538,7 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON ProofCreditsLogger.debug(responseTxn.toString()); } } else { - APIResponse.put("did", receiverDidIpfsHash); + APIResponse.put("did", DID); APIResponse.put("tid", "null"); APIResponse.put("status", "Failed"); APIResponse.put("message", "error from mine service"); @@ -496,7 +546,7 @@ public static JSONObject create(String data, IPFS ipfs) throws IOException, JSON return APIResponse; } } else { - APIResponse.put("did", receiverDidIpfsHash); + APIResponse.put("did", DID); APIResponse.put("tid", "null"); APIResponse.put("status", "Failed"); APIResponse.put("message", "Insufficient proofs"); diff --git a/src/com/rubix/Resources/Functions.java b/src/com/rubix/Resources/Functions.java index f69aff0d..ef5e8a5d 100644 --- a/src/com/rubix/Resources/Functions.java +++ b/src/com/rubix/Resources/Functions.java @@ -1,24 +1,22 @@ package com.rubix.Resources; -import static com.rubix.Resources.APIHandler.addPublicData; -import static com.rubix.Resources.IPFSNetwork.IPFSNetworkLogger; -import static com.rubix.Resources.IPFSNetwork.checkSwarmConnect; -import static com.rubix.Resources.IPFSNetwork.executeIPFSCommands; -import static com.rubix.Resources.IPFSNetwork.forwardCheck; -import static com.rubix.Resources.IPFSNetwork.listen; -import static com.rubix.Resources.IPFSNetwork.swarmConnectP2P; -import static com.rubix.Resources.IPFSNetwork.swarmConnectProcess; +import com.rubix.AuthenticateNode.PropImage; +import com.rubix.Ping.PingCheck; +import io.ipfs.api.IPFS; +import io.ipfs.multiaddr.MultiAddress; +import org.apache.log4j.Logger; +import org.apache.log4j.PropertyConfigurator; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import javax.imageio.ImageIO; import java.awt.image.BufferedImage; -import java.io.BufferedReader; -import java.io.DataOutputStream; -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStreamReader; +import java.io.*; import java.math.RoundingMode; import java.net.HttpURLConnection; +import java.net.Socket; +import java.net.SocketException; import java.net.URL; import java.nio.charset.StandardCharsets; import java.nio.file.Files; @@ -34,18 +32,9 @@ import java.util.LinkedHashSet; import java.util.Set; -import javax.imageio.ImageIO; - -import com.rubix.AuthenticateNode.PropImage; -import com.rubix.Ping.PingCheck; - -import org.apache.log4j.PropertyConfigurator; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; +import static com.rubix.Resources.APIHandler.addPublicData; +import static com.rubix.Resources.IPFSNetwork.*; -import io.ipfs.api.IPFS; -import io.ipfs.multiaddr.MultiAddress; public class Functions { @@ -56,8 +45,7 @@ public class Functions { public static String LOGGER_PATH = ""; public static String WALLET_DATA_PATH = ""; public static String PAYMENTS_PATH = ""; - public static int RECEIVER_PORT, GOSSIP_SENDER, GOSSIP_RECEIVER, QUORUM_PORT, SENDER2Q1, SENDER2Q2, SENDER2Q3, - SENDER2Q4, SENDER2Q5, SENDER2Q6, SENDER2Q7; + public static int RECEIVER_PORT, GOSSIP_SENDER, GOSSIP_RECEIVER, QUORUM_PORT, SENDER2Q1, SENDER2Q2, SENDER2Q3, SENDER2Q4, SENDER2Q5, SENDER2Q6, SENDER2Q7; public static int QUORUM_COUNT; public static int SEND_PORT; public static int IPFS_PORT; @@ -136,11 +124,13 @@ public static void pathSet() { BOOTSTRAPS = pathsArray.getJSONArray(5); + } catch (JSONException e) { e.printStackTrace(); } } + public static void nodeData(String did, String wid, IPFS ipfs) throws IOException { PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); File dataFolder = new File(DATA_PATH + did + "/"); @@ -214,9 +204,9 @@ public static String getSystemUser() { return lineID; } + /** - * This method calculates different types of hashes as mentioned in the passed - * parameters for the mentioned message + * This method calculates different types of hashes as mentioned in the passed parameters for the mentioned message * * @param message Input string to be hashed * @param algorithm Specification of the algorithm used for hashing @@ -283,13 +273,13 @@ public static String bytesToHex(byte[] inputHash) { StringBuilder outputHexString = new StringBuilder(); for (byte b : inputHash) { String hex = Integer.toHexString(0xff & b); - if (hex.length() == 1) - outputHexString.append('0'); + if (hex.length() == 1) outputHexString.append('0'); outputHexString.append(hex); } return outputHexString.toString(); } + /** * This method returns the content of the file passed to it * @@ -311,15 +301,14 @@ public static String readFile(String filePath) { return fileContent.toString(); } + /** * This method writes the mentioned data into the file passed to it - * This also allows to take a decision on whether or not to append the data to - * the already existing content in the file + * This also allows to take a decision on whether or not to append the data to the already existing content in the file * * @param filePath Location of the file to be read and written into * @param data Data to be added - * @param appendStatus Decides whether or not to append the new data into the - * already existing data + * @param appendStatus Decides whether or not to append the new data into the already existing data */ public synchronized static void writeToFile(String filePath, String data, Boolean appendStatus) { @@ -360,6 +349,7 @@ public static String getSignFromShares(String filePath, String hash) throws IOEx return p1; } + /** * This function will sign on JSON data with private share * @@ -404,6 +394,7 @@ public static void listenThread(JSONObject connectObject) { } + /** * This function converts any integer to its binary form * @@ -490,8 +481,7 @@ public static void updateJSON(String operation, String filePath, String data) { } /** - * This method gets you a required data from a JSON file with a tag to be - * compared with + * This method gets you a required data from a JSON file with a tag to be compared with * * @param filePath Location of the JSON file * @param get Data to be fetched from the file @@ -528,8 +518,7 @@ public static String getOsName() { } /** - * This function calculates the minimum number of quorum peers required for - * consensus to work + * This function calculates the minimum number of quorum peers required for consensus to work * * @return Minimum number of quorum count for consensus to work */ @@ -538,8 +527,7 @@ public static int minQuorum() { } /** - * This function calculates the minimum number of quorum peers required for - * consensus to work + * This function calculates the minimum number of quorum peers required for consensus to work * * @return Minimum number of quorum count for consensus to work */ @@ -547,6 +535,7 @@ public static int minQuorum(int count) { return (((count - 1) / 3) * 2) + 1; } + /** * This method checks if Quorum is available for consensus * @@ -585,6 +574,7 @@ public static ArrayList QuorumCheck(JSONArray quorum, int size) { * @param ipfs ipfs instance */ + public static void QuorumSwarmConnect(JSONArray quorum, IPFS ipfs) { PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); @@ -603,6 +593,7 @@ public static void QuorumSwarmConnect(JSONArray quorum, IPFS ipfs) { } + /** * This method identifies the Peer ID of the system by IPFS during installation * @@ -610,6 +601,7 @@ public static void QuorumSwarmConnect(JSONArray quorum, IPFS ipfs) { * @return Your system's Peer ID assigned by IPFS */ + public static String getPeerID(String filePath) { PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); JSONArray fileContentArray; @@ -627,6 +619,7 @@ public static String getPeerID(String filePath) { return peerid; } + public static int[] getPrivatePosition(int[] positions, int[] privateArray) { int[] PrivatePosition = new int[positions.length]; for (int k = 0; k < positions.length; k++) { @@ -637,8 +630,7 @@ public static int[] getPrivatePosition(int[] positions, int[] privateArray) { return PrivatePosition; } - public static JSONObject randomPositions(String role, String hash, int numberOfPositions, int[] pvt1) - throws JSONException { + public static JSONObject randomPositions(String role, String hash, int numberOfPositions, int[] pvt1) throws JSONException { int u = 0, l = 0, m = 0; int[] hashCharacters = new int[256]; @@ -695,19 +687,18 @@ public static JSONObject randomPositions(String role, String hash, int numberOfP * @param positionsCount Number of positions required * @return Extended array of positions */ - // public static int[] finalPositions(int[] randomPositions, int positionsCount) - // { - // int[] finalPositions = new int[positionsCount * 64]; - // int u = 0; - // for (int k = 0; k < positionsCount; k++) { - // for (int p = 0; p < 64; p++) { - // finalPositions[u] = randomPositions[k]; - // randomPositions[k]++; - // u++; - // } - // } - // return finalPositions; - // } +// public static int[] finalPositions(int[] randomPositions, int positionsCount) { +// int[] finalPositions = new int[positionsCount * 64]; +// int u = 0; +// for (int k = 0; k < positionsCount; k++) { +// for (int p = 0; p < 64; p++) { +// finalPositions[u] = randomPositions[k]; +// randomPositions[k]++; +// u++; +// } +// } +// return finalPositions; +// } /** * This function deletes the mentioned file @@ -725,43 +716,41 @@ public static void deleteFile(String fileName) { } - // /** - // * This functions picks the required number of quorum members from the - // mentioned file - // * - // * @param filePath Location of the file - // * @param hash Data from which positions are chosen - // * @return List of chosen members from the file - // */ - // public static ArrayList quorumChooser(String filePath, String hash) { - // PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); - // ArrayList quorumList = new ArrayList(); - // try { - // String fileContent = readFile(filePath); - // JSONArray blockHeight = new JSONArray(fileContent); - // - // int[] hashCharacters = new int[256]; - // var randomPositions = new ArrayList(); - // HashSet positionSet = new HashSet<>(); - // for (int k = 0; positionSet.size() != 7; k++) { - // hashCharacters[k] = Character.getNumericValue(hash.charAt(k)); - // randomPositions.add((((2402 + hashCharacters[k]) * 2709) + ((k + 2709) + - // hashCharacters[(k)])) % blockHeight.length()); - // positionSet.add(randomPositions.get(k)); - // } - // - // for (Integer integer : positionSet) - // quorumList.add(blockHeight.getJSONObject(integer).getString("peer-id")); - // } catch (JSONException e) { - // FunctionsLogger.error("JSON Exception Occurred", e); - // e.printStackTrace(); - // } - // return quorumList; - // } + +// /** +// * This functions picks the required number of quorum members from the mentioned file +// * +// * @param filePath Location of the file +// * @param hash Data from which positions are chosen +// * @return List of chosen members from the file +// */ +// public static ArrayList quorumChooser(String filePath, String hash) { +// PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); +// ArrayList quorumList = new ArrayList(); +// try { +// String fileContent = readFile(filePath); +// JSONArray blockHeight = new JSONArray(fileContent); +// +// int[] hashCharacters = new int[256]; +// var randomPositions = new ArrayList(); +// HashSet positionSet = new HashSet<>(); +// for (int k = 0; positionSet.size() != 7; k++) { +// hashCharacters[k] = Character.getNumericValue(hash.charAt(k)); +// randomPositions.add((((2402 + hashCharacters[k]) * 2709) + ((k + 2709) + hashCharacters[(k)])) % blockHeight.length()); +// positionSet.add(randomPositions.get(k)); +// } +// +// for (Integer integer : positionSet) +// quorumList.add(blockHeight.getJSONObject(integer).getString("peer-id")); +// } catch (JSONException e) { +// FunctionsLogger.error("JSON Exception Occurred", e); +// e.printStackTrace(); +// } +// return quorumList; +// } /** - * This function is to be initially called to setup the environment of your - * project + * This function is to be initially called to setup the environment of your project */ public static void launch() { pathSet(); @@ -807,8 +796,7 @@ public static String checkDirectory() throws JSONException { File tokenChainsFolder = new File(TOKENCHAIN_PATH); File walletDataFolder = new File(WALLET_DATA_PATH); - if (!dataFolder.exists() || !loggerFolder.exists() || !tokenChainsFolder.exists() || !tokensFolder.exists() - || !walletDataFolder.exists()) { + if (!dataFolder.exists() || !loggerFolder.exists() || !tokenChainsFolder.exists() || !tokensFolder.exists() || !walletDataFolder.exists()) { dataFolder.delete(); loggerFolder.delete(); tokenChainsFolder.delete(); @@ -885,6 +873,7 @@ public static String mineToken(int level, int tokenNumber) { return token; } + public static String toBinary(int x, int len) { if (len > 0) { return String.format("%" + len + "s", @@ -921,6 +910,7 @@ public static Date getCurrentUtcTime() throws ParseException { return localDateFormat.parse(simpleDateFormat.format(new Date())); } + /** * This method is used to update quorum credits in server * @@ -931,8 +921,8 @@ public static Date getCurrentUtcTime() throws ParseException { * @return mined token */ - public static void updateQuorum(JSONArray quorumArray, JSONArray signedQuorumList, boolean status, int type) - throws IOException, JSONException { + + public static void updateQuorum(JSONArray quorumArray, JSONArray signedQuorumList, boolean status, int type) throws IOException, JSONException { if (type == 1) { String urlQuorumUpdate = ADVISORY_IP + "/updateQuorum"; @@ -974,6 +964,7 @@ public static void updateQuorum(JSONArray quorumArray, JSONArray signedQuorumLis } } + /** * This method is used get getquorum from advisory node * @@ -985,8 +976,8 @@ public static void updateQuorum(JSONArray quorumArray, JSONArray signedQuorumLis * @return JSONArray of quorum nodes */ - public static JSONArray getQuorum(String betaHash, String gammaHash, String senderDidIpfsHash, - String receiverDidIpfsHash, int tokenslength) throws IOException, JSONException { + + public static JSONArray getQuorum(String betaHash, String gammaHash, String senderDidIpfsHash, String receiverDidIpfsHash, int tokenslength) throws IOException, JSONException { JSONArray quorumArray; String urlQuorumPick = ADVISORY_IP + "/getQuorum"; URL objQuorumPick = new URL(urlQuorumPick); @@ -1114,74 +1105,70 @@ public static void syncDataTable(String did, String peerId) { } } - public static void removeToken() { - String bnkFile = readFile(PAYMENTS_PATH.concat("BNK00.json")); - try { - JSONArray bnkArray = new JSONArray(bnkFile); - JSONObject removeToken = bnkArray.getJSONObject(0); - bnkArray.remove(0); - writeToFile(PAYMENTS_PATH.concat("BNK00.json"), bnkArray.toString(), false); + public static void correctToken() throws JSONException{ + pathSet(); + String bank = readFile(PAYMENTS_PATH.concat("BNK00.json")); + JSONArray bankArray = new JSONArray(bank); + JSONObject firstToken; + if(bankArray.length() > 1) { + firstToken = bankArray.getJSONObject(0); - File doubleSpentFile = new File(PAYMENTS_PATH.concat("DoubleSpent.json")); - if (!doubleSpentFile.exists()) { - try { - doubleSpentFile.createNewFile(); - } catch (IOException e) { - FunctionsLogger.debug("File couldn't be created"); - } - JSONArray removeArray = new JSONArray(); - removeArray.put(removeToken); - writeToFile(PAYMENTS_PATH.concat("DoubleSpent.json"), removeArray.toString(), false); - } else { - String removeFile = readFile(PAYMENTS_PATH.concat("DoubleSpent.json")); - JSONArray removeArray = new JSONArray(removeFile); - removeArray.put(removeToken); - writeToFile(PAYMENTS_PATH.concat("DoubleSpent.json"), removeArray.toString(), false); - } - } catch (JSONException e) { - // TODO: handle exception + bankArray.remove(0); + bankArray.put(firstToken); + + writeToFile(PAYMENTS_PATH.concat("BNK00.json"), bankArray.toString(), false); } + } + + public static void correctPartToken() throws JSONException{ + pathSet(); + String bank = readFile(PAYMENTS_PATH.concat("PartsToken.json")); + JSONArray bankArray = new JSONArray(bank); + JSONObject firstToken; + if(bankArray.length() > 1) { + firstToken = bankArray.getJSONObject(0); + bankArray.remove(0); + bankArray.put(firstToken); + + writeToFile(PAYMENTS_PATH.concat("PartsToken.json"), bankArray.toString(), false); + } } - public static void tokenBank() { + public static void tokenBank() throws JSONException { pathSet(); String bank = readFile(PAYMENTS_PATH.concat("BNK00.json")); - try { - JSONArray bankArray = new JSONArray(bank); + JSONArray bankArray = new JSONArray(bank); - ArrayList bankDuplicates = new ArrayList<>(); - for (int i = 0; i < bankArray.length(); i++) { - if (!bankDuplicates.contains(bankArray.getJSONObject(i).getString("tokenHash"))) - bankDuplicates.add(bankArray.getJSONObject(i).getString("tokenHash")); - } + ArrayList bankDuplicates = new ArrayList<>(); + for (int i = 0; i < bankArray.length(); i++) { + if (!bankDuplicates.contains(bankArray.getJSONObject(i).getString("tokenHash"))) + bankDuplicates.add(bankArray.getJSONObject(i).getString("tokenHash")); + } - if (bankDuplicates.size() < bankArray.length()) { - FunctionsLogger.debug("Duplicates Found. Cleaning up ..."); + if (bankDuplicates.size() < bankArray.length()) { + FunctionsLogger.debug("Duplicates Found. Cleaning up ..."); - JSONArray newBank = new JSONArray(); - for (int i = 0; i < bankDuplicates.size(); i++) { - JSONObject tokenObject = new JSONObject(); - tokenObject.put("tokenHash", bankDuplicates.get(i)); - newBank.put(tokenObject); - } - writeToFile(PAYMENTS_PATH.concat("BNK00.json"), newBank.toString(), false); + JSONArray newBank = new JSONArray(); + for (int i = 0; i < bankDuplicates.size(); i++) { + JSONObject tokenObject = new JSONObject(); + tokenObject.put("tokenHash", bankDuplicates.get(i)); + newBank.put(tokenObject); } + writeToFile(PAYMENTS_PATH.concat("BNK00.json"), newBank.toString(), false); + } - File tokensPath = new File(TOKENS_PATH); - String contents[] = tokensPath.list(); - ArrayList tokenFiles = new ArrayList(); - for (int i = 0; i < contents.length; i++) { - if (!contents[i].contains("PARTS")) - tokenFiles.add(contents[i]); - } + File tokensPath = new File(TOKENS_PATH); + String contents[] = tokensPath.list(); + ArrayList tokenFiles = new ArrayList(); + for (int i = 0; i < contents.length; i++) { + if (!contents[i].contains("PARTS")) + tokenFiles.add(contents[i]); + } - for (int i = 0; i < tokenFiles.size(); i++) { - if (!bankDuplicates.contains(tokenFiles.get(i).toString())) - deleteFile(TOKENS_PATH.concat(tokenFiles.get(i).toString())); - } - } catch (JSONException e) { - // TODO: handle exception + for (int i = 0; i < tokenFiles.size(); i++) { + if (!bankDuplicates.contains(tokenFiles.get(i).toString())) + deleteFile(TOKENS_PATH.concat(tokenFiles.get(i).toString())); } } @@ -1212,11 +1199,9 @@ public static Double getPartsBalance() throws JSONException { Double availableParts = 0.000D, senderCount = 0.000D, receiverCount = 0.000D; for (int k = 0; k < tokenChainArray.length(); k++) { if (tokenChainArray.getJSONObject(k).has("role")) { - if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") - && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { + if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { senderCount += tokenChainArray.getJSONObject(k).getDouble("amount"); - } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") - && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { + } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { receiverCount += tokenChainArray.getJSONObject(k).getDouble("amount"); } } @@ -1229,6 +1214,7 @@ public static Double getPartsBalance() throws JSONException { parts = formatAmount(parts); balance = balance + parts; + int count = 0; File shiftedFile = new File(PAYMENTS_PATH.concat("ShiftedTokens.json")); if (shiftedFile.exists()) { @@ -1238,6 +1224,7 @@ public static Double getPartsBalance() throws JSONException { for (int i = 0; i < shiftedArray.length(); i++) arrayTokens.add(shiftedArray.getString(i)); + for (int i = 0; i < partTokensArray.length(); i++) { if (!arrayTokens.contains(partTokensArray.getJSONObject(i).getString("tokenHash"))) count++; @@ -1265,11 +1252,9 @@ public static Double checkTokenPartBalance(String tokenHash) throws JSONExceptio Double senderCount = 0.000D, receiverCount = 0.000D; for (int k = 0; k < tokenChainArray.length(); k++) { if (tokenChainArray.getJSONObject(k).has("role")) { - if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") - && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { + if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { senderCount += tokenChainArray.getJSONObject(k).getDouble("amount"); - } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") - && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { + } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { receiverCount += tokenChainArray.getJSONObject(k).getDouble("amount"); } } @@ -1322,11 +1307,9 @@ public static Double getBalance() throws JSONException { Double availableParts = 0.000D, senderCount = 0.000D, receiverCount = 0.000D; for (int k = 0; k < tokenChainArray.length(); k++) { if (tokenChainArray.getJSONObject(k).has("role")) { - if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") - && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { + if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { senderCount += tokenChainArray.getJSONObject(k).getDouble("amount"); - } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") - && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { + } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { receiverCount += tokenChainArray.getJSONObject(k).getDouble("amount"); } } @@ -1376,11 +1359,9 @@ public static Double partTokenBalance(String tokenHash) throws JSONException { Double senderCount = 0.000D, receiverCount = 0.000D; for (int k = 0; k < tokenChainArray.length(); k++) { if (tokenChainArray.getJSONObject(k).has("role")) { - if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") - && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { + if (tokenChainArray.getJSONObject(k).getString("role").equals("Sender") && tokenChainArray.getJSONObject(k).getString("sender").equals(myDID)) { senderCount += tokenChainArray.getJSONObject(k).getDouble("amount"); - } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") - && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { + } else if (tokenChainArray.getJSONObject(k).getString("role").equals("Receiver") && tokenChainArray.getJSONObject(k).getString("receiver").equals(myDID)) { receiverCount += tokenChainArray.getJSONObject(k).getDouble("amount"); } } @@ -1409,27 +1390,30 @@ public static Double formatAmount(Double amount) { } - public static void clearParts() { + public static void clearParts() throws JSONException { String partsFile = readFile(PAYMENTS_PATH.concat("PartsToken.json")); - try { - JSONArray partsArray = new JSONArray(partsFile); - for (int i = 0; i < partsArray.length(); i++) { - if (partTokenBalance(partsArray.getJSONObject(i).getString("tokenHash")) <= 0.000 - || partTokenBalance(partsArray.getJSONObject(i).getString("tokenHash")) > 1.000) { - deleteFile(TOKENS_PATH.concat("PARTS/").concat(partsArray.getJSONObject(i).getString("tokenHash"))); - partsArray.remove(i); - } + JSONArray partsArray = new JSONArray(partsFile); + for (int i = 0; i < partsArray.length(); i++) { + if (partTokenBalance(partsArray.getJSONObject(i).getString("tokenHash")) <= 0.000 || partTokenBalance(partsArray.getJSONObject(i).getString("tokenHash")) > 1.000) { + deleteFile(TOKENS_PATH.concat("PARTS/").concat(partsArray.getJSONObject(i).getString("tokenHash"))); + partsArray.remove(i); } - writeToFile(PAYMENTS_PATH.concat("PartsToken.json"), partsArray.toString(), false); - } catch (JSONException e) { - // TODO: handle exception } + writeToFile(PAYMENTS_PATH.concat("PartsToken.json"), partsArray.toString(), false); } public static void backgroundChecks() { - Functions.tokenBank(); + try { + Functions.tokenBank(); + } catch (JSONException e) { + e.printStackTrace(); + } - Functions.clearParts(); + try { + Functions.clearParts(); + } catch (JSONException e) { + e.printStackTrace(); + } IPFS ipfs = new IPFS("/ip4/127.0.0.1/tcp/" + IPFS_PORT); IPFSNetwork.repo(ipfs); @@ -1490,7 +1474,6 @@ public static boolean sanityCheck(String peerid, IPFS ipfs, int port) throws IOE return sanityCheckErrorFlag; } - public static boolean checkIPFSStatus(String peerid, IPFS ipfs) { FunctionsLogger.info("Entering checkIPFSStatus"); boolean swarmConnectedStatus = false; diff --git a/src/com/rubix/TokenTransfer/TokenReceiver.java b/src/com/rubix/TokenTransfer/TokenReceiver.java index 8f22637e..f265543d 100644 --- a/src/com/rubix/TokenTransfer/TokenReceiver.java +++ b/src/com/rubix/TokenTransfer/TokenReceiver.java @@ -1,61 +1,28 @@ package com.rubix.TokenTransfer; -import static com.rubix.Resources.Functions.DATA_PATH; -import static com.rubix.Resources.Functions.FunctionsLogger; -import static com.rubix.Resources.Functions.IPFS_PORT; -import static com.rubix.Resources.Functions.LOGGER_PATH; -import static com.rubix.Resources.Functions.PAYMENTS_PATH; -import static com.rubix.Resources.Functions.RECEIVER_PORT; -import static com.rubix.Resources.Functions.TOKENCHAIN_PATH; -import static com.rubix.Resources.Functions.TOKENS_PATH; -import static com.rubix.Resources.Functions.WALLET_DATA_PATH; -import static com.rubix.Resources.Functions.calculateHash; -import static com.rubix.Resources.Functions.deleteFile; -import static com.rubix.Resources.Functions.formatAmount; -import static com.rubix.Resources.Functions.getCurrentUtcTime; -import static com.rubix.Resources.Functions.getPeerID; -import static com.rubix.Resources.Functions.getValues; -import static com.rubix.Resources.Functions.nodeData; -import static com.rubix.Resources.Functions.pathSet; -import static com.rubix.Resources.Functions.readFile; -import static com.rubix.Resources.Functions.syncDataTable; -import static com.rubix.Resources.Functions.updateJSON; -import static com.rubix.Resources.Functions.writeToFile; -import static com.rubix.Resources.IPFSNetwork.add; -import static com.rubix.Resources.IPFSNetwork.executeIPFSCommands; -import static com.rubix.Resources.IPFSNetwork.get; -import static com.rubix.Resources.IPFSNetwork.listen; -import static com.rubix.Resources.IPFSNetwork.pin; -import static com.rubix.Resources.IPFSNetwork.repo; -import static com.rubix.Resources.IPFSNetwork.swarmConnectP2P; - -import java.awt.image.BufferedImage; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.PrintStream; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.SocketException; -import java.util.ArrayList; -import java.util.Iterator; - -import javax.imageio.ImageIO; - import com.rubix.AuthenticateNode.Authenticate; import com.rubix.AuthenticateNode.PropImage; import com.rubix.Resources.Functions; import com.rubix.Resources.IPFSNetwork; - +import io.ipfs.api.IPFS; import org.apache.log4j.Logger; import org.apache.log4j.PropertyConfigurator; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; -import io.ipfs.api.IPFS; +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.*; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketException; +import java.util.ArrayList; +import java.util.Iterator; + +import static com.rubix.Resources.Functions.*; +import static com.rubix.Resources.IPFSNetwork.*; + public class TokenReceiver { public static Logger TokenReceiverLogger = Logger.getLogger(TokenReceiver.class); @@ -150,6 +117,7 @@ public static String receive() { return APIResponse.toString(); } + nodeData(senderDidIpfsHash, senderWidIpfsHash, ipfs); File senderDIDFile = new File(DATA_PATH + senderDidIpfsHash + "/DID.png"); if (!senderDIDFile.exists()) { @@ -159,7 +127,7 @@ public static String receive() { APIResponse.put("status", "Failed"); APIResponse.put("message", "Sender details not available"); TokenReceiverLogger.info("Sender details not available"); - /* executeIPFSCommands(" ipfs p2p close -t /p2p/" + senderPeerID); */ + /* executeIPFSCommands(" ipfs p2p close -t /p2p/" + senderPeerID);*/ output.close(); input.close(); @@ -197,65 +165,65 @@ public static String receive() { JSONArray partTokenChainsHash = TokenDetails.getJSONArray("hashSender"); JSONArray previousSendersArray = tokenObject.getJSONArray("previousSender"); + JSONArray positionsArray = tokenObject.getJSONArray("positions"); + Double amount = tokenObject.getDouble("amount"); JSONObject amountLedger = tokenObject.getJSONObject("amountLedger"); TokenReceiverLogger.debug("Amount Ledger: " + amountLedger); int intPart = wholeTokens.length(); - Double decimalPart = formatAmount(amount - intPart); - JSONArray doubleSpentToken = new JSONArray(); - boolean tokenOwners = true; - ArrayList ownersArray = new ArrayList(); - ArrayList previousSender = new ArrayList(); - JSONArray ownersReceived = new JSONArray(); - for (int i = 0; i < wholeTokens.length(); ++i) { - try { - TokenReceiverLogger.debug("Checking owners for " + wholeTokens.getString(i) + " Please wait..."); - ownersArray = IPFSNetwork.dhtOwnerCheck(wholeTokens.getString(i)); - - if (ownersArray.size() > 2) { - - for (int j = 0; j < previousSendersArray.length(); j++) { - if (previousSendersArray.getJSONObject(j).getString("token") - .equals(wholeTokens.getString(i))) - ownersReceived = previousSendersArray.getJSONObject(j).getJSONArray("sender"); - } - - for (int j = 0; j < ownersReceived.length(); j++) { - previousSender.add(ownersReceived.getString(j)); - } - TokenReceiverLogger.debug("Previous Owners: " + previousSender); - - for (int j = 0; j < ownersArray.size(); j++) { - if (!previousSender.contains(ownersArray.get(j).toString())) - tokenOwners = false; - } - } - } catch (IOException e) { - - TokenReceiverLogger.debug("Ipfs dht find did not execute"); - } - } - if (!tokenOwners) { - JSONArray owners = new JSONArray(); - for (int i = 0; i < ownersArray.size(); i++) - owners.put(ownersArray.get(i).toString()); - TokenReceiverLogger.debug("Multiple Owners for " + doubleSpentToken); - TokenReceiverLogger.debug("Owners: " + owners); - output.println("420"); - output.println(doubleSpentToken.toString()); - output.println(owners.toString()); - APIResponse.put("did", senderDidIpfsHash); - APIResponse.put("tid", "null"); - APIResponse.put("status", "Failed"); - APIResponse.put("message", "Multiple Owners for " + doubleSpentToken + " " + owners); - IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + senderPeerID); - output.close(); - input.close(); - sk.close(); - ss.close(); - return APIResponse.toString(); - } - +// Double decimalPart = formatAmount(amount - intPart); +// JSONArray doubleSpentToken = new JSONArray(); +// boolean tokenOwners = true; +// ArrayList ownersArray = new ArrayList(); +// ArrayList previousSender = new ArrayList(); +// JSONArray ownersReceived = new JSONArray(); +// for (int i = 0; i < wholeTokens.length(); ++i) { +// try { +// TokenReceiverLogger.debug("Checking owners for " + wholeTokens.getString(i) + " Please wait..."); +// ownersArray = IPFSNetwork.dhtOwnerCheck(wholeTokens.getString(i)); +// +// if (ownersArray.size() > 2) { +// +// for (int j = 0; j < previousSendersArray.length(); j++) { +// if (previousSendersArray.getJSONObject(j).getString("token").equals(wholeTokens.getString(i))) +// ownersReceived = previousSendersArray.getJSONObject(j).getJSONArray("sender"); +// } +// +// for (int j = 0; j < ownersReceived.length(); j++) { +// previousSender.add(ownersReceived.getString(j)); +// } +// TokenReceiverLogger.debug("Previous Owners: " + previousSender); +// +// for (int j = 0; j < ownersArray.size(); j++) { +// if (!previousSender.contains(ownersArray.get(j).toString())) +// tokenOwners = false; +// } +// } +// } catch (IOException e) { +// +// TokenReceiverLogger.debug("Ipfs dht find did not execute"); +// } +// } +// if (!tokenOwners) { +// JSONArray owners = new JSONArray(); +// for (int i = 0; i < ownersArray.size(); i++) +// owners.put(ownersArray.get(i).toString()); +// TokenReceiverLogger.debug("Multiple Owners for " + doubleSpentToken); +// TokenReceiverLogger.debug("Owners: " + owners); +// output.println("420"); +// output.println(doubleSpentToken.toString()); +// output.println(owners.toString()); +// APIResponse.put("did", senderDidIpfsHash); +// APIResponse.put("tid", "null"); +// APIResponse.put("status", "Failed"); +// APIResponse.put("message", "Multiple Owners for " + doubleSpentToken + " " + owners); +// IPFSNetwork.executeIPFSCommands(" ipfs p2p close -t /p2p/" + senderPeerID); +// output.close(); +// input.close(); +// sk.close(); +// ss.close(); +// return APIResponse.toString(); +// } String senderToken = TokenDetails.toString(); String consensusID = calculateHash(senderToken, "SHA3-256"); writeToFile(LOGGER_PATH + "consensusID", consensusID, false); @@ -277,15 +245,15 @@ public static String receive() { return APIResponse.toString(); } - // Check IPFS get for all Tokens + //Check IPFS get for all Tokens int ipfsGetFlag = 0; - ArrayList allTokenContent = new ArrayList<>(); - ArrayList allTokenChainContent = new ArrayList<>(); + ArrayList wholeTokenContent = new ArrayList<>(); + ArrayList wholeTokenChainContent = new ArrayList<>(); for (int i = 0; i < intPart; i++) { String TokenChainContent = get(wholeTokenChains.getString(i), ipfs); - allTokenChainContent.add(TokenChainContent); + wholeTokenChainContent.add(TokenChainContent); String TokenContent = get(wholeTokens.getString(i), ipfs); - allTokenContent.add(TokenContent); + wholeTokenContent.add(TokenContent); ipfsGetFlag++; } repo(ipfs); @@ -326,17 +294,14 @@ public static String receive() { if (j == 0) { rePreviousHash = ""; String rePrev = calculateHash(new JSONObject().toString(), "SHA3-256"); - reNextHash = calculateHash(tokenChainContent.getJSONObject(j + 1).getString("tid"), - "SHA3-256"); + reNextHash = calculateHash(tokenChainContent.getJSONObject(j + 1).getString("tid"), "SHA3-256"); - if (!((rePreviousHash.equals(previousHash) || rePrev.equals(previousHash)) - && reNextHash.equals(nextHash))) { + if (!((rePreviousHash.equals(previousHash) || rePrev.equals(previousHash)) && reNextHash.equals(nextHash))) { chainFlag = false; } } else if (j == tokenChainContent.length() - 1) { - rePreviousHash = calculateHash(tokenChainContent.getJSONObject(j - 1).getString("tid"), - "SHA3-256"); + rePreviousHash = calculateHash(tokenChainContent.getJSONObject(j - 1).getString("tid"), "SHA3-256"); reNextHash = ""; if (!(rePreviousHash.equals(previousHash) && reNextHash.equals(nextHash))) { @@ -344,10 +309,8 @@ public static String receive() { } } else { - rePreviousHash = calculateHash(tokenChainContent.getJSONObject(j - 1).getString("tid"), - "SHA3-256"); - reNextHash = calculateHash(tokenChainContent.getJSONObject(j + 1).getString("tid"), - "SHA3-256"); + rePreviousHash = calculateHash(tokenChainContent.getJSONObject(j - 1).getString("tid"), "SHA3-256"); + reNextHash = calculateHash(tokenChainContent.getJSONObject(j + 1).getString("tid"), "SHA3-256"); if (!(rePreviousHash.equals(previousHash) && reNextHash.equals(nextHash))) { chainFlag = false; @@ -357,7 +320,6 @@ public static String receive() { } } if (!chainFlag) { - String errorMessage = "Broken Cheque Chain"; output.println("423"); APIResponse.put("did", senderDidIpfsHash); @@ -373,17 +335,79 @@ public static String receive() { return APIResponse.toString(); } + boolean ownerCheck = true; + + JSONArray allTokens = new JSONArray(); + for (int i = 0; i < wholeTokens.length(); i++) + allTokens.put(wholeTokens.getString(i)); + for (int i = 0; i < partTokens.length(); i++) + allTokens.put(partTokens.getString(i)); + + JSONArray allTokensChains = new JSONArray(); + for (int i = 0; i < wholeTokenChainContent.size(); i++) + allTokensChains.put(wholeTokenChainContent.get(i)); + for (int i = 0; i < partTokenChainContent.length(); i++) + allTokensChains.put(partTokenChainContent.get(i)); + + JSONArray invalidTokens = new JSONArray(); + for(int i = 0; i < allTokensChains.length(); i++){ + JSONArray tokenChain = new JSONArray(allTokensChains.get(i).toString()); + JSONObject lastObject = tokenChain.getJSONObject(tokenChain.length()-1); + TokenReceiverLogger.debug("Last Object = " + lastObject); + if(lastObject.has("owner")) { + TokenReceiverLogger.debug("Checking ownership"); + String owner = lastObject.getString("owner"); + String tokens = allTokens.getString(i); + String hashString = tokens.concat(senderDidIpfsHash); + String hashForPositions = calculateHash(hashString, "SHA3-256"); + String ownerIdentity = hashForPositions.concat(positionsArray.getString(i)); + String ownerRecalculated = calculateHash(ownerIdentity, "SHA3-256"); + + TokenReceiverLogger.debug("Ownership Here Sender Calculation"); + TokenReceiverLogger.debug("tokens: " + tokens); + TokenReceiverLogger.debug("hashString: " + hashString); + TokenReceiverLogger.debug("hashForPositions: " + hashForPositions); + TokenReceiverLogger.debug("p1: " + positionsArray.getString(i)); + TokenReceiverLogger.debug("ownerIdentity: " + ownerIdentity); + TokenReceiverLogger.debug("ownerIdentityHash: " + ownerRecalculated); + + if (!owner.equals(ownerRecalculated)) { + ownerCheck = false; + invalidTokens.put(tokens); + } + } + + } + + if(!ownerCheck) { + TokenReceiverLogger.debug("Ownership Check Failed"); + String errorMessage = "Ownership Check Failed"; + output.println("424"); + output.println(invalidTokens.toString()); + APIResponse.put("did", senderDidIpfsHash); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + APIResponse.put("message", errorMessage); + TokenReceiverLogger.debug(errorMessage); + executeIPFSCommands(" ipfs p2p close -t /p2p/" + senderPeerID); + output.close(); + input.close(); + sk.close(); + ss.close(); + return APIResponse.toString(); + } + else + TokenReceiverLogger.debug("Ownership Check Passed"); + boolean partsAvailable = true; for (int i = 0; i < partTokenChainContent.length(); i++) { Double senderCount = 0.000D, receiverCount = 0.000D; JSONArray tokenChainContent = partTokenChainContent.getJSONArray(i); for (int k = 0; k < tokenChainContent.length(); k++) { if (tokenChainContent.getJSONObject(k).has("role")) { - if (tokenChainContent.getJSONObject(k).getString("role").equals("Sender") - && tokenChainContent.getJSONObject(k).getString("sender").equals(senderDidIpfsHash)) { + if (tokenChainContent.getJSONObject(k).getString("role").equals("Sender") && tokenChainContent.getJSONObject(k).getString("sender").equals(senderDidIpfsHash)) { senderCount += tokenChainContent.getJSONObject(k).getDouble("amount"); - } else if (tokenChainContent.getJSONObject(k).getString("role").equals("Receiver") - && tokenChainContent.getJSONObject(k).getString("receiver").equals(senderDidIpfsHash)) { + } else if (tokenChainContent.getJSONObject(k).getString("role").equals("Receiver") && tokenChainContent.getJSONObject(k).getString("receiver").equals(senderDidIpfsHash)) { receiverCount += tokenChainContent.getJSONObject(k).getDouble("amount"); } } @@ -399,12 +423,12 @@ public static String receive() { if (availableParts > 1.000D) { TokenReceiverLogger.debug("Token wholly spent: " + partTokens.getString(i)); TokenReceiverLogger.debug("Parts: " + availableParts); + partsAvailable = false; } } - if (!partsAvailable) { String errorMessage = "Token wholly spent already"; - output.println("424"); + output.println("425"); APIResponse.put("did", senderDidIpfsHash); APIResponse.put("tid", "null"); APIResponse.put("status", "Failed"); @@ -416,8 +440,8 @@ public static String receive() { sk.close(); ss.close(); return APIResponse.toString(); - } else - output.println("200"); + } + output.println("200"); String senderDetails; try { @@ -446,6 +470,7 @@ public static String receive() { BufferedImage senderWidImage = ImageIO.read(new File(DATA_PATH + senderDidIpfsHash + "/PublicShare.png")); SenWalletBin = PropImage.img2bin(senderWidImage); + TokenReceiverLogger.debug("Verifying Quorum ... "); TokenReceiverLogger.debug("Please wait, this might take a few seconds"); @@ -464,8 +489,7 @@ public static String receive() { for (String quorumDidIpfsHash : quorumDID) { syncDataTable(quorumDidIpfsHash, null); - String quorumWidIpfsHash = getValues(DATA_PATH + "DataTable.json", "walletHash", "didHash", - quorumDidIpfsHash); + String quorumWidIpfsHash = getValues(DATA_PATH + "DataTable.json", "walletHash", "didHash", quorumDidIpfsHash); nodeData(quorumDidIpfsHash, quorumWidIpfsHash, ipfs); } @@ -487,10 +511,7 @@ public static String receive() { for (int i = 0; i < intPart; i++) wholeTokenChainHash.put(wholeTokenChains.getString(i)); - String hash = calculateHash( - wholeTokens.toString() + wholeTokenChainHash.toString() + partTokens.toString() - + partTokenChainsHash.toString() + receiverDidIpfsHash + senderDidIpfsHash + comment, - "SHA3-256"); + String hash = calculateHash(wholeTokens.toString() + wholeTokenChainHash.toString() + partTokens.toString() + partTokenChainsHash.toString() + receiverDidIpfsHash + senderDidIpfsHash + comment, "SHA3-256"); TokenReceiverLogger.debug("Hash to verify Sender: " + hash); JSONObject detailsForVerify = new JSONObject(); detailsForVerify.put("did", senderDidIpfsHash); @@ -540,7 +561,7 @@ public static String receive() { for (int i = 0; i < intPart; i++) { FileWriter fileWriter; fileWriter = new FileWriter(TOKENS_PATH + wholeTokens.getString(i)); - fileWriter.write(allTokenContent.get(i)); + fileWriter.write(wholeTokenContent.get(i)); fileWriter.close(); add(TOKENS_PATH + wholeTokens.getString(i), ipfs); pin(wholeTokens.getString(i), ipfs); @@ -583,8 +604,29 @@ public static String receive() { } long endTime = System.currentTimeMillis(); - for (int i = 0; i < intPart; i++) { + String tokens = wholeTokens.getString(i); + String hashString = tokens.concat(receiverDidIpfsHash); + String hashForPositions = calculateHash(hashString, "SHA3-256"); + + BufferedImage pvt = ImageIO.read(new File(DATA_PATH.concat(receiverDidIpfsHash).concat("/PrivateShare.png"))); + String firstPrivate = PropImage.img2bin(pvt); + int[] privateIntegerArray1 = strToIntArray(firstPrivate); + String privateBinary = Functions.intArrayToStr(privateIntegerArray1); + String positions = ""; + for(int j = 0; j < privateIntegerArray1.length; j+=49152){ + positions+=privateBinary.charAt(j); + } + String ownerIdentity = hashForPositions.concat(positions); + String ownerIdentityHash = calculateHash(ownerIdentity, "SHA3-256"); + + TokenReceiverLogger.debug("Ownership Here"); + TokenReceiverLogger.debug("tokens: " + wholeTokens.getString(i)); + TokenReceiverLogger.debug("hashString: " + hashString); + TokenReceiverLogger.debug("hashForPositions: " + hashForPositions); + TokenReceiverLogger.debug("p1: " + positions); + TokenReceiverLogger.debug("ownerIdentity: " + ownerIdentity); + TokenReceiverLogger.debug("ownerIdentityHash: " + ownerIdentityHash); ArrayList groupTokens = new ArrayList<>(); for (int k = 0; k < intPart; k++) { @@ -596,17 +638,19 @@ public static String receive() { JSONObject objectToken = new JSONObject(); objectToken.put("tokenHash", wholeTokens.getString(i)); arrToken.put(objectToken); - JSONArray arr1 = new JSONArray(allTokenChainContent.get(i)); + JSONArray arr1 = new JSONArray(wholeTokenChainContent.get(i)); JSONObject obj2 = new JSONObject(); obj2.put("senderSign", senderSignature); obj2.put("sender", senderDidIpfsHash); obj2.put("group", groupTokens); obj2.put("comment", comment); obj2.put("tid", tid); + obj2.put("owner", ownerIdentityHash); arr1.put(obj2); writeToFile(TOKENCHAIN_PATH + wholeTokens.getString(i) + ".json", arr1.toString(), false); } + for (int i = 0; i < partTokens.length(); i++) { JSONObject chequeObject = new JSONObject(); chequeObject.put("sender", senderDidIpfsHash); @@ -621,6 +665,30 @@ public static String receive() { String chequeHash = IPFSNetwork.add(LOGGER_PATH.concat(partTokens.getString(i)), ipfs); deleteFile(LOGGER_PATH.concat(partTokens.getString(i))); + + String tokens = partTokens.getString(i); + String hashString = tokens.concat(receiverDidIpfsHash); + String hashForPositions = calculateHash(hashString, "SHA3-256"); + BufferedImage pvt = ImageIO.read(new File(DATA_PATH.concat(receiverDidIpfsHash).concat("/PrivateShare.png"))); + String firstPrivate = PropImage.img2bin(pvt); + int[] privateIntegerArray1 = strToIntArray(firstPrivate); + String privateBinary = Functions.intArrayToStr(privateIntegerArray1); + String positions = ""; + for(int j = 0; j < privateIntegerArray1.length; j+=49152){ + positions+=privateBinary.charAt(j); + } + + String ownerIdentity = hashForPositions.concat(positions); + String ownerIdentityHash = calculateHash(ownerIdentity, "SHA3-256"); + + TokenReceiverLogger.debug("Ownership Here"); + TokenReceiverLogger.debug("tokens: " + partTokens.getString(i)); + TokenReceiverLogger.debug("hashString: " + hashString); + TokenReceiverLogger.debug("hashForPositions: " + hashForPositions); + TokenReceiverLogger.debug("p1: " + positions); + TokenReceiverLogger.debug("ownerIdentity: " + ownerIdentity); + TokenReceiverLogger.debug("ownerIdentityHash: " + ownerIdentityHash); + JSONObject newPartObject = new JSONObject(); newPartObject.put("senderSign", senderSignature); newPartObject.put("sender", senderDidIpfsHash); @@ -628,43 +696,35 @@ public static String receive() { newPartObject.put("comment", comment); newPartObject.put("tid", tid); newPartObject.put("nextHash", ""); + newPartObject.put("owner", ownerIdentityHash); if (partTokenChainContent.getJSONArray(i).length() == 0) newPartObject.put("previousHash", ""); else - newPartObject.put("previousHash", - calculateHash(partTokenChainContent.getJSONArray(i) - .getJSONObject(partTokenChainContent.getJSONArray(i).length() - 1) - .getString("tid"), "SHA3-256")); + newPartObject.put("previousHash", calculateHash(partTokenChainContent.getJSONArray(i).getJSONObject(partTokenChainContent.getJSONArray(i).length() - 1).getString("tid"), "SHA3-256")); + newPartObject.put("amount", partAmount); newPartObject.put("cheque", chequeHash); newPartObject.put("role", "Receiver"); - File chainFile = new File( - PART_TOKEN_CHAIN_PATH.concat(partTokens.getString(i)).concat(".json")); + File chainFile = new File(PART_TOKEN_CHAIN_PATH.concat(partTokens.getString(i)).concat(".json")); if (chainFile.exists()) { String readChain = readFile(PART_TOKEN_CHAIN_PATH + partTokens.getString(i) + ".json"); JSONArray readChainArray = new JSONArray(readChain); - readChainArray.put(partTokenChainContent.getJSONArray(i) - .getJSONObject(partTokenChainContent.getJSONArray(i).length() - 1)); + readChainArray.put(partTokenChainContent.getJSONArray(i).getJSONObject(partTokenChainContent.getJSONArray(i).length() - 1)); readChainArray.put(newPartObject); - writeToFile(PART_TOKEN_CHAIN_PATH + partTokens.getString(i) + ".json", - readChainArray.toString(), false); + writeToFile(PART_TOKEN_CHAIN_PATH + partTokens.getString(i) + ".json", readChainArray.toString(), false); + } else { partTokenChainContent.getJSONArray(i).put(newPartObject); - writeToFile(PART_TOKEN_CHAIN_PATH + partTokens.getString(i) + ".json", - partTokenChainContent.getJSONArray(i).toString(), false); + writeToFile(PART_TOKEN_CHAIN_PATH + partTokens.getString(i) + ".json", partTokenChainContent.getJSONArray(i).toString(), false); } } - JSONArray allTokens = new JSONArray(); - for (int i = 0; i < wholeTokens.length(); i++) - allTokens.put(wholeTokens.getString(i)); - for (int i = 0; i < partTokens.length(); i++) - allTokens.put(partTokens.getString(i)); + JSONObject transactionRecord = new JSONObject(); transactionRecord.put("role", "Receiver"); @@ -682,8 +742,7 @@ public static String receive() { JSONArray transactionHistoryEntry = new JSONArray(); transactionHistoryEntry.put(transactionRecord); - updateJSON("add", WALLET_DATA_PATH + "TransactionHistory.json", - transactionHistoryEntry.toString()); + updateJSON("add", WALLET_DATA_PATH + "TransactionHistory.json", transactionHistoryEntry.toString()); for (int i = 0; i < wholeTokens.length(); i++) { String bankFile = readFile(PAYMENTS_PATH.concat("BNK00.json")); @@ -701,8 +760,7 @@ public static String receive() { for (int i = 0; i < partTokens.length(); i++) { boolean writeParts = true; for (int j = 0; j < partsReadArray.length(); j++) { - if (partsReadArray.getJSONObject(j).getString("tokenHash") - .equals(partTokens.getString(i))) + if (partsReadArray.getJSONObject(j).getString("tokenHash").equals(partTokens.getString(i))) writeParts = false; } if (writeParts) { diff --git a/src/com/rubix/TokenTransfer/TokenSender.java b/src/com/rubix/TokenTransfer/TokenSender.java index 2ebedd31..7e1f47d5 100644 --- a/src/com/rubix/TokenTransfer/TokenSender.java +++ b/src/com/rubix/TokenTransfer/TokenSender.java @@ -1,5 +1,6 @@ package com.rubix.TokenTransfer; +import com.rubix.AuthenticateNode.PropImage; import com.rubix.Consensus.InitiatorConsensus; import com.rubix.Consensus.InitiatorProcedure; import com.rubix.Resources.Functions; @@ -11,7 +12,9 @@ import org.json.JSONException; import org.json.JSONObject; +import javax.imageio.ImageIO; import javax.net.ssl.HttpsURLConnection; +import java.awt.image.BufferedImage; import java.io.*; import java.net.Socket; import java.net.SocketException; @@ -127,6 +130,7 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception } JSONArray wholeTokenChainHash = new JSONArray(); JSONArray tokenPreviousSender = new JSONArray(); + for (int i = 0; i < wholeTokens.length(); i++) { File token = new File(TOKENS_PATH + wholeTokens.get(i)); File tokenchain = new File(TOKENCHAIN_PATH + wholeTokens.get(i) + ".json"); @@ -158,6 +162,7 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception previousSenderObject.put("token", wholeTokenHash); previousSenderObject.put("sender", previousSenderArray); tokenPreviousSender.put(previousSenderObject); + } Double decimalAmount = requestedAmount - wholeAmount; @@ -305,6 +310,32 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception for(int i = 0; i < partTokens.length(); i++) allTokens.put(partTokens.getString(i)); + + JSONArray positionsArray = new JSONArray(); + for(int i = 0; i < allTokens.length(); i++) { + String tokens = allTokens.getString(i); + String hashString = tokens.concat(senderDidIpfsHash); + String hashForPositions = calculateHash(hashString, "SHA3-256"); + BufferedImage privateShare = ImageIO.read(new File(DATA_PATH.concat(senderDidIpfsHash).concat("/PrivateShare.png"))); + String firstPrivate = PropImage.img2bin(privateShare); + int[] privateIntegerArray1 = strToIntArray(firstPrivate); + String privateBinary = Functions.intArrayToStr(privateIntegerArray1); + String positions = ""; + for(int j = 0; j < privateIntegerArray1.length; j+=49152){ + positions+=privateBinary.charAt(j); + } + positionsArray.put(positions); + + TokenSenderLogger.debug("Ownership Here Sender Calculation"); + TokenSenderLogger.debug("tokens: " + tokens); + TokenSenderLogger.debug("hashString: " + hashString); + TokenSenderLogger.debug("hashForPositions: " + hashForPositions); + TokenSenderLogger.debug("p1: " + positions); + } + + + + JSONArray alphaQuorum = new JSONArray(); JSONArray betaQuorum = new JSONArray(); JSONArray gammaQuorum = new JSONArray(); @@ -545,6 +576,7 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception JSONObject tokenObject = new JSONObject(); tokenObject.put("tokenDetails", tokenDetails); tokenObject.put("previousSender", tokenPreviousSender); + tokenObject.put("positions", positionsArray); tokenObject.put("amount", requestedAmount); tokenObject.put("amountLedger", amountLedger); @@ -559,6 +591,7 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception String tokenAuth; try { tokenAuth = input.readLine(); + TokenSenderLogger.debug("Token Auth Code: " + tokenAuth); } catch (SocketException e) { TokenSenderLogger.warn("Receiver " + receiverDidIpfsHash + " is unable to Respond! - Token Auth"); executeIPFSCommands(" ipfs p2p close -t /p2p/" + receiverPeerId); @@ -574,35 +607,40 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception return APIResponse; } - if (tokenAuth != null && (!tokenAuth.equals("200"))) { + if (tokenAuth != null && (tokenAuth.startsWith("4"))) { switch (tokenAuth) { case "420": String doubleSpent = input.readLine(); String owners = input.readLine(); JSONArray ownersArray = new JSONArray(owners); TokenSenderLogger.info("Multiple Owners for " + doubleSpent); - APIResponse.put("message", "Multiple Owners for " + doubleSpent); - APIResponse.put("Owners", ownersArray); - removeToken(); + TokenSenderLogger.info("Owners " + ownersArray); + TokenSenderLogger.info("Kindly re-initiate transaction"); + APIResponse.put("message", "Multiple Owners for " + doubleSpent + " Owners: " + ownersArray +". Kindly re-initiate transaction"); break; case "421": - TokenSenderLogger.info("Consensus ID not unique"); - APIResponse.put("message", "Consensus ID not unique"); - removeToken(); + TokenSenderLogger.info("Consensus ID not unique. Kindly re-initiate transaction"); + APIResponse.put("message", "Consensus ID not unique. Kindly re-initiate transaction"); break; case "422": - TokenSenderLogger.info("Tokens Not Verified"); - APIResponse.put("message", "Tokens Not Verified"); - removeToken(); + TokenSenderLogger.info("Tokens Not Verified. Kindly re-initiate transaction"); + APIResponse.put("message", "Tokens Not Verified. Kindly re-initiate transaction"); break; case "423": - TokenSenderLogger.info("Broken Cheque Chain"); - APIResponse.put("message", "Broken Cheque Chain"); + TokenSenderLogger.info("Broken Cheque Chain. Kindly re-initiate transaction"); + APIResponse.put("message", "Broken Cheque Chain. Kindly re-initiate transaction"); break; case "424": - TokenSenderLogger.info("Token wholly spent already"); - APIResponse.put("message", "Token wholly spent already"); + String invalidTokens = input.readLine(); + JSONArray tokensArray = new JSONArray(invalidTokens); + TokenSenderLogger.info("Ownership Check Failed for " + tokensArray); + APIResponse.put("message", "Ownership Check Failed"); + break; + + case "425": + TokenSenderLogger.info("Token wholly spent already. Kindly re-initiate transaction"); + APIResponse.put("message", "Token wholly spent already. Kindly re-initiate transaction"); break; } @@ -619,6 +657,7 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception APIResponse.put("status", "Failed"); return APIResponse; } + TokenSenderLogger.debug("Token Auth Code: " + tokenAuth); JSONObject dataObject = new JSONObject(); dataObject.put("tid", tid); @@ -631,7 +670,6 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception dataObject.put("betaList", betaPeersList); dataObject.put("gammaList", gammaPeersList); - InitiatorProcedure.consensusSetUp(dataObject.toString(), ipfs, SEND_PORT + 100, alphaSize, ""); TokenSenderLogger.debug("length on sender " + InitiatorConsensus.quorumSignature.length() + "response count " + InitiatorConsensus.quorumResponse); if (InitiatorConsensus.quorumSignature.length() < (minQuorum(alphaSize) + 2 * minQuorum(7))) { From 52f762a8567cb4c664161b3138f85d53ce07527c Mon Sep 17 00:00:00 2001 From: aparnaullas-rubix Date: Mon, 21 Mar 2022 00:52:25 +0300 Subject: [PATCH 30/49] Collect credits of quorum nodes --- src/com/rubix/Ping/GetCredits.java | 79 ++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 src/com/rubix/Ping/GetCredits.java diff --git a/src/com/rubix/Ping/GetCredits.java b/src/com/rubix/Ping/GetCredits.java new file mode 100644 index 00000000..1d838d4c --- /dev/null +++ b/src/com/rubix/Ping/GetCredits.java @@ -0,0 +1,79 @@ +package com.rubix.Ping; + +import io.ipfs.api.IPFS; +import org.apache.log4j.Logger; +import org.apache.log4j.PropertyConfigurator; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintStream; +import java.net.Socket; +import java.net.SocketException; + +import static com.rubix.Resources.Functions.*; +import static com.rubix.Resources.IPFSNetwork.*; + +public class GetCredits { + private static final Logger PingSenderLogger = Logger.getLogger(GetCredits.class); + public static IPFS ipfs = new IPFS("/ip4/127.0.0.1/tcp/" + IPFS_PORT); + + public static JSONObject Contact(String did, int port) throws IOException, JSONException { + repo(ipfs); + PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); + + String peerID = getValues(DATA_PATH + "DataTable.json", "peerid", "didHash", did); + + JSONObject APIResponse = new JSONObject(); + + String appName = peerID.concat("Credits"); + forward(appName, port, peerID); + PingSenderLogger.debug("Forwarded to " + appName + " on " + port); + Socket senderSocket = new Socket("127.0.0.1", port); + + BufferedReader input = new BufferedReader(new InputStreamReader(senderSocket.getInputStream())); + PrintStream output = new PrintStream(senderSocket.getOutputStream()); + + output.println("Get-Credits"); + PingSenderLogger.debug("Sent Credits request"); + + String pongResponse; + try { + pongResponse = input.readLine(); + } catch (SocketException e) { + PingSenderLogger.warn("Quorum " + did + " is unable to Respond! - Credits Ping"); + executeIPFSCommands(" ipfs p2p close -t /p2p/" + peerID); + output.close(); + input.close(); + senderSocket.close(); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Quorum " + did + "is unable to respond! - Credits Ping"); + + return APIResponse; + } + + + if (pongResponse == null) { + executeIPFSCommands(" ipfs p2p close -t /p2p/" + peerID); + PingSenderLogger.info("Credits response not received"); + output.close(); + input.close(); + senderSocket.close(); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Credits response not received"); + + }else { + PingSenderLogger.info("Credits Successful " + pongResponse); + executeIPFSCommands(" ipfs p2p close -t /p2p/" + peerID); + output.close(); + input.close(); + senderSocket.close(); + APIResponse.put("status", "Success"); + APIResponse.put("message", Integer.parseInt(pongResponse)); + + } + return APIResponse; + } +} From 0fc004de693a48356c3a20544eb1a007c4f0e96a Mon Sep 17 00:00:00 2001 From: aparnaullas-rubix Date: Mon, 21 Mar 2022 00:55:15 +0300 Subject: [PATCH 31/49] Listening thread to send credits on request --- src/com/rubix/Ping/QuorumSendCredits.java | 94 +++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 src/com/rubix/Ping/QuorumSendCredits.java diff --git a/src/com/rubix/Ping/QuorumSendCredits.java b/src/com/rubix/Ping/QuorumSendCredits.java new file mode 100644 index 00000000..a4e36774 --- /dev/null +++ b/src/com/rubix/Ping/QuorumSendCredits.java @@ -0,0 +1,94 @@ +package com.rubix.Ping; + +import io.ipfs.api.IPFS; +import org.apache.log4j.Logger; +import org.apache.log4j.PropertyConfigurator; +import org.json.JSONArray; +import org.json.JSONObject; + +import java.io.*; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketException; + +import static com.rubix.Resources.Functions.*; +import static com.rubix.Resources.IPFSNetwork.*; + +public class QuorumSendCredits { + public static Logger QuorumPingReceiverLogger = Logger.getLogger(QuorumSendCredits.class); + + private static final JSONObject APIResponse = new JSONObject(); + private static final IPFS ipfs = new IPFS("/ip4/127.0.0.1/tcp/" + IPFS_PORT); + + public static String sendCredits(int port) { + pathSet(); + ServerSocket ss ; + Socket sk ; + + try { + repo(ipfs); + + + PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); + + String receiverPeerID = getPeerID(DATA_PATH + "DID.json"); + String appName = receiverPeerID.concat("Credits"); + listen(appName, port); + ss = new ServerSocket(port); + QuorumPingReceiverLogger.debug("Credits Quorum Listening on " + port + " appname " + appName); + + sk = ss.accept(); + QuorumPingReceiverLogger.debug("Data Incoming..."); + BufferedReader input = new BufferedReader(new InputStreamReader(sk.getInputStream())); + PrintStream output = new PrintStream(sk.getOutputStream()); + + String pingRequest; + try { + pingRequest = input.readLine(); + } catch (SocketException e) { + QuorumPingReceiverLogger.warn("Sender Stream Null - Credits"); + APIResponse.put("did", ""); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Sender Stream Null - Credits"); + + output.close(); + input.close(); + sk.close(); + ss.close(); + return APIResponse.toString(); + + } + QuorumPingReceiverLogger.debug("Credits Request Received: " + pingRequest); + if(pingRequest != null && pingRequest.contains("Get-Credits")) { + String qstFile = WALLET_DATA_PATH.concat("QuorumSignedTransactions.json"); + File quorumFile = new File(qstFile); + int unspentCredits = 0; + if(quorumFile.exists()){ + String qFile = readFile(qstFile); + JSONArray qArray = new JSONArray(qFile); + unspentCredits = qArray.length(); + } + output.println(unspentCredits); + + APIResponse.put("status", "Success"); + APIResponse.put("message", "Credits Sent"); + QuorumPingReceiverLogger.info("Credits Sent " + unspentCredits); + + }else{ + APIResponse.put("status", "Failed"); + APIResponse.put("message", "Credits Failed"); + QuorumPingReceiverLogger.info("Credits Failed"); + } + executeIPFSCommands(" ipfs p2p close -t /p2p/" + pingRequest); + output.close(); + input.close(); + sk.close(); + ss.close(); + + } catch (IOException e) { + e.printStackTrace(); + } + return APIResponse.toString(); + } +} From bff13d8d2864b827807112159060db366629797f Mon Sep 17 00:00:00 2001 From: aparnaullas-rubix Date: Mon, 21 Mar 2022 00:56:32 +0300 Subject: [PATCH 32/49] API to arrange quorum list according to credits --- src/com/rubix/Resources/APIHandler.java | 69 +++++++++++++++++-------- 1 file changed, 48 insertions(+), 21 deletions(-) diff --git a/src/com/rubix/Resources/APIHandler.java b/src/com/rubix/Resources/APIHandler.java index 7151e760..66f11ee1 100644 --- a/src/com/rubix/Resources/APIHandler.java +++ b/src/com/rubix/Resources/APIHandler.java @@ -25,16 +25,47 @@ public class APIHandler { private static final Logger eventLogger = Logger.getLogger("eventLogger"); /** - * Initiates a transfer between two nodes - * @param data Data specific to token transfer - * @return Message from the sender with transaction details + * Arrange the nodes in the quorumlist file + * @return Message if success or failure of arrangement * @throws JSONException handles JSON Exceptions * @throws NoSuchAlgorithmException handles Invalid Algorithms Exceptions * @throws IOException handles IO Exceptions */ + public static JSONObject sortType2Quorum(){ + Functions.pathSet(); + PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); + JSONObject sendMessage = new JSONObject(); + JSONArray quorumArray = new JSONArray(readFile(DATA_PATH + "quorumlist.json")); + APILogger.debug("Before Sorting: " + quorumArray); + int code = 0; + try { + code = arrangeQuorum(quorumArray, SEND_PORT+15, 0); + } catch (IOException e) { + APILogger.debug("Credits failed"); + } + + if(code == 200) { + quorumArray = new JSONArray(readFile(DATA_PATH + "quorumlist.json")); + APILogger.debug("After Sorting: " + quorumArray); + sendMessage.put("status", "Success"); + sendMessage.put("message", "Sorted"); + } + else if(code == 401){ + APILogger.debug("Could not collect all(min. 21) credits"); + sendMessage.put("status", "Failed"); + sendMessage.put("message", ""); + } + else if(code == 402){ + APILogger.debug("7 alpha node credits not summing up to requested amount"); + sendMessage.put("status", "Failed"); + sendMessage.put("message", ""); + } + return sendMessage; + + } public static JSONObject send(String data) throws Exception { Functions.pathSet(); PropertyConfigurator.configure(LOGGER_PATH + "log4jWallet.properties"); @@ -176,28 +207,24 @@ public static JSONObject creditsInfo(){ File quorumFile = new File(qstFile); File minedFile = new File(mineFile); - JSONObject returnObject = new JSONObject(); + int spentCredits = 0; int unspentCredits = 0; - try { - if(quorumFile.exists()){ - String qFile = readFile(qstFile); - JSONArray qArray = new JSONArray(qFile); - unspentCredits = qArray.length(); - } - if(minedFile.exists()){ - String mFile = readFile(mineFile); - JSONArray mArray = new JSONArray(mFile); - spentCredits = mArray.length(); - } - - - returnObject.put("spentCredits",spentCredits); - returnObject.put("unspentCredits",unspentCredits); - } catch (JSONException e) { - //TODO: handle exception + if(quorumFile.exists()){ + String qFile = readFile(qstFile); + JSONArray qArray = new JSONArray(qFile); + unspentCredits = qArray.length(); + } + if(minedFile.exists()){ + String mFile = readFile(mineFile); + JSONArray mArray = new JSONArray(mFile); + spentCredits = mArray.length(); } + JSONObject returnObject = new JSONObject(); + returnObject.put("spentCredits",spentCredits); + returnObject.put("unspentCredits",unspentCredits); + return returnObject; } From 822b93065592e6fcc8371fa6cd500304ddad476b Mon Sep 17 00:00:00 2001 From: aparnaullas-rubix Date: Mon, 21 Mar 2022 00:57:33 +0300 Subject: [PATCH 33/49] Functions supporting pinging the quorum nodes to collect credits --- src/com/rubix/Resources/Functions.java | 344 +++++++++++++------------ 1 file changed, 186 insertions(+), 158 deletions(-) diff --git a/src/com/rubix/Resources/Functions.java b/src/com/rubix/Resources/Functions.java index ef5e8a5d..dddb5254 100644 --- a/src/com/rubix/Resources/Functions.java +++ b/src/com/rubix/Resources/Functions.java @@ -1,6 +1,7 @@ package com.rubix.Resources; import com.rubix.AuthenticateNode.PropImage; +import com.rubix.Ping.GetCredits; import com.rubix.Ping.PingCheck; import io.ipfs.api.IPFS; import io.ipfs.multiaddr.MultiAddress; @@ -15,8 +16,6 @@ import java.io.*; import java.math.RoundingMode; import java.net.HttpURLConnection; -import java.net.Socket; -import java.net.SocketException; import java.net.URL; import java.nio.charset.StandardCharsets; import java.nio.file.Files; @@ -26,11 +25,7 @@ import java.text.DecimalFormat; import java.text.ParseException; import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.Set; +import java.util.*; import static com.rubix.Resources.APIHandler.addPublicData; import static com.rubix.Resources.IPFSNetwork.*; @@ -869,7 +864,7 @@ public static String mineToken(int level, int tokenNumber) { String levelHex = Integer.toHexString(level); if (level < 16) levelHex = String.valueOf(0).concat(levelHex); - String token = String.valueOf(0) + levelHex + tokenHash; + String token = 0 + levelHex + tokenHash; return token; } @@ -892,10 +887,7 @@ public static String toBinary(int x, int len) { public static Boolean integrityCheck(String consensusID) { File file = new File(WALLET_DATA_PATH + "QuorumSignedTransactions.json"); if (file.exists()) { - if (getValues(file.getAbsolutePath(), "senderdid", "consensusID", consensusID).equals("")) - return true; - else - return false; + return getValues(file.getAbsolutePath(), "senderdid", "consensusID", consensusID).equals(""); } else return true; } @@ -1105,7 +1097,7 @@ public static void syncDataTable(String did, String peerId) { } } - public static void correctToken() throws JSONException{ + public static void correctToken(){ pathSet(); String bank = readFile(PAYMENTS_PATH.concat("BNK00.json")); JSONArray bankArray = new JSONArray(bank); @@ -1120,7 +1112,7 @@ public static void correctToken() throws JSONException{ } } - public static void correctPartToken() throws JSONException{ + public static void correctPartToken(){ pathSet(); String bank = readFile(PAYMENTS_PATH.concat("PartsToken.json")); JSONArray bankArray = new JSONArray(bank); @@ -1135,7 +1127,7 @@ public static void correctPartToken() throws JSONException{ } } - public static void tokenBank() throws JSONException { + public static void tokenBank() { pathSet(); String bank = readFile(PAYMENTS_PATH.concat("BNK00.json")); JSONArray bankArray = new JSONArray(bank); @@ -1159,8 +1151,8 @@ public static void tokenBank() throws JSONException { } File tokensPath = new File(TOKENS_PATH); - String contents[] = tokensPath.list(); - ArrayList tokenFiles = new ArrayList(); + String[] contents = tokensPath.list(); + ArrayList tokenFiles = new ArrayList(); for (int i = 0; i < contents.length; i++) { if (!contents[i].contains("PARTS")) tokenFiles.add(contents[i]); @@ -1271,6 +1263,7 @@ public static Double checkTokenPartBalance(String tokenHash) throws JSONExceptio return availableParts; } + public static Double getBalance() throws JSONException { pathSet(); Double balance = 0.000D; @@ -1289,6 +1282,7 @@ public static Double getBalance() throws JSONException { balance = balance + value; } + File partsFile = new File(PAYMENTS_PATH + "PartsToken.json"); if (partsFile.exists()) { String PART_TOKEN_CHAIN_PATH = TOKENCHAIN_PATH.concat("/PARTS/"); @@ -1332,6 +1326,7 @@ public static Double getBalance() throws JSONException { for (int i = 0; i < shiftedArray.length(); i++) arrayTokens.add(shiftedArray.getString(i)); + for (int i = 0; i < partTokensArray.length(); i++) { if (!arrayTokens.contains(partTokensArray.getJSONObject(i).getString("tokenHash"))) count++; @@ -1342,10 +1337,12 @@ public static Double getBalance() throws JSONException { balance = balance - count; } + balance = formatAmount(balance); return balance; } + public static Double partTokenBalance(String tokenHash) throws JSONException { pathSet(); @@ -1390,7 +1387,7 @@ public static Double formatAmount(Double amount) { } - public static void clearParts() throws JSONException { + public static void clearParts() { String partsFile = readFile(PAYMENTS_PATH.concat("PartsToken.json")); JSONArray partsArray = new JSONArray(partsFile); for (int i = 0; i < partsArray.length(); i++) { @@ -1421,30 +1418,28 @@ public static void backgroundChecks() { addPublicData(); } - public static String sanityMessage; - public static boolean sanityCheck(String peerid, IPFS ipfs, int port) throws IOException { - FunctionsLogger.info("Entering SanityCheck"); +// FunctionsLogger.info("Entering SanityCheck"); boolean sanityCheckErrorFlag = true; if (sanityCheckErrorFlag && checkIPFSStatus(peerid, ipfs)) { FunctionsLogger.debug("IPFS is working in " + peerid); - FunctionsLogger.debug("IPFS check true"); +// FunctionsLogger.debug("IPFS check true"); } else { sanityCheckErrorFlag = false; - FunctionsLogger.debug("IPFS is not working in " + peerid); - FunctionsLogger.debug("IPFS check false"); +// FunctionsLogger.debug("IPFS is not working in " + peerid); +// FunctionsLogger.debug("IPFS check false"); sanityMessage = "IPFS is not working in " + peerid; } if (sanityCheckErrorFlag) { if (bootstrapConnect(peerid, ipfs)) { FunctionsLogger.debug("Bootstrap connected for " + peerid); - FunctionsLogger.debug("Bootstrap check true"); +// FunctionsLogger.debug("Bootstrap check true"); } else { sanityCheckErrorFlag = false; - FunctionsLogger.debug("Bootstrap connection unsuccessful for " + peerid); - FunctionsLogger.debug("Bootstrap check false"); +// FunctionsLogger.debug("Bootstrap connection unsuccessful for " + peerid); +// FunctionsLogger.debug("Bootstrap check false"); sanityMessage = "Bootstrap connection unsuccessful for " + peerid; } } @@ -1452,26 +1447,27 @@ public static boolean sanityCheck(String peerid, IPFS ipfs, int port) throws IOE if (sanityCheckErrorFlag) { if (ping(peerid, port)) { FunctionsLogger.debug("Jar is running as expected in " + peerid); - FunctionsLogger.debug("Jar check true"); +// FunctionsLogger.debug("Jar check true"); } else { sanityCheckErrorFlag = false; - FunctionsLogger.debug("Jar is not running in " + peerid); - FunctionsLogger.debug("Jar check false"); +// FunctionsLogger.debug("Jar is not running in " + peerid); +// FunctionsLogger.debug("Jar check false"); sanityMessage = "Jar is not running in " + peerid; } } if (sanityCheckErrorFlag) { if (portCheckAndKill(port)) { - FunctionsLogger.debug("Ports are available for transcations in " + peerid); - FunctionsLogger.debug("Ports check true"); + FunctionsLogger.debug("Ports are available for transactions in " + peerid); +// FunctionsLogger.debug("Ports check true"); } else { sanityCheckErrorFlag = false; - FunctionsLogger.debug("Ports are not available for " + peerid); - FunctionsLogger.debug("Ports check false"); +// FunctionsLogger.debug("Ports are not available for " + peerid); +// FunctionsLogger.debug("Ports check false"); sanityMessage = "Ports are not available for " + peerid; } } + return sanityCheckErrorFlag; } public static boolean checkIPFSStatus(String peerid, IPFS ipfs) { @@ -1479,113 +1475,165 @@ public static boolean checkIPFSStatus(String peerid, IPFS ipfs) { boolean swarmConnectedStatus = false; try { MultiAddress multiAddress = new MultiAddress("/ipfs/" + peerid); - FunctionsLogger.info("MultiAdrress concated " + multiAddress + "|||"); +// FunctionsLogger.info("MultiAdrress concated " + multiAddress + "|||"); boolean output = swarmConnectP2P(peerid, ipfs); - FunctionsLogger.info("Swarm connect process response is " + output); + if (output) { swarmConnectedStatus = true; - FunctionsLogger.debug("Swarm is already connected"); +// FunctionsLogger.debug("Swarm is already connected"); } else { swarmConnectedStatus = false; - FunctionsLogger.debug("Swarm is not connected"); +// FunctionsLogger.debug("Swarm is not connected"); } } catch (Exception e) { - FunctionsLogger.error("Check Swarm Connect is failed", e); + FunctionsLogger.error("QuorumSendCredits Swarm Connect is failed", e); } FunctionsLogger.info("checkIPFSStatus return value is " + swarmConnectedStatus); return swarmConnectedStatus; } - public static boolean ping(String peerid, int port) { - boolean result = false; - try { - JSONObject pingCheck = PingCheck.Ping(peerid, port); - if (pingCheck.getString("status").contains("Failed")) { - result = false; - } else - result = true; - } catch (JSONException e) { - // TODO: handle exception - } catch (IOException e) { - // TODO: handle exception + + public static boolean ping(String peerid, int port) throws IOException { + JSONObject pingCheck = PingCheck.Ping(peerid, port); + return !pingCheck.getString("status").contains("Failed"); + + } + + public static int arrangeQuorum(JSONArray quorumArray, int port, double amount) throws IOException { + pathSet(); + JSONArray quorumArrayRevised = new JSONArray(); + for(int i = 0; i < quorumArray.length(); i++){ + int credit = getCredits(quorumArray.getString(i), port); + FunctionsLogger.debug("Credit received from " + quorumArray.getString(i) + " is: " + credit); + JSONObject peerCredit = new JSONObject(); + peerCredit.put("did", quorumArray.getString(i)); + peerCredit.put("credit", credit); + quorumArrayRevised.put(peerCredit); + } + if(quorumArrayRevised.length() < quorumArray.length()) { + FunctionsLogger.debug("Could not collect all credits"); + return 401; + } + + int i =0; + JSONArray sortedQuorumArray = new JSONArray(); + while(quorumArrayRevised.length() > 0){ + JSONObject objectSelected = quorumArrayRevised.getJSONObject(i); + int creditSelected = quorumArrayRevised.getJSONObject(i).getInt("credit"); + + for(int j = i+1; j < quorumArrayRevised.length(); j++){ + if(creditSelected < quorumArrayRevised.getJSONObject(j).getInt("credit")){ + objectSelected = quorumArrayRevised.getJSONObject(j); + creditSelected = quorumArrayRevised.getJSONObject(j).getInt("credit"); + } + } + sortedQuorumArray.put(objectSelected); + for(int j = 0; j < quorumArrayRevised.length(); j++){ + if(quorumArrayRevised.getJSONObject(j).getString("did").equals(objectSelected.getString("did"))) + quorumArrayRevised.remove(j); + } + } + + int totalAlpha = 0; + for(int j = 0; j < 7; j++){ + totalAlpha+=sortedQuorumArray.getJSONObject(j).getInt("credit"); + } + FunctionsLogger.debug("7 alpha node credits sum up to: " + totalAlpha); + + if(totalAlpha < amount) { + FunctionsLogger.debug("7 alpha node credits not summing up to requested amount"); + return 402; } - return result; + JSONArray finalQuorumList = new JSONArray(); + for(int j = 0; j < sortedQuorumArray.length(); j++) + finalQuorumList.put(sortedQuorumArray.getJSONObject(j).getString("did")); + + writeToFile(DATA_PATH + "quorumlist.json", finalQuorumList.toString(), false); + + return 200; } - // public static String getPing(int port) { - // try { - // - // String didContent = readFile(DATA_PATH + "DID.json"); - // JSONArray didArray = new JSONArray(didContent); - // String myPeerID = didArray.getJSONObject(0).getString("peerid"); - // - // listen(myPeerID.concat("Ping"), port); - // ServerSocket ss = new ServerSocket(port); - // FunctionsLogger.info("Get Ping Listening on port " + port + " appname " + - // myPeerID.concat("Ping")); - // Socket socket = ss.accept(); - // BufferedReader input = new BufferedReader(new - // InputStreamReader(socket.getInputStream())); - // PrintStream output = new PrintStream(socket.getOutputStream()); - // FunctionsLogger.info("getPing- waiting response from server"); - // String peerID = input.readLine(); - // if (peerID != null && peerID.contains("Qm")) { - // FunctionsLogger.info("getPing - Received message from server"); - // output.println("Ping received"); - // FunctionsLogger.debug("Ping received from sender"); - // - // output.close(); - // input.close(); - // socket.close(); - // ss.close(); - // executeIPFSCommands(" ipfs p2p close -t /p2p/" + peerID); - // FunctionsLogger.info("If - Closing Sockets"); - // return "Ping received from sender and Pong sent"; - // } - // else{ - // output.close(); - // input.close(); - // socket.close(); - // ss.close(); - // FunctionsLogger.info("Else - Closing Sockets"); - // return "Ping received from sender but not PeerID"; - // } - // - // } catch (Exception e) { - // FunctionsLogger.error("Error in client side communication", e); - // return "Error in client side communication"; - // } - // } + public static int getCredits(String peerid, int port) throws IOException { + JSONObject creditObject = GetCredits.Contact(peerid, port); + int credit = 0; + if (creditObject.getString("status").contains("Success")) + credit = creditObject.getInt("message"); + + return credit; + } + +// public static String getPing(int port) { +// try { +// +// String didContent = readFile(DATA_PATH + "DID.json"); +// JSONArray didArray = new JSONArray(didContent); +// String myPeerID = didArray.getJSONObject(0).getString("peerid"); +// +// listen(myPeerID.concat("Ping"), port); +// ServerSocket ss = new ServerSocket(port); +// FunctionsLogger.info("Get Ping Listening on port " + port + " appname " + myPeerID.concat("Ping")); +// Socket socket = ss.accept(); +// BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream())); +// PrintStream output = new PrintStream(socket.getOutputStream()); +// FunctionsLogger.info("getPing- waiting response from server"); +// String peerID = input.readLine(); +// if (peerID != null && peerID.contains("Qm")) { +// FunctionsLogger.info("getPing - Received message from server"); +// output.println("Ping received"); +// FunctionsLogger.debug("Ping received from sender"); +// +// output.close(); +// input.close(); +// socket.close(); +// ss.close(); +// executeIPFSCommands(" ipfs p2p close -t /p2p/" + peerID); +// FunctionsLogger.info("If - Closing Sockets"); +// return "Ping received from sender and Pong sent"; +// } +// else{ +// output.close(); +// input.close(); +// socket.close(); +// ss.close(); +// FunctionsLogger.info("Else - Closing Sockets"); +// return "Ping received from sender but not PeerID"; +// } +// +// } catch (Exception e) { +// FunctionsLogger.error("Error in client side communication", e); +// return "Error in client side communication"; +// } +// } public static boolean bootstrapConnect(String peerid, IPFS ipfs) { - FunctionsLogger.info("bootstrapConnect- entering function"); +// FunctionsLogger.info("bootstrapConnect- entering function"); String bootNode; boolean bootstrapConnected = false; MultiAddress multiAddress = new MultiAddress("/ipfs/" + peerid); - FunctionsLogger.info("bootstrapConnect- multiaddress is " + multiAddress.toString()); +// FunctionsLogger.info("bootstrapConnect- multiaddress is " + multiAddress.toString()); String output = swarmConnectProcess(multiAddress); try { for (int i = 0; i < BOOTSTRAPS.length(); i++) { - FunctionsLogger.info("bootstrapConnect- Bootstrap length is " + BOOTSTRAPS.length()); +// FunctionsLogger.info("bootstrapConnect- Bootstrap length is " + BOOTSTRAPS.length()); if (!bootstrapConnected) { - FunctionsLogger.info("bootstrapConnect- Connecting to bootstrp " + i); +// FunctionsLogger.info("bootstrapConnect- Connecting to bootstrp " + i); bootNode = String.valueOf(BOOTSTRAPS.get(i)); bootNode = bootNode.substring(bootNode.length() - 46); - FunctionsLogger.info("bootstrapConnect- trying to connect with " + bootNode); +// FunctionsLogger.info("bootstrapConnect- trying to connect with " + bootNode); multiAddress = new MultiAddress("/ipfs/" + bootNode); output = swarmConnectProcess(multiAddress); FunctionsLogger.info("bootstrapConnect- connection status to " + bootNode + " is " + output); if (output.contains("success")) { - FunctionsLogger.info("bootstrapConnect- trying to swarm connect"); +// FunctionsLogger.info("bootstrapConnect- trying to swarm connect"); multiAddress = new MultiAddress("/ipfs/" + bootNode + "/p2p-circuit/ipfs/" + peerid); output = swarmConnectProcess(multiAddress); - FunctionsLogger.info("bootstrapConnect- Swarmconnect status is " + output); +// FunctionsLogger.info("bootstrapConnect- Swarmconnect status is " + output); if (!output.contains("success")) { IPFSNetworkLogger.debug("swarm attempt failed with " + peerid); } else { @@ -1600,15 +1648,11 @@ public static boolean bootstrapConnect(String peerid, IPFS ipfs) { } } catch (Exception e) { - FunctionsLogger.error("Error occured during IPFS Swarm connect with bootstrap", e); + FunctionsLogger.error("Error occurred during IPFS Swarm connect with bootstrap", e); } - if (bootstrapConnected) { - return true; - } else { - return false; - } + return bootstrapConnected; } @@ -1617,22 +1661,21 @@ public static boolean portCheckAndKill(int port) { boolean portStatus = false; try { - if (!getOsName().toLowerCase().contains("windows")) { + if (getOsName() != "Windows") { portStatus = releasePorts(port); } else { portStatusWindows(port); portStatus = portStatusWindows(port); } } catch (Exception e) { - FunctionsLogger.error("Error occured during port checking ", e); + FunctionsLogger.error("Error occurred during port checking ", e); } return portStatus; } /** - * This function will release the port in linux based machines if the port is - * already in use + * This function will release the port in linux based machines if the port is already in use */ public static boolean releasePorts(int port) { FunctionsLogger.info("releasePorts- "); @@ -1649,78 +1692,63 @@ public static boolean releasePorts(int port) { BufferedReader ipfsPidBr = new BufferedReader(new InputStreamReader(processId.getInputStream())); processStr = br.readLine(); - FunctionsLogger.info("releasePorts- Process string is " + processStr); +// FunctionsLogger.info("releasePorts- Process string is " + processStr); if (processStr != null) { - FunctionsLogger.info("releasePorts- Processstr is not null"); +// FunctionsLogger.info("releasePorts- Processstr is not null"); if (String.valueOf(currentPid) != processStr && ipfsPidBr.readLine() != processStr) { - FunctionsLogger.info("releasePorts- jar is running on " + currentPid + " and IPFS is occupied in " - + ipfsPidBr.readLine()); - FunctionsLogger.debug("Port " + port + " is in using, killing PID " + processStr); +// FunctionsLogger.info("releasePorts- jar is running on " + currentPid + " and IPFS is occupied in " + ipfsPidBr.readLine()); +// FunctionsLogger.debug("Port " + port + " is in using, killing PID " + processStr); processId = Runtime.getRuntime().exec("kill -9 " + processStr); - FunctionsLogger.info("releasePorts- killing " + processStr); +// FunctionsLogger.info("releasePorts- killing " + processStr); } } releasedPort = true; FunctionsLogger.info("releasePorts- status is " + releasedPort); processId.waitFor(); - FunctionsLogger.info("releasePorts- Waitng for process"); +// FunctionsLogger.info("releasePorts- Waitng for process"); processId.destroy(); - FunctionsLogger.info("releasePorts- destorying process after waiting"); +// FunctionsLogger.info("releasePorts- destorying process after waiting"); } catch (Exception e) { - FunctionsLogger.error("Exception Occured at releasePort", e); + FunctionsLogger.error("Exception Occurred at releasePort", e); e.printStackTrace(); } return releasedPort; } public static boolean portStatusWindows(int port) { - FunctionsLogger.info("Starting portStatusWindows"); +// FunctionsLogger.info("Starting portStatusWindows"); boolean releasedPort = false; - String portProcessStr; + String processStr; Process p; - ArrayList pidTree = new ArrayList(); - ArrayList portPidTree = new ArrayList(); try { Runtime rt = Runtime.getRuntime(); - Process getJarPid = rt.exec("cmd /c netstat -ano | findstr 1898"); - BufferedReader getJarPidBR = new BufferedReader(new InputStreamReader(getJarPid.getInputStream())); - String getJarPidline; - while ((getJarPidline = getJarPidBR.readLine()) != null) { - String[] getJarPidTree = getJarPidline.split("\\s+"); - int temp = Integer.parseInt(getJarPidTree[getJarPidTree.length - 1]); - pidTree.add(temp); - } - - FunctionsLogger.info("PIDs occupied by Rubix.jar are " + pidTree); - - Set pidSet = new LinkedHashSet(pidTree); - FunctionsLogger.info("Pid occupied by port 1898 is pidSet" + pidSet); - Process getPortPid = rt.exec("cmd /c netstat -ano | findstr " + port); - BufferedReader getPortPidBr = new BufferedReader(new InputStreamReader(getPortPid.getInputStream())); - String getPortPidLine; - while ((getPortPidLine = getPortPidBr.readLine()) != null) { - String[] getPortPidTree = getPortPidLine.split("\\s+"); - int temp = Integer.parseInt(getPortPidTree[getPortPidTree.length - 1]); - portPidTree.add(temp); - } - - Set pidToKill = new LinkedHashSet(portPidTree); - FunctionsLogger.info("Pid used by port " + port + "is " + pidToKill); - pidToKill.removeAll(pidSet); - pidToKill.remove(0); - FunctionsLogger.info("Pid using port " + port + " but not in 1898" + pidToKill); - if (pidToKill.size() > 0) { - System.out.println("Port " + port + " is occupied by PIDs" + pidToKill); + Process proc = rt.exec("cmd /c netstat -ano | findstr " + port); + FunctionsLogger.info("Checking port status"); + long currentPid = ProcessHandle.current().pid(); + BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream())); + processStr = stdInput.readLine(); +// FunctionsLogger.info("Process id found for port is " + processStr + " current jar pid is " + currentPid); + if (processStr != null && String.valueOf(currentPid) != processStr) { + int index = processStr.lastIndexOf(" "); + String sc = processStr.substring(index); + //System.out.println("Port "+port+" is locked by PID "+sc+". Kindly close this port and retry transcation"); + if (sc != String.valueOf(currentPid)) { + FunctionsLogger.debug("Port " + port + " is locked by PID " + sc); + } else { + FunctionsLogger.debug("Port " + port + " is locked by current jar with PID " + sc); + } } else { releasedPort = true; + FunctionsLogger.info("Port is unlocked"); } - } catch (Exception e) { - FunctionsLogger.error("Exception occured at portStatusWindows", e); + FunctionsLogger.error("Exception occurred at portStatusWindows", e); + e.printStackTrace(); } return releasedPort; - } + } + From 35266ed0ff7f738df07b6d6b058812e55eef31fa Mon Sep 17 00:00:00 2001 From: aparnaullas-rubix Date: Mon, 21 Mar 2022 01:00:33 +0300 Subject: [PATCH 34/49] If type 2 - Arrange quorumlist in order after checking credits --- src/com/rubix/TokenTransfer/TokenSender.java | 32 ++++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/src/com/rubix/TokenTransfer/TokenSender.java b/src/com/rubix/TokenTransfer/TokenSender.java index 7e1f47d5..d96a851e 100644 --- a/src/com/rubix/TokenTransfer/TokenSender.java +++ b/src/com/rubix/TokenTransfer/TokenSender.java @@ -345,6 +345,7 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception ArrayList betaPeersList; ArrayList gammaPeersList; + int arrangeCode = 0; JSONArray quorumArray; switch (type) { case 1: { @@ -362,6 +363,7 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception case 2: { quorumArray = new JSONArray(readFile(DATA_PATH + "quorumlist.json")); + arrangeCode = arrangeQuorum(quorumArray, port+15, requestedAmount); break; } case 3: { @@ -377,6 +379,29 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception } } + if(arrangeCode == 401){ + APIResponse.put("did", senderDidIpfsHash); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + String message = "Could not collect all(min. 21) credits"; + APIResponse.put("message", message); + TokenSenderLogger.warn(message); + return APIResponse; + } + else if(arrangeCode == 402){ + APIResponse.put("did", senderDidIpfsHash); + APIResponse.put("tid", "null"); + APIResponse.put("status", "Failed"); + String message = "7 alpha node credits not summing up to requested amount"; + APIResponse.put("message", message); + TokenSenderLogger.warn(message); + senderMutex = false; + return APIResponse; + } + else if(arrangeCode == 200){ + quorumArray = new JSONArray(readFile(DATA_PATH + "quorumlist.json")); + } + int alphaCheck = 0, betaCheck = 0, gammaCheck = 0; JSONArray sanityFailedQuorum = new JSONArray(); for(int i = 0; i < quorumArray.length(); i++){ @@ -401,6 +426,7 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception String message = "Quorum: ".concat(sanityFailedQuorum.toString()).concat(" "); APIResponse.put("message", message.concat(sanityMessage)); TokenSenderLogger.warn("Quorum: ".concat(message.concat(sanityMessage))); + senderMutex = false; return APIResponse; } @@ -426,7 +452,7 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception endTime = System.currentTimeMillis(); totalTime = endTime - startTime; - eventLogger.debug("Quorum Check " + totalTime); + eventLogger.debug("Quorum QuorumSendCredits " + totalTime); if (alphaPeersList.size() < minQuorum(alphaSize) || betaPeersList.size() < 5 || gammaPeersList.size() < 5) { updateQuorum(quorumArray, null, false, type); @@ -634,8 +660,8 @@ public static JSONObject Send(String data, IPFS ipfs, int port) throws Exception case "424": String invalidTokens = input.readLine(); JSONArray tokensArray = new JSONArray(invalidTokens); - TokenSenderLogger.info("Ownership Check Failed for " + tokensArray); - APIResponse.put("message", "Ownership Check Failed"); + TokenSenderLogger.info("Ownership QuorumSendCredits Failed for " + tokensArray); + APIResponse.put("message", "Ownership QuorumSendCredits Failed"); break; case "425": From c1ac46f2601977cfd0b2d0e9c88aa6c2f5a46a5b Mon Sep 17 00:00:00 2001 From: aparnaullas-rubix Date: Mon, 21 Mar 2022 01:14:33 +0300 Subject: [PATCH 35/49] Removed unused variable --- src/com/rubix/Ping/PingCheck.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/com/rubix/Ping/PingCheck.java b/src/com/rubix/Ping/PingCheck.java index c8f8ef1e..b106776d 100644 --- a/src/com/rubix/Ping/PingCheck.java +++ b/src/com/rubix/Ping/PingCheck.java @@ -16,8 +16,6 @@ public class PingCheck { private static final Logger PingSenderLogger = Logger.getLogger(PingCheck.class); public static IPFS ipfs = new IPFS("/ip4/127.0.0.1/tcp/" + IPFS_PORT); - public static BufferedReader serverInput; - public static JSONObject Ping(String peerID, int port) throws IOException, JSONException { repo(ipfs); From ef60ab4d2b6af5badd19b782fd55944c86a1c73f Mon Sep 17 00:00:00 2001 From: aparnaullas-rubix Date: Mon, 21 Mar 2022 01:17:58 +0300 Subject: [PATCH 36/49] Genesis information, Checking credits for type2, Ownership audit --- .../java_rubix_core_jar/java-rubix-core.jar | Bin 99163 -> 1533666 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/out/artifacts/java_rubix_core_jar/java-rubix-core.jar b/out/artifacts/java_rubix_core_jar/java-rubix-core.jar index 8c4a3edb3b4c53d3e0684c01f3b1d9800b73c6b7..87dfa4102abc51dda17129a01adaed0346d09d8b 100644 GIT binary patch literal 1533666 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
s6o*tUs>E*!kXqqrP5 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
l)}nBl(FZYP2x0B^731ax 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≤P|x>HKu!6}e$+ckVG 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 z z%MEj4`T0gDxP%Gpw~);=B$e~$=WbUO2A1mXNQtvmuQ~TF7IwJAHi3dLa{H)>o;k>JKO)6`WGyJompsyAaR3SD8k1QOhC_hr;k zh^sFw@0jwJB)UMP4O$~$5=w5Ga!#-r;5urLsH_;z<-TZD`Yl>yG7|PjAd)BQX2*)T zb|N^Qv{OO0mjyn`TQNK&E{yY_k9V{CxPR@L(!+CeN0X?M0s zuusXDHrdusKL{x?Q5?*FNo#-60@N$|6vaMW?h3a7d({r?#+UM)nwdQxzJIWpPm}UU zuYJxylDTlJY5(;1sWhTM0b!j1Rg)Ha{WEUmdN%(O=5OTJnhnJ;M_`>Q{a- zJ3m9@T+4ezi*{qVfb(_NafXAe@38lz^^jb0PipHLT(+lo5mUKG**E}jvmaUoQhC3G{Tq?)HV17TFR@%+FiS&c@p5-DQ4jH|>MYhjgF1j3D)rVJt#)mN zF-PVgO7F{}_#_M5>y%oXbL8>-Qa`AoRalMn?%-1{aYvc4gQ1t*YASh;XQ(hMNnDiA zx=5o>yae|VTm^82E5_~1 zn$G_Own!=dGUHf4fC(iK2BaoPYVZqd{?@>v0EGgVZmno?c?zh zsj?t&u|bQw?H!F4R}RnP`u6aai%Bqbtez@-VIiH#`0DP$+S@pbXJqPY;saEVtJ74J zO@v4-*pu;56u!Tcp3#6CK2MO2w9qv^vQeK9yp}hR|Msr=$>OAzcbEMzWEP zZKFyF*bs|E8EXZU23={?{z@&*I}8xsXH}$OS4xWkTR0)K)b?_zUwy@pwyBhi<7yW| z;#~tz>pLe@GTe8NvDdP|n9t!UlT9^iQ6L<5Fc*I#Y&vbqW)HGTrjQ|2_fOctv>YiM z;MYZt)h*6%VZ2hK|GS!KI5E5Y3`s+_J5uO$nhkm_cywirb&5N!oNeG8Xy-Z=$)Koh`w2l0#!l2GCtwyH@d>Wukv??dec8f_@ z!dM_(1ktETBYmkP*CP%&Loi0Ub`Yn*ot+r1>DtB=peUbyNRKm6?Z@OIF*pa6*;9v@ zz0Hw+SUHI9;H}dG?IJ%Y38gbg#W+dnf^tM0Agt5`l{8uA^qZ!Zy*Qy_n+3>KyCWA$ zX9!E^B4Rf^f=&3n$*{d*8>hW&o2Pxsioj>1)`l^zI)4a<3tO^B6ZRp*{7|ajazB5p zN^~A@uow|=Fp0P!I#h}l(Lqd*sv<^%%ECmaFDV&(iqrQS6mPpPNa9*zzQ~No;u4R6 zX^>H@rtNZ6N@+Y@FG0c`300>2r8mxof4GCD=6EyTJ042C0HJRYG&b5b6)+|pOiAiN z#kNXL`z^INU|x%QdV1hMYd*o5-UZXSv>y{Q%{4@MT-nu&>&$(1ChdfG=_Xk0EUd*U zFHv07MlocE(dtl|D17mn_bZOfHcyr6OVW?2Q?4DLS{P+-GOEC)un&?MTv!ea$+=0Fjn8i?wDiVv#hr`42~K$V>* zuQFZ#Sl_HwWw{G78q$`{64W)xb0N`5n}Kb4-ZZRpRAY%K*I6u{T0&%POn`$kv*mj{ zw(^n$$v08DH=i{0LR<4;=VQAyMeDK#V;6B_`}k4v1Pr`&L*aw#6?6>p9;W%+GW#F^ zoc6<*bo$w^+sI-Ejm!6eX7%}JzI#{jJ(1rKZ8lA#A$X4T`xf`ma0);BBCr22iGz*h z7Fh4sM540A)0DBjLgF+_7L+A7i8@2eg4^VpFwc)oSCM z6V{RCx--|M&Fx0dOGfk9m|++daGkCpVtCv%$u}F3evuRkXi-I24QK+ zpy3aPE{Zit()AtG(3Z=OE~H1exaM8roaSvE#7HG@cD#O>Nzg=F1t`0Sr7$;tGBb-v zxyI5}4+qs+z6_JI^$+Ed-R~FoC$jT6Q%p6MvpZq>0XgwEN#7$6Z3WgPvh-b8$D8TP z8~sN2+%~fccR?=kC}yZmK8t52!~~NCjN0y`b@ZCF_RJB3_0+aSQ^`Uj?W_64atY7x8)#tkS>=Bbk=u{2n&yG9vy)OdnLC?)|HOE5zf5k$~)->&1 zzqiDUVgK8$#dmf8VQNihYGY(ir*C6Q_mA>`SkBby|Ff^F@F6=Vhs+c0WUdMo0qGC4 zi+0Ky!vWgW2oK{MV2BV$II=4XNO%!D5qpY#)*TV+H(`E1#{;xK$s>_gv$hm9J+<3U zxnF&L-hH6?01}Xk-FwVVrZ$Qs0@UMFvw=7vZ3cHnrS)p$CtJQ5}4fV~9=l+HlllVUS!gOdzb|>_7 zO@Z=rS&aTN#jtn3qQqmx_C1OAbmXkuI<#`GYv~m7?6CdaN`!*pa^I{Td`&BT&O3cJ7W=6P&(k`7-_0^ny}u5tGo2fz@f<1As+N=-Ft6%QtR$?0}o~tlW zNyGU6(N_@|<{!xe|M;Q)9S`{5uhj7Wr$6WS9h!r^!*>?o-)9UJO;xP#GlonYV+#yP zA)6+=i8O-`Gjg#CNWb4eZVrBq+BK&*IC{!>|F;u-^XjRs^BLM>p&=p3i6+_nK+NQRQ|@Gzs!$e!aDRxH;K60AAhn^Xti zD$b0@NL2_U)uldUs%0PoDE;j_Q5VlhgbA$Lkj7&hgh!uo9IJ;Z>Bf&TPqm0BjWZo} zm{$OhYABHM@+vdX07p9(CKV`C=+q;#Wajd4LTBoZje<$euqgTnsLYP$lBx^)!@wzN zqf=vyqA5$p+Hnx^_7vC?j}-nzCl#Z!WV#=4nycs;9BM#cb#5D_w_mz;-@RnGh52YR zm|EJtOjJtronT@vq@ieIBtSU_U1bs6V^l8kK?#y{hU+4`Bv2kTwo{lN7L~o*=Rhyb zrx~0}$}tH?j?>;7U35WF*~pKxpE*IKd)L#T!&G;b+CjnGCUFkaMYP4!5U%GZ2^QX; z8L`Pnw9GFq=J@;nF!qi?lE2&bXR*t!tS;NOZQHhOSC?(uHo9!vw$asPd+K-3otgNb zx%b4p$cT){e320u-}UTg?a$up7JJNE)gntjF`=HFSTJxpG$1V1AdFt1xWi5|1&(sI zAWTKuV6}&bn{e4anLwNJ6>3d$-pN!6R2S+1TBbH69`y!O_vdv;7~4(CuNINcKsS-j z&?k|5qhGhpA|s<@V>IKZaVDro@IS8iiG70}fQ76+*l&TnNA0ao)Fg~s3K-KhQW_7B zfW0DVqvcX`NhnkctUJzylPc(jv83=DP4WaNQH`T@4dtdJR|zP>p?yNNbbNY>?Hbt8 zD^(9=M8{1jsOP$ME3%kaGWKJ@E>PuGb*daTet2|}D@}5`5}eyAu#;0a2-kLaXsJ25 zwy9(w3wQ^`zR2~GDLbL^C0A6~WPS=NOx$)3j%X9qYwRxB4>HW8=R_}oucpJtS94-6 zsU&mH!zF&fo>6rCZdtx9FOpyvT-Kn!AO2&p42gp(~XK(Olwkh4z!qGM^v7J_TD4*jggeFdj%AxoN(54m_ z&^BXAi%rT!%x~lgi&T=->0N^TC;Bm->u-WXz4lil2yXri4sa~A_$I;7e9p=m3cdQ# zzC8PAZmX8oB5_0)ZJ$9u*3a!||F1MH5-S7!bV;88?vGfLe?o1R`n}N^fzJyc1#GmD|9Ht{Ld-V&M zj2iwf<({O4MhzmeJh;{7_(-kxbIi^t(l9$yvdy#{7Ne7gsCdj<$B>+O#0!#)qGpTH zg~WxE`>NP0uf%)^ivg^G@I55~B`iYeuH61=DG9Pgz^l zJWAxQNv8fGG8w95Ci1z?pyVfMsuX&i+R%KoGAzc0=F1}|=R5m!X*-fqPucizL8@Er zJd@zZycyXRazgjD`oE)L7srhnWG5KqOs?}1>8_q@7>bfG&NWbrTI`L^TsTA!6)%rV z1bknN-5^?O4BW&j%uNFZzgUbNl=bD1OnV!mnrs;`a_T4j4fJfv=w`^rlk5^r*A-*- zn%81hOeg7u$u^if!?L_vF}V+myDBjs_qs{S@~$Nn$xR-utjh{9YYasDszOq)8~BZK z58P`;Bst976J^J3AP;UK2i~f(lRcEK{X-BO zq=gV}L0E_eKDI^x-bH&x|J+|JE|~luqlrcGext`ldTcN;4Vg=b@&075>sv1k6shXF zp-`>rt$`l5Zk$Jiw$`u>>q8Eya%Xi}m4ozRppIUn@V^xISQ4Iy33z|3N}#*0B-cCV z2qs$AEz*ud-dHx|uW>;umrT{>$SY7&m8-oN3TpRdHk48#IFyFOj?mUfwP;g}ji9?G z>A2S0go!y!!$oDU_q6>Cg;E=c9#UvB6QPqkyeN`Zui{&kZ=ftR1CJ4-jHtfCm?-^A zd0AI~M4eQ;%h5mp<|?)fq>+-8NUhYTz`JWyM_3I_xkA0q6*;KiQ?hCC&%}U~1M0 zo9d_a%lWY7{F}38xJ1 zi3Q+CKvEgfC~}WB7VKU2)a@=M?cHc!IJj1tlBU(9EvRbvgl8!>qbc z)rWbFv>(^M)gY|?65T|RU!4RDS`izf+@vHd1aWdlDRp~WK>-gR1q6tJyu~WMG5D>F zEC%p~rd@YMY2kGDJw2mwF<`SZ3a%+=_b>d*WkcaMb};tQLLd(91 zS&RQSUEW6NyC(LP)m{DDz@H%q&8&=NmHAWBQcIJCUrMR2N!~KCV6jD`AGtYXt97lZ ztnh09FVA-jf~(MAc)Be2eb>$rduB^V5Rzgbw9D;#QZnam^Q6t~>*eZ+4@i6DCv*q{ zl~7++fL1F_hzGcve4M>ne*g$nB;g4t)YIU80{W$td!9Z}BNBC_2T4Gvp{@%0X?zd@ z33rM-aZs++QiyCA4c|hJRa=Frs-wsV>!f7PESphU2$LAP1dfhuEs`L(Rbpgl3Y?PP z>gw9;MMATJ%U)H3s?LJ7koQ|(T%*k*l%&Bx0}oothuf zsWoNDY1Eu|23Op`_2l}=B!V|iQm)qE4|)*gsAhFEwbyAaTYV?bORLX!3HP@h_^+xj z>wZ<_tDNhsdtr^2<~mZH*I9igP&FPS5^iYvY}}EhA#cR6FMpPVDxK;2K3NYXJId+y_{tA-WzHxlS=q6`QmCZRj?K6bgaAEdgtYU`SHV>MIK(qgZyEGG=5qSRZq=ufxRxnhp0 zIB)lqzqU~vGJDQK6!$IN|6vO~Z--Q{wT?WEE94*jx46dYd7Yri=iu$RNiFMQWz)Qw z(_wSW_(g9uq%ief#|+P*38k#bMvD#%{E1PRvi)G&+I4T%-zjkat6<5py-lKZGjb|E zuGSd$ivRr@1YH0-NU7iFQ%&-nH^c#V=5~d!7Q$VX(JN2-kqu1uRt*RW7Xk^)9GYNU zpoA)ISABD0m?H~flg)p8MVkG<=+Y5hjWGQM;ExudVYi+o^Zv`efTBQ`eDSaKc6egRv#Js2s&u2G(VD6p#I%RN&LJF#_A zJyqKT6oFWJ?0pPktMsOePLwn818Ps6>5c6N6V0fGudgus>f|T5iHLlbv&EyERRd5s z8iV8$y}%O}vqTF=(b`$%rfmR+?m=3q1iFBQymQgv7kK>+- z9wtK0VAnZ2wIR(7H0Ze(dKBDm#D}_qdL`~A#J6IYI|&HW{(-3J#^|fpw3T;Iar znygFGgb%d4koaZw?OqKMoht{r?b@ z|A)K(*F8H~dFLNZ`J5&_Bb^|X7gW?#EaDp^mI@DkWkQ9aFt=805?Fk+NUSloS{<4y z0pPjc&VBV^m^IOLI*VF}na!5+KI1*tvg6!rX0ixJMESHn<#=7S?YvC8OqBgU>LvKzgn@P}eRpZrDWDMn_zr{hgXw2X|VaWnOK;$E{kt(t!Kg z@7YF!st@U?xA0u9kV>2G?p@GMU$FluIYL?l3ZjvXQaa#j@CaKvR4`j+*|GN4Wnl|6 zHnfRMv|7`v_qpT)q2qvC9-)FR5BpF|_B!@y?Cm~EE~dj;F0t!?C(GB=5$k`x;n(J@ z33w10v94DvxBgjc!g(HSn=rI#1Ai0&!tF)^qyHLYzF^JPkql!ZQX>X(<56W=%T=<2 zH10mrfnDlaKhs6L1ZbG*;`cvJuTyp6(jCxj4&D!hs96Bf7DEQ$kTFypkVu!6{b>yc z0Ps$q5s88hkt|WBu@O6#9K5{-{^&ptYH?bslN^4sDFN`#T7y_{n4Z14# z5N22}oVFiL$i*K`9KS}A!$*D@FW+3K3YhL(`Y^WyehFfv68KU>|6l;y2XP30&Mj)l z9)z5s*rvJb>aR@kgB{1>6Yv=10=LLPfxPLAr3Ypp%-Yv!KmT^kfaj6RHvbA<1Knx< zDnIcHGQ4&Vn3Y9%0Q2%E^fC8DkQrgu+Po=91ZlEEOyMpOQe%4IF}i~4-`Vr#WwJ6h z?GZ_cPFyv6yJW51;L@YIxBo)Gpd&sgM%r`7+-Ls9e3oYH6|v9w3HC-ldVoDGMY_<6 z&w{)xlD;y*I5Nvb?z|@_N+`Xb{A&%Z2W@gbMBMpjd}x@Opa1LGqLHwl5Am%qDrlAi zUm|fq(lAgoe<`Y>bH#}8NoV7z1nF50sl~Awn6xrEo3iwfyH_}ctA+I)r~pwan=e0c zrxCXZVNYaQ-+`B~AlIC+Qq@qeKkGmhjX5l(3BBaO`?UrmsK`5HD+(@75C3jXZY+_4&#CU5$4G$$l@A~B;* zVGe`SRH4|-5z^hP-&esil2G#7?Is|5C>5ODrlp^{Ge5BwzRKK}S(g~YjS*ad?jL=W z*HLcO|NgmV->?7OcqI7#^#9|E|6`5+i{<~9B3A!H3oijaXN(h`Om7AIA^j0kfQ`h( z`|AQFfS{1WgMNX@3lF7^Nue`lGT9-T)414dozq@&(YVf4@DB!8Y|Yv(FJHcOuP)I> z%sX9qH5!{T3SW$*dYo)~U21%KO}Cvm9&VN9g3`yTw$;JAwarC$05%JEb=k67H-g{n zd-8DQZ}QN&i}np}e1xShU6>vu0J+G4K9smFg^;Km_0UwnN*pw znh2ZKa3au?+xB|B2%Cq+!nV1LJY!d8;SXoa*@lZ=KP;F}wtwrIVlIzB9&dn=6ISKL zl1#RId?<-9I-BspAK_V8;fJ(E01BE%m5l(;=G8f?k-t43oeI2*of-4lei}7Nb>>D2 zy`M%)`5T1lxxyIf!6VHN!y)({Bo@$kd+ojrFg3S4zN*Y{bQn&O4G{{8jj84QVXS)p zytyHE&v48Dtc@h|G6wvw1e$Y3rT1%^bsr`A??7H3=evVz%!^Vh9}IjCE)hg4%~ z322vR`0z$!?-G@mMn{ZNphd7y5(Lwe5W?Nnb4VSSPRD;Lg6U@px&NB=3yp|>gmp4}nkvjB>LO^6)Qo~o{OZ8W31WR&I#x8abaI}FH?vWS}1R5RmdXT4^ z+1Z8Gcp(#nnVFl&!pC=VW9U%D#Bz%in(Ra}(jwY8R%`$>rC?qodS_3Sznnr`8@p$M zB-?;7^udVCJC}pnV8ctZn@~9?h{PN@OBGNcSeOVtt>oByBs;*&7>CnBfX(zC|7nkJ zd+(X}Q=pLzr`NmmP-UjxN^2ID)}L%0x>HqfI*DY%N=>|Wj3*9JGld(k{*Muo6pdLW zj512JW?8b4=+%V{@~Puqbg;E#G?r=NQg3nuKm5~rp@oF4-DE31(ys0lm1UC}CQ;;_ z^5p_?U>3q)VpLZrJuL-mmsXU!iM7qAv99zcM5+xW1UkQvaBW{&5?tFkQ|IJD7yQ`u zVGBP`GmD)l^(hxM6@x_`veB*sd$iBtYC#4RJjiy-1*!=Je(y?SyU2Fm!A!cV+wnj|| z?1`k`Hy*s(HPc*T`@GHbrAUa7=jRdtmA-T9ugdiNE#!(2U#PP7eJ~O*sDUHziBc9# zLva#le^t9+mWNS&kX15n)WnlJ?JqO4snU7D-PM%jPY-!K+RT$M>zrJ&Oqh}22hIIM z+XG$C&jRMx^j9%d2#x%VOEe8{J!)j+`b<{06#5ohYucFMoTQvp9tGGKHHkZsF|}(vglE~>8^h7vx~_haBMe*8Iz8Mg8|btC^1RV4R|;W zJD!Lj8p}Wn+`J+b7Y&`sI95uA?UsVtn-lMu?HKvH-D)Cg? znSplbTiul31&kk{>`y@}czX_)$+sMuHf*#UV0 zvs!84bxpqz1(XGS{lS<_11;#&NVxq5ofHRr7q|T-XPhI+xq{kda$Z5xZr&k4GlnSO zF!bG6BRb;U)F#;NHXl=)bJJ`dYDrKTtR#QYf>k;=8^TiQ(7DK}qV}aKrs3?Ag znqxiA{Sx+t^71Q=?u4u$qBxAjpC(T%8pL2n-=evNji`%_)y(o|I)IHCWwIY-A{Uz* zbgN_VfNXSx?=$A~zmN|98`d~V_{j>jXr0F+gJ#Wy(HwYPZF@htKlfK)lA=F78iL`e zUKu1BIg=v5GNK@cHqO_B#-GA2!=AvkZr;+p4yD80Y@N72RI%iKwZxrCCOy?;9Pz?7 zz9C8fVuOjdmjD##s60aHE9Bi}r^br%1U@=tmb}*Dv#im)4RgqLP z?2XGLtqun$S`#(b;usp7KZX~K9h=MrWk=}8z4^P2!I3C_d?mXFBkmj=D#kJtS>|hI zj(`QV15B8zf-zWU3b|A*avG~9f{ZLE1uU=Sv>#*~U7ImDMo(FGCbb43dK-G4z&i1lukHEjDfgR zwa1!t8k8rNvV?zmzps#d7QHlBx7glRABr;`>iC0kWW<y6HNfdBXjJqtjaAxb0eVWa5ro$Q>V@s~g8+WH(3za*bxI*=1gGOsRWr5;&>F<~=b z??oioBC}|c{$uhw^E;}2e8LrOU^V4&o5$<24Pngh^W!f9&=mo?0GeGT`bZXt5&9h^ z+V%IAxNQ}Sw+~d&8-bL(NDA+uVrq0W74Ha>?~!@$lHFx`RYmawC-4?P6(ezA$kE9$ zMuW)&OO@&toBIT#Dw`Um$huAwHkG`GDl}u?^zXEfi8!CXoMn0uI-vJ44@WC9_yg`x9wxJva{kI6AkdCghi>|svfmn2qQWGp8tp9obe*KV zQIe!RlUj@3!o-sLs`3X+f;(c30sZ(vV3hZFVUn9jp1#}wFE*T=pxUmb`5y1Ul2Ypt zxBXMF0z969C$4+8lq98Fg@+|YUcGpVj$4n6$@{rA24TQ-p>rk|%Qtxl-!KEzeY(3m zkn-%8nH?86bL{0Nwb@LiieDywR`Wx#gvDUqOB>k5>X@%satb?Y0DyVy@JeTx9_1Z5 zM=ARymY7y>K4DBlAd1INGsz1~g^mA6rNPiCxI%33YsWsmCJ_ghxKsc=Zg=_x_I<~JNTnH9N9>NSEAKM^p4@2}9Q5l0~alsNn6One<9)~Di_F%X8 zoc{>=07}F)st2}yOdi`P?~)VKJd@~~ntk$Or+{j}CC6lt_6lPKc0c)s$n9uWL-2{X z*>}Sv(cs|TXEFIlU~s^yN*pvC?mmqs1GJU$_$bK`&=d*8;gP$ znXxqHX~4+(YiJsn`nI#n&O=SjZb|@aIZo~G!GL&{Og2#J4^)|!opee{{GMq{sBvUh zGI#|ywR-1C`@1&`>9S45p)2u=+X%gar7u~OYIxsW>X+_H6LT=vRuLV(t%F+Z z@7_PiU8R%Sq=IDRxetAhwjMPlKe1O-HG-v11V3E3yA!ed}T z+{n(z^t)-a@T3{wh8k^_>|qv4y1a)MqdXQCxf;~3Xy?kb@2RC$l(l-hX@S5upL2OM zyrhpgy&85gpmzd-Db_=DMSgR^c-(|F|8Z}Z;&M?F(^=2^W{gl9s~=QcmNcuY?y`ZF zr#-4*)GOA~+v-3*O!&6U%9j7^YIYv@r@E+8Bx{6>GdQXD#%urdh+02JcgSq1a&D}{ z&EY)n)`ki49PXS-Be5L$&fK#W$zFC>OzZ^5-H%{&-37(~Et{=6dKwInotlm_=qHTq z)1G~9W*NRJDm^pNb;c@;AWQ3V*B-{IGhw$ckFJ&MN}wx@PCb%C%88nAR~jZCwzQPZ zBRznwffmnZmPw6>)-Y3X8>8mJdc9VKwp%#JMwK0N|9KVON_ybq9oO%Y@hLwn_N+ck z)=HqSqa!TrJs!LgE}bdl56c>&(p!Qip_lytAZon9o-wLG%1P)&6>-U$+?!MAxnaxp z)?xkRHPxt4xLm!-OcaJesnN)`(oRG8&ePIdWp zrXP2WVatlW^uU6gy`RgLyHHcq`={yPaWNj6%8e5}s#aC7QD@vYSmU=*7aV^nsErg= z>IXs{o%qo!OH+V;0~^HgE-cC*VkV^6)CpgEr{pD-ho`_ zeSUVy5Q_3;OvS$cAn?Pg*E^*N*>b)j!hv-7n}4%hf%a&Kw;Riz!QTV>m}s5)Wk)ou zhPYgdIDZ4Uf8YGIbZ#`JQVm2UrG_xYEv{Arr)mdNb;wg60$Rl}=yL_ZzI=7s;f`g< z=>Ri^)NU(a3EWL9=!s9v^NU+l9GArj2m+Legb}6GjMTD(k3KQw%r&pN>!Q1>Yw01s zOIklR7JiN#O_O$(C1Rjxh6WD-lJt&;7q=Jp#7@~sn$e;=yx z@Wdy$Bf$JQ6PB0zc!}q$KZ0)_o>iBB5odh$S-2J>V-PW+ys1I|1$YMm^}GvO;%r#@ z*om~zoJ{9CvdSj4^Jk83p6huKn18|C*~6+>`w6;07k@e74qp3Oh>V)_3I30q3wirk z2Yr(S%!vQV*#2K?K6|@=iMfs9hU5T0A`gm{kbX1G zN~c^xLh+^%6?F)Luh;LEF*8D(hM}0y0>(lb!C<(b`dE50 zQystPfC>Ph3bK{~ud&nqMKR;maY0-+k=fM~ekqN-Pam^+8JS)cy9k;u@w?LWj z_Os}gbj03*yn?m&s#}F`Y#Hh9t5nhT14+&`;3h`Tw8>!Tg%DjuYbTE~#1?nWh<=_R z9BJD-Y(pP|s(gnWhwsF9*%^39wqMg(L{Q85LKP!L*ATx>v`^r6xM)NN^#T3oALXn; zxC;MXITZWNN&oMyihpNA{vGTSws8DExV~s*8Kr-4emWZotqT4ZMFlA6RW#y&XN?e< zISfU(CPya|;an_{>zN9iEd; zuf+G4w}YR*L{JyR^Wy}OnJ6d!w5AVgV>+Z+Z1#7?faA2dP%{qNbW@=>9N~N>WTLg4 zn+~}Z>(DV0S8mK#wDp^wBHYR7X_{(y@|q|CG+NqroXa==iqj<*8;uXAnB9gjuZS0j zRs~$$%1EK6mbaTptk3J2rj5HuxkVhYjhc^@$1Cb-tQ%Ihbx>@QMM!J7Rcx;B)+o;) zp+B`0kHqQ5Un-@tVfLGhR;@SNOQAh+3$$%o;F4(t8@nF14(cArn;u!;nf(^bzVOz0 zu5>Lt3&jYT)8;M8UvCD}kl^!F0l?{THkTg22g(*(^+AfkTY;QC=p(e0710By|_ zpku_y8t@3YNjXuOKz6ZJ@xF{K%%Pu5YPI3&78s##wGm(99)K~ArWs*rRp7d3$UnV0 zYt8KgjPJ^nue*kr?zarzymT+=Pp-Jb+I?cZyr+rMCxEMc;@}P2Ul_ zsuo~~4n2N=s;A^Fv}hOp2PXuIp`S5omk_Zk2^&ULQhtC$vn9?~P!Pr_NM|^Cw3qNZ z-r_7bjBkPze)f)QwYbSEVDgQh&R9~+Q|&AQg;6$DUG=dcM9v0Qb1;wK=O8yN z*ho<>!;nJJze-q}l$6%d@2BJNTlfC=CxrgrO4$F2p88iflC*`b)xU%=T6x29Lm5>^ zETvFgA(^}zC#a8rt4P&wd=xcGzZ?+V<_1JsLhAJ_ zhIpIIZu#W34D0}>7^w`wK_BkK3HC+T^17AXS!|E*IyilFML2T_viLp)=z@cAZdQ2d zO;otqO;-5HO~B?fdaL=a2ui5E1nCrJD>adBLMjL79f(gpP8DZ2redvQO&Umm8~?Zkv^SngMk*m>bJ7`5!ycHx1fnCOUl~;T zgTq9+5A`MlBiEq2F9~7*U?$Y_6(Cv(?CkcpEMfbvSI958-IEj!(J)s*lGvA-E3URo5l2Vl#;yJi9;&7g4 zF>pctooe4%H|Bu2uW{~GkWeg5LJ!x216?UBaX%i;>U1*ZoBS=hYd6ZEfU-VwqRa!w z%$vCNvjpDE-rp{W*&M>pVoj?X;9L{R(0@+u7CHM2KDp@=rv2$<{?xi~jb1Bp42(yA zAVhqP6l2eZDPjaWvdA^8T$Uw?2kv5JXv?HK*$z{$(PZ_N9QLXoy3R5r9 zRrdz^dY8y0Zf%fv%LL!0(28)r;w20;y^HN&BsrkL2#Pn*OD4XjwC@*^_?*Sig7E-e zx+|sXA!diqe@;(F*huqT4}nJf5D&lRCqOy7oTljTj~n_c+WjgkL4oFv zWGcP*3#&g}QX|btm*HWia%};K!4Q!qN+wk&9T2tJhM-7Sng_zP1+C@UW^;26@@=2uGq_A&elrfk} zPJdn&J%paxr&aeJ`1OZR!nTViF>(QBiQDVvm$=v~$=gZp6(5j3&L-oki9MwB_*T%7 zMv^0+q3tx$m^UdTqOAU?1#WiEQp|L-Rp`lsZ5HGO6w+P!;YJmYKzdMb8S914*sU@& z?u+D=<$1z|xX=|TeVz*?*p`YUf-pXZls@d7TlV%o-ZIm|jMShnfE=TQkX=v#`Fs`b!v(GGK?#r;z{ z5&4q1j36lE`VxPwbrllXk6v}HFAtWQ7AH0=D*?srtK3Bbmr#GiH^KZ3NQ`7A2;`Tt zU6GH)y|Gzk)`mTE!tu@GQ933`=>2qt{5F3_$8c3>kHm1#r=!h{2K0%ATTsu3>H@em&qO5qkk9rwx~~Obm7Mg{tPB} zD6`$Q%%Ro~I(#)aU142DcMOjqeV0$JU|%Rvy zUuE3RLchl{^ofTm`^=qS&iRiX{%!hal3S`kJ)$0lXPR5Cz#Sq#`scz=B)@s1*Z*4O zNoO?J6Z3t(E&Rvx?cam`B$ec3E?Kp%XD0%e}re!o{}zPTaj4)~QFhjRKJ_WAAiDBl?&=#I!K z-|cYvRvf?~c)Kr0=ayg1sNC_{cAgDuRlGGrcsvKkxN)bI8LtNERczO8KL5tLYQM?h zJoR&V9}cuwe*I=TBcHaOv$616Z@kz(cZczo`g4`<%$D9oSiVk%q1ZkvE+3mQzhoR< zzo@B)YPr>e5mfHtV-h)emmMS-K8Rs*_nlMtg;_A#+1Y6@-69ugXdjkb?$7pBtz{E` z8@CS?N~J(V8=f+b6Rjl_o;tcP@Q znYFS`U#J^5w>;F*SZEU|(!OLt1W92a7bMN7i3L`ux$ob6A>)s$g;*$t(@KvF1p&Ir zOY|W?k;qEXW}2>5-2pAh>sBf<7LB}5XW{_fv7tsewps6vkJ-|W6Tf}=IMm@O-oU`1 zjT#Pf&(DtCW@v(PHM`Y8gbw#xqZH8`!!Pze;qzy0(Rx z89ukN168vvOmjI&DFr%7^beyh16S{F^u=P2@f^XagsLCgwM|CuHry;f;vvhFggetWtJYTnKAd%mOm$6*BB!L}{M4W`bVf zn}tmUZ&E+XjWwi*Ve|MH`79gV@h;5$K689r z2Au?4`Vtl#$CzgNVC?J$Wjy#nLv4&)#-DJmK@xgPs8Mbr>uqI~_QIsbIMVIW67BA4 zT6JW&5oL(`Vb)tE6G1aAtwlB`gRAEnJAeoXBT9DPZn&KAfO>N*a2S``KhcA23`~2Z z7qFkoPG85!& zf0M=Q37CqMQyGQEi~Hjw%M0)=dS^{a2u{YSMHsbGIYP3?mMrbN_2)5OL+sgCF(8@3 z2Ls2tCgq51=uvIeEDYuofNGa6W5wQ0A+IaXUpl6gcM%3X(%T&UEiKdX-WSSy&wjv< za_edxlL_Ns+QMxHWx|yMj&*YxnR?m|ufl}g;)uSeRI3+fO?&*>6?=oBplsYOw{flY zFvDCJ7BO3q^wV_U&&oLyB4mI>D;%v!f#Nx!28Nm^U9@NCr4ap14>sn3iV z{z~fsQ4HLInognxRpJQrBPizUsz3rsMG6SmYimy93i#n zL^6w}mK7yW%`$IJ^1!5?7!~n@%i=-C-(4$JQvQVmjtHkCUm)JnO0`x;`qJW@>?8p^ znkG_3ID!V+C4^ksw93tD68^zR3Ul7<2^GcSGzNkzInQ>Xg}q3u2qv_%zFTRi8Gu82 zqCCu+=mAAVPliP#86urny(Bl`hH<6ZK%JaPn8P;6j3(kawP~FU6t1A@8oBshpzMmq zfzb}a!$bXZp>#Fgv*7@N4K1Ze;UN8}GoeXRmI@c8f@pS|*P121nziEPK90lF^B^}< zg|~9runK`8SuPJar%RUnDSY&|B9zXM{E#PNB;~dkeJOLep45^%JHglxsApggxQ{vPw5W+?*VQD!Zy&t zQMydBL;TnPnO^g(K!&vGc+NGsb?z9hS&24x_;y4_I)wX$K>&yvZ1^{E4s#1;rBFDIYHZYw5>RoOfa^; zca4<`&>P8Xke#bsWEDF(DE2Kz$wy1IrC(FDF*-O>$C6Pb&3>ciPb*Y&RAg)Zt}N4h zItzwyuqlt7=d9S`b+fhS<9?^+{l&m*xk&Lryjby@x9Y$-{kNtA5Q=xFa8BX6iY6;$ z?0P$bQ;^yoDg`A1{>n+y6W5!(J`O`zl@ByYZg+kPxyj{R@zwp3NH7GdfrY{zP!wht zKi*)Ofbr8xs|uSNV&O%N8=}!FPe3P}*zU$P>agbs9Da{E5cu}ZU)1X;?<+7?P;zf* zks0~Q*nPwt;=`SxC;OxwvukACJj`5_JCl>?(b%lWurOZd@L-f z&JthmgW7=4dL}Z|p4yG}4Q2O&-#%wMEoR2Fd!nt;pBdx&OlY_$dgGA{cT0@4U7sBq z<(MMcK{VU|IFIUdUfM>pfSswLjB;8UVA3-C zFSb@B⁡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

|}ju)JaZRrhI=r=mN70&DVUr1u}f_3UM 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®P{$G5( zQ;;lCyRO@|ZQHhO+qUhVvu)e9?b)_%+cr-B`>eBX&RVOYF7jq%RMd#f@qT)rX}R{r zUezyn-J;-4pB+|8mfC5(05+--x0@9H;bzBSl`xvjh}zu_m3QMyO~Fs3=h*S7I^YXK z<8THygH){nzMO0QzNb_M45RjZ%eyT(H2i`{lkB6k95_yc3{lV=(kv zeg&S>cbp z8ORBd(>1 zB!#e<*%O>cbwTt`B^uSV>N|yG(}NMR+}rD5mh@p+h8=l@8HGwzA1eGCpOR@S0@5`o zlza59liAq=>kbdPKJpLfKVs~|K`9{WH+I1OLp)jNtZt=-@_3*(v*yWh@HaM2_Jfx^L7XYMD{UPyy1X zdI*TM(Z5*Kw%_b+9Bf~#fc__nYe5nSlAx0D*Ss#oHDsKBXH?-^&HZe(KXES&Ul+zv zx*blEQq7zPT|8{Ac3vMu2AVjtV3cHLbmS$c7q9;wXH6t+Gf0q)*-{|GP5|yfBdx#n zu<#K5MIX^}X(z6NpNPxspqA593)%*;TlNkvKH0&{vtQQyTss90y7e$@o(Os`X`lQ* z+vwj2FlzJLr)vAFSN`WPkm7#}167<1?VQc*ooxSW2UTb6vD6X1@o4IHo4d(|n{hYS z<)rQsg4i4r$c6_o>V$=4tdL8?4_2XR_;tGCOv{O$RLWa(ysGAfu|)6lQ`?g37S(u< zXN^C8Sh8EC!>Ngzg}m&0UXC-_cP0V;{X9L`1MrEAg)-_q>~W#JB0U()fde|i**REC ziUizD5G4>P5zXUNhiM$qvA-oCI!;6a*g3}?P2j>W^NcdWkSK@y7?~62YRoXdHhQ0* zST)t0C!dB`E&9|V zoT+e`dc!?yaIZaL0Z%Zr8MAhq4P$2QwabDLu2ERR46J3;R5!msXT+;RyGENYQ&c?3 zE|ocM@}f*yRS!9^Z7@(NHkYGSYBg<_P2PxBYIT=mR$FWl&=?yH3% zL**uMt;q9MGPYTHHQFl01iPghegn>o*l~0wFq|SfpIyD|L zXYs$eunXiSm66d=_4MhNDm1mo1PVr>UTpQhv0>R3mQ^o$h=zCt(BEnxnK4}Sbp*j4 zl5PSAV_*DmxOdaxi%OspYm4C>tZ{?F;f&JSYHXgU|=AJgb zkys6uswV2{p2Dn8r#rRPC14(>E~FBLt>rg!WS)N_ZcK(0s{0$0|t}6)IVOcS$G+3pnBy z<-{S!sy%{@Zgv9Bi0#bY1WT^sLA-6%b{>E5U~+2I`jGfLA1(wva7R#ysHKe5oafXd zybLLw$d!p-<&)S4`WxcM&L`p%hn_)Xu^dj07O(5=Az#nMBnNT9H4ye$IitTJJlcXOCewbYVQHH=d-xzmIaBk#kr0f)y~nv&+C zfi;Dw<}t)!ID;XBmTu|}`ICp#%?6>=vfHZo?e71ed9lpqnuLDiC!7DZEAW3cQBZZU zwE1P%nE$eQWlY^nZT{caQ?jbIjfyIYZs|h@GmKkX6R1{S1k_cNTU}BC+8kdA1H-0J z>4Fko|J5T?_Y)KFLmA=SOj??SgiMqe|K~itK5&{4$$Pnk(W5Z3EK8pVGCu$3SgK<- zv%3RD@b1XgM-}hKW%tVVNml#&OldCgYJd-fZ5o6T?YxqV6eH=7AZ1B02g%SL!caUw zOb9}MqY@6Z(}|-cn{b+-*Z^9&IqRdrEoqa>x~=?!Gol<61^G z)3%Z+L_q&$fWI{+J#o?LrIV9csLuCmJ#VX7M_EMi8XYFwV?J!wCk>L;eNJE?Kz6}E z+d+(6!yHTRVWw(;xfLPLR){*6bn48}3(6T?cyKm%|jT;%Pp9Q@Xh zEM!+%rb+VC8o`jx!}+4}$ILbrW6MaLV)mBPbWHKY(nj1#W*ldJ+CH4=%%bxVxpW)Q zCB{cmB#PtYm6@fQ3*8GhpZdR6aoGYM%Up&j*$J6-)x`BON$V*kRjODnSzm8Pb7bnK zWUAeTjpJ35H1$QgG;=E#3eYSoUrZVlY37@`o!oZz!@5k+C77CK6WMN?q)DwD8oSXN z-sbSO;=_*c!KK1@e-xE$O{YR1JAz$osptVuRz0C~{CfRhi5_8sRdm1^caB`DzvlX+aFoZ5L3HNQsZ9h{ z@~W)-(CMC9`l{KkaRJcd)DiPaum~8Ht`^D2fvTLs{ONbCXGdB>FC0s7&XVxvDG z*cC(Ufjn~8vcIHM9n*uY>dPFKn6H2%rVH2os3@bIeu@U!to`X_PwGj>4dQTnxm zYEG2p`eKfij_){3+4*YgA0+{;ZeM?z;Z(5bDm)uh$&Vycm4TOb)x8lN^S0`>*sH-k@4?6fI(0IARr(B9u+>7{_ld{i~m+W{+~5cB0|D~ z4i2Vv|CewYt!`U})`yuZ#UE+9@n`Qb&Ppbu0o+`gQT z*r=gqC-t9BMzle5$5{NA@$t4QnbA37A-E3*6%_e*M}35s181hUt}+jS(cdyq5Iw|O z0lYraH$C)Q1pbK0M_XL&IMk63?VrZGI+-3i{T+zi%-0n7o#z8?KA)A)o44CAAqFe6 zDL-c8t5rO;GFbR@@2TgY^r+?+vxPg8D&andSd*$Ip{d13Am+riR4H*(pm-G~OVNfq z6(z$OT4HC>g6;)fG)A4XsSHi)RVlNvgU|PrX1bMT}!JTjlPZa2qimLj+`bhr-3iE zccMmq!!g*gjJ8#o5z}iLuf{;f2wfz(V&kjhFigy*b>#BZ@%-m}3;!bDi<0PUY%#Ga zlSL_Hao5T5kW#=rIia#?lv?l1cb2rjL72oM$`cA4-De`A>G2-k9H^0Vhq~UDd2og_ ztq`;z1(}u87@v7~uatPbTn>9j!{GUJ>=wLd>J*hb2 zMoq!kxg3v61v_kjE88OVLbp33P8>bVc6KO{+`HDY@uTN;~Y-l9V>=)2%vx=H)9oEn@ z6X+$Hb`7c&iZmL32?Y~Pl|_%TXRq42sBmEDNhtXF1QIsBH}yYk3`$-P}5cVi0>^ z&CW5aSY7EFv+1|Y62zo8V(L>h^pEAwmN|ElCt;--Td3zY6R^Ab^3u=bimPjaLPRLH zNEy1alGC}O_;b#Z@PtD#Q%J7g%$PC|Zkb(9Y666DnTxGgSR{|M>VzhKMsnz0KtT(`bZfKry0i1>*j$JOY_YRiJRWqBPm zI-`pLVea5XejQ-)t(5jYK3FXaDX$wRac4ZTgqO+8oN+7OM3J~-RVhyk@BCHP z*0662lMO8HU#O*&=mF%4r6>Ua1eTnD+{EBKEae~1mgHdKUVi$h1E4Z!5T||}W zLa+BGGntEXQr#GWv!_J|M4;7ZES(sx!8!oTZ5w{M5myUCe62w2us2#BQeM@gj=(8(jZ2fIhkNo&sz8M#ojTOiLcz-}*aPdH0R*Jn!c z03ThU!ti}*$8>8Z?dA6r$jNODd+y3)&*Xh82eVb)6mI<%T)r20&7FA=Vkf;WkJ9wEY7(^FlxK!g^T}IZc*3C*WNX z)RJ^1M;;33jGT0<5>P3ou9!z1@|)yEbj>p69C5ACep1j8cE2EzQ#`e_P9H2cU0rj7 zNw!VokR@E?`a3LKrhh=Im3iaq5M|Vr7K$JmJX;}-JxleC4}!OMshHytMSy4C%hT5= zUjQg?h`1v(am&J)GYB=U?%0Dia|#{w8&Y3`E)$Nc>>|gY)urJSGy(&|@WO++N>Q-H z->)5NoYO=HGBT@~28W$+6 z7&c;smR3QXR$$dAHtRgr6#5~JpJ!0-#N=QCm1|aP(Ye8*s&Py(1o|!9-ZK=I>FyD< z+!+V=3v(1|8y%za=C?p*QSwwLh=$J27sl7xP`AdPxSQ49bufpl=cB_%I%sC}YI0vW zE@2q57?Um(OUC+gxq3aWj*#3qch|@7fiL}`a)ly(Rbi!#L-mQP9Q=-V3nNIyPHix?DJ` zSVb0-R{0Q6TvO^Mz40!NV&X*fm!-)hKpNCPC24Xam6&%?K`F*^PtP2ZV(84jQ9+i&|eY0$oL@5HU$63LFwP1lZ9g zY1&3wd-9jGj*)hgwzEsyHx%jH^1AWN_{Q*$Ooq- zF>@ac5#`1_hC_!qj)ofbe57!EwO~rI9l&xC2h2flPCyPA>)*T3^>6n$v!3>|W*FHkU!04edYe(Bohe$CwF@NEg z$&Q)<^evS6W=vmJN{O?J+y!__#E?s2;$YQHc7yB^WfK->!dhDW(a&cVB;{CEI?`4l zsAm`RD#o*XH!vkLMxF zxunisnOsSAR}6(#MxhzYL+*YH#;_NdkokJdxUprFtXx&1NM=4)5+)>^SZ6rn8kVe9 zwtPlqlDt;fV$sg~8B6I>mSQr}+Hf98(*dWzGqmn&98W6J z+8yt~la{WO`+ieN<$QusuEmVqaD;726<_8g*|i^!bqKr6?vpGJmpHBb&Gx&4#;c~ zgRBHTI%97Hbm>~Y1_9Zmxqc{2^Tx!i9ZSn&dcOi=)1hl08P%vjTzZ$aj!b7Yx(3lx z1T6(bzqIqJ&6xp(q^*HDV{4F{%14uAvM^gvw2h?8kh3oCX;7-8Ivqv}@$kx2u7k`p z^-=C?WuQE81>G4g3b@(rgz5>EWUFJ!d?;>bO=c%jZqn?Zr@Zw>`n@3;*TP+ufiog4 zCGBqa$Cu&~gUkef(Oa|)5uwc&--C;nqPrF| z$}Qu;{axv6dVu1m&M-a7r;^Vnls)w;>$Va?;Ar4H+U`m)&@gd}(y%?sC)z(_WJgrT zy~UfPOI)Dg-=Wn3KS%M~Mr2*4@4Vh#d{8w1gu1#SG$A9Yf}75rvkc zM}YM@DuxB?{06$Auf=$W304*~efkM%gp>tHSXQg38k+R8GlPXGNyRW$i}Ja^jWiV& zv1R71u_V{Q5WCp6;tlG5P#NRyW4u*n@6C$RUFVnOEKZ{GNivW?w5ocDT}a033T|Gj zIx!*CSL(59o+mEd2qZ9{JFRZb3qr{@Wky`_Pganbfw2|KNO98i%fYDd7+gYI<|WP7 z1xa9lp5KWl%2y=%x8G1_3|F8`sp(@e_E=ol<;vbU16J#|n}hoD*l*rvaGT*+-$;j3 zV0W>w>Bfm|-JBl;;UC!t-fyH7q|?rU2XO(&Y0cg^tf{;0z1^B^6D7Gri~#Uzd7;!p z`6F9xBj4wu`g+TJ(*bUdw@g-~k0ILv#uT9)IET!)V9vMCA=BtbY>Gs6a7=b1LS2#k zgzT&LnYfszBWlx3GuOrVKGO%j7!E9wS7k@|4jhkU7A{}ckgsm+tWm=00>r#&TP)<_ zsdPqor8pVGj6YA1G`nN{J+p_Hiy<>Bn`>wpJfW_A3LED*8QeU3kWH7z;+5t&H>3Hk zFwk5))j2qJ7=bgI&A7Gk!!>%4xuxN{tC24Y7L4!<&J79ZsTz>GTutwOXTk__ui3`G9_3L9xVnQvE zSwyp;4}A!gyh#*_H)bKm{M89%7d<>Sj7}3pT$(@|(R8aRDxtLCKbC+v=fOAZYU5$lot6J0w)s2d_)wb1{K+S46YkBLHE%lY?wj!+u5HU!K zjJXs<>#=V*2ag_UVPvQ2k}S%P{KB=gO85mMp^Ss#(-54oyM|Jpe+~jYk`5sKctb*O zN$~m>ILrz=;h&1^>yax{bewInE+npYb)@0I%^7RRzp0+wnNm7O$r1Q9MLtOi1~m!% zas%5&h__XF;vMod%r34Z>e4hoTUlsl2pPJ2@k(Xo+n^>>R|w`__PUZbZ1ApS8CTW@ z<=d&msWQj}OPvdx;E*`PMIw%&!2|l^gcdh2?Lt^r2Mz7gpoeqFz=Tr~;N(>=Z89HF z?1q^y!G9ac-Lg6WM#Vcndr^5>Je>17rk zaq>AP-uX}F7j+gFW%OItGBWM}wUslh>C2gDU?a)bfIgLQ-9=mLZC;7{*{P=XmbYh3 ztB}IGVk4J`;#VFaH!RlIH8F(M|6!N9!tu0nFU1eMGo}P&<`qWmp07bS*^tkkR$g$OuAAkhVC+n;6C;gFv0b&BBtIRqBCF z8uR;05#rmDJ2x)_XCIO~tZuO~7YiL<#k{5dD)Rr*QAGlh7y1p&kEgS_cfPK>nFs#; zJf!{u zZ-7&$qCai3>=l*_wKsqt=R$L(!PFRz`0TRTP3}#Yy{q^uezeQlWw#6LQ5c=eUg$B= zyYU(nBQJJG2`uhdh?_fXUhrBKGlLl>ZIHWi7fjJZf%=am)lZY|OA19lIj~mpZpGC{ zSXg;`%4#*&t=nc?tL`#OLXn9lSE_TZ>Q;;er)vfhk+={ter_u>GJEd37)|ilGB~+EjfKiBJCQ#V$TZ1h3AahSQJ5!%x z3sf9$CmD_T2(iW3imeo7&`Jwa(Z7n)yzH8ts_w8^6Q=XJ2+a$G7s+pbSgBY}K813^ z0$r9Ino@=>cbp^E;=kiWqG{mAX6oNpRnRTMa+)5NE?G;q8q6b|V`QX-P4$#&817^z z8x*#wt4~E}f05TZlb}*LCthT7MvH^3x3;k2Hmz|q$&q7kGJ9ePfkO8@xIEeQXg+(O zdYNgxZ6UzX;mmiqKI$3Ws-g5eg%_$q4{L+muXxh#k(FdUvG^9N?X32$pR#lOeBP#BJ=wA&)!8|1ZRL3f=45^``f0DEVy;zI9ItqgwFl~Ce$hK= z9D$C=_=Cz=c>ib`c(Yoq7P814;^dQwGaF4)ooKFa z!BZ;;bsVK47F__m;os@ETDhnxU_eW5c6fHxTBQY4h1fSn1#NZ)EH;XfRNqnX|85p(7_z)6{g<@#|MRb|9>@($AFV(i~i z^1yn2W+k#S&(_cgsvn^9#uIL2yx#0cn@2>gw(?A9M>ycQz;kQLZL~?5fYQh8L)B*< z0

h621=ZhTZ1uV$9ml!cKW{)xKOEeYE=0f!p)p4sn=CV7O7Uo;T?+~ zZXxx9ueP?j3w=$lHQ-!}GUOS^!KBz@8D0f5gZ0c&qMO=0QP!&Qkm^KOSjksK=&p_k{cMNP&@|=yepj$xCibV#ZXt(R_Yaz2WgjEdI!H3KG}a4Qq*&$e?)GN4<=? zvU;aBLghg+-_Y#4wysQ*MSj{I8|0sLgP!~4Ej$z4$>Z#K>~J%zUj7Siam6XilkP|> z%hT?l_;|Vfmi-5BM{Fp2)d~LbM!sSF87tV5E(6ZJEDK=u%YeE{ZA5X=!txyk2`^|X?HVa?$&lDAPJDbrtg z>J$xPY|TPZ%l!0))aAKEy^;JeZVnu7CBYkkeZH9KLA=h;k)Nm@GMz-^udKFMjxYQ) zEDRN>aM@th%iIL1u|6mzYu2qnu9)g_9X#R`!6m(Yf8}PKO%kYBX44q7^dIS{8>W!D z{x|mab5pS&)c0p9^&T;PJ#uOLxZ>8)*^P)u<*HD^%YGJ5+k%$Av2kl;=i}R~sEMf+ zmOD}C6#h9fB5&D*)bUeL2e#_fWt7PS0yNWHZBq#Bb9ZK9?MHw28`C#MEA*PE#`1(3 zLL1cXzXQfKYRpOar`>)FeUT>o6fK6P_@_OA`TqID&x2e!S?!Ves!d7_F?*dHT_r?n zo#H`$qxUU9lRu#UIcn?I+%|E4J1WrO|F@&|e@Ag!EBaTH+^9KkV+} z5g-G>)x;qbU_&xN?k@-uhz|J^H1uaf`j`|mYjRLiqe*3BzT-w3TlsDUie%q?&!$(*;yv@GRR*!6dMrwxs9`_8mbj5Sk7(&tYCp2D+;A-UeI-GCGPjgU z9YQ^-q2n>CU&L+oJxVm$oug1rIh6cDSwJZ?pcw^^^3j26PVv1>beB%yJx+9mN6q+y zN)Ek87C~DMg&$g(PUW3Y4YChfcO= zsyVa152R#z)iG?46#)~HGI3sNkb|any`_=z7&zoL9yCR_3SWk;iXC$K`8<^HWA$S`o?Cic}(>V$BHWco*ER#X5eKG0LBy-v;rb00u2+A}vGh`-F zlgKjg^GOYBmQ~W@G$-w7j>K9*B->iHj;Lk0MlKY~+@6{a!uf4GsK2U(l@l=FlN1YO zG7X^5L=ctQ!A7J6l=Tu)B$8tt)6t}o4P4T!l$Z++q3`olyGpZ7lsGpG2YqTK#tjZS zXs}`heXnFC@o2#Y%0#P48fqq3iKfP;Q=!$hQ%LxT%=Z`(c*s%n;Hvn(CJ>8+bK06Cgr> zIAJt|Zrm}#trk>~1wg@a=-v+z?AwH8@`q$fSZNqSwH1|}67X+bE|w5@@}uni=c zCC3FnYr&Onf86zOh53OBG-tNti@LD~Qku5;hnPxH1G*!2b0%uekkfsfV#v zY~;lVw5IuXD~ol5WYz`%ydWGSF-}ZvABk-?7IKOiV2*fD$>#Uaf>5DU8=Z zf9x+vv}zKrJ_>i>S+(R!Z4P4zF)e0H7pIe@h4uzCR6`Qor*T!JNHzpTQ{Dya)!E&L z3bH~cz{+otXj*`IjNDf-$O@G8r7&s1&IhfoHlsNv$+$$ic>3d188iw-4CR>pC>&LE znPTX~g}hIq4zA^CX1cmwJ~EHOU&5lCzt|82NvzUsy=4bmm^*da*G2$b#V!;M=w559 z6nrBjbQzH`VGF@r?HDf!R67<`6Z!%M`d3;`GEl-#hRHFw_5ndbYXx&5Nca!2Wn5PD zNO9*z2P4tlP`n7ou8aQkFlF1}NlVBjw4!wcNkR4TeqP(Oj~%;O@@~cL7MFdn^r(NC zaGpNDq_GInQo1dgA`4ddc~kWBsSo@PG$?%K^86Y3qjCu`7@7vxmQ3sEr}KC4^vm5B z*OpW(A!)mc!Y@m6_RLLai2a*Eiah(8#H5vz+Tq{FQNxZ!^vEaJ@AS0$`$m)+vB5iH zupgwiKU3pSg-b`I-NG4OhkEIj&>pxawsLi5xb%e8CuQ;wq@Bn&0YsET<)Ue4Kevlt zm^)RM^aXz_p4#{$E#s5{+uU$mC($*GuM{gUi%f|CHew&}SLJr-C z?5SkXWsbmRLA22Vz4SaORHnQa#C?A_t{^R}bQAnAjg7AJ+OFcd6Wz_NvW$*eTTVYo z_=^{SK?b&E!$J_J8~S7K8BD-#6_gT`4l&ved{t$*@?*bEH>i13cV-!NW;PSI`9BR@|cBB=ng7ttqT=Y`j4t-(L?SVZ}#&% zU$)-i%fdD5i`H1nfuWid*Kf2@q8sdxjTueWfe?V{ZpyH)Q=^|jr0`15>7w`h22fPpN|Y3l>=GlcVvy?4wX%)j);{EdSc*Mpw>60^m1 zRqAVrIqDQM?SJ&|>=FGPVvU%2EbU?{Zd(6#M{$m}hTnFKXg7~4Jdhp~uF20ds6xr! z5MFvoF@}jgz3fY^n^m5qs1~G#1mx}={<~C;A04uuhM17(OQn5ln#;HMr-2PekC=ek z7J3}um(sRwymsnSqfz`26q4q#itIXU|h-{^!Jr# zL1KiV&SkxXiaR$7w$?%AoGm&o(zN;+A+=?t1q!lENj$%-oXsq6*?k!gA!hj%=~!$U zdTk)%PFW3KFPY_5WX%+lH%t+P^OfpVE-g$X-B~nhiX{l(madz~as_5t9fg?$pzpZb zvpL6tm2I{k)iS3LSL@~$6EiNBWkQ>wqGo*@W?&;I@;ZN+VWJ=J(<$=BJ`r3yA!(O;YL1_x7rJsZzDYjE_wi%FRo}{h zAw0E%DMDy54tIdH5-@#jbO<_`BI1q4U7PT6fmnPu8ep-wN`i1RFG1yOOUL{D)1d5i za^gSNDL3zmFcsj9u&@yj&KgHGVHJj6>eLU5AegMe1Q_R0d^DR0ZE1saAJY>hM-kv-Y zvkW1XVL;;;K0B#=|<=Rt=ihHhr^oJAUaJkpE#m6lCR4cYna`l0341S`5#H-3Ir+$c51qqCVcrbBg|mqy}hO+w^7HlI*F zP5ZfdG0SPUrP~g0hJe=cLIuB<3s_HxJ?aMC-~BhsW>>u<8Ex%-%7w;tK~|(lIp(y$ zFp0Rs?B0`li!8Tw0r%dM{7Z)KCgCB&!fEuy`&5rdRS_9^!B^z|>bt2Ge103xrRxmC zw(x4V5!k*p4xG4P=%_nM|9VY&oK9)tqb#pIwMkb+LvLHy3m$e&RG5*wO7p6i*lq6i zzN`CiOH}k|8?m#jt;+~K8YGaoRr(FD-=6c3lnZjx{9q7^E8%#SBST!3CD&{ok|p)r z5-?jP@)Ttqay&i-r76;@C@HcyMW!3W`_^XY-EQ4jGW(zqh>B!iF~vokHR*W$N*8dXjpY`gv23U6yV-b6wcj>b|;f6>A6! zN4fAlDG=p_lJ~HdlHvvRalU>FMEJ3c2vI#6kQyTir#VU`v&WX%ynkaC(#C6pbG0KlL z-38dSm(tJ+t@2+!Mzx06W||E zjx!@K5a&0J8=$*-c_=wu`W`{TEtWrb0K8J3{q<}JDs%-Sr>OwFAny@)rQ~_aq`qR{ zXOdYg!F&a!bpycZ=ckrlVBXn(JX3N8Bzixs6rlessXor$Z6%$w*BXIOAzf!#v^%G` zoK$sQ72D(tTV4B7PQ(O%f@Gs~fUN7n{m~aBb%D*6SW%*-nT5aXK&iVpRcFFT&nZQ> zIb##_7G(7XpL$+?oW=Q@hnLZrN(O0yE_CWy`C;M5tQWHH?-<5C0G-hEE@5gAiVT3X#^3Iw?Ip`6u*Wlc@!GIJcZ;QHpj;A#%>xU>3t7OYw zfL#czqJ41Z`8+GMDdM_8)x}J*R5iX?4sJ0Ar$rO>Ogmu_Sv-gKV8?X^u(aYa=vV)A zh(q<_>2->7o$5&xB|a)C8fU~}HY~g!9@m7`zy>H{4#Wr8D|*U^zl#a0&@EFdut0_- zSKI$4bkdR(zH!<*n{)L0$LU&ai~TEP&&&NI&S&N)@85eW>ows7C;>%sOGTYSGV{!5 zCGf3H6tpcH&D*rt3B!-7Mm1O#DyIvizh<(1lvdGHvd3e0Sy*x$p{J!7Sf{g=Riw2f zza(9W-S^ov=3T}K{vyb0!_*$SOu{VgG_n3oySVqSh@Q*cO zmn+1E*eh9BoNg?`R+NA*NX{m_3LlitH{^l)-^rI#(&!gAV za(>_*!)aPbr(>5@I2Z{5IK%HP=*|Wuvc%hE?1AW{P7MKVvi;StZ&LDdm-vZnixNQP z7C@Dzf>)9~l8eAEvfL+(*~62vu|Bko?mZb6w_K2A8N|w7kp=BM`^4J>GU|?HD~0=( zQ~HE{XH6E;X~Q3uoK+niIT=5h`ZLb=XIHaVfG4*U_Wn%~O2|5{LxSs`H~j|t%=q#X z1&2?#LNYfh}jOt2ZOFDboC}k0Z;S%idd()pd35TO3 zg#lKLGR!bzJ#~GKXpidk=B`*AJr@8YFF3oee*7E;)3nmJ4}rtuHg)g$+*LvT)U-bl zm%ec=?>yXR1%bc3*zib2`LI^Jjv}(1)LibRr}NIt2r}Y<)WE4?@Y9AZ7f<4fxG`C$ z%E?Pl0mylI-)N$9GH7z)D?@$-kmDMJMgamSx|55#$Cb6@ZEEk+3cK+gsl@Er4zBdD z8pL%jowTTPMLI~=dW)3fmS)N>I8|D|0)7iQ+4TSsocZB0Yc# zN(|bt4nM#K8GQ$ro2moGr@4>xr(J;Q3Ia34`K5d9n1%*_Z~h^`sHt@#B>kbAaxuxU zu2$%t_U<-ay{NJwrg~o(uV!%$lwdAZfh%KtRlypWutZ{?bJ3%8ebnAmez}#oYvoBN zHy7G}snyh%G79|PGUy_ZJv4!Vg;WhTm5+;O{%M#%L zZ#W``+;fuXtw-KpbR&R+l*==riM9pRbaLT3R9SdF|=?7?Z9=nsfS2PyHS( zVxZPJE_R|rhmTFYK6DDEt~iCOQPDuOSKXtcS9NZG-FtFkwKlSie&v)sI@{+J-b>fZ zFr9zx;)#?;(r@hcm_%H3R^?lRc5H^4QTFT^ccr4gRl=o5sY0i`R6i5_MJy}vu2i~6 z91T&?-zlNeqi&`^ij{hC_Oe2;dz7bRqrz2e7R^`cSsi&1R<~zpx2Y=7se1&cP9tb* z{z|nrouh?8?_`gx-?A10^t8$wP4Wzy%|_63r7EBJ5i3=#>Z?xjjB>l~WVLdeu*DiB z-UaG*-tC*-`Chb3WAQXH#PnFZ4 zv?F83#zd-f^!S_=9wJ-B@9@&dkg>`Uuh3l3xMZ@jkdhY9@Zhdq@=JM_{tE!@?8Q4#D#sCgGb{u)Wf2Bh*gS?MYhG^Yrw@I(?ggul>n8txV7L z)_dAE){?PswQsoy30qS}c?mI|bjhQJRVJP+wv4JayPf7vtE00!`EkD!Q#@SpemIG; zLFr*#t*c1vnecEJqIC0f74u_SU==kR2KdJL?XlwT^GB3ssHJ9=FPo&xwwx1S27Hzj z--IexN;J1@8?pkss9wT~wg?=nh0&91-%!KI%bmpRu|ym!YEaFWzzX7GNZ89I zGbb!;XE~3Y73XhwMucjJSal7S;OFIE7ZNNtI4J+V&wL)AS9dNId5l2C*Q%wzunrYC zOUUn|CUI>72pA4Apy8HY95xvX4Kon}j4{{|>9%;Quy;UY2K(WXZArj@GUlLCT$ds~ zbS(Q(!u^3;E!^<>b% z-0)h`W`aS^=p{u4dHE=TLPm!95;in`oLxItNJ89^vUQCrd8il_WI3`2WNl{cw*j1q z@%d>vQshvSms*F-j+rX2XbV*>xCWI8fAt9-}J!jkq>QiCs?rAI{z(%CacR+Rcaz`-W{~*j9#Z+qP}n%CK$Qwr$(ii>kkBjMu38 z$9S)CPw%$QK6|e<*WB|XHxMm&-7CE?4_kaqpaLCoj95yVF$VF9!$g&W)AaKXq({VK zgj!gZjhEMmBmh7oFb$g(JKee}5+miFMFtkoYb|2LK#H`)5^9m|+1+HCh&xRGj#8NX z4ZDuqg(6ORpV2yE)XGiWX!LSrn3BUd6j|b%kY%9Eia}cxPCvW;#}kXcr(#$Xk?fa3 z(_QkVMz5j{n_rZ5Xt9BwNgnljGxiq`8FJ%TeKT#AbRbLtmMPnGV?z@}6V!IqEzSe| z*>P9_e&d0t`+j`MJUUYtVwfv`e(|aAkjve1Z9n;=Ip(IsGd*<{zfaNZ=ff{q#g#;} z2Yl{=8!gQ3$!F6K(62mU_<3$gtfsux8wp`=?nLo7r;o>D!x!+!SX`EmfZISkZ)^I` z4Z_b2eXI(hd=Zf5rEepZ;@SL%)V^nPPrU8w+5Lw=;c19-t{!*>r#24anVF+zSmH#d z!aEVeacl-%YwwbR+dFx-U+I|A=%c%?OqQ!PLM^p}1GshTOM3k}HuDSb1cXK}`vKle z-rfzxY6e`B@D?8syz27S+TcM)l|*_F(rw!pAd(>vJTZPk-Yz6hF@W@?GqocLK5BM8 z>Q-YuI(N-|vKO%^I62{6+FVna+ChLtcZSjRRs_B~33ycYUiF`kh9U5ma!jA7?r3DD zM-~{hTDpzpLU3>)!g=h+9HD)i8&+m-F!UpnSN5nZ;)~(sjg1XlI0Lz*V9wc8ZHk+W zOU0TyeBSEW^9QiAcCkjVG(}ewvtIROe@$jJ&XA53fQ(50mns(t&aQ0$4AKa7J8~V| zEwm^_Ar^0x&Otw>iR%WT!?n<__EIPKJ_Qjb_n0k_dAWvx_$)v_$Z~3O23=n+I0N`M&v*rgQ!DU&#jshX$>bQQp+XH z@W>YW8}46~0Uqg;ug5lngy7F9o>AiM(wlM2?!Ibs&qy5s%7%vq=_s9J zR;Dl1ZgSZ#tJ}w9Hy+i-c38Po0qv0q^k{tWoh+C84(g>sWi#n_d~NJAk-)HzpeS@0 zqNaJ{T<@qpoBfA{gXt$(^cT1acC!WOgzo&?cK*#(F)AcJEC&R9*RJvH-{~L9Wkfnm z(toFl#$q^(DMAjnkMT@Da68LqZBDOe^A99__=ibxqPa&WYoWTUZ{c4>Mvz`DK)dYA zQNI4}$aS@Bz-wm?y8l7AZK>*J5+DScsXC04NrPT z*vvK+HmKi;{fYxi;NDDDxJkQxH6Wq6_+2Clc!w=R2fzY0CqUv$as+F~QXexhnEq!B zVNaVCqqQ$Kr9%tiUa^BaZU&I<=R1BV9&jEsp8icMd8G4K>hZ|O9PLw~s~$0Ur2U$@ zZO8Fhw6K<}QX~PCly|nQP(j@NsB>XyL(e+vd^5*MYIl&HCQjU1q?8s2KSzr%#PDLB zOVvM5LNlvSC@v{A1L@?EJVIU9;UQ8zmK68x@8XvR^shp%r4Z zKtblT#37H`p-p`u5=qkwlBRKFt8gvkkS49dv7KObu_r=f&+a|E`6czBr3x`<9_&>HvAh#T=U%R+1PKOB9_Pia%nG zrKS8tc0!p7hE6TUX=fa%#3JZY}N1O)Rn-HH@8*K&8B8fksQG~+>AAZtOh|cgQn}ftT5E6(RY(_ z9T*yp5Gp69G9&otcR6V}*Ws$_Ew~#|GIE{Nd<;i9sqAInfLD8`sA3+EB&V#vO%>9I z2`)dV4uuoymJ)KSem6V}2u_0Q5e7xiV*UE(`u&eZjdU9%A1SIg(SyDouc#Bat2^A^ zk=fH5_Ln=gRsQ)Oq2+zI-%DFSG|e;Vj+9=3*E;i74_IxP-xK|Fte}C4Zoq&lK z`(}Dc*{rnS8nnX#J#M>XDCSM$*IG)8Z1@1lI@?9f#7@keQrmtA@SOtJ>ip_AsEU0x z?2gJ~wISGcXSHmMUMXEBl{kJtAloQ??-*|jl!|2hjbP|!TReQ+pD*;kzdiW?Jq%Df zxm$K?8Awc0eV<|_Pb9>V#RWa=qzV$c%!C*355G%~JRZ78+zShvb~rc%(2&c%Dg>Ms zl|Mrsh-AYaZF&v*bZd9k0|%T5eA^4RmszDX>QCArauDCrS1^mMhW)#YFxI~Cr7SEd zbY3yFGIGBHkQ#nVxP<4l6Sv>VGe#=E^Jw+#)fqG;JK$&gV#C)Uf#53lejoQev#ShQ zstld{P6HlT=6kDckdEXj$nJ3-K8zkeDQ@_U%$v_k|2$kBz)O5%c~QN%wM{ep^^jrT z<+nkKbBi)|Wsr|^$F~h^=8svC;gKjy3=if-$zaGO$_nlkfPtxwbW!OMnXJa;f9QmP zIdq3%!GH|8q;xelW1XN;JtC_nmts)CUM~2ctDPEiaKwPj`4^fjEi@#JRFK=3>vJ#HaA>AD?KLvuI&Wbwr4P?_D@ z@_M9T8{UPdifR}ROD98$)lnFQz&Dub7hKaDH^s|v%{ZRypYML4RV@}n7ofTB*w{@_ z=ubpV7N9%4UJk;+&#|ph2=53G1jmbmvQZcLRAAm*;gQj#shmndge&?a2z7Bf`ZN_)`P*sgQcTz6%hJ+$>bG@{RM z>cGX^m58sUxPQ1H!{jQ z6vn&LtB#TGEx;=)8{s!&^h0tkmd8y?X>+OK)JuiOlxba^e>aBO>=ca1$q`G;i_$r} zcs6CezjWMje27fZp{7XjJ+S${P($)(Lwbr_yi8$wi{I6rv6-*Z%8b+>kZ;LvLObVX ztMK+y9Y67+`Pq`R!Uouu4;Qt=XbA;(1m5lhKtcGr`uJOC@}t*@;j8X5NRojMu4UI= zs?sF|u~1cxWu2B>Sl!)EA!UU2oLvWC#j;BJ8o$z05&IH!3OPw`Hfy_HB68IDhISkW zDjOI9w0(lAzjsiHOJhiWQ&&EW{+|nN-V#VcnSfuv27bcQ|99!Uc=L)3P8p7_kpN-w} z(}23FsjjV$vplZYzuAwoUf-&-eE>aBZkogAFIccX<-6$|6t}@|9i>E3tV|zTu<|b+ zu-`fPU^XSayk|8x)Q!i~%pXm`K67#*KFR?;vo|=4-peu9rBCl?_rEizy3M z|AtUM{+lQr1WP+lar-y1e1O;u;$#^Q`cJdW0D9|YoWH4Vgf^wrxi&fqQ9eZHDuu+m zm0yZwK{l_jBa~|1ur*q1u0$+>bh52MwEV5XY_3Wygp~5bzEDT`Y=sQ^!#+tz`PHbA z#-aqEMx^q7h&gCcNtzkH$>9|7=-sNE0J{*bSv>mKW|=7Ey;?!DbeKZzy;@dceKXF& zyjVFJ^>2eX6|jmOL!uDo$c7?A3>x+B0helUv>OdzG=@_nQl?t0^-3@r;xgQ~83=AW7;m37`}KFdGQqw71f;2tpAt;4+F_ z+)N32CTbqJw^%YJ^piW_o3oo-qBkNMj};;N8yyBt0E`5g2(^?MGHOH?GjbR#i$Hp_ ze)O1rZ07!cWsx5}=IpPCjHl^{Jg|z$ zq0|?EafCDH_|_cSuGm+^E);|~I(GleOPA!G``-ZK9H!mD+w}#zM1_ezk;Nl z4TV%9^5eLWT$FOx#0!S%|2U?;#6N8&cDXM|rV4-v`@o0$yMTVMMZb`7*Xv=ne7 zGlu1zB4f}qtyYQAo|Z7N;zH0^Q32g)*2tbso(6DG=K96EAR#s<^{BHdVK`sa4ok+m zOqsNpgoSi*Vm1a(oDA8nh?8~-LURkY&($V!>$|0xq^jv@aVtd@pzOzMU%ZV`)4LSM zQMH`z4e2``Bxm{(25RW~l(v{0tx|E}q2;+wL>3hvMn%FgukxL=?#k3W0EbU!Y1zGu z@e8#9k!G!7$_x`~ODSP%6Wmn8i!kmgY~#p~^(`rD1a-d-0;;rb7YvIDSog7DfYCVo zyHd$cqc{b%mU1K#MF)_;qIZyjFXA^lwuDFwe;cq7r!sRxW3ffr2|SHZ2S1Ez|908O z<@g)MG|qUa{QG*y14Knr(3|;2dxKK7J!BRCfGT9dmI8y}l{Rr31Cy!WcmN7^2#Ek( zhk$jMbRBjh!~@3j*E5!@rdG2KdIt+~d2?+kV`6*Np0*@nU906#-xT$eg?&1~b^JPW zYkw?fP!R?lF%=-73T@VKCYIpr_wY@kU&zfb2dd1RO(%b6kr8LISIiei&;D3FuB2JZ z_BvG$7NC?_dA>+P#mSLU;(Azid=~%#nmvaQHnX9izEKRhDEtJRVi&h@5fv*}Ss;s* zaOrHMApe5$Q`$aO#5%x9c_UVi-E>EfOLxc1mDeGH)h+M^DpVcNC5;qJOk%VH9nWGY z3DF9A=l~Ul(|bt)YG42D}R)eBJ@p<)}0eg2cpO?b_GpxqjCTOZ}KFxChYTbUd8&=@}a z4ud_21lC1$J^g2gkTHS)FZLZePtGN>j$|%h(O9mfZh!0W3Wpt7ipO;1_gxMFJb8N{ zO=3Ai4tZv&cp9CFFJkV($cf8Lv=G048ZOEjy|iY0vv%&Tcq(ZcBP>o%q7swaO038M zM7_$cHqQ}vJFF+BjA4E)nFGch!E245h~fk!>R`r4zt@r@9fm8ef_28fCrmjz@q`%k zJ2|(+)Ri@_^C#+HPf4DshNSM+xrlt?Lasuz-*}4rRJ4fxekGl3U6^dtF|7w^_Xj3U zvhnu&zXI4g8)KjBrxVhCNem?9FQ7!7*WT^T`3(rn%3i$Cd_ZG3A;-;fPLyO;8^15K z_t)oJt8qfAlcyl(`^y`P8O#Soq$!bPNujM2NT=(}soH_HsgK3Qd_<9$Com)_c!ini zXI_Lum-w$|7LTbrY6J5Gk9wsPduyuZ?Bzk(la4;SM~p~}0Zi1&-4`q8j8{ja#ERc? zcAH7}i2NUqm%UcgyxyP4u@o7i>JhA{yfMn}uFr<Z# z+Li}VItJgd8v!Jv&1Nbn3$ELL`_587GF@? zGKmSdDRq6y^(=HTkuy?%TM>7kZOD7`9I@#9wac`-l#EYn^eQg``e(Jl1({$)m1b(1 zBK3!&7YI>|1o@AIGmFuS(PWu@l;nPm;&JQ=`G6wnp>@%opgd!uUWsn9Ed@$KETlm( zY)kb(vR^szMcjC6XW#%mzx0mgP3lNwtV(`L_N}(AYQctL3V3r-ez7{|^@Cs}LG!&R zjVIk~?9(z}JdPjJ*AGgGpY|~-FEbgmYJTf@;=GK`euzqK^=%Oe${!ra zR|C@XGi3*Z^*$ulu)vSR?hvc?s5X1tAITD)VE#V_?u{Gd=`Wu4_q?}t%L zmr(EY`6V{N5wsf4U<>s)>BnA7*W7xDd=%IFVS@e2(`Umt4b(Q`#eCfcc5la=tV_K% zJ37lzF^pep3#R8F zYfoD`B*R;^6w^7K_2D3o9nv|xGXPaU1(fD#`oP$x+vSrUO*iXo9k;4)dM$GMOgOh{ zZ<6%Ipz+37lJ|zc*GD@ZsdYclhBU}V?o8LA1>tzPBhBg~Ub-#()S3 zkJ!R#fo8&KTEREl{=^D6MTsjQzwg+AZ<3`=vLGOl|SZ+n-Vt={9vz+eJCW z*DPyxKcz8>an14y`--}=(Fu9>0K3M!(+n2c{EwVxvknE=PHRY;#lJS~Szk?I+R4Kv zDsb6aFY)^d{@cTNh6Py1+$f7{NUAuhjDF=P2&A@?7*s01Dhp>Uo~3i^vjfsTc$FPz@|yN+#f7)Kw6Nqi2tOy*5S9vmR%_zBdHq1J?O+QTjQ^mo{@ z>_9aB&G*Y^yh@8dUKgh}QZnvg zT(}*=OU@YgU**K}h}qWfpg4+ZYJH&6-+rf)%`yj3N2+Q3W|h=Um#0hr%gT$?Vu#4u zS>PEBcETQ!e96Ts(V2-%9o~?F_qGccKW|@oJhSSK$T_`BvG}KP6vUcmYn{b!lh$Aw zDRuYBnmzpA{7HI`Hv883M|xk^7uEBp+Ew#mko|$%vcy8nq$Hj2w9=))gX*Gpy!QE- z!SAydujFQKF?hEuz&)t@O+*35xE3v=i)WDco09nnwo7;4$qU)WCxzF;`NQZkHn(+- zGCY8bb_eFiSeBuKA0j?ik`?dwZ({Y1>YGBN$^^zWZG#dU`c15Hx;A$w#x2VrBz&_W zAp5DMv0s`YXnX6}3sPts8Vx8>%7#Ply5EwwU15ZoQ>qwXWVW(=WV`&wIlnUlisL*{%d_qJ;+|o8b=V0m zs(pU{$1Saf0#ID*pBq}Og#Z5<`Jc>NBm4iUk%#tFR7v~x86|!;ws(V_{tKZ15jznG zVybSL(?IYSQVJLZ0#*o#CM4&XK6`Yys|P}Np_j#g{shqf0FRBYOJdL zs?9=0$ffy8qP(K~+B?;}@?;F`-8!@I^`BrD| zZF}$7iuPL*;LC&PXIgvIreChJ07{ zk}Q5mVWv%$OHP$mRK_G#cnUQsJ6b#^N$bxfQMgJmDR=u%+(GHzu@Ht5#NO+ki64Iw z6!n8Xtdd)8GAj82T3?l%SuMW=a+$JODH`i6LsD|N;{Kp}nbG1+@(k@xA%2{=lm01G z(3z6?jXou{f@z_6ImoDaP?b`NT;aK5+g1dQ|14(G*5J}SECn;9o<(Ovv^A9oN+p_v zwfw1Z(m$oOokCQCk|36{2C>3P{t0S-*N7YoC9`tz=J53j8>P>_K2|$hNuXeMY2@MJw zm~)C#C2q`;Rb#C3Z`1;jk>HwmlD3E#h>U*t8xyxu_$*imzDK~lR!By;x9WZ>_9(LA z(-=gx8XwFrp=zbmjSDRj741qfhXr|BbdG5OwSQEgdS2tBG3^Z(r>GopXs70gLJFb; zaXl;GawxK(FP6HQ5G~j*9R;e**1#;U`3Ju6%L@(_GM{yf3lkdx1qg2e>8(ewXM+YJ zGBIw@K`lGZyk530XK1jNC6%eju|#!n;EIrHDx3zu8^_=*ttt@?=8jH>R8Ji>5WMF? zkGf_KNkBxw!&nW5W^y{a<*MHUk?tAD+$3&Mf5lAVRAf*p`gKh1 zt}HhXd+5%VF@APPQ`U|?Px7J~@uNcG8D>j0m090w%9`pa=ls=Tn0ATKL|p!&0!4z( z=Zj9v(l`Vz-5{)@pf6Pzjm4F6h*_ByVlK}T)GnSy+a<2A>)Hq{1dqI!*AyY&PJG9= z=OjqM2s0+5jblSX&p76=;G5}OGg^);bx{gxvbJ&&b`2}FgHIsCQa30SXe1=}B0EH<=tGsKb)|4j5tjQ1 zjksA9v<0yz#<3G?m_1?sPrF1v4T5aIk zt%nrezPGd5Sh?!mKe)>`#L;FiFzI1rwvj;eEWucFot?ns4xCZ301SpcZxa)%JB!4; z27Uod99^kXd^>9Hf?00IYT@g`cQ(FZDFWE--gC@N8F&O1>#!Od#N01|snDebmRBoy zXbY`U%XBvFhn<$KX$!sN{qvy0$D%^bUYAEKZ#lh>TkY;tosXjVGtm8hOq|>h^w@wf zQ7(WO&YnKWNqx){rbB!=o=Qwd*HlR|fM+YWGni-*_Q9WTmabmW`EF(%B+<1J)E?5w&4b5Oy;)-Q-?g-|1>uGkJe_&<}DHsEd&q8nD5xK_Z(Fk9Zcb-N+3X=HU7tM@VH^e(vv};mrpi{TyFvOY_8uz zZQ|UX5Q)WI7}GeoH7A9%HL|`)TUFZm*41UV=asTfm^;@dX0;5peX-fDLPdM@fIYm` z8Hn{2GXZ+cN!I9WZ-O3lu721n&tM-zAS18NzEJAwK$v^)sHCu8S6%J2dG2%hU1<2V zI%EisPUe!uhP$}pC-&C1(8Bp+P%r>Kg&3kZe)lH=dS)gpKV%1amR?pMI*-(ken+!L z=h7sTALZUq8=j3MP}UEHMFOw%mFNZ-#SmjPiIJ>E2nhFWc>FW)py*SW2o{J&T3iat zH&Z4;Gi@Od5Hprg-c>zkt3Z&B4@!Z~#|T{NQsvTXILT{ZAf?u^bX2gyPLbZRU^W{z z^jps@Z|xeV;-8!~b;i^+RWvM5T4xVF2S1vtCR<z}e z3yYNH)57wrs!YKCnjY@TW$fBwlN5f~C5ww_^nyI7H)-93bJ2;3xxaX~k`DL5 zB26A%^6E15%+%o!px1|neKU$}?tqw^YmwJeNaTBp9CAAUIp1Th#CqAm#tW(rKep`iIQ>cv>NsNG(^d-okq z@Y1oz?S0}n0$e;T-WH<}m29gW$4$e2bjWkv>(eGAI=w5uDlflQJx1o(9jl_*?8jOU zdtT_1UH21}MB_7}*9m^2qjK zPHbHkMZaTkz%zv6+O61Ck~C%XKMHw;v#jCzd0^PeVX z6O3*1qp;DMOUHJiAP)O%h832`pnV_gLAZ2-;>W>e#^U;eu5;k@^>HB1NM|?h-W{gQ zb_~XsXOQ+gVin(Gw)gB~4!Vh0?jY%4Z8U=u7P#X}>=A9aJw3R6fb&EB#S+rRLBhq3 z!-X^;R@m8?EW`)dXJjMBwq|O-+|xyVODh)0tsia~%T+0uk|H2DIyoF9?l>2u_}?5weU`C%Xv2R+aQJ${haEeQs)+P2{)w6f4*eY0I0UKpl=`A z2!SV>!JGmkSb4Yf4?B3i7;1cYJdArtZ69O-&v_J$D5K-tqTtPazcXPcvnblUzGmVkSx^;aya9-G#=PdJI2 zXst)onqXjH;I&0(oazCc-D(oWu7G7JoD(d~?m%W0|6>HFqx-+Ov84vcwO2b3ds4V^ z)Sdxd?dQU=C%TIXl-hh{p@j`#6kIR|j!iK}YF4AQcd$k}xFcZqIj2rCqhpt*&+G)Y{b$T8(!JhG^6d%42#t(Z0&>wW9~cD&?ep=zGgo73ZEg7_DCwMca5UX2QXLD zK*N;Ub6l<^ee_~UD;E+sE*ZofE(jq-$_f{;^RTS#zgSD=t@8gEi@3L7CThn1y}K#P z>xk}NI?@{R`o_D7xvPvhCZxA9J|6RFO30DB1E-kY0g|J@W0E-hU8l%n3m2l(cY$`e zu#?F5f@ZcH^ZlQo=t~LEcSeL?zg9{9Z)ybT{}#_CW#njTW2j_pX7gWJw?VSw;y;8p z?)f6AbYX>aBpnbHE0leH+uRm_rjS+%Xi9>kBv}ClhQedBCUS2O-i}BZtCJy_$xdPv|&U#caLJm{+7{#4O<~)aNh=MjLrf zV^c1Rw6N@@v#=is(3tH)7VJN*(+BiO#zi!kXj%n3c1$q-?Hl}D$#E3|8F$Tbt}N0h zOME;GXU{^S7~UIO{0>2(kXkf&ouY;x%LsX;xmI}`++gd3-z0D2rzZiHQ^i_IUxQr0 z=+2jj7;$%sCMZ2lpRBcuyX`40P(}H!_TCBF&+T{g|`) z_4a<<K@E{(vWln%@bo1}9?d>9K1WfqIy zIMEe+5Z0Nl(?M_m^RsL?k)EauIF@iXit$V9WzY+JDx?v(?Pf(I08d~PJhSKP4>GUOtfu?7Y17(5|$m3>p^p6=UNtW64`taPHyF|XZ|h0W$XL(G(os^FS-{5H z*v!PqUeD3yzv#wEN>(!K%E;a{1$O!{iO8zURSPvUU~@xsV@pY06|hD|llY7t_c14Y+L;%^jykfJaHox;YwUeH9xit6e7e2$uXx^&s=@< zX_N!~7x}@Kj!DWD*&BboTK)7%WBHcHf>k<7PA;>Ex6I7~Ee+|ayML>7of~WR%52Q# zTlPOOpfColTK69FHB!aahJ|lX0v#>auACe76fm>z$p&ul7+?wx8ZdDcCHBFy8HYEX z7B=baBo6CE34+p!k{;uZ)U7sn!W}r}qqdwPiIKkXy9x}U@w3_S4?1Soqk1g4a&h|wbsPkHFHPw;xQg9^+e_zbKj5`5 znc`8C=uKgRR~J^PrXElI{8%Gk7(3zb`ZSQJi`T@8V>EM4!oAOoFwm=>sx5^v6>j7O zfFxkvd{&K9p$Ob|14itB*=y~Zw*-^J3MHZ^M|E+d7W9;W1^R0h?S_N7a7VB*YxXJy zGo2a(Z$?(96KqO;|6%eBB!Nv|k-rfaK-8hvJWKS0aE-DtjNN9?gpaCRXQ@tio@M0zneq#V1xr1jSFpMWj#r(% zM#XncI*psT7wxMBR!f7=X1QQu&;&=bHo3SB8l+yW2NW*~dz6jmECi;rK9}(B-6h2{ zYe=NS`FiKJ>B|yJAVOxwQcN?4 zpX4!^*V4VixEHkTqs!umAQ}+l4bVs}is><;>yS~AWFZ@c$M->_!(Y#QS~hDIj31qU z6%h0(N(VY=C?ob84#k%!`bGUq4-79pQlVKIz>oP7M~B${Pd4k@e0+ao+arO0|qYmuZ&zOgw?L_h?|Mh?0 zQvS!{;y;e4pS|S2PpSV-fVFT%HbL9@+zF ze%zRyl5m5UyjU`QS45rgofgk-stp~$-6DkapOQ73)lpndtG1?mU9ILzVvPp?cN~Ly zOYN?11anKR(E`&DOmX45^wzO`M z;eaSSy0l4Fg6{6QB%!68>}-pBv%hRQx9*>kE0%d-8|N3_-G_5w21Y35M4qa42ZJv`Tt_90!m(BIHNoKfqaY`Ev0fAsT?V3}5wc0gI)eq#_N)s1 zL?>#u_9(gjvxZE)%}aC{bfPM=;!?vxf;%W>?LGpiJjhMv_$EezEB2C@GwS3l>86KP zxU`n)F=ni^$gBdIh&kaQX0SCW?zASxs$=aXh7BduCJ&QY2eDX!R>3mBPl#wO4lof@x7QV~%&xT8J6HV^S9GPU)Y+d5I=u>IrkbN$wM-uFQ(QA6} zjYJp70eM#(=m^1gg=lV446(Q~{}Gmc$)XW8UN8HdfM1rg6;U0bYbGX{fwN}f@zbZ$yQsKb|(Ya^aZY~d{@Ym*8ke#1<1Q(SLCJE|7bb> z3)9;_+x!K?yJ}atL#ZE#7@4Uf&xE%8&mO#-X;ka}xaY znW6|D5k|lD1Re*YZ=0ac7+U`teymk@ps|iUK5RHA^*xlX%#g#^K_a zXNc;GYTH_gyzHHDvV*?eZVa3;^*G)bn!n~v6uR$p3AN`$A* z+p@P`oW(eXT6pHrk`ZtL(`E|#nTsR2?fIDFc|3mJ&0K^rl@3ULTN1M~97Ri8A}{UM zb)k_7RBv6LCj6L#N2l)el2#{FawkPi8NB51+1T9-Up~skAX-y=pYagwhc`X4E6u_Y zBgy$cWr^mrxMvZq{Rw8jMTqrNI_5W3hLstt_Kqpy+PP7(kZ#Pef(!a3XBllg2aPwY zbxejsW`<1^D2pI2>b;E%le}#U&zU#E%L^q6mZRoe+p%*F)t>-3(l3#c zzoHya1y#*pI?3GL<+-B$1f72M7IYy*_-)2eW5h=p2d;3|#7eKAYXCm*CigpBJZpZe zZvR7A;PCrA*u9^w z*zm4j*nB9<`76OR(I@r(CNYRE;7;WO1}DPsP736!<8q+P?jW4(P;%A%9fi2|)I?{K z*g>WHS{;o%!hA@~C&!b6CDj3&D*`Y8~s8u$UyhIDZ*#P zn1O{kIrK38=MsIytpS2)U`xV{SBS38GZN(|H>;q^hgO*pc8gv8^h)TF2kMc>7D|xE zG%msXH^DJ6fg|h**qSY3{8?IWk+_O23dO|kP@6_3@0Ll~fev&Dxve&B|5Y8%;&oDQ zlU~r}kKyqJNNpd?=lLm_PBHTWl&44V>qEu9LY*J&s4)*T>rL8nc*J zTjby4mD|Jje{@MaDkD-pKjjP~;{UCrA^+dHq#t52llad=-pIhl-tfPw8ijTFd0Aww z5EiSjU1b{o4L+tI{@8S26i_NS$)L2poV`E6_J4Zg7np>+p2;3&(R4iHFvcUJJ$-q1 zwoBd%faFd>Gf%rRlRBTaOtNiwdGLVI2edGfWXAz~)savSqlQ93>$C>H)DZ$0{AGh$ zQ2SzM`VT>{A@!L;>4X1H(7~F7_ZAB)V|>&vk(!ipQTi8E^C-Hnx+ zVRt?Fy6deD(A^P}GnXDJveu5&hs0wpOw%gmsQH$F!-!?no{oqGg5oreJT{IX<1td~ zqX-<4jdTx|j#}#LtTbpRj6`I(HEJJ`Ghs@K+3nQ?9OCj)-5kd2T%3k$Cd6h%M-FIl zW`q8CiEPg|Mp_p&8V$2dFfI1MyiF@eO^w39czyQ@IE>*evstabQBr)*s#)4!3DQOt zBQU;JQd>iB)Fm}5cupbASAIJ9{@$YmRVsnoYxBoKSE2J01Et?kqzk&mw52I>o||ph692*9+{#Mn9rwlXn`^xTqy~>dFX0kh%H92NGC-lI>B}EM*j$; z7D!^E`{Cu6kVugG%Z9kmHITQQkhqGA`d!`(KFKX<_*Vb=)=<1w7|Xi{i|1YX*kyA` ztplz<7@YNQH|_TypOu~1w@Z}k07zN8rOaH^dKKRNF4*@11-bI#yV(WekLaQ=)egt) z3OEzWdz_O6I@C)O1VSVI_>}Tyxb99~dC%VVcqe~?9J_XIM<9Il#njAa=Po+R`rFSj zG!m^Bu*7qi%qDbzNuWL>E~Q8$F4Q!yq8O{vRKsDq*1-Ev)HWjpgYs}flRupKfs%56 z_M=XLLxex=jO_yd`W5zrp#9%l0iyrQck}Wb1KA?7E!GPa6=k*2wt^huOA6|SK+E;j8YsQ=XemU^*&LxI(qE4@~i zx+-Yi`Wx2{tDT)5MSL2b)=jKQ6X-D8>+GLak1y(Vj@REe4l2L1xWRQnx1M#m;SLGl zpT}=}L;3@7Jz;fHb_vux*zmS{ST|pi>0%%pR-#0>>1;)Z4fyevZv$t@oVX5$0Ps+^ zR&oyw5I!Qt(+B%%o~(G={SFM+D2Ll<{|{l`7+l-7ZJq4cws*2)+qP}&*tTukwr$(C zZEMHLmvirZuijVn&Uve9t(t%4s+x23F-GsLx6zvCbodCA>oZ`~=!KBlTP`%u-43ht z2xaa*=&Y@LO0vTOI9Fl5@<~k;dv39#1+ts4NaqX!4h;YF*$R<^;;>OJ&AAEkYgiN& z|8%SEmcJRc-M$}Iwb_ViiD@N-i7Il)T4&->4#rtMIpOTqVmmn@mx>B#UMHY=G)ifa zfv1FoeR$BtpR^?6xS^sTqbjS4>djg)0jrv>%C16fe~l)rbc52W*3#VA_=}*SA~!lA zevnpv|H=#p;R$Mryj=X6@eO@t;R)ZZvELi8a1V3ZUdK6>ffZKf_y(pkm`v!Idn>4i zvXcJSNv596?9PtY+O2Ny0~OK?h^r=#DFU(2&uQ{yDV9e$LE~{%(1ZQ4;?#=cxwgJ- zCPZcwrLCDwi&#;ERO@H31$fh1Xt?0R)y0CRg>+0wjdU1}vsMxp0bmtHxu4YIR!r?b zlZXf~=?N{1aK2?6C!(GLPYt5tNoCx`AG9fOMXRQ%sm4?IA%)+-CRHc$;wZ$6M^#oQ z^~8!ghPaFjM$E2eYsdwN4Cjru7MTX>@2T0;ITq&iSCMCi>&HsYo&qa+U0B(9X&!GU z%vNYC`{&zg3mn*EMlwxwVO;k=XM+3Y7?FWbBICv&hf_}*GKJkthw>34ozDRId)qum zkS*=!kXAMt#~}xm${J4$4mdP6c8a!)hhF1kZ4;9a-rYFUCh#}IZ}(_=4Hg|%#nb4Y zhA0*ZP!yy^i^#r6m`|H54I2cUU2Kf1*V0Rd{A|ICj(H233RHd*pqWvZ_V#T_1{q1s zrBDuGBy4191D*3D6z_5Np2XnPVfM+hFbpkHp}~Nz*+%GqNk&+%fZ!@L8(sU4->N})V9;WT=>znw(USY00{(cnJ9q&ZF8 zC1O64ZT%D+^Vs!uS?B@W7?M6<@FZ(yQuN3}f{|Ld!>J)DB&O?xAj;pHm+#9T6+U%Hp*0L zo0Hx;y>idplsq{~H1*RK26i@_38UjV!D})@Q*OY0<&^ENFTwCi2qd|xF1tRPQSEK7 z%xhJr4h)&$Wmj}{va#~>1lN4SS5f14|4CR%?&cip&m_}mofvv${q>{I6a%^>2Pd-h z>)}DR*pC6JTh2-l~#jbr0ICmbmYjf(CL0q$(UjCQCCt*q`u)4U0$o>}Q( z!`<_qe@>5%5>V}UBi)y<8>6>sAlbZ$@i8$11bxhhys!KG zqUK43yUTK=t9K+vd{6hVXFG6Xa0YqyoXiWS@@s`42whfP|3slT2u1ptoX(<2jwGAI zRoYJL3{N1+NwW`U2peS)-AE$90OL?IS(NN(vTvq zF0rHir&x`-R_)gY!_8~>cRqRd$3M;KA-`LO*OJ;AkChJ#!i-a_8cFcO=8WCGbxy`4 zwDKo3X+n5qi9UrSc~jEd65=b5j6jYD@IBK}Wla1}sXc^o5uR6@vQ>mME(zdBJ!b8p zMAmHjbQuy*+jjc)1S3n3Y4km^`cXu3r%D=c6xW7d=v2jIam5gekH3bC(A^_9&L2Kt zG^Y}#k2zT6YyIH?)=HJ?^mUm88W^<>mWHvua{1%9`h`gk_W#ePvYQ zt_>(hIc$pUS@#sD`hdk#RzcKEs?q&9d;`}F3i*ADJ01%*BNCKN|-T8TP*$=ywgb&81azqDCHZN6u)ca=;6xQtv0UI@8e{E?1}@T z(k88cDn_X=p|l!CrX;BrrS~32HmxKXsK>ppJYhGeNIYF3J27^UNEg!Dlq#C?_DH5&HL5}sH&?h?gY5oHJe`H6bShr) zSc2_BTGv62U&~1jg`*4jb~Dg5#v5$1N1S<(Tr*Hfbut^18%IjDf4wWp z(v?a>j7hf*7VehK(=Qtm?K$;EropVyWcf#nn7KeODnX-dxf6+#*;AeZhvX|Vo?bDM znbbvi8Fxdwd}7`%#aMFnzm2wBW7Y!^AOHYT|FJTm|GzRUVQV`}T?Zi-eM1|E|L*E0 z%5ur{)53eg68OrJBKHpT4JDub>{VOmkY9=GyLbzFU7Ar|`jL$55V;uFcd7CTOLfQUnU>B&3U%7_D?ji!S?}afKI+v1jgG zjlR~$>ex<7OujK1`m2c0gZfexRAE`iKvPO;bOwdng!-61o7}3iE5-KBW;Ae_pDGdO zRd(d;h)(5x%w^eF6iO*co~5pP>Gz1R7lIuVW8-iy9{r|UO(1$XwDH%i@yf^TyOC{3 zh*ueRgr5N!i6Tr$^og{zbarnRxR5BBG0b{?mwg4o+Sf%NduI+GmI;%3`sBpYzgp#+ zmjxGq-wm?(|MX~)0l>k*0Ul)E<-gzQe}9O+udMBiX>@IL^-T@w@|{DD)8E+jF+=>Iy~9m=@ae{rIN9|L zh?vLVju6$AZ!o;2VsH2vB0l-~!jQPSW~5wFTj8cHOsb_|r~B{MW?qKB#$A<)~G;sZ2iYx2(JsV zaR!s!kM+4gJ?281(^L?`L<)m9>0-NkcllF(=E)ymz~ARPgA7mA1n`r%E3+3B*toK# zq*jF(zUh_9%v$t!82WV$tmeod38_L1$qZCZ>9dxE8l>7g3huckC-y%sJIFJ}Wmese zYESdB=r%Oikyd1n4br9`Rx|j#{1{$Zq0=W&MoQH1XK!*+SuP2DdGp>_#UhZ8MikB0 zCfZet)RJxE#jjel8C|b&K`%jqRu*Xih9e|%S%(ouFrC^Et1d&Yrr}Z!L$|Y@u}y<; z>=bIJ8j4Jm7&Q&u7WyByKsM8y1dytRM9V>A?0I_`D(NBc0+>?@)ep`j}O2s=FgeV(a4VcC<&=1)I&PHafPb zi`gQkIGq_U)X)prm&ya$O1N!URdZ?R)b5nGKPFu;8mPD|%p;trqD;JwMW{2CP6a52 z;88$Vw@mVzy`Ov>GX(iZN;0Y)12elNCo*P`rZveGtn=m?ET40WHa9tA)j}=ugHI$K zLG-5uY^kJWI~(*r~0Pp z+n0kOi|SvR#ufcx$pj{1EQ5v7{z(Q3)0*L0OTT|cR7|bfR4ZB;ONJ6Iyp_d_7HO7j z`7%Kuw8_rR=H!srXzH9$U9N8bWa}M2bLwlBqx>{r=3oT~7K$`tGc{s-31aLQ5%1PV z;n{rFnysG9%JXQso*L5>!eDT0|0^6ih`!ZNC{NeZbaVu1PkZ&*e1o@qfMV8~5_dzI zr@tNF1}$yZAi0a$Pjei$_=oc|?vqFL_}k{aCpDf88%kwA*yaac@V4-u($tVGiS}cJ z92DA=4v5%ya48CKBK=;JfVkQl$b0^g-o~XbxIo8g|JOJbcZ4hjFR%XW~-1J->n>O--^r4>WPFkQ2vg zz7;l3xnk_Q1i1L!use7$mRg6p;F{%~(y3F*Qv+-$EDHH55ba2X5+PZeHx6dgA1%z` z13&}L#N#G1PwyDHJ&RfNdPtq#{O;Bm=i?#Wpub!|dV7?n_l563kVB{m!WfW|p)6}~ zuC-9ytDfMSbp3t^7)G%YlPO6xaG$;4*#RMvd|_z^i(BlgdnZ0~YNKVhpk;&I#t^j- zc-v&hf~+!hodIN|+CI8(@#>e5t z&qE@pEd_+{2jSNNL&VSY!sjU9Mg842=3P8+LyDd^ilAx4nAu!&dLZSYyNAl0ebE`Z zPVDZKSR44+L~NQR3(8@#DKvhm0>6fb9IvOBTJeZj~C2N(#$X@&>*Na69i3LCmsV5u`hU zBSv?Z*8lTm<6B|o$Ta7+dMGYAAMujS2dKHmf2)CEbDvtzIl-1B`i8y>T|#jQvR0KP zmfj>})77uYqz-iowd%JmI>IdgAa3>eln)dIKTn8phAX8>+SpjZVs@tf+{MZrz3F4} zC|TGAA#U@_sg;L!Vd=~+6EYL1rueVcHy~P$HBNm`T*b>kIGLg zMO2zl8#@!Sz9Y)mKx)A{k#m$M@R}@s1TH*8{Iz2{J&M{IKbCSr{0egnBlC{;7rL~J zGfgY@?R-Y@Es*o~=+d`x&i}DB3!7Rv{1+37IUwdkt8L`Xnb-wy=_z9!g59{K$U?cd+Of5^Wj=*a5Y+nZV$|2O#jKc6)*cA5r= z4|%w|x;u%yG7lCT9Bh#m_Do)r=-WH|wAZo?XWev3nxXwsrIl3-`yKF;^ww#ekzYV_ z>#39Fnqj-S{u-~^8UVINT@Y0QHVLPKwFCijn0?`vjG$e?8p+PMs2to-CHPG5c}DJ! zveS<%MXmkO9I8s`Gg}67kb=`JybX@=^WWW$l zmyfKND8k4LT5@LB-HOfI)1ojDbL{TZaqxb2EUCM_LknWXK-#t^AeVhyFZ3|~n&vR& z@SF*N&_pfb^1c3Z2va<5Yq7Nf!!PsvdAd{sDAMAf#L*v-57O_9JTH3ENcV#dWv>u_ z4Gp|xiyh~8TB!DoaQ^+!{B8UxIOy6rd=HGUuKqV?is?UX0eLNJL_TD${$=tCD*nQy zwIs7jiBbzC7g|fRvY-&PM?eLA56s_f(A4b)swR8gcY%mfe~rw3W?+HXA>Y&P#s7wo=vmfSm+RW+SGm47U* zD~wnKs`yE4&O2~G%bY|XJ*ho|{2o_NZ|R!3uG$rg3a)X5=UeT>Xu5Y&dQZR_Omoo5 z!;d2iS<%LdLTMClgi4z0-OQv|{A10++ZH6MHCM~?j8kcC{dK>*17K8%#aHG#4T0W> zadY+hmTY{6iL-V}L(7&nU(o!~>ynqfw$DPHMrvwn;?uC{P;vX?C>jJGr4r&@*~%I1 zt&zp2oepS;fbN!*q}R1HE3~RJp+Wnu!Ry+1@2Uqd@LYG_m+%ZpE`+BGduv{oZ_Nod zsV^;Ig;Z5KXwvQ|QnMN`VYuk?PkZ2uE&9Sn25PV}^s!!F&S*f3yuo%64Vi_6=~|ru z|4^}O6H5vm5Z479RRFNW=C=fKDj!Ya43y%Me)3+-Bi}+1W!xc;lF1{XA6BsSHr@d* z(>OvE0CDCkMcF_Ns}9>+>=LCZq?jV;d4*qSpR!Z5{!pSXmWyrtfDYIKdHK4=<5I2|g(!(4S zK&pQ=yPSS`b{6!fNRM0+J&m@5sTNq8QYvTZMW+EQjvSKEUrA_aZ;y87rXrChVi8@# zdFzBe&YbE^HjN!{OnGS}2`Qeo=MO{efxr0>j`R|aQp&t@&qxf*s5yRTOkDl#aD6gf ziNHOdqk&cd@eKq$&yl7GJV?2K7KWicchw^!pgLy+x)mDAm{K=r>xU^uDJzGF@fVqX z#WoG9QexR@+vU z75&=A?4prp=UNrBc}7w~72e6XnI{)XkScnAbR*g)zNw%n^}swCFB0HraE8ES>uNf- zyV@q{WWgrhALTu{dY%+~C(s!RANf@OP|vWw`@%R3@+874BVfp0sLaSSxsB3Jpx+lJ z#RskUckcOEJO=VV;Yp#1gt(GfMm}!{({xu3v<@HEvqzf|F3%u_Ub1`wmN^C}RAL+N zGY=>qGIoAG71%2&<-}+cC18xEI_4N-TU`8xkrh^JNqNfr`cVeYYt=*PQk_PQyDp?k z1}3VJ)`47JZOy&q9hU>W@zp;IZ8D|2c}t%Zr$>%*;LS{$+fX+0m=uizno&_8ue}@< zSUihr43e<#lEIRiT!5B5Jtup) z{i}K0c|K%S=dYP~7g_3h^*s}l|I^9(-)AD`-_0jS2UClGn1}zXcf()s!N2a~Gtjm9 zPEh`P5C8X05vjB;k0k=nl@G;#4uTB~IRuJ@giQdEFp$g|w1d7E?gs!ywz4CkT9ByP zu{2hWB2C^M3pb*n{qB=1t{7NWK<*`~#7&-fHCyLX7xh8Uz~Nc+=J1rd+Wqx%=?swl zTccNP<6AqLH57;xMDPV2$N_tewWcJx3dyb7NV7v&D$?>m(HDIgF+4AHod3LX{dI>~kG*GRvvE76X^DrpXsgxL})eUoWXFsr9@MF&BtMPwD_eq=_y9OUh> zcgf!VGE#)z?+AlJmy;6~8YG5B(QrZaE!|@)Lr^6*bII)kEuJ8PmEJ-! zT7wtu>Ye}z+Ac~L0MPLl*pxk06{4Dj`KaDI89SrFOjEONXaBbFb(>AylbBJ^KYP(% z!xVki_I91dmNE2%*p?OvU9-s7JUWAZo2S7+90ngV@E7DiyinobM6_z zQ>#dA23z_{prc3#Kpzo1=N6Oy89Ujeu!;8>9U=|He8Z7eCKr7@UhTn!z94<$miyH+d)*5aG@8{ER2mcDRxj~s6C1y_x=`h=8li(?C z)#uc&+9#!dI5(GZfZP2ecrBmzBu(^MTA_uUJ?ek4lhFV`uvbeM-gC@xaK)KfjCK9f zag0^a-un(9v-~ZDIhT@XUNKc69Erm+P^~D&RZlZ!H@?zeTlaOduSD<=v+_p(w5-e= zJunxB)kwA}i{yQQ>Plc++q1D5nwFHqya*B(lpQ;c#h!mCOE-TjLYj*`@q>t4u(V?w zddejFqr=2La|C!K+^Kmad~^w4bg8L~D8CHZpSA-xzPs#)7U@0Eq7WG$`1v^VkZp$K zU73f$*2tncsfQ_O5HCK}i-MrEkVE-iMQgmvpr!POx#B2swS6Q+nfZqL-zUI-TbulAaTC;aF#I?AETwCu z`z>d8oS)hhxiPzCmh^xuFoE&=#8`Xse}wYKGYNTR@YU;Ngc9%hZtV z*~-vX&QEw65QqUNd;(u!&O30SnFjm-bzULNs>c#%1wQ(Dx-vYwdP@G@Ypul=x{h`lleofb#Uy?}@uR$QMCNErYYY{IXcUTg zYJ&E{Jd`lG%E*O=(G8OdC ztF8wz#{=DK1C8<-3ch#^*s3_*tIasN2{LB^c74w~ep9ly$vg*4`=*l4u|cX#lT`*e zQ?I%@-6~H;g`ro?Vh-pS@)S2_MFAo(wKrN{G%Tk;6y zG-FY98;0hRR|L!wkIC*XTdpgIGCnux301U287K{lm=vtCXuNS0Y9l3)JyHrYiVG5k z{rR!1Z%m83{s zI-SB{+`rmQRSeu`B4vT9Rnn!NW_Vhv;GkmpxmTSI>RkyvwOH7d>5RAqW`smWiC+=8 zI_9TWM>};T^Mi+M+>qhV=|4`yEHa2)um~WK8MxDkFl4B#SV!vwBdSyp;HTx7@aLKC zc|0?Wdy=fzzG z)PqY~4T9GpSt^UI{Xm?uv0^4#*1E0eZ z00q2fU#I1nkdmKT5-zei!`^0uBqD{)z4Mo%p#QB5g<*80`X1pC z*73KQpb<`6?X}TrwfaTaL&Sc8oHaE}FI8|Qqaf@%TXagi1Q;`54{tHNcuW9w*O6A7 zf;l~#zT8OwTo!?6Lxcm66^Q3ZZrzJgkJ18_5#??0^0U6 zp0o`$fw5$^_{ZN)B&&GaLs376;w=y16eL#K<=CLLo$cO+hAc0Kw}Js zq-cLQ)Yw)!woo zCYWcwkMk7@;SsS6eA0wI?(@F6tb*i(C*(pu&um`V#5W+@Z(!;Hk(3Yp-Trsyu5)*&k{Hq<>c1~Pn^^JKY|0Cx0zY3E7cRlm}4duTFGE)W0 zL&Mnd%e%>7ba|QPWp?0OGH9}24x7Vtu7M~@Vb}?=Fe!6YnjNi9G0Ey8eJqY-)YTy( z@`vI1(27gMT%^j=$P#l*f-p5xK5dRg!tjcJ;x_wlxFMg&+DJGK%r90KKx$AV|~d>*|$XtyMH&v6y+r55iDx?h^O-}2_k{?8IXTzLR=OMji}4-i$RU+lWW& z{GK8u-iT+}LgUULXF7h*Ssq{Is!!IS(mUHQ9(Z2}J>H7@d>!bD_yO{OO1e3C+4uovj0rL?fn|u~_=>V6X1UP0W&!kpWhiCRC2qNx0cObL zM2ZTsOi*4DvW=h%Qhbf#lCBfjXx&iII1AFq0UCWF^oV9b*iQN#i7UFmV*aQ&)#z z4pj&eQ^*UKjnLAMktc=^;ik(RU#gWKoOcY(@teYQ`xjNsd5nXWZ8k(J$FRH z9bPl3;7EVa56UblvmphKd?LgCRm9V;?Oyrxne@U-s45v&ODJs7Kw869=C0X6Sf@zD zYl~McDHTD6$mGuu4u=z|L*WtB_|NY6CXRCRCZ+Xg+Yq2N#gE&+wZ}{=DNm?2~CTQQh+3W#>}QVpi&oV z<3nIQf}A$VMlDCui1Q@WEnICr{bpNA!$EsxR%5kY17bQJ^TPYKrv7)Hcs8^t$Gvk`|IR%li!!Suzq44u=59eWrbSp3ITNaF#$Tlz zQjXyVCdq4-Wf~w3(QQ(8uI-_4`(mK;QVr0$BvS9hTl#vK48+>y+9}To-)12BIf}3d~4eo+n$VfUxn(d$6=r)nZjhzE)Cro$1 zT<>5FA2-+6P94tgxmxWjRlKWXG1U#fPfX0 zl)aJfyKTq}Cm4noi#-hq_8pIu6*#v%ucZM3O8h#iY%9PvN+;KNajs5O-vHf#Xd`=i z>~Kd=)u37i;g0K^k_Xxl2#j|&6wjD-Y)Ld_51yQg9Lnm@aGW3fBapraE+13AQZPhx z-fLW*+dFinGxEzb&e3t>vzp4JnBpDY4AF_N5HLw;HT#m1k8Nd{!VLp~qa=TbFPf6B zNJBvxM792o%kP%^2q72Y{jyyoj3BX7ZXG4!_P4;Zs8gu`a7Z@ASt

j&kiGd0WIYj|cBH293I-Fu!Zm}-~SItsk=Khi`z+&$K_g(5|*XmSjtN@{(U z+}&upo(KPYYXwLD)(XGgG(k%JVTFir{fWBWU!pZoHac?#(!f<8;$-VJsc_N~(&+wC zphVQr`jzqs1Mf4z1K@8#b$`jj6Lgj7knbo0HNbv}5a0va`D(ya|dTyUf`fEv9TX6*y1xaz+GOTiP1ydcvspn zHS>yLyW1suM=XV0^Ga0i2&CXn#m;=MUGZSQj|^XtoxpXM9WMU!s^M{sBGM$?^o$C>dTv}7X#T)gztL=27oDimytaMY z^rP*n?Rn3+wMA>NV5p5I*`h5F)hFJBNng2tf{{LK@)>-6Vt%EM^tzA1LLBed_Jb(s zmh9+re(j2TxJllGcmqfyk|Xuh8KDzY?&y`zZ8ii@xyL`ko8hXbf1+#KzJ|i!$Wef` zf78w^y}b!#W`0@j*6VrkP*i03hZE)MMaIRkN$+v#A=HJq&K$E4_G+Beq)WAQvg|dX z5??607FA*an^BuOo?T;AWPlU>O!Gh+H<0&ZAxTX*!8%u;g7bNy>f^6wv?hHxxwVI8 z{b_Y0pI3=5%Z+!ARf(3dGnP?_(|JwjWE)+&!f&^+6D>V1IH`f>|Pb#6z*7pNGlz z@&fv&p_A{#5W}L`2qMk?h%(!o`Vqv0K=E4;DIWxTen1A9cF9pHTaNflkqT20NV!zF zLWMw35y`34=%EZ1x>Px$B;6)iJ@G01S)N=d&sQPXnDh_oyv&|*!4kI73?-w9q)27WdZ|4BW#d*v|A%!r5Vyv8CBL4 zBAFV3?KO68#+2U7TzOkP@Tw5n2JY6rHpDA#R~@JB%5E#byG8qt4}@lbEb2}2bO!)@ z=g-j587-*iQ8@i%UNX1^cwaQ8cad8a_Vag~yulm&zlvziE4ghv7yy7?tbZz^{~2uk zuDqnItxUh^2LI_P{k!^VR5o|UQbF0&mmri#drl;dN(*8alQ0+!-CO!qU^>t0MdXyw z5~;;P?2{_0FBVD}7>mtfnajC$Crws;M|_9^2{;!=Y6cCsT=QDkSvvNG; zQZZuZuV!d^y0P5qo^5}{=6t2`)n<#-W3>TI;Mo6& zN@5T7GYi?48yGJuF0k1Df{U;-TJ$=9&RtoVhqymF{8Zf0bOkjCpoj1p8$ve9?e`DbEy$_^pBs(%H3)(Z@~u3$PG7Q+$FGp;J#)Yg%FAWLORS$= z7(LC54J5;GkI|E|Q$)eVLGehK4RSE&py7e?tCR`F6Ym|16Tf}h^aVs-U(Fp1wddip zM$s5V!UHv1P0UvkDc4d1T$dybD}m8oWk~Mo;fSUVD?rAjiNaI;oo*ux+h5;CnBtp^ zCSN?*Of&26Ft4njdosm+IUa)THac|rUrp{BT&E-_lI>pv=~c+D&r|1iuqcbDU@S*9 zd)b+JoX6@&CKX(#9Eiio73xn%naNe;~X|ge*CGNRmzh`8dZ*yuCdm*Dq51<6l8cZO|d7; zVu4B>5L}%?p?|Xi+WOspH({_uO)ZMRD2r6BE^o9thJ1N1&ql$Rl4dUvT%3q;6*SWD zu`-hrwADNc!$N2_Z6!jef`#e2hXX4P^KFf$(E;LlkjaaNpGZZvUI!_2Fn35vhc?a2DCiTVXFFb3ypWM$59cc!xsyX67!kq^*Pl%MgY{ypBtziF^tlMqk)DZGMnA9 zaEu&*h{vk4h;4G;sB^5j#0yShddHGcFWr7g@QMt#jfcIgYP?1g4a(4XNo5QbEn@*o zBK!1Q=kgEXb( zI;RZECMDa^_PF&nWINW3Romm|6KwtgE5nJF6&9vqUJEv&Pa%c$G4G}UpVI;vvM7R9 zV~0k`5pnx|M60Z{Bx?8z1KaCNt)}hP2988+`E0^*tje(T3CmI$%;8Z5KbZ=pY_0tv zB~aT=LQ9qsN@S(S%dcmPdxE|vOFSLNC)ME*|sel-r{wAu>D za0*reP=~lbo(M$8sOKz6R;@0MPY|$ota+H2*$2!(%UFE;87W5Y@a!hrd2wdXy62q{ z(#us2-2=2Qzg0-rrI>uN-^9PQNH#aNbZXXH1qfayJF1c8oC-y|6GTo5hFFbX z=kb%E@rE(~MpEj)U;DtHb?hXBWj{h1sAUpmLk;c;dpAo5vWUwlUm3o6`Sc_z=Uoz9JL|Zy`AH@11CT|dj~AVFf28I z;Vt3YnU^i0IL}l_7f%m6a1DpiV@>_A-N(Ct83S*LonQ&oQe{toQ{VDiU~~d91y2N1 zFQfIrruyXG#kOOQ<`L|9+lb-j4R@Q52%ku5Ul%A?kDQ;V(cMC|%w!u0;S`)+O}nZc z&c(#Kt8#E3XieTqGapf9U^str`m@Y+ryFbRMv717B2RvDR|0NsuY7)Z=h^=xb4Ze4 z5n>Ou6m?w=xx|Zj;z7}vn0;8`$JH3ohibJr)7rI*Xj@%V7HaUzDi6`(o}1n9TO10Gu{s2^=d0E;W{&Bu zI2$gfvE*8~ul4;?1-hn{V5}&3|Mf3LHkie&fzWSOEAl^{=pp?_uw35I-rCVl-|*kt zdtv;#3=-dWFZI;0nX(Ysge;^4Uz}!S?*mYQj#x?(k~lE#Id3(o*22N z5eXqpeh<8-p^4=bt(KM9aN62jL{OW#M%(O)K@9F`kQEw6-|7apz(J`i@7!pe)lH^V z`%ooU<&qt2x?^QywOU(>dpN?I>@{sgf>e2~nTYyFOgUA(ZFOmr_O?oU)0R9%hrUxK zd$Ho_g)5M>^m5k5?w=?urgzfBNf?Gq{9cCr67zY;UgJsUjtdtXzTX(Bo)2K&hus_pX(r=gj?QgU4lzx#?NCaqopBINfjS{%Gg? zEMJFW5pDIY7c(%o%5lZeteaFHI!<5GHG*Gx=pW@Ld|^ilL<*A5eEYzYS98g;ENMJ| zZ-RW_5SS>hKj2Pg1SI8=orOg8#(X37*MJg4$r{1{4xn`4&lC{B=T(Wu^u@alV~n&K zMG$A9KLSD(dnnx`PobwB8%4OwfGEj+ivdzdxl>EPK)y%F((sB+?TzOS8qyx)Y~4i+ z+`UwTCqs2IC_C(RVALSqqa#ip*^Y{J`i$d7DsTu2(Boc`{pU+C1c5GJs~Pgm`eJx&G8^3^&XX@ z`ga)f9_Gi{em4oC|MBSmKQ{{gD~y%C*;Dra70Vj-bF%QmUtpxZ@DkRlrOQ9na~ew5 z-16D?9f}xm1RTOH-+Z(9X^A8eGj1oX_shF-_Wh%|pL4NUe6{hN24aJ`jw#)}-nKX6 zv%9-I!D@Vs=?xA%>@|dOoeeey!y?5zhGx=dr_1?~|DSPXL` zLYq$31Z2AEozk+;-ZSXA!yt=c>=Fz2m4zSuriDJT{rQBtqmQ?(L-Mmb)uA zAH&!r{IUXr)^Q3MkFg1Q!nlh!AjmSkC)}l_%-X+9*>G&!frAW1M-@2w!NowRgm+;M z-TtLg_lq-;bs*{wcD%0J2Gz3Pvld~>)(HC2hb#ygDWsx>XiM=9H?HW4VohK$A}(1< zzdneJ$2~F%$U6SPSb%F3(j&-mS3F;vZLC1qVArUCaLwtceQi(nxa1TE&_4m$axL>eu*Nq?NSV z@Yg09rgH^=he;)&td&5}usHOYa<>fcfOwvZXtZYU0N#V%vdgK=R4GFyX<41q?C#f% zPwe(xU+?cQJwgeLM0B~k0ML=^5}4HcVVcChoRstw>^KVd(t-k@r9_E*&&jPyTF7W^ zyo(Za$|$Rllf(;CUlIfF_AvnEP+4Ui&SADI-o}fNRORqteY4h`HvbfZZ849>3aWQo z1ov2{L-m-ZXGuO`wxY{Dva*DdG$6-1l9;d2%Gcb6d^eh@WM)PCc06lBsW(jFEi=b0 zw&{oVb$G)3u{Lp@)_Ay{zzgy;^wl7n#AUMh+i~#@^@1gXb1ahgK#UJxZu3v&P=_IR z@qk^|pkukV!v<*oo_Uf^%mI?2wc3`|M%p$gD3a#5hmA(?=UTT9jB2;cP~p zlPTp^s!UPzGg(emR3F+6`G7o7G>SAyuJY*n!R#xSh%WDA^`6p|^cC3JVit=KnCA_R zMH`)6>sdic49F@NyZvH!wzr@&!Tt@wE#WzMbgv2F=3yax6ejwsS|QQ8qG{$b;88oY zDxDZUgp?p%Y+<9MsTm>(xV08nve?=1r^qvX{y*?E=qTf?K=**9f8??R=%R89>Ez-- zKxJE@cu7zSr?cHMai`;K^Err%k;OWT9uDP`8G?yJd3>FVSb^2TUc)O^)lXy#(BRsf z1zWh|8rOu#Q3iHOGMhKMk2bi)Zef_A=>AdroU-lE9?Bpox;S@ep!%MJ8I-A$p8t=w zcZ{xl{k8_Hf{JZbDz4kJDr1Yd-Dy zn`^B(=d+feoGS$7OSs$fu^IejQWVv=*N_&&!%@8TL)`Ctu`fn6Df{SB&oIcbu6Zhg ztc-Wp)qambHbG_G-xB+e*&b>NwX7ZLOybvuN$m+L7~lU|b(}lqRssP`u_yoief{tA zv;Sq1-POXx&BXD)Nzk(WS6}Ae|M{PHFDAx71w`4v(Aq@C&e+8IKP4qu4aOZ;1?`=z zeZ-nIk$Iztg2YC~LMl;a&L*#rpP*0%M?yw%HFy+6le9f?B4xz3Ew+GL84)QdbaXD? z->}v{m!hGRfImJ04G{@xkc=`c9}<%HD&QkMecYCfYS25K>0y)Oq5JUlaNX&G_dVwY zAEXBCIoTDRx%i)w{;EEdt? zR&LzzR1dkwOFT5W=h`n@XhGS?S3F2^kpx?*i%gWh zxjP!*Cn;Sm=?sd{G3Vk%h6FzHv9~w`Ojue?EXMaV2rk4%8ByYlXg2k?s+1+m`58q# zDXQ`twJP|tLMzhiur330Sd_|KX`=HBWgCpSb{C`Yx7ej{KD5MqXte^?9iWa> z000cRNqLbRHj_^L<`*ncr0>k@ti@E5)D}oCU;92z%7|`9+!olMk&f>*05@mY; zc*R|<$j~ri;cA3C3$3Whb1O%RfAmxwF_8QceO^dSg*J~rgfPh!sO^d_2TGSkppopF z($fF^Yjm3>^Z{PXLvpkkW1*6$-l+J)+!ilS)(Z0sRdgEQ94x<*UH}v>IuXUgl-T45 z>j%FEuVb<}YcgXnvtr!jcPuLdh)Pmm>e}f}T2YYQWp;E&>1A8dpQ-cs@hQrq6-Nzx z3}+Q#Otki>bluE?$Mh_P@L0((fzU3=HjxkhAW$KlKFYi;R0veL(J{hW4lN7LbRMw? zPsVR{oZ%D=yvV8#s{JO9Y{e-0r9E*)S(yDGPz-$o5IHCf$HT58prnv0H#cXos$65i z+<|~cP0^}eAzOHRL+p#qIa9dJY`w=zZXCc`-S|p(dTa(lFTS6}YIb*%CWkz>(fRsoqEkew2>61x4lHEJAFw=J9mlG zQJ_D`MFs$D?RWs1Pj6#lp2NM%MrVjOtse1o(P#atw-MY!_H*NkSXR1t37%rzlP#3C zzEv)%`(d+m(4v$%qHrdJrvdn&e&M()_2*ng0J_5-%fq_EAKS;FZf|k!kjC;oxeQLg z@A08cVU6d~pLK&i(hd5>=jlq9P-dQY(QuQsiZ_^}(`>6`2kSuBGftbtq6ET&9&!Jo>+r zE_hvUCY>>VY-E0sE*CKE$V{Dk*`avJHA0hXCYu$dG(zlFj$os*jD7(wQ`CBC&Ga^% zz!ry>;T2h@RB(bk*X(DeR@YlEHFe}>Mz3}Z82Pb|`{vm;wk-S633aM6C;w_~5K@1t zZMM$5ziyhYK?gD5=`frsA^Uqq=(D35xR3p``1HI8Tq2)bwgDN#;etcJ$6KT5q+~f} z1!x>{&> z0^>weh)N;X53$KJgCQ(KzxY#stB+el<2X5%th2_sI#RdQ!x;YYeH{lLyS2hgNd}WK zs^mFOJNr%Q{KX8kn2Tfi0!1ZTQ#%MVO79%BbqEsnn1oAS_xrvvQ;G}|ue>kCvhCh< z-n}Q+5DH)K!Cp5E>~izDw6Uk#`b`2x&ug$tPT*fal-l|iOad$=S?H5zF(92U1{*el z>3Ux%Vui8xOPNh5ihg07U4 ziJi4mvr;Zlu)9p$yd*iTL}{TOHIw>P76GJOg9QG(U)3?2e` zxJU4)6Wm1z>6MEv5(fOs+Y*56?-vJ2?rl?;cLg_Ni8U0BLF8h71B=w+7tmTEDNNYK zp}CZ_HYpGOPB|GOp$-lz&OX+_5%qFvYk<7Sfa0`WoljeGTIkBrv>$)rwsb{gQOSf6 zG+)C&x6M7HNifM4y$#tX!CJ#n55|@^@6?RQbro_(w2vi%r&r&>QFJhEe7Pv!Yt@6a zJQ>A{4`cuN=0)(}F7z5!a~r#%&ruOpvUSZK&4rrMxN^mdA+-7d_1S~Mo11_|I|U;R ziuZ7ozV`6_-R&EI`v?oZLG4@vSVJJ%G!YRT^`Z^4nZ=-`JJY4NK%RUu`^#Og z06HC798%Wm`=~YWYkN=7oEXst0eun8{?R|sxT8XJkZ(#G3SVZgGjC!$an-K3)X4VVNP0+!e!(2zNeg+oY0~_W z;SfEk3Tzv&XGFl@>OF=x%xR`@s%&EFVt54b^qdh*0*2xp!1^OaXBrTaCUjifuGU0q zKD@nCuH%1*XdmyR>>6FK44H*Zf$yr1V+N~Zrhug=LN1fXK;e$vlcz-2bZ3_1l9g91 zhwhsE0z)E;P^Z`-Mk0$e$8z`uQqG>ma+uU(iE}7?!M+%5=J}B4(k&$q6N{xG~YV?V@s*kDV%hZnO=Dpi4N90eF0wXr6pM#Gj zBF8OK$1N)LsO2tDS+oT2XOEb7!Lw2uS#vuD%|npY8wQ0BZGAeAAZK3jrEiM5mR7cw zH?qI=vvyF!HJgp=x7VN++F^9%44!;B5Gof%+SeO@f3BkGwMA*LA13Pf)R4tJ){atd z+{0uAdvTXr?qQfXwPvz_;*y^owKHD?+Ww1gX3bf@$nC?ns`A>|y4G9QsME#@eU9mp zEHFaNV!}##ektACPXFuXfZ+QylPMZ6wl3>g`FhcriUs`+OE=xfOIooq8TO-;2oj6c()x6)gg9I(Z0ME(Ed)&1SG z0ym*6xd9(<|20wm6M0Qm7?TA7Mqa_4^>Iazwx+;gf{)CB8nmsrG&72f@J4E_;K(!q z6X+2e<{JhIemD$YPb}kR45rReA8Dt}#qRo?)7GY*?&k_4jv&+`X;}T$0a#PGajZ19 znjZS~ecj$WEgL;3GzMudnazDQ*X6`ATYS|nLN3_!lg0>a!UWp>UscMCt43*5?-P^ZaO{JCs!}B$lS%s4uuf%Q`V8TCtqAWd2 zsT5bS$4q*FF4QV1pn=(Wt-$R!MKXS`*=zW-(;rH=!YWFEs zUNRTQ2r6pV5~TRDOH)Vc7pQkh)6&8{KyyE-1#4IgikLoS0L+$R;*9t@O?t-&HOZDT z<`|6gQUZi2E!v1S#tURZ&1MO{3Tj|B-6LQqvzZ!P7S&o!R!vfBHm5!X*OC)PcgFF6 zW=r)&d|YL2o>V(vFBz$JYW=*FPV_DWiJGYS< zPXpGp!zLi!xvR$3Mq?|@#Kch6^4ArHOTEaJQ)YV#)v!t!gWd+JM?ldx*xh*n%qZJL zHL%IA5knP{ivU;_Hfq1g<_H`Rv)N~Wg$=~P-Ts}VM*B>c*4UH{cpE|kvN*-K$1wye zRQce!41T(n)Ql78n5)D|2(~42N2ybWVRYuzI3X5!X(9jCOc4kui#d2Z?)VAkayHKP zjNgZYD99O!ozyv*v@g+7(4(cpGRsMm|Mr-SDLQHee?q4di|}5@Y|)`48>9yAuaX=j995{m0`-a@pif)1lSHjl$NPD`vDoH2v7{^v*sZ_{5+-Uj+$c36+ddRXq@ zMFC@&Xf2M)Os9;qVrgdK2IL6^RB!BEtojBcJ*SvaKg{(tJQBXB)>!Jpu|n(@9vbTl ze;)Cw-()12RbZ^+&8oOAY?89xRGF+8k%MT5^8VbHM-@DY0z3_d|4b- zrLdY#QFc;ZE;Q40kfC*laqkCdvmLgy>~t(Kqz{uv`9W^F)&eY8>APzUr~WB>{k`fp`MLTUX@;lrg*ll^fG{5QLA@{M)rF~bN z&9OZ}uEHX}WENU4jtUfzM^Aq`oF22I3N4~*dxfbqf+l`J*y*2|ek4!!i2~pa_{J_q zTlL4zGz6J8hF|28v^ErBG5bQyg#uVhUk2Q3QQg!us#n^x(AaOSTs3%v{s#yN&O74ZR7WxxRdL<*KE#urt;(+cj4OuUQw5Pw3+^E+68P?@%I z=L)o)Tcs_P|$sPXFyIzW;Jnz&~VWXC~-qXJz8}cfjQTtXGO_wsZW5JQ*#(D?m_1 zXo#ac{5vV^otOR*?zxJExu}Sh*F7++>{4~TjpdDr2~&cSbd;$GzkVRr+X}U(5(1?T(j^0^ zRYErtd}5b)!Bm{oGh-Dq=1Haa9e3B%Ti0b^Ni*+dpxjhPJSv2sM`g)_q)1N4YK&mI zuw@XZo;af(V}+`jmCfQR?2zd^8th;S>|n;Wu2_lACKUNj17Qw?O;y2tv4D`>$fqyu zSO7trFWfQUBG^m4k@c1R^0Sz_J^k4aO-zWsg0PvPn+W}vQ2{V6?LH*#sRp*x zBK)2n=+c&JhyChKnlkwLxAC4uBQ%2#Q~)b-0Cxctr25G~J_( zW1s_2#uFQq+QY!t{ktME$mNDRepqHv<@DH-F`EaDBONqw2u!jEdhpH!2wW%Wch4AZ zS&YWQ%#F<*W35Z>6ILZQk*CTn4gXapbA~5v9)V>t_V4u-|NGr}EdMXk9Z<6Se;|wg zZ{beK2DmE)(YGlyGjmBWTz|pPrx&`RF84NZNI0C7H1zxYZMjAaIDB>UL|x&PS^B)? z>tAQf%&M75i%K0wHYUd>xNpYCC#Uqb{63lIB?d*hAfzf>*~8#)tPkNKxH(J-p*`qW zx4HkyABtnyHP^IZUyqO9Lh}NV>V(J}?-*zNL>CY*qrK`-G zH4!#^BP9D`r-pYT-xWcw|5uHb{gYt6=sE z27O3g{CJQM>#F%J92QP!UwcS^nI)m^=dXEdhh!%ug&6;QLrT%HQf4zxwL!^;fzSQ- zgs8_|-t@(D>#s}Gv!zN>Ps$qoH{Euf2CZKwbARWB zB|sn)^C-)^)gJT?bAsm7q5>pM$&u$@G0w7Kk8Nr2P8sASC`;{NWj9jh(oCq3W!gM% z-yStNXNwjJW%i9o!Y1si-@7qBQ{9fWI9HKv=UQ?JJ)-_rYNUB4$zOa6bG%ixPuZc& zqlvh=&AM44)AuzB%=EJY8UFBpZKr<0jRqeD^fQPp*QZT$)AnqZMYb?6tdioVxABpd zGEhWscMON;aFVp2Gb^~-nrR*u+jd!KIAcW?r1UEewFZVniF9i;#Z>>924=xPOW=Wk zmew;4xhapy)3?8_Gp;RD^z=nUXQvF&tIpZmrpTWj6 zg2BK2>WDT{e2JGT>yoA(&kZA$g zOj3awH)|DPJogYg`wXtBe>dv7!*{Z%;o5SA0yevpcepP-0T@5|=skjUc%^m%nNd{q;9Qqb* z7r6JRX^JUEVJP25dwPo0tR0mToH`gN%m z9s~Dby?*&pJ$~(PY@)tVIHFia_XsPvj?%7ShUbuxt-Ddq$FmNCmIWs3BS+_^z7I8N z;QN~OACKUFz$WLt#`$L@l)%3XHl}~T_8)fBm8=KU#JKD_8G( zhzt4r0xv9GDk`|zBd&bZ5H}L%z65<#2(xNNp5^B!;%Ks)y z1Ho#`u`JpsT)hT={;Mkbd$bp;D`vzBy`+^5AcbzhAA(GP9hEyJs1qqR7XM0uxJb}J z4?dgfNuUHYT{vAi7E4kLKhc`Jj+{7!3@Ids(Ya&L{6q)P*Yz6)P=`;lLy!Lu?1^)0 z7*X-W2)kpOOW2tM0i#I|in*>PK{)S=TTq%SZk9LNI4N{358p?fFoKg8Q-~eO+uw8; z8z|8eWHB@-OpN7c`i<^(^`{B3;f>w5d>IjH;1=}SLxb_9B;tE_U2ewH1g3v&pqT)MjkwQz9 z%aK)U0F@KKEx5^C*Df6Txf`uh>L1Qyhsk&67T6*C12aEa9eFSy%s&3*){Xfen9bP!DWbZ9^?<09KK+^)IC7#h z$qhjd5Q1oE;sWb$aCZS1dquVx38YF1t~+FiAiiK0sNoR2{;`7E#c1N7pQDXmo(~>@ zmTF_S&&M?yKi&j2tTsb!lnjbiOIeYX#`mfW@@+tX4JaGjGHkl>ufal2p$VuTycnT< zc;e@wZwGNNo$cN`BScsZWWV{M`qUU#VL<7iet5yI1T6_L#)TgukNL!|BVc0R8#3>+ z25myOClDOE2dv}Aax!|-a`JjW%N{{@(-6v?9m?uJnSKhoBZf4dzZSujx@Ja?(6(fz z2+g!dp@YpHDZvmWS}|E}$jVEDq>VwQC1VtSw1xI4_^nJ!gf!S45XPF)<&3go6Y}nk z8rSmryNCVC``o=2BpqU#-ErSY&ZN;(QBP)@CXL<30Nex=4Th^kvnAv^cuZRWAY`qj zzXxMHW4^%98|n6GZZa;3(fXBvfJ8+x9*bFPUss11wSTn&zP(HCWA^=xI?T3PKKS6V zh6;Iw^vg-J&U>eHdg@5U)!N629k#!0(mTYk{s3e8AdguNtd{MZ7Q@lgG)u99ypKE^ z{E1e6Z6H&_RQy6g=XF|gmYja_l=^d;;We`vB79u2?QhCzs!06>|9iuvHi1iaZaSELQ9}QlcrInmKIe* z{<(mmR2U_(^85VduSl$v&*-UHrdZ~$7)JAa^rgTP$PkYTLtHR31=z_lrU#Q7Oo!QC z7vs$rdR-tTdGP_^ROl(S76veCcg{3Ib1pC<>-4oYJ4H~T1eMRdCF({co{ZIv z+km#3gAWqRggpV?-2#%KCYwvuXEF#EIF>z9Z0l1|*-kJ(5$i(&sQRHJ0RCY8t)uuI88c$vOX#kNt}i@jUf8$D#4EV&rCo#8hY%M|8(|P?y8> z7IHLNW}Z(<#h0_jVaf|{5Guc+*>-=iNln)XPy3$P5|0GI8B&+ zBYGofp=zaq`#aAlrDTfPZuT2-q(d!goQpW7O{0y+xJ$bU_Jh||&3=-IxF0`LYqLwJ ziK%hebI9|MiN#-m;{*gG^LDDj{~usv{hJvTb*xbTthBJ^+BiO1UA0_TtZG6yrIf)a zql+jJ5x}&`n|=6w>&kY@T$=tn<(;}0;j$NF2Es4t)>Io&I2iBe-oakB)0E8h%~ERh zC*a*GF}NjU>0Qr29QE*8>|N6+mH@1+rTw9l9#c~txiXaG2MP41W}djg86S>WXGvMp zribyB<~?1FADu1;;3qF;Lk}aTnJQl`0QfM@nu#Op9Ec@n%R8U>j+!iwIxk9U?42YZMkK$xOtP2V4>uS}Do&Rhz;zU)qG67{# zRLt^}AY#%+1r(r8=a| zrMB2(kvnl3j9dQESo)HFqkVO1ExW3FpObu= zji3Kx@DTzZl>057!|jjRmTNA%3Z#6JA&?i#L5(5r!JP-Cvt8Uja7YYHh^hc;9Jv2- zp=A5N-~h~S^UTS#PqeYFBJgS9G$Jr0%YvfeqbfuO)~p&fUL>B`FgkE4nUPVvX$0c` z3gYV#o9QOn)Bp_(iwjw4b-D+_VS`K0&-WcfABF9-WZN;&LR-QfZHz(HP&=}gl79E4 zO?wS>`DewcgiFOW??~T$)0aB-4kEGdvOh=0@4s@r0M?zX8k*0u`F$?tA9+2p>PLMh zE90N~%^c$om}u6d&g zn8(t}9+gh1Ugjn1R#vVfc$#j)5Fq81*14jRWhitO!b4+XDx-;rYOdfJ>hF39{B>rb zw8h1on7YsHx1zs_!Wc3L1(=5JP}!zY<4{)!)yVWYqE8=_WyJ z6hvtzqadL_JUWY$>~@kqxEq6&>5`k{4#d*E$wS#Zg`7gI1~cn(XJ6fM3Tas4<8Rwt!-4yg`3uCc~kc`{X)R+2}Sflx+0~8B2xN#crgFzR-1O6Qkt9hkV07b5dhJ!1OVXznCR!{LCjna|t(&pJdPHig-1UKqIga!$%<`WSp*OhDjxOqV?4~t=M5Bki9F2rVenwAnk(|r z$;!jBvuToK_@PO~yzqZ8@$wfYL|Kc?R&oAdBIOW>iJU)}h(=|bL5))aVuE0qTzMt6 z+EZvWtLK?7%cRY5pcse=Zxpv;ia{}(1~_r zYit)$j4xR9{+0&{96k-h!3tGCeMDryAOiXC-M`%69!BP_N+2Ha{$)IH{DTJ_t3MRc zoZ*_m!m6por=|5DintR%%|iz_uo|@7B3oNC-f=CSlvRBFnM5CXR53-_+*uhg8hc(Azpdm-+1M#I z*=5>n1+!b(E?08VP2-)@IU>9tfb>j|H}_ro;Qn(S@a=N?w6sj`6ku4#mCl6?!<4r% zeG;L8$$*d4s+azA@X%boeskh!ov{HYii+;(dg9mboHs-0Q!98HZsVcB$*P>wM3uLt zYTP@0t77VS>yCshN8dN8V2N&TKfYj zBK|bL_`VHvlH1@ZXHrqgGo@Q3OfxT>D=~?1oWqxCZ}uX~zV>AYO?97FW(?BQcp_AG zPfN_b$e4s3Wr)aJ>K<)Q_v4eLU*CK?@E_&;bAkTz+;#jxkQ7@u)Ms_OV?EId*R>1RQthu}bOM zh^c2+R51#VhF0leblE6m>osSDa|_wpZwAotLY2Wu9siwrtCs{+I)550`?Ak^PjdLHVZ>b+EtbF~7shFYvDd?)tC4`!@V+A#M zFZ6`ER(uV5G)2lv(IqdnGo@i5r7}YL4KLg364dq^pd~;m3_EQg3LpZCP*Y&A(j&w@ zd%4^LosFqJ_#IIEW${Y79{|Dzhe|Irim*h~A53Y@xn7xGO$lf4L_9{(Fz2{YMZIDW zW)b9t{va}u7&^sw!Ie!sQTXlqj-SZy!!X?#4P1V~Hrp6!L7Zx+?pW(Ne|A`{k$Lko z7x$9xz9VX8-wsV4EMq{cUuG1a8BfQdTldnd#@s5F+X;(9Haox~A<}dSLs9v~yn1Gz z$rvY1G#LXR%b5y&foWLzMj5Vo-@0X);x59TR@gqBE98Upd0+vF$P45IL#_CH0A|_` zIdvq5&?@Bh8_$p9aRzlxuPFX!sz5!?05x+sAsw{O+9X;tO5{Zjcqi{I0qI}iip}q6 z6L~?n1WTeB>OgFQ+x-`ZLTC{^%HvpX=a3zO!)Ssrar$v#h$b4gMom2TL0VQc?6$Fa zTs+w}R}lVF^**B7PVIq18tRvSRd#3m$Ls<6h$sw*Jc-ur6RrgE(+S<=**T;bs zw%^%nv+k$oD4H+$l6;1CjtU<7V7}tZ=aXbkr~Zg%t3sp=OiI_0BUk<#Ry^cj8Y9+K zk)UVN>{C7Dn56!3yi`)I?IBf^=*C`EqZw{5vqD;jo6FZ|?L?x4mPO+1FIhikRx4LEtxsr_1*6-X0-w`2!|9Sz_Kuxl-Bt}a}R(FSJb3% zQ7Tr=#z^W0+J0vl`nGL;=RZ z#JE`gCV5qWVNszZBq{{>SzUcU$!TMrdr{ zdY;({OyWOG#^!8wfi4frf+AIssrN;LvDIQ3Q4LjMu7QmC7L;%J1aywK36?!j;>T0l zIMAo;U*=_6a*~lTX>q&VCjq-xU_Ttszk3vPMRd(+mOT7@n+&9L(wosO7CgU;hakYT z2(B|d6YgiHQcyyCL`LGIu#WpqRv*z3*I9K1es(nn+bx} zJQp)(!kUedA(6*Jit<4dFeq!j^Uhrerb@+9*u^5GBb^By zXnvEdxkEvHqX{!{xykR2?oQHzNIEd{ImfEN>w-!6feM{>kptriuO&>gWxxU3@PI{w zM*0D|Y7#a3`YWnxTh6yG{i{C{QbP>;Y6(l#+hm4CaLJ&$e)Uo&T*V@Fm&l#lf8gLq z_!j?XLL&TcOWpt2k7NAD9{In)p|Z)hk+snyOo7wp{{e@VtoRj)2tHt#(dX!Y4~IjH zPp&l!{K0Eb==Nm2Iu(QJu?}=YfS!E(ld?{tnk)@9@jHoqp@c%3d$BrP?i3W6;yq*2 z$ka(+;)g}-vq~?*Y4%s^*SHQ~D_m;&nBHS+#+nWx2BI+aHIbib4zL+5_q@kj;yd!w z(bP%hD@Ad?2efE!%_p!~wxPJwFYR=7;;1(4x`KrUU==o;DO2+f|~Z8`9DQoR)#a0G1%c<;u~y*n2s;RoMJzS}sI|(qv#&S{IYzpIr9uSy&Y< zl_uDF5KHn3xbx#2bKVdCNa^t=W410^#s-i6i^~>!f#*Ira*#Eu7KP_ct7(9yo2K(Xwy8qNcRz5p)^7{{@E- zcFQH~^6r}=;HhW>>KePnOsy8x`bX@At*gJ5MuVPd3jKit(Z39be+&%Z0hK?>@@Ab0 zTtJ_GkG>K3y*%_dUKCJ5ri_bYjjnxp`8Hy9-yY2At???z>=_g zn&>sj!?wid>-z$q8+i&RtS(m*ECoetL^Na?Ma9qrma-wfw5Ah~HNGtPXEKVXmZ@a} zl0!C-97w5{l(=gTXjXibEX;oU1Pt|tjz<4H28t)<0DS1*O^1oC4&;b;J$aO6Op#AIH>ljYRKSAdxm(1C<_6Rst z;VQbAG+mlf+|eewEb&eW4)f#(kRu+=qZy{U5ZN&tNNXNhLoWW~ zYVjA71=ayULHRF(;vc)=Z;nW;S}|?^j=c7~uv(&Em@G?moJhEADWGmcFv~VGa?hIH zvO!Tl2ll_zjHX_oh!U{U`S82-Fq?~u&(G)Mvp(p9WsCnQQdtW_!2$Heh0%7>GRtc0 zhnqf@_LzEcroTXd^u}-y2YBW?dHQ&+6TOJuF^Xb`OQ^W!R@^^#3{*982r?~WE6afZztcC zGG?pp0T>^)o#$3YD-XI@$c(d!2nVt-Y1Yx=l;BC}^;XA}H&eYj z2?}L_s!9xs4*QN0YMRB%_E*_CN&P&`w5!(rLrn)H1ZIwbS^g!BtcRzg>AgtxeSC~- z+sCITyxwZ)3yy(Iy}gqDR2)%EMU3u4~d)hn2)nb?EE-^eg8fn8Ok1)0VgW-Mm z_#sn>(dpHYlW2q=B<`V_mtD#loJO+B-VMQ26-vDebqCm9cP07{`_F$p*6r$vTo?nQ zMe|=q%Rhd=|5{O48#RHNn+?8Uk}TC(BB7-MqAE?ntxsL61gWi=F{8|#z%3n=uRp^3 zC%+_jGgwGML3Go@$rT`pxLv$HKAmy-+gQ)X{gMQ5XiwO~l~XJ#YRlEq(qBM$Hnh^z zsHiWco-|TI5L2yf;fBcBw40JXCV!g+!*#H!hY!VlB#~B62~>3g;O1u!UNRaX*n23h-H34WTAbZ%rFl&52@|xLgh$xpsjm^9{ig= zk`hjGtAK#`mlZe0e>8dJGub~KC#aQF>fmC8KXe_XB?UeVWLg-5LK0X#nh})WL=E0* z<(VuKSK%YAtt>uburhc~jZI6cCjng3A536s_`a`_r?n|tZK>T1fr5sJ=EUd=YBYDy4;MK%3 z3QE{S@b1Zn)?uzylo!I;%|x*4^<|0nsPC8`_+h>9KUB3YE=9T0342-HmG4G1LlhRi zjn-9y)FOS4ugbKw-ORNArTyn=k&Nf(KaAAj^&lyW}G_XAPpbI@f8LgRk zCrwQxb0|NEWZkVM3Jsz>&FIo|4?y5Hd$(w-1NPluXFczYelaju|A-FL*VKzb#AOq) zhgbk^k{RXY#5za>sSvq?W)j+><*rX26NNLC*s?QtLsAY9RJ~YI4bz_HMnc(?G z^MMcGJrQi?-ozY~I(}R|ui^M}u*9j8Vn5I1T%|#URg0{OqjRhg;qk3# zf(bH_1lui>c--S(k=(I)A5R#90$5eK3#2F(0q`U&?p?XvmHoI48M%B@@yKon}*;PJFHp zYY%jKpQDI!1{92`ar^g)0rrJBE4Hv&n7t~IzZKqEi_C_o*)f~x15UBq4Gd=olEO1! zp;T`2$JzVSa7N4ePdl_xV(?YTmT>)CMprI{mBfeP%3&D2DU1nVxzR?k0LBhf@+^5B zj2`KCkl99QKV1(@-9vhRhM@IM?|KHP+g79odrwO75_H;BLV=&cVx#G&b4fx7bW}h$9=a8K)J4GnbG*&UJBX{J6t|WDWPf}(3BnUMbc{T# z-j9euU02?&1nrz{huW}eDyU3Jc^0PZy890Zm}$T?Wq&;=v$v;Dh*2GY@p?ezc?hfZ-QOEe)hRW@B|l2V$tjbh?Ac1zxMO1 zG=L%{=a>h;f1jdH#(OVc4j2>n$ln!#EkZ3<6lMYJMtg=(DJW~R5T>RE$1-o|4IdFd zOs|zUd%Z4A5qQe|B3|)f{!Xk#wD@x&R-Y)x-kj?oGv6+donH4x&QR0W{=QF>{9A}- z4pnE{Xt2%}aztGETt_D?o(N>TL<-aQ<}gL?&C{J+S=POl+dpYdFD$Z1SupM57&i@j z+(QL+c|@ZTS`4g*pO1B-o4USc4Sy4f69gR44rpjcb?Ol6aVm&n9+cqc*UZ7_JWBp)kRAmK_YQXaKO-5>!Gj9IHt)zm-kearG_+ z&Rq^>$Hm~N8J?E)c zUnGUB|JwKG4zk_5(odAqn_80Rd+!EiW8nc3dAJ9xaKddT6nUq||rAtrx?ktmMbu^6l8m7OI z;i4##6Y2SC+HhdBSBstD%n&GdLv64LPVBE`^??3g&S}I#e#n+R{be_09W>m7^sa`t zRrpi_WTVqrbK$aXgd#kbs*RM)Pt}6N$puEE?+7sl1(c|Gg~*D^@SRrkjGy}jY5j_p z!`H+)b|rd~zdhh=i`32bG3?3iash}V42Rq1r)%Z?EDq#a8HY(+B%Z_d-&Rfl?$z+k zW~*=+s4WEr_^K!+6oV_;;GpeRNu!GuAj@J<0oM$k< z;rENw9avQHs2ZH0sBbg1@sg$ycs?M18T!mlETsKi$sz7uCh8a&1)Qy&`mLm^yg@ z5kwj^oiy22?i481KZSvfK{uzz-BgQ(0nBFE*ld#HY0}M>>1KPl z{oxa7oZK&50QGW9b`RWoL)<`3iYWEE;HV%rR^+@wXOu=uv;#^^I21}Etc~SdH8C0H z(1v&lURQso%r=;UhvgU)Yf%=D-fx)W76lIhQMwTA7(qP|#}onucG!g?`7SYPC*Jf! zEK;S3nSv$EC~swC*t079h~yJjg`X(_MZY2}w%j&u(qnTPe4$^K>zDuO-9v>Y zkTOz4NLJ6JEX4JY1e`!Z*2DIi$QfXZ)@izi@w%#UYsm!n_Y8mLr|ddok<7RuhxJkl zs~m@u=#j0zxg9y2S?z+X+Bg$h?ZiY=NN2QI?S8ET68z8rC{BGE)7A7)2P^OFm=WC6 ziaLKvuSK0MAcp4rMc<@z(M10OF&XXW@<+W9)Xz46} z4Ys_<1@HLQP{J$ALQm4$TLbt13EMLG3H(+SIbyM82OQ1R9V6!ycS~)7uX5#fqd#+v zh{h1h#8=U%n%=UgAHZqq4yH*pG$DN%5_3+hXoU>*-M0TO-wODsC3j6Em$D zq>wr}Kdl;6nv6ZU*gT-6?gw(K2#J}akCo%F@)-DemkJPVCyuqXo6F;}BPvgGm&XUs zhUf&lBbkZ%!*KWFuS}wM`4d|*5ciG$E$;uvp4s2RQK1U3$yY$+X|B|1qYg}dh6_}- zfvFSWA0!l{B3~}64HkY+Gihyrk!o($f#!ym`-T6JrZ2&K_1T+zcipC3Sg5gP#Px7; zGLysUVg2|4U$5)4_>KuAHbB{#pzK#u1XoLWUu;^#4ka?CDnp zG%2byBiKg1N;oN&XnhR%k?0D2q;_*w-$0SAo%D%H?T+0mpX$-AYQS9GL_(FCa+`)L}W(-2as3TM)v z7|7~2waPn$MmWjPWO8+tqcaYc1nRbX@LBvBb(@ZJNT;Qblp!!vrkIav%rn$Dw($fD z2}u?$9lyeSy40HR1Y)H7uK)>9!V_FveS0t|*4)=-Fh4Rx7pAA9zrq=C>!)$L(10Vb zaQ7vFc~%gFSb)nhkN+wS)PQpmxBB@jJ5BBrO&)$fZ44>k2d5F2aa`)0L#H+jbtwbluG z@pQ6-~2~ePshV$ zd#y4V<4c`yL~vr8Y$5bph<$ax3aZABgFSJBAt$o1f>8zA=WqASfor(c*^jke>FPp- zUT4k32xK&pcg@TuohvD?vMqR?HFNGBDZiK}xXq|@$+@X#TYBpHcX&I8I>aw_8p}*; zdd?4An$-*-dFOPbLB4&V_`-{l`g5@W4lUII&QV);IQolV@;kvR@-fxx1;7dtcUzm* z0aDbp=1Ub}dw1F!N4GP8)AUDn!}B!VFtcHc zgdNGL0No3EmFLrSmfIWHAOGdX;Y-L6@H?6McbzzjS`b#dSq+-x5){(9j}) zhOIhGu&~HfAQ2ncFWv@gb?_`^1s>c7JZC6aDnER?8Nr0RoUQ`p>9;c%=< zKAIqPU;q0%Rq2D(r;qHK z3hFpy#?GX!w;?D#a8eeERf?~=)VtId19Rz`pigOX%PKPBc$wXiIhV2`an?|B1aAE# z7JWY$K%|HS1>{ZtAFRDokZ9eKExdQxwr$%scG;4tub?E=DQgzr{-43gstiI!x*qvc?f(5EfE@vjKS zX3KesY}X?QlO%bwRT<_+eCA&Up&4MPD}+fnwsYiS`f=?*g48fJw2gL93N_F=edj0TBcvJ5S8%Dug{hL?f0>!j;kIss^EwEJQaWE3QaGw z-^C&K>>zW?(kst82%FHT7j6pkp{FP;bcfI|&n14w*3uVF_k4REMTsbHUHBFiy1?ZuMKM1U0|=C1&+La#N znD_!7Y2Zk1^ageWTgq<=B%DK71t~r$BqFK%=Nu-FvFgTTMxs5O9v}u^(nz}mOgwTQ zqzY`bjP6JpD&!O)uAlP-?J$nJmo3DPUYZKm0u z*^k+2pPz=OZMJ_??JA*h95FrMRpa{=h9?HY9Vt{o1Dl?P>YiTo|q3|AO$GK3hXTL{#yjL55FMABZ(P*;e zj|C~^lVPHyv7*o2KJ^hrqYJ1#2Qoe!QHS7WE{1P#GDNVb5xBJ&t_>HPh<6!5jRvCk zPIs)R?GCVp^QBNDe&YuxV9s?!w^JLyI|tDEJ1XcSP9)>6iUwj`r1ds2I7d)}rj#vI%k-;(0D8s{=R4V%CAjB`}LqAg>zD zPuXgs9d@l&e{yp9fLc@%t^IHss;f1Kh%Li^HOtBFWH~a~z3xeoeZDdPiA`Hqq^}{0 z!pY%WS8V`G4^l9h{ncxy%5_NGOXqCTaFLPhstJKD0H}ukVLR78dIx#5Xi54#5;qzBXwRqR`?-f2HGIR0eNVL=xNOeyX#EtT z-**e3@kJ0ji@X1f86E2N<9c6s*`%(U02_&974omVPb# zCT<48OGRGVQ5(OJcRSENs5&61MmFO_8#yrdixhK#4kkjt9*D^6~f&6|3-X*-`Qnn|rpb+<`Eh&_eewQMcDZdiVt( zhg|Sr+M$$7C$f-b4SScyLz6U9=?~qPi=S~AM+s40tbKHAYJ%r};$mW>W}DX=K($u{ zMzGZcKg134xlVV_FNg{!-PJJ9H$N;stUgTGulHak22~j-Sqpg)+l{JA&>lcZhu7Xe z0J`K2XrbtJqXD$U8rO7@)0do{qh6;5qd$Z2G7KAW6W7Y0%5>BDp-SC-gj| z(POSu{y|w8usO1QETOkM(zD7XN-gV$o4vTCD>S8ywUe?edq8&6vr5{gBj_4X*~JWp zQC!GP@3HLVj+Z_iQQnhH=o@fL7SJ|jmsYVwm{;)wVo+K{L6hOPBDH?i+jMIx!cb}| zTl2I5xv76Q%X~e5i|vQC<3NsTp8pfF?H4dSN} zlve3R=YEHIvFEmR-=I{df$&;N0!|6goi zk&?#G)&}XzSVL766$rTIw@^j%VSTBqFg#hlDWn8Evb3$*kh9$;@qAI@i=^lMB&xPl zElE0B4%4kD`n076vuOoi!eutQ!x86p+r+BPHm@fDoiAyWDZi8;9w|zUxGe!i0J*A z^i@=>ShS3-mTc2gm~I(0c6vlz6R9`Z4smyy>(2vlf(GuJk3X;5Pz$t~C%C8XN;!Ja z)v*WL_G#=vc_cKCmniE{+0$Fla1^elJW$Q2F$PgD8yTr0{47LyPTMt!uozSJ3(;4S zk4Nx=WdF+Zc;rJ^aWMB&%TPfN9*t@OG4$8@s4)f>4qRYiZA&fEPepcrx_ zqMNdH8|HD^=xG(okhN17rWR6^I%}m)a*17t>r0F_+fcHT8HSqUFt*bf%!~$gE!~TY zcH=7MS=UZNQ}-^ib+=2?;1Mizej_L6K~)SWwXB(18&X_?dJZse5;pLuSjJhaG4!{` z{+t(SKi&MJ2{j3MV4sZo0kN7~ReG@U9FK!7lgds}Z{8u`E5+ zRbCdWUH%d>sklSVx?Qc8d}UyYX80OU$kcHePZ4!YUN|A2UwAaDH2Ej-7{)eqd*w>5 z)Z%jE`q^>e?vm>krA|0JAXp!|L=bL|M6k{|H#_E4gE zzx+Hz=0lDUHl*Lzh2zDV*fYU#aQi?QDWXnFEC;aYX2~O^HJl-!o!d2DkNDHlDJiUC z$fXm~A(9ivzECI8w2DHuRK4FQTn3?PBuf7ws@t`ZGhwfV*HMx|M0Zw^`sFl*Y52#G zP~Wg`*)Q^Jj_mxor;=Lr7r@mv8%YD|C=tF$xt9@*)h#kaS#^=fU|x@++p5jD%aoR=20YUuo0#_kX9KK$dPY<5uF^T19C#tS!un9cOyP&02y$yUx{T-N` zo5)c&=Kfv!KANF5-9)p6m2s4AX9@eN!phEOHZlb)oD5p)`_SLdKH7&DbSbB0vq&eU z*Q}1F-G40|l`Hq;0)Hsh-k-AkzxbE`i($=DIRD3j_hrm)t@YFG5kA%{Ed&urb`fju z#Vn=9@@0gY?a?w`z|^*0#Ow7w2}j1{iAy3%d;Y>5b2Y|anlbf%-=APNneue#zP|XO z-5)u9DXvQD0x`$X&`(yx_KZR7EDLQVtAd!U_oMHwC=5vCr1A%1aU5!9V6k@Txk^Fn z4Q_w8boAZ%PxWUXHsPunsCdH7xgWac#rBnfX0di2h6QsxM8c(qc&{MmSuhgyRdZ4) zqEmba5`+Av*~SGtiu|#Xxe{uNbOk46ouetqU-uLVNE#iF)}D0U^`1Y_M-$j2o7Jxuj?eX z;@2eiWJ%Au`MMuzmb~WldZ=IpenezUo2#bf?*MI^g@ORWypgA`C%MvRO_rjOi62C< zv)zh$vn9GyL{z_iAFE*{tVJEzibXORhikSC6C)Yr_7i!F|D-Gc{-i8){G==tk;XKN z8vLXzkTJXIA24b3vR7ss{gbi~2XSI%dPn_@-Ddqy%EC_WuVsNne&~Nv7B=`de^M5J z{z+NjN?r{|P!&^%Fxy|9Fee`q+-<2a z&@#H$G3eqeGa5NpNjQPvsK~;Z&mgXiw z)?fL=K=TJ(`*xWw(P9{Gc;ruP#!jXjN$R^GOAJ*6?$7#vK>kQUqTO?kjhJ~3f~LqZ zMd2@{sziW&)v3?FMXTNpybDAYQF~J+?(MIE-Kp{C)G=6X|vsGqhnj6t5^fXfrD<PJIT1AY7wTLXqs6U+7^K6fqvBF2pIZa- zp&U~Orp28QnnbPqUd#Vdg3cv?t`+>ejs9c{qsH9 zsjsh<8Fa1>;DjkjlWaFW2*HI3jat!awI3b9yr9J-cf1v;oYrHQtV6V4{ao23>4!p= zlUk2koc@9gJXBuXekhmPDo8FI*^MLoF=?_BiWyhY%_RG}{MKp^@og@(q~_f+_Wc4r z;Vgc?ZZ5y@Wwp5n9}bkhxK?IJ8vG+e8sP_M&X3M-B&A#2wvm)xS3mPU8%GgV-N~u# zVLZE`Nz=aff-zR>B$YMviZ5bbiW)4V?FuRN@qMJZPupXh=Be$r<*NS)A9kDQnfL;p zfPvSBh97$r4Bdbqn(zWkp2EVnNhDnH;gcMxdqLh`VwKX^rZ@Q<0W*%~4+aux50#YC z+qFmG3^}Fx-5X?d{x27qid+2}-47z|{&x}i9~0S61^mY`^n~z($S2}Cb>=!H1L?Un z$tHLqcyl>2O{LI>0K9r}lF`L;t=09$mxe%$-XGE1ckGKln@1Fwe7V}nW?Ea?aoTFy z`^WuHvXRrqqyYdisGFu;t?wWgt_rqhzZ0m@23<2TCaaaAr6RC>J1)^-drvuTMKV2guT!tX3Hvwz!=z zb~BQbi0%*+o*Vn3NvtcjDwZ0U*LvJmw7lnp&|vAGGU!4XE@ly102u;A2^?N%0=DA;86AQom7`Cz~TB z#PdBWP1JpyK%t0rbaClPWE93%|KA z@^}9HFdaEO1^UIR$o>Ir2{OZnD7ph19>9=|P|L$2zp<{RVQh^z6@$5{yN;yqVHw?S z(e!QQf2!j-ON=bpOsS#_F(-Xw+VT(#LM^frGO?FmTCcaLxw&~6Xc(;ql75^|AJ=qg ze}}I7JL9x+tAFmfu* zKL!!0(ui=Hs_p-F{BVr3U;MujDf>T-cl-b6y{VX48``-1>%mGJ`+r*=tK_x*nc%tS zmo}}`)Pa8Uz93l0L+ZKBkVeU!wN%iexe^I_Sb?TsXKps%n#6??@%-a%8{kw32u6!1 z>7JPAI?iT%-bl+a`3Zho8Q5f~-cbg|LAfxi^CzZySG~2v{nUkPnG6}b~@ z_CO+T_xQ$>;Nb}c2@f{RS9NKL{1Q6aEd9#!O?g&S-bNy`@e#krIV_(X6%D@~2Jncw zeHg0fZXuL4KZOBb&`+9s|JvnAgSF?~op7vNXIPCBS$%P-H|#)G?Idfen2W~Yxf~&6 z4Z3kkk2fP`7!MuauUjkEp_n4PpDy8Mca)`^O_S&V7>|14gE1ruaT5ZRxHlc}vYwu@ z_5%TcOi=u_A&mYD zC|sbPio$Q(6B(oHom>JCet|$>cyRKk0s`;=VsyVx_4|oeW0Ry=uB^$Pw5PY$PgiB9 ztEqG^9xIRCOxot>=Npze$K6U?-oCrt8f%W^X#ZZQ|jS=h{{{&|F=F!vI{US#wdqAE90pbrW6DowS( zxThL%*jdaN@`QxQ3;|Z8D%97ZK#`l}8`P(GD#)MJUlmE1R@FzBjQaE%Vi^Asy5;H@ zO{)q&nnQ+E<<)_v4yi*9VS=j97-0zw_7>ZP0xJ#WCD%={MS{GQd2s)>C{~7?gjBVS zpOqK{nKy0FwILLP4bd19AvDCeL|H&bEIYYD*DL2VJA+S#r_Wa$VA$0!hzOSs)MxD7 z5U8qB8;To}Ti{54i_TlB1A1h0=gKbS^?UnM*qu=7#DH7^_oUDeIUhOiHH6NyFE!5g z)2K_cuQN>1PZ5_M%h`3CY4Rb`H16o`6Hw5Qq^79eWZID1jqeP&o$lD=9 zx2-XFn`sKhEYGd$s0}#{Jr>&q0ORkAP*~^dV>)e1MRWy;Y?`D0WwB_iISN>=f-LwOM<;$1N7eG+y86P+{ncyIsgGWRQ6u+!&a)q*_&sXU$^V$4__4~gRlh^BZ#DlC z0nCbdojTNkvSHpS*!fKv`wRZDm!NgOf z{H|^KrO(9E48x}(7c&HJ(WfP{CbC9)9}^OXg(Q8bg=ZfZ=!u4+yCKpC<2#>qJ7WkI zh0E$A1LsR{FsAqxQQRqC=GWp#+c8jqzk*(>fa*>CUU=*Z0{Q|&*^OMBc#yDgGPz|A znr<)VPhpRf&H`)@iXJH; zACs2TqlZi4krS@1pq3*f*|G4$sF#!KdkuU572sIaPlF)9&l2b z;gFWIsPjasC~ZJ{!)wH+Psp9fA1?6JZzexdtxOf$8b)%UX30#y2NU2%zAsbd8x){; zdJGdTHmzM@!)RVXdRME=OpoH3H4G!xC!g*9OP;J|2@vO+rh0`)S?W+kuB>KB0j+Hn z&Ww`rXA%(XOq~Lza1SqsZ3QVr)e@$QYXRw;iX|pJB(2Y;4jAZ;q%J$$SfOzy(RUC- zh!W-Gmn^nm@rrIZOAgrEz%Ggg1%K;#nu83fkXfgkIbWnD#7hm;@A4TjO)p0Xp!-m>C` zarip5GoacA^d1bwRpA~Dh7+s!JC6D0IpXu{fHQ*B2I-GK_K!lYOy|1n{#A+HX0dAz zDGpI8Y}_u76w5PMmv>_LFx73VYafz~`UQXbW3KBMX?F1&E7Lo=0+&VI@SuYtmkc*; z>Yi{8o($R2`+y|REoYAFDyjE1qR&m3isznEjw^IPxNDZ9A-8l#Ka$Tw7_ZtMv|sg& z^{q*cYs6WL^erk#KSn?1k#HX-U|g}SC>=_4CAf2AAnUZ%t;-%DU`Jj7AzT^kYr!mE zVz2Kjr1F%NsV1Gz=2D+td(1tc`D3xw>MBqdwUgNYQUTRRIMUGS;7dJ+vZW4WeUt+!~nAd5^A7Yo4r&!j2>z3bSzeZRV zrSCcW;iLN0q@#QsDviBsxo6;^gE`MkJsWtD?0aZe5F)8BOJRcwek1Tjgq%m;UE_kg zfDqK-ow`N?)=;8AEi!==G`?`{wd(sQ0#VF^b!L8j1H~eD z#)hrY?KF92l*mMkMhwkYub!wJ%&8uL*-r3Wy=N!wLHUy6-&<;`oxZ@)JT;Swy$C^ zQv=%q6l&KS-4kE^^k~WueRu>vF=OsSBsSfyFtFx7Qh3I#<^=mJe3lZ6{DOWgpzhW59I`*o*=NGYKzjA%p|DK&Io&rA zI=mQ|DX&t;HdLgbs40tIiT4(DPvC5x5hx|PSq1IV!Iz9P7Ea?UIk}jRDI5+x@+!a< zY3z>Afo(3|^blXu;51u=V4kwY*m@APv@*E8)1I-r=xFa?1+%gl+~v&sgN z$wtT|=a*>lwJS47(x+d9p3tdbyJ=@G?faPt*Azb#IlZf_e-t-jihn7_sky3tEAssW zwr_y4D?n#x83pMYq@*#D!9r)%NK#Y`w?UvI|=`wz z#ThX(zs_=9u>B_Av{XzWfq`NS&L3RjbWDERPl*ojG4j) z3m`=|koR=}$?^omgSiN&i=)cXV$k`hHg(QQ!*Br9VR({|ZtQ^>(+s@}&1dXDhZEa( z@EHo5kfAxWLn_>@4PXYcacN;(1E--&_mT7YMD=^1yQt|{lNcFh$)B34kS!hmDR_<) z05#(%kth-nDnVs(7gEo#U5|~8W!r$WSBaL0?VP0c+ zG8;W;G3yXXTCh&C6VO2js`;aZ`O6aA;C-qS$g zhkm9E7WN?=zIRwU7eyL}LD2z250J?0?Cv?;0oe_Z+YSOmf?=N@*&;{gUKi>)M7r+0 z;5WYaK^qN$dX1B(y|M1dkjJ2(Y@xl8^*p&3;OxR@&MB(6L+HSpn_Qf76opJAoMn4c zwwwIfTktujSD_Ja6GrHXt>v*#O^2;Q$CmgtqS=)$w`x<}u09H>S34@Il&-_b_&=dChC#*xkx4W}Mf_&LAA=bkyjno&%{8+-p9i z(iq&w7RHQ$EkiTK}IT0J^9$fhprn*H{oW;zq62u!|Dq@>(P=}Yj{u6RE3Oi|u4_VRRP1H{qTrsN|LHJ%ge0z`|o z&mGMW3?n-XRnKx~4gRF2u&A9GZ5ypB!7vwb7c<{H~O?A_%LyMv~5s#hM5?vsf z))+NGD8dY&a1pg~_EghK7rH&pa;yNvJaaUj#Sd|4OwPejLI!jfwwX@50t>I~;BLWb z8V+qrxBqA~=~(*UBeh2T{6l07GlL_Pa|$JHr!^H9%@J?rBm%ZZw9C|mNq8)VUql^A z1OI4jI_CM{_&CL>iDDtlE(}mtEe3iuEBnsPmzWz>EjF@=H>+Jdifb;s58Jq7QS%9F z>krAHP1?DF5zoVO4=_YO@-yO2XOz(7HaGAv)&8<(bemDa<1kmE0R+alQK)4VsA_%M z#1@Kg=w-gXj$xBL8fXBBk#JLytLMy*T|^><1EQ{7LFC2$R7c-JJK^&npb`;P@sKA$ z;vk#G*PgHv-lcfP>V>yYXkc#UKGvEw9IrvH`UHMZ3}$a&$A;Wfk~ zx}D}eXVOr!vdr=h3O#Mx**Mv4U{he?>mTJ3`*v> zazP3s=27nx$Gf(4aNWqhzi|YD>>n^mjEoKzma$=SFJ-;T6|vq-pUoQ?X|pT|ksB#> zTTT5%u|>Fl7n1*5q0=S;_60!0a|Bh^Gu#o_@;2^e zCo|@R)?Yku2UEk7@=GuL+ERNeB)7VFyK`+XXHVw@RiZ*7;dTpUn~>FwxrTlaw)v&y zC5GA?iFehL!5ltEKsXTX9r}IgXtHxKQCCvr!`pYdZdDXYqvS@xYP3kNK}J@taOZv9 zlN?39GSWTS~KJUa)$c>;xK$w=4<=Ug#pW2AU~+WFgyzhuF)aqaRn_*;dApL zkKzRJ)Z}MQ%%zn#0Iys`#c_(3Id!4qCWN3T( zw|(~{msERRCiYd+`{`HI6R;FrgmvTlh?l_^UpYUVDN)QrlUo9irti-dwRm#{AMP2$ z^rphU4aF-LHc;4mr-s5~Di<=v50Ku@KKOY-Qpb#MoE8{zT~Gm0QRfM zwuz}wXckLS7MrkoVH;3kR_x+##hHcqy~A@hI>{%VlI5*po=y!Z`{ z_VYuILW|l-qrD!wGZY&$RG{#HG#ok(d$Rb1>qzp=ihYGsdqX2XE8KEYY#lA1HRcXW z9T3@d9(fnMa`Qc zme*leu@XATik7N10>w2LqYILgnh&{rBAPks2<;LTbCi=qKWAkb^CrrA=2*`_IdOd51!tmcPaF**c<)OG|Bp zudJ@VV!bd+9iQEh-zfWFy{C_fb(cvGyCn~17dd56z%d!$KLl^)lFMGOiJiA{tLFk{ zolos-lK;3q_G}c}y?}dXwVMOd46qnu`R1;BfmQ4jphB67GvL+JA0v4zGvqbNH$tl7 ztC>C6mOslxkY{q3rhf;ws;8C_#-)@Y#LQZ`o)^kcxudWLD`7;d3z;9!f!=nY2%p0l z&b8MxqfkS$!kfG}|Lj(^(wuIMQ>SQ1E{FhwPqQVN^oxqIMUV0+PC zFlfL5`3@Zjl?o#wxoktN#7g+ajtk8uiknP98btRtU3pqI8sssNo@1&ES}<<+4ZkHs zeoJfV*331Wd^~n9FX*`!JCl4o4k_i9M@<`#dVx>BltJ2_>ZhivPg+||Sexc7yEa{t znaqHuDznTf9r73?cK{2a*oxjN;s zxzlf=qLCOYwEVNHeJFt3sj(u#dICgU0-Py0N-n#~o(ySa2X->b@+2QScbN7ep;erP zH_CG=kbO=1v`F zQq|3S!&H7}nMb-qz-G@_=V{o{ka=>MDr#K(SCyw>eY(Zezq(uHULIIToGvz5kl>>l z1qSn5C=&N|ETl~`*y|wRx>OrzA`EAri62Hl(R_bI-&ozl~dzGjCs!mprdbf_|A2Qn9~GfM#-TX<&9t|10Dc%GfDr)l%g%G25%FE@0t zF0hY24@I4)GjP$EWoH+lb5#w_s5@^x+BeHW^V z|F&2r4MuKPsncejVZht#=XVEXO3@@uKD@pY8A-_zD;NM;b^h!MHt-#N0u0MI)!#%6 zf*qo%FxrQxAJGt$RNFcA#s|pMH@sWNa8P?rN$}KxC`T-bQhMltr zg|~C_{{_0M7j>G8iI;EBY@%|pL5Mk9A10zjdVaI+SnI9qu6MoiorO@+$-2LXdHYo` ze2`KEgO4XTw-(<1*LO!{9;9g%*Pcn$Dm}RPC(UAe@$t<&K2yopy6ib5r7+s9yYCsJ zs5EbzlIjwy63T_Sg?eS~^xD*}+Qm@8hbXkaiOYWBGHNMRw86g4g8egba9$M0-rH88 zmKaX_Yb4_63Ku+=F@}hy-QzXEvGYunifGVQRj2LBDUay3oW=<;EmM%UL>$WrG4Me} z3tZ(1#0eN`HLv6e4D4YD*OBJq=Kcp5)6das^IrE9ZQ#*vuk^pvmp#^+O5hQM&@eLIis)MUD2_jGPLaecq> zs<$*hqAzYIu23qkEpI0{+S!O#SX)aNV>UW7psMO>@dEgvA|2%zJ3x;dq+a{+yv*s0 zl(%kRW!I<7qFIRX{kis71mm?B4TjEFoD$Q5`KIMEW??kt!-8 zQ^ktCG|re?mwFsm?WhwMwvwPW}7%>i23th$_rDVXbey6n+YdCD}=ll^tC>w0i3khSctoKWH{ zkmK-DKYX2;Cw-GdDVoUO%^ie$2cpQ%d*@shU47Y|*~kdyq9S_8tldgQ8H0@!){r&~ zk3gCRPKe#%Grt;Zq>e^(MbB|~hj=m<=s02?()c|;AEY7wuRA=jAX~ObUl_6wLR|nM zT?`>T631T66(C4G$O}*nJ!ULmZ#E18TdHUdm~E^WZc=?WgiHX^{xn|+LW zxO-y2FnsRfsX>jkY>L`2dso(_>KfXefaNX%()M0%YzS}#!0UEioO)nfl{e7NM;$K^ zZusWd3aa5u$>f2^=aKe=Fo^MV)XdNH3z5UfRO{$Pdi3ppRrr-NaN$@Sr15;=by<|v z!1F8M3GsZOglxVhJ%J|hJNI;8Y6@U~AMwcS;gLGPo|eEEz<^Acj%6w%0Q({bJ?5_qzJn^$g7BMWwfs9!LyllaeIfs}URUz-cyV zx12sG@+{PUC*x5MsF*zv(_gS6Z}dFN6K-$37#uzsZD6KGKO8K5FAMaHlKL7F6bqIV z12JEH4v($#%nWW)w^-FBDnug|;b?wdy9>vr-vBinTx0YT3ci5-1 z36t~0K0s301btl2`^uYWmGkE&USZ5}ml&BH(&I-sw`GFY4brVAKpP0w_oVQvvqV#@ zg_rG@Kqfwffk}x6cih*Zb_dXU7sZf5n=aA+po^_Gt7bZTylWV<`-GH3d9N1Ny82;r zRj2J6G>OzaZKxwpJw-5XVaiv4BiJ7N*>DCmwnAJj=$Q}(ICvPNTtf=OTPUhrO^UKK zQ#su9*G3y&vAElon5h>+gBMm6-svj5UNoEh-8y-o;Ug4!C&VNNJiGBG4bwQ>{;Z8c zYF%m<4rUZYMWNK|U|}c_*TaF-3uiwbw4RUdzEdQjc*a38pW4&Wu@?2I1H@Bb2Czb7 zEa}I5ve({GW)~m$Aw*i40)wd*zhE{)FlH~(`C|WayWoTM_eACIj?m?0)dgaL6hZjL zpv(qMajuv_7U88=RWjp)Bq^wZ^+ZWycm<3>T!Iawf z$Az&F!4Z61i6!tvlU+uMlCZdDhmu*2clQJ;-sM(lhtb$NATj~HVhtFSA(bS&WE4OR zuQ~w!Pzl%`6>DG@o(*k&Sdb-7!3c_sHq! z-I9l_lv3ID+n>Vw^~eVO31;`vK|>D+u%kYhCC*qJH(mJfI}iLrn-u4WE@JPXtw5$u{fen2fQ(EEUzuF3%J-ihdw6YzlsWJ7H55|iYmJvEC&3C%W zhSslvPMj=Er)EZJMWNExsWZsB)0|wUoMA7F@T9_Fj`szEGth>9QhIdLUpFlzV(G{& z8R5KCl!&GVeygi)&vq%6Tmj=Q@wkY)m(C*~`buAYil{kXf}^8#Ca+w6kIerUcmXYD z=(Vu5KkgAT#Zl0d8bgHh%PH}~*S4w@um419v4<9JJB1FY<-UJK1?Lg>Y7b*--7RFV z&o(HjRd%4i6H$c?NXi?iS?rUrnuWS}0qOw-_M7c%H$R5VrCC0X2zs^fa%A7{0#~fx z1?P~$F^Tf*?m^c|S^1Wn6TclANW?OUHg`jxTlo>N`b_ku&ZmI%eYA;EQ3_{YD?BB+ zgD1jfu5%+(_4nUjhvDr#Qv+FE%WIv|oVxeUO-O5{R-@}{p}W^&2lsN)NizI?3AVUh z&Gw*Jh#?01wpc}7FD_i+yMawgoI3;RezAY@k4D$&eRm=)Nv*R4kij7>)_eK{^aghq z?9;`sZSS1ferd3$^y7td*|Ak&{u$zRYWP&*+oPe}_2wK;(BQOZ<7fz)!)r<&}ZCtW$b+w|&OdX$E|D7_hE1&6tKGosL z2_?D17$Fq|Ta^fxYM6J7lExNsLq@OT*HaVOuQWBkC~Uk%yKfui-RH7=^jSW9@8q^T z?|^09^A{8TSlVJ78^m%QhFCo7m3WQXHtcFR5Fk4&Jw8Zn;#cFLEm>~U0s_^r^@I|k*LD<5>7-j5UJXug=4!DanwJ2K7y+~P*7wgPVT zVF{vY4S?$#gO|F}X`TL}54MZ(o~Swa z57!IAYkL4*dZ&hYXx19)?cXg-%0!6fhgEKj)-$Zds~3iQr3o*i61y_HCGGDAFt18^H|S+%PVM189Y$ zkS2wY$|W7|p(I@|096A~iO*YMJ}!g1SBfl|;5^>RA<)1Wxv-DNP@a;OY~#ds+;`a` zQTF^U{oDiL9{aYq%`Fv#fowd5FLK^Ad+fL%x014`HFrChhkKZ3d+)%!8vC50Hf0q~ zXKjTPHlW5?7UgtI7n%x5Et1@cY_QK2pc7&V7K*1(e?jbYAOT-%Y@L?%aD2G+yMD8d zvbrN&n5&2_eqdz95{6z8m8Y6EvZ?F(vJPm-`PCHQ}Gc6DE zbt?ICp4TB918C*4?>S-l&3Suph5c~^pC8zu_GNO#vW1vr++G;Bhz$$vfd_IZUzM`w zQ81chSUV$6e705nNbW<}I_rZmYDh3@h%stNF?^($z6vqQEZtGc++pU&j^*%m_)xmQ zl0I5mVco!u?^C!JF8AeGvvekX%1S#x7ANwq*e_{6HgAU3I$2$Maxf|F1?*fQZ@V}D z4{PrjBze2E`?jZTbK15&ZQHi(?rE#qwrz9T*0gQgHczkTT{~jOiP-CX&yMqJpI_TiCp{N|Tkc9Um$ycvVs zNl+mg@0E0SqsFM)4TwH;QLf=P6ul)MU;m6m_JM)&!EvhZ{)OWEYBNoS9FIDPzUdj7N2#{ z>Wpt1b}=}c3e-7{nEpgN#_}I1|046|-d-ly5k@dnOk@BK7Q@QOJ%eYtlq7h!2y^?q z$zzo_!!`jtC=onp7cs;;GaP6na40WM9YPRtfjt83bCYM=dUe9^3@Vf!vV~TKl%=YWSDm z*W6MLNVx8otzu1V@)u_95Q@t}aStY3>yYlqx52P=WUzy1T1e;(9n#)Q*16MbitY4K z=D?Mr@cP8njBsXXe8Dey*$&Y}exg4aRLRPUC>u+1BM+mt5LRQ<6|M{buPYG|QnFH& z5r8G8<-9%_&jO0>s1DUAD;isUKw%G~VB)oBT}g2zUbP_~u78ARj9Zrrt9{jwbf+S`B!y{?R&tD;4pu?zFB&GU z`7n%|2i*)g#*9;G&r)gIM%kOVc7MAUSPoi{6ik>k8#QGlF4O~CR3@7Y=jD}Tn1D73 znQ&6VyU^H#MzY45;QBdN2lo#7GxTvl7Gs9=IUC`Pv%&`s0=9(Q3W~X54lT*KFpF<& ztF94Rh9`7`>7`4qY5qubo=WY2ipx_|y+bHJvnfCKzsb8F1+7+GBeV$@j>H~#n2g-U zGmVpD!Ap|&!zUV$$2)?JG6XQKuZF{eboj#QS0HxQv7o^=km!aheDDZIr9!Q&wqMWW=+azKf=G0kI_ z^wI1&FCh=<7m|R$l@1JKL6QV!?E#)TUx-u7<)?H@K8YA!pY>9K=9w3BO zr8B7|jtYGJHC@;oFLC$RN%0AI`xbHwV|?=Ijr%*0;^4@QiDwDhLE?16Mydsk+0TJj z5>7w@hLZvJ3`Kk(eG{07wgPhQ)DS^ykC=$ak2i@{OKKKxsaMM`WkyR?=1ayU#3&Hl zqX`&wGxxuW8`Sd6q{DerjP^nIWQ~V(Mj}0@rM6%SqTZ&xn)|_&pUP7Crx;xOc#Kj) zB<^&`Cbs3MGtlp27zSsYHl)k#rM;?Vx!z*T{uTZ zp)^FejOhvMw+QP~kXEcbe?3-4RO%4pT>Y$Yj%7uu_fl<2P#M;M%g_2{PW~u-#u37f zc##qMIA!i{N0{)HPS!LvD-bKsA42&j@KwcI(G9aLz`%hm3_eaZK{;xrpNgOj9vwyE zw-|>sE}*^Jiw%q2H>sbDGlwKr^%m(qT80vN!FqCd#Gp87ln&sHNcGpn^=Ih<{o zutK{cq0^UbN`~E_NFzpyN`z7$6x`CFUs`L>hzXQrm>UAHOaaWaC^^y`JbBZ)yCR5j zhM;%IrGrO!33EZlp>GF7Jk@UV-v?V)vpbpIL27t&851LFP!i#UjSO7?uTXmvW?cQW za*L(?X$&*>t+|bpLMx%;WHv$T)i#tuEV5x}NgbN)MuFo};ft?*%w@GLk=~oS^l2o6 z8Bq+zC1LhlFoq&Zk&O$e+co+%mD2`Wu6g2&F7)46^HFR`GOB26)}d@178~I#lbsui zEHj(eyqftnXg&`bOja#dZZ-XdRHw^apw7YfmXYnGG2VW4m4*n`0Z9&Y)uxySI2a-& zhC!%PVH*UipROJ%7CywZJfX=0PQ)U+^Q@hUbjA3J&FproQw0de_w7zQ;#-kk!&#-|1H=HXT%sAhW*b(`FSocn=yf zZ_$!m)VUu+*orxzv*&CB{yzr<802wb!FLfcDHlt^8bFf%ww5r-Q=`z{>pUgA`)E4d zJ%oe`v@dG{VAod8$U@A6d5})`l-|KUblz*|eoW2cRyuLG=l1vd9c~Li@jKPB`w_$+ z^Rfi@o@$E*#r39Ig%ij2BHi;Tp!&d)h0>)GvUxyOIAQVmcb8y&`sgXxWEoZ9$trV? zM_Kw9zP++2$l!(<;|3e!!VT_XlI#rd<*)u&b>u&XacKx_TM*dT&4))kU34y$6PYg| zJe@;&NDF-p=acs>RPbF-30a-)e`-eR)8|5XpcZz=BkI8Coqy!xnJ33yDe)%c?g+Ws z5FZgdiFF~a|ADv?7+P7Ac+4Di?(`Y_iMSBu)Nl+h!frLZAtXk8%jAV{7TG}DrUB-e zFVi+u)$ghx zvKiNchU^1O3D;WLq(iw=S-zYx_lgH(b$LdX+&0}Wdo<_YnNxJ@z%j!sB34vXDjG$j z9PR2KXleK2)a@jbbPEqANgVgL9PRn#qh-7So{*OE_EUj!9e$fTA}r%ueH1sy<%eVD zsof!Ey9n~sy1_5IF|{@BpxA>MwW1wx6T5ikC|82&9S9kNV)pgV5R-^s0e1sW_C?PK z+99hx?Z$}1ufUYsP-(#Qe|g+x4*Rtn5j*H%wwXCGyOM>rJvByBX$<)^#&1oaa0tgV znkw~`j7ck!RIHmTP4A51tYT4Cm^j0#l9W>QWK9G(btqTjF!$&{1AW7=G|AQ>g`T$< z5*oydkhy;?j(<&d3l8FpCg0So{3%T?PzNoc-hhzScX`+PL{RR3vBv$1CI~BTqhE{o zO89~yHfFxNxq3m+@58#L`(pn>XsbWl#)^`e=C3}*H^Z^q;v}{E72LLCO}JIF4nfSz zj&`@AB3n41|NCLJ9Pc~@VeY8(JTZZw6_e?}Czd!vKT;cH!O=IBCZ#n*!RV)w-sCUq zYK$C1zuVn;!*d~MR0wuhnT;ea*@=ar`Q^P>hLXM&l>FE4mWxx{t#STqUXz~CsT*yX zo(TPcg04~J_KC?HNR1EdIlp{of-#2x})X|)yHh3xfG4Cprvu%L1nh6O*gtFHmNtwWk>Uk%487w)) z6#GVctV5|A(SX9;XrNSeYU9N`W+@K+7^J~Pr};T5%lIVqh;feAacu-`b^a9Q-}04~ ztQF8Q1x>s-+n{DRxO$JeYT?5a^T40*0}qWR@P{ooZ<1RTz4)63^IuM8cM#vvx^n-aoNvEXr@!c}1lhB8V zdL(5`!h!W;>KpHYko^i{j9rr?Prttf2u1mD!w+F|o+e~5IHE)tO52gIC6t}oyqrJc zox`&$>1d=)T{>S1p|wGs>Tn4ZaocX3Up6IiFY{XFJ?X-OK7d>mfZGNN*#6F#+NFvq z!fl3!_X}Kh?R>T9I8Pf>#+YPF~Ua#FyVel!UjGpCy(hqwQHl5>wd2QS9{Ub+xMFmuMAbdTo#JWIU0X44J zP;!*3Y)2CQX4S{lm3Oi-jzSo$LKtFwtV&}!&nx87l(^3=q2_nc(|&3O!7g}{Te;(k zEx(mpnfb6kxe{G)WBZ<^7*{=(FLc()1f@;QMBQWh9SWtkh_Zkk(KrDgYqouyK~bpH z7t<N*CA!~XgAQT@1>U{^<=2$ueP;MG`)&DHdmtamzAh`JX<{Yat!h2$(tFuOQ!ncL zC1*!2A0P{BKM6AEPph{Sv!-+{CEq_uaz12rq(oe@lqi{(Wgldjr6$ur%!5hk#;A zT%5qo5650STGoRZL@y#ZDnq1=DxG*!KJ$#9esD-zJ$cI)Mz<^3dYSDPE}Y(25W>p9 z7|3fv9*715uKipinWHoc57D@n36hoLq9Zicax0&rKNdK2m`!Rtn$Jl85IRQ((CdGv zXHQYa>qvvxBt~3ECedHIL*^7C6v4e%#CdE+k!N%DJ<6|^xgsQ9tNP2|l~wVjF|E35 zl0~w$%6KnXHz-pub+9 zB+|^Tmc6b9I`ivs@nNE^OJ(Wl_;-7CyURy#b@%Lpo9y5{@z}geS9OF7ulCZOvrhFH zR9klW*-2Y=!I?*!ZtfXt+v6Em?irho-TXsc8=uJ1(b+3@$tVB6fRod^P?b7dKtT4P z{|SrpKe)UqYGCAS=g2B-VPI`%_HScX)fYFECA3cnT4Fd*-Cqztw6W9WHJB(Y{F>Pa z!RfHd}z6;k!NBEM~ywp8Z9$c+sx$Oo1fO7x@62Wz7_%8W2Wc}Wa5V87mI$FEL}or1%0 zU+0^57VeH=%V=Y8>ml9N$JRi%67E}JcSVa3qM>bxZ)af7J|~CURk(}z^RaRACh;@6 z8SIXqV1etri0p;OF`w$%_SJPFf!`P<+jtD48P9&MENEBRt`w~opj0ccih;a@3rsd1 z-RkeJZ)Ix(9=&zEadV3B^U!f~Jt zl*`VPQpist309rYqY2Lj=+dWtkN6srbx;o{ow=!i?Su=7I-~`r0L;Rn%IXm-q!ujBu$W7Mz&}o8?-$0R zCkCRVWhIr5jYrgvjFlqcr}ryW?ne_3Z;|Gxk|?t{R7-~@B^ ze29#(nYlKHI5LWZU1qD(bYRq`Gjo2 zyaa+!EO#}-4xAFW;0_St`Sx*hZ4TPtUF~>-dtSz(D-;wE=xc}xjfA({{v|5Sc2#M1=jNtn z+OL;vR&ZXmGpFPo>Qbs~DDh->Jn`nGsI7J}3Ye2Pe?{LrsJ)%nOhA+Rq0*6riTgZ3X;}xu=F=w12u6HTfX3;Snl@J^lWqCM7D>=WH~dP38HOjIO&gybUO(U z2Q_DpveeK-8aMw1%f1zed< z#xosM^yb8$PsGBIC&_NdBBD{(wwTPf){GsxQ8S_hJZyD;$BZ-DXVkJGat6T{BX_?F z>7OC}93amX1qBR6N%9nL++vHB&KMc)N8vXP@J6$1+2up58qq98EW59chJ+aJcQU0w%GkWvfm9C zRf|2UmyP!1A$jZaXSHP-kt)${BaWUd>3HHIIMZwH2tOsb1|emL2gNr7HEz58P&ni+ z6Iwz`o`KzZhkZGEmcw;de?qe?v?Xuz&VA; zH?S{T@3%Y87bbS%9{KwT&~ZoOKO9?f=iG_b)u!hd-pwU)LObu^01${o97E~2bKv*# zVg{HvW}z1f6Q~b%wW4|P zBwkYuL7EzM3~2|wK-v+}Kt{GjU((XScu7XtNV$~P!~b1xRBLDAw;ky!cB*G$z3@)r zG{W&*#C{W@mR&)lAkamv7LqlSZYqPhXa--jjM;v*Cy`%erA00+Y|FJXBbTY?S7tUd zCSpw+jY(Yil8+5B59?F)N($7nFRne1h zxg>cgv%hr`U%7LLrBNSQ|26{M6>>6VUR~0?KkvNY{~Z8^G=w}*D(arGjaPm?N=%02 zj()#iZax-hn!-fR;9E1G{DgZ`f`VE7Vxfw^9&K}cjGi~@y9}wtIBM00&}WAAiM5Mn zw7xblL$w8}sMi)ys%La;HsaCOUIV^(llVk3z(_TINbBSO7q}ljC)=RX2kHi<-|fMn zhrRVpbvw0f0>}ROnAE82H`o05wnynMR-fnkKe3?TiiKG84f|mHkFXE+|C?C&FVU2x ztflnrZS{$+s3?d;o3GrlWloJ48zG3~FNj8qD&lZGs4=PtVu2o?csg}kG`@`G>-Qxw z++ZQVbq_3UDm!_>{U>un&)4T2j3F|{fQNB90{DB?5f;llxXftz7mjEWL$T5NFK#kt z9_DF(C{i9ZW5wY_f4ZX9=tQD9gAN9Uz!ZaVDi7J=j%XI4wZ;SWPgo(M?2Utv_llDw z+7kV)zbzdUivE+0oED2-DX?V&T!G2SS^;^~R-A@K%Im0?Ke{Xu$kLNMY-^mB6diTS zUbvHo8Pbz%d-vaXx{0N=(1%=QJU!QW8ih4lOjXgDc&?<}yk=aA+VveAB^12d*UAwA z6%(UI(-D1l?t~-W#i{`G*5T2sA!$c%H%I4$_VIx;C+U1OSs z@u=cpcuF223V9L4eh?wIghFL`Te%es3w#Xx;eI3t2H|8}u@;LA&+KdET4}JF>vS^v zW*8IQ@+HIDdOK5VjmcZP`hBr$2s`2t!?c~%u#Y4wn~A%=x-n=+q{>}9IBHs4y%w%b z>TzsVDWe-VqUT)XNbMFZfd8FA^hUyw_Vkpckmv3MyBpCbfmW%X+VkR~_U50$geD%n zX$1WiJ-PftGI$Ff(*iLd>nQ5gOQ>!(B|w)_ZMtn5cVnN6ucY&=^>#w?p!bRVvvPh~ zyd`zJSNEdvB$UtFUk6*v9*f4kIol;AT`EXD3yO5XIj#Ye39mDp#nO+I^14c;6Q_)J zqN^oacssFVhZx&j-O`X5oPM}`Z;}syXbO&ftQWG$Dw1Zo`9>%*iY8WNz74SlSZ9De z+69gnLvdrOs>qMJIA|`TRekUjKD;%-I(amm0bMdJ$Dios+miJG<}|1m)!UXmmNVJd zo)_GtHoY?WD90qPum;jZ;gst`G_Q;y3gZclek|y5LJ()}aM7g8&f$+Izt)N7rK{Zg z)}hk5dvq+5z}LNba$yy`dWCrM$J%r3W5O&^9UvWc1&!svTu5#byC4YH0yv)k@!FmI z9ccpf{ZB*rk4_N(^UNz@YwzOx|H{1aYqD#<5CLDLgk(dwl9VNmwz-tztdO%As!3Gv zia`S6jead!nS>ga=jIJiqifgD;=hV??}1!yxNCnCJjlZwm_Bd@jYzNV|)U;~NP` z7HqK6g;PcyIxX0e_7h`3UIJaMEsd2&O690j4;y+ycA3?$;KA#0B!a;pK+xuN?{*XK z)jY84m{3XbBH@cvA2*R27Qgdvha+ynW~gz2KxJa~r0{p(;2IrY}pN#t#XlkjARYxv;OUmrYeq`{}*j!OTDp1Uq^A+HC_Q zC!Tn-#@^~r)`udZGeG07V)M=zKEn(hwZGRFKCqeE=<43}P}$NlDv%BDYX|yA%*Gk} z%n0pm&rUN|M?*7QTS_JtFX)CRKiaD2GWj;0GC{qB_^))a+cEXiO}Yl`Lu%IuJJh>` zOs6{y=ivtM>Jf5%jNSPSL5DF1B%pCy=}&=d?!#GoPt7&ihr+$(?Qu?C|A~%Wn0k#r z-?>=fKjz~9yXg2g5k5`_`~hZtao7;{bfuKznxU4c-^KxIlmrodZ@Bh6nYC#l~UzyFkzt3 zQFtV3Nf<6Xf7jMi)h25#C7r6H@x~WjR6m(`EPuQ1lJ6Vawr7-IFE%xg-%R_?hAVAC zE4y`JZ4uYN6#p)Xdb|SPWU20b@RG}|H{d3bA8X2^?=N6$)mfm!N}I6B8|6K4Zi(rY zjHLtew;scE#3{mt4UJn|SgYwcG_ZuVvTFW|r|Bk)=U*hcsYXn?5SGG1w0AI^ddoSW zP_Iu2^Cg8W?sh(n)>syJ{35m14GV^aJZ>zmAXl5YLwR~W%1VaRg7=U(>U^-|ngdN= z>s~gXjllC=ms72SEOd2R@z$p2@C38IYAKry)0eCU z53$I)hBGrdLNxUW{a3EK`fxY3S`=>Cwa#@uX|F?zt|1KE*?XZ-k^i6I1$6;y1Rfht-Ec_=V znv_B_#A(FPK(5TsiulB9pLV=etrVSl&$ZntCIyy%ux&%FRw#PdC~beUveLLc566c; zUqAN9{UBT;YHJM({8VrdYE1`z14ppo8}|1V2bTwnfp~1FNqjpoABi|jC1K27CEy5m ze)!{LvTnrXGY(c`JZR1?DXjCr(gR+j;&E>UbC*9+Px&kknCGR?s6HgOJ!~KY( z1?EZp<4Xj8^YdKEdl7L1dyeYvk8LXtjV_~@P0C~V`8i<%Pzk`k>4LlyXC*b44veI( z6%;(h&otpvWz@B*cMy&wI-HAiQ55r+XDs_wGfJZYVU_Rn;yt!v{mUiEOob^W#apaE z@Yd_j3?Z~IF?jQ}2l_ZJFx>Fj+mtcpfO;@=MMr;F&&!ZWKQG!^uB4h0WSMm_f9r|F z$Me+_cQS7iGIOb|lAx#Z-i!y^Vi$4G-zQ{7g99l49A4duEMo zEf#F>oJizg&feuv-Sxt~MvK=>-So4+0fFNUI)*kmHhXnv+&bS>9aMVV=`qRadO=2{>2Z#bt8*ZQ4p^9fN zckv5MYcqY^a(KzeQ!+O95dPIE3pv^oeEklvyZ@MN{^!c?f2&3RR(`5$PADpvUs-H_ zi_bu8%&kBn1NMb*lF{}A#2|CHql~XNE`S;#$~_ILyM9HebsY8a*5eu zl}|qV#sFn&2O2Zu;DTV^`<%-he-+_sfz zRD5m68gEw|A43vrAq8ajvE&@wwc1bKjJ8HB1j9Q^5M01NOqknobiTtM4dNVwHRUv~u@?icR3?ORHwa?x^=7jB@hz zUxbge`n)_lPj-*()kw$!#f>F*>tJr4rKNVTo+U zQqs10Nw&b6v30I>Y}y|46e5OE>PdFD5hhWuqtJ;&sI=}eHaT#RG#fch zsZwH@5UQArXchm_xQwJ=ZncSESm$S8=wV1-0rT(t@m&Fb>tj06; z76Y!wPA=@nl-Zp!?^`CjmEuOhVkGvOAYnm5Pc1Xk5;;kqXzTD8(X>r5^<2kCedAL&ol>zxfdr`L!3-u7<~wQ*^r&nrlkq&0lAAhw~& zQ`*sSakhFl2_~OIEf?Fd=$pG~%=4ONF7sZfBhC`Ps5DAJ-z!ria&Suq@ZS5nB;`Ok z&$uJqZv?nT8e$BEzEKZMsTiJP=j|0b1$J@T7KC%VhaxvY`d{trF+S`O+yLx0`cawr$uTT=W0elQl{Fv*m6KQ}zn&Phb?ojLgit ztTlGC$@7}6Z{%ufza=sPE$mKQm;?-zbeg+$-Vdc!cS9m8!m=oV{l*b;MjHc&U=q_N zn~ZNK&BQ#nK^UH<(bzFAIG>U3<*H_kmd7{8k&Jv)gXSry6$L_0$yOZ*Bb`OCe!o3% z!@XP$q#ZHc8z>3x`q2*^{NJmW0f2H(T0lOr(9+>shbBfd{YEh0;tK6TNUl-DoO_n` zt~{PF_y(Kx_n8AU6;l6Dc5xqrBbER}1EnVIrRWBIZP9(WvLqXQq20}|=Y96{br{S_ zJP$-wk(If~;jdm(Rkhq@W;bXHo`OjXDXS@-etY4tKS?@|CTlx-2mX=^>i}x@*VtNxQHuM5(vW}bxrsWW zU@sAMs-g@s%i(w7zNLaU8<|3n_blu!e<+viJMh1x0;MxDz~UQqZT}xp*W&+ulStXX z(AtFL8z}tG2Wbl@XC)JB6C-B}JKKMKF|jrIH&D1pRm%=X1@SZb;$d~N7|J$b-ewkn ztazlF^4(k0{pp}-e^w|Tau01_l*4gW?H1^k1@p&|5*5)mmmc+IHiQqYsTvx2w+z91 z4-OdlrvlV~42VA%LQm!c>3%+9n0Okqlj$Khv)SSJ>!Til7nnZ#=4}C59nj@a?KV7w zJ!A~zZE2)CTn7iuo;VO6EDYh!Fr=tA2X>Et(+~T{fcecu0bv zlVt2%Kqk_@gh2MKL0?FTw|p=Q)-PxaEbXDhNZ3HPK2>s;$y&-d6|;qxP}UNxw2>Xg zy7rX&$41kp3sZBs)E8;tECr=Gp8SloO>5zt(};0PujnIUC}yRbYjO-&&-69T@Qx=7 zfGL6gGJ$T+o27trB(uArX?j4VlsNt4{gDkHx34e_Z!VT`Auk!ll z6H$z!4sb{3hQ~P_ck(;V!lP?lsE4Q92E4*{AXUD%N`KAL>?^&;lF=13J6g2|J&=G)fO+-q7HqL4I4z1hg7mxz(Arh+w&Pi{t?ZdAD78(YD+5uQH(U!l4*fhp` z{nF`|@9s#4<^C%888LZTYo6ZxfEsIH1X$b4@7!I~=hCXRW^(%}J2OYBQ)bD6(1%yi zq~2*tOLS;@4qi`EgEUcUI~>K5e;m_;0xLN{Z0f{C20^ke zmU%#1#muxtz$uTr(?VMY9P8fBu|S)FZ&E$gc(KP)&}{1}K}SS9Y8FX+0Jp+7GGjo*wXSIv zL7&?##Ct)bSVQjC-en4Q;iQ%RlKh@TcL=or=_%=oj<8K&i9lNzoUQOdtQU-bthTVu z{F>4bg~tNBxMz3^H71Rr5mH7d{uLBkXi>nLJCqi+*Bt4*%Jak(QSCU(J^cf^Smy#T ztcO&~gdrz=-I(vUi$s2U0E+b3H-JLB9K9&9FxDBSiI*_Uk!mgOw^qzvvv(b~hBe{q zH(aRZ#I;+1_c9l2YxcrdEa?UR?FJO$hB*Eiiu{_H>>37cN6!Jcdk5NQ`0W|=&kZ@B z0iD*eLUUQl|vitnuwEC}5i=m?~u}tGYp|Mf7q*9Zg}=pSg+UP2v}(v_+m5 z(5v2dzVls2lUXDQ((2hB*-l*tUPqo&k6GO0pKi|-eyz_n7-|Nd_|*eq!RrUT8-4s_ z`}p*H(Q+flx`a8X^+F@wf_$X=bAqnWt$HJ7K|DYA1?d0MVe#(wnsrhPx@vf+j~w0J zc$`lT<9i8=5aaWlinKzuT&Ko%5N$xAYF`V5=N96qWX;H%%qvUAIkT4Bz;+X!Ebv>aut|VaJoBxOPpS@jr`{m$S=^e}IPO4iwc!2wsb%y*Vh(qi!iR zDCpAILJoxsBI5O5IEf;KcH}1h@NSx6xXPNw!idehe-h!y>7v_9Y{D|fLDwKsa}(*e z66$rQKfpV4cgwD1Iq^0We`o`guAoe_pXhXo{=~gV>t;l})J0szWrBcZj(r@BZPw;& zSB$}F-fh-3gr%a0l_)@pIN=pl^3Cy<2&`Lyq`p?isIDx+F;O1d<5h5~2zW;-IiCQS zr_fasEE3>t7q&2uD7h#!$i=XqB8@UrEUeT$4GZn`jLz(WQj>?>#i1ze=M1W%q@!TPu`D*kLHkkZPZ)QN-V1+j=Q#OC(}tO-uq^os z{2q9j)Mrm9sin3)ChMFrbQYQTY2*58@?;274HLWvumGFus*hBt)#sURwrap9z8Cbj zZC!(e$G9oc3cBqv=5CqxkX!+20|2XRSublsd~*R+(HY;eYk zU#{9#N@Rxu&RH5^2DV1m>NMlGl9`U8+Wf@zys3~@-?nk@nN8GVh7N>KzhHW7v~-ks zxq3ux_?&RatFRFqDx%B*93s`nQ4Bl&ury>OzYZTx;rfIg&b>NgAeC`yWJt}V z4k{Z&nd?E*;mlnRojH-NES`{CO8e$EK!(bigg3+bHr*xgGZRvXZG~r?Hl!|1@-wR4 z`a;SF{cXXP%G1X(gYO9Za#>#DaFxiZd#3W7q%(D3V~S`9(dg*iv}^Q8n8>i{8aiBB z>li$&VzX=D4HQD5BEDa7-0M7I6Rg9hjM`Vd$Yjm<{q?q*bqhs<*e1!H2gs d71UOAfNEn;OMNk}z=Sdi&K%Wws)XvyS>Ypx9l$m%* zxe9~|Hkf}nlz~pE-?YZvyGj$=lnhtr|4Hr}Ue@UwY1+eHA3wIq<@dzwWY}|qDfp8X z*B({(21M*eZsdlr*BpqyDPhxYkAmOdUWbsi9P_{df=92^Z*^?=gKgQY-64H-Q!td) zxgfumv}W&OELNyBjmMkWfq`#+=C2D@)lnxjYqR_kgyH5C>@g7;IV&omcop5Hn^Fau z5!eWtBm0JYhuz3Hu9ZVio2(4fatg&UY3BTnNuq0LV^F^PvV^YHgKKtc|11L~X%gV? zj3`%R7V=eIfnpo_>Mutue+`Lo{HhD$>uLXfcgK+HYwp2CM!TTsa3cyln<*WQDX|a+ z9tn2NzgDD4*qKseq*G71jf#$iUYkGZob)pSEgZ?lviUnpIO9{9VY@**3ZG`NxaC9N zQfax(pJkPIeQ1dE!hc}p=%BMi&D>n8EDxalpgSlX!$yjSTaqc+0-0lC0kpuqlT5Xe z(t~r%`G&()k4oC&wCq2njS84Ur&Fl4F01f{QkBI!N>xiAEn%vBt4#91Vn=_G^t&sSGF|C84t`mo?lJOi?|haybb4CX$In zgnon@oHJuN)-tVEn$n-;15M?F{RpM=Utwv(4xt^tqf`iB>cF@nPX3!ZBCJd3BC2h1 z&nkWXgpz{MpuR$|4@dXnsZZPqaFVDCV1b-S8+bP$0Z*pa{h5uy2uvR(J__;%k>aJg zwz``c<~4{!vwhYyJvp{s;3=5T1S!Onbc3o|Mzy$Ve=N+hQq&Xzu~&vWzE_0 zK6<1Y`fXENGVJIjB^I1K{c-@gonCxN6ZZX|{!nNGiAwmlx}!$@PYRFWf2i<;?5tgE zZ2#Aa>e+YC9rbIY_^<68Z6Z(+EjUPGd||M8Q3tfR1t{vQsDuO@g-gcwk89S;)|%l& z`P(>XTV4-=(agvC)9B}+Onb+XUw%3BzWs8it?W`#QmK>#ZAa@)Q+sZ@>>nRn1eZYW zuuC0~get%YfR1T~@m6P2(OfCaB>PnuC`v4d5+f$2@0GiH6$p2ss z?8U%S8D6N(Go9UOu{lX&87#-%c8^9iI>Kzu^kS*xv-Qm>6`Nq9p%oonYeOOfma~Y- zp1JUbr3OXFha@Xi%sPx6qJ4;5%pky-r`bs?U{g|dNII1@6H~X1IR;z2FeWQu<<>M- z0}CjcO&sztGwg?blLB^c%+v|=a8!Qt%K?4aF__q0DGs7yoz7-9z80Ml6GRQYDe@m((Vi{OBLfnwhfouy9BCGtiyy`DWt&?@7Ez%mh0VIeQPU+w2}x+#kP`{Xw637PQe2*(FW}BpipTJ z^`+56-#6=`>7Mbo-eD&g3oeTztW1$<*L5Qcrm@LLa4!yX$UoY%rujJ-1m5+w&QJgkOqP+3gOVv8PL#< ziH$8cw9updWa=#U)T)5uZ7$7U9>;9!CeK*e=681HIsS>6fc3duhOThRQNK^Gr2Di0 z!L3hpJv4G=^>}N-8J6VFd7cn5;c0)=EC6I0KoYh9oeP^GTr{&787pxX^Hm>uz(;UF z{3}a%hFCK8R}F<7mc;-C44_1K1}iCQ#{$unQ@mlN4-6LGS05YH>U8)VcWyAGrX+@+=NBlMij+$}gtep6YnzD<#ma4R@b z5p=Amy$9zrVO z@m;i+9oi>hJENT1r!b+yFWo)<=i*SpCCKTXgd8y34T(t$TXrJM^>D%h$?C5l<0xVA zWz=q{Em*d>Pzc-n^#xry&dnFxGiaiLw(^DUq?2n@fH!`vRS2y;0{iX=j$@6oWtCigElg#NOSgT*rnG|uZtK15C!Pd{SbQrr-N z-m_<^Y!S=HE`LP^?ZI4dUT`R{R@68{t`xV%2VtpMc%*~rU}c9@Pl>Ov^0FaY55Hlg zM!iuH&Fi52j>Zhv)#K{AY5o!I+qoB+*b$evhfQC^9+d;uX43a-Kmk_fg^6H8LpA`l2C#lrO#(!5B_E@T85_GeQGE-dA(N_ouCR$54 z-3MVu8%}^PTy!VifBb7+GP|JKkoJAzrr$G@|MRJ{{tr)G(aufL#Maov@qZ0Rl9Vr0 zaa2$@Qb=G6LBUt`ktE8hT$tu%<5a23KA@xE@XX<8HH94@Q;h9LYROP`8=gTvRZ;>7 ztXf~ya(c+Gq24bXx6%re0kaED+lT9Sbys{xm)yReZ)aCPbiEQrU}|rSkq9jR4{z@n zC2ON}37+C9+paog+qP}nwr$(CZQG}82Gr7TA9D{Pwpoo zcEpYylf`ko+E&#?ZJsOB7Y~fz7n6fE%Y(HKL<}!U#QPD`BAB2w=28>25#usphc`|CEj7@-}YZf=mfA9OKI`WSg zyoU2$sSiE9``SJxH=LA1w@ zE^OJuPXKdbyX{OokiHI=+We7g&c-2KL`*eZqrFw%`I};?nnHuV*0KkqDCI+0ZHdJY zZ?O$g30?To|GqQ2XUFF1*+~r+#2N#Bxu!~ZqDrOeg_H&N?g`8Nvc_giJXJ@HEXjVl zc~N)=zKqt`?Ut4>*k$or(L^g3(5$77kZa9eAh+g_G2FXoOc~K{drwxPkyXLp(n0$@ zi_IQbXc=;KTi65%vRo9JCl;A!2RtDpg`o$_h}I<(Xn!lYV~%2Qna!%RmQsA;sQrrL zpe(faBqh-vSi+m3RMh?`RvOzr0u{M6nuRuRA88mE6gInp}X#C4jpbfSLntzvO2i&K(OO4($HbvkmTjQFlzOv;(#wmuc14UttS#STC6wo{A_lbm6%MuVS{PmJkDv znI~FZX|2>zLWVNQD{jypk8uJC%^jF!f{yNq&&wN2Oa;|JrN=_ms$r5AHL^3RTa>s5 zW+(zOijg%z!?ecuIHn*-QK2P{Mt3zI7}V98;ZatPY++o67nF6aErMiz%xCnG67N1) z*lfHTo>kZ03iz^F)*G@i0L@|KVUVqe+wHHvwO86j9+=(Vx+~3}|1Lmq{%-<=qP?Dh z#kVei&(Pe-!O_ad+VOuJqGrjTStIZveS)H(95*j4HLG82D(8;6=cy_PSy&+#y$+1) zU?;<)Jn1KEo$eq1V!Vk@KL&c19cF;^OARG9ZZMf*yUR+u@^tWie}Bd9Roalm5Bk;- zs7mXBR2ZlZ5Sc9%t;QbKGomA_A+sT8K&?qcxV#H|PBj8$_$i_7wMdQJf7i^C&BM9p zZP0zO)#=f$7%NV@*f;G$X=UXWwiUx%3d0|Tdo7bN1I~*N>FhoeQOPq@Eozo$OJ`JF z7U2fFCn7j3TdC3xEweD}-BegT=FXnGU^XFo$*}cI)*$*dLs`Y9w3SBXR$B+`JdaMZ zMOI#_Jv95+Vkz)p2R;C0E$mNd#=*Tfg3Nq>xv{zdV;v*ZbaY?EC%9jNX5+(1uAa{w z3q#!MLL-V=%+OX7)a*h)kUK_cpQZ<&&27XMlm12#hbsC)jMAgG93aTMH+g8L^$bpm zLx7q<`JzS~a8-B~&_g?x}ozd|AsRH;Gw}Acl z;RfQQ_>I&5_M-a!W@B$cqi3sUU}{A3y*$fkPGf1zMB{8`+)&6su&}=35mB8y z8=;DKxld+aPNp{)_f6m= zTlfU2*6?~-Dz``!^NN!hT4n9Q#^lgJyH!MeA9bWnD(+2&D`+zUATJz-`o0T$m?__f zX%EV^S(JW^D2myvO=+$2x}NmuT-3v5vi7*!dBApwK<{@5LCIDoG65ZM1hJKPq6W%` zTMLowBAZ)X;h~C`?r8Jsn*EZ^!F$+Q6X%bAfX7Hgb_M1Zy(RiXp_(1- zIZ0zv1qWqOnSQ9H#^bcLdN+KQ=4PCWe|vLa%EqEtc@-6|zb`?DiGgPn#y zYRxiHL?Z=&;9YPFo*(4$fM?+f(qmJw>CGoc0Ys$kQsLXvJDi^TkJZ zdP7&25C*Fdd`Y-`IW3wwt-YYjna;+)X>%~s+VGbvTPN7&8Kn7)c4V1ye-`Rqjk`xh zM?ZofFCT&Fjq%nLVkrTu^PhteR^{jLGfexYR=USa)BHJ@F10#El*~Vy1hlp+kbUU6WE_M$@)%`%BTZ4V)CZ}MOYSxJ8pAU(!3 z`70U9ZQ}G|^OqB%tJ(ksD^=}-x-2d3 zvU5N%iLLqormMn$P+Mn^1YpLO-R(r`Bh6}$Fp0S<=9Q@{>J=E)M~pFTh#b{Auyv(i zL2Fi(87@kS!_*S=F}wQdFh|a86*zn2Pv0hvh8K1 zhIFbaGg4cPWr*hG=s=Y4Ww z(OzI4AWcOhKnUk&K`LLuTi^}bicR4gk%y=m^fj9thqsK9zmBHJjXj! zUo}j1lA(td^{V;Vl$EzaKKyR^#6=1n*&BXXp$p4r;S^2L8SR4Vkk{h5v@k%=-C(ym z1XW2X;lDKF6jpsIS#Ay?iEDJR!XYfAQ!w#yVPPPR@a1wM{4kq-4v|0Uq(ko@c-Vj$`B?eY8VgnM@MwubrVSGM+GJH)%UHHoQPJptK`z5FFj zf~^c&L4;{F)sz}Wtw4i2ng}4!fMFf(WsB)EM%ngkqWKF>)vs;52ar8ZJ&ZMTDvtB~ zG^Kt{aeFaYudk^Q=qB#)+nxxEXIEd~doRhGv{)2DtAw-xx$#z z%^zy2CC)Lns7f6oZ4qUg284}`Y@+H^aX}4~3uhn)54k=XyAP}lb?quAeNXQG9Ber_ zG%2qXpYie}hA5~nUKuZJ$vqwWzpy48&tZO_95jZP#JE!?tP@zr%um{p$Zpz2?Dxp9uU~b?Q%{q8jlF|9p8v*_!_=0WS8PQ^5wl2hNnfkeBb^nm$o?d zas+=bfn~w|y8@8^KbruBERFsu2mg`visGbX`oA~Awuj_%3CR6%MQnV-Bm`yP81dZ+ z+-Gc=B(x^t*W%lAKPjXbiE-WmK1uiQ2h0~TQnFUZIIcJw-X1@1A#%f@AwkPQCiR#? zny{A8#gCe2=57Ky7>cyUWG`ceByCk(VR#n(ZZnw!R^_tiw1V5zy?S-;-y!3vACpL8 zN>l{UGsE;Y&e!{~LwSRq3QdpW+KrDNKYDld3C`pGR9~G(w|TUUn22wU`ufO^u7{od zR6HgM5>U|=lR*@0dc>qE96L?ryb{f#lq*~OQvc|+kzq_OtXAzb6d@f!&?~kv z$Z0gBDrkpKKarP+h80J@pq|HPa0Z@6lY#*K(|NQ=Xl--Uj7gb9TCZ7D6@L&R8Br#i zpNqgDXDv;x?t?^@4dj%V_YgMKwaDv~?HN?R7|$4@9^pZe`|k!&XXVc$x9?WK)W2;7 z$p5GR=zmsG-;zpsBLf?ILt!&Z$A9$+s+9hr5iUkjZl=JKz3~tAUrV0I_YEh7Kvpyb z0Kk9NPo{5{NZvGd4u3w}zD9lCgA7|L4ZB(O*~OKcwnQb=rX@3;A4{8e=)TLEnDl&k z+(q;SpgcC^m*K*gt;mxR;gQ5Cojb%pl~_s_NI#5BX~;B^STV;XFR0gj zgK7wg$iBISX2$p}ZHWA+*mt6_Gmm6!CgP4);@bL^lQa-lQJ)!>ua z&G!4|?s{vzQ1qbnsa4FW<$-=|K^!q5P+v|vXzBj_?8zA{M@!7E(dtWH*T5I<&RCYi za1#z~m^pb&ag*3i%9d2PfwPdBo|Z|33cRGk-GPbW)^vq zD4a5vSMUQ=G*7=-2gWwXKlI-Becl7C>--N)$VLkXSWd8B`}l|s z=~8SaWM3>~$UjJC82ZerH~buA=CdiN+7Xv2ydIFj;H6PVLliPN$gww=KTH-l6(FX5 z6RG=G#!s+{*a#t_MbFZdM`Lr*$i-{Gmprgu6vO4g&L~{<%5&MkujXk1TQxGzWB@_M zkHDSMMIttGXx9ykWdZ`8Fy_&}uGtX}YU1-8pnrv?FJ{x{U&&@jb@3IpM7A$`T)Y2Z z;*(Kk_r0uSz2F;}^=kk&lf9M}C*r?#a}44G4anuSDu=QYNW;sCMrMrMbII6 zuRIg7*yYGx`iW{wx3hq29||8JAqsq-0HA*QcSmpO2co>lH(`JIw}f5%|LbG?cZ2s| z9tu?oeb)25a9;a?t#+F7`TTjjW)iXd;VT4v0O71~p`}RSf)!gVm+_X3l@(D5%_^T@ zWguZdxV<9y#!*6Sw)tvf`)Nn3EF3mVJl@`KFuI6O<*k86HrB$WJIaCUs^E4cgXW=3 z{Tqtu#Zs_HdKD?{ez76+=;V5Hefx2=xY?m)$|B=og2v{t?TAjErt%}aB|n^9?@;pE zJ@gy$#vS=f4F$NYtr4_8a1YJ^T_+ZT+bE`+7FQwrOO`0XXl9N+y!hJ^CX}wsDx8UN z-^MS-y7dZYB@oRXi{`nhd+V3|fADu&RoP?z8Zj6Wbpfqn#I0i|VyUy#__Un0X15DF zHP>-}$??F6{-ZctiXTlEVjk&68KfFxhboo5LJ1?JdMy+f=Zv@YAVNN-n&oi(F}SvU z+S%#K#{YYJdnz_<5kRkK@h&NP=vmaEYLblTaRupafcy&*8Al}a2XxJkH~4pRSGi9? z0G_+nNxQ7B60DSGEgPFmzctt?xW=CRdo~$O-7_*iEls`c1Y2@M?Vy}@CQ4++Y1Vb0 zi1m_5`|use@guA_8gZL%*O?yIJ%5tkhmEaX{cMR1(Qfa*XEhq^t(|?}@&Do*JpVD% z{ohIF|0mM?FQzN>&-nk}O$M6OJZu#g(Z90JH$|9PhzTiMW3S^yR^WbxTDSp60T8AK zmgvri(~L>gx1JAgW?aiw5G<81ETK}F59K3USwU6-$0ffmI6G|oG- zXPqd%zD;dy5TfZ4r%lx!ZGCgz?vX2xEX-){*9G_=Cc83vnNbyYbdbxVwpMUDP`mB4 zP?|J%nEop$!%-_Z!eA^xZMQ_|)-VNVI>}KQhVB+{Eo0*_X`Vt`)+sGD<9Rh>wjq_9 zYQ7z|El^LRjwWb2BP{(ZNgf?4OP2||#ORl(pxcSN0O-yW*SVIS62V;bUZjyBH&*C4 zaVOfVu8g50{i%LeNIM;_oS|1ia#3D-=OeHI&vI}wq(~+glKtY<%?zu8>`r1I{2)$o z{CZmKNlulC4Qt}gtDh{+B`qHxv)3XJhwYJB=1mL{R3qZ?&Q<)M?S=$rD`Xr6wB33E zi&jb+8JXrC>(XqCO;j*1%&ow8NPuVe!ThT`g%N+Wjt@!X!A<=7{lkMDi@VlN8`as* zPYv6>9)nK}*Vz^~!95bP%B<_KI=He{^=&RCiy1Ua9Z=KfsvbK}Dv%@DyUCE42<4p> zmWLmljgy+V$CBcM9U-M!zS<%|Ad54vai(w9>Ix5_m`rI@ zfN&FIcjzzsGt(_Sae`LwHQ|~nDZXxHBE)`i&!Ul6tp8doOF^*ghn1rIho9PP_A*I2 z_;4CCJ5rX$4|v|hmBJE7|J+4OoXv(6217U0_ z5_tSLb5%>4K&^{(v1xWnHGYUN{GPsC%Gk0ZsjQEn_nCp-v8jJlu(_ux{(bXtrhzL2 ztwOHXo(-AS;*|3VSmCi)6A8GTU8AkicFPuGLVc`GHaWGKl{vv)amg8FZ50JYMEQ4; zdlsv#t%M43N+?Lx7PlVhuAdRR&>MVA?i3J3aeraB!h+(gU>!=#9h?6T;it$c_ zo%EYYW_73}g!Us)>Wb4y;KWk{0EiB>%Y&SgBo|>G;0B706VlhV*)wx}lua5z5;0*I zwG)%*_6s0(GlL1Ngd5rPv%yWo$`iI|(P6mzB*f7>B?3u!@VQ+H^PNqwZ3V-q8Yloz{EMZrx^ksIC)(>-8TJY!5J7Om*l-8KU@l zd*bL@19FHx2$vZhLti4&BV!-?yso6 z?}q9Y{;t3++>CYH80#R16zZ88YOGG>R<#I&TACc?${{LDk)w@sx-y$|SsLzlE@Sg* z<31`>&U(+59nY^H9KWf#Tl164gEa8lU^=x|OQvw@Dr8$EJlQPv>GY#^HcXPTY-&2} z?2I%;UkNmKt8UKs4yCHENf7cdf?etb-P{?<9~ftj&zT^iI9$uf66(5OB2;2p_Kb*e zfj7%?6i8oNR8vEk#Et$uH+odkQl|INWNd{C9~lTc7q1Zsduyt2M3rTwirc%`h7VaP z$!zS8=iAGxo0x6c*PhNv&(|ivn=^M|$BsZut7Q1m2{_E3BW$F-TCLR}u5u=PsFgpY zZ=-v5OP7qilvNIpUCxvJnnAeChCJ?6GwDT0X|>N1Yj9JLw+Oi=hnxcK&+wayrwnX3 zvIsSKHLcmvxFD7L6Il76+b8g-8Q*!&ZyRsm-4$bgdy~SbGY~w^7U7mmE>_g3q^1#* z@}g??!@yQZg`7x^k2rPoYPR9U%Sso@cpq!&p4G&SHHE@**F8i_lV>&Zg_8KU8*7dM zl?gLoAt>=MIV}HBB+zI?8PN3*%z$Zh)b&T(pbwlM5ZL9iCCv^igm*L~TXq2L5VG6~ zFeQK1*8F5^2iS~FgdM&R-KSg*VwrI72&@yH9a`SuIL;qj!B#rvf}bE3hKw2I?y_he zfNmYNf$Jp~{8o_?LJm=-c7&HKdwrs`do1ctx}FQ6z$RQ#du@KEy~ll_s*E!M@fUne zPb)u_G)a>Jh`h>aa_f7CXlH#98220*^PnW)2k0jU?J*kC9W7ct$dq%__RTf@CT9F6 zX8Ty^>_C!I=22&Bf6!&~dqacWzPJ5Z5zO4bACs>Jmjs6m2R5Qi$&Q##7!fyjWIqCo ziK*xWZN*6|+6CmV!-*`kdgHtRa^IX&Pi4bM>B!Hv*tnY*n;tQV3vNNxXo!(geH#_# zzEbEn=a1e{Xbd%GNl@bkIYdH!w9vX@veo7-w^r#IMwjYtg{M0%8^uvgg74=xug+A5iCTSMZ6GIHtjxjtl*i>xnAa&Wd5a7SX$9 zFfHW&)L-*x#d19VR`FVC%1<^D6^JJk!H({xqKAbgDa=xQlg*TnQj1}U->HHaZ*e?m zangGRw*6o_#N24W5#JhC!r^v`5+z7NRk3SkCmz~kpKVSIGeLG{-yKAzhra0oqQ#L0 zPz$4jCp<4|Mz`osN~i)3DsX*seZE9WUUlL=cNixl9}>gb9kli*c5@Ot;hqB&?=0f& z*C$r%>UgM5FSMy`K(}k?+iY%xO;%^y^P$L{mghh`JjS-aDXV(!4Ytvsz^tcOgB^yY zz%MUS{d0a&1cHt3k(M{`rz-e;JJ_oxLA2HYAE@7^Ye_4 zdbgy@E2y$_?onNM-fhF&qGi7^-ry$IP@=jBH(_AkuyG#Oxz1bKR#53NEVG$fw-1M& zn5T%kU0^V_S>AQ_JjV5qSSS@yj^|8N}?<2l4d9w42rss-} z*gX7ZU+DL5NpIYOM7zgTy`z%5r=Gn6OuNO-w+Pg2=5eoPaIfefwn;8==^?rMt)78f z5~eqwBaUJcj{21&2~k(EM`_^wf#&qIe z@8v|_b#|}VuV1R=21W#2+b0-Jp&WA!5C)wn&*V9RAU334;-|sI!~KdzAJq6k*}eSD z!7qkP@M(w*ncQF#H->Dxg_Owkm8NXT8e+ftl=#42Y{UhMFllDTw_ME(Nvac_C*fY6 zTXU66@Cu7{1JlFn%rS;5AS4y&XiUwrVIXG<`WJr z=ZW@$_BRJGIDGe3Ne-RZisgxSofs#6ti1F_zgV_I9uBm8mWc1&t=D+Ov=;+p~l-A8ZtcUp1 z`BnIGEG38p;qqa>mq=Jz#zviqC!^)Q_{@BwW|Xh{aCc(Jx6-IDBJlDdIUKIqp0c@2 zOsYRMH33zJE6BxN;q|~2;EU-L`Yb^l0F9QFUgqj~3ydsD;<(bB$;Kp29%#q9D~Y^> zMhp`a*-z0t#7Vj)RY5U8W+;8RBpRt@H@Oz8C8UcaKeWvbxFIZ;aD3l>ck`C%tr1=q z7BOC6d2#K;bB>~++oUNPzs-^7pz4lkAo}ul7BQ^~6W?W`nQiGz%|T>fJ78VZ7J5n? z8DckqXfLaW)YHhszpI`|^Lx!v-yp7Uq%e75RDz+jx_VUbHd;hmif4>#q_>Mra7-f< zM2bg}A5y4>-XPq07Q*T(>C>^s59M*RL+zURlaou{GcQ7v|z}Vd=%oL$+ODq@<@YV5YVCkWjAYnSOYV9 z#98Qg_r(u$YY`V$kLa%h)k*>?Y89|EEhmtUPFD$Zf#IK`j#M&-=MB>>Jzi;DAw6Fo zcQijnt`mZ-H8=bQQvVzPMJ1CZOI4(njSxZ0O_o2)4!~$04lv?s%h@&IET7tS;jpN> zD-4NX=%*e=jZI{RyFpitmcn5??x8?7bW&dH-_)1x8Gtsgj>iYXuu?iJ{b9rk95Lw* z=N+o|C)ROIHk*c+ZqYoNJ7xnJPxaRlTfPCB2RD}TP+MsGYSb_}T;M?xw4rW8*P~!f zvG1zXJDhw0(Oa>89L(3-W;d%;)mL&I?nDo*JgW-xoO0$uAQb4cB}Fqy^ak;;cCW^S zTFs_q@HAydkHd#i8C@WosPhK^IohWgP@b;z7mde3W-O)@k))*g4Q?}>*&v1>(RPOf zlAzD`CW{7+LaD=7&wj>`4fn@X3$1016|u~uhJ-NfbA0E8zK_{RsCGyO?P|w`n&=Qp2$n&%+KmwIuB(%euMmkV;20k)3lgwF_bl9%R2}Ge7aVj(N z&h(i%sBOODQ8382-rJCHWI&n#SX6vQe3RtTpduFJ!1x=bqpE%qwgO25&=O!U39&{T zO5>)4CZLcqS`(O`nrBG1SL1OHM8o&E*Qn>nB3|H^YN_aDzQ@Y&f^zA;HtW?Ci zpvw1Il^xMoi}#`LPgz5_lOM>AD^~F9ajdC!8P>}E8x~O!ejPYf((M93#UHIJ1^~`j zun}W7o*ZPtEU^O4;*(fJL`KWppc7S`E}T7M=^Q^Jv>-z%r@1|zNu35D_eD}u$$`%q zBc4S^*Vw9za2dPeR-$`@M1z%5i9ai`tL@j8gOf*hp1H;Q>7&?E_~s|sB&0j1MU3Lh34y{Cug9ch@jZ7T zB@Z0Tvb-mS-yWEka15NSFE>EP$$lfsMQB0Dnw7sZ6RSU144ixPHD{hq(o|{F>?_Iz zb%HeX$E6sST1b4Umw)Je_bB(r z?TOZ$d|^`ejCgis!_w>^`)OeuwBS6Q6ZS*dAgFWUSnIGdVoyP{ZyT!pRpplvubrnJmT>ffyP*&Q)HL z&Iz?aB$0kpT`{1u4PLUghyyu1nQb(L=_;>9I=1Qv#XeF;*NI@MgCn*TNMplcw_s(S zuL@aYja4um9|{2EgDO8FR%36G{!1XlNQrJ$Y>6AxJSk2Q*=r&j9rz1#+!QU59|l&t zZT6h3z@&)8WQu6U2Z!K>xp(nB5dr;g>=S)y4#<_BXdtr3-3KZ8i$Aos8T^hRp_@gr zTLl|iB#5x%x9+5bvtnxot~#JpO7vX39MVFF8f(3Mj7n-M03pm(rU(c4ix&m;j4VN= zOlT=*z#sum$gd3IpKpJc1mu(KWZvJ3?;GfUR}%cE+s|TFRz`+q-{P77UMy4fmwlHJ z(wCKk#elqf0UGZqazbNmzGh(&vM3oae?*Z!nZIR1%~rKnGd{>aG?w7)=?wdWR zL3CU!Py1n>0iMAd7iKeYvk4&Dv`ns}x2f-of6J@iLeqVjA2s_Utj_zEn9jSIv6@&% zbkv6YqagTKjdBN?Pzm|AbkWR`;BG9@60S7SW}4A@#L-r*1Q1sfH%e|->7lrdyX=zq z4R(LzVp)=G9qhJH3`mD`%}gH>6=bt-84c~LRTw8h7lZ@S!yn`);X9Qh#?u2Ul-&wwY36CK2JF+Y2Wh(@oU9 z!$bEFE^Fpw-6mqVgOX-%43hb~bmc7&LGMBtL9g2<7YtV%s2xb9H8jVkZgiUI&~r)r z8P;2&QA36{kU3=6pk}Z_!uTA*amdT_2mq$@BbS}G-7EXGI3q{arqp38w@Q9xl4xbI zqE-_j_dvDI+Ej|=qwk#EB2b17O=YyVrldlf;wdoJWw%wOte8u_gDTn6nBNGf4MDMuFC&_QpP{InVdjY_8ygRd5b=gqbMYi?jUnZCns7utJZRg zq`H)?G$fYJoRv?twSEU(fau_Wd{8rs*)%?0rphL0f^4sCpQYZ|6DyBj_-xgz{fuiP5mT zC#Ag+ek4ki!?lG5=#yi!B$puAxVr|}Ew<_-B+rT?CeNB9sI1rnDeTr0H`wsqb2m)g zvo}=T^EX`HGdC#F=4f6h1{Hc&?ZLQ84#ta*MTztp6yb-(Mcy0h6_C~gedL}%p7_YE7Yk8b>o-mTd5PpR1^6*bDeXr7Hlgk53x{%#5t1Sc1i!X-Ez5s1UB7` zL6o7U+@Cf9#<0;L@JgGL;e@?g&AG%~dE#hnbjGDR@p}V>xm9xWOJK&-X1Q-n&gcpeDO9hZ}$TK(( zaBlJAJ;^?C8Ypk~vuEa!LH+}FhB>=CO~YtZ?=6*T?RhJg?=u)8=q7aD<^pT!4TP5YvPe!(;>r%M<WYiui&y4ZKCe-7fn*s9L4Gx;}Pt+Es?2SH&vMg`oU&&vEt6iPd3yN!%Ij`kCv% z6QI$U6C-weO!neZ1!W}eDOcjLLAUrH z_`a?n@nXHaKtaH!^MSm_gtE6gvm$$w8liJT@azCQ2I1xwi8LD4S|-b8^}-4n5Efz8iucWnIjYcw;y8V-9(R3kK3-Y`n;4>L1*eeR zEITRX-XhgB(-9w6-BerCt;65l;u_9710LkUm_yF`?nAApps9|9w@``&e=|U)Gvv3W z%Vk?Y9P!JP8MK#mkPw=mjZ>SeFfGnZ`m^t@wX2~WXD5r|)Zg;w4}Uw-djOC$u>mnq zsZoU7GZKb9>B>8!I=W(ysyp*7CO2*P%R*Pow3K4pg)CIGw-Q@2m9*vSt}YLa*XymO zqCpT3!<+Nw7glt52QozxmXm?G%<0%%oJOz99f7$JP!?@CrOn6ol2>sYya=kWprU*H zgf>uRWz##HO64$|ywdNs=Dv?{z*x1Y0;!o9eVK3s4XsvPp-Q1)xnr%KilI|w^bAoJ(w=N;Ap~<% z4qHWB<$zJFx!}U)dVFo(oX@^2>$2DsBufI|cRGitJUbNzpH;M|NjBzXSv-TooOTjbM`F!01B#^K5;5#RVCK+y}t<0qYv$vtS%$bz;8nEQU%u13{}1!I(kEXmPW z6?Ww^_&yk<;;UbE43BFQT$$mPfl=BW0RjH(a>-AZ3^T`(zkt$(34$?&e3?s z9mSC`FbgOP>-Z0!2o z{jSdynky?2zva#RLQfJqlK5BvO@3fRkv@KY6EJ~g{<#$j%RzEMN znS6-fznn`mp`d4LQ(&lT(1Ze{EEGAH4UoMcHg7L}!bdG*Fr-{6@Mj6ei<$mpkaVOeBGV)$TKWJ1$KA@&u;?M)CUP5rv~?G2MbLrxv8xN?aU z1%f){+F4_`fJ!LZl5;8{9EbZ%&X5-y|4~CAH10O!+)eMXy^>PO+)*&L6V%<`}*f| zL1cqQB(CMVEOpyvmWi>+V_Mo~PEYsOk6M3y1hEZ9J$>#ljn=AQ4s%u7xFIdXC);g8 zIuqSl-mP8)0sdy8L@m9QQeeFa=l1CJ!)DY*2<-KBorX7mSXa}I=s#6>oPP$YQ3HV! zhk2PyZ|xOE@hIsDEke329mq88-}#^UyA55lGFI;Ps0BI&=>^&eJhd;d8C{?I%v=Kv z$^Fh;JETbyIYIZsQGn1Yt+tQ!#vJlP5#`hGX;+m9(w#NQ0Kd3kp8~FZSE(%P>i15hCz^bhnjB`43<0RFI>=BN=qkD>({IkLL=+@N2qQn6iJHEA1AjSm1WM} zoKT6)Sq#`le@324q$|j7BYl`jCV2WOgTy22AEtEsAN1&*Ml_Gjq~c-fLZX^A-meW3 zP4a4ORkSicUW3zJ;Aijva`2zKhU3bZ2#ZGQlIjIE;C{VI&rdlv1}1*v}sRl5#9%V?J&fO$GYwSJ(CWe zGb6xi;)E7qUrk^I13DOEk|@(=XCg;E5U5;=uTimaPQTvKOkL=J*W1>0HP=4G1D~`PP=&K z8EP7hIz|gD9*H}GKgWRuxldkKvNGMC;s~@0vkNri^KW5bUEDnvwcy4QEyrrntla76 zJ%rI!&FlXNP=FP{Sq7vLV^uSsk0-N~&!39JBJ9L=0DM4C4v!MBId0n$ZSx!zIADHw ziQdAvjU=V|+=mI+j0|boPOesvqg9>6!L)7>ji?vB3w3;E5eIL=yWaZ=3bo#rF7?hh za9&I!A8GPPY8|(yV7DW`Xrpv2@jAMCgMsQA{qU+v&$YuJa88nJt5>hiUI=#LrFXI| z!sM+3yQKW0T2s%O-TGbrB*vp>@V~H`eI2Ag@{P^Bf9sF>e*&BTbnY)wkh1wp8kiB- z3QkQeXZB)h=Jx|1PZOLqH$R`83PFBBnf%miUos&|)24BY_i8s zo!e-6HQRTmS@|=GP?l$*ggB37Tu$}#?!2U$eb6Wn|4mR4IgI*U&mF?7!b0% zN6|RIwTC5t5Tf$4>7aU?s;(CBAlcxlePlHWDYHF8mgo2wg+UC>8pRmyqF3w9H(4sT}<$4|JBwRo5B^u0BeF+0_ArPB?lI$#dqMwxzK z4iA$I(HeXvw9zZ|lj&y*)&>eISCXETkN|?IQ-SNBF|L!CG01}1*Fi{^OSgGn7}7`2 zGBc#1kb7gANPXr;lVB?tYj7m@5b+qXpWVFLF#(0m#I<(zqf@jqa+AF;Km8!?1^ikb z7EH;|m|p?gnyD1aFiF?8wy|a3_2ff&uzZ=bkDPp#3%_|%xV<_SSKGfKW}$Uf*=(Buv_t;YH_{~mcR za^@Pn%*g?Gg$4{|@CRY40OF4E(9RC@E|Cw)w#^OLE)dHmZG$B9H9(>9=!)$%V5t1_ zK1UDz1c91C9aP0~5|Da@G#mdBi|6kx22h#CAcXG#hxuQge3||QLy5lv+$S?Q9e6P~ zUm>UZ_%Gi0%32}QK3ZZq$#>)9UWw=Zh>p?io^TgAY6I$Y=Qg# z1%%B11fhbK%{(mH=RCw4e14QPz8o%b~>j)Wb7W2XHt&>(JPo9J79gEHMRBKx@tf@pS0mmaK78WVEeylhUV5Svi8F z6*lg3$dB|Vhw#RDf`b?C<+;}c-OcjeAHml}^88Qs+R6R|UFDo>GNLJ=CBi7DNi#o# zxRKBYN!iH2y5pCMPrxYB3k!$MDDhL9#Dp+TVow3RN?>Qbkjf?oy1W+|Ug|hp%(ywvT|}sDBxt~apCSR%=3e@OVORy;xg~Vg(!qD??0%)yy5gM30Qqu zYm=8a7&z`YuiPH*o?>!-ROTxUp;NwEl?BsRFV{vUL0Bu=Hu!4*G9acgH=QK(sxPnb zQI61~%V(zd706{?@PQFCn{TO?O0K;sKW$5Jpzko;VE`iFk0c_+>drAcP0LcsunYBC#kyq zWK_K+2jj(aFJoGjCU1yjog14dcnNeWn;0Z3(23h*dGvh+oT$1Kl{Tb|(Ue4-quv4| z)7XLm25xD3t|9bWt7dBi?~={#@6R#exnG2zA_%7qFb`B?q-e$7g}J;9Ix;4vMSYbh z!Wrb~f+v#JJ*lB`Q929_LMCnI>^NeBMQx2uWlY+SWG0gkeJXPH)H!1VjWHU5`0_Hs z34nkwb)8+Q?yCu2zDZHpF+n+6scCpf{2=H#yLc;syZBi`+Q^gpOieg-bBXUq!#eGO zbj}W>?Vr=?Mk%Ss%(f0Ba)Bt!#<$BQ-a}`;yRKrruhEHR|r@goNm#I zRt~HHarXD_(2D6R&G9$5%>K*4#rjWh$^Qdf*7KGPl+aYT2L(kS_M!oS9;65eV2VM? z<&ET`MO_>jW_zX$)t%DfUr;JjqMo8y&j9aGz&?JzXqn?!eOnEQ)){P!vyU#G?_$33 zWtlH00J5wq4%skCx3r&C|!Xd6ALZyPyS9){!i zi+;RaJWHTgF~K%#JZj1i$W&}05ql}A8UP5P8}Ba+&IOITRYo6p2<4o z_>;s6`xEW8EcMHxvXIj`eprdU4M)MH69)v`#`5ToIMAIR##*FHQ%dc}%hrpRvp@I) zgh8cfYtk<3_3dpjDv2FIV{%14S&lPUB8T77AD4{td4z98zqMktXQS~6P*fV2sZ`hq zd2ww#a^M%-<+rWrJNSyu3YCBL7{d*Z(Tr{l~m%Qit%uHb(jWGe+8wCKXRQ zwMO+56h1|I^?Yb1xuI1=A+G5;j~uqJC0=jb&@esC3R6m+zYmC7WLAMMhHzK{B+bIOm9|E-Cf!Hc*t5g7^R)fl_0o0Ibz_a|aW&lmK#f>3&i+f3 zSc{GbPBgq0OLu=8X0szMgHEzlJQzzi>5gTSdJh$2hjo!+1c3@%png#7;Z|u;^xMM9+>%ct_g{4#vxF2jX?oT<^ro-HVTo zPjA$(w|5>kT!(}A%}+qZkJ+dY_uEh`zWtk+w0$x}A4)@pXuAh;+3!gEKhp!cb`O%c zU*Q?Ljt^KiJ`+dVb%? z3XAfPyMPXs+FISO{c*%Bqp28@%32C+R7FWR!4phNVHxB`^9t8RHnsHZ)PW0IF_)UGWA|)37yRgrvEaNN##6r84P~fT#J@>j zd7+LynOQT&9{Z0KnMsMMP&9Pn(U)ifo%bl1Wb|2#+a$y$ed2|6j)n^S)c*K}(J4#6 zk(uq@Mw2+*g>b}V2^*Q+^Sl~41o}@r(@03+E6}|Pj}1tpGeLAP%bK4x!Gk=#uPV8i ztbDxUtxRUcu5xEF{}3)HVC-{M!XdA19RNsTwU{u|Iz`BEBRbSqyKsVFXeWiQT7Ib4 z9wPf^AO^+hKnJqfsj9Faxl&*t)am(&lPYJH(;$IzpeLk~+IVC*vKKts!jwcvURANc zuJzrQkI$?U2?dWigo+z7L4<(_dA=}0QNA#uad;}}_!;kEs1~tzJcOc3=vjCvvN8}^ z(*=SejEDj5(xV)2cp9#RO}5XH(m=M2w_XJ5Y}Brxh|Ou99LLkqjp3;@$K?4sZpdDcIVPGc?(CB!*Ef7D6oQ`~w!`6tBjxbAzZ=u2XG$E5C?fwCy+7pA39rB37)vC}jH z7myirGl|0zQ1(!i!_E3ZA*+W)AghN&;%_PP)f>qT0BdNFeL!`4S>n|SLx&6?jK?6D z0tu7Djj>6SsrHe#+fCx*v(3)Uwvd=$SYq$^n-I@oxs;nr#?vbUbL3Z@qzI!pZ9Ty% z$H#IUx-p@f!Pw&*Cl?5@xlcS6WL>TCc&I-NUDcpV5cFeY=z^HFg;2LrVNlm9BhLxb zWSPz*nryqePqT7+$q53l7^Z4l;*Ynl@6`L_5BtZkT;gpX1X(bbUiTK`B?l`hxLWQW zLafml2h@|Ig(SG7wyqa4%p!T%MBeb(DiES}x*ut8<_s8|`6ZXJDmvRD)4c)Ka+f!_ zb21Gwhj9E!%MZrEmR32Z-DF_vX@RF?C8t~9g8KzL#uN?-P_E8h6?+o+oAko1id!z& zkJAzaE@CU09`l$VFq?B^+zwpkB-aBqSXfK21tlRb3E>ys~A zf2zrur?7BO`NVQpylr0=oQGvB$54$S89FALf)aaRtdqoOpH7bTkt1%6Ts2|De=SdD%#Yg+#;j4tH66cHP!G$ACq7j7qv zjQ&KA&|-E`7vn)&!6wxORMCP*L{6OkVDCq?jwq?rD?Oh`A{UpOH=B;vSc~Er6L7WP zQZ2M2nu$?kgS_CXtb{A1EIUD7?)sJ2zAq<0Uga~UE{3Iy(u+GExEM<9>p)lm<(ZC;yv$Ic+>+Tc9;}B80`?9a;1Hx zQtaGsb4NU>GM`!bEooX0g1P!OKB>oM1f3#;_o-WQ)C6`(mDY2uqt<#YY%x6wh{j7m zrNuU}q9cgR`i5w&S0&8(e)H$lj*=KnjW`_*4jc2N2H_P0)V1fxM~G_t9l&aS1PHA# zq13Q})R>vLc2#{2o~o63q#rng9#dDX>p?`}ymR3-LOalkrUhNYl2{qfW$9Fx*Bo14T6;Q3pugWPP z%NbCYMD#i5fh}9eXYpT`y&!rxuxcfs&9rE%U4y5*K%S>Gy1Nr(09*@znznwAA)-sKyO}(t}YOW9D)BE&0(rQx&b+|;lF^W!ZghUdHoN6B=N*lyy^%HF#=Zdzy1}$s_9(#m*9JvMY|R;wLU<**Y0;VU=vm5yD}S zJ4CAKECkOiP~PQR`JkL7$a2-lq%|cBUjmbiSvBzZ;T+6|r-F$jnzBoYkE@ZCH3~j; z4LDQ{C}0dtYY*OC8m_X?9)yoW+en0G#P7RY*@Ir<(CN{3UWm{$X9c0|c+ z!@TR(Jyf}LTV~p3JX|?-Uu4~=KcD|x!kyGSNWC{0AU_cG$C3a-5&;ge#lA3Dc7e4v9k8>@wu%f< zh6u&$OTyQui$5%b2_nrFIyKp5dYsK=dTGno;{|F5mmz-IiW0a1Vb+Qy#2f72>n~bO za)sHJU6jd|bOL0cs#jf!J(Cixo8S`j7?XuJt^edHga3Ebf%-d)pIEmP!pwMy*zc|U zXjbQ@RN%VXYITxYC26cae&~&xl%>bo9Vn^XK{NPLqCq;iO5=qq*!#BkRFfHhg}z9Z z=BT?we?^5B>4>3jMAn*(Mz^hI)EqHI0*H#{{zW^VaqXExTSZj+DE0t~drFn7o-QPq ztu`~c4y!R)aJ-fTi4F^g@l&Bor)Cj~NC(!-FkcQb_?QbwQZW$Z(Wf@2_ZmamuT_+l z$l_k+!plfBp6sx|B!PPur`@8r336q9enZ|QriDn#@9|OIWX-Bg`go6t1$p!s>d&;3 z#{Tr7<&vZHdYyk$O;%4|haW#=gIG~*Xc2PwD!kiWPIpZ2G9T6FvREe*S$4{deWdeO zne*2Is6!~>FvoNW1~I(;jJU`g!}(1@8>wPCiQ#iB2$7Br|k-N6K& z8gn0q_U5YAloSZ#5&DVG;PUUDOEz_tO*8F)xwBM@rjO*|ANaHrtmzd3VKHLil1$?z;Ct;v$vU4@5>Viw!am0H+}KiyvhmSKim- zVs*j0*3b~QtZ~iSO2V6+M+JHm$eBeweTT3%CkPxxPD$*RnKA!!*)yNx`FE=NgY^U8 zbiNH6+-uw7iztN~j6N)lgw5G59#N?jUt}w-;qBQjB(J z&-@m_tW;lRC^Oh)(vn*p9t|qLHFsYgrsFo1J}2SmA^*0OS~vD6g0hCBZT%!;WxAP+h>L(+dLn^QkQL!&1a-KU)UyM;$;eV>r&3R?q< zKQS|k0-k*ilMhX25DQq0q*fA~P&RSkF#E(i@WVU{u9i9s+;9l1V4rYcxHSkToge%B ze!c~YBhdASB-ObVZ;%e4D-}jj7y)Vx&6*sXX-yNZrlvHG(~tEcMD$eEEqc>4^km3~ znEnsY4!uqiq(M$DhC|T7+zXRw&0W;fZ3|4*hMXYZ{1)Ce!cT+gcJE}QQwDYhR#wz} z%U#XzFmU>(i%j(6)a zQoF19G^?>-x9iA+aSON+Y*!3F^3K_@AtB>I_pw+7!uo zH*=}dqi$;8pY+V#X@1CzRJ?XY^X;8VBMFvt60 zp}Wk}kU4*V{y~ZAsbfe0ZDG_y)vh^wAz#hGuBBYsrN=5_PonP7aY&boPgZpCbo#(q z;c!`&RZhMUiopUcYdVT=i@jo*0K@V)0AH6|i+FPk9@tmFO?g2Vak8{{SUlbSU|F4J z>sU{_3|;(Z}D!63=pv>|xF*5tt!k&62WXsMZpMmJ!`axUBd2 z2*>BSuf~|(puIya;$fh?D;&)pwOMUYCT}@G`5P5 zlVFd1jorODu!pHZ&N$Te3^;Dnm>V{KvJfFRFS*Lv9$IV}8fQhi<^W^ySGqLou4Psu zY8n|J5akoT3R|nY_U!g zBwuMHJ1!O$g0tGtw$WK+qnnB#|5sbK2-%8f*b)7A^E3Q|JvQMqG=oXlO*Z@n2Dh*j zn%NyVFCY}?*Ah?22#5I(m{^@V@`Ror2VZ3n9eXJR@jyQx!Mf}uk4_>5q|8T z3aB+AtW*6pfKHHTQS-c2c{S$uB|&}u^IyonhO5(03zdr?E(Mc(6UzBHM!3bPA?60I z=sghvlX}p&OPuAW8Ux8NRX}R08821+dK=Z%#i~hIU4dnEl%>E@)sAwx9siOO^ zLR^}3NQ6oh7_Y3-cj!x;i~0{DG`-QeacYWn`2n33JLO1W_ZeaY;#H&7>Mp)i;~o2v|us+1E}=KUClZ36FPJptF;O4W8Fb%N_S&S^(&Of zGMOsMQiXLyXfx|~DiwaRT0p#8&?2x1I;sjZ!@{IK`OG}0OxWxp=IuU`%!g9A zxNY-wykYz+ab`QgYK6o)l-mz*RRV*{k)LiQD1;p~9-~UlX^(wVVGA=!*H1OmVo$OZ z^h5QVW>{UOR-p&_m^qz3O?KQ}ZRlHrJtyB+91X%B`cKT6@*CFltgfkq4Qp;q34!n% z#BZT|xD}+!o#77e%hdvDEwoo%p*(^z4W2S98o*(6mLeM^17b_F9q4+g1_R(CGoDiU z$bIV=AUtmXS4v+dVl7peyB+-xB~hyYF7L7b{pk)fPGy(Bt1`@35dDB9^Qn^ zCfoscy8+w4@ccxx)g$_KK#z`8=E|x?DaG3x(RpX3AW>+JeN?tqsqteDw?OKua4L(%yOXX7Dge^>T|@&%YMYHX6|`s|$NS7BU!)@73bN8wVg`hm97 z-~_?qlt>N8Nhu6bFa_Xt19}#X08z_J1@5v^D@w^?;)7BpVk}iCI*?q3>9+5TgvjIG1NcKMNKh5seb{_g`3NdK$b zY-?j;ZtCn{O!t4DD*XS~V+j3gH2r_1cuDKq=$rme8n6b0m(tP_--)rwcE(shECgUb zCXwW5xv#G{e?qJtGX^~fh}LN=cRxQPk_jn%S&#=6B848BTL^ZNSw z@^zK=W%19exw%RA?dznQErD%}IQMxZ=KY%IW!rJaXSyrl%og4q<(zoBr2QaXc~z+7c)upgl2xWUyx_r)_g$PAl48m-c42 zRp3t&4n#l#;PpvX|1@pDFX(NW11RI8cjxZWTwAbHr&vJuONQ3|T{!S4G%T+$Us@D> zZIjsy!oUefce+1vCsaU-!)O;D1OYY7r+9$f;WezMGyz{_4=jKh6L`r>E0~XX98a8C zHE^@PM}g+wL#?_9QeN&voxf7O_;7cz-bl@DrjI_oBIN#5WO`&U=fE4-%pA$ymlU=M zop3pKQ}J(z*loPpnDf$1nL6>p=kk74jy^bY{@LF3gzjG1r31mQeTVMe+5H9WBNuod z+Xn|l6?1rBz@0kr>n)Z!#Mws*oR82Fm+dtIjE`W848~`Cmky#XfRm4gn}?{g)LEDH zl?sf{^41aT&(dxU#z$wLF54>>SdZQvH7B=c_Wo<=G=8C1=RbdpX?KGWCT3blbE~+)+!$fn}8pZZeb!LPZ z(WEOuo_}dbW4e|b+Pe>+Ne!hHEfoz#7a*N7mTRivs^qqY|3()lRjjkoqcFEL)|{;- z02D0%K~d7!<)#EjR0P(>4N~RNeq|;YeSx z8!FmTV~P*&ODR{?xw$&G(rvaam0yQB)2*v)H5?_LXCYXopw!qzIkOEKZdAEtbm4Np zv62jAc=k?i8eUz-I@cG_`cF-yO;dQAhT!Y~KCJld4XdGvjaxN-4l3BQkp#&rF+O!B-WLya z-A_=YBzE@{P=H$quaku!tGZV6YGIjOL5cvLJq1X|=FiaUGtYLTPBy~SBrPz20)&b^ zgnsnTry!DQ%KI~cI+Va>Lqd(sM1av!xwLn<9G%+bU)HWWqPzQh%B!@`R z+6;ULWB#nMC2<_KjQFVE3S|WzE5YJR@Ox^piA<1Z6>Zwj{sNICZVBM_fRm4X5vC>= zT;ph|^p+~hJhJ$@J*mM=N4No|=_nH*)S|&vg^PV0MqH&+td4=|XmX%Z;pi!3l{*#w z+@dFNRXRr%RL+5V14G922oE|U^`-MmRM0PP zs1~n+pgTmxuWS?NqO;Up#8^YU-z`bw<|Qf7Hu6LTg3J7S5M&9p9!MY0f$xYaA@#L) ztOQRyJpQmwhk>5>A7iu@>G`)%T(pw661`1Bza$$np=R!`!bKB3QHs0lSV$92$nC1I zw(G}f5Qp~?5Q3`;lj5M#lVl%Ii!rW|s-}JPHm`za53e;(lg_gab8om<^3)hj8sMH0i6AHdHvwNl3SBDzehjR7}WLzas`+ z{e)!f9b8_A0k*b=B&kNUhm^aa#vSIP7-M{}bC(@O=xKr*aZbUCQPz4wT0$Ao%Nkv_ zk$r0tR`r|mqqmN=zm73R4$?KJ!AfZeI%u^nIxB7XrXKtS(2u3=%dNz?!$ZDVp;lrx z!znbI^$fvdu~2~1Z2slcJnN6az2t{t)*qAmnKv}f9;QeQMZ2J@EOLx-wGFJQ84Z>}Gn3ERi&q-giV2`A&xe50@dpQJIrcrN3H zsR}>l4p&}fZ+l#=N#w+m#{L}lq<*Nv5^8lwVkA7+GoFr&{W(~1_8B;2d%Ge14%nH0 z%OU-a__m&>J2g(wNjhdR-;O=D_P{WfOD-2bX_5Yd`^Ht z9<*0Ok9JYlE>boFFs#qR?MiL^3{!0$H+5sBXdSbRftngVryqzSTr$* zKY5kn^LJ@NlByEsnp-q^prR-$OVz}S32~L&MPWQiUDrzWWt~}+XxcOkHJNl6Ts(%# zXH=vLA+SWzD5_RY(`a&uFUx}VTtGELlCmbq{HYg}k zQ_9O9lpbVC}&Pbro(G#u4`@2456?0(Dj9T3a4LbH_3;T6GL#g}`B`axmU58*EpXJWPD*Hzs-dj>EX%^TtR0@<)@LUr zP3R3h&plG4_}-DDG%y*@_|0A*B~MJfEAN8doYB|vJ|1nFkM^& zJA}@`G?SIH3OavFPlBOkm}9hwykf%|V*a8$PhdB3{G*@)RGb34k@gnJqR(z^Aj0)` z;Jz{Oj(vBvY*krbkYh76V+X|3P|_87dmUXS^0^xT+2@XqYMlla(9qfsG`OQ3b0O)V zx1%$kgRb(1r2NpogXJtDsl=(Ey*(nKXvckH>HYrii$hc<-!Kp2u^C#EOK&R2u_a^Z zg6sIhd^wF2lxR~^ozCvC@t`nyq2_keiOGUbb8iwKh-H|+2m`2)yOks}M>qukUiW-5 zDoPI&;u_(tzkFdvvFGcOvYa#yLbLYV_u~QDwAoCMpP0cY^RVeLkh{|bkXj6Jy2pDw z{r=iWfMypVsjAu-J)y=5rxXwucp3-ioczFr}O2N^SByNCj=S=kO-t-mDU2P$2j`vb6hZauEle)dU zvI~c?yW696i%Si{%V;GDz_=4}({LzzjJs3xCg`Uevu=i+v>F5ZN=aTd_DPRztG7`8Pa1 zs3NdcoJ=m)87*Ntzv7wAUuFhxFrp~h!B=0)PLP9{_TeY=KhrEaes?F@2TABV2be4R zUNx4T&tHmY**iqo7LB33>z@d&ph)0lAWzpUW1-)sXbj5Is2a zqRfRdgR}zN;x$T@lElY2)J3U7Zt-IzQKRf znD`}b%OyA*>;-)BnO8p^fE-KOGO1&n&o_M*Bg#jzhIKS{?WEZ_w-PB|-+m=$E4 z6u@jAOA2>apE{hkCD^tI!xTEpybiYBvVeV_mr#aQ9R28hi48rh5ybQ zKiQ2>3NdF$Koqqb!>6gbLv_z7vKQIjEelX;z@r)@3E!1%f`eVSFUz2MSn;rKt>NuH*$-)ts?{ns`G#!E(U+Se z!doPJzzGv%sY#7)5z5J-wPn<436^Lm9 z)CoQdl-ChFcS(NzD4&=qw8DhW=c!-8dkBab)@TC#RmpC&u77=xl;hsrgx+z*?g`dj zdY0WZAo~Ds>p+%WkSD_neBfhiI4fYKxhf%3tp&m-tj%5t6TIi3H*q^}ChE&TbSq5h z<;&x*S$bG~Z9-{SnQrN_-hhW1W&aod@T^Bsy*t3a8XC7G=x=`3n(nt!8?l*s7~^sH z@_8U0WRn%Mh7$IKmm>yDZMe#_Xo@o5p^$uL0KFyL*{0Q_;b3sFh^2Hhot{&hO&1#&MwR)NxYB>QM8 zmWLFZa!PkP6+$W;tfR-SZhr%u?f$5mnk9o2m!;5Wrm2y>F+YqYgLMP;7ptqGyj!*C2vabX zkUax0niZB+0fdUeuklzwr)c-e$WHYKbz}b>&GXHF>;qN*Nk)C6+Zgf%qb2Hh^?izY z+2yA`=0!)(g5TH`#>44C)7OoL|L_3MyDc~a2hHSr0D5Wy@O4YKI|d4-$;LSyL%!u^ z_xJY*qow?6sEwBxKnlf{SX3=tRff0ume$efFj0>r2WA^gfmUUE3wP_bbsv_Xs2S1z zM;i+`%(kGdgn+6NvWGQ{0D^=NucnY(sEs8!m{;g@#ofTd!fzaM$kEP?(g>gcr!SvC z<(SG2{)VMJw5Xn#IPhUVc;VPvK*l063bO|tI;SPNc1|dW2gpU3=IUjFO~e7THOV(I zcSZFQ1y(b_lX*l|bBdS}kLiL2_MCMNu?#oDt6lNN46=nI?x^Zr!uEL6S>9~%7JG)D zzwXW6nuIA@zrhB<%{PCFPbRyjyA%L~M&rG1FKVs_Le(q$W=Eom(`<{p`H(MfjiN>z zv6rm|)k|@cgX+4WjWf3irIQP?GDJDs+t9SQ#tG#V!cmeCT2_1oEYkTy-Z~+ETFgmY zUs1InC7riXHlcKR7WXuuIcDfW7W6@!u3}bzM^?LYa)NZBMlHAYMDdQy!9)q%d~z2i z;Y)^4oM-&)a1wiKIAm*j@h(?_tc+@<`zsk@>>&39!3ck1Qfq`4QO_Qy=+0H5Rz!$u zrI^_kLG_*QNtFS1!dw`=lx46mWa{q+zk(WQc_pBa!3gpc**u8OR7iJ-QVj{R+cKp- z7AMG+q6w-p6~!hK_x9z?i^cSy)q?<*!(7;$GDw=a@IIfAeM>)qK$a75>kYfWW-bzy z8G&=_3V<_tIb1IOV7uA_0g}%%c)^^G(-V)-DnJm{c_$t51~*U?N2aOc&qJ z1~5O5Q4pgL-0vi z#g{aK^o>!YKrtQAb}lo_9GLYDbBr44imkzLZe>sDpZG3BS-I3?E@sa|(IB-BMi`7Qx3$TOu@Nl0!?x-Sg(An)m}7fC#8?P#8KvQx zFO^*Ik}ShnSG>ng;Qh!2LK!(Cva&Q+1*{v12Nt-$$si|wo=0VRXUb>H zLzduu&(1@ZqkByNAF?9osGi;dC0t(KaOj0*P|9F@?2&Z#9wAIaQ3L5euq3LXb&ayx z&i-^b)kP{;Z0|b8*E}mPZSZbd|LA9aQ9R#5I)VOHWG`*7?q~lRILhv601{(zz(6{> z`Q|XAJ6p~3wO2t*ckMTw(Y8{Vz~dkxxLn%@>W~3b?5V0saGf(dw?CjYqI%1pUne7S+iq2<4Z2)ieCGuteGI1vp(~l>g|l?`BzDB++vRPZl!SjG z=JU{N7_8LHIJGYEHm6?KJTJfI#>rB|_(p^qk_R{vS3&8&5>Y{$cuXXy8MFx2;Lnze z5CePN;D=iMQQ8E9hR3-^uku4oV`bYgx&b~d8WF+wyUvk)v zOk9qymW`?#+1kat8%$7?pS29D72Ztn6|7#z1N!Q*$$*O?t5s>;8`DTHD;&i3@N>Ci z+s?rt4Y8Q!t+RQbstLFbE~!7;+U;ND&VBf;OaB_Fz6kEnmiJ$0$%~VaXvLbKKANOZ zE{E^f4of`beb*vyPoSI$H$rI+eAtqRxK%s-7V@>8&cF*r_3auW-S zv?mTDx5xDb8apg7y(Z2_}+}5x(EJ$#zAlF`fdQc zh&7uTae*~OdzTOJUn3f$bNGQg@RfH4BBOi#^AD9}vwM-R5gh;^obBICW@=r*j@qf}r zvQ*8TluR*vu8kNIq-Z69i1~p)jnbr&&DSU^K*Z>cNdXaESae9)^y9}i*`bK#nlyT= zoT*UrmIyTt=9hCx02RoqJeMp`Qr6p-jvilSd2o3|X?SnCTxr<|?jBzayKlB_-M3#n zw@lQ|uOAM4_;|7T33w6t0eLAc z`AB8)QjP)5W&YlU0Tl1|0jTUJTJey`<|LLZ%xB&m5S-y9A1nHJX~g0oESMVanHF-W z`p$sea&T+-&b%|g_X1_c9z%h?=0BPm&!iN-)#Js0%7y*8++3V( zEvm|6P}o^kLaS1hLp+;@HQx(NzJzWuQn)iZ!30fU#Taw?EotIn9#%Q+opFJ6?($n> zBj4F`T?6yQK4(5vboc=ox$()&o92#4tGM~8upZ_v5I3xZ2~vXQ)QU74Ty%fTrb~Mm z;zkooc9`h`l=Rx?gX(Gcl z2{<5iR0rk@&@<~|4Ot$=eOhb*KCQ9Tj#}AxvdtIXgL~t{g@#&vQl`Ll+D!Y&44kpB zYQ6UKS0gMxaU*!Fp&ZF6(j=KoN2JszRwh+yGvF%Mc(URW zT7G2G1|?Bk+N*}x^O{jA1u2UoZt0QTW3XAII=0azZtz4)HG0vWJ-8Fa`)ObDk9f=; zP7iK_3Y^H)n4W_WqYrhqD~i#ew5zFCr?ZM4@25c#!}m-Gdh5iZVr?v>#k)ws%e3K0 z1Sv7{n`YFqnTIm2BnpPV$ykEP+eVia6cPet;Z&kW?D#Xs#Cc{7j1(ER5O*8r%H*js zlsAK_D4TP2hPLjV=$e^owz$jP;I^qQvX$vQ_l@#&wmLQy>)RC5YbxBBFqOT4MU}l2 zC%vIG&sN#riuN}cd*I%cy?)s$-=UhX+mWAS;UHsNsM>>wsy7YK=k0gw|8<=Al70Sz z$CnG%V4khBcrfxn=@W`4zY{;vlo)RkKc&HnIuRclj&^JKJHAMCNcP9QBWs_<@QJ4| zH5E4QGIA55J1I65tC8}A@S&2b_fRrY@$aiki-gvlc&scu8zcTM(qZ9Wa|4fnxO zt?b3sQbMEhXS<79eZ02^-a#hoO}00;v#hHpHwoHUYmlTD>}*S6!Qiei%Czma{1gsS zBKx)@AVoRHx@ZdNi34TmMw66SC3eqn(k7?G!>=Z%gl$nH+xbf%6){2$&VaWMsr6o2 zBs!Ap)xiXsXMSpy0f~d)i*4AI#(^ z8_12jqhg{pMb8d@fKKH;+7Xyk{um;r^?s>^wJ1|_9op#?>!Z!}^CqM=FYKcUR(tj= zOyIVGV2Z|uwVC_6ezufA#KCvLCS8sh)$iDzl-F+kS0WQZFx%mWV31VIfPQVk`qTL?#Z+Yk+}+yH~gp) zvDOKOEaU6*4x1xVTbhh`H$sh0z)>%8hOtH`1QmK}jSw;js7?AM7-=~I$}aso(lVuq zNr}hWkX;Q}j`n1x^@H~b7Y-1=xpj`iOInZ3tK0oqTE_{WDuu=|nMf3gheqC*Arcxj zq9fJmD#&N4kM{N`ee~D<+BRK?kAat;+BYr6rt2^MuJ|=ld(W-z-iN^I%3hhcTAz^b zkQ%m&L1I<6Y^$j`r0kz0E7;ElqvpIzf_C%<>(*U0kgEQHBIt3%HB0&pu8m;ok0|56 z-Cf=9h-z#S_{PaLNCpQ*FOI6eZO^o*^4u*L{@qLcN%Wog9rnGWYyAAR<~*8vAUeC4 z5%|Tb2qJi}#eqQ1@~8;;eixy3UOoA!KW6R}sh1Y9c{B%4)U%JNqT@SW!d2D(I$WGC zsa7O+2K82}(Pwc(P4{pL9bQDo6(AV>@QmGhw-0bEEJUOx?pH-J3P9SiEi7I{O{y)E z))T=1^wm%FiK2MRHvN@#{`c2)FJGF@_dd;E+ijumy*}N8J)2x@`Pm;Ddy(60)#07z zW`xgBh@nKD__Rm-iZF8CpkyIuXM%{V%>n#&l&4tZOHM1Me`ib+PYwJHZ%!UB^lp z)XOSnIZX>)sbebH)1(K5EuX1!Bthkl^>VeU&{5~c2)Q_gNSs3O+PD<89-b1VT*0J$ zXWF1gQiVcObg@Mi)K_Yl%SX>Y&VXIlkvo|X008%h|8WNV-#cxH{);o9x%H15#_`|S zZ2qf57Pw&({I?{{HUm z?VX;uogBMfS$tbx`4}6y7#TX7p1hr!xS1Tk-dOuwU;S8J{@dBU*WY{G({(U3a5gjb zFgsh`WoZzjgB$49T07G4+Tp4V1>E_q*B`rF*J+1at*-nQG;x-&R% z(cgF4)p;;9c+uN)G(L7aHhMEUay2+`Ha+z)Gp)+x*<~?9AiT z3J_nz_Ik9*E|^>2-;HL^xzL}g~oh&jv3<_8AuYirjU8aAt|m)hF)T3dG; z8rJLUS8HpRo0>Kn8`rzLkK5XIT3fezdrx|Lj=Q^$Iy(;r2G0BY&$_w}Iy?7tN@weThNxMsu34_ATqv)YZ))DI z`x&KfrQ^>*d&hoy=3r6DY+k`cS;b;){YH7^Vsq=x{r!DoVmcJX(~L) z%-T{;mIhIao&`DzFw#X)oJ@wAQWK32nhSC|G)YXEgbIPd^tQKmcQ{ltlq(qn5m+h| zm>Y#b9so#yPbjHMeze~tFcbua=@6rc&Hxu3iNoBS;Wr>5KtGW7s6d`r02l{IFUqd9 zS-va*(Mh4)a4dfY{^pyg5(#k367 zOGC#A2^WSXq<}y}>z9NtN~G^_Q7HogHvK zWD?Pgp0c;^W8dTGWWSNc;eC)>h43(#jXpLDBV&*Iq;%0{AC;};_nV^n}YaKtYSbzzJz z=F{ICc|3i+ce(!YLc>M_0fAFE{hEwuw$NN0?(@@^ZMUOWd9q=vv7y6})8Q;wmk4bQ zz42O_DPsAAOvGpUp?O(47-sweJ!Mt9Xt?PRE53jt6BaN)s>oR&Q#!2Mr^Y0>1`0>J z-`?hbe_Q!j~Wf5V!~P5DPDgV)sOlmPoTG%TMm7;iz@Dv zKMCkBRJx%;aj}u$>ksWX_PqOO{WFgcQpfgOgEdCTD?DqPAURTKhV~a}TihH93sYi7 zD=KSiIq{OGtgWUR8+L&w<=^PJ~RfdiY^TYjXU2XK_o$`$Uf*>8`Q`kL?JK!Du{Y<4UW-+ z4&koi=x1|p^wfhm0CgaW9wc(0!Zfg&fmv{1Bn~nzRE(npo40%KcWUdQe(YQjwAkR5 zDhLLFo+Hxy8 zaZULyx3d?pg69?ZLjk2LQ{F^?hU3zC=F!XUed=*%V#g1lb0{QIg2zFjZ-H`hFMVR7 zGw=is4TlDaZ0ACJ13pN**;Rb>W=JgImSHyjBjdwdY60mgPR=y2jksUPz_|k-_xP&* z8d(>#UZMLme7gQ|K)vhYZ+z32*qaVXel@&s8U%KxjiAPhmMAr8bd0hO0kPC-*>=f` z*E+mmagD-8vt3XC4$|_qKY1ItgCW;_qAWHozPH7XdZ8y1SAuCJHCVq8q7qyR4~@}K zUqvXo`ok^KMbMMi8ex(m;V+cvXlIy>_LWABcuUg)! zhGVD?sJ$JYOdID&CO>nv=09gdp{QjB7X8QqG^C8SO?FOK&As|>{83Tdn;_t3)yzY55s z)u7!`mQcTLuKQ&Z{Nq3ce*;AF!(@&q3RD&-hyCtFB7zjavn0=yXsBD$Ff}7I$5*Xh zUQboELA|J~E^DqPs138Ts#^bRS*=>RWVvM7yuK`^h0kkd>YARN4SH{KvfciY<@D`! z?Kj>2Fk0%i39Fw1k$RxKsT{(#IT@?rPmL<`Bjm1h!0~Z z-Y-=3*UFbi+rQjB$Sc{r?z+D6*!iUcuxcE%?LDS z;6dOc99%E%mZ;UQrdP_HGpq;X4r-r_{J5e=> zRHAU1rTQ379fcjrhg-v2bfettKWihKc!^u(trwk__}JmS|_GKL5C>^44`p zvb1Sri5v8&1Z@olByBUvQXynmGf;8~qhP$^0S__5+~y#^vydOzx&nv9pLm%!SJp(v zV5`mk=Sl71!5f>k8e^h`(sLl>&4xG51Uz3LZsVNaJ-();{COf5WS7bH!jd*q&u-h;>ATboN24iMFpp33;bb?S=oOf$WVSZi7t}iO~Et6OXiLH@Uf6D z_A`^|(cy$uT4cf|Lff=tL@VVj?*%7o5c&0-XVtLr=!}VJBm}jrn4?=(n$pZSl-rW4`)y(n*p*B!P|nQE0!9(`53$opWBygu?BF(l z2lq@8PWZrvn0z78*bXxecmx0M*D{^B-ZP?WWu)!KZoP4J09x>BM2bcSW(HL7)C%-yof9y#myadZv>tV6mI>AEm!6E5S0 zJr^cAq<}%W)L?i@%#&TKXJ7b~0tsVZ^t-vil1k-^zXcwJ@0j<9jwgax|W`$^^OnZ14%9rA7`ECz$S+UP~ zWl2L63MLEf$^s>mN*y>0WqzaH#7f4*3>s67x{Q50BR=%~b+F8H&YA zz{_)()JN&B4za>3m%HQwjES>M8+O5y`$OeaH4fr zwhIWU#o`3UW~&ejf>8HFz<=!w7?!h2s?6Szl7}P3xIAoDRO|gYBp_{B_X<(B#B^e4 zDDOU1^`2Gap&3Z;tx33srZiDWZug8xIG1gBLRx7FhRbi)rE!G56N%FU#e%!O27Xy1 z_1<&|<+$c?3dwX+ufT{8+_*ViXr}dGi~dP4+glV@DBGty?3j14Uv!RYzKETCO5do_ zFijFHkUqkTFAyC_R?*9g2Crcet*?2>n9sQ;^Km4GH{NSiQVs$7=Vfz2lqT}D(@tLw zDmU#Z0}!8zp~Kwjg>Ka}Y{>r6v1u(`yTbaTW7T?bnR0D!Dh0Y|UA~)6yF~6OTcRkJ z%IEn!yJ2mA1|A~vEO?n01K;&XQ;LSc51=(C#=C|j2!vgRx*AqwqmL)iaCs{}VEej> zHcguSAPv2g^23Vk1(S<@BR1ZGIu*DEx?|&^G%(d?=Ls~|>HoULPe+_RAqBuW1(xs( zvhN1mzK%Rfc8WLducb52?n!0lc(V7Nrj3`EpFdmY)0C_O0k>E68Mk~XqG6>}mL>L_ zXUN)ok5G{zNZd9;yg?W&dM!lS6^qqBS|X47V!bwtaGohx*lrdZ#n?RJNMEWWv;NL# zE3=@xNV5|Ib$v7Rdi2idzaE~y&YLz!E+k{l#QUrdWn|qn-2Y-|N#h(8?75C$Nd&u@ zzw;$`kr>2eg%`i(=48 zV!CU>h+P|IbXSoUyE16lDFva2K5-keD(nMn7eTX)v{B{gY$7in!~&4D_b>Il_LRZMD=w{7k9dUjU|QEORr$N+4N=tC(v;8_#3Z-=7(Ld z7y{z<1Z3(dt$bi4{&xo$*H}B>=5ofvOZefzFp%Y>RmVtF839R_z89OZWse*&KEg3P zBQAbAci5~uCK+Oc)0;Dd93ApvJb7!H>-j60jBB^-CqOig*bMYNV0YppN2qfIM&lJ> zQgAoIMhv91s4pkwu<%Z>2E2j0xo?#LgbZ8& zfQrP9&eG$Oij)BmkmcIt)}XWqo$p<1Sc%V^f64ve$*-YPX1%Asn+vLr&&WluV1&P|}UF7$=DM zusnuiu^@aGZU|Fgg`Q+V{|%Y9It|GYXht*v1z3s2IO^d-fknklxqfX%Oz1%r8svpJ zNoQ@s5+adLnSF>;Lo7N(mo`D1aGQc0K031uTj+)On!H}44k)fuN-~LbsFjn%M-k-! z8gN+xE(VwB*vr28%2EFmtrSRmT?lQ+a5&DEj(Eo{NBlpQXbNphYDtEwIIa;tnGe2% zvSS<(zI|7pZLtv}5`*Z3Skw5}V*-+xVRr`@GNs)agb~6YWlld_ISog;WqH3Yj(EPR z<2@cpsLMpoq$EKU3iJalV+U8dG)mATp|pMybe@xgjn^2Bx9$rK(ZCuesuXwC{u_^# zhrG(1NLd)WA->^h|zS?-&Jh>06Q-rOyjUc6Ud_` z+x(*K{*MT8+erLeHnG~*kj7EiqhN9bYVN?82VeD81AG6rv zqp-%%fS443#>KFQl5zwKoBY$yAdboGaTc}&=m>GpQUDrOz-z~l#vRyUFSM_gb_5GQ z-ylMQ)D(b*X|Q`@Z6#x?eOpOKIxV&MY8z7PJ9G%O2P=o{k&^Sx%#J=ICBX4cc6SP~ z&GA-us&9;6ck($$s@rF0)49h|K84kn4}a+H_u)cI=xaR+-&#KZt1ml5*VnfDM@7@_ zKT@O-{ks$K&xuIM!q)1)55n1MklHv)nBTwD(@Zc08-jwCSa6BMjR_*{GoS8jkWYG-SaMzI2%eByhjb?tM^*Q%w=7Ei z^ttuat=w?#W8d@)5lyr3L-b*773opTO9@?0^i16wmC?EafVFIm3D(ePLC0QP7G_0h z1rLUIEvGelrL7jv)7%^u;~4bS#EqwZ6{8z`B5mfVc%beHXbB|ZgFJ(FATxBU=^~k0 zj$-lz3BwzVffg(0lL}7$@T6Lp6V|2Vy3tDC_j7AaeI=zc6smX^P_6EQ0 z8<$ndX@SLhs;C+}C4Z5McS)b@$s{&DN{H(^P_)8LmDoD?a#ulv6kU^|b0+q;QRI#+ z8-7|$V4v1B$ZcOqYmSMq6ZcU*gn!C98h^WTolPcbr08xKtsBC;O2-&+Q#o%I?3=x| z_hNeCZb(|DtX#2p@f+QY!!hTjr$t~pq=gNMhAKh%=I=Z3v4&C!l<7jOf{|i|E;x(4=iw{(zN((C$dK3ZW^nVOOGzZuKuIU7%#Hk!oXc;xEh! zvN2|vaAoz7mokPeC(LIqrp?K7373xY(U(ndVRS9Y88@kjxNs1n<14kaqWX&Qqj)Wi z@Ec?J!2VXa)$@3zbj|SyMdhh(=z$PPDlgCmar}+eiiw(PzNYhE_pkIauHwfs&MxOU2?; zipV}0C`xn_U}|a{(ZK|(tU!%MZ5U3~&$Lag)r819uv<*JJbB7FJfy5Zo=k`O1avax zP7G`ntG+%;04*!U?W(N{&tt9WpcTLrh+Fyh@hbSr80`yC_cX(rZJkf`J(&^Gr;93O zOjy-TD*sBi#GI;Q?f_kB5}fWB5Z#Dz$TZ@NY_lrjXnp}#^Q?&~jlesmKl+0||7Zl# z#x+geA=f+(Fx(y^eMiG7n5)#vEfaI4&N%4YbPZa*EPEy29TH|W=GVINnD0ut+0oLh z;;M?sB8q*BfdldIVC!Rh7%c5pOmgfQA^kdlPle zdy!6MWXz@gWz$}pk<$zc7K^BO2&Oq_;*wkHsf}}9emRK%+gFE%qOI?PEg|;>TEvDx zt?AHG@+#S)#anU#robBDAq90^lZ6c%myO_2$=XephMBK`^G$||eh<@sx_ z>2Px?&NLA;QkRFS+o^RM|Mw(DYr$DW4bfa<;pV)eQ($k#g7!Ld;XuQDLU^p5^d13* z6;%d$BrSCo>xee2pL8+TyoGA*o^hvmwr_7zi|YAy zzDISTur)M25|y@M5QP~nSMM{G8Psxw)rps+zOY-B$0tc>zFOj7n#%A1ADn*)T|4gx zfgg@G24L2Z-e9U=9<&L>cqaC4<_o}!C*e0`S^v?hz+Y&9dc5Q!;1yAPsO?DoHb*4M zrp{_^Ec1(S)uty=>Wy_^h2rWiB1J?v*}QX#3S!hmh-hMpouvi&_e`y25g>B;MmMa; zzoiNremIeG`eTqm8`QCdbe+yXPx0fBG*)UvlJ0LHSTTahK@gB5!@0g$U`Yn#xv7Mc zCtz4Ed=(CamJW#LvoS}jVW_LpFLa{JT=sZe5?dkF&dk=mkNp;YF&N#LP@h*@4prOrNkx{r{2>wztS!Dc8-9}YPhWp+ICBGB-+KP>Os2fdv zXQ=s%lmmZzsPZu*kt7FsXv3o>Gro5UnZ+2*{4S>-3{vg!L-G`!e3cw88Nd>3mMT=h z02+;2mE?3nbB!>OLRm#MAd$7DiwY@PQ8KF@@+?n+lHGsK6lJ92HROr94uzwI}N^Sv~E{2Fj5 z4y7Z^z^-Rp8*E?5#1q8);9mf5Z0)yto@GcwybFtT{tJ@nE1i*{zYbM|X$$5?2s6-jX}xb# zN^ShVBX6Bv(|UuE+r$I#;__O>fbdS|^RArDW#A6eQV~K=Us*wpi-Qg|f$VXS&pcW7 z!0xw&ud&l>=3g^;5!jLIupDFbljvCV83{RrJ+KTqLdeI*a0{wf%AL)?5`2<;aA|LS zsa~69z8vA>n&(XETd!{@Z!HraCAl6qJB2c}@Se5h%PftigX>C<(XKmF>bU}(>?_Sm zMEg{{*WJ@YzclI3Z&m4E3=?Y;C}!?gbm`!TxAA5jaAqPKUf;&Cof)q+agkSvt~N7T8~GT*ZAMHrL+ti(S>9!>`*o}l+`Pytx`{dijz{rEIoU&{ z=y&E%?VXYKzpgEk7JdWtmE8hDFsO_>&Qo_~KjjRXY*rR+s_m<6+hWu{8^8OohOHn_ z>`cMtcH<5T*!9=K0yuO_)sl z;P-S(-728P1wT5dQ1fb(*}TAD)FjaCjm+#1YisGBE-#J9SE^9SRiy&Tmo7?LvM;duCVedXK@P%ib{B?omc2G-8z^a+&JPK83WFC>R} z5v6h!^`uA-*kQD;VcMJ7gpN7Rp+dZss2rHi-GcZIvg3Fnr$$czR!tjQ|24 zbSd*=h4^rw?v+dN)z%6PSAY<66{knU-C{+RTM9ZnXoy8%T9-R_Q$G?{PM99Q@I_(% zphh>*Z%Zi6^&cYsA=?swYXJt&geflPfi?k0RmQc(+|$qe%Qv8dp-R4rJSoonv)5an zSBBXNe(%PZZ^CA|2}}=3c^rjqhw4wMhYhblmK8X(_u?AHfU_T1{Aj8 zmDI9XvaE)}Ybs#HQ%5vGj()NnDtvBg)vT@Px-_BRsPM5fb!|wW1aka%8+pI!dGGpu z3690{!2viQT3fRRuQ@bL23IpG43a_m=}SV+Y`2KNb%t;A___1co4q<&SG}3lHxBO3#$;1_8X?!^0FT`_Cib%vyJvTp znxu0c*y@f7UN?HB?QY_uD<$(Ht*X}j*7Jjko!#Dvn4R6BF*VbNrYzHG*R(U(-|h(6 z*6H92=L5@kE4uaJ^*8p-?oGDs2bkZ@J});3&V4Uir&hn$raS$>&d5O^UMGIf7y`Wg z4FWs7sghHg7yKO|JoA+piL@ty;NPM%gX?JV*D&z?Rhqp*TO5;Yo@4*)S6X0-1=|lcx1NJxGxr6B;oGX9nfk2jV^eT;u{ICgesmstQv4?!@A##AUdWys z|4NS%Y`@(;{QcO?S0hNh`(3%)QfuE|MsU8}(5 zp_s?m)?wd;4>?~?R-fD{oi%J}SiqNjJ+MT{wu-Dlsa7Y;7*Tw~H_&(Iw}QCqetTw$*0 z6?XB_qOX1?4r8rUpz~!z80;c02xW6G7RbX!hI{v=4`c8wtlKZyS<~2M^?5EHR8$^r z>N`YkoPIX;0>0mu{nge$*N;^&5Y&Ke5HqbJU%i15LrR3G*fhU@16RfyW$MO1mv<&l zLS-hq7y>F8F-PMEh zwCGP5lDKf-U7s^lc6=EYVGt>oHj(U~vGp;K1A$l5{;KXbDDO*-hm>K9s@c+MKA@>lL0rJQDG$z}y)Fcc=P^Sl5tP^90DmJ5FHE zGxv{_cS{}Wh$+g_QHTe^s4ydA4`UUY(J}Qd7ULLI_QReX2)rR^kiR^92JxdQ$pB$p zL7a05KxGYs4^-pxb*0KCBB{_x0zfv7@s*KDMC59*aBoMjmvRJ{=B^%dDbf~gTG0cG z<}re)gD8=gr|JTOSg4EQf;~7q&mNlM-HVbnTCAJE!BI-|dHd{nRE;Rr40ngn1Ie7Ca*Se#@Alr;{DfF$l0*F<**)M&x>D-zMQJ*;~0VtSe*)Z;5Alv?(8#afm?|_$-6+6;bA4)A{L0lb0H*<<5<Qm zxvaq-V2yQXe}oF&{AI*~uNM}!^`JOMX_GG$-C7oIKhrk5RZdm_SWG%51HWNVUr7uJJOU%Rrwv(_&`U*L8EG@8E#^=7` z#l!{7aBJ z|4gFcuI}<%=50z8-3K@;j~jkw?=O=NbhPnXxK8Rq>~Gou9iC7BsPCa4D3Xd!ZCc4TPE9A@Z%U3tck{` zp@A;7S1@dpJ1b(h$%UbZmO!(8&4zigI z&SO}|f}{3CQ!t#=jUh4CIE>)AKQgz|zx#M=7)1wdpcpj7)D2uA-Af)KDG)_*P?APM zCpB!KDY>mvmQEgGaTh^b7=pq4nyw@dPd_vZ3ID4+WzE72QMR|OuSZnzxG32_Vk)f4 zSu6Bp0=3?)KPi?!Db}1glgpH8tC2P7hJ}ia8K--m1Xp zt(799INHRZBVSHUNuqUxutpV1C4%fU28xnM0g38FfdWf?+_F3yj?*10N|5m!jV6gh z2hDPSEW&wn+l>-1Ae;0~jqf-+Urkv!QLf^^NS$k7mq1rWg^a{f3qZ1PCCxN~*?2*8 z^5V3>r-M6Ceh5#K>dUO=l#mtW;F2kmH)g7SAPJXoy=>JAd#-yqGv64gVE$7DSt&~; zZCIw)6O<^D*_a`4;wEJWNxcGE=AbFab&t3zNUuC!&f6S#_i17DLZ(B!qhe6|d) zX^=M)p%hC43dPdd}F&U&E%=>~D+FSrf-mkZ!~p z@WDP6l8;%d#g`><-XSt`PDIQtL&m-pHV-l+-PVCf5TXG^KTVj2n!^QF*+)5+e;mqvi8?jM zlj9ZV7KK?|h+EG(;fD9efBS-BR|2OUjZ4qa7o%d);;a zm1ec@fVCZ1N@^vzvTCnPysWBf2{n2FW~hJLVcEqWd!gwGYYx=6{lfV{pN$a&k4wv7 zY7K@MWo|X|7YjtE#4?m*M~Bih*$o(M3MT*S=)?c62GWsyGzO? zqT~Lgs$b82gcOG7^DKa};AV7bdfDs8Q}LFlc|A3{gp#1KQ6Q?S6<;~Yqp6@c140ec z+-k-KmSuys*RATBrW-R^T}qw`xJrDv6jck#K!V8 zFM9f_o#%|kcCSPG_^Y@Wqg2^+0c9u~yj1nmXNlqvJI(9DQ!}N&{T<4PG9eeSN^z8s zhd#X{KwRZ0`;~1zsu_D#@%M~8ZJun6$N%iCC=h0rK)0P>4}OTou8y(_Wo+EqYLxY2 zJu~W0u`a*`{pT^^#jml4ZICbPHvhyuxVFUWg`M9L1h3_Qzq{SAcf6u*x`to)4!mYx zx9z-pEWGgUc8G^LETTf2YXfs5n{EmjDtzz*?dDdd*x?GUBzAw5 zD&A1KXRO;TlmRxBffJ}j2Y5{|7{dpi2*94Wl|9X(>!Tm`+Pa72JF9a*%>bFZ=P=)D z3zRZm22>b~mLrKl7%U@>R#O=pKD6b|$N=IhwH2QmjADb`Af_p+_<%$VPiF$JE$Rxk zd6t#(<2?#8KK3b}hNjoyTJ9+pd^1I-Abs)#qFpn#iu>iVx4+XGj2GN2SCF8z&aIJZ zRfHPc|M0|#ut-Y?Qu>tO1t+=>>fEs4_@7CnF@of{-b}U=?=E;Ywuu3V$n{1RQJ23EdCMJmR`xX`vkkoLfe%&(?!22v zw|}+fM|KIDzA4RJcwyM zs^W*NQ~8KrxGYw#tXxbzd8quIRnM)honc>*tDX<-bV3M`~f4%qKe4o!sZ>lfepS6bo4x&)+np9}a6*p)5a^1IlUGzx8x?d%;C= z*_N=!@~W%`)1Mg&hpXD7815#W%fRMwYzy3xlKzM+ziZJUEDb#l8k9s@XZ57d*fKYN zu94*%sG3L2^o=L|D3T!?#)>Unkrq>l8B-BEydf8)tY2=-+)qICU1}A+rvTuAiSrY? z=|LvIJJNK!WRCmR%aK)e5{hYF5Q>9-mQQugDYZLb&`)x1C5QnC?2iHxQA3;XfWt$RHUUoCY(zo|snJrkJ>%)>rkze6l z*lR+S`2Ig*NfLo%jzrlKI>6tuGj+U#&-=}v>g|%2Qu@Q|gMEOT_I>Z7ydoU;iyfBW z4_HQcOi|3k)DE$9qPe5`R=4k1-F67P9EgfX+sk{T2yPG9x42CZ+sFK_3Y1=Hlpk}V zd_P~lvZAj1)YiE&>OIl;Ju?Gw$zkrOF5-_Z4+iPf7wI7%6wCnIRfiNAmPuKMCPf&e zL>RTO(C<08dv5G|!0gT$$#B2kL^Xo=ih`?M2M?t&EOC3&3bia{2#^IUOB0Ah6I$*r ziS^f_WOkcmU~W#&cJSn{!s>85r+pc3wni{UmF$7Dt^Wn$DJeB)k%6;P%qgauE35H= z_N_kbqG7gcOYE%|MQtZU&z!QFouYzV33t(+2lzJYY5QPaX~{YxkWX$H2D!$UyCH@1 zf#7@}QQ0sl8KWW=BP$srD;T4=?<03$8kdc98s|M8Q}N}#gtc^H)xzXR4|}wIO}$1@ zdT{r{WK(wk>e=p#DY2$2V!UlkIoJV?*0hwM-}`1^oX%9AMWX=#bpsk#1THgNFPab0 z>TZ?kuA&)I3$}fe(+FSMjFJv)jUxI`dsVPvz4E!|2Y_@XoeQee17?z9uVZYp0IuDo@*PDTkjG^z=gt+aijn14VlSjd<6|8SAIbMYOc5^^se*N zRyImaOMkA#QhZAACd%v=kRK@}ntaXQOtgK|K3OQHP>BM#FG}Imy0&OhB!%vTP4dlS z^_*ryFh*4u08{B5@Zu%rggi8DM{w~NLVIJ{okWoa_dwN>7{MSEM*%UJX1a89BtxOw zQ;Ie?jaT&O{vnVji)H^8<`7F6mdei5Q_<`o zDT`008@lsbhvFJVF(f+tkQrB)K2JVF&iAtutSk*^ogup6k2he3#zl=w$$oUGz4;AF z$ho}V3CE~j+QM&@WJ@reo>BJ-Z3)LctGg5~@;Y~OrXj(AWMhubj6B=y~w9d2Q~bm?P+WU>``ABbB?porrLIOZFJGKlRcRw>-Mg zzXmRLS zG1qiQOK(}Fml&aC(REiRY1xXs8X>()Sq%A4z?{=vb&G))Zs4gEqpnZ~U8s0z zr`hb@uO4Jr4n4u`d9nlRfWvBYQed}DGuR)g$Q-<54Lw*$v>Cvd;hl(h=h}baI^N-1 zxIajDdaQRP-5swlteO|!3H84yfMMORn@={X7#50z_ghpBdV2|4(gcO^*hhT81Z|oi zDDtZ;3Jc!Tys1dnlMY%TIo3FEQ`Z*!$PYBe-E>)iJllFe*x~@8Pt|!v_jZ%-9XqHQ zWlu9vAfsA1r(`;(9FPP~6Vc@KGE=hdL|8H2b&>$jeAM-}Nlpe3WuJIc&s17_x zcv2Hq3y)&{kOWh6M&9SknYF9PdvTJOQ^IKzMa{`>4L{(Yf^+2&*+wXG0u=VP{S1w+94WMFiU_T7^ zGDv8nmthbo(T|`Ye`r)DoX)?P6~2$C>f|+^&;nJ(s^#`N)34!9^>|qTeX$bn{`=%3 zug1H=mJ!u^h07|}H}y_XS`lI>i3G<1XBr)DOqC5~n56CwLp6jfPoEPsv~OXKFq38{ zpDgT+x>fyZ+B9iwjX7PM0Nu>_v&npTGJ)?~S*L2~8^46NaZxa{TZdJ3@=l+;ONKdC zuT6I)oNkO>Z&;$(ZuzlLI{wI8ur=x7jPR%)6OyAk@u9NT1x+2&y+17>^d)Xnub{Xp z8b>1zCZqwl%YlV6HR{L{BbD$1M1DcW98Y<^qY|N2X#e@ah;Tg!HVg_bnAmm&;waZ5 z8wl!xq5Ze0fQ5~{wTY6Qk(G(F(mze0|LPA?3-?1FLH$}z z>AEm63KX|TGFK17jbcP1JnTo<$1u+t4bcQ!AzUGI)YOR9nlBQY?kS&QZ)8d#jUW8_Gx%pqj=8@%eQ9F1h;lq1-EvuDTdkb_O2sBuk5ur zU^xkuqK$IzZLLkEPI1AN=fuPfCz8C=difa~RTwHq4%I}sZ&`Vo3eBr*1Nr<}d<$;{ z&ND%_JFYQN_q+|4#O6EbidsFH!!)~YpL1erI5e2D^+J5Qqpt~A<_(qA?IiRhxRVNnI!#HtGCm9j+|c?H5YY)hQWOo_GN-aBpo z-up&!lqy>wegUm=bCX~PJtz0-H$&C9xj`19Fy*@PaFd5Fw#6`^nintMZ79pW3ZjQ5 zg}hQ8_5Q(g~hGWq8u7u2*r&Xp#8UGgQZXJv=wUQQeZecu#l(ALGED~aMRS2E>$pBZ-hUm-9bP(5t+5Qk^S5<5+7n*QbcGho|;B6}}LfA}!fyEkR65tqBq8o-U9ROvuj7_T-|Go~}yGgz<- zlOra;z5;rns!W#MjXGK)iamf)VH~<7LNQ*kLzFvB^a1_U?%;vd7^auGNwADcrRmQ$ zU{i+43c`cU4UuG`%nhUYV0i+F!M2C7VW^~g6&bN#$?3}6M|%Ifq7#2a<>+s~col1B zkbssPfVJq|O8j79nuJyTDI=qLBy5Q@<*%*&-@83j+swCo!z$kTyF%V51>ZcO%MHRf z9G+1UM}Qh?$CryyC$SnHY!acTSq7ELhY$QVeoT?u5)O`ZR&%73@9R`3*6ccFD@CUOVv;_?|cN9Q%4N=KcZ6X)9M$;$i1qL>#D|&Y2ev< zY)iM?=yg5f(EBnp?X}0_YhOMd89Mw4YsJZwB&9WY61~K9h_2SWXXvL(+_V6lpkMdy z8vf*Hz)^2LWI=Own1?K>HFydO$N~FWZNKXR7Y#jPRJffh(XFm&d z+UE1Yyk|5N4Mr{bH{j)wc@WfU=w}x9tq2bW7IoL6Rq>_vcXCVP>ABt3HvXEfKNmP{ zh03f08XJ*T{Y1YQs?CQhA0&iVe~rBh?|EtK7r~}SQHydqbc)f33eH<@wWP? zOhN2?_r@k2?&jYvO2DYz26(MB=e4yijPQ+7uuk8;UT3ZwicL;uxP-GwNfC^d z8}wIpLfE!AD6mv}grn4Kxn%2~(_7yTt?>BWeyNeo z1=A;1{~ylYu{*OcO4qFlDz)qs{6b^@`~B|743!9Pw=%B9PH&b2X#^6M>%0? zD2Zt7$A^u@Q!$Ii^; z|E%7osGmEdsG6+azxrPjzwMlAv3U zG=l6L$qxS>v zrTEvoBWpA{Zc>+q_04yHwVS6lpCj4|7iKRw*!S+h6!VjlY)%xj%u!rOIT2!DHBty% z1i2Sq9B(`Rpvg!-RD`o^cN%eqrX6uWhbWq|y?oc!@*b~47kY0CkzS_en(8lFG%`C* zDFyCm8(#wXUoqj9G`7uB_<_LUL(~1vnzBaX+$Lr{preY%tr3l@mGrBJyXb}8lqg?NawJi#;*Sz@!Y*H!lwCb9vs zy7cp^MV(nD@u3#HklfAk>GWwW%?o8O{-oUG9j;IaFsoaWjJilXwqGIznExn^Q*n< zGEr~XIlMBwKxX(Su4=q;LZ~8BC~QH&!F~NPCg7-DfSsI^FNQCdf_xR6rKkkNU=3%w zi4{!?lX}EaOh|qhOco7Y7Q8j`xxcW5rdxGS+MCG%vMZ7ZJ|?zlf@r77H;xX*S2!e2 zYWyiMl1f+YmWZF&EBa33QF(@h&`$yVh+8r%4%nDHT ziKf4b(4U+wVOzM1j5LGd9Q~dWePr&TM>@s)Z7m=tx1ljR(@<&ZiKS z|1*(BC{*s`EWGNoS6Ft~Q@#v?9K3AdWLD%JCn|TmOVMp$n@xO$KOvHuHtP3glFuDmB8!kh$*PNr#3<3g z!&Fls}nSFQdO>SHf|9 z30Xm99x$~r?GLwX7jU_$s z^#ZBiex`i<#2>aR+IRjK53nn`djqLNSK?zvAVZ!gA}0*HU!9V~KLcr{H9j9h=K9fc zznU5y1IrtKLVPB!eHT7u@{W5(7J^<66fO=V(;?Un;#+;Izx-a#pa3?3im7y|XGUJ= zx4NJ2OoG-t-#(a^YxQmOKB0v)s|nBE%x8`^iS_?(g4}~u@XjJ>@hp@nXS@PZZNGz4 z-deJvJ3x{7fqFx?2MYlh3Im%`!v^+5PjFo3@gAI;%};c63$Gc)-5o=&`b)3(7JOyr zLH(fcjWb#JL-tah1C^n1pZpl7_>P|U6hMWJK#tD~nDuzgXbva=&)DL6XMGkr- zxN~6PkH~~H3TRiF2=EV2dW6t)Ky8Jr69}0XyzxT4{!@auA^4BKrD`d_V)~nB5c5rT z`u~$u`+xl{|0|lL0p){wi1yEaoV;sI78zNXkZ8bx0*COYkP>PzsRipd*ppQ;CTVLN z00fwSZ=DyYZ+I=LTb~v{wtBRBz|=qqEn3;m6{=S+t$$~f)N9mjt6I`pucxQv*|VUA zKN{_Ofz!`l*I!3}%bo?m^5tb`MQH4vzK4T*b2YMleFtH(Zr|GgaT|^haaRv09Z}<3 zygj2)-oC4Y_dR~7yAs_mCiq*UMSl2jH&^_*@NZ05?>+51QJ{Xj0T3Cy2ZIV99++_l zM&N#D!$tZZQwUfB=1%cD9#c`HpXsqWJ}=+`2(LF_0(lR6RQ&I0{Jhhn1T&*7FKBs> z)d+u%QjUE*axwBAfgB!z8h+;@;S_&N?ue7p(m!&?CuL*nhcwc=Cl1&M^v$*WcTIL~ z_Tu=v#|PWGJvI~q{tX@AkzX^vvf!NYF>F8YgA#o04;%EnWC`l`phr~*i7bE@lVhJf zDv>29qOjUp=r-8cI(r{iF0);N6iVd>w4;O~vn*516=%Ys5}=n$-qu)F+uK@xKkTh+ zPi-u0^p}Nj$GLz0seQ5x^$Ja81e4D6PLY$gRgDO--hkyphG9Uzv9YkVM7^Odh_5A= z^vD=SQ;At8C!VZ!J&LyG&PlAX98$A%6l-2zuGOC}WV0Mf`jt~j?K`AXT_q&b6OL}J zSTun?PhAO)mdi2R$u@8GTd)^7PJ(2aT8os^G+`YehprMMh0Ytt zI1IF+Ek0YoLrIjhSCkonP1&Z?URYgT-R>}!1D>_S&^_9~Kn6ldTO?KDBm{TT7go!P z!y#ugVr#F1`RJ(W6%BTR13F>04OyDWfHuDp)4Zig(V0@?g(@po5?s$(;-wq2zLhd$ zYbzyZm(m)lW>rb+bFPv2dmTL|OkTvM!&sw*WaE|PPVUkuGW1p0ry9a&#ifg7yY7sRtNh}uZGme%j)(n@S7 z0i?M2^8q7}xpt`-tSBtW*a?w9%h5gtMy7t~*duC%rC=+-c#W(YSxz#7jcqhF>O*DQ@uU* zx;2P63yv2>Ki6dPdM&$gW*%c^7~~*LpyOpl=2C5B9`x~S?8=gP&SsrU-bpEKpbRmC2Q zg{sF!c0%o#;NZ1Eao0UC3w?yruLj~u7pqHOScE9cT z>|ajT0lmfPFZU!Ou?_1JH?n#0!Xqh$FKG4M6TV?_IecC_cuJ@zlz9bOG%gXWEu10| zA%z!PN_MC*ma#)L^y`9~)JEUTC0C2D|p(0l*sGghT5R*&X&6VGKdby_N*M_@?q zhZm#=JB`;= zcc=^5AOISF5^Ydc2ze!6ku0u67HbZYamNx__gBR4<`%o)bm6?;RVU5`kcSo`JYdW7 zv@qw4KhGDA@<^m>@+`R6=UH0xC6lipb_F_l(iN;`j#L_sU6L3*MULLJd^Q+Y29Nx} zz2*-@Pgbn&Ri4X^!Pbkapp;?&IF>nYXt6LCBI^0=FAf5Ypu^*xejXrepJPUeT`N9( zcKEq64_P<6#s|Pj%6<*TTs!)d)zEuOiAMO}v0(lzjvKAuwi4_wJXU*iVBl77dvJ@e zeJgR@f@DpLs_=aRV1z#e=B#yp=*qP2#9HZwb$p9kS1myj=?d5h@f%!2xQyQc8H7pf zV>#?&ViMq%d)T7AP^k&Ou70n;9mCOc+LLB;AkAb!9n*0lwUzGa9_;D{%K=nxC_|i^ zfGzq?pw~+YhL#ZI5b*i=MaA)ewZNaKmxJkks0-B|Kgh^Ax3NO&V7WxE12Ei?OS>51 zp7YV4OSu|mMwmmcLs~cKd9+Qr?JwXxo__IuVp<2@=-f#|^|cdmB}sxXO1cR65T<+l zDDglzTh&~4Danh8bHCjFC)vE*NfR;w1C;C3y>m_BZZy{E%_2ENc3^2K1_iwen&L-AtwMKpI>@FgUrXUqN>=H(2*nzV4JL^G8E!FwiJalZOB;V~;m z*{Hm;sojZFR+pV~#l~`{yem&4X!>FXW`#IOm-k9{?VveBRgq`=8mLzvZnZ2w3a&$C z5P%@{88;SA@LOQ{?1aS@pTD2Daaoz@FJYr&>WyK|Sjj9n19wPVZ`s{nk`EXE)Ogg8 zc16@ZX{KKrCniQbdPVM$%(@ICKmgOvwz<)Pt%sVM^70{~H%Je0*^x=(PL+^aiJnu& znJ$vp!Ps3H)!~!-(6d!CH#ho*@0AJ027-CTnRidMDdE_1r^L|q>?Wt_*dcSh$jOT) zt7)$CA!VkHNv;W6=R)!t*#pi|-K%7%9N1Lquy0v-GAnFh0<)bM#M13T#gFtQ!yo3W zv*dp8yHnB3WLA4$qnl6pJ1636Nmwwx!ff0_ek|Cn`C6mm8{L5*B zlc;{1!$Bz-+X`L7DDRp`CtKOGRzte12ei|01tpq{B9Z(clyQd1yl$nj&MjM)lnpZj zD2Rc(EcXVxrMg=w->mEc#Uxdi#y<7?G>fe-beL<$we08{bb)%NF&D9ZZ0(k%T|b4%_7-?XS5pu$_Hl0?I-g9cTcTgFA)EU zD?<<&YzPxvG7ax(#})29Tb58qFHjfQZV3t5VQxeoF9S7ZR`jD|*=^cQV}*9gWm>IP zu-4fcLIH$cQkbGg zg@G1j_u}tP%YVO|Q^hb?OF4{UDgyhUJLl_ueL?)kbp{hQH`C*LyL@w z7dFjs`xPvRNIhVBM3%vr!O`tGsN9EkTB=H^DqN#!g%_!YLxvIzy{=ttL06;Q(qi?e zb!TPz>6}1}&i1n7dKx|PrsR<1Ioo@t=lE;J?K7~#3&F5m_6Q={ zP^Iv5!sIb@H z(7Lso0KBljW`jmNy|ECsFQNGeYYw6VgTjw;MrY+YJuj(val0GrywpTQd+EW~h}BAJ z3s46{l9kx^p~k$<9y}j9A1#i2sI|80Af1)dWUw2>lyfP!lBB4XK)7?rL7pYa@Nd;H z+c3eD4a_@ds4;X^9UgIMBR^nu_yZ2GYm39I zM1a1qWN}0oC1cnctU97>%#EsS%{Pf*3qz^IS1i5?*)WrV;-Vm`!Agg}lwx?*n7}mh zmy+-ohOH7YH!$~NB3*ZTzMn}Of2HVq+;Cj&ial3|ILZ&0f-2F_ma8|HH(5ZZ!ygx9 zH~j9A1N6p&F3*?1oTb=fJ0|ur=PS-8f(#W^jD6PAFN_fosJIxK9dtt=LcxV^55>VR z$k}SalZS~Cu9-fa)JfdN+L5A6X@!!aJ<}P0+`0_FU$ndR`udl~YmQhjbCf_PpEO&5 zhC_9`J^F}_4x0Q`uwR&38L|N#(2=+^i=!^F?IAQ0=O8~4_0kZX=Ab_^2{J}w`~sz)a;u^%DRQPmY03IK70ReJ@hFFB z_`v|dmD)rY>nE{K+%;2{s0p^e4TqI_9!n`w89op9~~889uV2zr~@17+d`Z5!$F*&2((q$b$i ztUK&Jc!DlsivWV8vHR{Th zAOuU}NBR|p`}2X{oR!9al33J|*An~JEX{9enQY6~zxxv!iRF=)f6`n(jOj7&qBIhm zyRa(8Hyz19sWG((t4ESILCq2E@b3bDXLE4ETZduqZ^9!CvBl)&KTwG5;F|JdLyMf& z&Jt(S3peijLyqUKS#IJ(hJj=xrn47^=*An7&6l>}D6sg`YpsjoPKvcWvLHrpVlTZG>qwCT-o4C%=5^ht|#jjc)IgX8&1QApWr=%A!|df?MPo;L|cI3>n^ zH#9gafPOc$VXx@-1vkOKrxNxey4w;(^re-d6I8dY7^X+V=8rBAjs|PbUu{7- zO}kdrqAJiI;LDI(%=|2WVDQ6$q~aZPAdgUgrK0)6n5gI@ko%c<0CFJebrDXwAa2)E zvXaJyS*t=4R5&Mqtl{#0m*`?BNf!ds^(f;`0u)Pv(mB7yzdxt) zAsEB(hj`Bhe7K{9Yb2nGK;_PlSh#xgNNlsN0u^OT^fZ zr7#*fA~|M$mR5;F#YLDJ8JQ{MOk7aMSG>|bcYbEb8uvTNHowS)j5p&3txtqT*^`gBxVRE%x;dXJ-B9p zJ7jlfpxN1jXuKk0UOTI*ms~n^`o>Z-)$oR0;uc#ObjDh@$5thlo9&mgyq*T-^@C!t zuMAsG=}zhZ9``fNGLn-`?{5(~BwZP5%_3U3Bi5jzAJrQ2v>?uh$0HQfk2{r)<+_w+ z!pm4Sol{6~?iSWRLO*Voo3=3fw^ReEWq-#xx8%MO60c6_k)OcN%-~-P{>+8(3V#e@ zM&}h9X2mwCNUSaJO2%;^n)HQCY{zzM2&SSdNome}46-|TjLOi-t|;-pBLn5`-^v!H zdUT@W8`b-Otvp3Nnz#Jgx}{D1i{)`jyYdO6DZyaGmor%NK%D1{gwz>4{XoR}2Dy>G zBSc_Av7qg`Q3gLh3ZwHj(g_&I?SUByVtVLlQPBw0hwHfc+ zao#4(&VI}Itfs;nAx5FJ2&2(>#(E6Lb>Kgb_yw`duhBKj!HSgE`Fs+C)UPVIDp4G}^6>OwOmWj?V-K8Uhvya-5;WXT%pgpz0^vD0{oM?hqFc{yb{ukwyPfMv~w zopxOZ=202|wPW!8o&fN6XxsJ*ob?WCR5WM{4}%Jqmu_ zqWoex4hWZ~wQvc#LDhWr5n!hl!9t=G-}q^0XpE~)=6ctR&DLhEpyfe~7fEh&bNf=k zuyQ8^rLS@zhf#VeNS+aCR-shvM5dbssJ7fh}qEcfi+6 zZt6s@qlmm#hs{>pqs%TR_pDZi^ua@vBP|+KO4w=&(pr5noMXfrcHm4^aWUuYbWZA_ zJwo*TK~tC`iS4m#u))Hk$2VRzvPCq=IV(PjvvkHP0h`4mf(eief>in^@QI7nTg z(kiMO*K&4kNX4_U7+&WujFVo8L7bi zhc(6)yHi`Bun|6=!@LC~`DFr$+g~;!Jj(KrK`-Wx;?`Dmp{-;-KPPqY-=wG(8+dJR zF4FPSdtl(^3K@f>u-j3$w+Y<1Vb5CM=-5eR4mo@(bBo;e1Y@OLS_51*(Lin zHY#%wm(pg{5r)J>d9y6pF6&lfw4^hBqH5yO^)NWZ|-);&c z^GHheF@%*y-8zqkV4~ZdcwU*{rlqyTiH%TZm~$fyCiK#%&}MLz@YyvL2V3(hU(lY) zJ)juwR}Zih#6%(S?zg3u!VIcj;QXrg(YW|nY>JH&?%IvG7$-9{E1Gxq)W9VU$9t&# z5T?UcR6l;!Rjo#|qxlczseWiJeuT36Bl&))iTe*`eba?7qsCS5DCo(9V*J;+ zW71VK@yC_JgGyAKG?{p|ZVgt83=jX^8zX}JE8V*Lg*Q2|XhE&Xy0?3xzah_8szaPe zdW2q+=ctxIvA}Vp@b&XKqu+|-46yV{JseENQTmy>S52wOS)r}f`!Y(6G1sMX5v6iV zyF9$VdUZaP)od*mkodTebWTg9AF~FDyQ9aFiFVQQ#Q(-Pmlmv2I&NKbf9pD>bvP~P zve;GfkXgzIe~9Gsp=XlD>u9qi$MNWAB502Z$~7n55t7A4QdXPsnc>vcOss(JdKH(` zN&rVI`e0FM$FY-r9m6>}FSd`5bC#2MVbOn^N_af|-H?p|J56zHTyvx4o1c=-e>|Hh zq~VdWTShTXn7Dl1hQOy2F2T5FF7oMJ159{&ncA5DdG<1{FeUKrH6g{fp9=^4yZ7^*3L^SukaR8%*iRnY3rt@{e-2N+sYKJ2<$LK?3hWQn5 zj`fJ{BxSsD9e=EiSOwwvnv6T_OGUe!xRHx6uO*OoUlL3iU7!A6?M`9;BLjxAF z+Je_czMx&qcQeTP&j->A1|i72erR2*!Su`eiN1KHwi*j?BMrDM%Eo^6;HM%F26W`; z&YJ3A7JJGVOOkZ{XsqmM$s!lt#I+AXaQZUt-f-|2WON`jZWv7ys$#-kw|do^F|=Hh zAzlTvKLKh!NV%aH70qeo^J%Blb$`nY$PQN|-{F+~@w#4cxe@FWCv{-&+pvnRcbSJJ zV*eQ>cSlt@f~`=4w`<+*vX?-*$B+1t8D;_SVj7}+5#Az>oyf76V$v>8TP=B6_uYoD zdXVP^?L-j<1qWhJoFfJu*Q~r}7;iSOe*MM+PDIn1GdRHIxFjub*Ft|1^IS)VC@ZR` za8arr0S;4$F~kzGG-$1e)6|z3E1fOrh-*wJ3fK%O>_fhd>whc9B~>Zy+{|MYQ?!K9 zI)yJsa(UBwITUkcxTv!kOTR?D>4+OD_Si6+;>A1iFao-kwK3@OHe9!PfTvs=5vu8hfm;U)CLjf z^)1=m#liPk2;=gw;q49Kb9%6ic!@=bGpWP%)hK-Otlx>c9)G4d`1P`VKK%3b%NN0K zcNn4PB>_X=X`e#>L-lG`iUIzOGA}Vb&-2C^A@^w)1B6RYyk4aVjC{o&!3BcaWxCR$ zv8)oziAOjSi}5#J7ueAf4!~QC5F66X0?nw%ckL;%)}p*{+roZjDn@(p1X?S!BdXd_ zyj*4%eN=y}++wp;4@TS7ixt48Rf-;tn1s^m3Bn?gGVU4JwM!= z*6C^0u-WQrdGKdXPocK*!E%<{sd^Y7BuLjrO%g%N9Y!@Jn)^U5*Xj!pSZ(Fq()|`+ z%Qi&3!P>-CPdAnE;YET8X%C-H^qQNF`f=aIU%o&$&1#|~V_joieF|lzL}PlgdE9I? z7XG?MWxkHNP@^a+qh_v!H$UzyVekK9Gtb403y?i-62&LdIbU}9_5Rclhc~}rO&Tt{ zv`8FUvP2=wMrS5d;jPq+9|-b{%NAp;($X}qms>gINIa#OR*Y$$>VTnk&l0S5szvLd z(^=SGzl_b)<2qF9g+4wO-AKKwhXzZ5Jg{OqG?m}VPD+x>anb4|b-x=QIcQ;oYu}tJ zxW`!BUoT|c%no6i8Cqcsw_No?=2v1&My;l5gqGw#MKkc8w77+1ZM`6SG+n>^`#bm_ zWgt@}p}HB;m4t)Ivc$_-xzE8_y5GJzme!ETB;y|2lq{&!f&|m{<~n$Xqa^nnx1PJh z{6YP8qx1Tb6S)IKz~?R7_xw;Yln#vs;78}oQp@M(jr$B{t2!#vyGRfJ_@xF*RJ+f* zkDsk{3o=v58Fo+o75q3Z7d@rM?fPQaUq4s!`a87t-a<9Cs-4hXfK3G-MpYHU_!2KQ z2kMZhh*!;eV;>)7S(6FZ8Uq{)9qe6$Qlp8u`nqtOjOOR2dcUlHfDRFbj(pX!3 zFOhg;Ki`r|Ij3D^AVWRzxs(C#fpCS^o+3o!9;9vuL3c=bM_#cSgpO5*fp_s3nbKFh zSI)&XO2bQR@ABMBWqH25LZq+*d*07n1!6a zS{u`yx*&5@hWfae%3efTB%Hb>MUuJzQUih##I#^4O|es!T5KEHr1oTld~4PKE9!}* zvml>RpjoPaRLR;7Tt4sbN!^<&wx6KOUl_GmYy2~2Ore-*G(MG(@9uL~J?;>v%PdsV zg$ZGfL@_qZvDA7hkVa9@ShO+n^>HIjj{`^_t|CQIJPXf~)rHF$rCF{ag9Oi*lMPYS zpqrh{XU}BgG5#r!mKxpKvki*{7~2mU6=Bu@*}LI$yJ1V}@RRs8Q2u1w=G`@RYfV(# zhGnyxfo$Zg9mJXAX7k68UVubHa97^+-Xvoh_AcymD)mCl$II+@16dSU!%{1KR1sVG zo--XGI!PEy-}d~%7?mC)n1baRVt2`L{Du>JZz{NBv;f>AD>2vZY66?SbIU3csgslW|IA>@6$`J`*Q*(9P}V34-my`5En z+2)B(WwzU7>-`^c7j1zs_9H_iwGreiqIhzP(KDe=;w}X! zO4_Mz)ON<;A3Pl({L-}nG;qEi6l^-^pZ=|Rj-&cbuiv$BmxJCLCC{Uk2CT@`F_t?&M2D&`ryr=}^PwI#jP`^bBfyNEmi;?fI z^kz*(7&?qH7fA1743A;MN{-oHRPQKnLNkA8_0iI(cF;A3AQoj_ErtDKW+~m)oPHeJ zda9vHQ?-U~wc?^;6srdBtBn+CQmIC!ARnwbQLX$T|1!J3prM};K5j?Cw-M#f^i(1^ zXtCSV;y$f_^hG0+KUQO}|4H6sHfO;1pbIPHa^Ly<*PAEeg6IzEqEF*>$Bm)~vw)!J zp*U9GDUb9Su|p!9NBqjsDG&Gp*72DP+RPnZ!>Mp3bD&TB%;sc3@qB&ID|Xd2)FW~A ze(;q9j2r(9zM}?t$>w=O2rB$hQ;3*Th>4^WN=Z@>CB`@;oo>uVs}zMVPDZ|5pkuS! zj>R)fK0)_a6lOg*!mT0egYV#);!oNK=m7!gKgL&y2tIi~g4bE+O@%M12_ctoqTnHL zCj;_lH7ACo_g@|MiSO(k8sYB&n+W5d;XsA)&*(dBZnVJgeX(Sug%l{p#k*kw1#mxk|b7|Xc55mG=JUIy=-XS1DudDDO-T4>&>DZl%i zYxj?xn}L71obZMToC4upj&Y$1mM<=d{J6)SCsBl|`vO8KO73P)IcxW* z;1nQ`Mp%TVhK>&pVX%8KMagpM`qLbU!;f#eV=;{l!Kng`B#Phcs?0 zL+ijBAZO1!4$|XZr`!}2z?881Yq|i zJVZz1e!oEZRRYbq{pdx!^`t+9k^QO2{K%F*we|gq_S&%hG=jd5ccJP*g5MS+dBv>) z)-O>md-e^}7{qa@iKu5T99d(YH4jWe$XP{Y3nholWn4Cs__nMorD#&WCxcI`~C=j0`HFO!K8+9qvdtc7r14-hI zo44atYFn0d?Kp}J7K^xLqOs(MN>!0<^$a?(PqdqYT$E?5+HgC*^2opzC*NkT5&f`iO{U&V!NZG9 zk)GQ}lvqH_u_=uD>m_A5X+<-+koqjlti!dNavbAbq#lRUmc*=9in2k+*dS;MGJKkh zl{BCh0(^2UGgd`X7_t1<4I*16k`M_vOyK*Wu_51fdgNU>URW3{$Y@2u17yko6pkOz zSQ&Oan1CDAVCzFsi`Z#od!)v%MNTvt+40g@j!w{Y!c;<&==-h@bK0_+%m1lf(nFty zd?VfmSyC&j({y1LuPX*WLZ6Tfq^4i@F73NWV9>U4Z^@B&I~deyc25ZC<;@%`JgG`- z2j948Mrq+Kr#Ntz6FplDW)wxTLxTL10u_km$<>OsKwY(9;)J`wbVG#87_9IDryKPQ zqiW-LVM?2=`iR)dGf2DS(w5?)f&_X!%=XJIV4BO56cM9@hsR7KEE7nzBAtlbnq>4X z0uw=v3J8=RI!FRQ>LptcTZAi*1WJM9g!@G>fv~itJ8GOcUDjiz2!%{L%&()68$VDP zhc_5!laJsS2SGOA;9Qs{mH=EOf5uVRc;U;k{{1;Ah_N5aDI#mktxyFC>w`)F%(ruv zljtCx_8uh7J^+h!h=mVqXqar6g6IAsN9hVtX6_xoQwD@narS8`8Y*KJ;zF=08HHCE zXOfrV82_r>gIp(t5bcrnTNOlR_s)1C&g}_r#3<;I^gG3D$7;hgE~PX|>=}Y}b>Uno z426th%1k#4Uo(aWdPE@!O~Scx&k0d(I`E!q%g2crCcoLh*_ve7o0n3jT)&D4qwlbV zrqdiX%#E>IdUNI~XHF4?5$ikH`+Z2sabQa3dn1nTh2iOl;X_mV|3(>0{tDwUd&p@; zSswE7QYwp}7Ezu2dk=EXl#`5h)Q>vDLuqQL(k3yGrL1fnwq#j~V#n!z$Gneigt;2= z8LCNW1()8g3-Bo*B4*x?REet=ek8GOT58p+<7ZPc4;R~)t#D}Q&Nd4tGqx-!+}>T~ zO9ft8j}1?^VwguEi)53`9A4l?HnHShjO_z|Hp#vHnd~!b&qj&qw~L@a-g7~Zo@27! z=M`Br5kQE&u0d!q)jREpmx6kVXcXLC33Tq2Ej zLIk;M&ffq|+pwK!fkK~y>?w{UlAC?TsT;|EdS%BkaC`d}(HniwEPRf1t+_KE<|jFZskpqbyb*eU%*NvGwk}iUY}MK8Pq(W^&+oLO<8=Dj zEI7Pa@`qPuznhFWwdlF-G>9uImmj5P?JrZ_mx764CZ5V(t z3}7nN?YNDl*S2m;A$+L9W>{|yWmDT_5pyaJBvuWTZI$ZWngF~$n#T@r#txIX0fakPL~9d45#Pgx{3~Zo*M;j zvA{qAZb9#r{kGEt(@@eBI(bhDAyuzC&~B=lCFWeL zd?;|g1uBoYN_-$4gs7(W(X~XekCn00T?^T6l$ZLU|7=krSQaFP0Dw#D-=w$d;V&yN_a2d{l)twi(M8UeRB-UBesc z$%Zv`Y>Svi9b*0n6%DiWU?SwrP>Db!DE%wgK{h--S}A?{`I*EiSi0LmL>1~+{+<`@ zD4fgD;DqfU%Mf8V_a1Vd>%J>DgBk65#rg26Ncw{Cr8&G;V|uDp@puz&($ss9A1zkj z{L?yrHl62e2Oi6>wOO*XyPIy@_aA2)7*9r83=?sb9IRvi#%^(A^OIK;;@wy(IBr+` zq6aA=j%s||d1m_YhCY6*J7Pq=*`ZA#qXVb_$QuZMJv(C&D(epxTz!zwPQCcil=urH zwVE)Nk6woT9y!+SPjzS5wVeHx0W zErCtjBVi?myJsQX5Tfd=NN{4V+h!o8hH-kFDN8xG62UP0TW{<&$CsWq+Ce>uWrZvI zXjN)7y{EnN0K2^WZU$n7KlrNk<@BdAojk4s0b>Ot4a5AVb)(+p$Fxnl>&0j)fA#fX z=-Ur)8uVlcW{>yOpUuj>a?JM0$#RE*-{BIQQsGy-3Bxal&oQCqpjQxlQ7-&`Sl-AE z&Z!GLBlpKfl~^N`H_g+}>VKn-B)NS#9*NnbU*$(!0qu%c@f0)5d-A6og_!owHQGPoddzYw%$sx+4u_CqvHOWg z>El?!L+H!VK^K_60*NQZE8-;agqI+TRR`9?0?tO&rKO*Ux&cj}0VvTgT&h4%w*eT7 zp{Ui!G|ZLBq0=SZ2sINH?|zzU>!#cDJD8Yj(_p&pNyx)^#IP)g-69%4FQt#<#9Ne( z!s@MnLYvuBcn8YO$PHAsA^9XcRu9C@{@8m)-I@o`d*KZ)N2wFM9t&#Dw6}&H46;VY z;6`@!Lt~mtdlLhDibwg7KD~ec8Q7e-nyzAl`SBwg{eP;&ss7vcsHgL{s{DVaHUDe> zOcTmS^{_?2oOygx){aoOHP|)0+^DgUgc4DhFwiDZ5K_iS(k>AyDT9;c=iGXyVzai6 zwKdHmwcYSp_+TPfiE#_Mu1?kRb7$|0Hiu1KUCp)S(%E}nmn^wyefNR;pZA>alHBJw z``X4m_x+&(MO1Z!p~I3xg3-NJVj$|UM|7_QI*q1Vb`LrvjYhZP20BE8TDQcZWuOXGzs4bEpapt`O1IA8 z_dptTx40Weq_iBf4$UBUNS0XMBS>?*C#XHDLsEI0)*i!{chrDR)9UEP5PeNXz9kB_ zUipTZK^Uz|WUn8G`>h)nF=4wM5fn8pawY!v`nRtUhJ-Gzs|v@M&>D^TMSMyQv_b6+ zy^uc97|qs)Sg&*_L&wV`w87=R^`;BB0Zp4{PIjA4Xx&)7#NN4CjA?uSuz~AsOnXx1 zTZ)dlMs0=3zE$Z(q#`5oBY4rdPoO>@T&@WE^!msI8wkz!H`CW6ae&8!?(XhxZ0(h2 z>_8WLT`#2$nqJj*;QMHdtvl(m#QoJ?=dq~C!zuF}12zpYq8uY&TBQ#;sjTvnzcmS`Y z7vI3TOdp!uxl@|wQ7{faHkln;m*Mj9eD0`Tpfb!cd4so-8a0C1%;l_?9gm`Y!$-+i zjB@i5)Gd+9SoIID_WH^771YTjO4V*W9%RcK$N=HV`ErIhgin`n&m8q{HLG zAwH`Lwe5u>hz-~ratv6CYNlXqRk|?qbY$kkoRrv#hYQ(IgN%Om9yY{CLG2MBljTRj z{23uE-qmHqneEbJN?O|)pOQaiIOqs`BJ6Nf0d^Q?fa7@)_k#uUK>Jez_!5gUm!djy zjUrrG#?LZUTY*XzdU~39(ER=|nBTVavJF(=ICC4T5KT{-IxKCMk!NTH+xdjPBR!0I z@dLRD`2Lo1KY4Z+A4kXnp2O??wCV(^C9G&Q0yl_<8c8}`*#LdT&9p9KSD4ZqrG$@c zVu^K@F37ByYcoM`19M2wL4_n}V&wH|>bn5(U&od_K0ires+VD76wB)5n(@seNr_Zr z3UDR)kdcZW+=8smcJJ1ApA0R`6*)=0&m`;Fw}$zhZ2BvcBLU){TV5uMD_g&-bifT_ z`zT}=miJ{1AZBFFV+FC?P0BeoE9-7#HskQI*U1L7N(dH`sPRhps2>*sq(?0SEC<$9 zP-PW$bj~fU?^V_4F0S-3BRq6{k|qp*S^ZIeYUkrl98+=;^#w4NXa6=ijZvj+7q+Q= zh0@{{N$B}RP3#meQ2ThwwRoAx$a9c5+M0mgaw2r1Ng^5L_jcwdy$-_ovZ`1bs~MOI)v7*A`= zH7LA$K534+R(ySbVBas{C=A00;=n(4qR!8I=CiDZB5hFCnBmkDNC zC|j;2^FEr_31(U;A9g({rCt>+@<^}Zr2f6z$cQoYmQ4p!Yvu)IU<5aA#t=twC+U;h zBlVkelEKv_FNxkT_ztHC$(7j?CYWiXY`K!W@@O6>m}#ecxRU%#w>9{;%0J(G{{0O+ z6`AEFq9rK_Ej3WK9<SIDtg%Q7 zF6mBUq~qOwH9lTgX6$<5p+meG5pkk*O#OT>iqQ^iEUdi^a3F*?pzFZJ?vfpe^y-4K;_7GL>5HZ*#D__yVXVSbgr+J4^K4;utcXNQf`&X+^JVjb~A?lHgO z50T1!6x5rPjC0)7{DUKnz&xXbC%?ofjSt*Ug49ETPP8(c!HVQs zz#vUFmq1HJ=C|>OKz?kb9WXzM2geTKrKD`);y6*)jpf*B$x67>6}{l7%9s41Dm28E z*o9+^(f$rWFvt*b$ksNV8z@C2JWwMNwGC8+@CUej4sY6Op-ynfM?Juj^nyu0F!uOz z(JMM%{$nAOFiBuuN<%*Nas#U|4p&0)dYcQdRa1j2Xi*}t z07Fuf{-t9{mRkr?=PVaphJXbpdTIcWqjRLksJn$+1KY*4vZM9cWmyIOg3~}U z$#A@uUWp)!QZlYE`|WhLpjWExc9C%P>&3G;ouDmm0f2j<1<&%C(>bfbFjC4@wF1l( zHH^|iZOY_ElUsDkBVfao9{&O%rR5r{N8cDpN3l75kNS|FZn!!LUso}5Os-6t;k$~nU^6l)T?RwCkys#g9+fEey?I0hPX#VuuPL%yyQ2u&oZ-jkYiXl$W-Q2L7 z&`*A{*M#4D^C7lipXw;Qg}1wsxBWo2vLUvhpFSv_puZzi^dp0On4rCpY)2$*<7`JH zZ-;V35#gHl%3>&oAgeMFmXX7Dz>}}KJip7leA|niS@$k>;@XVI^^V{;^R`=X#lMDy z{|pNzhR!>_WEFy>kvqviP4$M3?BSIo=Iyo#NTCW{^vhY$YXJ`K%z zzjB-dN_?qdcTjY?6TWY!R$8otF4mW?G~D}ppDqHB@sD)b#u1Dt0Xgspdi)5y`OW+5 z5VqykyNo#kA}gCkfq1Omk1(Oj()KAs0A5#2)T(;!o1r+UB>dSr3 znlatvwfN|hlyLVvd5vV}#DEjCfG&w2CyDYzOodL=+6VMLQ#X(B{ZlrafLknX$ zdQVqYpFY;k!o|T-KO1w|a#20! zTT<8A4$z02UaF-)(D=KlWp5rAC97M*y%|Gd%7$BFrfsC+&=#2*k9b)f8U<%#ZRF2? zP?s^b9zn9!uIHr>w^%&-iz-w%9Lbxly80P@QJWV&;tF~uv&*9`sfX*F(RFb)ny}k| z46R%c$0(a>w7v^g2M@46#EZ6Qec-IMT%bc{x&~l8U*h^`?Jfy$tUsfMZn5kiko=!H z1a1tn6oLTl?~pc^y%mw0#Xp`{3`BxTU0?7SN6Rf3dyubQh;0i$!+V27_=L3iPl(-d ze;O3uv!d-&U$+I3u?9w~z2k0-+^P#MZk!jq^2Q=HB_p}<5gsAFyY&a4oGU+fi)ePk$#C8EDalckoYCsZ~VD zNkrvIXY+=$xYL+8u-QNGuiCvEn?1r$nhkb0q-YHab&{jIk}J7odip>ebn8NiN}6D= zKn(mjDr46xrGbaXhu6Rie$?VaI^P*+yD2>*UbIb1*Jsz0d#pPp(Jnf)X)X6k;~<7l zViQEHNSyS@ja>FVo%EP1r6?e0gj2xS8X_!7?!3NawqMQv-4_y}&%q<3{_mq(iAd0M#h61u-Jdxo5 zxAZf8;Lq>Ixy&O0Swfq;h0(GjUgdT1?Asi(MJt=!_x&w-$)@F>D)T+?p`t9_b^vPc z84?a_w6m_o=RT{y2%8tJNj@v`I{Gqn>2uahrOyJ%Sl0x)18$YUNApsKB6>ckmoI3i zJHzgj%%vOMK*s~P&d~J59(`HlJ2}1y&3l}B!07Vg}b}ZKGhiDNmGLAes~1?UPlL@#Td6pdF07GmzycjLLN)-OA?Y4pqv^wz0kdV;rsQ zDs}!IqP9;-1Vs}@C5hLa$L>r2Gmq*vc7G=u2tJajfCkDteOw_?;gx_kT`b2)y4e4N zIuMZ4PBosHmvFZcmV>;l!dp~$of2lh!`fLhn=rrgM;V*yfyShxFwv3Bii-x^(msbn zJ!@rDV%A#QNBC{WQSQhuG5oT)(O-D_5ZoPASSI~?uq6jsO|a^wU;+^~6(0zsqx+fj zrFmW2Wa^=5WhUYv1Hwo=as!id(YnjZ8&Pff}G%+iHF%G7jQrCfaN;BHYR?xz!MlTa%VHN zYJ}$ChIP3cpkXD&o)--F9$cssSmf}5lDe95=;)jx*RlY7D%}msup}y{*DXVuOMSnW zEV=JA)fP5LRd35*AFdaB1ho3P}>8!(NZhx8JovroqScDR|%q&xMNy~Cti8BO%wZ%!t7%XXxHWI(rGhEHVq zezCPe%Ttz)h(UJPie5H6Dv5%ViJBVx_n0FlRJ}LWdI&-0zH0~VVxr^^q*NwnbM;I! zh-oiiiR&m$m8-SJ5svtDTw}{HtB~sH<98c@>L!N1IPKka#gS>{u3efCD{5u=c{N~*ng$1{ELvH_^*Uw6GwCVf2p&kYR7sJ zXkvaUc8=S(p(ie%-m4aMG;k@ zi!36sjUkEME+SJS$!^hvLkuh=dZ-w!-%}mh8@&l?_}HAf^lV4W@l|@g%>8@Wb+x(m z-t)>;|Ni%09;D59Ji?3Aa8~qbE_OUMLre?_5G^kBi?q&kHKIB(MO-etavGQbkveF?>n4%4NfohHIvPJ7&c8nsKbh+#cfo|2e{BMO`M66& zD@+@q?Bi0OB7Fc*_H)UPe%16JiGlWiVi2O{7N#lg)EoZN!ku6qQzyFJHOXAU?(vqG zV6J?Mjy8k)rL#5$$6wq>%v&;h-1DO*@thF7vBu&r?Kj+Jg=AuY#e&2njGxpWaxHsZ zbIckKuMDy^eznFvhgk70r%nrF9y~$<97JSkX$%?@NRO4UM4PQ5W4EEEa^Hs*BKgS8 z63*7WggtW&3R=(d#Q`9^kMH{!Dtk7H4tZH0zfFekLWd&FxA}SAvOad>;pcfARt41Q zQmQb)DrJgrg`wz^an=p4eJ_^<@>#99ZGd;E<4E#=rIbmT6*9$xf|Rq*>jA`);X$a$ z(nyjP!0K1zARHJI4d6FE7i>+gyp^PYfPgm-)dHH-YP&v5WtNlMQF15m?=EU9%h;3( zeJu%G*K(OqOD0PDo{rOT7M_>O3TL*YRz$ZdjuhNJPvK^FYVOZa zL=>YGr1H@$0yX$7Cs=im`K_A1m1Pjh;0;i)YiY6+4@G6&+dsRH%33&jEaR3XZj=@@ z?=^Lxdg3Is*%KYo^P55jkZaAvMV%q)+#jAA2;SNw5=-;~>|A02d)^wu+MEJ_QBHqE z#_K*eRPQz89Z$HVe&$%juXZ6Y3WZfv9qhZv5qnCjg)ucwmDof5#TS zaIJVgf6Zuf?~pmluJ($Q_xsvFpnQi!$<~{Q*}4PiYW|w+5VPh-hvWN?aoLm80));| zyyCv8r98%9Bt%GtF%#APRM1>RV<`waUs0>j`u_4A3?(}r@{Jn8)*2Bx?syH|2aYE> z8x8Glh-!8{Q2TJv*#g{VS6A5~aQ*i4KKl?&L>$Y4Q!uEcwA4%08$raaQF%PiogTO> zrb`P2_Z3S@Ri4RC?c%xG9gCd9)Z$yX#|oZu}V7!l3GvWACAR!7G>QQ|}2mGDh@*UCg`(`?zj zwAu`cHBbR|7=EBW8kmlf@z+LtlOz2i#lWcLU+xkPx(gZHDIg?B<@#Z`-DNs#7BCw)~y3p|ufgFo!~(kZjU^TyPq543Y06KQ*>{ImUi zzj)*Nswk{^x2%fGUpk`8t_F`uw14whqaO%&+P^(mGJ1W*si$<=UzoF{%hLSuhJ{2Y z%RD^Wz;7&jiccFD=Il`T{=2lz@?h{7Y<{OjJ+)8j0fSVPo${h;l0=Z}2737S+lfXD z-pWYD@3D_l87>~_CPLMhgNv|`zo2nFAsfd>Jbm>SDbYEISOq!mTs`^4@o3&KL;^rj z+bp}VGt@E-b8as}8fa^s$sgeTH)B7xV=8EkhgFtoy)g*H`BQbn+dJz(IDPLUu;F6xD zhM6V+4NM}sy}v=|5sD@K2|@mA^aR45B4Cfz{oWEW5{2C3J0$i z8csw}ggvPdHjNhbu0o>=SG zlg2ev=3<}n^55um#vaw>-_y*j_h0ZJH)b+~KNsN-kear?hdukW>_S330m510YyD&D zhQSIA%%jU)!1D<+Pm!R|2KdBS@kH0QtB6mxxg)5x zV5{$xH1Z?x(e7e%g__<2c6xxG0oFB^)mx@X(Fo%CF!oN@%x?`+46GVV{6X>GgTc5k zr{TT3KIsCn=4Q@qT7RsS>a>^W5LI`+UC}Uw5tweG!uEh&xjfPE#T9Or8u7OH23c97 z_6umG(E3Vd7A57izJXH(+Z?hZP9_Sihx*+p3CLq$M+K)G$w*^6p`Y>Q75}d8&K2Iy z#}byn4wPUPrb-juQ4Bytf5N4@aofL!Uyn1|ReFmS`jn{e9Z`LQir;RhxVgH<2vkP< zNThxXx9aX+{FpF;sZVBdx(@3#ferGqZHq~{+tX5ev|KUxsGKli1q2I&qtTaayWoGHBs*-G`N#h1t-=a|q*uP@Dq z148~_m2OhAj|=Y86Ul)gOTC^D+xiD6-Dpq&5wbDo=fY|vw9nv&tnNol;pdvHUF>4z zW13AnHnGKGb+FRLU;*VmdfX_^2|avqgG(ST@%N*kf1n2rT5!k}Xb=$p|0q8DZ{1n{ zH+uLlcb1mCI)*mJ$K{;3*%}EbDySq-41h`?83utUg-Y(?jTG`Evw)CZXmU*C=PPns z!7xSlNwQ}D$6Q>KK)rFIG=||8x@mS+=5`~`#2b-T4dd_nsE_{<|KIhzt`<0BG8a>oD`w!z*BYbj;N`3}fZ6Kn@Fb(t2KOm=4eIs%==&?Z88Ka7u*1kb87CSC zi)J=@lnEwS{g^I8I!lY1{Ul)NhQ^iaRAQjLZW*nk72ASN!sf7GoFj}i?(!YvP^8F# z;#%XoXmGU55rQ&c9g^0W%#q)fp`DMp$Hq=*I=8bUyJdkr&8phNMg1<_p3FuV4hB$r zvwxR!F>b%U>g*PXa>p8~BfDkT?9ZEbJ`9YpzgmG+`?9XNL?Vh(*#-k?*nSLJ zT;B>4MHiu#u4o(>VPdF)IlCvrWtm!AGM-^_T#&dV3Rmdt5f-Gh~O-H294_R2O*8>i63nH|}hu{|Yv=n)q70s{L z!y+6BbIU0tnzKG@YV;RVnCTFIQ%#5!{u3KI4-N(F0a&nZVJ=0P-y z-0_m}8glD>&neN;c7rLV7wj5lhS-ZQCpk#Xat+S+gAM*Pau0gyd__r zh%PkOuZuyPa&nRqC5U7yz?kF(3e#==m>H%A@CauzGvK4)Sj723UvN~UoOCmah&0X_wVBgr_@AuK-)+hUxwuaFq0b4n5Enzb^u zaQX$Kp_Xr8h)tM8h$-P2%}Gbp+fcPxPp?nlECod!!AsZc3fnXEYQ~}`C|mL~thyp$ z(}DHH_0|G7zv5TFbP2;*LpFR?DZr7-;dCXDZOd$H!TzSpJkq9WWs^M+>cXurVGa3Z zvqWP!sn$awzA36`1DEg;I)~;D$KhrP^2+AJG;{W<+hPl%T!bl1=(5|$uwqNrX~>?E zCE==T;9-bp`#*iLZp?`gZL>xziCtpwV~Y*0=KeyJ9~ln zAFf<>Vp0BF9y$~bqE+7T$tg@HO!AdsNFYDw9MGdK!LGT7+6f%43Q+vEwaxT%7<`8M zhA?l}B0-K>^syXxOF_n^PmYnCMPhWguX!16_q5L*nNoPnF2quZ2-w z>(Boq*xe4xT)XilLA&!6ko)g5r0D+LjZ4?U)#*#b%u?OM+1bg}{hvm&R2$wM<2UXH z;QUg73mz6ffq{e}Lxd>dJIurg9G-|6kuKJ}O!YqsWbav0&s;*4SZn&nJe`VT5dX3D zM;A%fI4#zy*3`2zT9U4?lkX;j40zR8zZzw@ul5#!@l_cV z-`$9SSB;e(nkdF2Lf;c2br2a2#DsoZ7dRf>^A;N}Ack*LA56fB7~YH6y(s~R;{{S| z`pXS2;^oa>*8qrP!jCxKBnI#B4Ck)Z5t(hhWd~15~fI=fNm2`OrEe5Bm>2^w6Z9EU-s)gd~8cOj9Hs*qNQwDcHNIX{+#g)>AH3 z_j$RJrH2KjNHgCMSJ(gT`g-nXl&cCtkU*&@Fp(kH4A2YxP_Lo{;?l2 z8;@mWCk&XmDG=&k!tb^FdTei>0^=RDu)-7Kz zkC#jBzFc~*u<@hQh6ATE&bqCAnME>8a1EG}M;x$behG`9$?cjI{eW_K#Tje3F-39T z(jc%!>qxzT@4>DppLX5qhN(eh;4Z-1U(1D+6e}lfb{k|WnM8KQ`pu=WW0B_03e$ZR)#I>*});W zR;3VoVFMCKMG+Qh;NI{~NAfNgSah4P+sNMOv40G7y_Egv2;=miXQxyZ6eeJgF!iU? zkFn1MiwC?pDDEUvJ5$nNW{Gt`%)BxBa6{lJO@C-HEbC$*ZM&YsYzwwPTx$j=u-S!A z=|)UxHGWdRt)y++gOc+$H7CsTdyM!0)qImIIjI+j9>tomS&2i+MN(+3SP>fd4uOjT z3w;eLgb^PP_Jl8VXtE0<7RRBAz0e>hU5H>#G=|yv`=~Q>{)mfxY%=-t zS|-`0q>Vh$mblBn{xmnrU5eYG6_g{Ij0Rta$fHG-ugds?C)P}2-#kJ$mi$t2rfkGM zk*C;h@3&U0I=_;b(h~xm&~4q+`;x8>Nb6Y*{07I7?k}Hs`gXivlf%^Rnr!EZu`qrK zZ1@8FeTxWhe|Zg`=lOMOj0!@)3LP_jc+nZxP}45Ow{811{7wb47=iCq`r6NQI_$2i zHSQ-*d&s}4X1fTdh^&0m^Y&LV>g>4qp5xoMJpl0L0-da064*U8&XuRV1cI2GS1ZoOHT^1Q5=uhI18xcPL)zL#gytb=|&X1;h zE7BHuvq>s8BG`1bPc5dx;=oYiQK8Ge3XA<$y(*eEL#m6) znEZf9IiSzwx*&u<^-ZOA_XCWq3RR4;SNyD_3r0RtAZqsax9H~Q5#1tjf>}{~#*zRY z?Cg?vyK7GWT;HK{fgEK)(?`TQ%rPB=>`KL9xS@HZ`g^VRo(%~dqPXFKWATi2uCQ$s zxxa4XY|G5UxnZ*3n5HY*ws{YR|JmAHdyi$?ii9pw!SYIW7MM^v*lb@`!t8RGYRPuRk!tPf9Tmj%hPb9BJbE43;yuO>6oT)_&?@-28|;QHQiE$^>PN^leI4++h3B#8ligtXVu7Mih$Osri*ntvpNU*g3JozGdZR6r;aE;8FZ zhlyr@D){}Gbc=+Jyh`O8=De7$s3J#+57zCDVAyF}rZ@_`5G!-TVU<~3c=vn)-U3u3 ziP$T4l6`A`rzis)CX(q5Nu1R~7#uX&&+ViHWvarQJM?p(Of$iRY<58+z^CG-!sPxF z=pgxsvJ5$EV4D0QWd`F}dE`D~(ofEkOFFdHs38O8)3(Gms%i`VGYe?D13axs#F~_i zlA8dE`9L+hNLk;s6yMM&znDtD2v}cYTwBE*a;lU3oS+ax|7iFd;u&G^HHL-g=o*Dr zrX=pj^vI5clMSV5s)dq%q)W@ld71#e7z;u;TD{bgYt<&(<@a*eCCGd*-ZRu55n2LT z>6vra{VArehhbmlZ}@2IWh{HjRH{fP z-^_4Bx_NoX{E!leNtWGaoKk>BKaD1foX5Y~Z!w}!F0@ zvP5q0Bthi;r3<>C-27k*SAT7-=d&js>3obc+&?1?LFguBj=W5k%$*SBcMHFx2b5`kJ(?eAZ{~nr{CTDvBEhIN|8sRCzeD!&8l@;QlUV2TJXLUS5#Dh`!vT6gR{> z2`JPPnP5Dke$u@A0#$LIgp0PZiLv6;H8x>G$`QqR$5c4RTz(3$Ye%s+7i_xNRb54t z`@A?-41N=20dg+!8i~CqpuS*w(DXz8dNwT>=VMmP0-n-xgs!q&^$fj z7IHuv(~29|BzaeZ%0e#u&in8SVc-=g;b)GXyX_sMekrtT_FyRLhv73|G)_R`1=>S5 zTD8)~2%J5EMqLpe$uWEG)-?pHduILzFG4@Im<0R^^QFf9C&vF0M1TPS@qzTv_=5HS z{|Dpi*Z->m=KeJTIK=-(H_V+`Nkh`p!qHvfzsCm0YTK#fFXIMkVQZn;HCULL?!nI> zx`R^Ig`(r5^Fwe$1T&KN!6yePonA>IuW$VrgGS$x=<+l%F6HQsO?`= zcxTN#AwDku2z&b;X!DxWY+79OrJBZjbk2MAn)COzyB_KDX?E)p%p0axVOz92K?K=y zSHFh_$^fC66+?51vcQ)bfRdxFDp!CB&zb?NKZ1#Q0I|xN+(*XH*fd;~)ThZ~T0ym4 zM1_NoN?na{%!(L|da9Z&2IpNf*H=eh1(5iW8ID)Z1W~Thm`Yn6J4& z&&@(Sn60Xy)OIa4rh*RKpTVVd6D7I68^HMIwz@h$mXg7ZYTcI9K-n-c&R%3^f-eV9Y;q~ zSM%|P^=<<`^-7$joSo~tdQ@b?GE9- zzIulau!Ss!gou3P%P~^JoDMOM5-}ECbOUwR25z!mv2M3vg%0x;=NJMw+n%kahd7&P zS80Whm#mqSO(rgq?;DGvEAe<@`uzcGedcM^&8q46RkQQcbsSpPGs&izR%V() z{&d@%Slm(aVbtR}7S0TMpWHp>J`?0R1Cw+-5T$in;u;kv z8ZdMTi%t12BahszuB@B?RKOTO^WwRymuM4>Ld6{THWJuNutal?x~Jo#uWmSh05yLb zH1j#(xz$wBlgF9GWJr3HcaX5@w>|KN;%Xh+40PSr&{kD9{|I@3tN{q+posSZ3`;ml z66X^n0R=vZ5|9RpUjfeqM2|&PJ3K_cor$nl^Q@pW*;lyMAzwQ0U^re>uB@xj6;mh^?PUXDXi(0qxgjh)#Qin8Ned>Te2zT{z3m zsE~+XBCUgpK>9yFP?O)M>mFkYDxZD;{$2}htdqf$4aB&Ck7fv|W2-;C6ocRMkW}CW zg2EB3@>!h+Pj@m*T|5XuN@qbV&%$W~n|9!m*XZ4UGj{miOq3MEUlKYl=(0>;4pv6f z9puwk&UW4}J+S=P{_)NH=O;JYdNNPFh|wV=^D29e6=`jIq{FGXHf5iv{#x-m~t@DPtgIGDBUAEiixk+ zl=muxOc!*Npce{d2QIP{Q&K0?RbEbLh_xTrJA*m3m;iJ-d2bn;2OenV0bCq{@xjR? z0ZK=*lCVDdx_TfqqP5YYT_p0YE=s`5w4WQP71izmC@w{sQ{|{Y z{$jX9a5W|&HaH%bDQeMW+Jmg(76~>+rP^%C1)u5o6ve$V?@IB;moB5oML3b?XgQLT z0jwX@TPXBKUWJD1?nhP1mr%N5pWqyh_i~ir#nFC!6Mc;u`#DC(0qYzyhrCCTYge1i zGn7t#O;ImLK2y*-|9t~TlzPTgIB$Ry=;{U3J*v3{0ank&E5NBW2OE!r>@ z?GFAG&RHS_IFO|!SJ5> zyVaN#M@jhI{iwASmuH-njf6mRv_Z9u5dBj1pLZs;^%eH{zp$OJmq-!=;PY|T()-{P z%>jh-#bUQo8amHcRw<|7hBrxf6nVO$XF}~dj_&>tSV;7JBAL<@hkhav0K#8QnkVQH zo-}XQ3vIMBOYCq)>AjKa<)rh9vUxk*02?H7;{p2?(SR*wuLxPN{uvu#pT%Fo@_$Vg zUa>3j$+YlK5|YOKR%iQd#`Rc+239%Gt0R0jR=J{H@mw5@p$(nJth0&7SbIZr3e(1{ z1*S>PskgY(7V#l`n+tjNe)hZchVR={L8m8gUGv-_Cd6YN%V@uQd`s#P`{U1kn}QyKD>Q?QE|{P z>Ef$D=)c?<_{jh3W82B~KOEctqXXothlGWtiHE(rnuVjeh3mfpCSp}5l?GH$1jXTp z)$+ezLC;qdjAR`n?Tw69*%plq9hB(M$N0@oWoEj~ z?gs|;1cChNPl_TaOR`(-1Hv-)>wvpK9m4(y5We3757DYMK))CNof4)xihQ8+`jfPn zejX+x(>aAc#18dYc9Zi$fTK zaQnBFr>;%9axw`n*wD;8_Ym*1(%}8GZPo`=xL z6a*v)>_0KGH2)J?`&vY0Q`@hKiU0Q+@;^8&3qe6afkP>ILV0>ZAxS~SrMwmV>Q4DZ zCI!Wbm|rv0B=Mdz)a@SdSyJ?*>bUMu{KK9W4!}E;&zbweC}2m|1jv2A15_K=9L9&5nm29bAinFasLCHTlwhPlu#K zw&o3f$$MWFWi)JvRq#(vQ(n^zk}{%INne0&5gXa8vr_LY)dN!$EaSvkcGYF89c4e< zPI`A)jCMNPs;7=o(*RPj>k4g2tWasUjVB&RElTJFpBb#-GVI@o+SIr;hg2}aKE{xZVj-5sg1P5-cl8(cL`AwCityJm&^!>7?Q|YtczlZbA7g0}gAf2{}lrzty*xLEHs|_otsyF0Rean=Nb5^n{ zJMx&8E916u*ua}h>YR${pS28z6DR-d5o*Py`g}NWXr$qjgyT@o28z|G5J4{YX&9S} zYGz1OdafxLoBS$2_aDq2Zj>f* zt#!rB;Acu=AtVJ%U^X!&zt|d8C~37STxV^8yM7&4Mf*2^nK4o+k6~z%&tc2 z?_L_+G0Al!oC^aW9@*gvbV-~Sk%`l5x=UOfdhtMyWQtcJC5Y>v(a01}w3y|MF&}Yf zrmydXZ_Ieh*`R z_!u`E^`Xl@gx0O9KC!5I5k}6nGu1uup!5Ex<QyW`k0%5k7k*dEwqX80Ym{a)TKTHrxD+JEOCTT3|RZN>x+vGFUzej zeY3Q0V~fsaN-z^90w~VvZ>{1YvM?zErLlWfWP&(+7vnW$%s4Hs3hwa;hI9#v!|nqR zt9-OVQ-PHO$=S4BS?n)U&8 z0cIuscQA)-`UBl?2MEO#j^Z-!YT>N8-JSgFf(Jg9M+n~~~q80iSw*)Eejq!Ue` zeRE#ww*Sccj0>yozqD#6<|dg6^Guu4Vv+*dm4I=GPw(vu9o8YULskjo|^=#~H>g;cxJdsDP zoVs8i4%W`(4tVu1M`Q$gt+2gg)qEYQzc>izHNQG-7Hh-7C2V zIoj(oCKdOWA4%|^RY5;E=cp&YYAB=q7w-F?$rr|d0{}F>%FUXXOS?LGIRERQ{I63| zLr)oB8slRG+mjVP$Ca9*Qg&?!BGiqPVkZj>Nd+h#EcU%+{ttpB>Sk-22Sj{gQTIbn z<*$f+O4Z-c+x;@Nc&+vCst&U^Vy3q6n$@}NM<2QDR)_VyK>^6yPHN4Zg{$!G!2m*V1!x_%60?jjT;C4wRX(*+^5~L;{BHrGwj>D30>_tS18DPkF`CBI;mv6+f1O7 zJUxC;%BC8wS3|Wz%QjzGDkZVWg0SL==R!DQa2s591|=VUrj=bacUKr@vv` z8;a5~dn}Ob(xxg+z?)@oy~B8eSHDqEd)>v!F4VKmRzZTj*9J>Y!RLHB8G>&a%MLaL zkA6d~h>;-6Gxd&LH-*yT9mC6Wrii{Jq_(M9zzeqfyxUeTyk4btF3oB#e>>JDzw=?YK%L+$5lNuAK}cebm=ly z1#O+6+fN}km{>roWz!~TXf2v3S#O5lucIzkk1B_c`mwn90BS-=`Ua!S?L}2G;j#>S zLPu^O2wr))ng@~FA>w7UO(w`LRKx*n36xuRCT?1Wta&4-FFl$QBBnwo?g67Pl?(9&)<{nx z@`>*&9WZe8N3e*pUqR%HMNm)!?;j%XPpFti@i4*JJIVzjYotxOU3BFo6(+lTvb-ct z%z6K$14)(c_oJh4sEn^0k}a3B3vB`U6Hkz@JO$kI^n!}~moWgLFc)aW4fqQ;UPpGinRN3trB@FB-lu_cHs_P51 z6A1%wb-Q?+T)=!3No*7A0pt#)%(wmCC>-Bo6r}MY?3;x`0zzW2E5~iilQ+jyq|3+N zf8co-MT}r~a1apLuPyx#u=_u=uQ>l^JKH+A{fDdEzcT{==%r}k=4N7L@!yPqrlN|T zCdLO7#3p+fn9UHGtyvIwH(Jn~7TBM(e7r0O3Y*41A@TcYh6=ZN%*+_SQsKQW*E?LT zupL(sYx(w$JI*$9{YGQutq2H5+%_lW$w|lu_t)=o-G07q_$fIOT?M=feow!4K{;YA zG*;`^K)J|JxuIH{G_W4T#MIVQsLoJjo$SkrwzJ>bO(}`?@vLi3R!g*`E;bFmAPaS> z{$@%&siZWF=;>JX&GI!aTF+h^qq}<76UD1x!pE-0TCv{`&K>d$EEiqsw{sc9s+l-9 zB-o;*DBOJsuxjcT{n^6I$(e=N04;lcy3=V}e;_ylPqvhzF^$FQaEIf`vm!2Y_Hd)x zddps^9AjQuYnEY(e3NcMTMIgvZU4PMuv?>s?AF4bMUO6!xhCCwQx>6BL}!$%O0o*I zbKoIu8te9DhA!QVCd~?u}s(9 zbB)bjSWPON{L5>Ov?&TEY1v2#IiG<>Lb`hp*-jyin!YFUA-GP)1K@24p2$xAg(ZletV?zl*@$B#v;y zV9@|KMD6Vx+A{&Mn$^2&R!RU^3yU&0dI<9phm!AannNC$Bnp0t%{xVE5+oNcx`3a5CR}wAlpqnj1z%;; z?J&d6oy7hbOm@xr#C&-Pn(oxlC{!J;Inxypi4{1Z2ifYJpsm|6$vK3IcAelz%sV23 zOxh!~Fe;OguqT9eQ=Rvi7$}uTx*rygz;eq#8Y*;~GyB#Z-@VPAf1g+}>W^G_Bl7f1 zWE)kM`oEvR4`)%=kS_up(9dK ze}HYIF&d%=n0#NSI8X12o4*YwR6I4y8p=%jO0Pc%PH_Ws_XJBTPBnN8~8u0+fa!XhT>QJ7}u9a>3?tC+)TXxgLPy1H#YGfy+qyJU2RM~+%4Sxn}Ji; zQD0QS_;5@wNuj}{DJUSJ^OS{c`c?WJjGWvo7?nVOB)w%FV4UT?@aqKmTKW1EzWzxK zD%Zu`|4zE{hziKo!v2!r*XH-r-|B~OVBiawG2EmJMM7d?YT*c~R2e?$zG(&qfC@-k zxPiLbGG{3<00ge^Fv0LrlQZuzg>pEpmbH(eD3yBQkkQXDSsl}6acx;^$gc;~r8C^# zW92qEUL4oao~v68eHB7Lu$^~7RIEQa5UkUQW9_QvtKVfvaPC6=1YC)u__t}+X9%~tEsmND zPnb@m0GHKv6R`xC3(7Bu@Lo>57RD{58NW^IVHM`fA!ohUA^Kjq;Dz4)cKM@x18o(; z@ikWInNaBy>K}Wke}F8w;fw8?`PxVSeh+;)Z~tHath0%`yM?Rcf7nEv|EZgptBtvp zg~~q%`HJK8v~c|z?w|LCT&<0-cwCInjYG5KX|=30EHDhw5(*pR!rK+oa5ddf8=Guh zT1n$<$E4ax$94M`${7{}WTB@j_NU{}fH~-#!j?a%E+f>$IWAJ8pHhNe%_YRLjeNPA zewY6rXWtlIiMnjt9b?6I$L=I6wr$(C)j@Y`+qP}HW81dT;mh9l-1p;-bN0g+>&N=N zzFJkYX3eVEa+vr znTRd-;AkTC@Sw@&xTTe|NspIW|3Si3}3MsXR#-Of_KJs(xkCfPXdm zxKfSQ)|0BskgXjK6m@>bh;p>L=(mC_Wty|^;UouI&y;qCsj3;LT*z~Ns*JZ z-M@gyq(k_8u!z;I%|oOQQ3s%HKq1<;){3VOa)*Yc|8s5Fxn>ysVfaYjU&?e-s*|k~ zQ)W!*(S8l*9C=dE(Mr=elMl39MNX#X%2yM97jcyF`ZTBm+9saGAWM^5Oqi9IqIrQ= z_D5GTYIE2I(}|1F$-aK`lG8RRZ{R<6)I!~)WxT{ zmUJ(KD^ZmtPK@tNnMp$I1gNaVYS!h~RT@#FTaSd0okeA0)58qttILee`RFaARRU=n zuZXz2x+RIO9{jm$GUC!m*Qh#0$Jq<;-FaC{obFDaC~tNj-kniB`$qrPW>e@)Ww)WE zZ5+Et{)J;}S==x;)h%5gL|HDuU)zviN#9i9b4bN98F@G^^p5Tbs4oTjKLGcDC_P6D z@*0qsZdoXv-k2wp;PFneEpXrCrzaG*-{Fx(X3etS(5ID5%89r(mYTy0orLTn&I@ru zoWO_nVEt#pmgEmA^i-d7qG;dWj$I>HMa?t%@ijO{{(N_M1UZ?GKtDMEZ5Hb}<_Ga& zi}KcpyK_bByNduuelg=ZI9CYR?T+L$e(Y1%|+Gg<{!V@|UNHfw7 z3dP)kx~k62u|9P4L{J+k_a{3OA|DA*rV%BAP=`jO0Z|X+UiKv2gzJO58_PhCR^C3r}3;GgX zSBIO#k6BatozC?83!%_;hXEUn9ehJp{2DJGZ#`{iqb3(!zZ|mF>gjC?wfy3uLI+CV zCKn@PE^_UO2W4xyk~_&{{0i)xl?6k1b1~$LJ{2Jrk#lk%zA%XrB)d4KkB-r1y)mQD z_NC5%a2!dNh1Rek@eCTA!(k*3ejN=#nI+LDa~frE9PX&iNC=vu2qze3{N0v26u;%*)Q<((Yw6 zWqO8^iU6xT3M?>Aih^=#qkXvQ&1iSC&Tnme7v{oDPL&1b54GP5Mm}bgJ#_ziu_HVN zMupE2o6A3r*y#T0#RT;Y&5VtN^qq`FY#pri|F!w>sc^DGSwwrUB$2%N(bH(KJj~K4 zJ}Z=XzC_XgOWG^~PNbg&>??d=BF%z?4%K<-Olb050=k%(q8I_Z^)C?V)O<=CfmAg_ zGjYk8p?t;+nV-&Nv%nOYqGPF_O|!gHj+d3j%jor)(;biPliXDu?^_26mS0-0I)z4) zxSvA7ATvK{>&}y&MUwb!ddNsOyScC;61VGmj3KrYtWM7iy2(Ut=+h{{&8^XEAnf+* zQW%O3*HFVx#oneX>rT(1FiM+4^ANSH!{j*J*Gi1dU3A^8BSl=tR60|(i=+E5p4^yGOXu`;V+=8z18`fQ+0*8 zX>IXFG7VnfhQ+wct+s4HCe#p{vrP^lBI!f$?LvhnE7lrlOwTZU?^7T=1!TfRel9sj zo{7jTN(aCvgLqZk$c_ZqXs?$E^W8hFKj;O5_>DT_*DjbJP4-dbc}z@CLR~*SQU<{U zc_0?mAdAgr>m&%)?_CkHg5<(f{o)2LhI#QiM?QvmXV;&i9wPU zs~LLMVrXeo3LMoza-~4yFq>LJjHoiKnQtX==CpaqsLT!&8S)4gBH!BtC1a9@qzYQt zYYi!fQ#2IV_PEN4D9Z47-Fk%XPlf#l2)orTqs`Rs1Pa{Wd0~n zSc0vJC9&riW32>+OXVtxJ05bzi5SfLOwVGQ28gizf$#}$$pu7;NnIxejKc$sT8Aabodd)G?WAk?7|4e-=V03gIeB~?7Y zKcu%_vsLtJILqr#9GJM%J8ZPnPzp@l#iIGYFD@oQC=_gcP!fBw!X_RevGFGF3`+!u!yM&VmSOhOVv znTmA7OMsa!r}qJNbB#g7K&*?*xJZ&X3jy&5W8{|j(li|Mq4|1kMaPOIVC7M(e&d;{ z=A9OBMET7>$K7V7KHot-%<2e_gOaJi&&d7@jVf`4{;`E83zW3iI3 z+;@@NO>j`SopQIxE$qq*=h+yy`|#7s8Vk!^i^xb-H7R`5El85YNUKK~i+8u_jlF9T zO)IVjHV?JGGGQB1g?p*v$G8U82YSgnLo8#?{n~YIaKqoR?imO>uhffbJR^-o?%H%P$KWTh;q{h!8 zV%BCn8ksUTC5299B;2j4euou#cBkjQ3y>pk8m#yxCr1@4u@J5%R-T{qIdVcOm6JWB zH^W5U>!t#mikJs?gPUH=E&8%4dbdIJ%#q8h1Xe}?yM3< z*Vhr^JIHUBBwb$*h|I=Ky%A+M*B7Y74Qnn#K{Q;LhH*Z4<_SIV;Qquw3psW_3(MOM zN?bSp1sj^2dnm0bxd`%VT+td3*&MjZt49*>OE&O*Fzp-m)^1exCobk)aVzo?^ig4< z8bPilk(#*5iT)7X8UCc)!G_9yZ-l7o`^iG=wS?TP#uepLi&T!VPz?;96AM+v3Q6vT z^GcWWqlc$gZXI6U%pk4v*J#8B?hSbFKN?A!j!HRDd-98l_!N_d>YQ&AIb#gxXNj-K zK|1|0E?x1W-{ihGI!?Kxdfg{YO(|}>LQ*3RGgJP)~rx6|d@!SsdP4la&q34WI&bKr$7U~`A=36!Uo;952J z1N0|yi&)%2pBo@bAx0Td6|Aj<#`r7`H!{W~L=@jcXykfUCzqo?B&jUUhzB{~gs93p zXfoPA&GUtsN0J=D-7SOZeyR(Hm`zgUhfoXEl5Nsy9?4;@HhjbWv;dM8!-{u}ovXOo zGtT)>jLtxs4T1Gx%p!EX9aQ2;yq$a^8E<=P=r&)bn-IwjGx&~(lM+R>6@ExneAg%! zt^8SqA$G1_bDn2f_EM>g9*D0p8G{=3*}&Z;mkCd7Zy&`dds19Ma3qUDvXrX%{jpt? zdJl@B$E9*$P>Ipa)1H}+=5S!MWgR#VG1oP;?PM;ne$|1$;cAcHx_CL(W=Dci02@Q0zw$!mq5wW4%OQSr z7+%c`M`opqWtM-?@f9PeGmWCt8wB<(cfCh( zYv;F4>u`rLDM9uyWE|1`LFE{0!46#fqwdO}TpUvDjk z=5+OM#7&2M6f4H?RNK+R_7U17$yE**PtlcuF=)ZNZca2n(`Y1WP!a~(Ho$OQtqk(+L-pKV1cA5-WDlt3bO2Cp_0OD$jW+ zAXOCsR~A{XS(F(-Nx6|=M7&ii(IUYu`Q9~loqDKy^-F*C41(z-Qu)Cu?TIc`0AirB z{w1ja+g_>5Kp=pA>>WIaAECYDhxYKSVU&J3L6W{)#K^Xdx)>*$p&n^q@aZd=bV8X* zqS3gbd1Sj}7nKf&g@~dTPEG!eq7x>41<`PEU?53f_qPR1m5+|TldL8tQ~+0xBHSqi z%T>5djiDZjFq|etrr~NgybBik%Z*147R$H|mXpWxut&Y?s5p{M(LAV0U@G_RkU8=w zdQVk^YG^KPU;DCPBKIKbVGcUx4R>YyaaE-EzB04}jQ&RTld5;&rDP2Um77 zblsfpv06@4@Yj35x7-8RXNl+r*>|XlA1vcDF>7cLJTYiJ(Ki9)j$#J*u4b$&kwVyg zgyKU`7s%w|}&I~g01Q&KrAUZXPos6x>Lr9?hO3~iP*$msiCy9BF< zvGR1Pxks_XuOXs*ph~Iot0$ASC zKH>W4e>%GI+^Kme5kgO|ZPhqIawF&Oq;VEj8lbfLbh#pc{reV9s1ogktGGpz>dtp% zR-}QdS1V~Nm;Cj2VK|rY#sSceN-W(aA#i$>-<$eRz77Vzu_kZ~UIeqs#WCg@bX5cRdfQn{o;bvS;h8oy(2=X7U?3@C!<>*vvl;xjbP}j_-bMa-H#ugj&BFGrD4`m z+ldj-Qe@ROyDS$=&0!ua2lTeP$luBBvIsv2ASR+u9_wS#MR}`7h#?z0Kyxg`g`|sF zFgp-snxucmiJg>)73Za573n4xs{J8HQ_EiTh}RjzJYax;6*3~i5kJSs2s*NXDKeK< zP|E)>sMlP!)mtv83ie|8V``R>t+j==<0h?U8=Y&`nh?QcG7i~IG)WE}W`4PvoKCe< zUsR`y_!5~zw)0$H-#*iSRRrH|oV_vo-ot0ADU5f-G_ixre=_T?MZavWMG~R`BHbdb zTBydFdQxC%ke^f`@{*~qX*Tb)q|p4ii<#J~ti{-<#X1jfBE?N?xj6jg6ydMnSMNc7 z2>c9wg?|iw#{bvg|1Y{ZLB-t>#TeJSQM&fHRt}1m0gVAlLQKIgxR`%>1|6D(mgOrg zezSGs@q!U63691U1VZ~I=p>f&+0j!__!Lm(y4${;CpfG3+P#S|-`aQP_@cAx<-Oz2 zZkFvN$ddnK`_kzEKKNyE~VD#9v~kPd<~7 zytnlT3N1hx*#PxuojKm<@rJhM*6w${ ze;nJMJhjS-s;s4x%!ja9X+3VGGCXw`N+_UYq#~R#MXO_|$c_j#w9P;hq=tM2{Y2nMU~$ z-vGUdwzfHsi$j7tH`YeGT1@Sc_in0Exe?a5R(C9wQ; zs>WK7`5wKbxtK^b5EnU-E~(VJ(6v9f7URHRA!B;73P; ze>V=5!BRg&I|-!!o(Yz1>E{l9*;0sWv&x}sbT@pkYF4PLy+AJ<9PQl1sDLCgi$6NT z&o}TkPr^isH$C;y1Z4GDs*`mM@iijnJL|R0FR~TyG}HubH@YYyXtgoo4V$1#W% zLkn(bZq}#mkJdQ@o_oy>@?=AITKsg0LS%m?Q&Oh-rI9+_PG$^+Ed|zCWYRkan!qp^ z{JOpbV2jpXxtNzVEtga&l}!?qlGCI^`=98-`7TWVN<{2$_-KhCtzTkFsBQ4{X_~Qt zUJP)<2KATA;ZO!Ud_b z5#phnoGj6ll`xW!auIaK*5BCRC-e)6?kpgcxT_b3{RO{W!2!l0-`x@TOg&dT$qe@h zUH`=Orl^K-KY}(TSxtLlS@H{p-?jdy@a?9iw!#{B7^z?equlPr1fyE(Jad5D8e`Z( z4i?R0MRFkBZ&Pe)&`d@%lrf&DK56prQR&WJfe*o!w^;Q<++SV086%Vx)mUIZnWejIiDOCRO2R$^BHgga`H}&lGje0L^Pu zo9)c=0mf#Op_qPH%>J;s8yI-Ifs-|UL$`<@Iz|1QTAi1-Z(n%^gPw2+wqY}6wo%gi zikf{ABl!j-m=tY;@%`OfV~R}Hw7AbpGY4znSz~r`;IZtjc0-)Ad7D5c%sFigh47wg zbLm1tLeIX1HsfiR-{`0<`Pit`fOCiUl~84wWd2H2FUNy^%XC5xosokn)`5kLM^k0u~aLkzP#XK1t+~Y;li+cvzsxmPmrR1a$?(L zr{>x5v3=qh=+7ENOLn1wIL2&H@zd(_C&8s#&|{UH+H;#$y%r#D+IkfA7PtbNv)dB| zJ04iEBjNBXlle~nhePWkbb%SHsct_qm26X(WCm{|cA{UpI*+{WfFi z-`Hrn14UDDL`!*)1QO{LxfJI;U~!%vM<=4R7+>g+LaB#1s;eZ23eN&H^-Nh?z9FP)(qj2_Kp;E%t<^sE~=9q@LdNs{l;4h z&bYtz%D8a3zL=F%!YAbW7D7~Go_+dkd&R`}%VDc5Yd8QwVa)?ybz%5z%#|z}B+86) zlKIgk0rNjMKQLaJmytS6iU9)vk+YB6aR_g)Qp|!4u|X*5R#wcx;ni=(`FRt>OM<*s zaSh@=#>r|uY!$#P@qCng!@F-SbbJvGv1-%q!Yjw?gtnb}dt(%s_vFcsG6tPB>X=5O zPE$QJ%x4I#!CYkGC6F)6ihmDY5E&~w96o9M`G2JGIsXZd{PnC-wubsn=C(Hf{%JFm ztYtq1CEgbc)0Nb@I7FR{h|7bL@_b5&d9Y+8qXr;7n7rD9+LV+{(#Kb}A!N~JJEFW# zdEtkNFk#eYPY#zYMU(CmqmDCKU7g;L^kJqDB5>g;^w-}IKzGUT4SI#Zl~I_bPLhEm z+!cm_J!+Pfw(S-Rs#xea-bYJZTNQZv9-WL`mXKVbLKNq$mE_poVWO3Eo0(51om_~7 z>XHDj(MqR0v_PwZ){*S_H|rkyDZ2tQmxo57=AI_58&tHQrV&Ba4wNGF^X3--I3-Wz zr#0;;Iy+7RLWH(=w{?`{kWQ3JdXJ#?g>IDNa%ZFlE&Bi^1 z?4WfMT2nweILC83+e8Tt@CL(p11SX3aBQ7J&=>$hgI9-+zg-i_4tuLMb=}`flnJEK zlE5GE+|S**NO{8>qnAHMV={IYOTFPm)5mlWn&XyeK)Xg9q^4X=0zTcwI!UT!lUNW* zcZ$XWkR5+Zz!%VgodXa+2%E496*w*nBp!lM8IOX#(61>_#TF3eiO6Pt{Xt74i5^{r zrq19Pen!X*Y?dezXO$!M#jcDo&iEo9Zhk|dPfwVVqv-+=bu~-uHQML^~OcNAlQ?H#@!KL2-``g<7VWNu?BZewEmujHhpZHps}%DuaOkC8U$d{RHh07qNUc)9=<`bP}P z{wx_g9eqSPkLj1%s-jea`pD=OIQJi={2LFq5sjCMZzl6c*cHAFGx6&q?xE1Y{cM$0BmRhGKdz{8Zv zINFAFS|DwavPXLdw%&eiC~@IJB@Nm9EP?!8kE?>BhwOY54>_|*c;F=r`lhLp==_LK>o!WkecH+ zxAYk0N#ViwdZm1MI64sGqz_aGTNK)o)cm!I%-H6K75TdHPA3>4VvPXK707N zIY7#jV751xj1A2r#DwxQ+zw%~Vngv`?fipKo3!vDy9$59G-Ly2s<7z_YjAre!ztQV zwCm!#LvsZ9*%Y29|IURTp6(8cX8_rS9;~bRBfPuruBIn3c(a6hs8bi^9|?zi?NpkC ziL3!(^B6G5s$CvnKeV}auki^vUrX(cGg!&{7~h|$y)aO8q8{CPW>R2BZ6VMM;2roy zFq)9)4GKjT@g2+1G8CEn0d-e4o14Q;UH=dAqLzM)r&dcA+pz_x<;mx1o@w$JB z$N&8<$Um1jXDh4!Q;EC$tHg0fIa@BGP3NHeWF)JFQ>EgTx$f$5*>bq%G5dFotM)&HF+tr^Dt1fu_f7dB#&sI8($WXoijV{=7@SJGlCUV<7hqtJ~KF3WAC6#r$iZ@i! zB28Sa{a$!j*4%FSY*fKOvS4iki36zd)KB6sZGIu^6B<7->2Rz!edZj@6wIvewsV2o zM8E7*gn>U}5e!WuC~e2XY!{!K%>w3D<2>m09W=q-T$T}j?4mofsSg*@f( zMog@?G#s^H=FzC*NE;^5)Jlf1AcCmlszF;yTt6g@)EoVRfLnU%0#YTot$3&pG?UR) zO=wz!{RPP%pI^?J@h&wNxO$y-&`6t_(NQc<+T)|I)i3n{O$1VrgA2Di#hjl#@@Ynk zDQiSysn$~(UWEPIZLs=B2?O*VH3lidV9V=~9dR9SGW0Ovu%Kp~=H$0Dbjuuh#6l+$!kEw`#ZDCX0QV6)HQ}(#X7nFJCa3gv`DJK_OSuGmeM<*)1^( z%4<}x1=;2sN^DC=iFc*&H1c}fEqU-F#!o&?wO8MM=)ERTs$=>+@Ex_HUb^EBtX_1F z5-*9~R$&fxv-KYB-;r@M9?h~;Xk2WH8L$OkOKjyfGKl_Q&DalHc6$U)97pp#u>OU@ z$>L%q4L{49$v>7imVbh4;x$VMPQ!WDI@h% zHJujA&6_mooxrBGSW@CN>W)Tu_e*hG-6%bS6OjTsH9ZH zg3^G#K&@i2rArYNK&*|E?#t zTrp}^XFt<&Y3n1-N|_1`@N;QhR|#6RlsR?j8=yB@MKlZG&`r?Uu01-xy&~9TQ=}iG zff6~%aW|GLhZ1uD(tE_PX`*{z`e>ABPj^9tUet8Qw3~+bF-}QJK>h?Fd74 z!iA^&!sN}GQ3s6kbB}u6FjeCjbMzJZl;J*C^O*CQwP1sOr+~U*6A?otvcn>e-|+V^4M2PNZb>WGK2HYRVOOQ z%Csc5)kf0QFb)j*2os&Rr>F*|cx==H)Ah_E5NH|vXC6ZJmQomLVyd{c(Pd)j((3aL z&yZP@nhhy7R{V@0ML~MC{ z^ovK7La9ejO2x4J!8WGH+zixK(?KH@CxsTHGQyUCcBI}w6&S~-OVR1e1#dfu?+?%6 zn8r{W@HfbQT@$P=tYyIM*8;rQe+zWq>up97#D`^|*&*wT=}P<-s7WC=t6l4TY&Y*T zsfje&03&Yc7O33lW$MS77=;pP$l0lS5F6LNvE@M35mbBzM zw6T`+Yoze&O!2x-#LLdtyo*fv#~*&O!F(%l9D$i`TYB}k7RqYW0OGHusl>11R&g#W z(x_e=>gk0^1xfhj=y&=E55D?YhxaA!+0HnhSC={1r8Y1%%)y0ZPNZzzqZU}dw`Y0h z8TlyQjgi{U*cCx>MuSi+}eg+BB|ag7C5lYmNZ9Fo1rvM?kp# zGI_l;sTSlz;;cAtFgxiL_ns)DScpCG^oDE4z&9j%7hSl1iTGnz%nYTCT4~v(!ykBUxTRxX(>o}aa#svD( zBSn)J^>efHg2Bo@ne^e}=0u|7j?xdzMK zFe=Ji%+-OWfU+b7VW4gc;u>pdR}bL!AUl#0M=*5ngA%MSzAx_``nU17IQ zGJ3twqNMeYaEt37i_&KxD;nGBJLo&v{s+)ipm-|tS)ASjHpmtI^*r><73vB z#A@`xH~K*)GdIK@kXR)D7zII%K0zY^wK=mmIDS(o42k{q3We{JSNRlpf`=?s_)r~$ z5ecm}j*DoK1sKwj@d4v_7ZRpLC}ZMfw741-jQ-eoUj)n54y`L$n~jf*7a3^%BK>d* zja$Jy~%tzWM?si5fv@+h;ctf)usoH-q@DQVo|7Zx=qxMwku#LB8`&Ey@L3 zWqWPjd2>HWzF9BEqyLeDLo5VX%&_l$?=z|0%r{T_A&(8ge`~GZa_R-MTA>l)sdV!- z=NsTQX-a=etHpS=cV#mHP}k>#g&xOkT1D+F-|>Xbqh69_tCA!{XOOpY)F??kny832 zDLo(5AHY0DMM^|1mo6tSrAO(%Pl2z`70SRIPK4dNOQBNzyZXVlL!mVeP}aB14gQ)o zRvmqIdGRYq2rc#4k>Vz*cE1!Cw&3-}!8=I*hh4~Vhh3E=AmwXdiGD^8@J%v;=NihU z*kYQhP(sx4mq9!`X62L(4v)syxMR$)i1h9xp1==k5K(+qkzF>zUo^+Zr6|d{+Vy=s z%ChXfmdO_<#^x%f?}lK!85Uq2OSAZu1dPcADccQxfhMGr#G?{_G>}vt48=!V}wTbh$^tg}?JXokJ64 zA#vTza7c3U@3xz|Uj99KK35f1Gx&^Ujem^ge{3D3%s)4q^#2pYinaZ#10Kw(gX1{S z<9HAL{S#~uj3ZnG1ptlc#gF~XXX~`hUiCuZN7~G}N6Ig<&MVNTobbcOuv|^JLUE6Y zj>A9evxk|Nyq(^lazh$OjKZkaYRPy#^aoaBhCRKx0i?eBWojb5gSs}yyU3xcL5~v+GxXh6Uu@jrn%daezVfsS)aBO?M-UIbo0#H z1!csONI7OY5<`m{WsNAI$uCg2tk#Dl(g;pd2}q)a35k)FLQ+c=52ICr`^_u2%@vQ@ zSpA${>ldFb?Ll&8P(CFg&8DAVwP6QFAh4Nj*8iC1yZ&vZ;7~-P)q7i5yG{LvQwRAD zv8*$>#czb)ZY**7BZ){i;17+G)iqiINW|!wN!7l}0&hR9$=W9p*J=uMn^^RCAY{kp z^kkoWg$)?>4X4VD)kCZ^&BMquI+%V=%4ZtlAUtXBoJHT_{v5JEE8Xk-rt4uJ)=RE4 zqCZ!D%Ohue&T+^*;ZvgI1H=arHyZArB<3OAZ`Cr4e-Jr`2$;lteo8YZf99}kMA;C~ z_!DMoh>J4DFm2?JO32&E`Ufs<(_~&Q<`5zHE`9CH< zThqVKnEn@uTA>E3hP&weK3O|T)At4B?u!rUT{Rdi)N-t~I>IXQH(0D_02KIWV!Q8G z6%Ci^vv2;X^$n{`;%Q_qvq|YoGCO1vhMe<#TtFNlMo^l-TXtBIW`l6U$ zqauN?Lg>8nS6$fNg?S3eDqDxx-Z{7Ls~p}Tu6s*WP9QM=9vubvO`UM2H2_kMM1>OEl&Wcv4D^}YZwVu<=}6fFz1aeZ z3E0|shK#h+_Mo)$#Z+RWP8u@Q{=X&Aqbn2i698q##fd&x^KxP)4IK0G9W;x z*3p%5u8X4&9Q?0v)0eSl6-nEHo~(m?Gk%Nej`NZjh~<(|x%39%#Ln4DHrNLZ>vqH!V+ z0Lkb%xy&|jO#VTA9eyUDww1hd(e0B%cVv!BKo9r4D80K@x|P0OdPL@^)ai0m7tNSv zw3+|`newWnY`FV-mcgJQC|F!`ku$M+eNi?BvmgW!X&%+FLyg_*KH@&SgP53LQo!+d zp399f&my>#5Fxj2sYTnx9zm0;@x4$Q#s$-xk;XlSb^Q7W-M z(TnWpb&%4Wy$9p#xFN!4nouhDR;F#?e%gbMCOFK-Lv^EtsW!e{3>!lns0|_pCNINN z{Ie&qt~*!&k9y8AwcC~TyH&p!Ar(QmAnVn71FLeMgFKTll|&hb8!lGCF9JJ@v+jo< zQ8T(-RFxG}zw54*5<9s1*h?m`uvIk>h1vK5%C{=li$oy+tob+c!lmI7vDxORA zXTd3mRbu3_YHWHdB_PecD3ukJEu}|rFki{((M{W8QH%H(kZUsX8M6>f#RoVDZfljE zvFI}PZ&Dr#MNDVN;*{0TvhJzuV<*|IB3r^!u`{^R6>0h6#^rlg@luv&Oc`9tYWueF z8#zP+gLV_Irf416GJ}`SHvQ)veJI47+#vs?_M~%~QelSG&+=DLlPc3WEYzh($nhq1 z9Eh!wmc)NjdjWZ^ttPrGWqToDl?h4BYN9*e%V}%2krLCR0F*!B?4G&2)3~>|GKi={4sJ9^CCe|Doc;Gx=vHE?AkhZcajX&!ktcnh4n#41%S+(ZFo-_)lTph*21cZ>z*6N+nBCvnZA$^@lNx*UgV zcM^RbcNqK{<@0+bTB}a;rB07bE^Gk8PFiRv1VQeL`T>UK&zx2 z_cy*X#v_~7p>Eync##)44!%chx6Bj;tN^$*^3tU7gh(b1Gr6iKUy~tiFK^f`YdL}x zi2K=JKCZjmXIpjHGW^C<*-&^Ag0ut93zR>Uy$WZKL?Wrv%bxqrqP?7z(YyAqLg18^ z?Rn-1@IzKCnK-QE;sXJpHM-kO6PRuSN?vM#vO5eBI}mWAZ5Y?SBBFrr){ofni0W3@ z40gQULpAf*kkiaC)6A7NAHGR&TG@FJ`1+vRq@L<|@_v!qlHz#WAKMfQW@FjAcQ|YO zMna+dm*_lo+EjHvrRshF!6#)+7A8o5r7bklHce*|KJvS2c8d96E{1L-J-4kVXWHAi zZ{~l}J17{VI|Udh()`R^TQ4I?t>VJ8>@R}{bk(SSHVWs;m#Bmt94$9rshA#L3oK)q z(4pU&POGfTP5d%Ct|!`l;8xenSyob_CiO!4>9u^oK-Ne>n^EMQ;}8=yBt_n0%EFkw zaA1RPde0reh?g{AcQqu|IBH);xR0o-`6GZh{rH8rrn91k$Mp91u-iVP*-(aiYC{G~ z_y}3WdF5=HlBp`L^@L3Tp7cb$n3Uc1eqljw>pn2!)=C<3oI-UCEDuX1bzj(hXF<7S zO_~ftb-r7|f_N>lpnu{WP}!nYmDsm~!eZoeMYTRY$x(ZGAYvf88?Zqq$O+_p5{fk%nAyVIh{8)@{|yD?Yk;NmOpJ>@X9WN&<*ZGn|h z;-6;NGIL^OJ?U$uGdhEwPl^QbP`z46o9sS~85N3FfORm&jf@leDEvHs*ww1QOpP*r zvi_>g-Ii7ZaNWg6d@%g#MA`TSKmH&v>rwJ&-=)-Wmw~xm`@Gl8u^V+(J;lk0cJL2} zy!=dt`*vLoq6VIw%(^vlR_@S;;GMI$??G9{Y=f4)$t#=_mX%W$AFK(0iFfJt1A)qi zOGQsV1?)d>msBNG?hiVz_)(X;^Sr%LTHY){WHC55QG#)Vn5B54I>k1)KZy@ zo-dmnTK1>G4bboeTfUEP0V|UWoz(;RG)Nms|K#=RgWRa@BV$2U{W2%THzCjXb*jpQ zpr3#!Tj?dbY-RM7YN;Uu5~}uCbcN-;G~fz%p{I7Rl3IHP_3>=z3x^mz*H{C z)E+O>&{~I&_+7)i5j1sp$9!S$?@vA;GtVT~kZ)XQNQ)T-kGWts2oKL3VU+MDe4@Z` zT^Kbq^HzN_?$sA~52v#ix8IYWo8w@O3oF1bP{L)43oE$)%!WQ9@@Z1kQ&?Wa^%Hr2 zSB(o)l2sJuN&<#vQ%_ANf!Dfjs3UOxiLCF2Ht^EfsvF1Zjuk7_mXT(YpR+Se#uI`2 ziDzg90W+MyVXu8a=fe&d)|kII+-#U~dVg zG)2fXGxZJW!-@F?>OHvy=^gCnNvnL41GS#}5hYEk2s^0Uv?G23cU*H|(+ydT(3hR0 zA}%JF1d=YjNZVcP_Ply}T&hZRf8M^VHr&d?qIOtdj4!MjhakD?17)-W@6kH1Pte*6 z+{N3MO;#WsM!pujTM}<*R7(=h`sjdX%T;b{&XtlGh%(lS95_>{Kfj~`6uJi(!9%|J zq2^6xIHftc+}_g+YGMc@cR&E6lO%~#N#Jo{vJI_72~U7aif9^+OOlJfEle$%l-ad# z{BWKN$mr_QIH+@xMNzdu;H!W=$jaaz4ntHbeHO16#*J%!b+G~P7BeTR&M){y$!$Wp z2kRue*T0KhtI^L>L`IpRYYY0|`!sz(LPZ0zHcfW}hFl^#eAvMGk<7t*PwBb-`}){V zy2P8qRmgZNo&()}tgC8;#@~t$iulnOY9jJ3ypGz;5!{hJEBn_VDp`7ABX=MwQHJy4 zYs0W!AoCRsblC@BRF-tvg|tep@PrpIPitTn^DVv6bvt|25>S&{Xt9XdZxs2U6nP#s zq3{N9_uCM_nwV#MNVx0_h-pE2guaL~kgS8(^FHi}!>k@%D(i=~mA&mcx3&2~1wyE& z$?SLWg5&TgGB?lOS&yJoz8zZFLUws+{c$jC654B#LQQFP=e1CRL3aAg|fMs_@}YGoBGy8|aHYbCbaz;D7F@U|pe|@30qUPnV=@e@st|acws? z_a-=OAS%8n^wSJ(?&RWd3~4izk*dl%k|Ji$)yp*?#~p2rl_0xkJlPit@oon{Q%c@5 z#{VzM-YK{ewOtqOq+{E*ZFX#%9jjxzW81cE+qP}9W1lhS`s>s=d#%+~yDB%ys9cTr zd--5ydezd#koAK}B+o)F&qBK0N`Un<%9Jl@|N7QVEvmmGNw!w`kCQ2Oqr)f!({S74 zYed}ceC+wS*o2S-uB zc5~q~@8rAFZbZC5FJnr7M105dFn-?Gnfj+AlX@ibrP{d}FI_xLKgW5vbyE9It+-_N z;|Yp>-c?HF=6Im!_9g2;F;;(@QorVDTXpr&k}J#7x1&bib}=Suh4uc4{Kre%)vGzb zZ+Q>1D&hCsuR^qLsIL7B#ICr;_R(>a4(9MPffuc8Y?8~W9a3%K6XkQagPIBNN1vX% zv#6hiaSMvJqtJueMF8(}nM~^5?lL*%V`Qq3YLCud*+aA*s!tHEaQCnJ6;HJE=h^vq z2QU|>tU)llyA6p8?(m1=*b2|Gm)^;VLm|ss@RfD^1NN_?`?sgBf6sd(N1XG|05Q%4 z;=jR1|0=Wt@Iv{^-P#Ip-$U?5ThsNx$q6KaDuFnApunLB11{|VF^Df>^wo>VZZhVK z!tt22Tlm_m{w6~(8vsCHh+&#G!;&>c(q}uHI3KxXrLKN_?vJDTxK$J}W)2A9di+~3m+y4EF62?3r(|H985h7`LN-D>F8ZfvFq=YHc8 zwf;vpd9=B3cue(Bv=&WhP41IM)W%liEK%0l%W}6UrzIX=a)) z^P{J1#b`q-K-?ELDDC|_U@yNH#T&0?rApmr#V`A(Qx)0#8JYQ-j$@sh7>F5CSYogb zh|f*eqU~5dAq}_Bv=Qf4!`Jr|+`FKTyUvg*n5wD;r+{yGf?*u5CvH# zi!`aTL7c{NWmqS|T`3aBP?#P2IW3;?%RG#>5K;N+d!^plzl*bCES0=az@}CCubbAt z0*?NPbpQbI-{sl=e9_K~ld+lqfe^Ian3)1LzeJ0FSbrHvCKJXf|AXqx7Z@oHRJ<~5 zz$)GvM{LTvL8JIg?)3LgA1DbNMAbXRK!ssqQi(_(wVSDlX_kx07k4tjf0Q z!s?X-+LL*ixoRY!L4$i zT)Fc{1S`0B){nUwy)o~l>2Vo(LK9_)_zp6&LYNYH&cuYQ0Su!sl{kdALv`^xYov7r zdm0uEEsz*b`JQ5cz(mAEENZE9BA#u3jZXFwChR;j*1RF_bi2-6UB6XES5Wh1*NJw< zb(!;*rGqgdYoR^!L}_W^-8Yy!UOIRt#ECyrKz=B?)*`E`}ns}QwP*h*bT5qKJ& zAEe@t?e1Aj2XZzj5DO$7j4p;nud4-?5 zN~9mp5M6q6N?Cg&Ofx`Kg=RolwacZ#w9%tTIhVJY#d$T1Y|$9fL1ET=&``j*LDQkt z4fM~VRgp74dl;~2jR2fX|93*whX#fgz~N_8&5ks0KXH=w3P&w40Jopf1T;F-FXZU9rFN) z`F+6U_?7v!L)lZ!smlos@uIqIsNH^pH%3veJ7Efg8S~CxT{B;B!Ng0ivccTgza-Yb z*FGPu-MuA1=rZg;^9O1kNWZPU;v(KfE@LccvK)qM!i;mj^${p*$L*~#TZ=M-c?<5d zx$Vc(s4H4O>imASzRSrb*&EBNH^Q;E-^C2kGEcTo{o(I6A+~X1H_VjgYs0Nt`OM!q zT7|w+C4`w|BCmL=%a)5aS>Fkde$u3TGkj4c{c6T0oR>Sn%1U@sv7cPSlmAd7M6;MiH$Yk zMqE_GAE1PP_%jf8l#Y=n6WgV0J-inN)XN=(`A8Ptb&T{Q_}D=w}NJyT+R+}&=e zMa=|S=GsSWUXNn3#43#{3%=|=bnbo?!#ZdVDJ}+LkZ|0Xi&rQPA!ci&&Tp zM!Z~-Tiyp4R}I44P)s}0Y;MGWl8ka5Z%ZPZ&?{}Am`LkEyCT3?J3LII_km-HFqCBnN~k#)8KP16XdT<^*C_Gpg#v5D)BpVwW(-}NT;b35 z;GtP3ZejZ!^gpqvOeNY!0mxm6e_i_X{%z?mW9(>VWAt~pWTEnZ;c=9jE}S)lwS?c% zsOFNQMSu_mAdsZREervSfb1aWHX3u&G~?cG(zG9Wq0xK*Mu1Bbw%LWB=ueZWjn1cy zXoq@0M81IOfrX=q(jHi?xTg39GGa$FSm*oXMIw<&ORpJaF)>c+S*bQPEmNIi!-N~7 zy3*O)o@Lo$kEO4>Xz{>^5Ns|JZ74O?mHnAf`y;d7R&@{y0iaIa)4k2Xt6{i94dQ|s z>MVlv|5#1VvtQXj?Pc4xiXkoM#Ny_;dEjQl+RggiGebTYEaQe?uR&^9c+=G}9o@3N zGw0CU*OR=Zc*`%zq9XM>SGX0##3HxKj|?7D6>3uhPP0o(HA}1tTTC!WN(Y7>{@iIS zzg-UcvM=Tf8V`(H`B!C9OrzBxgC`=r|9ptYdV-S^*0Cq zF+KirLzSQC+#}IUgpa>>3*75YN{Sr-E-5|11>nDg7Q><4MCkA0qt0!pVI0xJT;r@? z_rmN4TFW3m1}|W~(d9v zvHJ<{&aN>?lihF0pwc6in#^Vc>9rIlk{A&b2FoP@SOGb~2r-n#8f;EsS%&Tfwu!Ro z);Z!Jq}s#>4Y;w9W=tdc3}mTATECh3dY@g*ID`2=5&kfu0m`paN zO4=)!nbXN{3pvGRT5433ZaQ{|iPT%*dNHJF0WMN%?gVhhCvwDgq2QAF_l`f;_fcPU zr||2?wwn62Z0rlnK1bPk$CUyXzA$LS`@as|wxGZ)zW`Bf`PYj4S9vj6VWIyyyCy3A z{`C*?*Jd(}B~rGX^Za_MOs09QBB#U=#$;0uA#8>T@ylK6XMMyKX@U8NrmX&VP<|hL z$qtEeoL@m#*-uxU*I5qNyva}h-tU)YXKuuWB*fsTIZIqC@*~K(vi4HL!ekMZL=pwo ztz6o)E|=JZHXntS_kdjB0$6W0(Succ^2Gz@EV_SnW~b2pj1m!7jVEm1m7rfU8cA8? z1uHy!0_pd=l$gcCy$r7ze*#CLTHBU_uXbBCVB6!3P)6%3&k=u`$CBC zXvs%v`Aj&MeADEi%&XKJ!L5traS(;;to=GzjK^Sw#k4fo*L1b(T=DEteWZl5|HgUY zS}D`@zzwmOA>qqESRnenk^rG@`2jO5`F2j0Eu&XiqjNu6Q0&6B)@U%n?wk?Y$|vh2 zfp^%)SLHj`AF3sog&S>=O`kxgpf#0%h|ns=jt&$D@3wHgpfFBquQ6+hfyCbyV$=>I z2@x$us`ILC8FXYoZh0J&S##4gi;m!CGvK4MVg@bPQW8mit?CG2+T_=$Oh!Phi@?+q znM4lKQ#fcR3#VXIGkSYq8bc(A?8s?2Q0f_R3#U=r3Dxpl8N2lo6?SmtdXUX=CP{W4 zVU3jB$ZF-4nR=fftMKUDt}=~VBs7H*M-BcfRC}_074xo76k7cs^|ND;SR-FPueT^` z>=eTix80M8C!R409?#(aBvk8;=U!|;=-K@>p^E%1q5h-wAz)x&Z|rRT4~T?B*xtrg z#M0Ob;1Bu#`SX9>SPK<5W&Z*2%DRltIe}I*x?{_I5&~-dx~#{xLes2q&seaJVAcbeaLx&*i9)WQjm~s0o4CIG zM}q=yVZay|L+;q<^c2%6q36-)m#Voz?4{7OregmTyU2Os@+dBBL`AY&d(|fZ~P&J^I=#Ax_QE~*DQ8yTw|`@iLZ1r-6A+8>e{D2{|8HVZM&I>+ z4@HH4X7bOb&c`)-V1sbIQXc}m#>XGjWO}4UZDLW>yWr2?)C*PR!bAlky4WbLj-Qi@C6!Mk*{?Sls= z{Z`%j27RkPfKIkS)m7?Ufy;|(he#;QMd;OQqJbLQGhK@=S*9H8Im(jHthy5Nw?bnd zPEY~Kjzy1`1-s_2YQ~87$^fJQOL@pbCp_i(&e1TTMF6U>_JRU*j&~xwtjEW<98B?K zUV*_DR^&U{QHY|#aEI@Ci+)Z(I?UmhQb6y!+Bb`7abDkHZ6FQd{ZU|D>g>?W3GPv-WI!?9&-L)+ zMKY%B_3;%dbKx$VlD3762$MoPd!9?!P{z$8y#~fxN2EyXSJh^mvxlQ}@jobx9Myr9g5&L*QnIJefx9Ko{L4I`3hJp(NXev_Iqhp`M>UW(d6-ph6qcDKaiol1^j~ zgAS`2s(p8+`#5G;X^j`6tMjlKs;inp zH@y=vUKc`*<}id6#KKXHbnRd4!{!ZnB#KYvV1a7{N4qPgz$iP6-mWuWHv;H~`ZJ=5OtlcVYQb{w}? z3{o)}=fLnNsV?;=z$qbBT%VYbT3r@PiK!Iy9QmK3_yH{}uK<{Ml>y)1|32{w{NE&^ z|1@X+?fa`#UI!FJ6rEyR42&XeDi;b>VH$KyVG#4&umCa{tRD;*1IhFD6hcMJla7)z zrrm48WrjG(nQ83ofTlOK=Gh~acY6~5P>yV8p z{nJ=v^rta8Cx30NbMT~ z;h@sCXa4*UOFqfMAF6d5}@pqD{=i+Wu^Q& z+NNfmV-YBS&Frw&WiYNz2Vlg#}&8mtChEM+OV?fbyB}$}##mgq|pu z3iLy0*o!VLXCK(wGZEdynx%tAM&$z?2K|t?cC?5lGHVDqHffXs0tvNS&)*^YCtykP ziG18qkweBpN>c_}!kncU2dZ{66kmS+vQQnkbhzwR5@gnx*@l#p+_VYPHfv(XtuvHa zXZtM$L|ksFd^DdhG4R^YHRwZY*q4+6tSo?XYMQqd><{E0)H0P zF@IUS*=h}+&!zGH+8-9DXZQxl*XE`gq|i(G{e=FuEB_Dlf$!&Z47~hdf4N*%vFNK! zvC4NgpimJ+J;sKb;uHPpoLY01*pAkN>?uI24Q!Tw(hxqQAZjN}L3N^i5%M-%KsFlb zKv8*_L(S3>e1^-?o!)(Mw z>gmJ38&A*onire)yaWEMFyy7#1Fh%Dka|)7IMr3rIGt*<-R%il6F|=8C`}&ILu+i} zxG`kOf8;o^A7x)RcEEDLx4(4$PrT`3?Jrejf)HbyK8;v)wq zvQHI*L-$U@!$l2jP%=tH?AN7E-?Iv5N1`f)pY6P9dcTk#J3v|{EW?OuC7@GZDUorLBn-sk-@Y{d` zIYR74FO6e)mU3&Gd;35dhIZ9QEYsAqeb$3puxji3J#UZnNcIA14|e%d z?F)~totFJZBLwHWi|zyCFDL$#qv7g1d_)0Bop1RGZT{8)+w^gk)%8zt9~9X_OQtcb zZhj$&oC5d#=A~5OKnXu097)W+`5Wzk4HtVDV+>);h*-cl#bOlcAU&M9t9yZB8_DPvju zfUtz(hGL5#CzPFoii~_@b^)LF<^>d$~hfx z3{YfqnUc16gS`F=X?A)OYI6jHy47D>0J{H+GV-4xN>$1R8{qI{&68D2KF?BZj%6z@ z`TcozAeWY|*DZ!i!tRVK*KHR;a`w zP|#o;EEE@sKX-SdRw!MpP}%Y*3*g3}ikM-RRAqTUg9S45!Vt)zw&pWQAbHs@4kuKbv+ULdtx|eIzoYl9S|{ zqJVOkNaQrDb5(DO%%=PFAQN;NFw(5)bJd9jNz%@Nn+bt*1*vh`bGP)}ff^Nxs1&a3 zOCW`6v-056^SFIv50tr^k&_umgD}Dr3iZ|+)di+-_Z6ChDf+;0)aBiRrV9Qh>M?>x zOt*eKJ=>S>%rJr#F^iZ{qP0c|WKg8THB7|) z7^uFUwDjj1c-OuVBLf5#fflpo;hKz^wXn=QMjC72koiXOndKw3g%+MhVvum>&}(6> z?9><9!0w-t@)}+%s6YsQSeyaCT_^Xy zGF%7{v(yEIc>=D9uG0yDk=}2=HH!5Ur@L+~IdHW;psd*4Q{mRs7t3feH=FQ zbTnVR;MLoXSffE_=%ip*LoMa&NhwClUJE~6_wZ5Dh!J;RI^-^0k2n1T~v-%`E-SCD!CE+ zS|!=AtZcRsqIeL2wAS)?M2B{U*fOP6OljDaM(8XR8Sl4V;!^FlNp(WqwOlJBydiSh6 zD0vn-K{Q07QJI$ZIUP?wW)g`2e(76hAp)D^vT`WGpwrf#nK6I1lAUBkO7An0WS_nZ;m11vUEl-Oryy{Q<=ROlt}$`?bg3V@3ar!xT9K#puk_Bt@=1?!(+0?LUyOhus^>fvLwNp`g2}1g7qKEkdSOhHP+D9bI**dXK0sH zDnXH>VJb9Ba;qTytu*vcp_F0?B$;rRMT|!I0fpFzkyFJKonaUT<6J9z+^bZ1O>0wSYh*oSa6MF-X z%#yg(~5n?MmMO&7n0o zlsl!^a_zR`_3FRcOUgG2AVAHP`)keptM9}A99@wL;}+{bPWmI*bAK-i$`FKm|KO)Om{Jcg@K6A8z~?&7axnem z<9i3Xfh@$av^3S%7sG9bd&Ie5R!78#2okKHCf|T|JMf@Q1&RGVrWbt>9pi1%1)@MO zjj@%Ct{{5slkGN&>Ox&}_mNRQnuFr3g~ zH@*MvVh5SOMpZ*)^Zf!_XSc6knzV)hY_ZvFvIraueQ6tMfCS^uPVn-jB8D>jB8K1Q zW##5*nND2MA|Gih+6$C^U0j78KzpfGg zs$u<~5cn^f77|5(+pe6orQ84OMxU544v?Wh8S3VywK5M@LmdDQ3y}{~6c$DSsTC9i zA^ao0uvoZ}(0e*zWD>U5m&pw<*lcy!6-0&=K;C>4!<^29Yiv;JW#N7LXa_V~FAs0) z@Zb7V!t*f=BhC6IDTekT^l5z2HsX$&SdizWB^|`lD9wusTd@Z_De4q9Od(KP250JO zCS6>MPAuF_VzrQAVkIVLHYkIP$}Ft(G6^$S*#misF!%IpYX~n?x^m~G?RzKeyfW9* zaNgqeU8Ec^kfK4hwVCcWMcfLxY%uz!&Nl2oXrt&-oca1`v(}L?Hz%U4O=+&$`q-Gp z3!PKfqiQ^;2}qa^Ryc!#GU!@l@)J;!M^b~vS^M1xoH5tDKDgNbq!vb6#X69KWzB4v z+Oul3kIXoJQ$Kc(y=T8jSW98h_HYqtfw3y}4Xc?+Scpre_7Zpk-9%ck*)$a+_HIlmx*+NCnS=}=&z=3qN;>y52j(hYpm&&RKr}E# zSVP(mr|Ts2v=lmgp|63fMv5)_Yu+fS$VLI$}>FKD<7+rn7n9#APavN zdr`9{LsWHtt^5b)sXN@@FI;zAag2e)Fkq+;;#HfDyUjvgV;h4m_B!%@8t5a7RtoYD zfDKaPWKr(ySQx-!^14e;aN7e{bx+2AfO`Xg%e{*{s&L78iDQ1R@|b z;0gqS>l+vZJgm5HrGx~K(LOv$7czA%tFZ0t2+AO+DA|Ccd|Ai}7QPP#3#2GwgWrP+ zej~hAWn*P`_XqXo@5`^JYIrV(t1Gf}OE&qDEsrBl2a}_TROaJ}tMhIC-%#I%_USKT zB26%9nKUo;1XJGBDXG1!*Q-;<4bI?`)G~6x6lBA8-zvp zqqq*kjdG|D5%Tot2P@-@RemzT?YorW;=sV08iDYO{^=i$9=|NGM{yX1iaK(^;vb^m zQ0=vImL84(nHZn}tw)`RWmFsD;f@-HgpyUZMPim#wGH!o*~lo{VF4|^qk&%Oz`!Kzs@u2h5FDb`@XYmdNGTQXHNccY$r#T+wp;dOD^VW8U(v^VJN~9S7|jHVelyYw zl|<9ep#oJUZ(HcM%+M&=y9iaK zU`wk+2f9qDUYV0lDbtGu`m0r=I7h7a0ZMl~L9N#v)C=l0)k5CZ-w((d40Qq3QrVVR zDILX9(Y7AATmOs;v|8;3478cSDc?^Eb)#rUMtZYihZf3O%@$m#naVZYj~lfkvy>a9 zL#ekNr6ax61LZw8qW!`ae{1~S3+hUBhu8W_!M57(X}krVP`~!bp8npAo!*v}prnv5 z8;#;mo1Xx!xSoWF!fsw1tH>QRI;UmYuI zVqhZafcn@sf_r*R^{xgZMqjXj%@93mUG>#f{k$m9!oy5llPe1CtyO&ijFys`xPgRf zO6m&DmIC|9JyK&*)Pfw#&R_Y|)e29pcV@uM2w;=6wA7UJ+VXW|JVXOrg=waVNAL?p ztytQNPMT@UKe^q!H2tNP8-3_2Cw^*`gQ8)gOxow8<)HO_6AD~DET2SR z6QjE?8cdsop|snPNJ-@kmNroGRdj7Y{p&*c^2=uDI&Ule!tuq%Z;pkvPZ_Mj+T<+oKr6tO_UpUgmN)x-8L8M2H427YE5dJil6Ae{81lx z6~4%pxvEvq%5TBXJT&r4(QByK2NBF*5r*6%8NHni8kXF((nFguh!yDj|X9 zGcHRuVG*VhkGC(N-Z0>vv79^Mjn$kQ7qCyyq?6wt1pvr_^4l!Luxe2dGDkb1s${y(MQj&ESNQYHUfTF9NMa`qDI3rnE zjl^v}Fbg4|+!X1{9Af1;Szxog;ddQ{T|)}fEOTZdgxrzCW~$p55oSEyQ-cdyI~EYr zdiucNK+5WzVKU^vw05iIoRp)-$=`CZT5|4=4n< zn7~*Z!%3M6x)Im8%y&7Cohsq_!y7e`@K&UoKqFM7VI(N#JsaI|ALdgl;wL}y3JHwv z@qRkwtDEnAlvC!PXeN)W%$7sDhlg(!Z5i^uM!bb!8l@Jn5=NYPBP72)w0??aw-=OZ zBA-iS*uw?}W$UmuKzsZszqMF&&x$<>m4OBQp--?wv^B0e6sAxvx87j8`Fa9T1Q$2J z#yTTuqBF-LtvN5eHmpgxqsuqPvTpmh)_fmOvWl5#d#3#h+<(Oc0c()jmys?0=X9^)i>;5 zWvsGZ4VDU+EXjwZ&)+|3%I;hoJyEussCEm}B@I4> zQ`fk)xKm(AS;ILcKXHiI;0c)^At|z{Tq#l~L$@A}4dsIRQy{EZZFSJ}Ry$!-bS(Ck z74>&ewUTW2Nk;x2_A{9ki(wR1*B~_C*y-ah0Y+*r$x~@ZXZ$27wxJOPi2lexv}2I! zpCpiw?HcBU<-~mk31H5OoGfnnCo=4?K8i4p-$DjLfWxA zR~+Q@jo-4%SF_d(?mOHadR`2sPM|yfJ`w%353LD@Zgb!h#VUP9K zF*Tzmp^=)j0DWLEGAe8mG~m8phbOidP8SH~oZA3Mc?7~MMhhRYBvk;}HwA9={uI8? z-|}UNw=>!WsdFHE$2scpFzAYh{aA32U(trS?rHCvGuY#x=}>~X?x*h|(ZrV@mv+dZ zqGbu*&*hxJOQO8UOyi7zk!t%yI4}aZ=Q@9__7@82Sq1H;_D}o@ZWdJZj)}MNljd&i6G+aHZh-^pF zXEWl?tVMhTl=qOeLbUOU;4P(TdBYt?U%~zsB1y1lW0K`R04H80*;N4x*0lgcsUk7O zhM}ytt8u6$^HN8-y#(hEeL>lTa;{%W$voJ!8N{;aNh;zUH@V#NY>HU_ZOdmP7-SE1 z0gV`5fIpa2WH<0v*Gy6#NhBu-D@iyAuZW>&m@5#5P&Sah=-fO_DsGZ0Mjd{J2JTLY zfq@w|40A_{Ob{k*a3C=y&rAkAbbR`)r7)#)Ksx1^Qs0(&-_tkFdrZ-6?N{jwp9QM= z{w=8f7sfnT(Yln%CC^q&_W0F(d|yX*ncpaMrm80P_Ra0_Iwo77lu(mX`gSW06egoH z<9Aj?F&aU&lPR<2h~ty22T|c8s3s(<=K=4HIv2io3yB^OmX>IqYt2*~sFh{IC;?Qt zVrKH{SGYK^Rt!{bj?@LWl93X4wT23w2h%&3h1Bc6gv66fo$*VgSN z7$HXNI8Y9yAHN%jKLs>)ux)!>Q1rL^DGu0L^;~%hi=WV;4Ru9kKcYhBP{T=-; zfbJp*zjHY!-p^dvEC+w2JTBx#cqdx>p!J)N+mRKzJB3~uaeyOgtZO{tb+ z=0#Ko*8KUyV~s>JTX7r)?lfQ|1Py}{H;`X3tG18gRANjuSRjZ|v3`V?Z6pCs3BZ;6 zQc4udMc{V8}VGl#22Uh47i|DviIiJ6QP!- zmFGB>6XH5^fU<#>Wi8NgSgE1eojO$nd#a`SDY;fYIpdgfGE$T`X`ienhp->J+ z^!(m7RJ$HK=+GMntXdxq)WhN4X2_G0>m($uX)s}C(z6}IF0$TWu^s{*C^;XjISDbk zT#vFR8q_VsM87jdf4qD+?oO}L&ft8`K4uHzPhYKDm6br7K5HImk6WCK9`+qhPwcHh z7l}7|^Yah5uA%4|L2P3L?=a$EhgU1aLpTJ)tmDRnlzXR!egZ#~$k9VnS_Ej-} zzhJ+FyxvM5*!OC8sY(iJf8GVuNhez-T zodh9f2ClH4qfrw_mCRc{hikzhhx@{m(D$y^{ToKvZhtj&feu-)9E!$&?(9uN3JS(F^Lm-m_^MvCF9P0*t7YO28jK8hhd+lD>%3+e4 z&?-)WfL=UUzj566Ajy8ch6E^$IfymYe7zTkOX)+DW%;47FgX_s2wMBFi(<6zv)83=W=BdzkQ$+cq#MTu3S>-0)`ZP zi`X}jE09^JZJcQ_>!{rA$`Z7%}9 z5xD%*t1F2sR?#b$xc3@N!!vM>wn^E#-%k2W1b?` zpIHr@{Y$1L>$-}4j<<|j2>jTTmF3k+LKwP*n8f{4*?1EMF0+IL;gSgHWd_Vx8#OoEory6c;^xDJ#SA- zLgNgJ>qc$1(*yQ!w9%Hi!e2-pw)jVWS$$AcH5U%>Ib-(KTB3Y3(9JHLS&tz?&Ue0$ zpFi>odPK+8WfU1Lla_iP=Ga;UxWwJwKv$@|AlN0oe9~q7_1evuE*NNo)}>)<<{f!A z^w;2A(%|}aiso&bPYqj!?`bcX#%*m#hF4{_LnELE+@Lols%j}IsiAzb zLAKh-he{6WhBQ(g2x@|81uDk0{}4tNNLa(`Bjd!Fl8}Q#4?evw?RbWMom12ORUD{k z>ba2mS<0SqPy8=|^_j+xKV9$?rg( z$US-x#f&Jz$W^b5ID0%uJ!S}o81Qx}W_=`8tol&%7AcT~fxZY;hN`J8h&?j=b3jId zErFc;N1&dnvy3!K1U#K(HYcNg)<<#X!)z1U_;PQs^R{3hn%q~a*)CI%uECYYl(vp* z48|5-RuXHNUZn(yywv6BM~>_AZ(%d%2a$0S~DPq`mpU3sgcU@sQfMtp{GFYUdtW8cYG-W2PPuH3aR)4ki^EfJN zQJ_X1G$fAC_MQZ>WOh+?t1YXknhhII*dDCucU99@j#UWJXTf$75Wx5%AMQI1Q;?8D z3b@dq4|%;1(Bg_bk2^rQE)X<>$aWbxIZ{*Wbh)ljpwju)Uw_jjI8YZF%wtJrPUTM@LVG}R?I{+hiD3Y@Bx=$HFi&2SVkw$41th{5L*Sh+$Uup1=A!8*h>F#%2zu5I#G{>4L ztCJO_Ytj)^tCt4f6KLj#{1EFfdL8v&uvvbS|+u$#ozt8hM=?$C=aY(tfWzJ9e!WA>{;7F6?>37{@jJkEWwz}gJ4ey~p zQ7LB-iL7NC^7Mo!uX-LsU;H#`QK|H_D5OZ;{~iHViDGEB%OMm&nYBSc$(~xuvNw{G%#Q@dIL!Xcc1`nV375t$`FQFG z;QR4D(EP`=D?ThxglR_VPhLpuqksw5RAMy96LBw!tGO4j#OKiMOjNYW?BpVwU{#h_ ztz%3CuHyE7U7JvPa)>H}SJ+$i=f5O|WIT;eJ;3pq3i5AhOzLlGOwrg9;8x^ptZe?@ zp$;TM`i5r4M*n=|;HYn9`yYg(Vy`uTZS95K&I(yX2_#J!*dR|3NpbY8n203gn}Uds znYb@0ut}mazWH32{^# zhKa3sNs}i`zqO<6<6l-_&AG(A^45~1S&?A4`kEc_5aY$|JmwC>m)`uRCfxSoi?Cap zhzjR9*k7fJeJn_PI8aosa|>i}ZWiNx!ox1F`WA02RGySbS);WzJLvJ+Lglp#D3y4- zjc{aWm`Oz(t{i6%0jugBQm_=apYr^L(){8|xp_$@>Kt(5PFn6pZF{v1SE`>&>$Ky$ z`y^GbH@1CZh@|l4d{w(`!Pqd-pW((qFa9RkF0Xk~TbXH{WqNJUX^7L6OdAz4tq1#) z+aJYIr?FEr*q~4)D-!a`wf!T^5nu=N?qSY0J3WQJTR%}NbT@@^ySl)Sm2^3h`!8;( zHP?k}WLlRgluS~6K>B&6zPTA0tK(@92Jh8#G}GTj-6WBhEb-^x>=GX>QQCI(Y&yGS zZW3E$U~r*`4ItnvLVK5k-peciXAA=*7i|emHAry8vuD30*l3VSDj)5JUJB_f>OQMTw>!RI9Km=s@pIIDPu5NtMv^T)Je%e zHH@_pgyfBMjbU1ni8^U1l+3;f{X9#kULEe+G;|q#mDUJvm2D|b=frlSNZnltCJ=Pm zb)<0^T2aT~-fa6n86d{A>D@e3mv%1e8`N{MBMh8^igd&+A(!i*M^7SqQHyD4hRJ+0@md`3y@qL1{q$GOj!F_L zg_kH%C>%S-tYR$%)w$QU$?-HAZE+=TI%pEWReYpif?|IY7{~|KYtlJzcV9Bxe}<-* z4Gs#|z#Lj}0(xy5^*Z)fr^VEmlm-6Nc&h@Deq0*Him&8e1D^q{B?JNT{)@;Tq=LzQ zrdXsUu)B%=}l+G znD^gaS;cKm0Z{)OakT|(A(yzdHSgFMrwd>qagGP+AUa~?2doxr8ze0EdNvIhyXby) zA=U!OG*t|BcoUL1K}Lby4G__8GxJED;l8XnkT^tcpcAGK{^SOC zT_!+8AZEyhg1Hll6()u8-OpnUeFMX;nNJ|~%5?~EmP7o!$1av-ccSDEXm3%A=LmR< ze1}ItPq5n`mR~j)mcM_7{D1iR#wba%rrWNnF59l^vTfV8ZQJOwZQHi(>auOyM&Fv5 z_x--R?wy%j`K*6U{zFsKO>iMkz|zy7MZ~IC76|J)Kq(?V z+GlH`aV=z*Bai_yEi(tZ-^tju2JHT+o`Iw4;xOq%LXnKI; zLN6!Znx}vNIod&>H)k;S1zaotEBE`qj^!vA**O_m8yHDDS?T|iP)Xr`rf#dhrfw^x zIWq5DEEWpusRa_~I6&$pmq~?8Q$v1s8da+aKWae zS&|-Yo>Rr*rG;3RSGUvQcMT;%pxW8FKL+2dR-#$K>Are@+{ELi*S{OrO)KocN24)U*d=;zuTUMdec!-LPsgNSD3Eu^6ofdECS6h(s93gqV)URla08b{5g<3S{Ev{i!v`n9iA8h z%2H@p9zI&uMD=5sY}gYOElbLZ$Ku12p+Aqwn+EX{Anp2npKONc)-VC;0bH}utY0W_ zQy@zlx-o6gN!?4;Qe^!i|z-V{U?{*N#sN^eglbFp6Blutg)Y74G@*hh^-tvfA%E}KvJB*eYu|I zzqY3RE60$csr^?k(my0O|Ch^6WH>uW7gsf!&s8#0kdkBjt1+Vm;5SGPbZ@RMG3HD0 zr!7_=ATi7SL2*5h&NyCc{Ji()r1z%7)Yqi<-qF(4wAZD0v5ET6q9mb1Lbz2gH}VYX1xYg=&B0d|j@Go@=BO z-^hj_F&)S2NWFiXC&_T<3m}6k?C#N%1#+3X3z$1=fwEZInKgE9>sQrmypVpcVyzKa zSd1sB3gl&6I8TiDLCxrrd_Fdvc@)OyuBPsTdsNuUR*B;odK+pX+1JV3Bx9{ z4tc#BtrAHIsMRKBD_h_N@PyI)GhNen5>&1|_^;DL;+D(`;g=hR{i_=a{M!Nb%MEQ@ z^zOCDdL{|%PC;YZ&n)k_yY-k5=&Fq_$ZrGZ1~H+ve1*gm4*6 z%7whi?WHZPwfGlxUGl{w$~ENfUSiGAE?rmWF>8PyR-%PG-uP80CyGFW?0qV$a9|(=m=};F|2fP5=|N*31~Qnp7Hq zM>6C>IqgO1Q+MT20Tb(#!)ub;0S}U1>htv;$x-GND~`~zo5qjMrny--GupkYJ4k6*23>zn?LKoyKzovr#P$I-Crj-VY@$+5>eiWFc)Y} zuUKTOyD%c>#`&l|NA-13I(arDp-s7Nb@@G4G^zl4ciUh>WN=kCfGDM+B1`PywEEw7i5>~94Zg&?GYMXm>b_O+2_cx! zN^XH|4wK4{+_ud6M`0blXxL@VT*WSN4s&-1A<+-4wS043pyEuJD8~0BdL=H3t5aSHv-c=wnu9UnKA2 z5tbQ|=WK^i#p|p=SblUJ$s*MIo$o>KNrXxSe3TOS+>%Nz4=Oq;N-E9wM_aHzfou_Y z0&eI*`a<+&`(uI}II&>*qwnxEO?_ce)jBr(2&o%&zvokK&d@IUferPyL{M;w)0y)N zqH7{Up<*9@Jd65-8a!V0)SHa1CopO-aSD!BRUv6|Sj(HgT# zT=IA@_15;+FU-_PK7h(PVp^1HC&w^hd?Ta!pj2!%g(8mSM#u~cdB(lvs1@c|XxqU(wyMswRl4ri3w=;m0~2o)mk zfjr&j?=cZBF5Qeqj=^4oN`BK`{4E-^Il7 z3cq4KyaH}>-p~W|aL)4Uxe2=D@a$JRkWLsAu!6rTbIF76yPly~V`^z#&FX7n5@qb_ zA4nb(i9(X-NNTv`#;YziSt)jhq=#0jYRj zkx$tq6rItQTX@KDvSOD~S6~r$&!SQ8Gz=jSoP>1m5>&cJmKbm@g0W3@G9{^+Il145 zU{N@bzv9fW*ZpoyY>Q4}ORIf!BYIl(OMUYqnzO&?0Z^!|8{|EqltsH;1^bddBZY`= z3LTi~>@+Y>Wohgnt>AcP1QM$RHMLn8+=AMK!mAZQ+0DB0E}z4?O4XUq1$u112BRbD zVcY+JKuSkk-rqIVgwq3guU0r>ZD!zJCDV_ycrh8%=xx2obYzWoaD!dNNWnqjWRy*i zXCAP6y4o4h%-u{3Cs)m{;RiNrE%;4%vuA?gG=uXFnwT2MHmf!P6&y+X5oOYGF^6DN z@W#^&s+C2X6ZXo2u@)`-f(j|dk?;CZuP62`eu5A#$c^A&ldNmY?5fWgOAmdwYTqj$}U_B zH{aewFN&)fP=282Uw!kUnSGMKB8J&K>w2Qx(`$%3&*wx;xDj*QMMA!y`t<;%HZ^Mr zc4P;$M|flhFxDa(?H#xI3eVZopi+unHpE$*$xFisyCGu9xBD83CNuLhL!iZf$!wow z^NR!X)r_Z1r?83B9kIBy4d7ke<4M6%s)1+N6@{yyzX1g=>r(fw`w!HjYo&kJ@arTM z_^;)@ztsi&Zvd113$<|jn<$p3{N{l8$E0VvJVY{7+25H!{vS&B2XSn*$?;;u$45!BtldO9`w{f?1a* zx!y7zx*aYJu55mKJ#qO&KF>xw-!J6j0zH7~R|llv;@pdcyv1DS!}wFiQ9i!ZWIw>Y zeF@+32m`YE_*2SzR}A1ed-(*zf?UJFfZBc+Q6ohV1~TPK>&D*8BHv+cH&l(Noqk6f z2EQ~?+gClNghFvcfvu-iQ$?@@M?@e7es`N2DKDxlP3p;8ZlNy~B(|i&45fG};oWeS zS~|}JZ2anU2asvDlQhaGDh~}^FENLq$XBal9Exa&!<#GEYk#Y(9X=2t z8T9T!9Ln490YZz^F?>M&bk=6>Y=S&yFHceVq7Eu#3p-&0K}q$xE`u`2%u3YSLwjPZ zY=Vwxoc3JRibwv52fA5qH%mcI-3OATEKI^I%1X9})JM+_hoWkqDTAvNMGD!VT-oIV z=8!;!UVQUK(O?%O$zjMDR8NmHj1Dd{;u`m$K%X_lK%Zr_?%bqUPV&+3#hJts9{>drX8r{q%WRnUz6F|_t;Q|)2 zE#AmPC@=S#Ew;FP7K@wcQ3(GiIYQw3ccFC@N?29vQr7YUHLlhUsYdgWgiU;jLo*aD z+sIyEV(RdzR^=c?k6hT)JfZ~b2pI}2NnazP>pY+}RcoR$#n11^abdX}Wl?BXN}=vQ ztd5)VPLdeRt7M_INpX8c622%@cZp9QFD0OGjw-cUv`vXdPcgnL15>OkY=l)BLml;* zwFF6#vV|?ngJea|tDP`YM_=^4)a8xzt4m|oC4RMr8v;>3rLdP8pMaDNjK2)IAn)v! z8Ihqc9I$d4m;I^*6mhZ4*nex+;jvC(3xxgdP+?D@;wQ54i^SPw4uaiCl;bfj9rfjr_8Rr$TfeGXeA*Nx}wNMn&UhFy!mr9FKn**>0Gp*VSq5l zD7ENVu3E^nO34dIql&4f04(t~F+Y&i{k&TAx4}05SZbVfTM{$hiI#G>Gnu}HSe#A> z8FQ4)XQlZlEa99niMEBee&pTc9x!=E4Txau3woGd8GA&}fvV7!${)@b%YNFHg~40Q zw{4gL$9{e#@e{_bCvW8ZmPC&OoiV6SP4G!g+%WLmk~itJqS_jn5Z1#mEEY3iAYlNS z5MGh1Y?LT1A$OX-QRtMZLI&%NEa2mMrM!6#FcW^CS{fzwlG`E;tWGKY_QDN|F>kjo zbmhpF&Sy7gN)`JxED9PAkna^m*iK{3Es671^U4bCnX4G)7NwQ>P28N}O=H-}s0n7M zRC`{kQP%3a8-`bf_m8?XueL})q6EU-GyY4zkOtYw=QyeJ^LApNF{u>_Nt`C&c)glxt8!+e3USWVJ-&$xf) zt){urrLt*Z5$Aq3uL+>gU`=N=^%MF+^0#jjLllo=(cGR_eJ^1QsnIjeTh~?R6$kg# z#bNPJY8`+YjIHGvUuk$P{Ku8pXlw3^=KQEDa@*t(9C*;@#~kdymh|j(g%I_1i+(R> z^{Zw9VH!K=72D`AaZ_0_*w&iHY?U~l}s5q4yXY^sA~z3 z7si2Ny|3Xdf6phlY@EY60#Ek@ndqAnJ8mw${&@VT5LfYmIl#kLetSms6&l!)L_9TU z#ioZxhHO0Drr^2tj6>^vPG~>~j$kE%5vW0uo;Ec(WP@@aPZgzRA3x#BXmHXSQu4c@ zzD~)jI1d3qJ6FbRtkWc?Kpv7%U}4!%2-UNhdmoLck**&O!3{la-p!LBPJ_CaFo&?Q z*kMJ^DGAP01`9Yq z*bh3<;q?)Yb0{x#hhw6JT0-9?b7$~-`jBHSkU^z}w28~*Ts-7G5W`;`iS$j`LsgZS zmocEhV&ZTb)ANXm498{pFO}K)*z(mSpJpz`O!g(cQ!EG4nIC$}(I?a;FC<);ZA_hvL*mqdmpKrVm?=2NARP#6qaedvh5PE41#;U~A^}l~ zRXf!EN<&|yh_#j+!JG9m1CGA<0#I!gdn!tc;IkC?Hi$(0kyOEHcF|D1#QMJWhrCnm zc%;g`JSXE_qVpjf_-b)i=<0A+fxdKB>Rl>u5?guRlim|q_?xBxmuqTYrtv&EwjRQa zJ~QyE9WQtjLQfx9F?z_jk{`usU0jDx44HYYG6#bSdZx&hKCH{PQ+=C{7Nt;L%2;4`?UcU7RlXf#SFa0F}cP&45@Vnx!nM^_qB>PymwEB#2YQX`; ze`S1QkWaeT3TEYVd-z>>6)`W>l$Xdd9fzku4=jfCv%ARSfY!G*rny|04W-aa%3a72 z*vTrUJx&gZjNCU3%aZAiR5z-eT*HQxILk1RB7!=LYcxrD2xbWh!6t(lK@vmb^p|qd z-R!GqxcRX&f_?f2RF}=#d z#M)XOCVdM0nXbJK1%sbD?hZ%4$HqYL8Yhv{okONvvBEsS1zb9UpP_kOg303dFvF{-|ofNFFrtgYUCXw{Ra%xSJ?mn7hq6|#?q7k|sbm2}6jFaRd_>vdte(RK- zoSjB7857gQZ(DI@LP&;q;^GM|-(QQ9Z*wXXfXXKAg&ytk?vv!_)1KVd-a9I3xxn}N z^U}Wi`BIEww#25X@XiIt2O8X_&1ADgy2&e8DQ`K{#2be)x{&EDnvLv;?s6D4t6AeP z_wWOv7}itTB{7C;5_u9&&}U06xw#$dtynHMuFPLcr$=TU#Q{~8&QQ{P+6|n1$#U(_ zrc6quc~2&luGem6j;&$#(HC!KP){nd_NSX=!b_YOw88+cGg`iHNS>)*cYChRKxQ94 z+z(6vt5Yo))MOP);V@5IO2L)ea!kaH`a~`ZmixFfru6mEkP;vCY?bfAX;^dxUl3L; zx{}B)3n0Crg`Gm0@5WH)Jc}f-TBD1IO$i}I_lPIhjkg7?6in_mXtD)5ykJ%sDX(Vn z^_Y>>S4H;A5qJjAvL4QdN7WHpS!3Nv=S-8ii^v{QrWCLbN~Fl}5DCkw(Map^O`-k5 zhTKz4K+r%M)-Ps_A`+?S8|fYAbipcdggO(!GcAO{VGEu44Ecr#e&hce!ajB%C1jv8 zfYCaCLps0~bX4Qyh4aL;AiWwsGh6-maZB_!%CDbn-h(i+T0IKMk`!AP1JvRbz(4Z> zpKnPU?=OTYhC`DVIn}Wj_TYrM5J!sPP-R6aw}`jpc9-)2~%avf@RYV|HG~PR1J>XXk)4ohxc4>?~T+ zJf0xzd~SFEwW1KWS`fv3Xd-TG3k$6k_3oJsQur%e;E^zDoUg`uW=#w1-a< zytl^ug3`+y?~4gXd-q zeUO5zt?5TC8A0-qw&!#_hNITyX*}EByd?MV-Hf9&4N{wHO}S%@1kU;Gxs%eeLJbvN z<<#j-hPBb2z;1!9-h1AGG0iE6C<4Dax~*`eSlmm-?J5{}Q1&1hz5X>Bj#V-3!#kv_ySOiukRCjT)=#%IS2ufZ=gAOvq zd*~j-mz7V+M&t*}mSRhc5cIAKs%)$34}=tPN8m$i%39!eCbeU6bp^RQFAcG%N~9&O z@fULDHo$LXeuiEQpog$z%k9ntX6+;wd5JfT5~KbNEY_%*4R*6gAMIXJ9*^Kuf-w12`fF?t>s^)mQ(VQtwa7fB2df$1F_M)! zig&y`bMV5@z{ApB#nWC3inw8wypVn7t`R0npCf~|c3miil;SYrUod7WC8b$!J+LTG zssW}kvie!8Q`Fg%d$XVwXg}$D&%*k!OHL18#TCof-X*EE3zIvJks2!e@}S72ET#vf z*=;xqsZEiRr(?8{I8mrTKL-*Froef~Yr5OSiL^10BIX@)=N&^ElEA3-*1its5xwT^ z_0prv#ANXj$n?S%N{dFqMfZIr7iij_5Vs&{E?(xVn;Qy|;~Hf((kEeJuMP5U^W79p zRa*JQ`!-xEssckYhd`=PG-v}Yjxm7)Ue^H8jPz4 zg-$354n~*p^;`SPsw=abj^vDx>C|vi^$$lzG>uEJ&CbdG_7lel2z^D=yUgXWA3ph> zXCeeqdK^&(per^kAZX`5u+ih9oWxC{U86#aWwzrTsd_f@Jt3}B2Ts^HCZ2vAWzLq$ zohTZ@r{~|7;-PCriA5_~=5t+lYfTbGryY!%w5IE-3(xo#+~-8T%^!QzAZF)P2Xt?n zPhCPLzzLzZvAmS=+V;PqoX);bQCe~8*#g8(SOr^Ginh@ zty4+lR&Dp>RMl1cg)ra{3x}q~^_F-RC$*J#Rk^p`8mnajb(I@Uo{kCL` ze_+*|<)Y8LQ?_@=r)Vq;2iWh!%vvGNCZAr>`zhCV9aD4fT@>fcucn4>KliHjzRUdH zsBNJ0Q!ww4Nnpz_M-ezec)U(7a$Ro^A@Nrk`&OU554LVt(5!kznF$yVRDl%h0t6!M4C3qz0wWCam^Xi$Hy)=b z3<3+C{hsIeG2l0_AEEe>@$MK;`LXLK>6QI{e?Q*gxKuaafnXtpKTk_<3w)G}LR8#l zbogxo8NzQFE+#uZRkJiXQ8j5~BqvA@Y99NQvzAkW_B$VZ!9pyi9^q7*r5T~85>kn}0?=dOlzr&;)Y|Z`!kD~gg zTmF0W;d6BS0=WJ_$p1P71;*A&_tV0CiLMv=CM3xRz(G=s`k^n=8~KzX2oQlVv#DuOj8*UvKN&dbvD_eLj17fZ7H-z?$F`1>{Q3wUo7puE16KtC`W` zQKWX%O&d99hgV?)P6f|DSVZ44urE zNdvP5O!*~pFNQ`yAdPi-fAxG5608eLn7t%ssv=$+oIv)+-PfviRtv=^!{T_FwT!02Y zP!DWCHuT*;5&F?Tt`hM(s))`vBQxvMMbMz_X!Lq%dF?xUs*D~GB zo2lM#K$JQ-ncBIJcof2Buv%55> z9%;s}T**l^O^;EG;<23Ua*bZu#{*eS=}Qm%uAR;hdL=n6qRyeCv472x@a<*;Qb$<9Y6bM?hwBL8X zWW|s>LSO~1%2;v;rSx)#@^&*W9BX9|7kXogwZych8<@hvNoULu%n=ulnKxKypN^4N z9fs6$9U{wowd9uxyn#@1UlSsg+=WmI%OaFh*(I4ep@7_;fLG@?>Cr93Q$}ek zOe#)U{s4oQs*W=D6PQ=h{P?TKlnS$Dg?>hn-X`tW-jV2 zm(x@oOhM+E6FixdmZl9XUj(lZ3?=lcBjBb?$^(qSggd$=VRSYW#^nJXq;7Sg^l>q; z$W41m=|b7&m01NBVyCE#p@^B>YpJ57?k&TL#o}>`Kc#_7xrE+e$D(R3NEzSJv>AFy zmoItVA{)@F&gwbD)6$ifo6b`l2LmT|IEZAwbf^AfD(h+r^-lZ#&D0Sc%&{~2SpOEsgY{i zKS)88n8adqdzYlm$#6fSeqos$-?2}TrKmY-sJzBM>Sz(y2}$pitMqzYx`)!7&GX?g zwj~Rx5TF}1s$6hdV|$#ojv-)v*`Cql_~HfqSX;kkchkg(X-YdML2=wwGJ;O8^W}o;WG0cwLk_@B{P9JDOpIJ94M8Ba_d(oVE9T9nO{`a;EJ*&78f}{nYc;`$ zEV9aRfLzte#+7m$7b3k$6?JA%Ty}c1Q0ak8As!gPd6dvP*LlbBQt?zO!2BSr!xkGP zP~D{}s01c=`OJ<`+~C|^=9QB$|{S!kLOi-pzSRi}hFguaI3 zcE-1lb6IF%5GXaOeBji22e>!^ZW2%UxdK-$bMXLE8yTb{Pd~{VS>i(Ldu`6H17(a7 zk8C^jw!S^lM$+e_bEC@YadHIN&}U)x-<|U^Q!Z(&-#p8_XRm&OyvE5{J5U)-9JTZ} z#v#@W2wbFZeGqJp(pEukMT3)}vIiJV>fd-(L_oo)D%F%-WLA@Ewk6bC_X*66n~|AB z;x8+B0|kJpb~cToLu6Nfe`U0b4@S4R_%n==!KS%PeEEgQzs?`f{gZEqni<*a*&CR; z{V5+PY3AT)Wc^=Xv5Mk?=;K8SFfov1Ow>IAM(S;>iB-f86YAlw(TNxF4rw1F2C-*? zgx$^^5Uio=GS=np+Tqf90`(!{L2#O8Ki(Dimpl=T|9IeR$`8A+v3Qs)XfLu-A zg-kT~Yu+2x%j&1IF&buDS(rCUXM9^~%%hn!RJ?$=a0+cH52I*!9AT;uF?lcT)j2Br z!SBSwH|5>d7&;zpdI*VN-(G%?q={*NXvP(rdOYd1ey=~9pD6ul^6I{p3;M4Q%Rfe- z|7wx_(M|cE!;LDmr^bTQZ(Oz6_yZHmu~@`GJksoC<@4_tp)K!S{ zGk?b>@p!9rc+6Wfy!*)jyQ>Q4cMh|=Q0Lj&=?(USYa`ay;1kkAbl59N;o}syr;eSr zLNxC4sGFAD?>wB}WjoM~O9~j?$HVULqW#f{12PG_-7nV)xZXwAouxZRVGoeFpIVjO z2mL=uc|K=@bzZJ>V23?jM}qUY-_`qnnt#<(ej_}`hbGKq;-0Y3`|&P)F840~GNfc` zsAEYMD+sEBe+EGm%jaO$2m7@*s>*CJ^9fJDl7Ul0+|}zzk1hpW1YC7K;m2-~FSxpC zEJ7U1K)*iD^lL%a?tz{9Ff6=LK)8wpHGHdq3Naj0W8wq&4m*c_NOv~mNLk%N5nQ&g z^IKU??&FHOpvv}Q%$iyHZo)Y^drps&lMS3=Q?bH|CS~GTIME$rExUywLakwT>?rYU z>BWo`;L7>S%1nK=Ro7K0tX-!^|7KOzBlKDx*M>*_MkbdZk=Duh^si-8N^Z*v$)aH8 zE1gtqsfu&)VFR|y+;<^Fa)i<@L1tVDYqVVp!{#4`ZEmIX9$)X1rX9)GL)D*gXG}0Q zDM1dwx0@RBt$GB>A&?yw2&ID7nK`Ascxvn0X)7e_%OtkV#h@*23vN1=_1dViy769g zX_KuJj^!zM^CdYIJUpZ+EEY?VFTH$slAVe&Wy|DK&?I%l`sTzfG2%8OP`1L6$d~N>4-xbbrLY^k zx~YQ0;$soZSclbXkywtmT^G=gi%7_v^X|Nce6w6R&IgN~)Tn3~eHd4*} z*q|c|!-N6}MpFdlX2;TOoD!g`k&pe1h{jDR;ZLdrR3v%4A?4VYQYVW+GL8<|8^WU0 z5oK0SWEXRwkdS9R#4R`jY@AU0yuqUL@C#B~`&sMXyi_ zD|Wh_-eGZ20%$-qYo=e=6-?vlOu>!lPa>kQqRyUmIw}p|KG^k-m#(9tT+Fccz1Vk; zP3Y22q_hMz*_{oFqW}tjg=8w5a&O~bT4}Kyu%Y!1OI*Jp?hO?Ih0hXLB$PWV`T{o2!q72U# zE0rlqw?iJ!l1ll#-raUG+$q&~t0Qe>h!Ud<2&Zi1y9px&I-Fd8gC2>fVGWFL!XS9A z3nzSQ7_W0ryrUh*M;*`jPPFgOAZAR3|b0yK2JHY1UC^6>p7bjA$qj0T^V(DK* zaPl5H=uMW;z{(o0c*bUq%kPMw3krTFxrQnM%e1>m-MGZUxvam8W(W(^weAnh(BX=- z8ZebN;>;eU{e-wT}hXWYoE|5b0< zBy3K~GA=ynpJNTYM~x~4jTT%nN4DdcmCa&i;kMUbJ06r#xGBvue(R=kp5&MX*i~if zGQ7DNb>{jS+V|;1^cY=+dJKHhsfE1(VcNxGfoq{9(BL>i3a0o_;uO_*guQ<)B^GX( zjU1=%1)jRX@{J@2ork_Agr}&fzWp&5Bv?sc-)6qQ%qnfq+GE`yD$gB9q}%-4;Rudy zl;!*(TJtb~2jjWjG?oBbUYBl410?eMLrTx*?mKZ+J$L+LDYIS_Wr5}t{|5z0qCnP^ zzmEs#`gAFZ89R{8KCmf8(Ka_5%mwgC+@;+!{sbcFPaN;h#@4THi>#P8wI|+kmg5gb zZ#EdNeHi!Z21D|-24p-dz+|k!W0%# zMkyWP3#4D^fXEqeAqH-f-~B2NdT)bs)5n|)2>lM?QzTv~4=>pLWz%`~k5H5lQ@RQE zVdpgn*qE42_+k|-9H^=6Pc0|;nV19L5nIj~`$z=T(~n@T+6}Ihv(8~Ct+NK==o%am z=jt3(y`d6OoL=PM#QVQvK+=0_xMRg?SzT5O57p`ePGm^QZeS@VN$Dz$d^FN2HYnLb zDRC}Irc$VH@HL;wWeHACoFu+I2T|Y(Sk!Z6_IQ+O;Pl=aubI*xr57R8%pRV!;P|54 zH?_UAE$}^kud=sfi(2%WM3$L0sEXJ-HAq>*dd|!-0lcCjU*Dm&*iA>SmumF~P#Rks zJy0Du8?|RjyQ8R?&v0NoTAMMPTtG`++jkcJys$6EKrdo(Xo9;U`JfBh&V=fV&PV8u zR$q_&!R>4G48*vLqZ!B}NK(zr)shVEjH__yT{KLB-T}K!?HRTX`r-zbJuJr=X^=9| z&l=1#6z=++W>3x&cK8Mar$7Cf(%b)wbBO=lHLkgyu5|dw5TNUa-a5h9jga~+ky+2& zte=>=9e>q;*vSCdNuOD3R>wt340lE><~4HYp4v+E(f+rrWZ2z|^+21E&gUY|kmP+Z z?bx~JsEz=Y10zqBuE?vgGgm3^2;32w>$Z+SmVK-DX{8|C*7fJov1k@8hiiu=&-Xs1 z=w?mG8wwRf??{3B$?t#-7vHRVDnQ3IB`4g$gK_drfb63aq*_Y ze_U`xtjPr#?e<;8+Rvq5ZRaQ4O$*ap=4_3b>ZQzQ7Q9Ms4vTdTY*cEgqPXIhC6Jy{ zXGNsUleC0~C-L+%tcpc?xM8;kV_2&%^xd@~se_k9yq(cT<+!O^X?>g3dCwFkS$b8AwxO@*SK^TLtblKn=j(k1QeHXXnofw@(#W z#vA(d3_#NeN7sP1CsU@I)Nu3F8D?E044)pP@T{in#Ze0bP%}J z5<{IS$ceZ+@KUwC$dW3&M@})lqDH^I`ih_(RTyGRyV zp+p-vr2{n59$9(Jy-g2jaYR_K5NJcP65F0it7g!VFC|91Zo!S15kzj?jiaEAfilxpODp_r4sU6gGPJImIiF*v9{wSkapDrFk(z*LQ2bsfc zkXpSqU3r}s(poV1+~G$RIleVH{-&m&=RJPN8AJ#svOZ*cq#YkT_nW3J`!0JSJK~Ku zzBIxO7<@6ByBXscDZEJttBRl}jtLNTV=V_fE(N~#xUlC1;{cOF%cKfB#+%o98a{iZP3!jY?`gz% zByE#<5#U$Gu{WG1Sz+m+yLIrcQqn(byIfa%xci&%jIrGZIE4OWTf45yvN_Bf#^VS{`2S;u?8%NU3jkgZA>tAn0)A9w7XHIuUV$=bEHAj_>dzU#cn^NPV^AFO{i@%0yh4~Qgh8sd-)Hmo6`RMga*XjpYBcoi#k}PTzobruL5QFx z27yywNy)!J6S$;T5~D)m=8Ksk(@J1ADZx7i&@AV`Zy&3N%a$*rY!-qLQZSr% zx2duCEOK4T!X4n?KeTz`CJH*<5H8P1XX&Y@p!&d;5+xUl8%^yS7v{~;7mHR4 zO{=S3s_k1Ymzn7t(ceBUZVA3B8kcNaZ#O)5w{KJ3VA}}pBhebyxES8KJIUVr+tBEn z_xWE(!hCF-(Q68HZ>oNqcUR1-k@IHycj+J(ruWTgv1b{#7aE>V%-;m{PlnI_P*-Eu zB9Ys}j`-eq(ZXyPZXcwG-V9_a`J6n}7T&jVU6yxmr9O`65C@H-(o(ag^moNR!h^si z1qeJ+xuulkQt?xBAB_IuZao~7FcbF*=o4{zO}GxGQI@IYa;@2iGoH9qF;9UNoKy%P z$QV?Q224t?wSGyaNcRTNN@j|cGxE9Z<04GnZ2{B^$Mlg&77hHQI@J8t33`c8DkHXq zP~)CVT155b9}Pi^zs{KOPa6B2Go!hGY?&Lmb+Y;pWlBTa*ve=T_huJ1+#d3tVgnL(^0(E5vh7t-YT` zYR{P-1;Y4kTK_bK0PkN9nXwV9lV8>kGB9SvL$c4qzW82QoZrd3*q%+h5LZM4A2n|Y zHQ0`ry8-Y21njCKK-tt>-MrG$NMi{hu-f}}5r4APfJ1-->x5qVYPH!pY$`+BDpmx4 zLF;N_V4u!2V}+3mBk{=Z9SRM0_G)SpA)8n#(7~cPce-ix7=W;&nh<(Kvb;+bDl0>S zNrYgba)y!%yaLYD!c6BoYS#}HjK2oOFd43Kwp1_JSWD``khY8xc8}hA)#0Vjm#2G- z!QY$YG;xOEQfXnWy(FAcH&(6s*TmGl7QQLy!s?A9 z;^b62?erncn9G^Dzb|N=_ATH!yXdayH*TTM2akhN7Z=YM_=$817ODp;5uPSdF5P_j zd^%lh$9Yf9FUFtM=x0phg3BS{R|;ZqMNa78EQlJseR;o#P!sdH@pJ=!k6Vhw?IMv2 z%S%?y(g(7bkhQ!_GWVTZ-mfbqKe0PeBxWgW-@3}oy{cQxlE#No!pA<4)`GElM1C;m zKQt;EO_n0{EBM_7C8y7w6%QM7s2H+jcCJ{SoLxkw_VwFfbk@4E_Cmm;$YfXqt(;r# z8?ZZAqhFa(&JvIHRaWhCZMaW?are!JdUEjL(KsvU$JbJ393@IP8$aZT>WU0ttu5}P zSS`Mq+Tcn|YPc)DAKLSA+4@YZ^zZED8DnI^Z)(q#lvT?rB`(QFJlmKhO+3tab1-WN z5Ql3vS8p6QDy1B)ZXsEmSX?!Uwm*%#JVl5O976~#Ha6EAY@{2vGBZ616%MxY91Rqh zCuNFQC1qENJe+$T>1yVqAVcNCoPA@-0-$yhzO}M$!((|OlBY^V3?IZksk1SF2`jnC z@N0=()<*^f@3IV}XOK&Ymmv>32=z=YlOEr1Ti>TnFp_TBf7BShlO*U>;5Q?z$6C06 z97eQ5KIW)6w!scY0YKe5i};`dS)+)l04bZliPQ3JY6;Uj#VN;1y3T@LVzIhxh?@)w z5-OTOJYyMZ9ILnWQ5?N1PZb2n@=7imN`9S2lCTVU5K{1)uD?QHzFD|{$0UE&(DyQK zuf?P6WZJ%L9}7s6u6zd1edkYLL)`$+VXkChuaqi6XK-2%HgQ}PUvnIYot_~PVCiFj z)U6g?b7}*KK0A(0B-LksrQ=n#pK%I6mraiXdX5q1a9j;FV7C@Xj{4xQRS8cA^%|3!Y@y#L9Z{o%sCUHD12FQGb54QXP1RMT;2>Zt9$kw&nj&0kv zZQJbFw#|xd+eXKoq+_#V+Z{WdzUjTs`R+OQ+k4+Js%rhHQ9o9#=Y2SzIfdYl?}$2L z0)OTy%DHyr@Mj|{2+y#-dOg1+Avx$o>g1hqbdLCdP9vt$IF9qc!kmR6P^KQ_5Wzpi zo;oGbOKtqM`YgxgfyH45HV zvBHT*BnfQYP8jw^*?ifx)trhvu!G^;v0n~;K7=c`Wb1Joj5|xR%(zDmKM5|ySnPFU z0&?%@J2TlyRcbK?YAS=HPTPtpLyYrk?JwnGD-mDETn!B~h#eFi2x$sYw+TVPETei} zp4r=8;S`B~dg@gs0n}xJ@m6R9H@w)fw|-e3T_% ztL4lzGZV#y0hRgk-52E1zOpu6(oIgkh_q5$ zl1Y5`iKwu2n29NBi+M-zNfnl@NQRP#=GK5@vuC8-<#Hj1QLo^HpbmUVEn=N4Fb0$N z^ZI=sNzSlA3Y~<(5DY9ky~PA$4u%OZKL&`Y6fMb%E=lcEv-nkforcVWI~|5|bq7CV zw`+fN7eW*9d1hvmjMB|V5VtrBH=&aZ6l0^sUjF(GxK@@Zm77+Gsa8>0uxJHCOKa*3 zE3U7_%s6jZnRMG)t9{8Y{roG|drK921XjjKP@me#92PF49tODka!%8*U5j~(!c7BK zd11O6g+8yfd^f~jodpUCthj=C`sAP(k1ueET0gu+9PbY#Qlb?xbph2rXU^=`CuE_B%w$kV7^WACjV5f-5I>qK3Q=eM}<{=pYk@< zD_*lz^z>3ZfAgq7RdINA&hL{s{Q7*cHX?>EzyT@|k8uYtl=Kaw8e7<}-V5^G;GPj0 zkPndtU%;q2Mi3?KJWY(q8zE&|(!M~F&O2aVM2Rmv>MR`u;n4-l9p?|kutt%0Pv3{3 z7&NR^%20^wA0g%etoDRVZ`f9k9$el(?-8$1{iWE@+Fx9%Q%Ec4yX^T7C6)%K*vts9 zuT~F;_-4AItr9jH-P4!+ev7(_t#djhI=Pf(Tw|6}2ZyFgwgV-rlvQp)YTmhOJQ2`c z0aiX>X}e-N!7Q3_X~|YN1rdy~R<3`(#tyiw$fXY}Gbl64%nFN3liyfmq*lkA!g)bZ zsI+|1#iYa_of=gBrOF^AOlr7&8OTlG+ilmdnbk7AfrB4iHY^rNB z24RU%;&F_#PoXi&;&6;3tkC`%`!F>#rp(XLd5v0rLx->KI)Qn{aC#DSexqidAaWik zbRICaPiSsCOWEE%hVxyMk-yY4YB9hH3ynK~hFw5nPrz~K;p$KLt7JL0)9nNgQcKMc z9NnJ3%igf)Px23A9cna*cqF$Y;rHjQIexF)g-$2njkPqUGzFQk;fZK$L7Lbtc|)2& z2e}?5iDipSCcR`D7BFCcFK?cqqi#VDnRfQm#HHUW^SNb8=$lVxk*82tq?&f!Jj(tB ze3azcJ;a|kesq7=FIL;%KDEQ(glvZYP)3lOdw+$J-M+Y^{pt{afRUpHjfw{aZ)}%I zWr4(686clR9|RP(ofJzg=Of)cX&}8yB-;q=h3BDp|$7?+esjwA{v+l`b|0i|NWQmWKs zq%>th-V~a9=#j8Y<4oKHtFN9QKPA}XW|&X8?0xhDXOWxS#8u%{eqKX z67N+0E~2+=X_*pJh*+>D)fByhqvXIei24D4R(icn2k!!F%)5{TWBa)nXR{UoyoQ5;x8{0d8igwS=0d$(m z)~@Bt=&%xQ)0d1AT1bz$!k79v7hZAuqwBV!M{%A2QlheG#}u5wIYZi{%psT)Lr;pe zCwkChJB?#m=W4Ey9a<@5Nrl8S7Eb6(4lx42@~e%OczUhQ%igieqVl>M34Q* z$s*LB8Y}F|3sa6)I*ouZnUy#>nc-!=CUHlsr3WEa+(9RGpH0hZ%?rBwSi>K4N;=)# zt*osc2TIl0LugfB8%w_PMANi7n^RnB)OXMwks>sSJE)B_)*dPsTU^)~Nn1~EXG$np zOxE&+_?Rxc4iXr2eA)BSU@xhoozSF`|Lhs7!j(3w&fyN`$v+{dlB?i2o^(X{=sqt0 zQ%6onp%D&3Nm8Nds5@Hg4wm{vi?*a+Q-0VHuC>hzJ5Xp#kRwMhJ$Lxx4){kQh9g5x zpOBt^y8Ipzcku8r8Sl4Cg;@bKcZr0(pZJ<_5I z9o5Ea28XQ2LPQRSDugD8{w^M;gI3-RPt08x|sf@^9cwR-!0nK}nq z->|9?cc!fFBUQw2K~hwQ%gV(!@8sR4x9k_#?0MGSKi#OVm~9ewxZkaprCDqFs!OP96Km^U3qp$z|0O!gk)(H2a>K+bm5oAs@^n52XE6Q$@HT@Fk-t6*R$#U1co<1MfKzvUw#_iw5?^WaR4spi{;6CQ?;frPqM8y`qAN1yhG}g zo|5LdpR3&Hr3U5vIOUGF>RCOlaBXj;&!msKPi>>CDu3 zAo)OO&yxRB7w&H{g7ONAe|8`L)pSvxbY2rh^*@W_Y{)5=$|^3FgGz3RO&X$-qarIH zlCyu---lcuf{pj7}t6$ag{_~mRQ#vpWJXCxKA$%x3Wzd9KGTa&yA#5ak?7oV26|eeacddvUsKBAYP`@{oI}1P&H*n$w5k&9<`EjjJk_TgUg-)c@NEn z6qeeYbcXA=V)NX@GI`)g5WNcUS5L7bnFXgnY#e2w!Ibwdz2xt5ql(L&O_&XCs7bx$ zy{E9!*cKUr9ln0$MN+1A?GaRgA*AECDbNchR*0NO&OcV^1=NL$UL|(TwIxxG6J?XI z(UFN6(^qdElSqn>v4I-J2zA(%x^Q%h7xQPBFhF*{!AD81@KtKz(o3%-_dc`lLuFG} zc1Wd_TPm#>(`D}}GSjIhj0=wS`?S}~M74Z~>SUIxS~*mc1R&ig-B#P2W4`di@DCG9 zdiJ`f;f*r7xVX7|ZX}hR+eH3yc-D2RV>Pi@qaB$!YPG=3MtZ1>u1|gePMdTSAv{j_ zP~hk0jk7}I%^J5U2HsCafY%)c{ja-peJRI0}od8e+H zq$QVK!=v_-UdBpnZAdtr=CI3@NmVPkJ6$&?@hlR5uxk=Hdm%l~6yG&jlDf1haUKM^ z?_hGjsPY0OPx&gl?lTicLalX`$XEKRYWl{St1M%*bio|7rKKGT)M4*o5I=`#lZ$dm zfa*{e&q-0}L!2vPLPN#g4r59uztsD$_=u(!(U|qqK4kI^q45{|8iql9^I5qjpq@x$ zAeM@QD-k$9=%luluVQ8$a^PPeKw12`(wfGDw}klV422pkM#WEx zsp*Qcp)>+~E9o*xsr1|z)AW1APepg5cxwSxqTsLFCA$>zjDG0 zqYle(mLgigz7WP(?>PW#NZ3N^oE?z^wn?*vL2TFql!>wtzF7|Mv&BLQ#`f~GIRJv; zRn9)Sw#P z9ZHU*CB94|javX`qM8t?eK?8dj2o$baK;d0NROr9D&+Rr5D?C$d*H51vml;zcIA=htlB$F1zf>O&5|u9qhw;d#?I3 zUP~VXfxY^V?>@O9ZMyA_z=~dZLfjB<=D~P2sg@u4Lf|A4)^$UUREcYXw~#vZr2)xn z9xhCp(GCz{v}{7r>~iRu&a(f297Hin=lwogVduiU{Nly(+9Fxaaijv}u`7k~%Ji6aG|JP9Ly|JKQ) zuk5Sy0^JuUzV8oD0>7PjPpwy>^9N^y&WE1C-;YxMa+&rwF8_a=`2RaiNm14P?aukE zd0L9vn&E6mAVNOTaYEJ1F<3}tv63=Du|XB*Fz!Ued`;jWk;zTLJ%&|y!^aN@GXppK z;AW--bXsdMO|4QPERJy5Tw7`Gz4L1* z|59Lgb`%kZg;`Maq_@A;7HRW4-VksrN_BB}>!}6gQhd*~2u+96f*?r&B3mY5FZc@xrp+bFd@qCFX?&C=81Ku*J z7%BQzSRncx(l;`_A-w9;qR7~3hN%DE={`NrVd*IFh(9g`mKS6+*FhiSVVy`wRAq=~ zN4ttFs6%nf32g?bzgn!HJ1(@$+M3gvm%Kuxkdon2z*8>m2*R46WLX}iqPvBcRuM&h zS*JJ4B+;Ih(YuU$1iB8Z3bu$I*EI;!t_vQmpKQ#S0d`);tXj(bdt;!9c(;Zkfdvh}@J>zAQq z*f;>&!rOS8qpxhnf3f?;0CDVqVEFZ7Z(=qMf z9fcTN`hK`zXKzS{8oKs^nRJewi|C?uTPVwrtOs_-Sgs#ibqmuh#N?)(t zo^yDODtj(-%$0q0QYoc`&44Rn)vD{DYi_!_E) zn>y*WB+j@Yj3mj)gfRxI|C)WXU2uvX|Nv%)!AcOu`3RNzEBfO&@p(d zn2LWu0&4K07^{6N;rUCPX;B$QdozaV1jRDi>Vm$*yXb>~;WcWzAHbZCJ6km@IFvMn zIi;)rikXFs1u>hf9dRnPX_|m|LTz%6;GS|6?b|P-gCH{>RX4^B)<( z$o_7OD(`Azqw$*$@n3sRq49DGz)XmMtw3FMB(dwPV10<-^fvr1%Ps?1b|M{Ck8Rad zU@{uA*Mgq$qzDNA0D&=1U3QBgD7jTn9+v5eX8kRKyifE>bi{GG5Z>?)P@y<%>eqBc z`aISs)qo#T!tE79jVZkDrcaa|K;G1H7g70i!lpkm<|D(XiE%kxIUNQ?pF~c;y&Tw_ ziXxmoOCj=xQm5{)eR}}GV={USCdF>_WkU*5Ib-Ezu)T0k;wM_NykhK_PUKY^ij z;D++`tdm{3vEPYG@Ib=tPD)aIAx`~@OuHP?4~BxY2zyF>A&oY0-mk{^yiXu=u(WjG3h!VV4XJ^84*^_P ztYByJ2H@CgLtg4OAZX;#t0pPtUsD#Bhhn9E{_$Ai-y?xUKjxW2|G0bew;AU`>jQ=sF&;FS26NMK`80ksNTP5hJ8)*@f z1S|U~b@&+x899kp`pNrsNTvEY3YGFlN{fR7#cTfo1MvM-T>X6?nOz)Q9Gn~+(ZB>q zd#D%Kh^Zb}iX5E%kLkVLC%T--52MQec>jIKq5eCwQ~rap!PH5`)xp8u$>q=L!8Z0A zbdVsb*d@!naya@=Av%}&W(%Y?SZy>R;nz`cl>sdAi#_c-AYavDQLKeE-nPq4=dBCB zcHs1HUuIi(5WyQL-H8RD>FxkDeap8?%EQq#_&K2CCcFw6-_QF|5!VZ2kkB`|56q{S zbBAp*t_vaGnOnkCMK5)>FQMcqY49S{5~2EzU7=}8is{SXQW&2N(Wnje_4?|6?r51H zL4s#8$qGY|D_+u9YZEQU#BTn9#)oI(j{1$pNBu`M{@?C!{@!@c2TVm=GN9WkCiCh~pAAkmSW`S61-&y&@5#q~-P=yqjCMuKu4ijcEx%#X~X< zyPdS1IqThZ*E$_YlE)jJgk%oXoQ*7VHZfP8)%`SDL!>U~3wCs^GZ=q~vVFGu@Q1Ey zA%j~zTik}3;B%EtsUI^!Ga*6~$^2|a!CX{80t>4B??fX{VZ=J&<6gi2<5U0JDZR42 zy^DyUi>dkl;8a4DFRkYlQTgfw=IEocCfDQaP8%mD*+T~dx7Z=(h){yUaf1DPtO=yV z&uQu`P5l$}(Y{9n>4W{EyzXXoG2LK`rd~Y*#FM<1LN87-x^0Zi~F*mqAZtJY}(wV|nmSc$6P29z{Wtbp2o?kNyJP zKc@RaiW6RpiR8+v#*d?G9YYF`RkGDeok%TBk2Qh9rD%IiJx5NH#P7!N6pykk zd6#UV(kP-!39Oku7#m8aiEcy7$g1tM9pXcoEh<*HM>ez+GnTj)l%z zhjDASodb~eo4K7$R*)&zD(^R4e!7guOfBI%LRUFTc zMSdo&B&&?ss=wG(z^tK3?k;*mGHty^3$^xVcLl*!^bx|>GXk50id$$HK3(3s(L7{4 zTW_0f$}o!?T|I-MH=Zyx(cw~_XH%;_z564pO+ZM*$NX@gqyGpA`P<0$+t~iIHxc?L zG{`rLv%y+cL`ORjy?nfEFC3F}pae3W7!e{0q=x#SO-{XqCMkwp{z*zl2sl!3H*(;& zWQ}@ovikDk=Sh#ludPk5uhWltpYRKf3vBy`T4LDFtC4hC9r_34a9qz$+3f3E1kv#@XwCoSR9EW zxpo{92U59(NDNvu9Jrud_r=vH|Jsg`hnMX^&-?5M6h2W5P*s9oD0XUBFn zG*2yaf{_gDNR0~i174D=(rH{?3f)OT(`*l7<#qJOgBy^NJYb6 zuW84-`f8_6Hu3ubrO+%N;+p-UqmN#nGH+@lyy1WJn=k*IM#ZeHu`7LRI+2hG1Yu^4 zjk+y=!Pdw?NstT4JoS6A=n|%q;{C?OJIl2gfg5++y*#6U7TvOos8@Q-Mtuh?zul;! z8uUX$RX|DS8}|;k8VJI1(0w_DXmDYT7+-C^))g8Gc?)^1QIiRrrD^kG&@>}|?(9O; zep1ko7HTr9oUgj+ZNP_EZs#jZ?dR9Pmu=KT4ow0Bunh*r)OQ`skZCCW_%MELkLS4I zhm2vjlLYyaW80r#znv7TqXX^lJwo+=w41*qdH!7u{T18%pYbV1bxrw0qlPaj#0C;Z z2^4r2jv*bU-a|qN6a*4e2~t?=r7?tv7R_BbD<-vjRR0OA+bSjh$zUf+^%>0%%5?fi zCLz7Fnw6VZ>8nfLe9m*j>j6!G-+EjjlJC7@!DxwoW*VxCq=YFUP>orXuNaWkVke&LYO*>877KF2KHO?zrl&x%+oF7&XD( zKU9+Goyv$!&1CA%>mO??alov;UG511B=uT7g*59hxtsc^Exe?r>zryRp*5D8qur%q zg`(0hWBE3MlbY!IX=ijjMi}9|(+l`^vdG(e5y!$!D@jt>WcgJ*y9a7KTN@9nM^LD8 z$`dZ|0Ox8&6Y=kz#ZIH;L<$)+eO|R|q!1~Ng95Jt7NdQu$o$#+U`?3cfm@HPsfSQT zL0oJ$&m;+*m1`D7=QQdNEvYc+Uz)}vg#%?iDY4sVyoC==n%X&5QeG2C9r7wfMjna| zj@?3uq;Bp|Xy?(&4?4nDSqN1{vJa@Oe+!RvbD_jkbHu;`Z1x{as7aFKDN0rm^LrHb@aE_UXyr`KTVrV@ynvu_y~^*ZUG$W7`_Z^R4}7j7hi*A*gtnRK&Ht9XKsN#-Xc&)r>3%u`j zK4#7srn%NCXwP2An~kvN%q?6(tHt?>xCzWX?8+VdYx1HQgkD%wUQ!`~S=qe{BR^;Ngh^o zK5SS%c(2PpdeC+h=vb;BhZPs%pK{5+WD5DO1N-l!^3T)y7x{8*@>~A*uH^5;;^1`u ziF%EXE_}NgD9%>3p0ps{`47rq+p2bdHBETX>KQLij&nM(s zFTbI$n7{c#5Y?al|IpVqg8uv8Od%uxm`1UDeEYxH>;LkG|0|1*iSC5|$f8A$h$D@R z4XqKdbzykCX;4s@9$+@FMgU|m$30q4Kz_+c$UL;^W{IO2x9`0ApIXwn(>WcWZqut| zjP67Lk<-~*%k@OGe80-&XibQULPF=R=}}A*BH=sjaS!x|$Ihy*>OeVWzC=95Qt=7MvG}&J5jd<{8re?WReC zyYh-ZZjs?1^X9+*6Pzr6qn`f_`V@0Bv~m5vbRDkIbnty2i@irFbHLE>0c3;*NSrQ8 za)|j3b(4n;lcj4m{_tVjpKv1u!2rGCqv6lp!?$h_^@E(^xW=OC887EC;SZ(B#q*{j znzSlMVvd8)YBXmi8s#0#)UL#NOMb3Ivhua}?fjTkP`3;Ua}Bobj(#c*!y)$yM*`uD z7fhz@sIC*xIUGoVi1`SiAwYe8hEG2}&HjP*M%C+@O8>a=wU77Tmrj41M63Tnnem@B zdrHb5aS8BC3fQop7zqs(83_#*D1vw!NVH!nI2;01m3Evgy8e4&2|Et$*A^c{`>q9Q zFd6A_Yl6Wr#ZL1j%<7s*9g{hh`Jb-8_?kMm{Qcgcw_(i+IWdBJ1z{aw#hFk=KtZsv z9r?lGFg(1NB4v274h=)X#=CgO`co)t#S_pFvw-DTtcOYysMvj^L~}9b|J~qmbMeXrZ&y8*);j8w~d~ zOotjZz!#YZ;pV3sw$p3(WgDQ{cSgE)#!Le<;f873fWwsalv0&6N7uEri{cGyMV1e| zXj&;5zi>{$vpuWz7pxZyUi(uz(-&y)N;`54ZXt(P-l+$2PPg-G6WP%Z3mLwyus}~H zm`dGPKm~Z`!qr|(HpLouZ8LXZ1UEt@ozh|hLjboLJG+gJj#DLl?&xW>_C2SY!C&57 zNi_Ae*ZA1r-U`p#K75<;_pj z5!%r+kiL3GZlpb%$)}$;q>d~RF)-kk=aG}^{Se9G2(j9qYdZj3UMA(H55}ffI#fZ1 z$A90ZF!|zYRXO!(UF&;64{%wEBeuMv3g%Kf#Y!-#cX{Ob6yG>L(Mnp?$d5Pw6|F=* zbuqW4+^Fng;<8HAl~5J_dnl_27}k`Eh<)}`kT$N4?fJ;82ja1H^1N~NNIM-#Ez8C} zYK^$OGbSt5V&$16Nzyz!A%qc^B-9CYlSQ z2-QR2lwakv4GB(HuLWv}GVABmdUc?#Ls{3pvrjMDfASq>_n`%B}! zlK%ZyMcUO!OpIM&F(d*)P+dwp9l3d;*rDQL%WwWp1vKA63AQC7+!HCSbTLQPd5$)n z&8Bkxpd~s>ry&YH0XBn9C);;#{*YJ{E>-U#H9-g}B~G@zsG6VB6$!;?++kw2f{4AN zH!Yv!2Wy)BVuzA?PUu3nk~sCHv8#8Zt)ZiImRt4xXZI1FHG}dFyWz6htQO5&pg(@- zs(Z%giiNs!oRySR3g0DZ2Rk~vO7(JFtP1ji<@bH0RO_!7U&F5x+tnTqcm2zcI_A#m z1ASDuRx$M|@4YNqn@u5V$CHa{Z;CEnpjc9*prU>qn`0aaQMjNY^hRF|b1qJN0go4p zRs1>q2HE6~pP}0D>D#4MH|@yCP3BR~U;^i%dajT{HYBRYXAmCP;WVzy+ZekL&5P;|_w2gm&%JwKnhAg}n3Xa@C(8VnM|n*iMF~~6?6CqwOf^0#jo9jQ3Q*vHxG-zDu#FAfYB__~ zDt?&=AY;^J^*Cv3N8rhbIMHIa2*EGe@zRox44fc6%$LWzuIVB3_Uy5h;1ha7<`C6{ zwd5YP#1dymt~hWz>CHKeja_|v#y|}zI%u<1yQ-INt*tuPkW6PI4cuq$(gu{LRO3xF z%oT?mH^Q8J@{3sMZ;0W^1Z9lmh_^Zdh=^;zv+Bbr>2&SgmXZqW+GF*)&ZbMp(p!l` zi?`51WQ(-J(2Es3X?3$tfHhU%jKqU-ikz<en~eaFI1o9_E}n9&vI(KXQ4YNdlf99`93;;kGl@8iszP&odAR zeD*JGi+bOlZ9&x-*M(;rClc)0O8_2Rk5Gkk{Vur-p?uK}FY_8H2rVo=SDL-K%UiDpIrH^`XN+IkOQq;bYfTfg^KGZ!AG6Rf{OTa$Akxr>s zrF%7=Q=UlVIgYYm;;O6BYJP_>zI_8Iin{?^0u}toL@1=j`yahrk8t%9rH@7nALu_N zB!5Y;@~3|i|1eo2Lu2dz&25yT{@EGD6w|M}h0E=8{)`crG^gfTF(N|13~^>EC~?7H z3o0VCU1Hs6svNr=$4)-3D(HIs+`@>_L!ly34s}L;7LH{Trcl?cU=4%Ea`(84^<*f;OIM)Qk6}0?oJ)$Uw z@_IJZ+?W=@6xcP;l(X}2_03sij1!4Q*pa3CsuXpQ6u$C6yWZ}3N+PQ z>=+9Mib=GSXn<#S6k$}$x)=p zZ_)P0A~Tcj71=VOAXks=t>x%fLgcSRl?`4(BR>Dsrm}3YH$kZzDKv!;KE5k!Fz+I* zKLb0Lw8O#j(dIDCSEmCOv2{|cBLmnIJ{9Y_SBZb)DzY&%5#AHVv`IVpDqCZK@Bj_V zI-X9;KzGfAgOapYpvf*HLqxGua0{(&Kt)+ZJk!vo@eNJYr>$}u8yT7y6Gd}NXAHV_ z&loHWk;MO8ZZe!a3jLr&r_qF+OC_!yA&;^xFbmqQp*g48fS*A`22hKmp&6bt5lxIbg)XAqfDcP;FFrk%SZjtUN3%Jo_=24kZJ_#17q?87V?fC@ zX+Y7G$pq_5KkB;iIege=Bj!0jYLz%BMW-Ukkf(DdQNl0BGi$6S8UymLvRov1wlYsz zEOjE(jEl9&pHs6NcOe)lYAnA9erdNXMic+kW6Eh9ctOW~qs%ayH40Uv-{Gp2L9arf z+O*O}5A%TLbLhmyztURrZT`87N)34{i7Ja6YvFL(%1QkhZPp5m2GQ>wMwopF%`en; ztQPH}qj~F!v_~wqFTI9|Yqc_w{yY;yFMlZ+tcX|xqhs`J6_)3ig$*`PV^)elmRj&i zVfo_3N%^eIx8vcvxa9-+eUO*J6VZS>>v8@iZSR&cVt$la-MpluphqyQ;GXaDCB8#& zIi~k96ZaIKsJXrdTCOCT-sy|achw#L5Wy#J(7Zy9H_VL?WqiUBnvgRsGCV?HZb%VK z3ITG93tQX)q|dzpBD>Jrvp`*@)&iQ3WJWR~MFe`@M6=t$<*yFm7P$TMqU&P5gt%C1 zsyq{GKcoGa> z%qi*3XGMM`T?~0veurspl|t3GKmng{&5*ah>Inb$2yQDTQ^#^KeJX5O92R@-UB1j2lg@{@8c$r z!xjOol~xCzYr@KR)J5?P98$`bx?4C9`{X)4wPHU3&V2eGT+O=oSA9D3`Z>N&xTih+ zK-&7r_9U*;{bRkwD}l5k$@c z3uH{=92jwTX?c_<7}5X9Ns#+vitoy+6-#Ju@0J|G7mG%%31xhNG6iAZ-eWEG^YvU~_E zs#@`@?jXuqQ6{>32x$I+=;m4}rmAg{2{A^3Z^O{wj(m~T#c!gK3M3;^UkL{bgOF&& z97MiJRS2js(%&CKz--=3cR06aPJN8oO)$Zg(mI3_k(?@-5xJU1e zN1W@Kt$6$@HBL*r#QlifR-G*ZlZ+)_5k=VBrK2+LX{Qj!SLpStx9FT2j8O4z2Ap#( zIja%@xgR3xek-+1(FAChFOxXU_4G>aQdWrqI=2&W@+a_z)I+5Oo$E`tfl&cgF;Q~# zH=Xgb?2>DrfUpMTo5gJvraO{T$~AoLOw$g3WOSXb<;v9W@Qv{Q@)*Cww3E`W?ddnk=mTQ|a7`7FAL(ek-N zU0**9$G~OLS=UaP8){1?J$6!8!0>6{jSCv7x}q(HVZT3(y1Oq2vRmCSe}u7qxJ?;- zy&h8@ZzDtOv{@%k>I*OZsB=gPrwo`xCS_b*XQXSgYO<-EO$5Q|3@9K;qBQ_KPLE9_ zPuDsM*QT0nHB!6YzaK!QMOm48Uf*o zhvd+#oN|110S5nz(s0(kRCB422s2?E*d1-XNiX6GRq-kxB8o_&l)#fjbCo#zSr4Zyxj)?&(Vo&B?#8d9uT`G(5I?D!1;`xV}vny>c}u)bn&Yxxc0HAX$bk^4zRoI}6EjxotW#m=5fWs^J* z$?ovFNc#anZBQ+WA^2GR+j&} z_Zvlk%9G|WQ+AyQD8~1hnjJYj`<=pAY#rs)aqL=3nYdU+uatvIfHn8aOdS9S4;&dA z-1S_UxuOUO>VOY*$Q94tm@^s)uLyJA5#%!Dx)z!he<&o8qu)azkeqFO?y4Jr04nUs z!A9a6xDjFLJQd9|7Z(Rw>I}SKNyFe!-)z)=O;c+Bz||fkuzmRAD~)T-z_3wMck&9wy_q=E8iv6SViasnMx@Xqq~fWDU*P_S`FRg}U-< zP(Ks4ssW2@%B8l=jV%|}?j2I=c1dxi_V#kq$g$!k`09-5HW@C*Oymc%k!?p!;4)Ql zvdC)hxCIhtz3vvAq)&M~76=6*nuQ;GAa)}-tt?Ku(#rBN@^TYc0k8GiyrluUD678f z&v4o$ylYLjft(~gQhQU2Hk19+tT}3#=?G+ZxV}l%*R%mvJ!H4s6Vl#ti5#bhG|@e#{LoF|bNX z6IK~(?RC@f(f)y%6ja%2vdk;Kn0z}>wu$0hLOI%0DhnFDT?oI*LGnmI0Qo)%c-aeuBds$g^jzUm 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%0A}WbCY~(jB^GZ%R!b#(`!5q@Sy; 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 M@qW|12@Vv0b>eX)o0&tV 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