From 0251ed077d820290ae7277b2ea19d883f0fa98ab Mon Sep 17 00:00:00 2001 From: GME Date: Sun, 21 Oct 2018 11:31:53 +0200 Subject: [PATCH] Init JAVA-API project Setup Basics blockchain class, pom.xml for maven, Logger, Basic IO Tests. --- .gitignore | 83 +++++++++++++++++ .idea/compiler.xml | 13 +++ .idea/encodings.xml | 6 ++ .idea/misc.xml | 14 +++ .idea/vcs.xml | 6 ++ java-api.iml | 2 + msp/toto/abdel.context | Bin 0 -> 229 bytes pom.xml | 52 +++++++++++ .../blockchain/client/CAClientWrapper.java | 48 ++++++++++ .../client/ChannelClientWrapper.java | 28 ++++++ .../client/FabricClientWrapper.java | 31 +++++++ .../java/blockchain/user/UserContext.java | 72 +++++++++++++++ src/main/java/blockchain/utility/Util.java | 85 ++++++++++++++++++ .../java/blockchain/user/UserContextTest.java | 20 +++++ .../java/blockchain/utility/UtilTest.java | 54 +++++++++++ .../blockchain/client/CAClientWrapper.class | Bin 0 -> 2284 bytes .../client/ChannelClientWrapper.class | Bin 0 -> 1015 bytes .../client/FabricClientWrapper.class | Bin 0 -> 2151 bytes .../classes/blockchain/user/UserContext.class | Bin 0 -> 2023 bytes target/classes/blockchain/utility/Util.class | Bin 0 -> 3748 bytes .../blockchain/user/UserContextTest.class | Bin 0 -> 1047 bytes .../blockchain/utility/UtilTest.class | Bin 0 -> 2164 bytes 22 files changed, 514 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/compiler.xml create mode 100644 .idea/encodings.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/vcs.xml create mode 100644 java-api.iml create mode 100644 msp/toto/abdel.context create mode 100644 pom.xml create mode 100644 src/main/java/blockchain/client/CAClientWrapper.java create mode 100644 src/main/java/blockchain/client/ChannelClientWrapper.java create mode 100644 src/main/java/blockchain/client/FabricClientWrapper.java create mode 100644 src/main/java/blockchain/user/UserContext.java create mode 100644 src/main/java/blockchain/utility/Util.java create mode 100644 src/test/java/blockchain/user/UserContextTest.java create mode 100644 src/test/java/blockchain/utility/UtilTest.java create mode 100644 target/classes/blockchain/client/CAClientWrapper.class create mode 100644 target/classes/blockchain/client/ChannelClientWrapper.class create mode 100644 target/classes/blockchain/client/FabricClientWrapper.class create mode 100644 target/classes/blockchain/user/UserContext.class create mode 100644 target/classes/blockchain/utility/Util.class create mode 100644 target/test-classes/blockchain/user/UserContextTest.class create mode 100644 target/test-classes/blockchain/utility/UtilTest.class diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8c95b08 --- /dev/null +++ b/.gitignore @@ -0,0 +1,83 @@ +# Created by https://www.gitignore.io/api/intellij + +### Intellij ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/modules.xml +# .idea/*.iml +# .idea/modules + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Intellij Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +.idea/sonarlint + + +# End of https://www.gitignore.io/api/intellij \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..3f8ab6c --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..b26911b --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..4b661a5 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/java-api.iml b/java-api.iml new file mode 100644 index 0000000..78b2cc5 --- /dev/null +++ b/java-api.iml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/msp/toto/abdel.context b/msp/toto/abdel.context new file mode 100644 index 0000000000000000000000000000000000000000..95e9850b9c4c40073709ba6dc1192053aa8ec158 GIT binary patch literal 229 zcmX|)F%H5o3`Jekf&>E+D+gdB2Vg`DNZBe5;HGW~q)A9zR2ELe)wlzNR{X*C@cjPk z4OtAZE{s!Gbw+KsZKSY0^<(cWQ^znQnZQ)S43%=NWrmf!;2niQTZ^27w)IZJ0;@_J zjjWx$!4nb*bF#r1)6n;6BVDM)`Qa%TDr*X&!XjuTVtEyZKiHeHCi-JJI#P=bjd#}D dC^9UE{+6{7Iq|OZo*`w&?zek{A;Y31<3F`ZNl*X) literal 0 HcmV?d00001 diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..bddd040 --- /dev/null +++ b/pom.xml @@ -0,0 +1,52 @@ + + + 4.0.0 + + com.monnethic + java-api + 1.0-SNAPSHOT + + + org.springframework.boot + spring-boot-starter-parent + 1.5.9.RELEASE + + + + + junit + junit + 4.12 + + + org.hyperledger.fabric-sdk-java + fabric-sdk-java + 1.2.1 + + + org.springframework.boot + spring-boot-starter-web + + + log4j + log4j + 1.2.17 + + + + + 1.8 + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + \ No newline at end of file diff --git a/src/main/java/blockchain/client/CAClientWrapper.java b/src/main/java/blockchain/client/CAClientWrapper.java new file mode 100644 index 0000000..15e5b71 --- /dev/null +++ b/src/main/java/blockchain/client/CAClientWrapper.java @@ -0,0 +1,48 @@ +package blockchain.client; + +import blockchain.user.UserContext; +import org.bouncycastle.jcajce.provider.asymmetric.ec.KeyFactorySpi; +import org.hyperledger.fabric.sdk.exception.CryptoException; +import org.hyperledger.fabric.sdk.exception.InvalidArgumentException; +import org.hyperledger.fabric.sdk.security.CryptoSuite; +import org.hyperledger.fabric_ca.sdk.HFCAClient; + +import java.lang.reflect.InvocationTargetException; +import java.net.MalformedURLException; +import java.util.Properties; + +public class CAClientWrapper { + private String caUrl; + private Properties properties; + private HFCAClient hfcaClient; + private UserContext adminContext; + + public void setAdminContext(UserContext adminContext) { + this.adminContext = adminContext; + } + + public HFCAClient getHfcaClient(){ + return hfcaClient; + } + + public CAClientWrapper(String caUrl, Properties properties) throws MalformedURLException, IllegalAccessException, InstantiationException, ClassNotFoundException, CryptoException, InvalidArgumentException, NoSuchMethodException, InvocationTargetException { + this.caUrl=caUrl; + this.properties=properties; + init(); + } + + private void init() throws MalformedURLException, IllegalAccessException, InstantiationException, ClassNotFoundException, CryptoException, InvalidArgumentException, NoSuchMethodException, InvocationTargetException { + CryptoSuite cryptoSuite = CryptoSuite.Factory.getCryptoSuite(); + hfcaClient = HFCAClient.createNewInstance(caUrl, properties); + hfcaClient.setCryptoSuite(cryptoSuite); + } + + //TODO + public UserContext enrollAdmin(String username, String password) throws Exception{ + UserContext userContext = new UserContext(); + + return null; + } + + +} diff --git a/src/main/java/blockchain/client/ChannelClientWrapper.java b/src/main/java/blockchain/client/ChannelClientWrapper.java new file mode 100644 index 0000000..5db76b1 --- /dev/null +++ b/src/main/java/blockchain/client/ChannelClientWrapper.java @@ -0,0 +1,28 @@ +package blockchain.client; + + +import org.hyperledger.fabric.sdk.Channel; + +public class ChannelClientWrapper { + private String name; + private Channel channel; + private FabricClientWrapper fabricClientWrapper; + + public String getName(){ + return name; + } + + public Channel getChannel(){ + return channel; + } + + public FabricClientWrapper getFabricClientWrapper(){ + return fabricClientWrapper; + } + + public ChannelClientWrapper(String name, Channel channel, FabricClientWrapper fabricClientWrapper){ + this.name=name; + this.channel=channel; + this.fabricClientWrapper=fabricClientWrapper; + } +} diff --git a/src/main/java/blockchain/client/FabricClientWrapper.java b/src/main/java/blockchain/client/FabricClientWrapper.java new file mode 100644 index 0000000..eeb3ee9 --- /dev/null +++ b/src/main/java/blockchain/client/FabricClientWrapper.java @@ -0,0 +1,31 @@ +package blockchain.client; + +import blockchain.user.UserContext; +import org.hyperledger.fabric.sdk.Channel; +import org.hyperledger.fabric.sdk.HFClient; +import org.hyperledger.fabric.sdk.exception.CryptoException; +import org.hyperledger.fabric.sdk.exception.InvalidArgumentException; +import org.hyperledger.fabric.sdk.security.CryptoSuite; + +import java.lang.reflect.InvocationTargetException; + +public class FabricClientWrapper { + private HFClient client; + + public HFClient getClient(){ + return client; + } + + public FabricClientWrapper(UserContext userContext) throws CryptoException, InvalidArgumentException, IllegalAccessException, InstantiationException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException { + CryptoSuite cryptoSuite = CryptoSuite.Factory.getCryptoSuite(); + client = HFClient.createNewInstance(); + client.setCryptoSuite(cryptoSuite); + client.setUserContext(userContext); + } + + public ChannelClientWrapper createChannelClient(String name) throws InvalidArgumentException { + Channel channel = client.newChannel(name); + ChannelClientWrapper channelClientWrapper = new ChannelClientWrapper(name, channel, this); + return channelClientWrapper; + } +} diff --git a/src/main/java/blockchain/user/UserContext.java b/src/main/java/blockchain/user/UserContext.java new file mode 100644 index 0000000..47fa4dd --- /dev/null +++ b/src/main/java/blockchain/user/UserContext.java @@ -0,0 +1,72 @@ +package blockchain.user; + +import org.hyperledger.fabric.sdk.Enrollment; +import org.hyperledger.fabric.sdk.User; + +import java.io.Serializable; +import java.util.Set; + +public class UserContext implements User, Serializable { + + private static final long serialVersionUID = 1L; + protected String name; + protected Set roles; + protected String account; + protected String affiliation; + protected Enrollment enrollment; + protected String mspId; + + public void setName(String name){ + this.name=name; + } + + public void setRoles(Set roles){ + this.roles=roles; + } + + public void setAccount(String account) { + this.account = account; + } + + public void setAffiliation(String affiliation) { + this.affiliation = affiliation; + } + + public void setEnrollment(Enrollment enrollment) { + this.enrollment = enrollment; + } + + public void setMspId(String mspId) { + this.mspId = mspId; + } + + @Override + public String getName() { + return name; + } + + @Override + public Set getRoles() { + return roles; + } + + @Override + public String getAccount() { + return account; + } + + @Override + public String getAffiliation() { + return affiliation; + } + + @Override + public Enrollment getEnrollment() { + return enrollment; + } + + @Override + public String getMspId() { + return mspId; + } +} diff --git a/src/main/java/blockchain/utility/Util.java b/src/main/java/blockchain/utility/Util.java new file mode 100644 index 0000000..6d29293 --- /dev/null +++ b/src/main/java/blockchain/utility/Util.java @@ -0,0 +1,85 @@ +package blockchain.utility; + +import blockchain.user.UserContext; +import org.apache.log4j.BasicConfigurator; +import org.apache.log4j.Logger; + +import java.io.*; + +public class Util { + private static Logger logger = Logger.getLogger(Util.class); + + public static void writeUserContext(UserContext userContext) { + BasicConfigurator.configure(); + + ObjectOutputStream out = null; + FileOutputStream fileOutputStream = null; + try { + String directoryPath = "msp/" + userContext.getAffiliation(); + String filePath = directoryPath + "/" + userContext.getName() + ".context"; + File directory = new File(directoryPath); + + if (!directory.exists()){ + logger.info("Create directory at path "+directoryPath); + directory.mkdirs(); + } + + File file = new File(filePath); + fileOutputStream = new FileOutputStream(file); + out = new ObjectOutputStream(fileOutputStream); + logger.info("Try write object for user "+userContext.getName()); + out.writeObject(userContext); + } catch (IOException e) { + logger.error("1st IOException"); + e.printStackTrace(); + } finally { + try { + if (out != null){ + logger.info("Close ObjectOutputStream"); + out.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + try { + if (fileOutputStream != null) { + logger.info("Close fileOutputStream"); + fileOutputStream.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + public static UserContext readUserContext(String affiliation, String username) { + UserContext userContext = null; + FileInputStream fileStream = null; + ObjectInputStream in = null; + try { + String filePath = "msp/" + affiliation + "/" + username + ".context"; + File file = new File(filePath); + if (file.exists()) { + fileStream = new FileInputStream(filePath); + in = new ObjectInputStream(fileStream); + userContext = (UserContext) in.readObject(); + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + if (in != null) + in.close(); + } catch (IOException e) { + e.printStackTrace(); + } + try { + if (fileStream != null) + fileStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + return userContext; + } + } +} diff --git a/src/test/java/blockchain/user/UserContextTest.java b/src/test/java/blockchain/user/UserContextTest.java new file mode 100644 index 0000000..7aeeafc --- /dev/null +++ b/src/test/java/blockchain/user/UserContextTest.java @@ -0,0 +1,20 @@ +package blockchain.user; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class UserContextTest { + @Test + public void TestACreateUser(){ + UserContext userContext = new UserContext(); + userContext.setName("admin"); + userContext.setAffiliation("org1"); + userContext.setMspId("MspidOrg1"); + userContext.setEnrollment(null); + + assertEquals("org1",userContext.getAffiliation()); + assertEquals("admin",userContext.getName()); + assertEquals(null,userContext.getEnrollment()); + } +} diff --git a/src/test/java/blockchain/utility/UtilTest.java b/src/test/java/blockchain/utility/UtilTest.java new file mode 100644 index 0000000..af9979e --- /dev/null +++ b/src/test/java/blockchain/utility/UtilTest.java @@ -0,0 +1,54 @@ +package blockchain.utility; + +import blockchain.user.UserContext; +import org.apache.log4j.BasicConfigurator; +import org.apache.log4j.Logger; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class UtilTest { + private static Logger logger = Logger.getLogger(UtilTest.class); + + @Test + public void TestAReadNullUser(){ + BasicConfigurator.configure(); + + logger.info("----- START TEST READ NULL USER ----"); + UserContext uc = Util.readUserContext("tata","abdel"); + if(uc!=null){ + logger.info("UserContext is : "+uc.toString()); + }else{ + logger.info("UserContext doesn't exist"); + } + } + + + @Test + public void TestBWriteUser(){ + BasicConfigurator.configure(); + logger.info("----- START TEST WRITE NULL USER ----"); + UserContext user = new UserContext(); + user.setName("abdel"); + user.setAffiliation("toto"); + user.setEnrollment(null); + user.setMspId("test"); + + Util.writeUserContext(user); + + } + + @Test + public void TestCReadCreatedUser(){ + BasicConfigurator.configure(); + logger.info("----- START TEST READ CREATED USER ----"); + UserContext uc = Util.readUserContext("toto","abdel"); + if(uc!=null){ + logger.info("UserContext is : "+uc.toString()); + }else{ + logger.info("UserContext doesn't exist"); + } + } + +} diff --git a/target/classes/blockchain/client/CAClientWrapper.class b/target/classes/blockchain/client/CAClientWrapper.class new file mode 100644 index 0000000000000000000000000000000000000000..6e94daae18a7925c0c2334b051b94f8f12aaab52 GIT binary patch literal 2284 zcmb7GYjfK~6g}%WQKBem8@J(+(5AG2V~2{;Kns09FbxSfZfPE+Gt4j>d1I?pB+p82 zn|}o}gmhqrAHa`dI4irh+S(cN!Mm%~xp&XGckh+|`S;Ji0W9Ou1RQ*BhU+$_aKo&= zFvFKNhnqHT;kJ!C_{t1lTUfDS)rdqW!ROQ^0QN zsHJq`t5{&RgJ>sy;NI`;8&q@8la;_%VIokfM!MlP4`>#sdP8Y7 zQC-ot>W8Y<-rrSvOYR2TnW;ve40fdU&2x7%pEP}Hy_9w9rPAD&ydP@WqB`=KYN%u_ zqkXBkcoOwvxBSpg?g*5NZw7yGu#F)5?sHGI5>p`FzGFb6E6~{v$VVuY?@uf-jU`QokBK8rqMf1$6h#{1?qH&oJ$vc$@LgjRb2!{*W* zE754&lA0xz@mJ`hd%G5X61aX0(Ls0k@~ZTbNFNATy_K^bhP-Pgf~LPs^XSa27q~XG zoR2G&;$UWP_CJ9$o>nqZHT7&g&9uiGzBRPAUT?f7>NV4Bov(;nE}pmzm{#HrRyQ;t zxX5qN6u(n>cl%7-SAbXl^ qe8Sut%{H!bl_N5TPnoHa^z1y}UE|I&5jlK@`zccJugeDRVd6iWA5O9W literal 0 HcmV?d00001 diff --git a/target/classes/blockchain/client/ChannelClientWrapper.class b/target/classes/blockchain/client/ChannelClientWrapper.class new file mode 100644 index 0000000000000000000000000000000000000000..a349f42cbaebbd5253f4a48a96cb91417a4ee192 GIT binary patch literal 1015 zcma)4O>fgc5PfUA2?=hSwkG{96i`Xb$6mM|3(0eFjNEi7TrhJ70j+GyZ$6Hl5rWC*mlmJI8| zOYvFoTn9f}S27-Egi z;j94b*q|Fjghv$T!QMQ$Qw#25vj*(XgQHsT7Pc#JPO<`G6U9Fe#4o2{@vAAk`1KV2 xH+uJARdmS=(7=GqZ4q__JEURP^^RxwN)>f-c3CSTXPDEV_h*7fkQflsQKz-S7!vht#s@GS6wI{oQV_RYGnf0*Q zh+!K7mA;CS2Z3v~`Wsr68-7m-Ot&3Rb%y(06+D(*mpkX$zAfEd894em-7H4~CnSBl z>-zRHdmtUpN_1MySX3h5Ngxj>m!ifu9nXpG2`tt|ZH6I_@dJm3??vimv{By`nAE%J zhQLB0o@hHbJc#_Ap%YQ<&7$Lm${q$zbZ9j)6KbnIcxkJH$nm|Yv7)N z&kcMbaNZ7-j8tPFJx{qu!QHI2pUUUba;4X|cA~)X`Wy98wP{37m}Ma;dvZUH?;H9I5jxAJTAT7Hk(PnLo!kymK#~>wPdTPV?vE^U z`cqDw#eLW+5Rw-+Eb;3$$q${tm~InXmAIb5G{+e}S)2vuGb_JB{LIA|&T<@&H)n8; zYcm1hJZAYM*c;}E(#9d@66d9r-!b+YrR|m1DE|hbxz=7KoU5-e{^S>e65`mzO&@k8u{`!ahby>B_6lQn4K;e0<-bl` bDOOVEy9Ms7(sm4Mc)+>JJqusrJ}UnLtn6pY literal 0 HcmV?d00001 diff --git a/target/classes/blockchain/user/UserContext.class b/target/classes/blockchain/user/UserContext.class new file mode 100644 index 0000000000000000000000000000000000000000..88c8e70bb1dea8e41afdd62f82f10db2d11fdab3 GIT binary patch literal 2023 zcma)7YflqF6ur~e(o*DMsXPUgM_Ytde4v6TA|#lKMuhL%GL(VsF4=C4`l~d-nE1gT z;Eyt%yW7&TYzh5vXXnn`Gv}PSlm7kp`wtO4qRkW~>3Nd6XobTnhZh{yIK1TWN~3j+ zUTd_W(HlX1HR&kB+?P&G+1B1RQsS+ko(h%}vt}^vq>0%|ht16b^)*Y1Iy|}u18EFj_no%y>b;}jh zZ5$pdQyDJ!2}(%|r$bo)S1 zVpUnnT@w_|<@cdx!#)6|-lDSPPQ6-^&L^W}div}#TruDc=8a^`JyMW2UM!h*`J{Yg zC`+%yKYb4YhPmKpeXP2nLYDMBggCXGfY zO+6&&2A*hydMU;<@f~BP$Paq?Eao8X<-ywu!cKe`SRyb;WJIZkSwr$Lvr}ahck`^8IR$V@eZf3sm!<# zjuj7LO#*AG0~TKlW6jej;lf>_hQn(2VWm&;fS;k>jURt{MC4p`hEjJ4>s#l`kG zqsVty+}<7w9!#)3?$d+Dm9~28jH1EfrI2F(#+Ja~VJL%G5M((7MBpEiPY%+L2a8uj diyzaIkm5wJcs;auIrL;LSiBWl{M57e*?-d|Te$!L literal 0 HcmV?d00001 diff --git a/target/classes/blockchain/utility/Util.class b/target/classes/blockchain/utility/Util.class new file mode 100644 index 0000000000000000000000000000000000000000..5f9ec2d126444dcb2fb7300f176f0c1fdf3daaf1 GIT binary patch literal 3748 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 literal 0 HcmV?d00001 diff --git a/target/test-classes/blockchain/utility/UtilTest.class b/target/test-classes/blockchain/utility/UtilTest.class new file mode 100644 index 0000000000000000000000000000000000000000..7dcb7caa4df2e1c10fc4c5cd327808335ed7868a GIT binary patch literal 2164 zcmbtUZBrXn6n>Tfy9o=0K#TM>AZ-IFY}K~bQd>g^6%9d?0M@s<+1!MMWtZ9A)b_Lg z!av|=btYx(j352rZ*m-;y9p3N$8pBZ!vt|0WTz8cH;f@_BxKgM(p0#J~n6_&) zL))>#m&PV#MFb&Zj7ga-3A0vgI?iSwG4(aAUPtN;xta6aP`r?i!{yMl_SVgVC?08G zE~Ta$+WTV54r~I+x~>T?oO&KG7V zYVBR^q2+Y=NR+*%Z;4e~Wy%3AS>jufU>yNdT}D2IY`e5p$@f50 zaH+dIdTv>ViK;~Hg`N%zRUI{uy#A0Eq@yks4eThmc_vsyLylu5zjDGvPq?0H)L~-O-1asTlW;4PZxT_EXf|5 z?53j&AKQ+#7*%4Y1r+4E&uCxVQrD>+&D^O5>|vNyHfSCk2)CwS;SI;lojI>l8g$e` zuN^|cMEa~DE!04SMRT8goJ#iy7}Fi0MYdk&s}S`mn~93N>wAu~FI+M|pN<-3=jDO$ z9Z}Q*-$ImZlw zrMU>po8C%H^ZCBQH(fzOb|z;7oU>s$&TwT=DpEWD3d+x%^xO<)q|agXC8Ohs@mv_p2_jN=y4m?NxtddAWB7w)OZ zs8qMJSfEs}c#Qc6x=YMP2lFTayv7(oCJULQ+QN7yInl!TjMBn|Omeb?w=##AI-%wU zqkvq-$l?%>9VZo2M1PIwW{GN^1T7Mgq^^zCIL3OJd`qmS!QDOv*GuR{N$AA?CUk*d z7YWuN*xRJ?9TNH;3BB6|^6@dq|3Ik5BaSLaO8Lc;mkx3HSHvV$N>>%>