OSDN Git Service

Updated test cases.
authorLoRd_MuldeR <mulder2@gmx.de>
Tue, 27 Jun 2017 22:06:46 +0000 (00:06 +0200)
committerLoRd_MuldeR <mulder2@gmx.de>
Tue, 27 Jun 2017 22:06:46 +0000 (00:06 +0200)
bindings/Java/example/src/com/muldersoft/mhash384/example/ExampleApp.java
bindings/Java/library/src/com/muldersoft/mhash384/ByteString.java [deleted file]
bindings/Java/library/src/com/muldersoft/mhash384/MHash384.java
include/mhash_384.h
src/self_test.h

index 264f4aa..5519eaa 100644 (file)
@@ -48,8 +48,8 @@ import javax.swing.JTextField;
 import javax.swing.SwingWorker;
 import javax.swing.border.EmptyBorder;
 
-import com.muldersoft.mhash384.ByteString;
 import com.muldersoft.mhash384.MHash384;
+import com.muldersoft.mhash384.MHash384.ByteString;
 
 public class ExampleApp extends JFrame {
 
@@ -247,7 +247,7 @@ public class ExampleApp extends JFrame {
                                final ByteString digest = mhash384.digest();
                                final long totaltime = System.currentTimeMillis() - timeBegin;
                                System.out.printf("Operation completed after %f seconds!\n", (double)totaltime / 1000.0);
-                               return bytesToHex(digest);
+                               return digest.toString();
                        }
                        catch(Throwable err) {
                                err.printStackTrace();
@@ -264,12 +264,4 @@ public class ExampleApp extends JFrame {
                }
                return result;
        }
-       
-       private static String bytesToHex(final ByteString bytes) {
-               final StringBuilder sb = new StringBuilder();
-               for (final byte b : bytes) {
-                       sb.append(String.format("%02X", b));
-               }
-               return sb.toString();
-       }
 }
diff --git a/bindings/Java/library/src/com/muldersoft/mhash384/ByteString.java b/bindings/Java/library/src/com/muldersoft/mhash384/ByteString.java
deleted file mode 100644 (file)
index 8db86e6..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/* ---------------------------------------------------------------------------------------------- */
-/* MHash-384 for Java 1.7+                                                                        */
-/* Copyright(c) 2016-2017 LoRd_MuldeR <mulder2@gmx.de>                                            */
-/*                                                                                                */
-/* Permission is hereby granted, free of charge, to any person obtaining a copy of this software  */
-/* and associated documentation files (the "Software"), to deal in the Software without           */
-/* restriction, including without limitation the rights to use, copy, modify, merge, publish,     */
-/* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the  */
-/* Software is furnished to do so, subject to the following conditions:                           */
-/*                                                                                                */
-/* The above copyright notice and this permission notice shall be included in all copies or       */
-/* substantial portions of the Software.                                                          */
-/*                                                                                                */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING  */
-/* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND     */
-/* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   */
-/* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
-/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.        */
-/* ---------------------------------------------------------------------------------------------- */
-
-package com.muldersoft.mhash384;
-
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
-import java.util.Iterator;
-
-public final class ByteString implements Iterable<Byte> {
-       
-       private final byte[] data;
-
-       public ByteString(final byte[] data) {
-               this.data = Arrays.copyOf(data, data.length);
-       }
-
-       public ByteString(final String data) {
-               this.data = data.getBytes(StandardCharsets.ISO_8859_1);
-       }
-       
-       public final byte at(final int index) {
-               return data[index];
-       }
-
-       public final int size() {
-               return data.length;
-       }
-
-       public final byte[] toArray() {
-               return Arrays.copyOf(data, data.length);
-       }
-       
-       @Override
-       public final Iterator<Byte> iterator() {
-               return new Iterator<Byte>() {
-                       private int index = 0;
-                       @Override
-                       public final boolean hasNext() {
-                               return (index < data.length);
-                       }
-                       @Override
-                       public final Byte next() {
-                               return data[index++];
-                       }
-               };
-       }
-}
index 31b8aa7..335a2b2 100644 (file)
@@ -23,19 +23,24 @@ package com.muldersoft.mhash384;
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.Iterator;
 import java.util.List;
 
 public final class MHash384 {
-
+       
        //=========================================================================================
        // CONST DATA
        //=========================================================================================
-       
+
        public static final int HASH_LENGTH = 48;
-       private static final List<Integer> LIB_VERSION = Collections.unmodifiableList(Arrays.asList(1, 0, 1));
+
+       private static final int LIB_VERSION_MAJOR = 1;
+       private static final int LIB_VERSION_MINOR = 0;
+       private static final int LIB_VERSION_PATCH = 1;
        
        private static final int TABLE_XOR_SIZE = 257;
        private static final int TABLE_MIX_SIZE = 997;
@@ -1300,13 +1305,106 @@ public final class MHash384 {
                /*996*/ "\u0013\u000C+-+\r$\u0019\u0012)\u0010\r\u000E\"$\u0014)\u0020&,\u001F!,-\u0019/#/,\u001F////'%-&+/-*/+,../"
        );
        
+       private static final List<String> TEST_CASES = Collections.unmodifiableList(Arrays.asList(
+               "",
+               "abc",
+               "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+               "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
+               "Franz jagt im komplett verwahrlosten Taxi quer durch Bayern",
+               "Frank jagt im komplett verwahrlosten Taxi quer durch Bayern",
+               "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.\nDuis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.\nUt wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.\nNam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat.\nDuis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis.\nAt vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, At accusam aliquyam diam diam dolore dolores duo eirmod eos erat, et nonumy sed tempor et et invidunt justo labore Stet clita ea et gubergren, kasd magna no rebum. sanctus sea sed takimata ut vero voluptua. est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat.\nConsetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus.\nLorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.\nDuis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.\nUt wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.\nNam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo.",
+               "4nfPXx\"DhcA7*'\\1;2DMhbL5f%?Yk[2]P=F*RNX*#rFo>+M,h{afxB<m_$=s4&.9~)PSYR^bs&A6JA^'>II/kH''\\%3@4ty{Ji4F|:hOU53mM]l#'^Z1rKoLU2@^g2B2MOZz:R+v5:Cp8eaRe~Z>V&S8,{]akDMsReuuarYB)_uPW]DY+f.!B=V_$H=6TavZk.p.RRF?~zdGoYJncq`+-`ojTmq:669dsEfE0wy|RS[^SzImF(cE}Ox0wLJNjw`Td,)zYgk}v_'0!fJqvV-tWsU]KP6b]Otha)0/o'QYfaIZ2I{#!Z4\"<8s#4\"M$|#;';+Oj}sPTQDNo4ILfVpNC@QIgp.W]s&BjlXm=u`:,\\\":RTh<Q!exDec>aB+`gEl=+:a.BAv8Sf5f?'s]hK&J+]\"u5@5`Lo_Y-\"=|;rAT>FR4\"D=c_aD/?Y\"HaGU^nK[O35cNo=C!y^_1\"AF8YP8,:dYjes1.!!'sNiy?e8Fj2//(vWO>N[b'u_-8pnX(d>^`^uqp9\"}m@#ejYbV**SJ]>|2m'lj,Z~#SxU%p$J1_B!r_f{wTlBW0RLS1Y:&G[l|\\_:amo&LQRJVix|@(^^6`w(ym\"#g,(f8bM=l5t0;m.aH0Mp,S9SdCw\"',*?UQk#g^L1_3:>g+Q6~'L.~2b!Qq.qa6vdMyH&JU9\\b5=QC=E\"EsBssy}G~t#R^pyKyR163bZ@G'|}/5,|#@)c!!Qm2e<ETW#=B3n9fW1B5PlX:bdC/oB}SmF[iXc;gi;1cK$eR%$|9APOTVfISe[*w*4?,k(ktt,Kd56YyY}(2z5e}Y/|FGh_Y3aH)m(e.WYmI~u9YR\"1Hs5v/j-b`T.&S#o)yiglxvhF2d]E<94;(r+BY#g::pP?Gl<di\"z\\jVX}ILca}sW9;O{iH<9kpMO']LR6%\"Jnj}Ys--,bO}$7/sO3i@knb>\"w_m7FT]O9O.qg'$7j.v<|f@p3`r!Kh\\xbZSN[i{2/?X>EF\\R&pqi&>wW!YvjQ)lD9Xt{_Y}TVPRGd>x-Po8,4nfPXx\"DhcA7*'\\1;2DMhbL5f%?Yk[2]P=F*RNX*#rFo>+M,h{afxB<m_$=s4&.9~)PSYR^bs&A6JA^'>II/kH''\\%3@4ty{Ji4F|:hOU53mM]l#'^Z1rKoLU2@^g2B2MOZz:R+v5:Cp8eaRe~Z>V&S8,{]akDMsReuuarYB)_uPW]DY+f.!B=V_$H=6TavZk.p.RRF?~zdGoYJncq`+-`ojTmq:669dsEfE0wy|RS[^SzImF(cE}Ox0wLJNjw`Td,)zYgk}v_'0!fJqvV-tWsU]KP6b]Otha)0/o'QYfaIZ2I{#!Z4\"<8s#4\"M$|#;';+Oj}sPTQDNo4ILfVpNC@QIgp.W]s&BjlXm=u`:,\\\":RTh<Q!exDec>aB+`gEl=+:a.BAv8Sf5f?'s]hK&J+]\"u5@5`Lo_Y-\"=|;rAT>FR4\"D=c_aD/?Y\"HaGU^nK[O35cNo=C!y^_1\"AF8YP8,:dYjes1.!!'sNiy?e8Fj2//(vWO>N[b'u_-8pnX(d>^`^uqp9\"}m@#ejYbV**SJ]>|2m'lj,Z~#SxU%p$J1_B!r_f{wTlBW0RLS1Y:&G[l|\\_:amo&LQRJVix|@(^^6`w(ym\"#g,(f8bM=l5t0;m.aH0Mp,S9SdCw\"',*?UQk#g^L1_3:>g+Q6~'L.~2b!Qq.qa6vdMyH&JU9\\b5=QC=E\"EsBssy}G~t#R^pyKyR163bZ@G'|}/5,|#@)c!!Qm2e<ETW#=B3n9fW1B5PlX:bdC/oB}SmF[iXc;gi;1cK$eR%$|9APOTVfISe[*w*4?,k(ktt,Kd56YyY}(2z5e}Y/|FGh_Y3aH)m(e.WYmI~u9YR\"1Hs5v/j-b`T.&S#o)yiglxvhF2d]E<94;(r+BY#g::pP?Gl<di\"z\\jVX}ILca}sW9;O{iH<9kpMO']LR6%\"Jnj}Ys--,bO}$7/sO3i@knb>\"w_m7FT]O9O.qg'$7j.v<|f@p3`r!Kh\\xbZSN[i{2/?X>EF\\R&pqi&>wW!YvjQ)lD9Xt{_Y}TVPRGd>x-Po8,",
+               "xH-5Pm^ISCqug#4f\"LM6uv/K848USL$H$G>YlzPvSE5(aa&'l@'?oKy`H;jicu=0U!OG#DLI;Ep[.Ev^h:J;Qk1@5pPqfN:q#\\K0p0]Y1lU[CP/5F8={tgMG_|`)314)9]B~Wb&xb=aBHWm(*RP%f@w]?$B|}JTw#{K$Z|$_k=rUl`1Tgvu[Q,6o([y+NJ?VWo7Ge;3s6S*Se#rF3QjPYIU7.S2d\\J!hd7.<zfUdqPmIgbBU_OK1E_-+c*!v.02>|XHsqHJ\"@[g^h*\"8<sZ?sZ_$IC'_[bIuqx0ndk#8,tJ\"jcX>kEjwfyj|\\/..D\"!OY4\\~\\zzZU^ai&'Tf>`ohw2~RH@70Nv(^g)L-K*F'N|?LZYR$-{Fz7]-<[_AS33bsgz{iV@!(B-UTq]w4+M12G1=fsSrJdXJisS)~kU|J8Za,pu*fN.EBY6*|Sr@BXlVU@cb@VEGJ>tnBx|}Nq'=*W'-qJmj$*@!qc^[t-s!<)MgKy?N|~REsh^3I\"jf:E~&xpe6h=aGq>-tEtQ/xV`)FJH?Raa.\"Yt8k'{7S8\"\"NuTR`}iqee5d3ntWj\\)gq$b$[dUOa,T4*3Zlum+l|fb-\\ZBM5U/H!St$QpgwK]lO/Bo]\\!&2#uAI(IKQ`EFsGd~i\"N>wm&K+$TSYh^x>gF!&^B+\",{[unp.>APFH3*dh_%/0Gp-Jqdh=`OFtxwx1zLaZ}?xErfrhd?@X|CEn[NAf=M;N_d'YCn3B/`<c?<|H{h1cJo/0(\"E:aG*7O4t^7IC|'Z0QD-]$pi;b3]+zUq$wk(Tt$^s3!p%4x~CnGkiq6ceDU,7{/X`kv|[J6]pqlis'N\"@SJvcp7Cah)*}`>9$BV-S&-O?mpa5I0,O&FVV|%<mt&,qw\">u5I*JY>gV;$G8QD$HLE_l;O]@tb2)XP$TT?!n6u.rZILDsrc<HW0KO@,!zHg}Yah7HI@;RNsqiToEdUj>Go4IoV>pPN\"X)W(b@Bjm.PEi\"T5TN<dee5{I;m<tI'%+xXx@*f\\m*doIM%};,ye49-@Z#C2]c3BFacDj.Bg&/3CoiJoR$s\\{Oj#Ja:.xL2faN[c(RF)Bfn+6yAzOpBj'tJ/?>rEc'Goo_LYEtJH-r.'K9i,1VmdUvUT{FPc{jOGA~w\"wq\"n9!+sO8x6KXT,fD&AoFFhmH]h~ax~%-J)h9AbA&CYam|,IL|[\\bS*f*)8kO]5:]42:m09FT5d'Gw]l)WA:!r0\\WNmTF>LJdwl&{:uyjswtADS*^s(PvQ4u8!*XDow\\'Q&bT;-p.9@<<2toyiNE\\/A+R>g4u`qyc-^>2:A]F;fA(&55VQR@5f-mzvB^-\\uny|W^i|IstzFr%pR%qTh}'Ee$R0nq0t2TUQp]w`leqN}J)])SGKDSu)_,gF`\"#RmG~NmA0lCAE/Kj0buRr$}CZZ0^gF|dzBv;PKAyAF&sk_S2'~\"b=0\"f!-`J;`fvo+k$3HvU*&hIL*A1D4nc#h0g'I]\"eI1J]\"dffZlcgu+%H'hC}5fOY:*nYbty`c6^>(V?::X}\\[3)9HE71y`mKF@c\\1LD<<|,s^+\\gf*\"n~3lb4;u>~Kn[#:uY0zjTDG=3*m9*AX3f/7]f;nT:f1z1ghXB#ZT*Rwt[v\\l=w/\\A4w#qD\"~}iF;tWi%C5Z|vC8pqv\\[VM8,!&ZC'@6_tINR2TLE[2MSGyuAJs=R'(M@1K+V\"pSw\"F=Gpzom}S2xqbl\\.sMv$*K&60W2&g^ANR_Xs~ssUx1\\y\"%L+U/)v's6BR~aGC!F,;)(S-8eTeA(}D,4!T0H\"Ip*tQYIUXUM$iJ?@(gS][n%FY24u0G:Hh7>49+~]1~l%EWHiC3\\c`x~C;P9&g?=o6OKccHIC2&?bs>\"6{0Uk$D};X~l{cOzPx)uy0SmU<`K;&romGo%av<c'-^W|{p^}4\"t+K)iG>#1uMnvY?^Ato/o1*/+(}wm:Vimc0@M-x*X#-L+ZrI&7DSl(oMqDzk7[nht\"JIu:eiubYipjD;u0t`Gz/Y^1+>?L)uDlP2ggskl,i8aaMr,'.DwR@[O@!7o`&=Rh;yA-.g9I$MNZjZ0VR\"[byEPHu82V26xigkPU{1|1;cE[Nc@w2-p+372dZ=y)U[=au':P[efVUWO+y1y4u2|#\"|R],M<l$mK0~6|<p|G8o-46[byoNMG^W%\\'+F>jvK?4g'V!V[eS#Z[`shmE5o\"j?nWMF|[[ux#P0,?O!L,oi*1d}ik5>$mGt#=</W,7~,BMVgfUbpwb-{9]:SZNLaf-zAf\"5gxtx:_R&+Ej{EdiurnI%Z#A\"qc5PK\"\"x^\\yc*J]TL&EE9z>Xwv}z>YOh]l9G[ZVl;<^Ik^8zr;*$dn$@LT}@|}=t5<3o3'^dC7dFk<f)~|ew1REb:?wUyce=2G:OGuAY-f&>wnU(}r{IA;^Tj8<odqlw_ll<;ky6L27e!H4Ig{a$7ksy{3=?AQ6(K;:*Ax-+2@#Qh[59%0LeM_'^f99*/IeqB{|LE}|P#^UFb<,?TBS$i*ghB6xnddpc/l<@6nF?CDP1<$`=;v|(@vYJ}\\Z1iB<eL/\"QaKZ&zv46pp*H#H&JC7icPB2s@5j0CqWtDCWSo7~gzl?lO=]ovB7gW`dRCc&WW@Z.Jwkyzh\\wY^Eq,@=@|0kgm)iD*x|2^EJdhTL#|eU$\\n(DpeWB[sjOVqNh@!eX:HqJcGoH+;rw6Syp{]fTUm>1Gaz:1'I6WRYN?OTl`;IDX\\D{^#3(!&744;-Ms,:BIouf'PP3@Ec<[9&1#JRceAc_9?:CiHxe63=~\"d&S)SovS75S+s\\p6JkFG}LSmK=f?tdcodC-!%d*tt`iXm'WC!fT>5)99_OUOUAByMpGMbMp<^?g+3p(_y_-tfNod.BC@E4%N0{_Yg-m,PB=_|ID4j<HcKs=>&d\"KC+fe}I03Q<,xbeu$zPL%|`q!}4C(xH+l08*<dz}Zy7<$Dg3<=peH!E{:$QQj}]Ldx(OcVuh:n2:RLPU\\i\\6:~*3X#kyEd1d^&GpX\\.mF2PR*-x;{t|YdTc*\\'#hhG8e.8qTj#wnLr#o/rK&so8,-|3[t6Ws_&riO_n6%&t9-|3HbheYP_=zkV{`VI\"/>laQ\\m^5EfGv&>0'oa}?!W(8W-e.w<Gtq1>^`_|5%^.d~hi!rx'@dmdLicn[M=\"e_s|+p=]S4d)x^M(beqVc4b/Rs@z9+~aJ\\e/oO>g+Ls+\\^/K((:'mMzuBG~|}s|WzKf.U/Z3NJLr6KD*/k7cTut`ru1],quA_c:2ezpj>i8b*6ch*,*oV3[gEs2:|2t1C7$L,+6N$t`KVv+~{cjt=8XvNCBM{,V3Bo!InB\\ONl-,~.Up}$.H(u0:!v)X~hFqI@kOZA6}Ni674G`[LlB'&\\TQX`b@&J82K093'X=][S1>ot+B(!cJG8Y~&:?B+,KsjXdAGm\\Q=*sy,U/SAwmOU`#ERSnuXJavc;|8m3]1wA2):,]K4y4ERzd)R8+NY\\rq-%S8a=0J%U#%cV::8\\a\\oT}99#9(f}}nIhvpa6+Zn>0E&+MhL:dI[x|bzIPwwv>xHZf[%I4L~v2w\"lL-@~cJRqTVhdTO00'#APkQY(Zv1/}\"qN>1b^]=!00}r:Ou%NlMD!3Y_C%AtvGs!fhR~=yrFVJ$eQVjPU\\G1r&j#1522O+LX,N2}q`?PnIRA8y;b{RKT0.-,Nu/5M~uAP~Gl92Qn<9hb`@>.-\"2CL)s7HOo}6@kQ+GY{e+\"UnhJO|Irzp@^\"x+PvRzVai>!~1sz*^`%!ay)|kB)u[Ls;@u}(W*-{gY<ARRq?X:yTX0OfO.dlb{$$94a}1^R&]WO)bAXXZ;ksL@so6T,c+WRlW'{'G8Gn[.Q}H!r<N^%wd,EhH\"dw^&UpP^AIk3Ixg/;vJSiAcUVFk|]-d5V|hjZB@BPs#F[<dpBMLa,V/nXa@O=q?/(tyALK5S!Ih\\\\w4HjHEnW-ednl`c9Xi(wC~%Rp0i_`z#=%_D4FIvk;C;MuGmj/xir\\d-.]yy\\D^!X03g}%7n_9X452YJWN<)76/S~1[s0u+%Ao5&t+q59j379Yp+y:+=/w/x2b`@#GoFSf'o:=vT&i1m\\j%j[OwVz5Dw,H1J%P,7Vtl]~8]b`~cayO4R\\\\n#S9",
+               "XJ}Zpnt1xNNhsl+\"3[9K9bdQnq|v{vk1_,~!L'*Lih=`{o$'y3S}:F\"2MJR\"M,Bw\\=VpoZ$lx+6#DJ[/eURe4=L8;HTpK%sPDf<[7;.K2t@G3z>OCZ0v=V{$;`]K!.(EYCN@dzRX,lr]HygmfFtU;zBL5z;)/Q6{KMpjz5M?A;c$k3Oxc.i!yHF>}_t4/RUc?)HKLv/Y=jZpYJ9Z!Nj53g(ePk$~4)a3|!geP?.Ipy3=\\\"iUw$N_HmXP_yEK8S@{Yq))i=~:>^,K4N5%D<'(Q:0uf&VwqaxDR1%/}n1>~,rHo\"moQmh`y>&Xf_b/w);BmIpM)9_WBxn4w$;-8hiRt%\\3/[q&<^vMq\"2bQSOmqH|o7SjX~?a/Plnn(8Qs7;%E7IR0U^s};njmmlW5f.i(1gr;#9j0f9F^~t<S8MR2&0uo<|#NJe-zmiYOh=cbtD1_<UJW?&w[%hwHoJy$M+z3?RjL55^'M/zYkO5s23&p|n2f^'QbMs!1F*d$8IOV7tPP63Xd}CGHN,hbIwf2Pw.I&*MZ/'}E{^&tS[ouat,%\\R*62_y=,K|xVA^^[=?nw1!xR7D2*N[bMqH0#ZEc5\\zzpKELCE`z[be)$1,EegU0WC|c]4fZ+C3!5l.'?:`/UMv(avO:]Q0v&}4:?PF`z4B1~o*2{HPtx|2%[LS*c<uBVTlHjhFU#&<q=Z:J7XSD&VZASUD+lg*Y|2:xb6.~-cn4A&Yl8mX-9M}G@oP?O<VesD5AKW6*GQ=.C%`03bj}Nv0-Rc)GYyaShuBJ7Rn8`S}Tg5IKTuhjxwN_o/nVC(=VHEDKQ.M#;45l.sSrChuQNtey,{V4$0Fxg2%&iO9C.P3bt@19}*2|EPIysi5yt9|3-@C`b@LmK,!#')8>s+6+`VZOrFtKsCLInbH{QFEgJ.BLXnMhqO@OQGeww#B=]+MS=qmnj~RXx0a4MtgdQ\"7A7^TtguH=,-Nrb$r'`)G_.Xep\\%~{ep;M408\\>MRdp:[C>}?)H1H'#;jA:++z]jiV,)cA.MHb[ZFSK?ROteR!z6Jvs1b0/pZ#y{ByYxAyg]Z*)o#7I=bh8`Jz?LE\"/-h7rlu)<o'9u&c-x3zDA=yltl~X5GsjxF#S)TdnyqmQVZqpLPFHU0\\Tm137~|`V\"7Qh*<d8mRCG$O^M(``R,wN=A9o[>.rC<LNKgqKorRT`ST~{\\5.2|]qj<|H@D@:|cCfXSft/_](*>xnJwp54(vz,]~_*=3e:Zr^&\\<]x?>)XC<g6?5|HE}vb-g>=f;6Vn.VDlDfMNb1pE#60={}].`?klW}\"Tu(v)U0nPqh[#U,;C&\"&iB%G%7PM9*JF3h?zXD?Yyrs_G36DJQ5Lbu[R/qYQ]8>[ePf{v-~.Sh_15.MU48:eoX<Py~$)^JQ)b;q+qTEr@57f`[xGoJZBh;Gub-<>qU>+7,G<RY-*2r3S%z)0_8!(Q1TdX%A}q_oR7e+U'|U,zQo2bi(HHX#?!FF%}LsgGK\"iX+JM:nT6jc5g0fvs3FWvP/+H/@-MoZhK\"nXoJ|mU)&Wv$1$ALW_~vI;aQm~e\\\\}yp``O!xele#OF=*@=J89g<8h_GS>DXcyg9.{*Uqt.3P34rFS'@.*z}T^KW>WkA?\"J_BOk`;zX\\w88y1o:s~~0ldTf[Mx^*>^DG4T9|:B3#q8&)IgjwpVc[_sSKxeO#0]gaA4PQO@*)'>C||ziIh|$hY@{:g3~<.$p0|S$$%5LJcvS4xURN`v~\"5$hLqRzC]wRJ4|yqB<x<1Z[U!2pst7)v^|\\9,_CS06+|LGe7FOjT$vOHOO&?n-UD'ecuS|]6S^>3D-0qJ_q{?\\9^?DF|S+n#5e6~xVY)p4?<R\\<>IS/<#ln5d{F:zf8S}][b7[tbX$RN'c+xppU`vPuN:?LPD_$dnrwsB&sEH)[-+<5D}mqb`MGLMQ&~aEqGgAMklbTt#f}r:*qkf_cE1ptxTZ?/m&\\J[QN\"30vu2IY9^$kR\"a</r'Z]*v=-'4~Kr1XSM%E<m_h|0MS!\";8@HpzMHzNC^W3}$GY)I;Zf]`A,PM)tnfZM06&M)ywHCBW_F6uan._M)'.2o^\\,/OlNgXvanc(4T)e;_b]d{O6@0xHm)f\\9RbT.hLh#-7:ty.ROvVI&sT0%qiil+qh:VD#~ElW%9lY:kz3{CFxu2E:p^`Hl2^xOB,geo%oHJ4f#vFfuuNpw/l06>Vm/:KJ'ZMWNBQ_ZgRoXJ7+\"z\"0%SLCP%<m}Qm[$<I-&oo:%hW;emi\"8/Y~0@g!^H~(GK{a~>C'9]i)Q~Vna!CsG#dN$Q_Q]Nqx{)8pz0xHH^JcY|irqpk/\".b=q1EI2*hEGY)93\"3.zEBl36&[{5Nl4+w&3EG'in\"ti@[W:*8E7D!z{|D`?|Um--1TV7CCoOP5AB#O=GD^Kl^XenqL:HI_eULs#ee)ssNN>sQ!Gv]@es0@IWwA'M}%XJ!p_g$RCj\\N\\T99EHiM~6`Ggx]K~noCP5*\\BMUP-7C@.Eqe7H8~leX94f}m;Cd@5-zSWe76426}s*QN-fmN(vG$)]bA7c]-^>P%+<fe[];914Xmvxu22a%:nPM6`(djF6:A`b+O&%t,hE%ZXg~#^dWh!MyPYbYvZjBgETs5IC-^3]wDw00PhHOc%%_l17!s6ky>'i~u_)V!M@tV[Fs7{Ls-b?|*vi;^__f8q(yVEd>3FxrOTwep/*<N|_KIS%GXIw*dtyUj<^(Q3N:SUy)ftu5v}?=Tmcnt_e-MkAMwwK(er_gG@WJoWCJg<6<om%r(~WvsQK4O[#n#(CGAxKfi'buWalivC!`85M2|\\88|4T/6,j$`/`-L@y\"yf~\\LYXU5a2)xf10;$S*JTaL4PubiG$Iv<sq^EzSI`;2FcGx~VlRV\"}N&#C|6f<B\"{8H@NbV=.Aox|t#)sB~$(I$r'j6B9`JCP[wr!%~{;Yn@\\U_#XjlBw^KkCv,.;o?5Gfo[7556-:[g2qV_>3]ao.<9lW-A!3FK?lF&@Z+_S(AxuHn6[,2TZf8rT?8#8)kInq#h@'z]~<`CP4B2{hh`+&5r5k3Y9(eC\\X0#lJ1d32R^BrQxqxlni+_H74D_|oU^Gr}pt>S_/)7__.pn0y&I-[S*Dc#(kZET1vzHGJ/T7p?:_vhl=}XK1XRyXw0$uM,6k`6R~d+--,p56~GG\\+VviT<^Uz':0B*5{P6^m<ZX=/,TRS_{dNLo.G.Wcr8a.y;-[9tW|ZP?&HbflZX\\^TyDGjk?9n}[sgn+xme`p#|G:fsaD3o[BQwWDeEDJ3Ga6?`Qh&|,J(0aY$;]QSl8\\a|lcD0wp*L?5'q}(,+SiQBWt3[[J<VA^S#_?4izlrJ68st|vGOuu8.c).=w7]/Jxdv`a7UREDEE9)x9`%;<WU,8pep#k_1[hiF=gpZ,jsb;;Pky0ZPYvf[24$+0sff|k7sratO?;X-A0Y][oRz\\rCL^_B7sIT3BL9O~Z\\t0C\"d\\FU7Q(V_0T]#k.+^SiNY95uho>{rc{-Pu\"%<$!`Ibg/w;]j$Mi<q.Lk$$Ep17zi0%mZD9X\\dWe{;oh,f[nf<0mCe>B<1,$'>1E/opGsF,fa-`/e_ZE\\U*94v[qJ.0p46=#$6QHZavH!f^t,K)Al4g5=,PbY'u4$K:mJ\"(i9Cpw$0TiLM=cVNO+()Yp`zGZ4'8H|+^R:)hXju/[G\"qfo=H*,Ep8Jc?zP0U-,%M2+-lGR/s:|eV*%C~v(?257CTDR0quCOL6g081H)O$$bqwF4^n\\e1nFvPNw:/0oC\\tu&.D+LX~N*LtPPAr0gc:QF+W2/X;q_#P20HS!HpJu:#sY~.>$t;siwyr^[3iPeo[}$!4tciN.<3,l6TGZ>Yc0DyoU<mIwW6M.WEAd|$;u+sr,_;ievqi`D-_U04^d3o.!?imF^*/U/GU?6*4\\>|6Sxi(,nAc,][@WPx:vP%Vi0'57TVHCnmg`x~Ib5^Y~_G#=Aw$[.ydp6,z\\R\"fOeCV~&&1(K2(gNXj]^[=3Pq{7<~?]>J$o8(?Ox8ZsT:p_5.@L(hBNVV<Vj?{+K\\bBY*t0>c*)1z/K*<'CE3)k}Ys'S$Tj?Wvb.fb+y|\\YSz.30DS*jJcWM7LB7&6y@^{(sCk+yYkVXfZ?;I~5$$&<-n:n*X:$:K==q7i`(W(,Jl=p.$qb2GlX-M5zX!=TUklG,\\q8-XQZ)eX#!PywvOIh'MP>^pZk3Qp89_\\]jkFIWg:sr=5@t]yzkp(Zy;!t!Ywv`j)nJOG]a?at-(-|yJ_2BRYc[L-,69?]7VBldT84<jUq+vT`dqcnHvWdmQXY/)Odg6;:Nd].R<&=@dAcrZR&|E}:~x'#n3<FRvYSh'#:%.1b:5Gv,(9#U3rZz1>22Je?8Y1D;0hN-av]ukt#Z*jti)\\x5\\j\\wVMx?eiNOY)WZ7Nd%;J~g~\"\\fI9R_bcDmh&b)JJhm%7A/,AExs><t*CkYo#*#6V$vjVox(>%|/17s.gx+zPwq1Fj|\\IO|<0=402Hk'^w>L=lj9bBZxlemVKL]8#/{T\\Y%kijgV\"Z:,EufM$4vmBo\\BXNWMs24E?,\"H\\xoJ@2f'/9b#T*@Vb7`G8oB~xh5cFtTogxNEKwg1'@!ZkP6A=XgG,u3,ug`;Vs@tT3L@q#u`_NQh5OSxKy]:*:ME%F@oY8M9N>}5Wq4'F2}'Ad]4?vECQ~kjiEwzx9<S*jAL~uv/anO]#A;<]HkxJtvgjK>Noa:/vANqg.@(2p[T}Fnm)FJ|w*/pr|Pep&2[|QQr?I11RU!;8=H/+l`IVd;(\\W_hf1+-UM=\\Jv+mA!aka[bNMP05UO|hJh=5_*ynen=\"e/jL+?D$D$\"cqa>Z04325OmYY#fsN^`|wM/mJ&\"nkT;\"0*2}Y|Aj>A*-VP$m~c,572u%IQWkdD)PBz'h|};h(@c\"g(A1,'IrpM=j&=XLKrzj\\3U{OpPr0i,^8/D9f>pw/vST,v[8nt2Dj6r/HQp8i%9a}\"PHM9).8A;}tru3\"rgZG{TviH6J:^1bCm,Qs\\_%Z6`5_}9N$!Fs(}R#6_`Kp1qE\\!fRbC%_YcM>8Z_u/)QG]:fHH8\\?v[k>uM:B=Pr%Fw'+2`D]A2S\\]s^0VkVRE!r{U$Cw@63)KEPi@OjMoOs7*R$,mUCF5w#HY#L]7TolPqZ+_G,vj[j&EfLroszQ=;xf%*imysb36M0hu219*&Uf\"z6nmgZN<'dy^Z+O!.)nXVjVt$90eWX7{rk\"Gssv{Osc?wwi3`{CJL,Rj`IvI/r2GOPoJnP`yr([s@<mn$&WPyWQrJb>Phw`<b`)v$sUdy-}$a8\"j!{_]Xz>9ijL6^C9fg[aG,K>704PCozH-2u)0'|>T-e*?_0oy@vdd,sk88XzuK*T0gu#%\\\\;dU2hlv5hJ~M{NMqH*<lw_V,UE[z=\"($i,KTPhWn0'.tf09C$%?JXhoHDrH#[~c\\zwZLrUezwGaidk/lS7N,{d=|E=?^,DgYx^F;>~yaX31:8v4]bOzC#A2bC<j_T|nf8u*1*2nLM6FS/%]3EkEcp@n]({sW':O)fe61G\";'PodS[)F7vO:TXvSg2e}W2]ompFoMJve<Y1>\\GT/Lg\\QwP]x*;c\\t)FGlk.`*&#+q\\C3{T~X<X0t&iWqWhezEN0_#CH,&V7ESf@\"=-1(*1DEK!DXVM]pQn~]#8<8#cH9ue,f4;|;8djB0`R+Q5/|EqX-hG|M2wBRC@|Xu[D!q^YrD6'7X-vMqc).Ti!6]mCof^Ez+T,G~aCh-J6Z~*rn0{ErGXvw?:jo.#%6XvfVEW#`-UXw9N0%t15=wK:sr3ogcq>XVO/8E3kXW3T7EU_Nq$qJ[i'r;y381:;WF`1\\E^6?5up#I`Jae{DOTe;!v'z,rB\"O87w0p>ztTCdKUF!+twJ&G^:6-$^`cE(h1mm2f=>O\\Ei1HGa7RJ@v,g>7',#*,1Lr!JK{&{0*}jz506;O:j)NS>EqmCXWO.(])bR!RG`}Om:!N9vym1?LIh|%}i{yh<R=$NW\\8v'\\g_7F&48ZW!r=nwc?2pN!%/?#zf2/4)i1pR!2Bf$;p>Dvc.\\~\\-IB-e~NAI7puTv<i?zjWiS0.]Cy&fbnz+ryp\"ZR,R|h!Vkn\\u8.,FolaErIi;DJr\\cv)5HHT>%B]7@uw_a_oV<,C&9p4$6x)B)Ry+/WOx?F]jeZYx-/!si02iG-*2Ry-K_=|KT]iph232\"D'*h<kW*Q-&fFOcW~Q/0LX6ej#f|(-Elf}pd6_>\\?)-]2GtVcIlE..W.$U?aNT6*R:?&qoHpS~4J.DefMz>oN>k#-^st/Z#a*46oV\\/\"XdQ7^a8TTSn31;f?SDfG]`$joE9o;/4+m_2,$HB5NO@qxg/c(B?(a)>0V2b(N$Vm>WYK(}#<T_,W\\fV`W-(&w{`}];vs<_6bKp/^P8~#R'1yo*6Pu79Es(4Rb6hcf=nodmZKwcXjw|T_^C3/CC;kL1{XRy\"|!^eo`S$qoDe\"raPjR5,>(Bi\\5xSR$gh][ck-a5r7^`(_Rh>h`WCA3zYgV+,.]kG!#R~@Mzh+c^^<\"BleMT)%E%%I/DMLkDB^kc\"X_LhXci\"J\\Sp4kl>ATGrl/|:bR1YDK\\uMfT.8*nO#Fn(L)a30zR=A$(p[sqr`J:n}lm>=?\"O-k{AG5$q,%-\"L<C=3(Z(.@}yg;*dVI3urMow#m1a$s&FQ:N.~m+5O\\aqh-GuWaK\\Br.Kh=|CUJ<O)J@S$}U+Y}EQ6t>t[fh~'X1fgd&\\s5eg)aG>sn^9o||$dBu{/EWFWTe[q1%}rD{w-|fb\\Op+f)WJ~^eY'Rpa(rpweHY(P&$vM\\m85MNX1^fXgV5*Lp|5vMC%EtTbDw|[w7>%)WT8fn_8R3'&f5UlQ/CfhSgP.%mZy5c3y.+:4n)TRa*hEAAm/*S#-W$FA#5k4<Q*U@miDS>c35=!A\\40RrKZ!DL)UCH_}@Js[cv~@g3W*mF~8aFKx6#`%Gkpy:}.9/G$[~c|<#K^h*X9iOnf9LZ>2?T\"Yu+8o502BtY[pFMyh(XDw@}?vP~tYRWB:c,JJ)c6kt>DfKOMR&t'ZC$#n(q;t(sE[mMk.nC>G\\Z4\"JrXd7i@1-Vhn5JVt7#4j2v<T6Uk+sm&Lui_mw:o8Gxz)d5='HkplV+Mp!FK,<Ju#m?gwi{b8L1r-H5_\"9Vc8pYvnYtQo=7-d\\4FV^,_[[WxaBV(9x.wEsB$;91L;ITij&)R!K!O)>Q0f&QxkJ`v&ouWX1IEc?kzbC.{%got+%Xrc=wiNT2Ldr(C;(6cKeH7XE6:(x9|ZK$`7:4`t^Bl?Sd2vl=d;GU)1YK8zku~T1RmT~K0iPQIc};+EPjv;]7|N}`2)[A11E+z7~\\/0xo$*ncPR}j@;tu\"JQtRXP:f5g!b`b?lom\"Zoc->kKup,XkeX??{:VqmY]?%/\\|7MPJ=MIB1zmQE\":'}XY14\"n7KI5n@Q*H=9qr;X[X4o/gX@N}&C01m_.v;{IVXhfy46*u%JTK&#]~zX@s3qg]g?iwXF',s'?VBbp|HP:*m)5;au8l@u4[,gZu4j~gQ=(E]Lm-kB8I{Eo$\\x<mUYd;XfRRuQgP4RM|$HX.+7{<OQJjQ6sp}qny$SA=`AH!+s5U6agLKs_$|N_2#[oq^k8h~u@Acj6w+fX*Pz*a#CHFR,Mb+Rr#-tbFe.e/HgED,8YTj&($O.uYzq72T*,H.x?4);5R.4rm/R>/3YDAbXl]i7PBpe7<E=Hj3EE,f!(N.#*G]gO7Ya*;!fAyb+Pe'ueljzr/kgvDCR7)B]ElgfEk&%77_lw8(*!wvMP^~gh/mXN<5[S{S6EU@7.F&%q|.l:<rBb/#t?>3(=DQ*/1M3g`s.v.27ba~tFDT}gDHH@}1D+9~48}k7_ZD=sZ}j42.ri/H!h=MC_Nh%gdHDF9ub6ZS;F;;Ip/]a}t\\_!.UAYf`x(?cXaym{}~kZ(&^Rc[rN^omkuNBu/qL8'U79dl4*Y_h_`*)I76?70yd@e*Li%MRs+x]&I]FtkUU7kt_jvtkj}0TJtrqh%ajL,I[J1S^RA1UpzGt\"iL/@EIp~}Kx7{nH0PDzA;']##Uh>KzE[RT1V-yl$lP?m'>~Ud'OAQ__V~XA4PYK76-eT4b_Jlvs}B~/QS\"WSooZX{,?GgF\"q]9J/FeI\\Yy\\KL66[rmwwE_.L3ayBXi66>(E&FCQaL!~+kZstp&`@j!j+>c{<DVd0|.#9;=/l/,r)b=M3w(6g/8VH}u1):O{d0GwK,qPL;tEB%a(1)\"NtV4^"
+       ));
+       
        //=========================================================================================
-       // HASH STATE
+       // UTILITY CLASS
        //=========================================================================================
+
+       public final static class ByteString implements Iterable<Byte> {
+               
+               private final byte[] data;
+
+               public ByteString(final byte[] data) {
+                       this.data = Arrays.copyOf(data, data.length);
+               }
+
+               public ByteString(final String data) {
+                       this.data = data.getBytes(StandardCharsets.ISO_8859_1);
+               }
+               
+               public final byte at(final int index) {
+                       return data[index];
+               }
+
+               public final int size() {
+                       return data.length;
+               }
+
+               public final byte[] toArray() {
+                       return Arrays.copyOf(data, data.length);
+               }
+               
+               @Override
+               public final Iterator<Byte> iterator() {
+                       return new Iterator<Byte>() {
+                               private int index = 0;
+                               @Override
+                               public final boolean hasNext() {
+                                       return (index < data.length);
+                               }
+                               @Override
+                               public final Byte next() {
+                                       return data[index++];
+                               }
+                       };
+               }
+               
+               public String toString() {
+                       final StringBuilder sb = new StringBuilder();
+                       for (final byte b : data) {
+                               sb.append(String.format("%02X", b));
+                       }
+                       return sb.toString();
+               }
+       }
        
-       private int m_rowIdx = 0;
+       //=========================================================================================
+       // INITIALIZATION
+       //=========================================================================================
+       
+       private final static List<ByteString> buildTable(final String... initializer) {
+               final List<ByteString> table = new ArrayList<ByteString>(initializer.length);
+               for(int i = 0; i < initializer.length; ++i) {
+                       final ByteString rowData = new ByteString(initializer[i]);
+                       if(rowData.size() != HASH_LENGTH) {
+                               throw new IllegalArgumentException("Invalid initialization data!");
+                       }
+                       table.add(rowData);
+               }
+               return Collections.unmodifiableList(table);
+       }
+       
+       static {
+               if(TABLE_XOR.size() != TABLE_XOR_SIZE) {
+                       throw new IllegalArgumentException("Invalid initialization data!");
+               }
+               if(TABLE_MIX.size() != TABLE_MIX_SIZE) {
+                       throw new IllegalArgumentException("Invalid initialization data!");
+               }
+       }
+       
+       //=========================================================================================
+       // HASH STATE
+       //=========================================================================================
+
+       /*hash buffer*/
        private final byte[] m_digest = new byte[HASH_LENGTH];
        
+       /*row index*/
+       private int m_rowIdx = 0;
+
        //=========================================================================================
        // PUBLIC API
        //=========================================================================================
@@ -1316,6 +1414,7 @@ public final class MHash384 {
                final ByteString xor = TABLE_XOR.get(b & 0xFF);
                for (int i = 0; i < HASH_LENGTH; ++i) {
                        final int shuffleIdx = mix.at(i);
+                       assert(shuffleIdx >= i);
                        final byte temp = m_digest[shuffleIdx];
                        m_digest[shuffleIdx] = m_digest[i];
                        m_digest[i] = (byte)(temp ^ xor.at(i));
@@ -1371,31 +1470,15 @@ public final class MHash384 {
        }
        
        public final static List<Integer> getVersion() {
-               return LIB_VERSION;
+               final List<Integer> version = Arrays.asList(LIB_VERSION_MAJOR, LIB_VERSION_MINOR, LIB_VERSION_PATCH);
+               return Collections.unmodifiableList(version);
        }
-
-       //=========================================================================================
-       // INTERNAL FUNCTIONS
-       //=========================================================================================
        
-       private final static List<ByteString> buildTable(final String... initializer) {
-               final List<ByteString> table = new ArrayList<ByteString>(initializer.length);
-               for(int i = 0; i < initializer.length; ++i) {
-                       final ByteString rowData = new ByteString(initializer[i]);
-                       if(rowData.size() != HASH_LENGTH) {
-                               throw new IllegalArgumentException("Invalid initialization data!");
-                       }
-                       table.add(rowData);
-               }
-               return Collections.unmodifiableList(table);
-       }
-
-       static {
-               if(TABLE_XOR.size() != TABLE_XOR_SIZE) {
-                       throw new IllegalArgumentException("Invalid initialization data!");
-               }
-               if(TABLE_MIX.size() != TABLE_MIX_SIZE) {
-                       throw new IllegalArgumentException("Invalid initialization data!");
+       public final static void selfTest() {
+               for(final String testStr : TEST_CASES) {
+                       final MHash384 mhash384 = new MHash384();
+                       mhash384.update(new ByteString(testStr));
+                       System.out.println(mhash384.digest().toString());
                }
        }
 }
index bbf629a..203af8b 100644 (file)
 #endif
 #endif
 
-/*Version*/
-#define MHASH_384_VERSION_MAJOR UINT32_C(1)
-#define MHASH_384_VERSION_MINOR UINT32_C(0)
-#define MHASH_384_VERSION_PATCH UINT32_C(1)
-
 /*MSVC compat*/
 #ifndef MHASH_INLINE
 #ifdef _MSC_VER
@@ -67,6 +62,17 @@ namespace internals {
 /* CONSTANTS                                                                */
 /* ======================================================================== */
 
+/*Version*/
+#ifdef __cplusplus
+static const uint16_t MHASH_384_VERSION_MAJOR = UINT32_C(1);
+static const uint16_t MHASH_384_VERSION_MINOR = UINT32_C(0);
+static const uint16_t MHASH_384_VERSION_PATCH = UINT32_C(1);
+#else
+#define MHASH_384_VERSION_MAJOR UINT32_C(1)
+#define MHASH_384_VERSION_MINOR UINT32_C(0)
+#define MHASH_384_VERSION_PATCH UINT32_C(1)
+#endif
+
 /*Hash and table size definitions*/
 #ifdef __cplusplus
 static const uint16_t MHASH_384_LEN = UINT16_C(48);
index 46f2c2d..ecadea0 100644 (file)
@@ -53,27 +53,50 @@ using namespace mhash_384::internals;
 while(0)
 
 /*Test vectors and reference outputs*/
-#define TEST_COUNT 8
+#define TEST_COUNT 10
 static const char *const TEST_VECTOR[TEST_COUNT] =
 {
-       "", "A", "AA", "AAA",
+       "",
+       "abc",
+       "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+       "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
        "Franz jagt im komplett verwahrlosten Taxi quer durch Bayern",
        "Frank jagt im komplett verwahrlosten Taxi quer durch Bayern",
        "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.\nDuis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.\nUt wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.\nNam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat.\nDuis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis.\nAt vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, At accusam aliquyam diam diam dolore dolores duo eirmod eos erat, et nonumy sed tempor et et invidunt justo labore Stet clita ea et gubergren, kasd magna no rebum. sanctus sea sed takimata ut vero voluptua. est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat.\nConsetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus.\nLorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.\nDuis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.\nUt wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.\nNam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo.",
-       "@/NZhR/&=#8<Ojh=K_zHo;Q.sF|rZNVSiaN(9|gjylXU\"qaXs7j@l7**aCss$=`Ar3qNQ1E1JEf\\+[~J_u!b!9,f(+T2jV8yKodz8jIF]V5Zg@#M]eC?=i=.Ct%smOnj:7{r:spEaiOcz<PxZ^y$zzdfi]\\/g2.Up%/'YO]W8Be^.PA`W!11?85;0F'\\oPPLu7c\\Gb2|De<6Y0AH_a{<OB;3t.f2*V?O_5GA,4QFI~Xqi_$5T5ko)#Rb4\\9YZ$d!R,fJ)1@Y}f5]&dUq3z{WaDw.qbKuHbCy\"x.Gi}dG#RAR@6yUfTLLA>z?+nia%s@?rl/Tla/d]1rN]DB|;;k3D%6#8{(-\\o#>)6He`D@Q?aF:?lwX0K%0V\"Y6qk:A0tCMAZ&uVDFWks8R{x]l4te]\"IowlsH[&qv-<?m|bvNC#rZTD1L'x~LH(-.}e{!RbwrALR3n5sl(y'9PKSKr:t}4g|^k6\\Z#w\\Z7:QIZ;Df{hfb,80]fJ-^*hR\")[0ND#?s\"!i>OIl/ht,%98_@F7)KX9,i1(CaJd?!`F/r43T1Vrf%NzrncO$f;'a\"$?pr},r<[^@t^||%l[@PEC9O1kn](`RgA%l[#^a:ot$'3&:|[FB#KAN#2!]kYE\"Sx!Hua.Uq>x2z2'D8/m{'eiB+J5|r;K4g'oayq{K_~;yM#pf5-}HBn>uOJeh55~${r$9a1=kLg!bBi+TF7FR_j>`@b@&BvZ@=2r~M3Y.Q*\"fPE[;D[pHOV>G,1jm*oMsE\\t.b5GqKJMum<kMs\\C}43;Z^@[H)^e.&US9UMpTje(E*4*>^VlH)R^l2)tBHfqS8yYo=Ya^}5'&P>F,G+6Fu7=U.gi!>k1\\Uq6D&=t=g]&Cz>Uka7($wc/hz=cSGqJ#T3Tv0FK&WqYj.YT5u:h1x@<;#c\\YDP\\atcxi`7W2Kg2eD9DyCB=s\"=$M6\\diQ;~#N@zYtH-{m#fV%(BN>c'!%\\7v3f\\x{\\_.76e?P=l\\Vf.,L3="
+       "4nfPXx\"DhcA7*'\\1;2DMhbL5f%?Yk[2]P=F*RNX*#rFo>+M,h{afxB<m_$=s4&.9~)PSYR^bs&A6JA^'>II/kH''\\%3@4ty{Ji4F|:hOU53mM]l#'^Z1rKoLU2@^g2B2MOZz:R+v5:Cp8eaRe~Z>V&S8,{]akDMsReuuarYB)_uPW]DY+f.!B=V_$H=6TavZk.p.RRF?~zdGoYJncq`+-`ojTmq:669dsEfE0wy|RS[^SzImF(cE}Ox0wLJNjw`Td,)zYgk}v_'0!fJqvV-tWsU]KP6b]Otha)0/o'QYfaIZ2I{#!Z4\"<8s#4\"M$|#;';+Oj}sPTQDNo4ILfVpNC@QIgp.W]s&BjlXm=u`:,\\\":RTh<Q!exDec>aB+`gEl=+:a.BAv8Sf5f?'s]hK&J+]\"u5@5`Lo_Y-\"=|;rAT>FR4\"D=c_aD/?Y\"HaGU^nK[O35cNo=C!y^_1\"AF8YP8,:dYjes1.!!'sNiy?e8Fj2//(vWO>N[b'u_-8pnX(d>^`^uqp9\"}m@#ejYbV**SJ]>|2m'lj,Z~#SxU%p$J1_B!r_f{wTlBW0RLS1Y:&G[l|\\_:amo&LQRJVix|@(^^6`w(ym\"#g,(f8bM=l5t0;m.aH0Mp,S9SdCw\"',*?UQk#g^L1_3:>g+Q6~'L.~2b!Qq.qa6vdMyH&JU9\\b5=QC=E\"EsBssy}G~t#R^pyKyR163bZ@G'|}/5,|#@)c!!Qm2e<ETW#=B3n9fW1B5PlX:bdC/oB}SmF[iXc;gi;1cK$eR%$|9APOTVfISe[*w*4?,k(ktt,Kd56YyY}(2z5e}Y/|FGh_Y3aH)m(e.WYmI~u9YR\"1Hs5v/j-b`T.&S#o)yiglxvhF2d]E<94;(r+BY#g::pP?Gl<di\"z\\jVX}ILca}sW9;O{iH<9kpMO']LR6%\"Jnj}Ys--,bO}$7/sO3i@knb>\"w_m7FT]O9O.qg'$7j.v<|f@p3`r!Kh\\xbZSN[i{2/?X>EF\\R&pqi&>wW!YvjQ)lD9Xt{_Y}TVPRGd>x-Po8,4nfPXx\"DhcA7*'\\1;2DMhbL5f%?Yk[2]P=F*RNX*#rFo>+M,h{afxB<m_$=s4&.9~)PSYR^bs&A6JA^'>II/kH''\\%3@4ty{Ji4F|:hOU53mM]l#'^Z1rKoLU2@^g2B2MOZz:R+v5:Cp8eaRe~Z>V&S8,{]akDMsReuuarYB)_uPW]DY+f.!B=V_$H=6TavZk.p.RRF?~zdGoYJncq`+-`ojTmq:669dsEfE0wy|RS[^SzImF(cE}Ox0wLJNjw`Td,)zYgk}v_'0!fJqvV-tWsU]KP6b]Otha)0/o'QYfaIZ2I{#!Z4\"<8s#4\"M$|#;';+Oj}sPTQDNo4ILfVpNC@QIgp.W]s&BjlXm=u`:,\\\":RTh<Q!exDec>aB+`gEl=+:a.BAv8Sf5f?'s]hK&J+]\"u5@5`Lo_Y-\"=|;rAT>FR4\"D=c_aD/?Y\"HaGU^nK[O35cNo=C!y^_1\"AF8YP8,:dYjes1.!!'sNiy?e8Fj2//(vWO>N[b'u_-8pnX(d>^`^uqp9\"}m@#ejYbV**SJ]>|2m'lj,Z~#SxU%p$J1_B!r_f{wTlBW0RLS1Y:&G[l|\\_:amo&LQRJVix|@(^^6`w(ym\"#g,(f8bM=l5t0;m.aH0Mp,S9SdCw\"',*?UQk#g^L1_3:>g+Q6~'L.~2b!Qq.qa6vdMyH&JU9\\b5=QC=E\"EsBssy}G~t#R^pyKyR163bZ@G'|}/5,|#@)c!!Qm2e<ETW#=B3n9fW1B5PlX:bdC/oB}SmF[iXc;gi;1cK$eR%$|9APOTVfISe[*w*4?,k(ktt,Kd56YyY}(2z5e}Y/|FGh_Y3aH)m(e.WYmI~u9YR\"1Hs5v/j-b`T.&S#o)yiglxvhF2d]E<94;(r+BY#g::pP?Gl<di\"z\\jVX}ILca}sW9;O{iH<9kpMO']LR6%\"Jnj}Ys--,bO}$7/sO3i@knb>\"w_m7FT]O9O.qg'$7j.v<|f@p3`r!Kh\\xbZSN[i{2/?X>EF\\R&pqi&>wW!YvjQ)lD9Xt{_Y}TVPRGd>x-Po8,",
+       "xH-5Pm^ISCqug#4f\"LM6uv/K848USL$H$G>YlzPvSE5(aa&'l@'?oKy`H;jicu=0U!OG#DLI;Ep[.Ev^h:J;Qk1@5pPqfN:q#\\K0p0]Y1lU[CP/5F8={tgMG_|`)314)9]B~Wb&xb=aBHWm(*RP%f@w]?$B|}JTw#{K$Z|$_k=rUl`1Tgvu[Q,6o([y+NJ?VWo7Ge;3s6S*Se#rF3QjPYIU7.S2d\\J!hd7.<zfUdqPmIgbBU_OK1E_-+c*!v.02>|XHsqHJ\"@[g^h*\"8<sZ?sZ_$IC'_[bIuqx0ndk#8,tJ\"jcX>kEjwfyj|\\/..D\"!OY4\\~\\zzZU^ai&'Tf>`ohw2~RH@70Nv(^g)L-K*F'N|?LZYR$-{Fz7]-<[_AS33bsgz{iV@!(B-UTq]w4+M12G1=fsSrJdXJisS)~kU|J8Za,pu*fN.EBY6*|Sr@BXlVU@cb@VEGJ>tnBx|}Nq'=*W'-qJmj$*@!qc^[t-s!<)MgKy?N|~REsh^3I\"jf:E~&xpe6h=aGq>-tEtQ/xV`)FJH?Raa.\"Yt8k'{7S8\"\"NuTR`}iqee5d3ntWj\\)gq$b$[dUOa,T4*3Zlum+l|fb-\\ZBM5U/H!St$QpgwK]lO/Bo]\\!&2#uAI(IKQ`EFsGd~i\"N>wm&K+$TSYh^x>gF!&^B+\",{[unp.>APFH3*dh_%/0Gp-Jqdh=`OFtxwx1zLaZ}?xErfrhd?@X|CEn[NAf=M;N_d'YCn3B/`<c?<|H{h1cJo/0(\"E:aG*7O4t^7IC|'Z0QD-]$pi;b3]+zUq$wk(Tt$^s3!p%4x~CnGkiq6ceDU,7{/X`kv|[J6]pqlis'N\"@SJvcp7Cah)*}`>9$BV-S&-O?mpa5I0,O&FVV|%<mt&,qw\">u5I*JY>gV;$G8QD$HLE_l;O]@tb2)XP$TT?!n6u.rZILDsrc<HW0KO@,!zHg}Yah7HI@;RNsqiToEdUj>Go4IoV>pPN\"X)W(b@Bjm.PEi\"T5TN<dee5{I;m<tI'%+xXx@*f\\m*doIM%};,ye49-@Z#C2]c3BFacDj.Bg&/3CoiJoR$s\\{Oj#Ja:.xL2faN[c(RF)Bfn+6yAzOpBj'tJ/?>rEc'Goo_LYEtJH-r.'K9i,1VmdUvUT{FPc{jOGA~w\"wq\"n9!+sO8x6KXT,fD&AoFFhmH]h~ax~%-J)h9AbA&CYam|,IL|[\\bS*f*)8kO]5:]42:m09FT5d'Gw]l)WA:!r0\\WNmTF>LJdwl&{:uyjswtADS*^s(PvQ4u8!*XDow\\'Q&bT;-p.9@<<2toyiNE\\/A+R>g4u`qyc-^>2:A]F;fA(&55VQR@5f-mzvB^-\\uny|W^i|IstzFr%pR%qTh}'Ee$R0nq0t2TUQp]w`leqN}J)])SGKDSu)_,gF`\"#RmG~NmA0lCAE/Kj0buRr$}CZZ0^gF|dzBv;PKAyAF&sk_S2'~\"b=0\"f!-`J;`fvo+k$3HvU*&hIL*A1D4nc#h0g'I]\"eI1J]\"dffZlcgu+%H'hC}5fOY:*nYbty`c6^>(V?::X}\\[3)9HE71y`mKF@c\\1LD<<|,s^+\\gf*\"n~3lb4;u>~Kn[#:uY0zjTDG=3*m9*AX3f/7]f;nT:f1z1ghXB#ZT*Rwt[v\\l=w/\\A4w#qD\"~}iF;tWi%C5Z|vC8pqv\\[VM8,!&ZC'@6_tINR2TLE[2MSGyuAJs=R'(M@1K+V\"pSw\"F=Gpzom}S2xqbl\\.sMv$*K&60W2&g^ANR_Xs~ssUx1\\y\"%L+U/)v's6BR~aGC!F,;)(S-8eTeA(}D,4!T0H\"Ip*tQYIUXUM$iJ?@(gS][n%FY24u0G:Hh7>49+~]1~l%EWHiC3\\c`x~C;P9&g?=o6OKccHIC2&?bs>\"6{0Uk$D};X~l{cOzPx)uy0SmU<`K;&romGo%av<c'-^W|{p^}4\"t+K)iG>#1uMnvY?^Ato/o1*/+(}wm:Vimc0@M-x*X#-L+ZrI&7DSl(oMqDzk7[nht\"JIu:eiubYipjD;u0t`Gz/Y^1+>?L)uDlP2ggskl,i8aaMr,'.DwR@[O@!7o`&=Rh;yA-.g9I$MNZjZ0VR\"[byEPHu82V26xigkPU{1|1;cE[Nc@w2-p+372dZ=y)U[=au':P[efVUWO+y1y4u2|#\"|R],M<l$mK0~6|<p|G8o-46[byoNMG^W%\\'+F>jvK?4g'V!V[eS#Z[`shmE5o\"j?nWMF|[[ux#P0,?O!L,oi*1d}ik5>$mGt#=</W,7~,BMVgfUbpwb-{9]:SZNLaf-zAf\"5gxtx:_R&+Ej{EdiurnI%Z#A\"qc5PK\"\"x^\\yc*J]TL&EE9z>Xwv}z>YOh]l9G[ZVl;<^Ik^8zr;*$dn$@LT}@|}=t5<3o3'^dC7dFk<f)~|ew1REb:?wUyce=2G:OGuAY-f&>wnU(}r{IA;^Tj8<odqlw_ll<;ky6L27e!H4Ig{a$7ksy{3=?AQ6(K;:*Ax-+2@#Qh[59%0LeM_'^f99*/IeqB{|LE}|P#^UFb<,?TBS$i*ghB6xnddpc/l<@6nF?CDP1<$`=;v|(@vYJ}\\Z1iB<eL/\"QaKZ&zv46pp*H#H&JC7icPB2s@5j0CqWtDCWSo7~gzl?lO=]ovB7gW`dRCc&WW@Z.Jwkyzh\\wY^Eq,@=@|0kgm)iD*x|2^EJdhTL#|eU$\\n(DpeWB[sjOVqNh@!eX:HqJcGoH+;rw6Syp{]fTUm>1Gaz:1'I6WRYN?OTl`;IDX\\D{^#3(!&744;-Ms,:BIouf'PP3@Ec<[9&1#JRceAc_9?:CiHxe63=~\"d&S)SovS75S+s\\p6JkFG}LSmK=f?tdcodC-!%d*tt`iXm'WC!fT>5)99_OUOUAByMpGMbMp<^?g+3p(_y_-tfNod.BC@E4%N0{_Yg-m,PB=_|ID4j<HcKs=>&d\"KC+fe}I03Q<,xbeu$zPL%|`q!}4C(xH+l08*<dz}Zy7<$Dg3<=peH!E{:$QQj}]Ldx(OcVuh:n2:RLPU\\i\\6:~*3X#kyEd1d^&GpX\\.mF2PR*-x;{t|YdTc*\\'#hhG8e.8qTj#wnLr#o/rK&so8,-|3[t6Ws_&riO_n6%&t9-|3HbheYP_=zkV{`VI\"/>laQ\\m^5EfGv&>0'oa}?!W(8W-e.w<Gtq1>^`_|5%^.d~hi!rx'@dmdLicn[M=\"e_s|+p=]S4d)x^M(beqVc4b/Rs@z9+~aJ\\e/oO>g+Ls+\\^/K((:'mMzuBG~|}s|WzKf.U/Z3NJLr6KD*/k7cTut`ru1],quA_c:2ezpj>i8b*6ch*,*oV3[gEs2:|2t1C7$L,+6N$t`KVv+~{cjt=8XvNCBM{,V3Bo!InB\\ONl-,~.Up}$.H(u0:!v)X~hFqI@kOZA6}Ni674G`[LlB'&\\TQX`b@&J82K093'X=][S1>ot+B(!cJG8Y~&:?B+,KsjXdAGm\\Q=*sy,U/SAwmOU`#ERSnuXJavc;|8m3]1wA2):,]K4y4ERzd)R8+NY\\rq-%S8a=0J%U#%cV::8\\a\\oT}99#9(f}}nIhvpa6+Zn>0E&+MhL:dI[x|bzIPwwv>xHZf[%I4L~v2w\"lL-@~cJRqTVhdTO00'#APkQY(Zv1/}\"qN>1b^]=!00}r:Ou%NlMD!3Y_C%AtvGs!fhR~=yrFVJ$eQVjPU\\G1r&j#1522O+LX,N2}q`?PnIRA8y;b{RKT0.-,Nu/5M~uAP~Gl92Qn<9hb`@>.-\"2CL)s7HOo}6@kQ+GY{e+\"UnhJO|Irzp@^\"x+PvRzVai>!~1sz*^`%!ay)|kB)u[Ls;@u}(W*-{gY<ARRq?X:yTX0OfO.dlb{$$94a}1^R&]WO)bAXXZ;ksL@so6T,c+WRlW'{'G8Gn[.Q}H!r<N^%wd,EhH\"dw^&UpP^AIk3Ixg/;vJSiAcUVFk|]-d5V|hjZB@BPs#F[<dpBMLa,V/nXa@O=q?/(tyALK5S!Ih\\\\w4HjHEnW-ednl`c9Xi(wC~%Rp0i_`z#=%_D4FIvk;C;MuGmj/xir\\d-.]yy\\D^!X03g}%7n_9X452YJWN<)76/S~1[s0u+%Ao5&t+q59j379Yp+y:+=/w/x2b`@#GoFSf'o:=vT&i1m\\j%j[OwVz5Dw,H1J%P,7Vtl]~8]b`~cayO4R\\\\n#S9",
+       "XJ}Zpnt1xNNhsl+\"3[9K9bdQnq|v{vk1_,~!L'*Lih=`{o$'y3S}:F\"2MJR\"M,Bw\\=VpoZ$lx+6#DJ[/eURe4=L8;HTpK%sPDf<[7;.K2t@G3z>OCZ0v=V{$;`]K!.(EYCN@dzRX,lr]HygmfFtU;zBL5z;)/Q6{KMpjz5M?A;c$k3Oxc.i!yHF>}_t4/RUc?)HKLv/Y=jZpYJ9Z!Nj53g(ePk$~4)a3|!geP?.Ipy3=\\\"iUw$N_HmXP_yEK8S@{Yq))i=~:>^,K4N5%D<'(Q:0uf&VwqaxDR1%/}n1>~,rHo\"moQmh`y>&Xf_b/w);BmIpM)9_WBxn4w$;-8hiRt%\\3/[q&<^vMq\"2bQSOmqH|o7SjX~?a/Plnn(8Qs7;%E7IR0U^s};njmmlW5f.i(1gr;#9j0f9F^~t<S8MR2&0uo<|#NJe-zmiYOh=cbtD1_<UJW?&w[%hwHoJy$M+z3?RjL55^'M/zYkO5s23&p|n2f^'QbMs!1F*d$8IOV7tPP63Xd}CGHN,hbIwf2Pw.I&*MZ/'}E{^&tS[ouat,%\\R*62_y=,K|xVA^^[=?nw1!xR7D2*N[bMqH0#ZEc5\\zzpKELCE`z[be)$1,EegU0WC|c]4fZ+C3!5l.'?:`/UMv(avO:]Q0v&}4:?PF`z4B1~o*2{HPtx|2%[LS*c<uBVTlHjhFU#&<q=Z:J7XSD&VZASUD+lg*Y|2:xb6.~-cn4A&Yl8mX-9M}G@oP?O<VesD5AKW6*GQ=.C%`03bj}Nv0-Rc)GYyaShuBJ7Rn8`S}Tg5IKTuhjxwN_o/nVC(=VHEDKQ.M#;45l.sSrChuQNtey,{V4$0Fxg2%&iO9C.P3bt@19}*2|EPIysi5yt9|3-@C`b@LmK,!#')8>s+6+`VZOrFtKsCLInbH{QFEgJ.BLXnMhqO@OQGeww#B=]+MS=qmnj~RXx0a4MtgdQ\"7A7^TtguH=,-Nrb$r'`)G_.Xep\\%~{ep;M408\\>MRdp:[C>}?)H1H'#;jA:++z]jiV,)cA.MHb[ZFSK?ROteR!z6Jvs1b0/pZ#y{ByYxAyg]Z*)o#7I=bh8`Jz?LE\"/-h7rlu)<o'9u&c-x3zDA=yltl~X5GsjxF#S)TdnyqmQVZqpLPFHU0\\Tm137~|`V\"7Qh*<d8mRCG$O^M(``R,wN=A9o[>.rC<LNKgqKorRT`ST~{\\5.2|]qj<|H@D@:|cCfXSft/_](*>xnJwp54(vz,]~_*=3e:Zr^&\\<]x?>)XC<g6?5|HE}vb-g>=f;6Vn.VDlDfMNb1pE#60={}].`?klW}\"Tu(v)U0nPqh[#U,;C&\"&iB%G%7PM9*JF3h?zXD?Yyrs_G36DJQ5Lbu[R/qYQ]8>[ePf{v-~.Sh_15.MU48:eoX<Py~$)^JQ)b;q+qTEr@57f`[xGoJZBh;Gub-<>qU>+7,G<RY-*2r3S%z)0_8!(Q1TdX%A}q_oR7e+U'|U,zQo2bi(HHX#?!FF%}LsgGK\"iX+JM:nT6jc5g0fvs3FWvP/+H/@-MoZhK\"nXoJ|mU)&Wv$1$ALW_~vI;aQm~e\\\\}yp``O!xele#OF=*@=J89g<8h_GS>DXcyg9.{*Uqt.3P34rFS'@.*z}T^KW>WkA?\"J_BOk`;zX\\w88y1o:s~~0ldTf[Mx^*>^DG4T9|:B3#q8&)IgjwpVc[_sSKxeO#0]gaA4PQO@*)'>C||ziIh|$hY@{:g3~<.$p0|S$$%5LJcvS4xURN`v~\"5$hLqRzC]wRJ4|yqB<x<1Z[U!2pst7)v^|\\9,_CS06+|LGe7FOjT$vOHOO&?n-UD'ecuS|]6S^>3D-0qJ_q{?\\9^?DF|S+n#5e6~xVY)p4?<R\\<>IS/<#ln5d{F:zf8S}][b7[tbX$RN'c+xppU`vPuN:?LPD_$dnrwsB&sEH)[-+<5D}mqb`MGLMQ&~aEqGgAMklbTt#f}r:*qkf_cE1ptxTZ?/m&\\J[QN\"30vu2IY9^$kR\"a</r'Z]*v=-'4~Kr1XSM%E<m_h|0MS!\";8@HpzMHzNC^W3}$GY)I;Zf]`A,PM)tnfZM06&M)ywHCBW_F6uan._M)'.2o^\\,/OlNgXvanc(4T)e;_b]d{O6@0xHm)f\\9RbT.hLh#-7:ty.ROvVI&sT0%qiil+qh:VD#~ElW%9lY:kz3{CFxu2E:p^`Hl2^xOB,geo%oHJ4f#vFfuuNpw/l06>Vm/:KJ'ZMWNBQ_ZgRoXJ7+\"z\"0%SLCP%<m}Qm[$<I-&oo:%hW;emi\"8/Y~0@g!^H~(GK{a~>C'9]i)Q~Vna!CsG#dN$Q_Q]Nqx{)8pz0xHH^JcY|irqpk/\".b=q1EI2*hEGY)93\"3.zEBl36&[{5Nl4+w&3EG'in\"ti@[W:*8E7D!z{|D`?|Um--1TV7CCoOP5AB#O=GD^Kl^XenqL:HI_eULs#ee)ssNN>sQ!Gv]@es0@IWwA'M}%XJ!p_g$RCj\\N\\T99EHiM~6`Ggx]K~noCP5*\\BMUP-7C@.Eqe7H8~leX94f}m;Cd@5-zSWe76426}s*QN-fmN(vG$)]bA7c]-^>P%+<fe[];914Xmvxu22a%:nPM6`(djF6:A`b+O&%t,hE%ZXg~#^dWh!MyPYbYvZjBgETs5IC-^3]wDw00PhHOc%%_l17!s6ky>'i~u_)V!M@tV[Fs7{Ls-b?|*vi;^__f8q(yVEd>3FxrOTwep/*<N|_KIS%GXIw*dtyUj<^(Q3N:SUy)ftu5v}?=Tmcnt_e-MkAMwwK(er_gG@WJoWCJg<6<om%r(~WvsQK4O[#n#(CGAxKfi'buWalivC!`85M2|\\88|4T/6,j$`/`-L@y\"yf~\\LYXU5a2)xf10;$S*JTaL4PubiG$Iv<sq^EzSI`;2FcGx~VlRV\"}N&#C|6f<B\"{8H@NbV=.Aox|t#)sB~$(I$r'j6B9`JCP[wr!%~{;Yn@\\U_#XjlBw^KkCv,.;o?5Gfo[7556-:[g2qV_>3]ao.<9lW-A!3FK?lF&@Z+_S(AxuHn6[,2TZf8rT?8#8)kInq#h@'z]~<`CP4B2{hh`+&5r5k3Y9(eC\\X0#lJ1d32R^BrQxqxlni+_H74D_|oU^Gr}pt>S_/)7__.pn0y&I-[S*Dc#(kZET1vzHGJ/T7p?:_vhl=}XK1XRyXw0$uM,6k`6R~d+--,p56~GG\\+VviT<^Uz':0B*5{P6^m<ZX=/,TRS_{dNLo.G.Wcr8a.y;-[9tW|ZP?&HbflZX\\^TyDGjk?9n}[sgn+xme`p#|G:fsaD3o[BQwWDeEDJ3Ga6?`Qh&|,J(0aY$;]QSl8\\a|lcD0wp*L?5'q}(,+SiQBWt3[[J<VA^S#_?4izlrJ68st|vGOuu8.c).=w7]/Jxdv`a7UREDEE9)x9`%;<WU,8pep#k_1[hiF=gpZ,jsb;;Pky0ZPYvf[24$+0sff|k7sratO?;X-A0Y][oRz\\rCL^_B7sIT3BL9O~Z\\t0C\"d\\FU7Q(V_0T]#k.+^SiNY95uho>{rc{-Pu\"%<$!`Ibg/w;]j$Mi<q.Lk$$Ep17zi0%mZD9X\\dWe{;oh,f[nf<0mCe>B<1,$'>1E/opGsF,fa-`/e_ZE\\U*94v[qJ.0p46=#$6QHZavH!f^t,K)Al4g5=,PbY'u4$K:mJ\"(i9Cpw$0TiLM=cVNO+()Yp`zGZ4'8H|+^R:)hXju/[G\"qfo=H*,Ep8Jc?zP0U-,%M2+-lGR/s:|eV*%C~v(?257CTDR0quCOL6g081H)O$$bqwF4^n\\e1nFvPNw:/0oC\\tu&.D+LX~N*LtPPAr0gc:QF+W2/X;q_#P20HS!HpJu:#sY~.>$t;siwyr^[3iPeo[}$!4tciN.<3,l6TGZ>Yc0DyoU<mIwW6M.WEAd|$;u+sr,_;ievqi`D-_U04^d3o.!?imF^*/U/GU?6*4\\>|6Sxi(,nAc,][@WPx:vP%Vi0'57TVHCnmg`x~Ib5^Y~_G#=Aw$[.ydp6,z\\R\"fOeCV~&&1(K2(gNXj]^[=3Pq{7<~?]>J$o8(?Ox8ZsT:p_5.@L(hBNVV<Vj?{+K\\bBY*t0>c*)1z/K*<'CE3)k}Ys'S$Tj?Wvb.fb+y|\\YSz.30DS*jJcWM7LB7&6y@^{(sCk+yYkVXfZ?;I~5$$&<-n:n*X:$:K==q7i`(W(,Jl=p.$qb2GlX-M5zX!=TUklG,\\q8-XQZ)eX#!PywvOIh'MP>^pZk3Qp89_\\]jkFIWg:sr=5@t]yzkp(Zy;!t!Ywv`j)nJOG]a?at-(-|yJ_2BRYc[L-,69?]7VBldT84<jUq+vT`dqcnHvWdmQXY/)Odg6;:Nd].R<&=@dAcrZR&|E}:~x'#n3<FRvYSh'#:%.1b:5Gv,(9#U3rZz1>22Je?8Y1D;0hN-av]ukt#Z*jti)\\x5\\j\\wVMx?eiNOY)WZ7Nd%;J~g~\"\\fI9R_bcDmh&b)JJhm%7A/,AExs><t*CkYo#*#6V$vjVox(>%|/17s.gx+zPwq1Fj|\\IO|<0=402Hk'^w>L=lj9bBZxlemVKL]8#/{T\\Y%kijgV\"Z:,EufM$4vmBo\\BXNWMs24E?,\"H\\xoJ@2f'/9b#T*@Vb7`G8oB~xh5cFtTogxNEKwg1'@!ZkP6A=XgG,u3,ug`;Vs@tT3L@q#u`_NQh5OSxKy]:*:ME%F@oY8M9N>}5Wq4'F2}'Ad]4?vECQ~kjiEwzx9<S*jAL~uv/anO]#A;<]HkxJtvgjK>Noa:/vANqg.@(2p[T}Fnm)FJ|w*/pr|Pep&2[|QQr?I11RU!;8=H/+l`IVd;(\\W_hf1+-UM=\\Jv+mA!aka[bNMP05UO|hJh=5_*ynen=\"e/jL+?D$D$\"cqa>Z04325OmYY#fsN^`|wM/mJ&\"nkT;\"0*2}Y|Aj>A*-VP$m~c,572u%IQWkdD)PBz'h|};h(@c\"g(A1,'IrpM=j&=XLKrzj\\3U{OpPr0i,^8/D9f>pw/vST,v[8nt2Dj6r/HQp8i%9a}\"PHM9).8A;}tru3\"rgZG{TviH6J:^1bCm,Qs\\_%Z6`5_}9N$!Fs(}R#6_`Kp1qE\\!fRbC%_YcM>8Z_u/)QG]:fHH8\\?v[k>uM:B=Pr%Fw'+2`D]A2S\\]s^0VkVRE!r{U$Cw@63)KEPi@OjMoOs7*R$,mUCF5w#HY#L]7TolPqZ+_G,vj[j&EfLroszQ=;xf%*imysb36M0hu219*&Uf\"z6nmgZN<'dy^Z+O!.)nXVjVt$90eWX7{rk\"Gssv{Osc?wwi3`{CJL,Rj`IvI/r2GOPoJnP`yr([s@<mn$&WPyWQrJb>Phw`<b`)v$sUdy-}$a8\"j!{_]Xz>9ijL6^C9fg[aG,K>704PCozH-2u)0'|>T-e*?_0oy@vdd,sk88XzuK*T0gu#%\\\\;dU2hlv5hJ~M{NMqH*<lw_V,UE[z=\"($i,KTPhWn0'.tf09C$%?JXhoHDrH#[~c\\zwZLrUezwGaidk/lS7N,{d=|E=?^,DgYx^F;>~yaX31:8v4]bOzC#A2bC<j_T|nf8u*1*2nLM6FS/%]3EkEcp@n]({sW':O)fe61G\";'PodS[)F7vO:TXvSg2e}W2]ompFoMJve<Y1>\\GT/Lg\\QwP]x*;c\\t)FGlk.`*&#+q\\C3{T~X<X0t&iWqWhezEN0_#CH,&V7ESf@\"=-1(*1DEK!DXVM]pQn~]#8<8#cH9ue,f4;|;8djB0`R+Q5/|EqX-hG|M2wBRC@|Xu[D!q^YrD6'7X-vMqc).Ti!6]mCof^Ez+T,G~aCh-J6Z~*rn0{ErGXvw?:jo.#%6XvfVEW#`-UXw9N0%t15=wK:sr3ogcq>XVO/8E3kXW3T7EU_Nq$qJ[i'r;y381:;WF`1\\E^6?5up#I`Jae{DOTe;!v'z,rB\"O87w0p>ztTCdKUF!+twJ&G^:6-$^`cE(h1mm2f=>O\\Ei1HGa7RJ@v,g>7',#*,1Lr!JK{&{0*}jz506;O:j)NS>EqmCXWO.(])bR!RG`}Om:!N9vym1?LIh|%}i{yh<R=$NW\\8v'\\g_7F&48ZW!r=nwc?2pN!%/?#zf2/4)i1pR!2Bf$;p>Dvc.\\~\\-IB-e~NAI7puTv<i?zjWiS0.]Cy&fbnz+ryp\"ZR,R|h!Vkn\\u8.,FolaErIi;DJr\\cv)5HHT>%B]7@uw_a_oV<,C&9p4$6x)B)Ry+/WOx?F]jeZYx-/!si02iG-*2Ry-K_=|KT]iph232\"D'*h<kW*Q-&fFOcW~Q/0LX6ej#f|(-Elf}pd6_>\\?)-]2GtVcIlE..W.$U?aNT6*R:?&qoHpS~4J.DefMz>oN>k#-^st/Z#a*46oV\\/\"XdQ7^a8TTSn31;f?SDfG]`$joE9o;/4+m_2,$HB5NO@qxg/c(B?(a)>0V2b(N$Vm>WYK(}#<T_,W\\fV`W-(&w{`}];vs<_6bKp/^P8~#R'1yo*6Pu79Es(4Rb6hcf=nodmZKwcXjw|T_^C3/CC;kL1{XRy\"|!^eo`S$qoDe\"raPjR5,>(Bi\\5xSR$gh][ck-a5r7^`(_Rh>h`WCA3zYgV+,.]kG!#R~@Mzh+c^^<\"BleMT)%E%%I/DMLkDB^kc\"X_LhXci\"J\\Sp4kl>ATGrl/|:bR1YDK\\uMfT.8*nO#Fn(L)a30zR=A$(p[sqr`J:n}lm>=?\"O-k{AG5$q,%-\"L<C=3(Z(.@}yg;*dVI3urMow#m1a$s&FQ:N.~m+5O\\aqh-GuWaK\\Br.Kh=|CUJ<O)J@S$}U+Y}EQ6t>t[fh~'X1fgd&\\s5eg)aG>sn^9o||$dBu{/EWFWTe[q1%}rD{w-|fb\\Op+f)WJ~^eY'Rpa(rpweHY(P&$vM\\m85MNX1^fXgV5*Lp|5vMC%EtTbDw|[w7>%)WT8fn_8R3'&f5UlQ/CfhSgP.%mZy5c3y.+:4n)TRa*hEAAm/*S#-W$FA#5k4<Q*U@miDS>c35=!A\\40RrKZ!DL)UCH_}@Js[cv~@g3W*mF~8aFKx6#`%Gkpy:}.9/G$[~c|<#K^h*X9iOnf9LZ>2?T\"Yu+8o502BtY[pFMyh(XDw@}?vP~tYRWB:c,JJ)c6kt>DfKOMR&t'ZC$#n(q;t(sE[mMk.nC>G\\Z4\"JrXd7i@1-Vhn5JVt7#4j2v<T6Uk+sm&Lui_mw:o8Gxz)d5='HkplV+Mp!FK,<Ju#m?gwi{b8L1r-H5_\"9Vc8pYvnYtQo=7-d\\4FV^,_[[WxaBV(9x.wEsB$;91L;ITij&)R!K!O)>Q0f&QxkJ`v&ouWX1IEc?kzbC.{%got+%Xrc=wiNT2Ldr(C;(6cKeH7XE6:(x9|ZK$`7:4`t^Bl?Sd2vl=d;GU)1YK8zku~T1RmT~K0iPQIc};+EPjv;]7|N}`2)[A11E+z7~\\/0xo$*ncPR}j@;tu\"JQtRXP:f5g!b`b?lom\"Zoc->kKup,XkeX??{:VqmY]?%/\\|7MPJ=MIB1zmQE\":'}XY14\"n7KI5n@Q*H=9qr;X[X4o/gX@N}&C01m_.v;{IVXhfy46*u%JTK&#]~zX@s3qg]g?iwXF',s'?VBbp|HP:*m)5;au8l@u4[,gZu4j~gQ=(E]Lm-kB8I{Eo$\\x<mUYd;XfRRuQgP4RM|$HX.+7{<OQJjQ6sp}qny$SA=`AH!+s5U6agLKs_$|N_2#[oq^k8h~u@Acj6w+fX*Pz*a#CHFR,Mb+Rr#-tbFe.e/HgED,8YTj&($O.uYzq72T*,H.x?4);5R.4rm/R>/3YDAbXl]i7PBpe7<E=Hj3EE,f!(N.#*G]gO7Ya*;!fAyb+Pe'ueljzr/kgvDCR7)B]ElgfEk&%77_lw8(*!wvMP^~gh/mXN<5[S{S6EU@7.F&%q|.l:<rBb/#t?>3(=DQ*/1M3g`s.v.27ba~tFDT}gDHH@}1D+9~48}k7_ZD=sZ}j42.ri/H!h=MC_Nh%gdHDF9ub6ZS;F;;Ip/]a}t\\_!.UAYf`x(?cXaym{}~kZ(&^Rc[rN^omkuNBu/qL8'U79dl4*Y_h_`*)I76?70yd@e*Li%MRs+x]&I]FtkUU7kt_jvtkj}0TJtrqh%ajL,I[J1S^RA1UpzGt\"iL/@EIp~}Kx7{nH0PDzA;']##Uh>KzE[RT1V-yl$lP?m'>~Ud'OAQ__V~XA4PYK76-eT4b_Jlvs}B~/QS\"WSooZX{,?GgF\"q]9J/FeI\\Yy\\KL66[rmwwE_.L3ayBXi66>(E&FCQaL!~+kZstp&`@j!j+>c{<DVd0|.#9;=/l/,r)b=M3w(6g/8VH}u1):O{d0GwK,qPL;tEB%a(1)\"NtV4^"
 };
 static const uint8_t TEST_RESULT[TEST_COUNT][MHASH_384_LEN] =
 {
-       { 0x99,0x81,0xA5,0xEC,0x65,0x62,0xB1,0xC7,0x49,0x51,0x78,0x94,0x59,0x73,0x1B,0xAF,0xA7,0x48,0x0F,0x9D,0x9E,0x9A,0x19,0xCC,0x3C,0xA1,0x04,0x63,0x0C,0xA9,0xAB,0x62,0xFD,0x6E,0x6C,0x62,0x42,0xED,0x98,0x92,0xF9,0x95,0xD2,0xA8,0x0D,0xC2,0x62,0x1F },
-       { 0xB7,0xF7,0x1D,0x1B,0x1D,0xE6,0xA9,0xD4,0x15,0x5B,0x8A,0x9F,0xBB,0x2B,0xB1,0x9C,0x30,0x40,0x9F,0x74,0x06,0xCB,0x0F,0x4C,0x39,0x7D,0x99,0x7F,0xDE,0xA4,0x68,0x6F,0x98,0x9E,0xF5,0x44,0x48,0x22,0xF1,0x37,0x89,0x6F,0x9D,0xC5,0x05,0x41,0x45,0xF8 },
-       { 0x34,0x34,0x80,0x11,0x15,0x14,0xF5,0xFA,0x8C,0x89,0x68,0xEF,0x2B,0x0D,0x4B,0xF1,0x26,0xC4,0x07,0x7C,0xAC,0xBD,0x02,0x41,0xF6,0x25,0x81,0xFF,0xD4,0x43,0x98,0x7C,0xBF,0xE6,0x29,0x41,0x7B,0x3E,0xA0,0x5E,0xC6,0xCA,0x74,0x52,0xBD,0x24,0x4E,0x0F },
-       { 0x8A,0xA7,0x24,0x9E,0x43,0x96,0x1C,0x90,0x27,0x53,0xF1,0x53,0xA5,0x07,0xA1,0xDE,0xE3,0xC4,0x17,0xD2,0x74,0x13,0x79,0x32,0xD3,0x87,0x15,0xFE,0xFB,0x14,0x73,0xAA,0xDD,0xB9,0x14,0x77,0x58,0x01,0x7C,0xFD,0xD6,0x89,0x45,0x68,0x99,0x79,0x7A,0x05 },
-       { 0x99,0x04,0x23,0x92,0x45,0xCF,0x29,0x9F,0x5F,0x4A,0xD4,0x00,0x1D,0xD4,0x92,0x61,0x53,0x80,0x01,0xB1,0xA9,0x4D,0xF4,0x97,0x5E,0x10,0x2F,0x75,0x22,0x90,0xD1,0x59,0x0D,0x3A,0xFA,0x3A,0xA1,0xD0,0xF4,0x70,0xD6,0x77,0x67,0xA3,0x05,0xF9,0x26,0x36 },
-       { 0x30,0x7D,0xEF,0xE2,0x9B,0xC3,0x30,0x57,0x4D,0x79,0xAA,0x2B,0x0C,0xAB,0x7C,0x4F,0xAF,0x8D,0xCB,0x73,0x5D,0xF2,0xDD,0xDA,0x5D,0x8E,0x5F,0x23,0x3C,0x28,0x1B,0xAF,0xA9,0x25,0xCC,0x72,0x33,0xE4,0x7A,0x44,0xEC,0xA3,0xBB,0x23,0x62,0x76,0x9E,0x5C },
-       { 0x56,0xD1,0x98,0x42,0x26,0x38,0x71,0x60,0x92,0x3D,0xBB,0x51,0xD4,0x5C,0x9B,0x79,0x1E,0x50,0xA5,0xB9,0xD9,0x31,0x3B,0x5D,0x6D,0x96,0x3C,0xE1,0xC4,0xF5,0xF8,0xEA,0x36,0x6C,0x56,0x11,0x02,0x63,0x3E,0x37,0x43,0xCC,0xE5,0x57,0xBA,0xDA,0xFF,0xA6 },
-       { 0xA2,0x87,0xB6,0x63,0x40,0xD0,0x6E,0xFA,0x50,0x26,0xD1,0x36,0x37,0xB7,0x75,0x7F,0x44,0x8D,0xB6,0x3B,0x9B,0x5B,0xAC,0x12,0xAD,0x2B,0x4C,0x4A,0x45,0xB8,0xB9,0xAE,0x30,0x3C,0x04,0xE3,0xE6,0xC0,0x45,0x96,0x14,0x1E,0x4F,0xD1,0x50,0x53,0x68,0x77 }
+       { 0x86, 0x03, 0x84, 0x37, 0xA0, 0x03, 0x00, 0x40, 0xC1, 0xC9, 0xC1, 0x6B, 0x9D, 0xE2, 0x8D, 0x82, 0x1D, 0x94, 0x59, 0x3C, 0xB7, 0xDD, 0xA8, 0xB1, 0x56, 0xFF, 0x9A, 0xE3, 0x34, 0x26, 0x4C, 0x2E, 0x88, 0x35, 0xB6, 0x00, 0x2D, 0x96, 0x65, 0x7A, 0x37, 0x30, 0x41, 0x9F, 0x5E, 0x43, 0xF2, 0x02 },
+       { 0x11, 0x53, 0x49, 0x9D, 0xA6, 0xB3, 0x58, 0x7A, 0xC0, 0xA8, 0x8A, 0x80, 0x32, 0xE8, 0xCE, 0x16, 0x2F, 0x42, 0xA1, 0x1A, 0x62, 0x5F, 0xFB, 0x11, 0x91, 0x69, 0x27, 0xE4, 0xEC, 0x76, 0x62, 0xA0, 0x8F, 0x55, 0x52, 0x5F, 0x48, 0xEA, 0x03, 0x63, 0x93, 0x56, 0x86, 0xEA, 0x69, 0x02, 0x07, 0xD3 },
+       { 0xA4, 0x6A, 0x55, 0x8A, 0xD1, 0x9A, 0xAE, 0xFA, 0x44, 0x6F, 0x33, 0xFC, 0x6D, 0xE1, 0x3C, 0xFE, 0x2D, 0x21, 0x34, 0x51, 0x0A, 0xDE, 0xBB, 0x65, 0xFD, 0x16, 0x8E, 0xFF, 0xB9, 0xCD, 0xFC, 0xF7, 0x35, 0x9A, 0x44, 0x88, 0x25, 0xA0, 0xC8, 0x8D, 0x5F, 0xF2, 0xF2, 0x3F, 0x4F, 0xE8, 0xFA, 0xFB },
+       { 0x64, 0x13, 0xDA, 0x65, 0x91, 0x94, 0xFE, 0xED, 0x3B, 0x5C, 0x16, 0xC8, 0x97, 0xBA, 0xAA, 0x25, 0xD1, 0xF3, 0x6E, 0x0B, 0x72, 0xF1, 0x8E, 0x45, 0xB9, 0xF4, 0xB3, 0xF6, 0xB9, 0xF7, 0xF8, 0xD5, 0xEC, 0x9C, 0x16, 0x9E, 0x85, 0x5D, 0x8B, 0xD1, 0xEF, 0x4B, 0x5C, 0x9C, 0xF8, 0x82, 0x22, 0x4D },
+       { 0xA5, 0x21, 0x92, 0x02, 0xF3, 0x73, 0x23, 0x61, 0x24, 0x70, 0xD5, 0x95, 0x95, 0x54, 0x17, 0xD8, 0x2C, 0xFE, 0x15, 0xBA, 0x81, 0xAC, 0xDB, 0xA5, 0x14, 0x1D, 0xED, 0x04, 0x07, 0xBF, 0x27, 0x12, 0xF4, 0x3E, 0x0E, 0xD1, 0x05, 0x1D, 0x79, 0xD2, 0x5B, 0x2D, 0xCE, 0x83, 0xE9, 0xD6, 0x16, 0xB3 },
+       { 0xC8, 0x14, 0x7F, 0x57, 0x3E, 0x02, 0xC2, 0x73, 0x08, 0x7E, 0x01, 0x1C, 0xB1, 0x58, 0xB5, 0xF3, 0xD9, 0xE8, 0xCB, 0x9C, 0x74, 0x79, 0x79, 0x18, 0x7E, 0x3A, 0xFB, 0x6A, 0xAB, 0x9F, 0x9C, 0xE9, 0x56, 0x07, 0xA6, 0x27, 0xA2, 0x5C, 0x88, 0x99, 0x11, 0xAB, 0xFA, 0x1D, 0x20, 0x25, 0xFD, 0x07 },
+       { 0x0F, 0xE9, 0x8E, 0xB3, 0x4A, 0xB7, 0xBD, 0x2F, 0xB1, 0xE2, 0x79, 0xE3, 0xB9, 0x9E, 0xCD, 0x36, 0x72, 0xCD, 0x0A, 0xB6, 0x3F, 0x6C, 0x5B, 0x74, 0xEA, 0xB8, 0x8E, 0x07, 0xE6, 0x4C, 0xA6, 0x27, 0xF7, 0xDC, 0xE7, 0x22, 0xE0, 0xD9, 0xB6, 0x60, 0x1B, 0x6B, 0x5E, 0x03, 0x43, 0xD1, 0x30, 0x4A },
+       { 0x59, 0x4C, 0x45, 0xF7, 0xE2, 0x15, 0xD6, 0x00, 0xED, 0xD5, 0x55, 0xC5, 0x09, 0xC2, 0x5E, 0x19, 0x84, 0x8D, 0x0B, 0x57, 0xE9, 0xE1, 0x71, 0xD4, 0x45, 0x07, 0xD4, 0xDB, 0xA3, 0xD9, 0x11, 0xDB, 0xCB, 0x11, 0xB1, 0xE4, 0xBF, 0x47, 0x53, 0x92, 0xC8, 0x3E, 0x70, 0x0C, 0xC8, 0x00, 0xC7, 0x37 },
+       { 0x27, 0x95, 0x42, 0x54, 0x2D, 0xE5, 0x1E, 0xA8, 0x0E, 0x58, 0x5C, 0xF6, 0x84, 0x07, 0x3A, 0x06, 0xFC, 0x28, 0x7A, 0xD7, 0x46, 0x8B, 0xF4, 0xB8, 0x57, 0x6D, 0x23, 0xF3, 0x39, 0xFB, 0x94, 0xC3, 0x9B, 0xB2, 0xAA, 0xF4, 0x79, 0xE0, 0x0A, 0x1C, 0x23, 0x9A, 0xFC, 0x07, 0x28, 0xF0, 0xDF, 0xCC },
+       { 0xEE, 0x3F, 0xC8, 0x3C, 0xFB, 0xCA, 0x1D, 0x41, 0xCE, 0xD7, 0x67, 0xD8, 0x8D, 0xDB, 0x2B, 0xD7, 0x40, 0x31, 0x02, 0x08, 0x73, 0xAE, 0xE7, 0xCE, 0x8D, 0x90, 0x47, 0x1E, 0x10, 0xBA, 0x2F, 0x68, 0xE8, 0x8D, 0x71, 0x07, 0xBA, 0xBA, 0x4A, 0xFD, 0xD9, 0xB9, 0x5E, 0x0D, 0xCE, 0x65, 0x65, 0x21 }
 };
 
+static MHASH_384_INLINE void apply_permutation(uint8_t *const buff, const uint8_t *const idx)
+{
+       uint8_t temp;
+       uint32_t k;
+       for (k = 0; k < MHASH_384_LEN; ++k)
+       {
+               buff[k] = ((uint8_t)k);
+       }
+       for (k = 0; k < MHASH_384_LEN; ++k)
+       {
+               temp = buff[idx[k]];
+               buff[idx[k]] = buff[k];
+               buff[k] = temp;
+       }
+}
+
 static MHASH_384_INLINE uint32_t test_distance_xor(const uint8_t *const a, const uint8_t *const b)
 {
        uint32_t k, distance = 0;
@@ -89,6 +112,23 @@ static MHASH_384_INLINE uint32_t test_distance_xor(const uint8_t *const a, const
        return distance;
 }
 
+static MHASH_384_INLINE uint32_t test_distance_mix(const uint8_t *const a, const uint8_t *const b)
+{
+       uint8_t buff_a[MHASH_384_LEN];
+       uint8_t buff_b[MHASH_384_LEN];
+       uint32_t k, distance = 0;
+       apply_permutation(buff_a, a);
+       apply_permutation(buff_b, b);
+       for (k = 0; k < MHASH_384_LEN; ++k)
+       {
+               if (buff_a[k] != buff_b[k])
+               {
+                       ++distance;
+               }
+       }
+       return distance;
+}
+
 static int self_test(void)
 {
        uint32_t i, j;
@@ -96,21 +136,35 @@ static int self_test(void)
        mhash_384_t context;
 
        /*test XOR table*/
-       fprintf(stderr, "Self-test, step 1 of 2 running...\n");
-       for (i = 0; i < UINT8_MAX+2; i++)
+       fprintf(stderr, "Self-test, step 1 of 3 running...\n");
+       for (i = 0; i < MHASH_384_TSIZE_XOR; i++)
        {
-               for (j = 0; j < UINT8_MAX+2; j++)
+               for (j = 0; j < MHASH_384_TSIZE_XOR; j++)
                {
                        if (i != j)
                        {
                                const uint32_t distance = test_distance_xor(&MHASH_384_TABLE_XOR[i][0], &MHASH_384_TABLE_XOR[j][0]);
-                               MY_ASSERT((distance >= 178) && (distance <= 220), "XOR table verification failed");
+                               MY_ASSERT((distance >= 180) && (distance <= 220), "XOR table verification failed");
+                       }
+               }
+       }
+
+       /*test MIX table*/
+       fprintf(stderr, "Self-test, step 2 of 3 running...\n");
+       for (i = 0; i < MHASH_384_TSIZE_MIX; i++)
+       {
+               for (j = 0; j < MHASH_384_TSIZE_MIX; j++)
+               {
+                       if (i != j)
+                       {
+                               const uint32_t distance = test_distance_mix(&MHASH_384_TABLE_MIX[i][0], &MHASH_384_TABLE_MIX[j][0]);
+                               MY_ASSERT((distance >= 45) && (distance <= 48), "MIX table verification failed");
                        }
                }
        }
 
        /*test hash function*/
-       fprintf(stderr, "Self-test, step 2 of 2 running...\n");
+       fprintf(stderr, "Self-test, step 3 of 3 running...\n");
        for (i = 0; i < TEST_COUNT; ++i)
        {
                fprintf(stderr, "VECTOR[%u]: ", i);