From 08cf50c54a704bd76a30602a5efc65ccb7985695 Mon Sep 17 00:00:00 2001 From: Robert Schmidtke <robert-schmidtke@users.noreply.github.com> Date: Mon, 12 Mar 2018 19:30:46 +0100 Subject: [PATCH] Java/C#/Python prefixed size support (#4445) * initial changes to support size prefixed buffers in Java * add slice equivalent to CSharp ByteBuffer * resolve TODO for slicing in CSharp code generation * add newly generated Java and CSharp test sources * fix typo in comment * add FinishSizePrefixed methods to CSharp FlatBufferBuilder as well * add option to allow writing the prefix as well * generate size-prefixed monster binary as well * extend JavaTest to test the size prefixed binary as well * use constants for size prefix length * fuse common code for getRootAs and getSizePrefixedRootAs * pulled file identifier out of if * add FinishSizePrefixed, GetSizePrefixedRootAs support for Python * Revert "extend JavaTest to test the size prefixed binary as well" This reverts commit 68be4420dda47e8d0600bb19691f03be71503a68. * Revert "generate size-prefixed monster binary as well" This reverts commit 2939516fdf78df4f061c627221e232b312301417. * fix ByteBuffer.cs Slice() method; add proper CSharp and Java tests * fix unused parameter * increment version number * pulled out generated methods into separate utility class * pulled out generated methods into separate utility class for Python * fix indentation * remove unnecessary comment * fix newline and copyright * add ByteBufferUtil to csproj compilation * hide ByteBuffer's internal data; track offset into parent's array * test unsafe versions as well; compile and run in debug mode * clarify help text for size prefix * move ByteBuffer slicing behavior to subclass * fix protection levels * add size prefix support for text generation * add ByteBufferSlice to csproj compilation * revert size prefix handling for nested buffers * use duplicate instead of slice for removing size prefix * remove slice subclass and use duplicate for removing size prefix * remove slice specific tests * remove superfluous command line option --- .gitignore | 1 + .../google/flatbuffers/ByteBufferUtil.java | 58 +++++++ java/com/google/flatbuffers/Constants.java | 2 + .../google/flatbuffers/FlatBufferBuilder.java | 55 +++++- net/FlatBuffers/ByteBuffer.cs | 72 +++++++- net/FlatBuffers/ByteBuffer.exe | Bin 0 -> 71168 bytes net/FlatBuffers/ByteBufferUtil.cs | 39 +++++ net/FlatBuffers/FlatBufferBuilder.cs | 141 ++++++++++----- net/FlatBuffers/FlatBufferConstants.cs | 1 + net/FlatBuffers/Table.cs | 17 +- python/flatbuffers/builder.py | 22 ++- python/flatbuffers/util.py | 28 +++ src/idl_gen_general.cpp | 27 +-- tests/FlatBuffers.Test/ByteBufferTests.cs | 95 ++++++---- .../FlatBuffers.Test/FlatBuffers.Test.csproj | 3 + .../FlatBuffersExampleTests.cs | 38 +++- .../FlatBuffers.Test/FlatBuffersFuzzTests.cs | 164 ++++++++++++------ tests/FlatBuffers.Test/NetTest.sh | 18 +- tests/JavaTest.java | 32 +++- tests/MyGame/Example/Monster.cs | 1 + tests/MyGame/Example/Monster.java | 1 + tests/monster_test.bfbs | Bin 6184 -> 6112 bytes .../namespace_test2_generated.ts | 20 +-- tests/py_test.py | 23 ++- 24 files changed, 660 insertions(+), 198 deletions(-) create mode 100644 java/com/google/flatbuffers/ByteBufferUtil.java create mode 100755 net/FlatBuffers/ByteBuffer.exe create mode 100644 net/FlatBuffers/ByteBufferUtil.cs create mode 100644 python/flatbuffers/util.py diff --git a/.gitignore b/.gitignore index 9a3b07e3..c1011c38 100644 --- a/.gitignore +++ b/.gitignore @@ -47,6 +47,7 @@ snapshot.sh tags tests/go_gen tests/monsterdata_java_wire.mon +tests/monsterdata_java_wire_sp.mon tests/monsterdata_go_wire.mon tests/monsterdata_javascript_wire.mon tests/unicode_test.mon diff --git a/java/com/google/flatbuffers/ByteBufferUtil.java b/java/com/google/flatbuffers/ByteBufferUtil.java new file mode 100644 index 00000000..624dc4e2 --- /dev/null +++ b/java/com/google/flatbuffers/ByteBufferUtil.java @@ -0,0 +1,58 @@ +/* + * Copyright 2017 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.flatbuffers; + +import static com.google.flatbuffers.Constants.*; + +import java.nio.ByteBuffer; + +/// @file +/// @addtogroup flatbuffers_java_api +/// @{ + +/** + * Class that collects utility functions around `ByteBuffer`. + */ +public class ByteBufferUtil { + + /** + * Extract the size prefix from a `ByteBuffer`. + * + * @param bb a size-prefixed buffer + * @return the size prefix + */ + public static int getSizePrefix(ByteBuffer bb) { + return bb.getInt(bb.position()); + } + + /** + * Create a duplicate of a size-prefixed `ByteBuffer` that has its position + * advanced just past the size prefix. + * + * @param bb a size-prefixed buffer + * @return a new buffer on the same underlying data that has skipped the + * size prefix + */ + public static ByteBuffer removeSizePrefix(ByteBuffer bb) { + ByteBuffer s = bb.duplicate(); + s.position(s.position() + SIZE_PREFIX_LENGTH); + return s; + } + +} + +/// @} diff --git a/java/com/google/flatbuffers/Constants.java b/java/com/google/flatbuffers/Constants.java index f5906314..751f4a65 100644 --- a/java/com/google/flatbuffers/Constants.java +++ b/java/com/google/flatbuffers/Constants.java @@ -37,6 +37,8 @@ public class Constants { static final int SIZEOF_DOUBLE = 8; /** The number of bytes in a file identifier. */ static final int FILE_IDENTIFIER_LENGTH = 4; + /** The number of bytes in a size prefix. */ + public static final int SIZE_PREFIX_LENGTH = 4; } /// @endcond diff --git a/java/com/google/flatbuffers/FlatBufferBuilder.java b/java/com/google/flatbuffers/FlatBufferBuilder.java index f98fbedc..44f107ae 100644 --- a/java/com/google/flatbuffers/FlatBufferBuilder.java +++ b/java/com/google/flatbuffers/FlatBufferBuilder.java @@ -816,30 +816,75 @@ public class FlatBufferBuilder { * Finalize a buffer, pointing to the given `root_table`. * * @param root_table An offset to be added to the buffer. + * @param size_prefix Whether to prefix the size to the buffer. */ - public void finish(int root_table) { - prep(minalign, SIZEOF_INT); + protected void finish(int root_table, boolean size_prefix) { + prep(minalign, SIZEOF_INT + (size_prefix ? SIZEOF_INT : 0)); addOffset(root_table); + if (size_prefix) { + addInt(bb.capacity() - space); + } bb.position(space); finished = true; } + /** + * Finalize a buffer, pointing to the given `root_table`. + * + * @param root_table An offset to be added to the buffer. + */ + public void finish(int root_table) { + finish(root_table, false); + } + + /** + * Finalize a buffer, pointing to the given `root_table`, with the size prefixed. + * + * @param root_table An offset to be added to the buffer. + */ + public void finishSizePrefixed(int root_table) { + finish(root_table, true); + } + /** * Finalize a buffer, pointing to the given `root_table`. * * @param root_table An offset to be added to the buffer. * @param file_identifier A FlatBuffer file identifier to be added to the buffer before * `root_table`. + * @param size_prefix Whether to prefix the size to the buffer. */ - public void finish(int root_table, String file_identifier) { - prep(minalign, SIZEOF_INT + FILE_IDENTIFIER_LENGTH); + protected void finish(int root_table, String file_identifier, boolean size_prefix) { + prep(minalign, SIZEOF_INT + FILE_IDENTIFIER_LENGTH + (size_prefix ? SIZEOF_INT : 0)); if (file_identifier.length() != FILE_IDENTIFIER_LENGTH) throw new AssertionError("FlatBuffers: file identifier must be length " + FILE_IDENTIFIER_LENGTH); for (int i = FILE_IDENTIFIER_LENGTH - 1; i >= 0; i--) { addByte((byte)file_identifier.charAt(i)); } - finish(root_table); + finish(root_table, size_prefix); + } + + /** + * Finalize a buffer, pointing to the given `root_table`. + * + * @param root_table An offset to be added to the buffer. + * @param file_identifier A FlatBuffer file identifier to be added to the buffer before + * `root_table`. + */ + public void finish(int root_table, String file_identifier) { + finish(root_table, file_identifier, false); + } + + /** + * Finalize a buffer, pointing to the given `root_table`, with the size prefixed. + * + * @param root_table An offset to be added to the buffer. + * @param file_identifier A FlatBuffer file identifier to be added to the buffer before + * `root_table`. + */ + public void finishSizePrefixed(int root_table, String file_identifier) { + finish(root_table, file_identifier, true); } /** diff --git a/net/FlatBuffers/ByteBuffer.cs b/net/FlatBuffers/ByteBuffer.cs index 37a2c7e6..878e740b 100644 --- a/net/FlatBuffers/ByteBuffer.cs +++ b/net/FlatBuffers/ByteBuffer.cs @@ -30,6 +30,8 @@ // using System; +using System.IO; +using System.Text; namespace FlatBuffers { @@ -38,12 +40,12 @@ namespace FlatBuffers /// </summary> public class ByteBuffer { - private readonly byte[] _buffer; + protected byte[] _buffer; private int _pos; // Must track start of the buffer. public int Length { get { return _buffer.Length; } } - public byte[] Data { get { return _buffer; } } + public ByteBuffer(int size) : this(new byte[size]) { } public ByteBuffer(byte[] buffer) : this(buffer, 0) { } @@ -63,11 +65,64 @@ namespace FlatBuffers _pos = 0; } + // Create a new ByteBuffer on the same underlying data. + // The new ByteBuffer's position will be same as this buffer's. + public ByteBuffer Duplicate() + { + return new ByteBuffer(_buffer, Position); + } + + // Increases the size of the ByteBuffer, and copies the old data towards + // the end of the new buffer. + public void GrowFront(int newSize) + { + if ((Length & 0xC0000000) != 0) + throw new Exception( + "ByteBuffer: cannot grow buffer beyond 2 gigabytes."); + + if (newSize < Length) + throw new Exception("ByteBuffer: cannot truncate buffer."); + + byte[] newBuffer = new byte[newSize]; + Buffer.BlockCopy(_buffer, 0, newBuffer, newSize - Length, + Length); + _buffer = newBuffer; + } + + public byte[] ToArray(int pos, int len) + { + byte[] arr = new byte[len]; + Buffer.BlockCopy(_buffer, pos, arr, 0, len); + return arr; + } + + public byte[] ToSizedArray() + { + return ToArray(Position, Length - Position); + } + + public byte[] ToFullArray() + { + return ToArray(0, Length); + } + + public ArraySegment<byte> ToArraySegment(int pos, int len) + { + return new ArraySegment<byte>(_buffer, pos, len); + } + + public MemoryStream ToMemoryStream(int pos, int len) + { + return new MemoryStream(_buffer, pos, len); + } + +#if !UNSAFE_BYTEBUFFER // Pre-allocated helper arrays for convertion. private float[] floathelper = new[] { 0.0f }; private int[] inthelper = new[] { 0 }; private double[] doublehelper = new[] { 0.0 }; private ulong[] ulonghelper = new[] { 0UL }; +#endif // !UNSAFE_BYTEBUFFER // Helper functions for the unsafe version. static public ushort ReverseBytes(ushort input) @@ -136,7 +191,6 @@ namespace FlatBuffers } #endif // !UNSAFE_BYTEBUFFER - private void AssertOffsetAndLength(int offset, int length) { #if !BYTEBUFFER_NO_BOUNDS_CHECK @@ -171,6 +225,13 @@ namespace FlatBuffers PutByte(offset, value); } + public void PutStringUTF8(int offset, string value) + { + AssertOffsetAndLength(offset, value.Length); + Encoding.UTF8.GetBytes(value, 0, value.Length, + _buffer, offset); + } + #if UNSAFE_BYTEBUFFER // Unsafe but more efficient versions of Put*. public void PutShort(int offset, short value) @@ -321,6 +382,11 @@ namespace FlatBuffers return _buffer[index]; } + public string GetStringUTF8(int startPos, int len) + { + return Encoding.UTF8.GetString(_buffer, startPos, len); + } + #if UNSAFE_BYTEBUFFER // Unsafe but more efficient versions of Get*. public short GetShort(int offset) diff --git a/net/FlatBuffers/ByteBuffer.exe b/net/FlatBuffers/ByteBuffer.exe new file mode 100755 index 0000000000000000000000000000000000000000..4361c00f2a116cc1336d27077e71c7f11c21e063 GIT binary patch literal 71168 zcmeFa3wTu3)jzz?nKNf5lSv>6OeT|%g!?2x%sn%Jkh`F$$jyM45J-Sv$Ur72h+q^& z>Ya*sql&k;wpz7STdTIE^-}e(zG$u1_r(^gZEdx-zWRPu>x<uSt-a5gGm{HgzyI@n z&;R+*S+jq8?Y;KeYp=cbKKq<GIc52E!X<<-@cHsfAs)jw{i|m>G8q6nv*__m@krWB z;~&%JzchaF+U|JqhQ8REzK-?9t2%mnWBtV|yNdfZ^%i&c7B`=^sCa#>vuk=rhHsJ* zy`V*i`5LvJ_;*<7TDs;H!mA14lley`BVCMiJ-$ghO6yW@q*#CY7W=_h;#{KsG9gCu z|A}t}xv&rqLGH<vUZIJ<L*Af&1Dfy;$~=aQVyN#Z<^`VXz|;G?HunP?CiDf5`<iS9 z%3d)&-r3RLA;bdGtsZ5mj33{QfAvBfnBEufTZKIC1Ny?{Mh_}iKfSN3Cx(LDC-jYM zD8>vb*XR)c|0n+sw!mSUSNKQ1sSCGw<a!}K-7N&=eqR$N@xIExDY`2VhEJKLrMk-q zgb`cJQV7T?*TsA#NYA|*;<asXWdmuH*0#B28pXA3Xq587*0y;l9Y%4V?%IYgLpQde zf}y*&p{!9lMc+!f*L0T_%2eqLeJdB(O8mCc38+UHiGWO;DhmemFd8!Btl?6<7{O1p z7p~Nc1yb#Wohx1`{jSO_3fkE#SD*k&PytGbFWZZPohwRn%3Wd|ApMiI*0mQ!R5c{S zRz;+PGA+LBMSCms@l;2)4w;Nt1(K^EHCPl*Kx#FDR>`hzaSrOk2wB_FPhXU*9q>hR z@g+OzGTYo{;qsz6?VYdgGjrQ~rZMODUw-*zq=ZVQNAeRTjkerno@H*2Roau=mhLg; z{1&CTEkpEDVYG$84UdBP0_%LT*=bT(9==S~uBUBxuN1X%g-?k(ObwS&S$|}lqb#-T zUADW|%T1%aH@D62HRc>bd9(BaS6~j}xNu3y*K`}pW|M2u;Q1~nJymz*vNoz=<JEno zC#B}?<1v~-Qdobt)ZZ6DHxiaIq=npb{z83*HyhzBa$z(PlufvT#=3CEpuAo?FQm$a z9OV*usvOiSROJc{S#^l4-|8+^b1O}jfU#ef34JR~m_R6uY|M<1!h4iv|6xntN|PyI z+@Z^azLh3apitGroMF7z)*#7_yVsPqrkHUz&Ff$|6a8PCNWMbJ5a)I$lIzKSg`De1 zNuMpZ$3a!|sV<nesf6mO>Z0uSO&CMBI39J;Z}^}Tj;h=X^LCX`omIV*J--<Ng5yYO zt**yt=EsU@5Fv|V6L}X*nx)6mkn1x;F^Dux_L)BL=%1du&4-rtqR}#Dr4tyt4NGYv z4~8)iXy8-y1*s}}xdJByAfgZRbc5?E%pk1~Q)NROZTc=ih{9gM&|OzUz7|Ira~sq! z)SO#~itMxcR?3Z`@20FEG3uI1w+PKYeJg7=c`Ip_yKJ(LRWt*zEae1F_)qw@rFdW) zd^tsBily*+ikYr$oIuR9o7T6Ivdc<gH$xOzx-nm$%sdyhNrlXSE0zuIsH|HoKv@_* zOUXjlVd!hR(>?2o!8y>|9#}UMnv1?u$TG0M?*dQmO23z_l3@nYyq;wq>A7j%IBck_ zM0#9=dK3c@A!v+dqqczZlpd_Q(Y89b&6T^X-4~&-<tUJ@hv8kO>W72jS=OdZ&i!(= z8Etc(rq~paO_|~8s3&bw2AMowPMh#J$huJ&LF7iDt_Zvu<M6_^EIdlR7~F{*mil|t zvQq5uWrOw@xng6EBG*}V>`}^w9CG3DBkJoci}h;6vV{)0!LLvj6JkWUP8~u=DeKe$ ztEO4nsOJX4<w)tSa7AiHWoky1%m~_5s#7y+WJbs?QJb1kCo>A|5|Px5Xlj)isU>Do z#^btb#ifUjLxx;W;h+ddoZ(s)Y8$PgW30m!dU!rcVfV!`E#xwm%Z|IPROw1x-%3ob zAZ5hQrKZSV>n-1wVnVKKx<lc);3AQ`%om~HsJqN-F)8wC+W5jJf@y+f24=lO@hUuz zWUW-{%0Tg`9VpPc3~qBcg5+pc1mXFji&n^|f3CnRE^rYQKy;wqa>qDkUeoQGg%Al% z91-3nBfRVpN6XS%5N1%$kd6I>WI-xqu@t4^ZKXT)a2b@ILBYsy&&1jwbR#?qSupFV z)SYWo3G`SP-R^Fy%n6P%Lra-`)Dm-!TB81_B^r)eqVcFDnvPnc*--+H#x{c|3Zut1 zT8pE|&<4Q>+h!fQ1bLKY_?&XD=t2`1nk?l3fiT%LjB)k3VptS?K0VjWWha%HSj;el z*lqAqNXwU6C(LD&(|L99#IW%Drbu7)XX{(x)<%3CN|r89IKatCdKh9fmNIk~>mvD- za?pQ}Q(-#6sRCgh2A-8@oeJeHOOIe1AUsHT0&}3PTJ=49qVHk0V7Kj$Al@W$p&0aK z|McuxCKsQz8G2fn-9+XGZj<t6Jxdb~r6Jc?wpJGL2HS$mWjc^!;JV=k7SFbz9f`gb z#xWo}$1QgVImjYzmOF;k%FOX(c~pkU8TAVwAeiHgl-q)`+*#f>W?CgJJQL;?5nA=K zph%84%bVqy^Gi}wHJf8ZU@aH~S1kHg+JDVy2RqA%BDx8LCR<T+nPc-LRn0QYWigDE z8KHfItS$v#(_KH!&I&H)u#l4`d0FcFnr^yA@ab7;+sFix3D+PcCg=Ea+ju*e<&zNv zyD(BENg>HmI;fqQ+<PuY<0x+JnaI#C#6($JZef?DOXM-6=>kVI{O|Y9pbNXc4qa?8 z<c9MbNQSW;^GUzrxV#W$=pPJ(XlR5C-kgM_f3#U^8_gUeie)#+kZL0+y;F4xer)j8 znRfhva62keDp#hkucW?nOg6<CkcURCzR`rbrd!zsTO@NCZ~T(xn;b=AngLaEa5df{ zV$r8{XFb|bduQ&SJE?ym*+YZpb!a9V>@HX-#0CrJK)=5K0ghvb<hvlx7lHK<!p#_V zLB3ZxUZ^GNPvnX&x9lb^hH&)JNqwheu1wNq8oL}H@2Vj{Zm%gq(0&_x4`~;iT3R}9 z#pVT$LM)xrv0^fd533L5$!RnTTEb;H!zDdHjvkLMU1L-K<y8Y*$1wFa)MP<C)6BNg z*-D^`v)f2%T_wqe*il$}YidQ6!rp)zmC)x3wWV{Il({h)7LOT&&-hAjgM8`=_7ll1 zCCe!79j;uc4K9Q6l(xZAi)+6yh8EWkGcc?oTRSoqz0CKN>Sj2Od_TVX@SWk%#+w$0 z623V4;A7iRd_*v%YX+qqT_BeEvgw?`(NhVI1kk1Y*cwPxzO@|n$+mJ?7{-0_U6%Xc zP-Y_4klv#%LPKq4TMUC_zA_W5fC!ZG0ZnMm>+q*sbeinH4Gcu$EZtC}GFrG2qo6W< zDkohJwfQj^8Kx&(fS%?U29HIKJCI}Ykq?5b>22FhUukW-XHwKm&RSNQ1ub&SEHlfP z^D-1MJ-FJF_Fswb%w%0G1+bIj##O@^s$C<H<K~WMVI@Gjt}OTNndlCD(#B}fjTYTm z?zB0-Rt;9_7h*mdTj4=Q>1qjh0vR%GY-7%BI-<D%2GloVEcMbpM>Uniq%&gUQKa;| zp_#52ir|!KXl|%YR^C1wTUEb84;99+mSK||tD`TM{E8h15XTt%O3|mu)F*N-icj*~ z0qaDTo-K}yMFM`igLLT|r8$o&<cUR_9^OgJO1*C?+$ww?0hoqly0(!I%e1kL8(`C1 zhBEp_k_?}BiBn;CjChtT7*dlcii;PXL<mcIwq`0dc~+=2Neu78iEtc?urGozF0%C_ zW3hkA_p+b51g<M&tYw7?EZGx~?GTbAoFh;K6H65D1tFWbM9t80ijh5>9C;0!TN<$Z zG?FBv@Yr>sSy<G`wo2B+mhqMJpcq3jLMmS5vlOAYEc24=5#EU5;_y8N2ia^#)aj>j zmh&%~EHBfNN0G&093`4#Ar=J+FltdiIr6)y!^pu##?p%esH$b@lIhe1PVVfRtqZ2w z@VXc=tXC$F6peNAI2Dby`ZJ=_Ag;;o6!JLLChK9#C{ETR$<Qu7Opy*VgdW+)q=&<- zBqK!+TgJ$G*yiAI!I6N#7+C%?#?m8T_r;{!D`oK_dlq8t!>$W!AFUO%pTj1_svofG zlU!OQ!NUYka*xpRHizeg8)%Lf+tM+|G1t``ALKW-{9*hCeKJz*60~$eBg#)w^>I#v zA^p{sF?_pjaW>?`x|S{MV23Lnwgm-6%NBz)h{4C4W}(0vhi4~3pHG=(sQF~KHN1Xu zFN2NcApH`)FE=wTryj)^9vOWxnxujp_vOibwSzAX8wT~&>KBLi@UeH4d^{!o*g^4Y z#vfbGF!r+IPhled7-Cs+pKTem4w0`9H@;t?%NSdiNQrZHJI5a93_;_A#nl??Vrvdq z<AZ+NzBuyuRMPx}izFNo`(ZUd4S^#JXH1@8wG&2uz~M(pZSeZQSB>@}LH%wTMi%xn z&iI}r%9VV$Z3j1!mlEqIS-K_sU0%f~HQ7D+GDK-bGE!o!Eu(lOo%qsz*jPX1nDn6i z<M4XeGDg;ewwVb%Qsz?lnDl_L%!rQO2G&`7ofMncaz@q#yXWC`DLp1#FzJt?i!Enl zT`<%RT~hpH+A-;Z21XbkTgJ$GV3i$SkLkyx$H;zS%NSXY5&fk6nDjWhpV)Fn)@4LL zsXQiKj_xP6oRM{L`iUWE9d{*SYPF?H3G$t>PR0|pmded=Qm`9hKWxi7%6e3tSdUzy zc^G}BBi|8vlhu(2ZuZ?kD_~NrqqV`&zgnw*BgV@~G!N*4YQn)$^XiA%AKP+@ll4lD z<1t+DIp#u&E|IUO3!YsYQWsm!*U)9gSJnj=nnSE5wwz<vWzgPsmZeKVM$&L&uYJ_L ztu131-{U<s?eh_>to_7nt6giKPiG<4-d1^jVe&qIE5<jDnVHx}pw4jnd|UqTIt|(z z)>}HEk>UOS=+~yUoMGCw_J;M&xtOwNvt@jhJsa5=*Gra-8?F9WHU=-%#$V@J%9cM& zKY83!=3%p?6OMp}wJ`=h=3EYjh<CP}VcNEA+?=qnJQsGvCtJoy;|*O5Iuur+h5OV5 z-5qjTkF`(ev%D0d2Kk>nQ%gD9u;m@4Z>=Nr&6aW0zTwQ$**DtvV>P#YXs*>aYu}GK zobVyFNbtsY&_&A4wC_iBPs~>wqN@2SuXSNotDTdqcC2e%ocY=942nppmw<RC)QrQr ziKcMm%S~at2Au)eZ4F~z)REV^=+_|q5^LEI*Sg0!uXRZUy4D>OXXaadO~@MJIsyZC zl)b7grx;_Vh60NqZkWhJTOJlyEO`%-G9OR1bUE65bgDCiO>H^D*wmVjr;gyWwv40t ztktC{deM~FDKHcsYzd6gwoZWy1Y&1V#tc2z#YeO;L`Ac7x*l{Db;@+3o`<ryxHSSX zxI0zOM+Q9G%78uT9H;`{F7km~dgvoI7iHDcAMj*)`eSztm#@}CA0N;iwb(ooSc)35 zJdy>j!q@_tJI)n|oi3AwNOI$?dQn<(>!o_g739|NG-Hu3nMr!hu=L`mQk;6B5ByXL z&ewGAVeG_&g8Wp9rC`VvvYSXxZi4%M^foX<^S2^&`Hra#KiZ(eiC$-<wEF*?&0)1n z2*(kE)!cNwXcP>78rdG{(MT^==`5s|P`Xkt%60|T#g;0NL*NWmYK)`CSVxV3vqr96 z0~!RAyLXKKgy}i5Kb@)<<+*5rh|kBT)yLXMKjejE9-hlc<mFp=LdbH^svub_Y4f9x z^;h$!amkI8>V*zxD@<k{qg{?V&(OD`WXZ|Xs5qIKJiiMutqYy=NX_rPv8G|hqY#st z;sMRj@hPH@P4>;P)?<)80kUy<X!$W(o0#0%vBd*irR8tM@yjvHRZN3PPCuSJxIH^A z4sSPHS`O*Qw%ur5#6CmD*BDN|O`mQS`C{i##W<d*^1-dqG{p?Qc^K;gCpB+1<-y)A zF%7aph}H42I^AX0w;}KuF7pT;yTIN6Tp#_kqs-jO`SeI~8Q*`n74@(M%2JO};nLUV zGxX51STRJW<DvicDBua6nW2ZgX>HgHhBttbV-)%16AD?zG9%oJEYk>YCJyci%SUX} z(j#Ojz*$-NPRnh}fCRrM4Ua-$=OeOBb>fS=)&}1v<>UHN&y1_Fl4N`2X?d2%eh!@d z3J%HtcwHdl=-i{&O0>;-fT6S1QW;KsK1$QgT`ZXD<}R)2i0Gn#);qel3xIpO6S1Qi z_TDaSyXbZ<NwIF{QrdYtcM{6z8%dZPrwH1>Kww`*CGFb|aw}x3gDniFc?%Pp2yLw+ zL>lYFea<8q#Src2Qj(0sHfX7y%UcFKkWosyh0CZH6I3o%2M*~R_jAfMdUn9+qh|bg z*c>y-@;Tg6%ZleJpF>1op9_-Dm6Ol8+2=T)p5d21w+Au{QP1`>AD&L@L#7!#)31j- zUfa(y@PHFPKA)z%jBSzQ&UW+jyLeb4%aGpY_3>kAfb4DbYZS;yH@$dPmF5|F8;wG? znP!CT{c@=}W0!I^bTr@LZ1nv5GStIF!Shbk0d}zvrX<A?M;3b>>xBnV9Qh&m;jl&N z>0^Gp04{7jUI3d)AH=Of>4TUz@Ij2i@IFX)7sv-mj^%@tcKToijq^qlCVj9H{gOUN zC2b$XP{MyG3$8<7@+lkV`A4l}gyb%kd?4Y^RKvcFCH<L&ASxvbOu4po`g4+uVp|{U z@*ts<EBTt#dC!Lm*|&T~)B|?5j-c6}6Z0xb#>jeLAI;Z~*XVh2Ug3dZvbQTdlfK;H z6X+{E8x*rlmQmYvRJC^8)3IZ=_Fkpfs|R9>AeZOa5OWX%$j%dn0Q-3x0@m|3ly*LE zQ%^c<%q9=O^EP%hmBjoo_`wc(-exGK`o+NoLvw>|F+@$X6wliXRXNxu@7<UFn;s0w z=WTLh(@_DB-Jm1%*bNS7OkF;9Q>D6wMSsw|z(B}(f#n?YVjh`vxaV$8CMM<u$+6}I zrJeKQB(@3(lk=hu4kzaYm9*!D^dVazOb$-V*i1d=+e|?zBjH0yGNca;EhF)0gCjOC zAl<^JQ!nh;T#DEnl-E-5*CG4@c4WVR-&n@8VhYaDr0vGA?G}^Z;cT~*n6Mp*v1~_a zr|p)Iej7<xs_m#`itTKDU^`By*bYwtC9i8qGNkQ>mXWX>#*Snp#*iwc#G|2QB%Npu z*29)DvL0}w#5q!`9x3r?7(K8i4ik^4f-PfYJuoCrJrePmWF($vl1@F0B96dF_Nawz z<-ACiF|s07V3gyMqKDr)cNtL+G+-HI2t8~WBkO@P0c8-9k)lWDG3hbvJwmpJEn{Ro z5M>>DL`9NK?Ps7yv<H~>MiBLfu!${aWL<(I>0&<zHKH!gP3h3O*m6eJ1+l<k7aRaM zea(KJYD8Ud%Bt?6p?2!MA|4}K&d9o8uj0_99>N@cZ$CRVqAoZ{Og-ctVw`MQBkPkm zoF*A5K4U*qg`vR4&7R9LY2QAzS19$YrSm+PZDY%!%QUNUA9X`RMu47cROR}Si6rTg z9A}Gc8S;M3FuE9thxq8ay$RwS_O%xcc@{gg47xWmgo&Zkpnlo%j?yo+o27m^?~!ny zZ5boknD3D!hKhCRLEq?~UgVeC!c1RyJFS_S-tdL|?Fr*e2*CdECH$Qp#&6t!)53Uf z0=~`g1^n#}Z{crTU(>fcd_H{{;q&Or72ZT&;mbhryA9PCPF-;oXPvrYXK9_f(#CQj z4PvRDXYDcRoJbu9mg@OPE};U`ac*mENT=&KxK(F?C*d%QY{CER<F_<N-ZH9=gPN3s zTU0ovv##r6CqRJumB!F#$`GD<WScB|xO16fICC0uUxiH_@2hYulh|()u=d-OcJ8+? zr$O0>6_EGab~XJ%PGTi6VidDzzdaPw#W(Zm`Szi>c)p!0W4}E#d*tecBUdlPcAdf? zZRdv)Uo=`yz|u>G<-1}u8HN>LT`vqLz`kIhID;*-K)lVOBN@7W!6mj-i;P$l!jrJJ zlKdnrW-WZdC2)(3|KYH^s90Wg1m#sn%0)<~M_z?wn({J4U7KXORkjhEiO%RDS=k+% zLCBC_F8L*|T(C=GC&5`;%9#@8i`;u-D}w8m8)>c%xA&&IhP3x4Dc0Vb($2m2P3&DH z4A%w$c>`!jzeSMt(eW7;j>Pv;J&Zp1@Z+ZAAQwLn#<iGHdQM*jexaam<-Dzw6-K{( zxLmYK<KTx%<5-7Y=2AhGuIO9El{jxJ72w}t>060Qznk@8@v!RSTF)qL?R$`G5C~(U z`$``eC0tiw50HN(K$Pw%`DS3Gh0eK>7rzZ%zQ7vWrQq_qfuH|g(>>Emg<Y};ezOD7 zu=0_@YvINDF7qz>x{An=08!aM8VVtL#`lw4{t1tMP4}E<a25pPbMv`Z;XFjsnX2Yj z>rqlHFqi|mxE{ke3Czr_fKQL%KCbUA(riku?=5`cSH(Df5(hCe^27CD#_!}VX_SjM zw4`SUFY&CGUYx3j@1tQ3Kfv@s(9+p@ZuowJ0sbn@FHaNnJ4>vGS-Ek{6w{Y?HQLlC z2d<?rv+u7kcI-?rF6Qi9mHk<Ac2H$|3}@-|ysM#GzTXT(f7A3xnHxz^_-*8P1J@GY z3>QG9i)B)ll+8Fw<_=d<w(KYw98}U9E`t0FvoFWeF2^wYrrN-5_Ep)yH1osnLbp(k zhhGz8W_e!adz4xDp)CENH8AVX7-N&~0_J$lzBzW)G}X_nH13`3R*ugMhW||6FY*<Q z3AaL%DP~b&QCKCVoOBfWfC^=sj+>6zZU>MBEnAw1XajR-8(9xhU#}KaZ+$SoAiM{S zgn!FzE(jl{?<_;Al;sWoo^WpXkKCG%&$+{Y;xg&s_xRf%{tJBv!v9TQY2m-p7mra+ zhAWzZHqESza3LCrU?>@k12Fk`lYe=pk~pqKF5-b1Z-Bq%WM*Z?8YwZVZyv1XiuzE! zZwHe6_*&nUNcG_*P#eNcRBCkA=&VuUW+dMlg@Rd`Q4fE`T99=}wvm(NisA@cWMzeM z;%0{0va<NJ7hlx+vM{QYff)wK$<mSf9#qBGC6tk!osH|+Zy*^6qbp_E+2LIPeAhdS z366|F_*N>JlbsW8C8fq>j|pFeoIaWXVRQgxa%GvZ*<)py0BUg=nmnpZP?pI>VU`oj z4$3k#WmFlSY~gQFdwJP;^g0Az_}`#zcD8JdIic)O5{K(ECqFyi$qDa)pxkh}>c$O> zR4<7YP^{eWAeLP#H@w?XEjO41gLz3XFO&pB`3@M!DUf$;va<@p*Fa=eL2jEI8zgcH zvI=1OYmq<aKj<($I}mVGhJlmy2qx>1m#jx9SL5Svq&T}VIc_vMVs9vA)wY>HVk zFo$kgm1U1Z`mDzA6=Z3fi42>Gg2_x(({iU$K`~ettMn80>*T7~Ke$DMj?fLybg{4b ziWX#x@D<R7yUi|!401Ql;NXM|@*C+6f;Go01z7QPRybQ@<ykdkh<apP3B9e1ddk47 z)?|hq6p(o>Wn%7@1p#&w$fUk&;p>sk$j^3#8!3~Vz5t+^0J>6^3!TVYq_c=HI$B0| zPox(c9R9M6gxdKiPXo!F!tYN5h@)d@f|}VP%fn+&zca;;_9>XE!u-0iB43uQl`R6{ z8zCYmEjx`~0piQ?W{X^zm7bk0vwT6+y~%2*s59Hk9l#f<-rbh%V@%&NgB7Amw^)^U z382PqrW~5eybe%Xc1{2l?jbf$91*@6>70!0jPOaMm!C(CjPJ|#hfkJY^X1nm_~PF} zTci0Hs?Nav0S_34e@tRBvoq<HAinUop>YITeVa2Xdz9qR>@Nj_u1%>bVq8|=jTA9X zLq(s-FOEvrJsj0gkjizTT$sxJ8s&0vN9jlaL#@-boKN=hEiekx@q3w6#-G3lz~hbt z;3>`;ACahxY*#A7(oNtxzXWX-jh34TvrluYoj|&^`pXrlxDC@Hd>H*Vi|N)__;-}# z)x~dm!*U^6g}jV0J|&HA(e+KX<l*+Pkrw_hG9WE$v|pf~6|?j#qo|T)BT>wf!7{@i zaT&RSd647bX7B^~m0-w~zzfH@lVtkfFdU%MSUq?kPf?l|tU5BTpjwo{okWH`XR)6$ z#46YVcFBsLPD2!42uinNeA}zAV?8cw%n|bk7}fY<WDQUj=hN#X%F;db=!`ET@;HVt zjh>wG`MpJB=o;C#z1ph%Fx6g0wJD49=@k!UIfgg99NA<b+OhdC^PmD|9X-$G;~#gs z16RATC#9zad{fL^dRD;q)-)8#@%CXKxWOB1M^2V0zr3*(K;aG$Ga$>NC<%n&d^7Gs zsFo|UN3P5sxiY6o_Do{Kk3<^(KqyTu+uLibjyysg!BG1KD2wyy{R?F|X?-_97n7b> z@LdIW(X!I`E4&&RS!sdU$P;7fm%kbuU5MSH;Co`4pElcKhgkC$F^Y0^JmvN8X&PxD z_UiO2exH1w#X(&7>EU|dKx{4OHQj+DdYKj|Jx4!?W6eRV(twV)YuFDF&>R~NnKT!R z-*X8e-&vvNBHm}=;T;Ia8#zB*bp6TYbCb$?0!6F%Wne|C%)st2!ekjLkbGQ`(kCmP zNB6~Lt#s4F(|sF4qJhUULUfC~8~TS4I#AKN)+N1yDedI)3%_!$Rsv?O-JIPX+#oBS zPwmOtc6%qu_6i2IC-ppz>Wv#hPsBsgvv8Pt)2Uw35be#E^@<18lfO@+{)JNdSDfKb z_wjGOityIB-E8|JKlRcB+Z17Ytx`TSPo~ITQvc&gkMX33lxp|;6sgCAL3+q~<y3DX z)k_&4#B}QSq+#k+P`$}Rw0D}UH)T*gmpE7XPhm>G$5X!zm#*>6>|^bF$P7s%<eB+0 z5i|>ABG(+3YM)BdcPi;CTet0l1%>*FA19~yp|lTTTUNY;>ZRBRL5b>>4pR?NEh}C& zM0<#&RBzg#dV}W|Ce}VRA&XXd0(^fib$%h}WW|pgLcc|_o#{iggKKl1$JYD`<l^O_ z0jsH8v_yB{<kYwPtCre1p4v&7SBqskaKj<(hohIQc*PL)mdJXQgX*~iY{&Xp^CM7{ z0R@Zv`^;cb`aUzS$Y<%wGY0w=57IY6?N(8{Df0nq6WPCdP`h%xqg1bE2z{}RQN7wh z^<4Z8Vw%sEUk{~kD74Sa&)a7f1oxTaU~jqSu{|GsKy)?30Sbba&1aA<b)-v*&tfSh zUGOZ_kT#!5^`ca79M3e{*RkGGy%|H)D}l{%P?c3&ja8U7Sf;Ny8v|j6vCfq7#?nk@ zrYDT$g+e^X9;$Z&)!V$ZI-9oFTyN=Ss~+W~Gt<M8ta|WU`ps|F_`kh$-*sFUE1&5b zpIyCl^L6*V^fxn{$L&&Xx?RY_x%MJ9Ti;5{NUmCdocR>)gUBC)`p$d`=d@s@=2N&P zIZ62^>02p$1`~nV76leX$iUDn3W7t`TCQ)UcoVe8og<zt6l@ABf#KN{J%+12L*Gi1 zK9}Rf6k8~=7gH^s)JfSi1#<^y(+mmmlu9a16F|<iq-^rVLU!JyY;rZ}(}`^IYuf+g zOwih6r+ZwnX&54p5BoUSnqE-^zcTo|yB_6m)b|>8SU!0IlWqnA^6_nn{keFxs$-8b zay^({o#cGAdKi;`sU8N)su%n!dSVp+rFs}<t6u1<v<E*Jwq6;=Yv^%Ur*4a>ktj^G zNaHthJ@}H<VoE)V3q!U?n@^$60@Q=-s^vj_MGPNWhF#rG#NekxXd-<OF<r_DjOc@2 zkMcn3_egad{&&oE9KLtVbsT<o%yk?-cg%Gh{&viD9KM!Rht`pLn(u>bo#JP9t&})1 zWIczUrPQk$uD#*?%$7joTsK^O+qLY3)5k0sC+Tq$tME2#tJI6O>Gvq<MV(;-*(wH} zh->f$*hJmakQ-3P0d*L`v<z_*>$WMGlW8kQ7p^9sV9NqU7xS%Txo?{sD83k~@0*-E zM9JbW!Q%S_a?>>VATGs?@H$+c4U$?s;gT=Eq}w~D+?-54h^zJC%6@nRa_b#saV<Yw z*%x1Y@rxL`ZQ^z1K3ok?K8Wl5;R;tSKJO+vjZYNDVZhLZ<+WuDJ#^UA9KY-Q)k~VI zCS=8ML~nNm=LbUzQA6RV)^se@sBQU9M`zo)x$?(h(tv|3oXaDjtQ#6)xcFwu6jcBt zKY55ka3ya0hLnEi29Le%{2|&7CMg%(H+iT+NeUiZF`Q8?9oMJm7(AMN>JzpfqU-YR z)-l@W{?xWdwoma(_a%FDLGeqFuy69XVlc$uNm%^&q2vk&JBBkyvfc+Vn}_yA{!Qts z6utYNw~iRCjvqvkp#_+Iuh@l)iq&N69ImvSKZDx)Pg{f)2XNpuTzl`>h3)om8a8xk z*&g<UN%K|S<{u^$^6!W2ey<r`vYZoG9g<|r9q2H!1G(156XD35Vh1Ojy$!FwA+VYL z3T@b%TW-TL=tv!*xPrj@71}7iWi#&G^W#sZG??9&?veX~t|qk;<Q@BP_9|XlZMTy< zLZet+hA|-Z4et1_wmHmzojYQC<P%s=tTh+sA~H_ONtte4r3A8_KNPm?Xw9LXVVmGs zjF~@T8`7?3pr}p_Q|^eZA#4s~K(s?PJU^wqpo(oKU(fRzZsHOh@rjmmtEWnfl(rK} zDc`aB+&jD$q{BAofTc2FS9!Hp<PY#eNoG-<eBLdOpD%K1CLdQK1*@}pUtnJf;?M;9 z2q-LPq@@X#_<zwJMdNu@GmECF?>hC}D8G3<J4PSaFuWFI5A3&->|u}jc=?bb&bu0& zlN4t-u@&g79XB_QEPp5D*E{Szg#2l$B{rWW-;}@1k<P~#AFK$cf<>n|tKd$TRH<Gq z9eu;A#D0j)WRgyW>;w4CTLu`WN6lA$6MEqsdgM`#?4WkyM`<T@%}^%`feCcCd?MQ7 zfBev<<vZ3^vwsB9=!09F?h^FAB>WbRw(c=6cI#?SXk4vhw@N=1#cx9Jh5*^QjL7jo zs<a2Ci_*`bTY)X<Py%<c_{Xnw@q<G<L5gGRDKNIU1ti2?e7=LvQ}{%F17fCa$HgrU zR&c;%MqZIQGdPDXE+apaIgo`iG-i?S$sAlFAcrmtBe%+&6F3KMXhyyvb8sAoGIUWF zp@@OD5Dt(-muwL%>XcJYIr6vh5lEw~2APGxX+}_ivKo<<Z0E>i$!SXB(8YIz4AJ*j zYz*XI&Y|DOrn%<4aKsw^9Jj}t<-Se*U9G#3@31|+8~VpEa5i4qy%N&YCfY#KlV$E% z7EXi719(^e&cUOQ7Q{>Xb9`C8;PRaGtTcN>3ZYOPKCr03iYP9@hm7_JJ}=|*9zJe} zi;M^1@yPaMr3b=3G{tw=BRRyNVUdh<VvNGITI6$7-A<z;8Gd4nA;#Opph1$13}U1a z<2ho`SV=}EG3fj?@*pv2$RuMFF+9W|r{R&4jM2o%B?g6H9zbTS3uh50K%7;?X|QCi z3uhB2k2v#)L&HgRCIE<V4l(`2oJLF<QDWNT9UemkFr~{<hc*jiNPhvrHKz}wXuYf3 zm@@}RUIVzqz0?N&Sr?$2Af7Kk2QVatwIe#u&W#|IJ3y17=;8q~IbXvLkd65Yb%2ao zOxK?SWX0_yB@o6Qz&Aj~D}L*(xBh2<{Cqn}3WR%zQ;+0$T!+%XF9ygk{8F+3GQ`Bc zOmANNPrP$sfO?KU*CzkSU-4+1{A_EXEW`;H{eD^iW$DE)WoVfH#93ba%;j#;hQBdI zh<<qOsD)=;amOCdx`sey+Td4XOL^#;`i%gWQa{(hNj^%K%HsU%P?f~s8F)cEv@mgB znEtK;3`}}e{mXKs9{*bXanR%I)W?+kTJ?**X8q!?S%3W3tdE)Zwfc|A`L*g#`kM78 zbN$9eCpBvHkPZGJfQa*|r<YH!DzB=*^rgiRb5A^i**0;z5XG2l{g}HG7xnjb_pZT` zFT@_?drjmmStRydD*qnt#1ogy!+I?42cD0hGqJIU76Sf<$uatj+wUw%gZqfjwJLh? z9JNk9j9?%TMFh>DIrt#h^55K`d5cW|wBh;7??PCFG!{WVeTFBq3{(+_!}ND}_?`xR z3(+}C_RbV7#(cvRi<mBBx`OE%rr%`xDAQM%{+{XQOusZjZd1&0lY}#w4luo!=`Y;} z!Tm2zXP8uGy}8RY#jQ+V<eWE{{*h^}hsylPNAzGi(f62s#&o=&a>|*`X1avw8h^jv z6g!#T%sEH=?hI2DXAqs9Q3tv`W4_@Nmt|as^qrjl0_PuQ`UTVUOe$HPNv$+yo|<Wj zUD?#TZ)a1^%lSkrW`)Sy$}`AAG}t|Wzp*lw(}cz|^5R)ULgfmTh>P*iVk4t$u}0hh zDNBLyr-6aez*`Fx1?pxLXEau<V>G}hfaemZ<kgIF;e~|uFv?TtJK`2d$roFMh5`OQ z(DR7!7c+X4(Rd)L_XL-mtk6@8rik$x@m^*$RZM5}D@I{4htY2sm537={hd*%SjgxL zMrC3rBd?}uQ9NUR15_C;%CwNSQ5+}sF`B2)w-~JjssQgcM%x)3k3Td`^=@WVDelzB zf{y`>#k{zic|TL=JK6wvZz%MA=KYRQt$38t-xT^4Bm6o9QfkHfTrZzdop9^)U}>09 zGalOa0!;&o;%}R!=`NrrFkoZFiDE3HOl%0p;+}dgqq{N*%@cWy{=n!Yk<Vxn_Ecl> zSFp!1TFhv^C}MOqqf^9qMlUcrRZL{`DWlWGWJbr2CMgTVR7UF=oi0ik?PIi1lregZ z(IRmiBUcvHTP%)eRK;kCs9>~;(Na;xXg8xXL=B^#F=`Waj6P(vOhk3E^|Wk~xm?WD z(}7L~isI^BqQ{fa)Ep=8GHfCfC9AOAlW4q{t$Q$ITJ?0$lbJ5iGm$<EzaY}YYCQlN z*F&HeF?Xk4i1Zbl-os_~ar$1Sk8;jWIsF3D|IjChr30TKy>uYcm5#rYSu}`F=A3D+ zLU0plO&sr<j2(NeuAy#~s|553-1l8N@EfKP<PaBUXafse$AK<px*U}1Rt%z(hs_x; z+Fdnbyy#}S5&9(O5I0N2GH%tg#9uQ$0$rCGag7(7T@k$fZJWyjdKGA`xYacQ^d1+z zLG?kG2Ku<`1kh((^`Ngna;-SzY65-F)e8EtYaZyAuKA#T<1}&lK%UVAJ*O}|&Zxky zuH3Ulv*_EIg~<8eORKcD?8{tL+Ap)O2mJ@rnw*=E?qYgF4&^_?^uL)-9z!`xm|j2T zTSz~}>5n-*aV&8cjU@>?m_E$(9i}+}D&NF3&h##(zhdgjC2m9RouC_;-jPdk-peHo zgTd=v3yKlW#m-=_@i^?g+(rjnx>(ETV(_NJPYy_)_cQkntjjMb)Df)39C%fsbwT32 zt<d>+JDW%RMIv!&a3TJl-Ny=D5&WggD?H-`{_Pdl1z!XjXQNkKX=1L8UU&J#0Y;aK zZw3DoUNCI})w@(Y82pnfQ~VpFi^YN9$F9-h8AdzB>%q@l+2T!wei!`GHAZ}3BexL{ zg?v@DQ~U|MJP}st{orULU(8bIlVHFYCl)Al1T7SaPKDfg1qQrWp^Ur<xGcX?p|N>k zW3sqSp~AfB##HgTLR0gqjS`W8Z67QzD)MF+WujQ28F_PzX`)i0*?G;zapDApPRyHU zOc!$%Iz8`H<9M-1p|-q5M!7ggp%r;;@cp$4t<5{zs1*GQZOmI~REdWax*%_jQ7zt= z2qV1^?|u51(Oz+B-Ug!vf2@x5+$+ABcb-uziW!l=jMD1Feu>0gc?<E*gTNH-k@q`! z=jahpsL&I6mlzQ-RiT&tI}kl*NhDsvJ0hcEEu)LYE08inJgs<#@;-LW5DReOM^<_p zQf7%=3cVh@&Nx9lqR{VxHyE?UVTIlg-eSxV{;;g~N$_@~UPKf+0*`DEoeH`0?lv05 zbqZzVeFstFNrlGdJzzA8_Y^A3d)R0ZV@jmVsd<kXtzx!9e}-l!iqjPODDOIBu2`Ya z=Xp06^TbAl^w2HFN#YWP(nGf!CyVP98jE*6%@=noR1mt`I7K|F(4^3Jj8nz43QY?= zfJpa-LN%d>jRoR8g=U8yGfo$uDKr-{7m6@l{KJ9^Lq9PViIWvNC-k(jRCFq|HuOBu zLkev}y)(q~3SAmnDB8rk3S9$Uo2V_5GH(G|CeBvq&v~yK%f&?seU$f>akjWiq0jT) zHCBjc6w*WQ8>_^h6iN^Mm$6!;(SZl_91A_WMVUecq0fvSaf(8dLc$#r^h^_#oEGx9 z`^0XAYC@UrP2v%SW{1YQH;dO5nhTj*#it709x8Be7v0B6DffeSkr+_uhoK!flG=B? z<Q)io?7BpJ!RS))d}y}&Qn9>T@}5WEcZyDh4gy^+dL{C{6Z)lVm)NX${}rm$cZoxc zNXk6-F0rJ-lCr>krC6cR!O#Nt)x^NRXWd%<QunnIh-Wjr`M-4S7U#;6JpXo!eh2!d zpr6aaF3h`L?3Bn$_4bJCBoev#ry6_2Ax3+F&UW7*+?8BU6oYq@7|UocP?!5=QLK1n z`91DiMVCU=D7jButxyBdx5WJlos_@PeVh1Hp;h@;yKfi#M@JDu&dtBsy<hC7OGKax z(fXZYTD67lbKfIwVf4o|()wQUZHY9p#J%F@jCP7E^MC68u6RWv@1Fc;-S>+R74O#k zyN&yWzlLP)^xh5L_e7aQ;``uzPn^tXuQ-tZg8Ko{%Sg8OeQ}}U{VM+r_xHt3HhRbX z1M#Rr@8*Btenk92)?>{c6^9s+X8+~>k@!F&@0a<XyMHX^)=FJG1*6O#i|Zs3qYH9? zUQ@h$@E#XI9G{V2PXO<6ah62hK<1_T6XI6ID=P?^Pl)>!iWJN-o)Dj?l8psB#FJtw zj@n4dQj~mBL=;+EFbU{FiM*Q&O3j~&1B!P^!SO%_pA+o#UQ<wG{!Gl3NZeX51L!J+ zekJP71L8%6zFV*uXc`@!!PXC<^`DCs5{Ux^J?@{2yA|(M@O~kFqj(<{tTTThnsJIq z^~AUxID+3Skti59U_K?DR=lcld(5ZBG@MjWk4_jj$9S60EvVi?)O$vJTk$rI3!2Y} z#}v8-^_~&MbPR!d500Az)G3kog>m09e<@y6=r`le(SIp|vt`LYjQat2YbEl2f)<_= z_bZ;a@JHrz;_r%ASoo~_c~MPA@@S#5@JaJ|u~{PT+`^xmFNgz*cUIvuKv;yRq_?l| z1@nK2`4Wkpg)akLr+E7ccZe6oYl`=MwD+P2HlP~nJ%{#Q5@$&y-a>mXiT#TA3EF#E zyr+0+Mb7|DYn1hhi(WAQUGz&NYKmS4dQ74DML#kR3M_iu!r4VT#4DmsBC)wBXucxm zDzv-kS3ozZlJ^$9Y5qzaR=gh+y#+L>SxWgSc&~{biNy2Zy(S(~yw}0|wfI!=-Ujd2 zVpa>+6CW1!xL+3o5_z@a9pVk~h~gC%|K5B<jA@lE)PnaLF;^ndRy@b}jkr$n&Ia#I z@s#5A6bH>W#cK*}DV_urJW;lHY4Kw7KgDK=yjP&!A#uOr-BR3U91@=>-o4<xC8o}m z^$tMhTOy*+>&2e}4Jh=N;x)$a#6gL?pQGMkfeRG;+bPD351NO?7=@;dKLT`?MBc{n zhUfR<X~kPUJ`bq;B(CS}9lt}oBRVA#SB*d3^Nx5(@$MP_g88oaRPlZ?{$-$9C(HKU z7=O0$2XU!H-VY(=kK#v)H)=xA{G)hIq3IKvJbx4!^Qqomaq@(Dp7%tqLTwXH^ZZ%R zpF$^I`-C$+?~6Kx)&TugG%2)x!b;EI#A1auO<3poNUT-pk_mmDkHtL--85mV=fA~6 z3Vm<FC7yqXClvbOgeyFsiDwo11xo%?yrR$xkoiC29ff`c-k0J-h28}Zha{&+JwKc9 zO^-`!RVa7jR*zddU7_lU>pUK<Q=xei_j%H^?<%wgCDXM>6}oidcRd-}FBQ5P^+suj z6uM_(pC?PpJ5{##Eb8TGlN9>n#2<RbYPAY|Jn<KvT&+=|FHtg2J5{0VNzZ%owdD#; zo^;SNPFtf;WYQa+BCTJclP7KUjMoMfYDc|^+Eoh0QE#$#vqG1n-c;@16uNcNI!}rA zm_iRu`mLu-`)`F_gv{eKahmMIdz1d;IbIv1&__TO8vTHj#{Hi_RoX0t+>_UNYP1Ck z<xl>mr%v0e(2U7jJyGorh1yVZruMKxaqv#ieyY%3@aAX-6}oM5pQk~~SRmVb5G9+m zph7=G$ri0tq36ImQL9ntP4MPva~1l_<PSY3YnLfxOxfx=MY~R+aZ}cLPSfsIsC>#l zJf~}KD>NS^7ik|Tv}TI%F42xCv>o-%&_<swHM?Po-@8m(s?ejTcc#{%&}&oP@SLsn zD)c_;wQB<kxu=G_9okP63QyhYS*1Ov&`DD#db_mu6<RX&yPnnBmkM<Qt<}aXl&ybb z>ORjpZN5VHOs)3zXeZP0xsdypnAXN<uXu9mDsN2dw^7WyLE9}$@{XlXyN?m=ST=k6 zwI?OQUg`xCZ+u!zGIxqw^IryPV6;~poI2n=Upqsgx2Mj-xylNKKAQT5=K`%qp?^%h z%6p-<OCfjI@7<;yQ0Shi-|}9hy|g5u^(ERNMtjAi@c;5&qJ3(kH@rKvu}irmYkiq^ zJR{Qju=jGUULt6Hss0UZyW&-bgXTB1s}%2q@Xvt`Dqc(Y8K5y|aR0n-`rq?jp|wdQ zP78kkbTgy9;>_?z-Yd1AD6~2}&vUKztU@16UFo?_dqbfO;e(!UYVRm?epsaK(f+Q` zK-iPESM#+cdV8amD-rkTMy-Mo^(Z^-X01UY@2>DD^H%K~#k(eai*c)Vq2lcghtl?G zw<_Mg@O8#M?FmME#ogh;v~OvDU?hEFzxIjZJs2)a+pmpYM!M`34~FZ~?$C~7^heg^ zF6~4{q)UC;JzASYyjT3TwombBulQ~4Ek^K(@Z7X}wT~705LWuG_Ju+e+3(Z5%Vm4% zB}>x2r%hlaHG4oSSG*}DE7Bg&=G&+z?Ln<umSoMoukBz&nr%vZSlc6!cV<Z_?NRMF ziq}}O4XEHuYHz3a<dRF$eyFXGNGvSb33RvOomn!<{E_ya;;kyl0h)G}thc`8J?~@M z28qO`k`I6$QM`*vc8DKqpDNzvB|kEMtj#)G*4th3tow0oKq7H-$&=>e+S7`6SIN)K zCp7;#TvFUu@(j=diM)@NykI`5-K2OwDR~*_kmCKa<W2J@+N5?_@83(_0$MAP_sx<k z(|)QwqIhqYTnqH6LhqN%Fn*@huaKI32(1rjaf!q~OM>PB?NWuz(miPhwC5BWRl3Ib zg%<3P^~RK9U#^`jk(gK-G@sJWQmDN22+-Y(_KKOMx1>Fz6|AIsd&McG^E|I=QxrO< z^x?E$X%z}}mOh^LYi*W7>q^h`yrG?_(8f}c_NKN_q0OaRJ^!hlt<XiK&wJj|)+)5K z^q}W=TE9Y9m%ib7TN_YlPwAgL?`YR6bZhC))Bd1+TcJBk*LnV=J*m*WrO&1PS^G?( zAECYXH5^KCAD%(UziL5+UMl^E=Wp5)g?@{YA89KT`mpqsw2!q57)ihWM7vxf_T5jk zI~bAg9!mSawC_vg{h!h|%}=$L70*@nu<@z(f#Ri?y=i`?rFW7pJ4F_FpJ`<hdGo;g zTsukeiop9^Tc>za%dSlOr*?(nRg^tu{8PJ6@lGf!HNVjQm*SmR_HNo2+6RiasO&Fk z|D#Rnl6^nB>=U5d8Oa{G_4^fXZJEdC)}ONx-dv>rL6+p+di5_EQEv-;K7G_`DRW2J zJda-wDs)TPBwvPJ$%sxX7K%)LMiOeY(eb`ay^Ybc-UrJr)ko_aY+j9Tw0^aNm!m&q z^Je*S^q)C+WAs-T?G;ayHTdul%^IoM(`6_50{TjY{=IC8FQ{Lr(Ca{X`b`S`wrsgC zq#tG^wa(YylSurbY$5KNeWB2YjQne<g^R_9WtSNFdgpqHMo)X$SD-%<BeYZGPg{ul zYljr7W3*s{<TWrlYa^k(V(GNS>ErZI`Uve7XHL5!y-*LuC0af0y7VHwQlX90ZcH!M zBaEb;<Mn!p#D$PKUf-b5os9M?bdb?+6gt9abU(GQQ<NS@_2w$HjM0EXTNpj2(4CCD zn`FHg8PzNF8Kcb#<xVG=4=FU85&i9YYOkBo3WaWDbdy3qWOPuW-!kHda8b{7Jjvt- z?0_aPT6?~fIhWCXh1N3qjY7K^1vkr*_cL0c&<l)qDfAwrLkeY-Q+s2!$a>Ql%~$AT zMwcqo&FD#mE@O26R<6f0V7&eaql?9z<yHRi`XR{^52EA*eawZj1$PCZ`3jxI=u(A# z!01VZ(kiLsCkk~inzl_!`5~iDh5S`ia-Tvg8NH^^j~NBG%X*`$spJZU)-s}}Mrg$D zW%Qgve`fTBLM1g+ulyoeavh^ih3;o`lS1z^dQqXWTB>IZ$a?28nx)YFj4o8@uZ(^s z5!-Wu{;J{~Uq@07D>Rc)^(6xTc8U`jJ*3bQM$>jk-daWn723*Z{-u(4EhFPHiSA<5 zuh5Sfy{phGjOusFl5aD*TcLk2@?I`^Aw2RqLEoTI1*3Nrn#*YME?IIFqsJ85#)#ff zMm@TN(fta&%qVh&<bBHMNrfgvsl9?LCGP}A4=J>OQSd6s>tNK+=wcCze(ai{zjiJ0 zb_Xwv_V_31yRPGsZ23w0K8eJR=(Fxg`qK*0{l7{2D|X3#)cZj3c13?>PSLA(%l39f zxBA0+zl|>Tm+Ft$=yLxw{SzBq?Vqk!f77aWy}w-Vx6#f1O8pTV-R`f}Ke5q0{#w2I zdaK@j{)pahqwo7?=pQdk^k|m;1*09}(W#5Pv-A~961>^^T1Lcs!aH04A34L>67{<K z0xC(og`!>`%SguLdVO3H@3<shO%ksqiFZm8@9ZRAR}yb?5^o@hcYPA?)+F8oNxUB> z@m@;e{W^*FK@#tiBwo5B*467dj4ZoMNaB?y@uEq*h9usCBwkw*Z%q;}mc-kh#M_y~ zyCI49tt1{jLse^7R2L_tq+OzcbNZQHFo+HyM;Diax&&Tf2x*BNEB$~YU&@hXQqwM$ zW7SIK{_n|uk9GUk=rkAgSJDqzj?{UEoAQb3VjicL{eOTqu!iedD>+{0u~t_w{U+1B zO!qVWIjAm3bC-DP|Dc>_xG&Vl<lap)DW?)t6LUB{&rZu6D}OQaT_VBN1?4!on)m@r z*r`*#^a>|^l*<#<dA{JUkg+e(ys-Q{HAm(rQ!1m2FIk$~L+MOVOPb6ncH}s<a;7Jt zj3%ZsEeF*_glo;@9N7z^x{!V%bDR>K>1M7qkLi4y>f%&Rw=q4(&eueuj3!81XAYj& z;hb$ucQU<^>Ag&U%=87OhnRlI6p!Vk$jRoMiA+nFmZy|SZnthot}bS!<m+O-BS-3g zjw6S9r;C2hA=_$rdW&+dv2%1GEhh7&-DLVEN13}EX&Gr{nTH+u(zY`HNk{%Oj`TrC z+FAFIBY!ygpBzIOe_EoCK}UKxnN^N5a+Ib1O^*CUj`S)=I_^mCaHRJ*()T#hKXjyj z=|~T!oAef`kMbEFJLx$x|F_2==O2zTPMeSQC2TdE4#kc#&brea`NP$%KZY_(9c4B+ z(!<HT!cpcnM|$Y;mbc5uCN1Vn%hl&I$kBQ3Td`|!%yC8-XIjRta?fb|Zplg~tU5U7 z>$iAfI?1OslzK<)o}4~<v`d@_YS{S+9Zu%*vhT94Oj{DDq_aoP^kS~N)FGh_X_r{e zImd1#D>9I_Ryv`fGw0Z4p2a$}GhNAaHPdxWdztnzJ&)-HOt&*l#C%;`GAQRV&XKk~ zi*4J^wp|J87OO!`u@2NDdO^LS4>V1j2kH|SfToM>pnh=$Xok36NlWxsYA#1X>Mzr> z7cwpTBGa-*GA;Wh)3SFmE&C|bvZpdF`zzB|*qZ2Sw=DCW^E#pJaAk(~7P-&7ja%8z z^iHPtI@)~zX_t5i)DS-ab&E$pP4PIWM;rk4iswKzaqONzy^u3q6D~i^Wk0AUXkV>! zj!WebH@S?nymOCK!X@P{OYVg}<DBDo-rb%_a_-0+Jz5im*_3`Im)bf6D);2pwM<)( z^3Mj<#Q$4qFYJlGRKQlX(ti9JXcRu9@yWs`8=o9}#^5s+p8!53f=-ev#O=leJYh=d z2Jss_)kx_M{FP10=>T0Xx;gFVXX%N%UTk4{u{h-3f)m?6;OW3`2zt)>Vqut<<Ghv1 z%o9`1-N=uaw=lhf<$N3IRp$4^%_#E&=tIxvUo3usr*kGD=MVTDORw>v__6rA`3atm zD)8u9HF8F2vpBz*>3pV(nV!Y8lW7mrex?_)<V%@e#dHtTeJY=1-i?yGw0Yta-!&R( z{#|V!az<(QbN+a7Li(%PRh;t((<hle&GbU1dziig`ib^7sI=HZ^fAZp*NNsZ&DTpr z2&a@Ei8}v6@tJ7yPtnsfdQLn|+m4eJveHaFOS{sKKLfAbgEEW7_xwxr#o|Z)bM#r9 zp3k&^=_K*Af3rSG(9^+_#G9Z6Trx|0$G;tI{oQ}5{x0iNq0P&<R<F>`$+$uP06Dv~ z25n!)1NtZ8p^RVaUx=S(EYUv`zs~rRZa|-18d=`&@@vE$qY<}5tMgBCy(>JKABt{` zp04W<MVV!;janqL+_gpP$UH|c;JOXkmdtr5N%|1?Y}aSvB5=F4D>FM?A93p!Yd2<J z;i?dGgWm>S5PZOOGwRZl?sGBTUNIlkjo-YD(cEIQ2!LKFf}jH;q#0rtatv`5atv{u zDA3ZxXzfvW(A(~Zv}{pfzM=U<jrkCsqK}$~Q05+!O6GY;+Bi^CjQ1P@cQU9~l;Cb! znm7*BCn`J-Y3ZT{)GwmQ$q*+Xoh=%W&K518y12|6(58!XU6V4#>s4YcPO={skBN8m zr?k&Cm+L9brQhZHJ#J&X!_;L^dLq-i@C5l<@f6c{n7Z7QGm&W%(-lltF&$vKgXvvN zpJMtBQ<uqgnKm))V7iLw#Y}fFy@TmpOrK)<4pWzhB&?|U3p6~y^e|IVOF8wm%w;;j z^Z@4{W-98aOfl1XrYo2ZFx}7e0Mo-vMTE;Ut!KJ|=>XIHOb;+U%v40VJkxrnE0_*2 z-Ouy@)5A=~3@*>Kp6Pz32bdmaDrRySru9r$FdbmJpXmXnhnb35T%Kt?(-lkynC@qK zfazhT;sh?ww4Uhz)BQ{jFg?sv%;u6z>zS@#I>2;4(*sNoGZk~VJkxrnE0_*2-Ouy@ z)5A<fJ(p)%&vXS-4J$JJ4ojnpSNv*#esxE$dB9aMzGvaP9^WU3-@E?m@*6$IHsf+* zg1f{WaW}iSyZ5;FyB~4?*6lJ+GS4yl%`41*Ge0mhJQMMj^6B0N?>g^|-tT%}^;V{> zN&8z`rmw@-<$KLHE`3t^@#)Lc_od&Ret-HS=})FVo&I9_Yw3s5-%bA@{gd=B(ha}g zKgM6+pX4v`PxnXt_5Kt6^Zkqb%lsSgHUiSw!0y2#(xJ5<zlt3NIvQ(M7JeO=jn^XN zpeJLXJ^dyxfM3n!iPQ1>SKM3VH=0}*{Sj968>3Hv?&I`5(E~_7%<0FYPa_>bBu%Cf z&-2Kc$y9QmiN1uK=cBKKzRdKM=zk#nI?H)f{1)jyM&AMb8|VC!Y0eC4y==yNpcR~+ zKjR~$m(Cy^+BqjSgW9@i#^<2d&Nu>kJLf;d`9J6US2_P3&i{Odo`GSSNz}tMb0)Pi zm1zsp1x(Lkx`FA=nI_8L!s$n5QY+7KTJ|pDp&Tns{rba9(q~KNDAbbqZRyna<>@(g zj_kGM{&^<le=su_^lvk%<i|6q?mxJdf6k;ne#tUjv#2f4EYd%HRzB#cS)_lEsg(9W zI&mLj`U9qqq*KYq(|?PS6K546ElZZnB5e~?hqt(}7jol2y!8Qoqv7L0x(vQUe+eoL z>Eqx{x>zYPK-a>fbkPHU(y^z>0lg5uq>Jq$7xZHI6V9LEO*&SdaiCX-BG9YEc+hLb zM9^=F$)J10RM4BSr_%B3*fP+4Xh#>fiQ_@{!((-EH+)tX_u%(Jy7)GHSI5g#qM-L- z7V6@An0vZ-5O1T^@r&LD(1-Cx9$h>tT0kGe?@@K}1iV}qKM^N`{!E+#`U^acsEeoJ z^}2W#KCg=x#1haK#TlRnv5V8iukc1LUHn>{4f+ON=%S1Nz`hRe+t*fsPSLtRr)z6K ztF&&=8tq)rI&D4Z94!XgsBHvo*5aTiYMVgkYv+S5)V6@0p=||SrfmZ~Q@aTCZ0x3V z(XQ<P?a(d*U8P+P+NFI1bd7c;Xt#DXXpeR+D4w+g-Kkv<`VH*{&?~hYL9f<s2EA6h z6?C`uEzs+=+d*&8?f|`Ay9@LV?H<s(v~P<(Sm4*<cj8Oo)e5!A+BB_7n}OZVT<tV% zsdl#3shz9!Y1_0PYroU}sQp#@5+%PByYzeXm-OH1U+CGcd{=`@)Z<ru!V7w)7!7)s z2!ft1!l37f2xz;g2VEiNf_8`npesci=qj-Sv{MX#c8Oh}tHr&bYs5pKSZ6`I#X-<@ z;xOpB;_sk6VswLs-};w>_KF3dF|h%3gSZZKqj(6kPy8J;F3KBm-Ye=sH;K8R=Lur~ z(IDwx0Ei;J^{*-8v{{r+&THem$?*Ouh^JHG)nR-}@F~To44-NE9EZ<ze2&Mb9G?n& zD)Fhpry8Fcd}{Hj!zYU0v(3O~CO)(9IRPJfCqX9qK;Jj0@AuXBaoX{$(mWUOg*aJ# zpN{W3@wxa5K4;>0<a@+D+L_{Me7~g4b<NY~x=z98bbOZMvl5>*_?(MR44-~|ns$$N zpLkBc5AQsBUQpQ{*8<lD*Id^oe74}T4WEl$Cm~<s`4>gZpidAsisBPQ#Hb*ZW}Oo2 z+|<)GTeS9c^fzu=y}GL}E*iJ=cgeIPxun0l$5E<rQ+H2iSDz!NDb^eB@96E1i+Ln$ zB?~)k<+`p_{o=IMtK(h$D=M(%mv5Jl8Dc4zu|5UB*@Uu-J685|iBq<m*s;EAddudH z^&0>iR(AJv_iqsmy<0?6tS8ndPNC+Yz``!*+{bkm^>?6pS6q@s-BgpMozdODwxxH| zda-!RhOUO5?v8j@oZ7BZ&4_uu3p)C`dizgBoAC`DtGXQhice>e4g(Qx>gkBb8~X98 zjFp@ElZq4fl&=1@vCag$As+AQ>u>Go?&<1m*}ST2Lw|RySIFE3XuoA>){@??%^P5% zuFl14`(o#()^sYV3`LE{#e%-rn!b+pj?t6(i9V>|OU;hAZo1$Cm8nwA9sM0*{;D-> zSUEQ5b@XiNYHt_qa*Rd$hFDy*$5yWvt9xP{{cF2=Heg`7d#zMwY!il5WpC<<^{!Fr zc4_POl`BR2`tDwg%$i=&eqKM1rutsgeL)w5vmarA`}(Z{Xc9xZlnWz$9=p=1o7T7V zbghqzS*@|YRb9<pt2;LJ^v7qP+uq*TvFcpB*QB+(tEW@6VkG8uV#K>wcX##8@9JIC zzgAFF3;McNcW+i1OR1w`<x1`#DcQb3oO;@+Ey``$mC-BP6VBKvPVDRI>J^Ptv)vj# z(cZDDe^W<~Xz%Xr?Ak2adtlJ^*m+%ju-N(Ydi$#?lVEMNXpF^rWcy%8WNJwwiBv^x zBG*c@s6=*Er7fbiI+1OqTWPqgG7K!vyx#8q?hd6uJLWZf9MejUzZ!NLbsF?VuqvkL zqAi$@I1=H`H1m)PQW$+vQD8bvc5xmXwYzu2rhcl9xFA-=Hud(4PV%(I?tTOk7>4Hd zy!ia?{{Eh>mfp_pj$Y9thpC}&&8GDjy3;oGpSF5oNAH@h#Kf?|R!?lzxlOSR2pBZG z;EQDSZrLgJD2j22B<nZ85&BN->h0=77acQJ_GbD*DAtWQWR+ah)puU^DnySsxn-i= zj?PXPEY{o6LxSVDthcmGl<9(Fa@!r`=hOqiLqb7GSpo)KxlX{X;gvm|adDn9&^*$A zsQ$*V7{^6R@2XfQMnR1M0@mh!v8JoPeaYh1h&ZvUpOk81Bg^p1Oy%T?jj-K|q3P~C z4U@Nn`jXI`Eh%RuD+a^$u0pKsi^ck-OOQF_)Df$brWUu<w6+7wN^{rBO>5S4^)(`t z#c7Hs;-j*5b9cv@-dMc9d({x7DY|1ybqg6EPLr+!?Nygf-PF@VQnAYLpfBoLLpCP3 zs=xcZ4)VRGzAgxv#|ssLd^be^W%~9CD^V#<K@bzCboYvLyWl&WqO%(_pcfTZs#R}Z zr)akF)_3%Fh_xHA<LQRq_M(|BaA;bh;0XQg{WQ9i>cyw4bG5xRa^_0Ra!#!6h_8)T zRkpA0J+H#f*p!+PudPlgk(y!2=olm<kz+|o<ZM!6WKIXonb>O5EzV+AON#depbx97 z5auzPWWYt(Z>NY3U*!NySjKyrBNQ0g&+qCuw;f@%3o9&am?)Rbh~p2x#nq_xVjWgV z+o%@HitwZhPaR4qCMByKY1NZBztL)NzFa$0K4QT7Esip&<K<v=t>4h^EUE^tHD&CQ zFpQprVe%x5fg|h~lhh0)!BIkr7(8eWRg)}GIRqnyNZSbmVe6&1G`fz0H7YH~?X=bN zX|z-FWVp9-Hze<+7AMBXl9AZ7S#_kZoB>y1p2Jg4Tb-0^RhT8`@*>uMsoF=Xb$Irw z_V$L}SnncC#;z^p9Opawy5q54L<6d!oN#^&QH*wCF--nSF{H?ZszXcdS{$P#4Pipr zqyyJV4R}LVcSLN8i0+D7u?e4Utnir5q8rO0hF+{jdNsb!i-_~&w`EcwmE0mO;29?a zLM7g~ungC2WKL|PLFIg`YH#3DRqc(!j;KrG9cvu%)y`ks(T8;*o+v2nEsENqVBfSJ zp}l1zwkx<4Kn&=@(hDZ<SmhU1irBebyql)gg=S%EUu^x{j^0je1k{>Ixhm(BuJwqD zh|^uzl&V-i?=-PE#(|nQW8#dy?tbje)%rOP;T7S4H-a+R#VZLfn4Fs15l;Xq2R&<7 zrlX`>@D_G;blPGU$JAm0GsMMwgm7{Q-nd|i@9BXXp_}pPydmgbCFapp1C~RztY8<v zer3-Vs|H*{)gUXhZ0=gMsUIPaw)I?$GdHk<k}<F;oxQrfy<`2PRUNC=c9o0PO}(pD zRATkE+OP!A@9y0w&RC0pX=?yahN>h{mZsH=JGrTkE?k7X;+WUFI!1*g!ti0^1C6ln zM|YE2uTV7_aV;boIy(W^uk7k$0VJ2Mgh&$cog0DPI2=L_7PL&#&(hvuNL;0z*L5oG zMv@w@#EhgJA2l>D&X-cuR@0_<e{8+&t8p9|bc<PutI_rao8(TWqqjHK573}O)`E_B zzue8F&e2WSWTr@1v=$@MbgUvOhOWN0Yt^~&p_)V#Nmf`k=P2LMt0G0Ru2rcOv2{LX zEvtvB>}WH&shXpd9!A63)M~U69J7jbL)IQvN1U)E+mRb{6dy)Oyhq4Uj~tk`zFbd+ zhGbJTq!xD!*HGmfM<_p(J2a)1r%@eNo91Cl4<)-LwRFNnL#f_6eDR^ASCos@&P!-9 zYe66FqPynNu?p?1dFgEK>c^=@e72axF__}q3Dsf}UnU$^QB~CtsfaW*S65UtHMKTW zG*-0KAg8jnwzaCMs;Vj4Qdil~SY<64bNS?eu0;6i6W0_nu&WiNl`e|ZlHzDCVl`J& z+0+=RuBmNkt!}KTtFA7ui#9|WtD@DBXr!_!T3*>$QBxCXthCBUYpWx*4UN@R)s4~C zrs~$}>bmNxil&yjXeH{kG}J_*RpqtiP0qeyDYrV;T-(|ZiL^#)8k(vj&E<7<<u&Ea z<+YV)p{lB}x~{b~T2)zIVU@40tE_2=Ha0i5);70Rmp8RkS5!Atlt(IS8lh;UqB)BC zHBEN;rmDt<hPsB@rrOqurt*fyXiH07O<i4MMYO4^qPDiSGTPi+)6iOH$uBRDwA9vC zltW%^OG9O2Wphnqb9rmDx~Z|b7E0DNRzpCuJvb3qs2PJ&-C7HqMeC~260~b*ZmOwh zsB38{FK;TZX>75rRnbsU-C9-I4AVrbA`Pvrl~GuzvZX0f*HGD7(}I`EMysN&t(HEK z)|Sf3y7G!hOHEaCU2SDcW3;?F+7xMQYOScQZmMgpsf<=NHa9!1i%pTTZf&$R+EQIp z-B49iTh)w2WpkuF8i`cZVFc?M8<D84s*Kv@%Olm1n)2$Z)<_hE>lzvxYigq9Rn?W1 z6}6G-rmB|a%I1ouh;7|+_(WrCLsg`vv8pao-cncB&|Fzl*H9j<YpttlsjaAvl-E@@ z+SaOwV$dM2Ioi_DQb$IvtZiy(D6fq+*OW&qVYH_5@@P$?rGK=lxxA*PqP4cFuBo=7 zF47XMZjC~x>ZZy{)M<`H>dKp28*Fc?tHWHWj=*IaS}NhG_=bPf!5_+N>nd8Q=aGum zmKs}rWnF7aOQgKA9Ij9U?`UkQt88vXEu<qD=Ehc(t}M68S5?(DR5dm=Rn=gKDjI8B zqjeQkt+k{y_qDpFrmD4~!M0~@V@m}bAlg_}TT@Y80avQ2Y%PyeLFe*1XjvC6Z)s?% zsj}p^M9b^Ss~g}TO^p?`b=A#{<>k%Mx@dDP)M~DSvqE51b;3K!tDE3M<<W+UhG<J; zT|;$ad1EB{f46sav5_TLx%#@h@9l28ardxfSF(pDc$IxvEp4}d+LD*J+ik~IW@d-6 zJ?mY8ni)@f*Q{r3+%r2fS&eY`kw8M?M~So`BISWdtN<wwNT3KL9su#MNIc{rLP5#{ z4?Lj21CLR{_nlL9Z{6<ptOGj_DBCl)>eQ)Ir%s(Z^>a_%d%eEgY0NFP7cu<Wo!O<? zSpQ2)>kDhp`ZDYW_P<eI!1!w71_&c>etmv%4H*q6*~zmA>tDbfRCB2V^KNe}cb3=I zn)CIA#YJ{;v(;?1>djVc4|8*kWmwq4`o=mG+nk$SXfCa<!9E&wj0EUmtvx^6sHdzI z+jncNuz<yS3*)A<)>&W1*hd4F7EuVJt3E%su-0tMFLu@vZM8bHa~P4$cDvKWu&J+a zV6d-YLV&F6i<l@Ht;M-STXVBWc3O*_c4vLQGq*mAscxY?+eCpzXSTW4X)HGv8;vHM zFPI{AbEPg*h24~e38d9nL)+&zW|!A7;FnvNF*=RbTzvyG*lfGCyo7noHLD4t*6iBS z#@u>m87AE5tk+@v?dHZ(Yj(B{EjG~Y^9}6e)$J!S)Y3mXhCi=&AUnJc{d(N$T|e%N zlgz;9mn3fV=mOk6f?EyFe0cu)J+9e(x5@MzfZWTcJc8;$*VPUi0$s-pc81%x!GZu; zF%~3uegt;=4uaT%IMkRcsHBf9AWl(YtV0tU3S|v|TUOaF5U?x(ktGpiiC9=NEi3^j zO8_3r#CvuFw@UB!=q9x8v^Cs+=~h4G(H0%1G1qU=`F#A)`an_sgp%_Xjyrr8tNcVz zHHfth0Bjoou?<A94Tz-;OiLR8Xd3|7HUQF2!0`@T^m;pv8=E^8(tCAxmo6^DzPW~5 z*xns;?fAZhq^$K7Z_|S8ExvefL{dE=0$)pYqxZ`X4o|^k1HRq<+crwHhn%-yYqUVC z73N9Hb!X9qL;g^2M5qo+)a79Yt&-VyPyvpmy6}SYyXXMkRZrIu-25&P1KnHw?k)Py z`s#i}#)Esjb?$cICF+XDQO+E!Q=+Fgq&UDp$v)3NC@}nsS0B*d2|ya)oQ;Z&eUGXj zcQ__TTrjK~aLcy(?o7hQ+BDoXC&wOcP)dB2ZcJq_AgkRxu^0g0%X>m<NnFL&(@8S8 z12kpFA4p@A(%Z&3I;qee<4H3WCNKImxQVnC$4LV7QcfUS6JgQz@qz6f$0LOurdH2i z%+FFQ_B`tL<Ilq#%nH`&DijyYpp!7>IGB;BhB6Q4s+OR)QJG#>in2!0#Py16GEUKj z>uFMwPD8%aQu~LDeXLIj-<7y4)07VDQ#wayn$lr?O6LMiQ#!0q89PVQq%qp3wK6$l zc8!YBK5gt$9pLL6t3IujYlyF-WkuGGsONs%2|hAy27Zn|P|js_;B}@ht|UFciA8J~ zNI0qCsrT?$r4tEtv?Qcf5{n)l0e$geA)6=kj=wA9<=K)OJRl$$fuzk$`Rx=kO0^L4 zT(Hz`t>Dt5s!U-Lo+-4?Je3hYX<$9oQlF!+xM7|)V-#1P&%m<-Y*1WZ;yzBd!ov@= z*vm;~96e)AIl^t<j>>TjOVOw6PiGA`J)J*F18E9f_}!X={Qx$5T(V^?L5vjyp?DP$ z$IC-}B4<|+m0X#{L>7s1x=sL~j%As!FqsoKuSEq+iZSVoRTptxIEV0l_2*^Unk+xN zkPPut{5kwmnc%1EiDf*vHdqx=oWZO?_UGhV#=11vge(OX_UC*L<tBFz<z{gY<)&*7 z6;I0^E}nipTs-@FxOkSeIICuzQHQiF=s_*`MQomBcHqnelcYm69F#H;c&O#5c*qFm z&Z*7Loay=;OK*Zq>~lnBQd(w46@j2%sh75GSV)*IBrFuN=XJI@DV)!AR0g;^w43cz zq5<qEKDL0(0;f@Pq*sAA=?#eL<&3ImI2&9?&52%R12b2;QR&Q4RgR><J&BwA^j;*j z?H+MslFnBdMjmG3&fw_y_?-tQ-P@15d>~=vXYY2qb#BOYqo1h2s?I~mEtQvs7H~@e zVLjZay1neU9`KSo+AX<%vdalhK6Q_Q!#E46%fWJG84*HCvlBpvNQoeb;JH<3+2So( zo7*<k_6B0oWDd(w&-ZDi=jDnV=Vd~a^Ri+MaK*txYV!CXMc!&!DFHCO>(T%uAKqfs z&K4k{h%vhsvjv~0r2!-~F=p3dw%}5+G=PLA#_U=QJa3kU5NY7obr?W5Riv9uZ>?{p z*7c^j$&+XnCE(E^m7*k>Rkf!PRj-Gju{GJ*PzPbOm<f&8Zl*M13z^c0EkJ5RQ;=LM zyV*<)N0$Pn2yTfWT#777vx`0P*w8(zp*?B#8#eWZq~5ftHzh^mz@cfp&z_C3PVb~h zcGL|gG#@kloExjd51NYBhS8997)gn*_WC^A$1_enIiuHyofO>a@0{YX!>#@X&hBwO z&xc0)JY1n@eS@<))zP)y!{kv=p4@Nm<B_lZx8)AO`anQTciY;@N&Ix&>+po|!AT*b zv!O50H8AhNCFC9;#^Y0XbZUj6&Qvjo!&HZz^Bzv^s;PDH*cHyj`znAnKiZul-0AQ2 z<C6!d%h9#&zu7xIw%(^<>ZhDf`VzoTCT_3+=4;0|UEjZtBmXpKq5UCQ>#^U+W+}T- zhnoZS!Y_A02|;;r`AF>5K3u7v8y~z5knv9Kg2IvX;?fEA`Qi;`kCYDskUe;#cmKiZ zy}s>MaZGz1Yl*b6!xn{X>8Oun;&tcwTzr-KnnW$=j*qM(?y`|J#JR)f2L9C8M^=!i zbz}`m_HY%x7vK7nJuRnl58+@wFYgFq+DX*TNy!{zpI`6t$^MiVyo<+X?qNk}!v%w9 z!0y;5z~xaP`*6_Ky?yNM@d`luF}=awQ}iFnb(^w&{A`~MS24qnU)bGe#1}UE41|3q zTxtBzK-Oo&R?ccZerfd%?|;wtqlamK_ul^7e7qmWJMrcs9-><QsRQyN44yXhE>ixf zgW)0!o<5u|!r>_<ev#sQN8`M1yh!<{S?xv2@BUvIJk`K2BEi#5+2g=%w4OZLo$mua zGns;M%R(x>1L@8_l2>+o)Z8PUsy2O;QsK79D+x06i^b`#z1818Jlt0QB`GcT^!6c~ zn~xLxI-gFzxg*cc3P%CCQoeSt$8}Nb8N_z|rE-`gkw#gQ-_Apx`#Zs7hJwS|JEAU? zP0mjTs_=49bbJ5S5#Jd}%MX1D@9wR8ce+-^$EV#n#SRd+pemeJ@P&j!D4fCUB17C< zrrEZX)oTafq=f`TRkoYrmTe#3?eYCG9Cxa0(15yoghcqZ@l@~IuN|=QN+Wv|zG-D- z&*u#2m3?^~N}i78){+O_b}uCx)A(tL)c(f4N@=_!ZF<_p%?=;CIM`#yxn;-JinE-6 zyRRqgT##Zr9<jyWrwQ4oT;Vf1@66LHs4ix*zU}PHcP=x7Y3EsXY3EjUY3EaR>DZy{ z5V1GeA!1juL&Sb$B5ZpolWPvq2hv~g1xunKQA#CqUejEL=gYOZbjW&yBTukwzB4rI z9<|s}zEMY+IO3e-qnw+LI_;WtmBQl&KMb5O^uW;lLf;D=FZ8<5<wAc8oh`9*$n*bD zH#kSMUWXg{J{(_%!{eX&Qf~afwz=EiKR!J=yq!D=jwjfY?fomgM?JiA{3(2E2@iJP z$8`(uhHoSO0^TM!jjMR)8!sH;YaO?duHminQ^a_^1>q^u_wj}~zSabY^rv`>+`P2` z4y0(KEZ#pAd>?OV*YK`7Y4L7{a3rr|d=j3#6H2Y=F>>zVMY<Z^{AR6(xcC;wW2w21 z_ruLEoL>(mJ_XNxspsxM8~P%Vwp826dZ+=sGJ>#2?(dw>{TOom5~!5>AUC%BP^7Qn zVR@%L*Jjls>!6H1v=DW@>gw|Kpc<n*@1o_Dj8fhM$Ggz!A<7=fi-u<T;-%k(T<j6b zj6Vc$cz#Lt)REQ4Td22(n(yGN4}QxZLJIc(F=V2J+``3H-Gc7%ez`|$KI3W{wuz)I zHDg}zb*8$qvcB<j4o8rXeRxMCWe+G{+Gx@X%8|5qrblE)oztWwZfitoQ%ZQ6!d0~D z8b*hiUB~OBCn!T3U@z9pd-ztt6U6L8YNHQ5(6-+*_}kg|(7^d6XfbMkl>Sj%W)!bE z@_Kcc7t8IV^a*%5>tkPYggzEYorI>eA>-~2`przVrMGC0_#k@eb<xCK;LN3~z+4qO zR!coaKHJI^zEcpxbH)_Nky<eL0zD~c5vL+gA762}o8oc@+-W0S<SS=}ChQ`0!VlUN zUa=+2t3M1kCtF-PWNFA$Xrp%@05*kd(tqpt{L4Vge)^iot$mr!y9QbBvh;J*NNrFj zZ)m@BcH6)^W?SY8zMRrQ>LEr3?M!=?Bkvt(mv-lDf;2jUIKED$S7@*AVa`J@H=ISe zmi3XxS?wOal9BK@fP8AdXlr<YdeE;0>KtG6049U)l#H27A!~B_ZJJN*f&=^O7J7iQ z_ieF$tODj6t>=s1`<KsM{r%rL?%nu@{eLw<J{RP(WBF-B5u$Nij3;oF#`4uD$OmKj z%1gNBaW!$h9OS36`Rdtk2l;%E4}*Lm$QOfrDaelp`H8Wb!B@|6nd*xX{zv)RSf)Hx z&Sp?~wwB41^UqbLGMD+;kZKEvsEh(pp_YrvQ8b;4A~S}fD4927<*BKuoCy%+YC)!4 z2KiW&1Cz?nMdZg{7L1JWykx@KSeYye&sBCa&sE;Y<Z=>5kYW0giKOf$ljGMHO|}Rr zg3HiZ5J5~zRjE@#u+C&ML1rvN>~5yABhh8ng4Cu)D;jk)s%x~T(JCTvV>v{mL_|tN zBtf(a)lL?ltM(u#Y1qK2=O-pn@APFu{ACjrZ6-t|MP@oz<~O$Fmy}&~bgQIWrA|v! z3ammEBO;@cD_Zq+(coP)Q>gG!8~H*Pzot1>hOR@CWh9y}Pk~(kRHpi*a`r_i7(zr* zwq~YtLS8QC4Z3DJH&)C<xB^^xWM47>*tG$Lnnz+B*8~$y0NETkpeGF51S(iX_3ZaD zK@L`N_6N+YJ}D6Qm7w}0h#c?&^aJ?IP)-tk1)a!Rs!u{eqGXNPU(3KEBqk;^T|N7t za`xv%%k}Jopny#92b4qUvkxH6RP_lf`!bURzD6Kl3#O)~p$Su+g>qodQ&TVv77hZ| z!1xkG)1o4q2n7w1IIIQJU`*BIDCabQBCZ0i5LYRiubll`1U*(?tepKlQ~%E3KN$QM zga3w-IXDm%5oISogD;@MRM82r8)6_^lr@<!L{Pv?kSUco@*<c*2>XV4l@Nww3{k{} z=mx-G0?J%879u1fFJUNQLBgVhB?-qRoPc3uQE!HoXYvd}1~iULfkBZ$iNQF73Gy%H zOeU(L9hoYkY={V1&|H|MT}|hh$}$iLmXyha3<?a23`z{f8BAyk!NF8!#_O0CW~Mos zFjCo|Ado1V)#hm{^D-etVJOH#L84+&BCE1-<vTF}4OeRAd^i?Gm6>t~)kS%^rbU%e z6o@7QG=m+1D$9x~vsci*(4eR^7hNDNEl1-u3~D<&MddIXC8;QnHelF;ADUo-pc<8n zVF(s(W@KEA3L(XyJ;1Umb#TTADvX;knM&%_Ni@q~#t;Qp@a6Y_FlG>w0ZW!yL751H zL}s@V8d%v;7>uZMOy-)alV~jnBJ_u;G@+89(j+)9;C!K;5jK}i0d__vfV7E~%}7{p z3hPaWT~X|cU{_*n*_DTIR<aoA2%nCW=uo_X0WBveKw_FjPy|5J2xz216d*|>3C3Lw zb*;B9T<StZs}7<GSKppgvnK?5uGp#;TNUhTj4j3Dt_l+xcBYC?IAah`N<ZMQD-h0y z5>;w8o?&;)R3|xqG9O05sM56Ye8J{dY7-XH6~be^;=vtd6KI5vC%2+TC0Cct9e3%X z113C9d#U<X9Z9KZ>@rlH%wfQueMu}0E8$91hFOI)ME)waOMk3JL*SyOA#HJ0ZBdv4 zuB?Wz!c|xy>KCe2=+0FHSSotoRfImMMw2=aqEf~7MO+WkTv1t1N9*ZOc)*no>*?qS z;XD$AWs?>14s>2ChN`I0RShglY-)+D8&jL;$1M3@QU3Vb2?62C6;fXT^|)=v6?UcL zh6D>;*Fx7>2yo>(3tdMc3Y3MRa;^(<063`zn0H{6+2_rK2ztFbna$<Hs8B48PgG_q zGb%E~VNY8tnsB|9b#<c{tJy&{7^zrwIcPUAwNy5%M*C-{IypWLo=t7ro{G6gR)8ye zEWd~Hj^!Szt6`fmC3D>rw+5N1h+CG+*iRMh-UZv2EXG2RpTsVz`WTab@OJo<F!)MM zX6MQZ8d2jv%&L`|w2`P8g{o)2fh_^5x7KuCEaTDA#M2jBT8%ctNmOEIw92OA01LHK zk&9(^BcpQw>}@&U7Q<|%iGTBz`I)dpyHQb*2iOUYDy=v<tZ~!jp9!%=<DLc~_7hL4 zPXJ&)!ASNOQ`lN4>g<E+Y=lzS>%d;PBY_67wFm+J(R5DYuiE&JZTu%T{xchY-Nt`m z<G-@;U)%U^ZTxpO{zn^sXybpj@i%S!EgOFuYjOxt5MW;s1|`g|usiPitCO7G#xRG; zN)8yP%1n+?R1L?`=a?1>(EHi%GU6YLfjMB!h2_c)1RDrgR4&RP#LA2?jJWMUF@%MP zn~!3|X}T0~ULTLR`Iv|%#$LiQ`4Tpv00ID50`cd5qnC`B#SRjATxI0I@Da?rtQ7}z zkYB`A!Zq%Ydq{-1vbe~4f@L=^<A%WO1V8cm>8+D%-WQtmNuNygmtXk#n=j0N=eM}$ z{??1`#>ANK60Q+D{QFK!hc9NF;wu*N_>Q>pdc9Zf934rKAG~O4tHXsq!TjiG;0Ir{ z2KDJ*HGseSeT}Jr4?q0ydoDe<^X~h8`ZpgQ>~<QTt^}Y9EQfD=`=9=lX~r0f_|gFU z2;PskgLjXQ;Zoq=TF`vPxTzy5{*jJL5)m$+-%}=@caf0^5y}rWGo82TKYSEPDvJ=` z4SsZUUeh^Ao6OC5E#^X&<#(D<pF`Q0Uu`Y|OFnu}ycAO~k0l+RW!Y|2hrhYtetCSK zRCz02@)9P(A*q|?+e<J1lq<~`p9q#(a8D?8wT(&TJ6e7Z+dx{?OAZizSKCWTc}mM) zn!ljD0Dla^{5WbYfkPqYmIV%dWPhq}mD`xJ&;DAY(IAUo@92;4C%^x%8qja6!w$~U zE#LxW;GG`ElWr5&-Y;g%`!r(vdq3b%y9rNs7vVa-Y`zW8CVk&s#Mj{Id`&3-Ci|b? zhjqDPar{{exv>>z0O;V#fGbZ4Hmv7z3m!>&F8Q0mcrj)NxjZZC!#A0ns4)Lm%-8WZ zxXEK1eq(&o6jX1G;Pg$QsiWOX;9bX;gKtv@_=^<*%C4cdyW-cq2QGc!Yq(~-yc4Pa zF<NW=zn11@p>dLT;79Glk4iZb-#bW!UmfEx6U%l}yu5u-@@$L0I!=F*%i!C^CD2nF z^!c75<|#}fK^q=u=J=;5<b!Pv%3VPYPsxs?btj;uRByq@3;(*vqp~M-s%4%!(C2>& z4>dKRw43-!a|ZpaJg8-IcI{?LyyB2$Sf*FN@ewZmRHxU$habk&Gr6QiT9?Y7rWw>$ YO}Kp$q%=^=$U0*dQ`k=uKO!3VA1ycl(*OVf literal 0 HcmV?d00001 diff --git a/net/FlatBuffers/ByteBufferUtil.cs b/net/FlatBuffers/ByteBufferUtil.cs new file mode 100644 index 00000000..66e82668 --- /dev/null +++ b/net/FlatBuffers/ByteBufferUtil.cs @@ -0,0 +1,39 @@ +/* + * Copyright 2017 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; + +namespace FlatBuffers +{ + /// <summary> + /// Class that collects utility functions around `ByteBuffer`. + /// </summary> + public class ByteBufferUtil + { + // Extract the size prefix from a `ByteBuffer`. + public static int GetSizePrefix(ByteBuffer bb) { + return bb.GetInt(bb.Position); + } + + // Create a duplicate of a size-prefixed `ByteBuffer` that has its position + // advanced just past the size prefix. + public static ByteBuffer RemoveSizePrefix(ByteBuffer bb) { + ByteBuffer s = bb.Duplicate(); + s.Position += FlatBufferConstants.SizePrefixLength; + return s; + } + } +} diff --git a/net/FlatBuffers/FlatBufferBuilder.cs b/net/FlatBuffers/FlatBufferBuilder.cs index 90627fdf..a2224498 100644 --- a/net/FlatBuffers/FlatBufferBuilder.cs +++ b/net/FlatBuffers/FlatBufferBuilder.cs @@ -59,7 +59,7 @@ namespace FlatBuffers throw new ArgumentOutOfRangeException("initialSize", initialSize, "Must be greater than zero"); _space = initialSize; - _bb = new ByteBuffer(new byte[initialSize]); + _bb = new ByteBuffer(initialSize); } /// <summary> @@ -99,18 +99,7 @@ namespace FlatBuffers // the end of the new buffer (since we build the buffer backwards). void GrowBuffer() { - var oldBuf = _bb.Data; - var oldBufSize = oldBuf.Length; - if ((oldBufSize & 0xC0000000) != 0) - throw new Exception( - "FlatBuffers: cannot grow buffer beyond 2 gigabytes."); - - var newBufSize = oldBufSize << 1; - var newBuf = new byte[newBufSize]; - - Buffer.BlockCopy(oldBuf, 0, newBuf, newBufSize - oldBufSize, - oldBufSize); - _bb = new ByteBuffer(newBuf, newBufSize); + _bb.GrowFront(_bb.Length << 1); } // Prepare to write an element of `size` after `additional_bytes` @@ -475,7 +464,7 @@ namespace FlatBuffers AddByte(0); var utf8StringLen = Encoding.UTF8.GetByteCount(s); StartVector(1, utf8StringLen, 1); - Encoding.UTF8.GetBytes(s, 0, s.Length, _bb.Data, _space -= utf8StringLen); + _bb.PutStringUTF8(_space -= utf8StringLen, s); return new StringOffset(EndVector().Value); } @@ -586,13 +575,41 @@ namespace FlatBuffers /// <param name="rootTable"> /// An offset to be added to the buffer. /// </param> - public void Finish(int rootTable) + /// <param name="sizePrefix"> + /// Whether to prefix the size to the buffer. + /// </param> + protected void Finish(int rootTable, bool sizePrefix) { - Prep(_minAlign, sizeof(int)); + Prep(_minAlign, sizeof(int) + (sizePrefix ? sizeof(int) : 0)); AddOffset(rootTable); + if (sizePrefix) { + AddInt(_bb.Length - _space); + } _bb.Position = _space; } + /// <summary> + /// Finalize a buffer, pointing to the given `root_table`. + /// </summary> + /// <param name="rootTable"> + /// An offset to be added to the buffer. + /// </param> + public void Finish(int rootTable) + { + Finish(rootTable, false); + } + + /// <summary> + /// Finalize a buffer, pointing to the given `root_table`, with the size prefixed. + /// </summary> + /// <param name="rootTable"> + /// An offset to be added to the buffer. + /// </param> + public void FinishSizePrefixed(int rootTable) + { + Finish(rootTable, true); + } + /// <summary> /// Get the ByteBuffer representing the FlatBuffer. /// </summary> @@ -615,41 +632,69 @@ namespace FlatBuffers /// </returns> public byte[] SizedByteArray() { - var newArray = new byte[_bb.Data.Length - _bb.Position]; - Buffer.BlockCopy(_bb.Data, _bb.Position, newArray, 0, - _bb.Data.Length - _bb.Position); - return newArray; - } - - /// <summary> - /// Finalize a buffer, pointing to the given `rootTable`. - /// </summary> - /// <param name="rootTable"> - /// An offset to be added to the buffer. - /// </param> - /// <param name="fileIdentifier"> - /// A FlatBuffer file identifier to be added to the buffer before - /// `root_table`. - /// </param> - public void Finish(int rootTable, string fileIdentifier) - { - Prep(_minAlign, sizeof(int) + - FlatBufferConstants.FileIdentifierLength); - if (fileIdentifier.Length != - FlatBufferConstants.FileIdentifierLength) - throw new ArgumentException( - "FlatBuffers: file identifier must be length " + - FlatBufferConstants.FileIdentifierLength, - "fileIdentifier"); - for (int i = FlatBufferConstants.FileIdentifierLength - 1; i >= 0; - i--) - { - AddByte((byte)fileIdentifier[i]); - } - Finish(rootTable); + return _bb.ToSizedArray(); + } + + /// <summary> + /// Finalize a buffer, pointing to the given `rootTable`. + /// </summary> + /// <param name="rootTable"> + /// An offset to be added to the buffer. + /// </param> + /// <param name="fileIdentifier"> + /// A FlatBuffer file identifier to be added to the buffer before + /// `root_table`. + /// </param> + /// <param name="sizePrefix"> + /// Whether to prefix the size to the buffer. + /// </param> + protected void Finish(int rootTable, string fileIdentifier, bool sizePrefix) + { + Prep(_minAlign, sizeof(int) + (sizePrefix ? sizeof(int) : 0) + + FlatBufferConstants.FileIdentifierLength); + if (fileIdentifier.Length != + FlatBufferConstants.FileIdentifierLength) + throw new ArgumentException( + "FlatBuffers: file identifier must be length " + + FlatBufferConstants.FileIdentifierLength, + "fileIdentifier"); + for (int i = FlatBufferConstants.FileIdentifierLength - 1; i >= 0; + i--) + { + AddByte((byte)fileIdentifier[i]); + } + Finish(rootTable, sizePrefix); } + /// <summary> + /// Finalize a buffer, pointing to the given `rootTable`. + /// </summary> + /// <param name="rootTable"> + /// An offset to be added to the buffer. + /// </param> + /// <param name="fileIdentifier"> + /// A FlatBuffer file identifier to be added to the buffer before + /// `root_table`. + /// </param> + public void Finish(int rootTable, string fileIdentifier) + { + Finish(rootTable, fileIdentifier, false); + } + /// <summary> + /// Finalize a buffer, pointing to the given `rootTable`, with the size prefixed. + /// </summary> + /// <param name="rootTable"> + /// An offset to be added to the buffer. + /// </param> + /// <param name="fileIdentifier"> + /// A FlatBuffer file identifier to be added to the buffer before + /// `root_table`. + /// </param> + public void FinishSizePrefixed(int rootTable, string fileIdentifier) + { + Finish(rootTable, fileIdentifier, true); + } } } diff --git a/net/FlatBuffers/FlatBufferConstants.cs b/net/FlatBuffers/FlatBufferConstants.cs index ab3092c4..e30f3f39 100644 --- a/net/FlatBuffers/FlatBufferConstants.cs +++ b/net/FlatBuffers/FlatBufferConstants.cs @@ -24,5 +24,6 @@ namespace FlatBuffers public static class FlatBufferConstants { public const int FileIdentifierLength = 4; + public const int SizePrefixLength = 4; } } diff --git a/net/FlatBuffers/Table.cs b/net/FlatBuffers/Table.cs index 55182b38..4a188ff8 100644 --- a/net/FlatBuffers/Table.cs +++ b/net/FlatBuffers/Table.cs @@ -60,7 +60,7 @@ namespace FlatBuffers offset += bb.GetInt(offset); var len = bb.GetInt(offset); var startPos = offset + sizeof(int); - return Encoding.UTF8.GetString(bb.Data, startPos , len); + return bb.GetStringUTF8(startPos, len); } // Get the length of a vector whose offset is stored at "offset" in this object. @@ -91,7 +91,7 @@ namespace FlatBuffers var pos = this.__vector(o); var len = this.__vector_len(o); - return new ArraySegment<byte>(this.bb.Data, pos, len); + return bb.ToArraySegment(pos, len); } // Initialize any Table-derived type to point to the union at the given offset. @@ -126,10 +126,11 @@ namespace FlatBuffers var startPos_1 = offset_1 + sizeof(int); var startPos_2 = offset_2 + sizeof(int); var len = Math.Min(len_1, len_2); - byte[] bbArray = bb.Data; for(int i = 0; i < len; i++) { - if (bbArray[i + startPos_1] != bbArray[i + startPos_2]) - return bbArray[i + startPos_1] - bbArray[i + startPos_2]; + byte b1 = bb.Get(i + startPos_1); + byte b2 = bb.Get(i + startPos_2); + if (b1 != b2) + return b1 - b2; } return len_1 - len_2; } @@ -142,10 +143,10 @@ namespace FlatBuffers var len_2 = key.Length; var startPos_1 = offset_1 + sizeof(int); var len = Math.Min(len_1, len_2); - byte[] bbArray = bb.Data; for (int i = 0; i < len; i++) { - if (bbArray[i + startPos_1] != key[i]) - return bbArray[i + startPos_1] - key[i]; + byte b = bb.Get(i + startPos_1); + if (b != key[i]) + return b - key[i]; } return len_1 - len_2; } diff --git a/python/flatbuffers/builder.py b/python/flatbuffers/builder.py index a21f3616..dea77ebf 100644 --- a/python/flatbuffers/builder.py +++ b/python/flatbuffers/builder.py @@ -483,14 +483,32 @@ class Builder(object): self.current_vtable[slotnum] = self.Offset() ## @endcond - def Finish(self, rootTable): + def __Finish(self, rootTable, sizePrefix): """Finish finalizes a buffer, pointing to the given `rootTable`.""" N.enforce_number(rootTable, N.UOffsetTFlags) - self.Prep(self.minalign, N.UOffsetTFlags.bytewidth) + prepSize = N.UOffsetTFlags.bytewidth + if sizePrefix: + prepSize += N.Int32Flags.bytewidth + self.Prep(self.minalign, prepSize) self.PrependUOffsetTRelative(rootTable) + if sizePrefix: + size = len(self.Bytes) - self.Head() + N.enforce_number(size, N.Int32Flags) + self.PrependInt32(size) self.finished = True return self.Head() + def Finish(self, rootTable): + """Finish finalizes a buffer, pointing to the given `rootTable`.""" + return self.__Finish(rootTable, False) + + def FinishSizePrefixed(self, rootTable): + """ + Finish finalizes a buffer, pointing to the given `rootTable`, + with the size prefixed. + """ + return self.__Finish(rootTable, True) + ## @cond FLATBUFFERS_INTERNAL def Prepend(self, flags, off): self.Prep(flags.bytewidth, 0) diff --git a/python/flatbuffers/util.py b/python/flatbuffers/util.py new file mode 100644 index 00000000..abcb9c75 --- /dev/null +++ b/python/flatbuffers/util.py @@ -0,0 +1,28 @@ +# Copyright 2017 Google Inc. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from . import encode +from . import number_types +from . import packer + +def GetSizePrefix(buf, offset): + """Extract the size prefix from a buffer.""" + return encode.Get(packer.int32, buf, offset) + +def RemoveSizePrefix(buf, offset): + """ + Create a slice of a size-prefixed buffer that has + its position advanced just past the size prefix. + """ + return buf, offset + number_types.Int32Flags.bytewidth diff --git a/src/idl_gen_general.cpp b/src/idl_gen_general.cpp index 9c23c5dd..970f08cc 100644 --- a/src/idl_gen_general.cpp +++ b/src/idl_gen_general.cpp @@ -1331,17 +1331,22 @@ class GeneralGenerator : public BaseGenerator { } code += " return " + GenOffsetConstruct(struct_def, "o") + ";\n }\n"; if (parser_.root_struct_def_ == &struct_def) { - code += " public static void "; - code += FunctionStart('F') + "inish" + struct_def.name; - code += - "Buffer(FlatBufferBuilder builder, " + GenOffsetType(struct_def); - code += " offset) {"; - code += " builder." + FunctionStart('F') + "inish(offset"; - if (lang_.language == IDLOptions::kCSharp) { code += ".Value"; } - - if (parser_.file_identifier_.length()) - code += ", \"" + parser_.file_identifier_ + "\""; - code += "); }\n"; + std::string size_prefix[] = { "", "SizePrefixed" }; + for (int i = 0; i < 2; ++i) { + code += " public static void "; + code += FunctionStart('F') + "inish" + size_prefix[i] + + struct_def.name; + code += "Buffer(FlatBufferBuilder builder, " + + GenOffsetType(struct_def); + code += " offset) {"; + code += " builder." + FunctionStart('F') + "inish" + size_prefix[i] + + "(offset"; + if (lang_.language == IDLOptions::kCSharp) { code += ".Value"; } + + if (parser_.file_identifier_.length()) + code += ", \"" + parser_.file_identifier_ + "\""; + code += "); }\n"; + } } } // Only generate key compare function for table, diff --git a/tests/FlatBuffers.Test/ByteBufferTests.cs b/tests/FlatBuffers.Test/ByteBufferTests.cs index 3324f12a..58bd71e5 100644 --- a/tests/FlatBuffers.Test/ByteBufferTests.cs +++ b/tests/FlatBuffers.Test/ByteBufferTests.cs @@ -44,8 +44,7 @@ namespace FlatBuffers.Test [FlatBuffersTestMethod] public void ByteBuffer_PutByteCannotPutAtOffsetPastLength() { - var buffer = new byte[1]; - var uut = new ByteBuffer(buffer); + var uut = new ByteBuffer(1); Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutByte(1, 99)); } #endif @@ -66,8 +65,7 @@ namespace FlatBuffers.Test [FlatBuffersTestMethod] public void ByteBuffer_PutShortCannotPutAtOffsetPastLength() { - var buffer = new byte[2]; - var uut = new ByteBuffer(buffer); + var uut = new ByteBuffer(2); Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutShort(2, 99)); } #endif @@ -76,16 +74,14 @@ namespace FlatBuffers.Test [FlatBuffersTestMethod] public void ByteBuffer_PutShortChecksLength() { - var buffer = new byte[1]; - var uut = new ByteBuffer(buffer); + var uut = new ByteBuffer(1); Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutShort(0, 99)); } [FlatBuffersTestMethod] public void ByteBuffer_PutShortChecksLengthAndOffset() { - var buffer = new byte[2]; - var uut = new ByteBuffer(buffer); + var uut = new ByteBuffer(2); Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutShort(1, 99)); } #endif @@ -108,24 +104,21 @@ namespace FlatBuffers.Test [FlatBuffersTestMethod] public void ByteBuffer_PutIntCannotPutAtOffsetPastLength() { - var buffer = new byte[4]; - var uut = new ByteBuffer(buffer); + var uut = new ByteBuffer(4); Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutInt(2, 0x0A0B0C0D)); } [FlatBuffersTestMethod] public void ByteBuffer_PutIntChecksLength() { - var buffer = new byte[1]; - var uut = new ByteBuffer(buffer); + var uut = new ByteBuffer(1); Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutInt(0, 0x0A0B0C0D)); } [FlatBuffersTestMethod] public void ByteBuffer_PutIntChecksLengthAndOffset() { - var buffer = new byte[4]; - var uut = new ByteBuffer(buffer); + var uut = new ByteBuffer(4); Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutInt(2, 0x0A0B0C0D)); } #endif @@ -152,24 +145,21 @@ namespace FlatBuffers.Test [FlatBuffersTestMethod] public void ByteBuffer_PutLongCannotPutAtOffsetPastLength() { - var buffer = new byte[8]; - var uut = new ByteBuffer(buffer); + var uut = new ByteBuffer(8); Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutLong(2, 0x010203040A0B0C0D)); } [FlatBuffersTestMethod] public void ByteBuffer_PutLongChecksLength() { - var buffer = new byte[1]; - var uut = new ByteBuffer(buffer); + var uut = new ByteBuffer(1); Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutLong(0, 0x010203040A0B0C0D)); } [FlatBuffersTestMethod] public void ByteBuffer_PutLongChecksLengthAndOffset() { - var buffer = new byte[8]; - var uut = new ByteBuffer(buffer); + var uut = new ByteBuffer(8); Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutLong(2, 0x010203040A0B0C0D)); } #endif @@ -187,8 +177,7 @@ namespace FlatBuffers.Test [FlatBuffersTestMethod] public void ByteBuffer_GetByteChecksOffset() { - var buffer = new byte[1]; - var uut = new ByteBuffer(buffer); + var uut = new ByteBuffer(1); Assert.Throws<ArgumentOutOfRangeException>(()=>uut.Get(1)); } #endif @@ -207,16 +196,14 @@ namespace FlatBuffers.Test [FlatBuffersTestMethod] public void ByteBuffer_GetShortChecksOffset() { - var buffer = new byte[2]; - var uut = new ByteBuffer(buffer); + var uut = new ByteBuffer(2); Assert.Throws<ArgumentOutOfRangeException>(() => uut.GetShort(2)); } [FlatBuffersTestMethod] public void ByteBuffer_GetShortChecksLength() { - var buffer = new byte[2]; - var uut = new ByteBuffer(buffer); + var uut = new ByteBuffer(2); Assert.Throws<ArgumentOutOfRangeException>(() => uut.GetShort(1)); } #endif @@ -237,16 +224,14 @@ namespace FlatBuffers.Test [FlatBuffersTestMethod] public void ByteBuffer_GetIntChecksOffset() { - var buffer = new byte[4]; - var uut = new ByteBuffer(buffer); + var uut = new ByteBuffer(4); Assert.Throws<ArgumentOutOfRangeException>(() => uut.GetInt(4)); } [FlatBuffersTestMethod] public void ByteBuffer_GetIntChecksLength() { - var buffer = new byte[2]; - var uut = new ByteBuffer(buffer); + var uut = new ByteBuffer(2); Assert.Throws<ArgumentOutOfRangeException>(() => uut.GetInt(0)); } #endif @@ -271,16 +256,14 @@ namespace FlatBuffers.Test [FlatBuffersTestMethod] public void ByteBuffer_GetLongChecksOffset() { - var buffer = new byte[8]; - var uut = new ByteBuffer(buffer); + var uut = new ByteBuffer(8); Assert.Throws<ArgumentOutOfRangeException>(() => uut.GetLong(8)); } [FlatBuffersTestMethod] public void ByteBuffer_GetLongChecksLength() { - var buffer = new byte[7]; - var uut = new ByteBuffer(buffer); + var uut = new ByteBuffer(7); Assert.Throws<ArgumentOutOfRangeException>(() => uut.GetLong(0)); } #endif @@ -317,5 +300,49 @@ namespace FlatBuffers.Test var rereverse = ByteBuffer.ReverseBytes(reverse); Assert.AreEqual(original, rereverse); } + + [FlatBuffersTestMethod] + public void ByteBuffer_ToFullArray_MatchesBuffer() + { + var buffer = new byte[4]; + buffer[0] = 0x0D; + buffer[1] = 0x0C; + buffer[2] = 0x0B; + buffer[3] = 0x0A; + var uut = new ByteBuffer(buffer); + Assert.ArrayEqual(buffer, uut.ToFullArray()); + } + + [FlatBuffersTestMethod] + public void ByteBuffer_ToSizedArray_MatchesBuffer() + { + var buffer = new byte[4]; + buffer[0] = 0x0D; + buffer[1] = 0x0C; + buffer[2] = 0x0B; + buffer[3] = 0x0A; + var uut = new ByteBuffer(buffer); + Assert.ArrayEqual(buffer, uut.ToFullArray()); + } + + [FlatBuffersTestMethod] + public void ByteBuffer_Duplicate_MatchesBuffer() + { + var buffer = new byte[4]; + buffer[0] = 0x0D; + buffer[1] = 0x0C; + buffer[2] = 0x0B; + buffer[3] = 0x0A; + var uut = new ByteBuffer(buffer); + Assert.AreEqual(0x0A0B0C0D, uut.GetInt(0)); + + // Advance by two bytes + uut.Position = 2; uut = uut.Duplicate(); + Assert.AreEqual(0x0A0B, uut.GetShort(2)); + + // Advance by one more byte + uut.Position = 1; uut = uut.Duplicate(); + Assert.AreEqual(0x0A, uut.Get(3)); + } } } diff --git a/tests/FlatBuffers.Test/FlatBuffers.Test.csproj b/tests/FlatBuffers.Test/FlatBuffers.Test.csproj index 38d62d61..7c67274a 100644 --- a/tests/FlatBuffers.Test/FlatBuffers.Test.csproj +++ b/tests/FlatBuffers.Test/FlatBuffers.Test.csproj @@ -41,6 +41,9 @@ <Compile Include="..\..\net\FlatBuffers\ByteBuffer.cs"> <Link>FlatBuffers\ByteBuffer.cs</Link> </Compile> + <Compile Include="..\..\net\FlatBuffers\ByteBufferUtil.cs"> + <Link>FlatBuffers\ByteBufferUtil.cs</Link> + </Compile> <Compile Include="..\..\net\FlatBuffers\IFlatbufferObject.cs"> <Link>FlatBuffers\IFlatbufferObject.cs</Link> </Compile> diff --git a/tests/FlatBuffers.Test/FlatBuffersExampleTests.cs b/tests/FlatBuffers.Test/FlatBuffersExampleTests.cs index ccd5b05d..82d4fdf2 100644 --- a/tests/FlatBuffers.Test/FlatBuffersExampleTests.cs +++ b/tests/FlatBuffers.Test/FlatBuffersExampleTests.cs @@ -32,6 +32,12 @@ namespace FlatBuffers.Test [FlatBuffersTestMethod] public void CanCreateNewFlatBufferFromScratch() + { + CanCreateNewFlatBufferFromScratch(true); + CanCreateNewFlatBufferFromScratch(false); + } + + private void CanCreateNewFlatBufferFromScratch(bool sizePrefix) { // Second, let's create a FlatBuffer from scratch in C#, and test it also. // We use an initial size of 1 to exercise the reallocation algorithm, @@ -95,22 +101,40 @@ namespace FlatBuffers.Test Monster.AddTestarrayoftables(fbb, sortMons); var mon = Monster.EndMonster(fbb); - Monster.FinishMonsterBuffer(fbb, mon); + if (sizePrefix) + { + Monster.FinishSizePrefixedMonsterBuffer(fbb, mon); + } + else + { + Monster.FinishMonsterBuffer(fbb, mon); + } // Dump to output directory so we can inspect later, if needed - using (var ms = new MemoryStream(fbb.DataBuffer.Data, fbb.DataBuffer.Position, fbb.Offset)) + using (var ms = fbb.DataBuffer.ToMemoryStream(fbb.DataBuffer.Position, fbb.Offset)) { var data = ms.ToArray(); - File.WriteAllBytes(@"Resources/monsterdata_cstest.mon",data); + string filename = @"Resources/monsterdata_cstest" + (sizePrefix ? "_sp" : "") + ".mon"; + File.WriteAllBytes(filename, data); + } + + // Remove the size prefix if necessary for further testing + ByteBuffer dataBuffer = fbb.DataBuffer; + if (sizePrefix) + { + Assert.AreEqual(ByteBufferUtil.GetSizePrefix(dataBuffer) + FlatBufferConstants.SizePrefixLength, + dataBuffer.Length - dataBuffer.Position); + dataBuffer = ByteBufferUtil.RemoveSizePrefix(dataBuffer); } // Now assert the buffer - TestBuffer(fbb.DataBuffer); + TestBuffer(dataBuffer); //Attempt to mutate Monster fields and check whether the buffer has been mutated properly // revert to original values after testing - Monster monster = Monster.GetRootAsMonster(fbb.DataBuffer); + Monster monster = Monster.GetRootAsMonster(dataBuffer); + // mana is optional and does not exist in the buffer so the mutation should fail // the mana field should retain its default value @@ -161,12 +185,12 @@ namespace FlatBuffers.Test pos.MutateX(1.0f); Assert.AreEqual(pos.X, 1.0f); - TestBuffer(fbb.DataBuffer); + TestBuffer(dataBuffer); } private void TestBuffer(ByteBuffer bb) { - var monster = Monster.GetRootAsMonster(bb); + Monster monster = Monster.GetRootAsMonster(bb); Assert.AreEqual(80, monster.Hp); Assert.AreEqual(150, monster.Mana); diff --git a/tests/FlatBuffers.Test/FlatBuffersFuzzTests.cs b/tests/FlatBuffers.Test/FlatBuffersFuzzTests.cs index d9332465..2d411a2b 100644 --- a/tests/FlatBuffers.Test/FlatBuffersFuzzTests.cs +++ b/tests/FlatBuffers.Test/FlatBuffersFuzzTests.cs @@ -33,21 +33,21 @@ namespace FlatBuffers.Test public void TestNumbers() { var builder = new FlatBufferBuilder(1); - Assert.ArrayEqual(new byte[] { 0 }, builder.DataBuffer.Data); + Assert.ArrayEqual(new byte[] { 0 }, builder.DataBuffer.ToFullArray()); builder.AddBool(true); - Assert.ArrayEqual(new byte[] { 1 }, builder.DataBuffer.Data); + Assert.ArrayEqual(new byte[] { 1 }, builder.DataBuffer.ToFullArray()); builder.AddSbyte(-127); - Assert.ArrayEqual(new byte[] { 129, 1 }, builder.DataBuffer.Data); + Assert.ArrayEqual(new byte[] { 129, 1 }, builder.DataBuffer.ToFullArray()); builder.AddByte(255); - Assert.ArrayEqual(new byte[] { 0, 255, 129, 1 }, builder.DataBuffer.Data); // First pad + Assert.ArrayEqual(new byte[] { 0, 255, 129, 1 }, builder.DataBuffer.ToFullArray()); // First pad builder.AddShort(-32222); - Assert.ArrayEqual(new byte[] { 0, 0, 0x22, 0x82, 0, 255, 129, 1 }, builder.DataBuffer.Data); // Second pad + Assert.ArrayEqual(new byte[] { 0, 0, 0x22, 0x82, 0, 255, 129, 1 }, builder.DataBuffer.ToFullArray()); // Second pad builder.AddUshort(0xFEEE); - Assert.ArrayEqual(new byte[] { 0xEE, 0xFE, 0x22, 0x82, 0, 255, 129, 1 }, builder.DataBuffer.Data); // no pad + Assert.ArrayEqual(new byte[] { 0xEE, 0xFE, 0x22, 0x82, 0, 255, 129, 1 }, builder.DataBuffer.ToFullArray()); // no pad builder.AddInt(-53687092); - Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 204, 204, 204, 252, 0xEE, 0xFE, 0x22, 0x82, 0, 255, 129, 1 }, builder.DataBuffer.Data); // third pad + Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 204, 204, 204, 252, 0xEE, 0xFE, 0x22, 0x82, 0, 255, 129, 1 }, builder.DataBuffer.ToFullArray()); // third pad builder.AddUint(0x98765432); - Assert.ArrayEqual(new byte[] { 0x32, 0x54, 0x76, 0x98, 204, 204, 204, 252, 0xEE, 0xFE, 0x22, 0x82, 0, 255, 129, 1 }, builder.DataBuffer.Data); // no pad + Assert.ArrayEqual(new byte[] { 0x32, 0x54, 0x76, 0x98, 204, 204, 204, 252, 0xEE, 0xFE, 0x22, 0x82, 0, 255, 129, 1 }, builder.DataBuffer.ToFullArray()); // no pad } [FlatBuffersTestMethod] @@ -55,11 +55,11 @@ namespace FlatBuffers.Test { var builder = new FlatBufferBuilder(1); builder.AddUlong(0x1122334455667788); - Assert.ArrayEqual(new byte[] { 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11 }, builder.DataBuffer.Data); + Assert.ArrayEqual(new byte[] { 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11 }, builder.DataBuffer.ToFullArray()); builder = new FlatBufferBuilder(1); builder.AddLong(0x1122334455667788); - Assert.ArrayEqual(new byte[] { 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11 }, builder.DataBuffer.Data); + Assert.ArrayEqual(new byte[] { 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11 }, builder.DataBuffer.ToFullArray()); } [FlatBuffersTestMethod] @@ -67,11 +67,11 @@ namespace FlatBuffers.Test { var builder = new FlatBufferBuilder(1); builder.StartVector(sizeof(byte), 1, 1); - Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, builder.DataBuffer.Data); + Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, builder.DataBuffer.ToFullArray()); builder.AddByte(1); - Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 1, 0, 0, 0 }, builder.DataBuffer.Data); + Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 1, 0, 0, 0 }, builder.DataBuffer.ToFullArray()); builder.EndVector(); - Assert.ArrayEqual(new byte[] { 1, 0, 0, 0, 1, 0, 0, 0 }, builder.DataBuffer.Data); + Assert.ArrayEqual(new byte[] { 1, 0, 0, 0, 1, 0, 0, 0 }, builder.DataBuffer.ToFullArray()); } [FlatBuffersTestMethod] @@ -79,13 +79,13 @@ namespace FlatBuffers.Test { var builder = new FlatBufferBuilder(1); builder.StartVector(sizeof(byte), 2, 1); - Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, builder.DataBuffer.Data); + Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, builder.DataBuffer.ToFullArray()); builder.AddByte(1); - Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 0, 1, 0, 0 }, builder.DataBuffer.Data); + Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 0, 1, 0, 0 }, builder.DataBuffer.ToFullArray()); builder.AddByte(2); - Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 2, 1, 0, 0 }, builder.DataBuffer.Data); + Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 2, 1, 0, 0 }, builder.DataBuffer.ToFullArray()); builder.EndVector(); - Assert.ArrayEqual(new byte[] { 2, 0, 0, 0, 2, 1, 0, 0 }, builder.DataBuffer.Data); + Assert.ArrayEqual(new byte[] { 2, 0, 0, 0, 2, 1, 0, 0 }, builder.DataBuffer.ToFullArray()); } [FlatBuffersTestMethod] @@ -93,11 +93,11 @@ namespace FlatBuffers.Test { var builder = new FlatBufferBuilder(1); builder.StartVector(sizeof(ushort), 1, 1); - Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, builder.DataBuffer.Data); + Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, builder.DataBuffer.ToFullArray()); builder.AddUshort(1); - Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 1, 0, 0, 0 }, builder.DataBuffer.Data); + Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 1, 0, 0, 0 }, builder.DataBuffer.ToFullArray()); builder.EndVector(); - Assert.ArrayEqual(new byte[] { 1, 0, 0, 0, 1, 0, 0, 0 }, builder.DataBuffer.Data); + Assert.ArrayEqual(new byte[] { 1, 0, 0, 0, 1, 0, 0, 0 }, builder.DataBuffer.ToFullArray()); } [FlatBuffersTestMethod] @@ -105,13 +105,13 @@ namespace FlatBuffers.Test { var builder = new FlatBufferBuilder(1); builder.StartVector(sizeof(ushort), 2, 1); - Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, builder.DataBuffer.Data); + Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, builder.DataBuffer.ToFullArray()); builder.AddUshort(0xABCD); - Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 0, 0, 0xCD, 0xAB }, builder.DataBuffer.Data); + Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 0, 0, 0xCD, 0xAB }, builder.DataBuffer.ToFullArray()); builder.AddUshort(0xDCBA); - Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 0xBA, 0xDC, 0xCD, 0xAB }, builder.DataBuffer.Data); + Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 0xBA, 0xDC, 0xCD, 0xAB }, builder.DataBuffer.ToFullArray()); builder.EndVector(); - Assert.ArrayEqual(new byte[] { 2, 0, 0, 0, 0xBA, 0xDC, 0xCD, 0xAB }, builder.DataBuffer.Data); + Assert.ArrayEqual(new byte[] { 2, 0, 0, 0, 0xBA, 0xDC, 0xCD, 0xAB }, builder.DataBuffer.ToFullArray()); } [FlatBuffersTestMethod] @@ -119,7 +119,7 @@ namespace FlatBuffers.Test { var builder = new FlatBufferBuilder(1); builder.CreateString("foo"); - Assert.ArrayEqual(new byte[] { 3, 0, 0, 0, (byte)'f', (byte)'o', (byte)'o', 0 }, builder.DataBuffer.Data); + Assert.ArrayEqual(new byte[] { 3, 0, 0, 0, (byte)'f', (byte)'o', (byte)'o', 0 }, builder.DataBuffer.ToFullArray()); builder.CreateString("moop"); Assert.ArrayEqual(new byte[] @@ -132,7 +132,7 @@ namespace FlatBuffers.Test 0, 0, 0, 0, // zero terminator with 3 byte pad 3, 0, 0, 0, (byte)'f', (byte)'o', (byte)'o', 0 - }, builder.DataBuffer.Data); + }, builder.DataBuffer.ToFullArray()); } [FlatBuffersTestMethod] @@ -144,7 +144,7 @@ namespace FlatBuffers.Test { 3, 0, 0, 0, 0x01, 0x02, 0x03, 0 - }, builder.DataBuffer.Data); // No padding + }, builder.DataBuffer.ToFullArray()); // No padding builder.CreateString("\x04\x05\x06\x07"); Assert.ArrayEqual(new byte[] { @@ -156,7 +156,7 @@ namespace FlatBuffers.Test 0, 0, 0, 0, // zero terminator with 3 byte pad 3, 0, 0, 0, 0x01, 0x02, 0x03, 0 - }, builder.DataBuffer.Data); // No padding + }, builder.DataBuffer.ToFullArray()); // No padding } [FlatBuffersTestMethod] @@ -164,14 +164,14 @@ namespace FlatBuffers.Test { var builder = new FlatBufferBuilder(1); builder.StartObject(0); - Assert.ArrayEqual(new byte[] { 0 }, builder.DataBuffer.Data); + Assert.ArrayEqual(new byte[] { 0 }, builder.DataBuffer.ToFullArray()); builder.EndObject(); Assert.ArrayEqual(new byte[] { 4, 0, 4, 0, 4, 0, 0, 0 }, - builder.DataBuffer.Data); + builder.DataBuffer.ToFullArray()); } [FlatBuffersTestMethod] @@ -179,7 +179,7 @@ namespace FlatBuffers.Test { var builder = new FlatBufferBuilder(1); builder.StartObject(1); - Assert.ArrayEqual(new byte[] { 0 }, builder.DataBuffer.Data); + Assert.ArrayEqual(new byte[] { 0 }, builder.DataBuffer.ToFullArray()); builder.AddBool(0, true, false); builder.EndObject(); Assert.ArrayEqual(new byte[] @@ -192,7 +192,7 @@ namespace FlatBuffers.Test 0, 0, 0, // padding 1, // value 0 }, - builder.DataBuffer.Data); + builder.DataBuffer.ToFullArray()); } [FlatBuffersTestMethod] @@ -200,7 +200,7 @@ namespace FlatBuffers.Test { var builder = new FlatBufferBuilder(1); builder.StartObject(1); - Assert.ArrayEqual(new byte[] { 0 }, builder.DataBuffer.Data); + Assert.ArrayEqual(new byte[] { 0 }, builder.DataBuffer.ToFullArray()); builder.AddBool(0, false, false); builder.EndObject(); Assert.ArrayEqual(new byte[] @@ -211,7 +211,7 @@ namespace FlatBuffers.Test // entry 0 is not stored (trimmed end of vtable) 4, 0, 0, 0, // int32 offset for start of vtable }, - builder.DataBuffer.Data); + builder.DataBuffer.ToFullArray()); } [FlatBuffersTestMethod] @@ -219,7 +219,7 @@ namespace FlatBuffers.Test { var builder = new FlatBufferBuilder(1); builder.StartObject(1); - Assert.ArrayEqual(new byte[] { 0 }, builder.DataBuffer.Data); + Assert.ArrayEqual(new byte[] { 0 }, builder.DataBuffer.ToFullArray()); builder.AddShort(0, 0x789A, 0); builder.EndObject(); Assert.ArrayEqual(new byte[] @@ -232,7 +232,7 @@ namespace FlatBuffers.Test 0, 0, // padding 0x9A, 0x78, //value 0 }, - builder.DataBuffer.Data); + builder.DataBuffer.ToFullArray()); } [FlatBuffersTestMethod] @@ -240,7 +240,7 @@ namespace FlatBuffers.Test { var builder = new FlatBufferBuilder(1); builder.StartObject(2); - Assert.ArrayEqual(new byte[] { 0 }, builder.DataBuffer.Data); + Assert.ArrayEqual(new byte[] { 0 }, builder.DataBuffer.ToFullArray()); builder.AddShort(0, 0x3456, 0); builder.AddShort(1, 0x789A, 0); builder.EndObject(); @@ -254,7 +254,7 @@ namespace FlatBuffers.Test 0x9A, 0x78, // value 1 0x56, 0x34, // value 0 }, - builder.DataBuffer.Data); + builder.DataBuffer.ToFullArray()); } [FlatBuffersTestMethod] @@ -262,7 +262,7 @@ namespace FlatBuffers.Test { var builder = new FlatBufferBuilder(1); builder.StartObject(2); - Assert.ArrayEqual(new byte[] { 0 }, builder.DataBuffer.Data); + Assert.ArrayEqual(new byte[] { 0 }, builder.DataBuffer.ToFullArray()); builder.AddShort(0, 0x3456, 0); builder.AddBool(1, true, false); builder.EndObject(); @@ -276,7 +276,7 @@ namespace FlatBuffers.Test 0, 1, // padding + value 1 0x56, 0x34, // value 0 }, - builder.DataBuffer.Data); + builder.DataBuffer.ToFullArray()); } [FlatBuffersTestMethod] @@ -303,7 +303,7 @@ namespace FlatBuffers.Test 4, 0, 0, 0, 0, 0, 0, 0, }, - builder.DataBuffer.Data); + builder.DataBuffer.ToFullArray()); } [FlatBuffersTestMethod] @@ -330,7 +330,7 @@ namespace FlatBuffers.Test 0, 0, 55, 0, // value 0 0, 0, 0, 0, // length of vector (not in sctruc) }, - builder.DataBuffer.Data); + builder.DataBuffer.ToFullArray()); } @@ -361,7 +361,7 @@ namespace FlatBuffers.Test 0x78, 0x56, // vector value 0 0x34, 0x12, // vector value 1 }, - builder.DataBuffer.Data); + builder.DataBuffer.ToFullArray()); } [FlatBuffersTestMethod] @@ -391,7 +391,7 @@ namespace FlatBuffers.Test 0x00, 0x00, 0x34, 0x12, // struct value 1 0x00, 0x00, 0x00, 55, // struct value 0 }, - builder.DataBuffer.Data); + builder.DataBuffer.ToFullArray()); } [FlatBuffersTestMethod] @@ -425,7 +425,7 @@ namespace FlatBuffers.Test 44, // vector 0, 1 33, // vector 0, 0 }, - builder.DataBuffer.Data); + builder.DataBuffer.ToFullArray()); } [FlatBuffersTestMethod] @@ -438,7 +438,7 @@ namespace FlatBuffers.Test var off = builder.EndObject(); builder.Finish(off); - Assert.ArrayEqual(new byte[] + byte[] padded = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, @@ -452,8 +452,13 @@ namespace FlatBuffers.Test 66, 0, // value 1 0, 33, // value 0 - }, - builder.DataBuffer.Data); + }; + Assert.ArrayEqual(padded, builder.DataBuffer.ToFullArray()); + + // no padding in sized array + byte[] unpadded = new byte[padded.Length - 12]; + Buffer.BlockCopy(padded, 12, unpadded, 0, unpadded.Length); + Assert.ArrayEqual(unpadded, builder.DataBuffer.ToSizedArray()); } [FlatBuffersTestMethod] @@ -504,7 +509,7 @@ namespace FlatBuffers.Test 44, // value 1, 0 33, }, - builder.DataBuffer.Data); + builder.DataBuffer.ToFullArray()); } [FlatBuffersTestMethod] @@ -519,7 +524,7 @@ namespace FlatBuffers.Test var off = builder.EndObject(); builder.Finish(off); - Assert.ArrayEqual(new byte[] + byte[] padded = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, @@ -546,8 +551,61 @@ namespace FlatBuffers.Test 1, 1, 1, 1, // values 1, 1, 1, 1, - }, - builder.DataBuffer.Data); + }; + Assert.ArrayEqual(padded, builder.DataBuffer.ToFullArray()); + + // no padding in sized array + byte[] unpadded = new byte[padded.Length - 28]; + Buffer.BlockCopy(padded, 28, unpadded, 0, unpadded.Length); + Assert.ArrayEqual(unpadded, builder.DataBuffer.ToSizedArray()); + } + + [FlatBuffersTestMethod] + public void TestBunchOfBoolsSizePrefixed() + { + var builder = new FlatBufferBuilder(1); + builder.StartObject(8); + for (var i = 0; i < 8; i++) + { + builder.AddBool(i, true, false); + } + var off = builder.EndObject(); + builder.FinishSizePrefixed(off); + + byte[] padded = new byte[] + { + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, // padding to 64 bytes + + 36, 0, 0, 0, // size prefix + 24, 0, 0, 0, // root of table, pointing to vtable offset (obj0) + 20, 0, // vtable bytes + 12, 0, // object length + 11, 0, // start of value 0 + 10, 0, // start of value 1 + 9, 0, // start of value 2 + 8, 0, // start of value 3 + 7, 0, // start of value 4 + 6, 0, // start of value 5 + 5, 0, // start of value 6 + 4, 0, // start of value 7 + + 20, 0, 0, 0, // int32 offset for start of vtable + + 1, 1, 1, 1, // values + 1, 1, 1, 1, + + }; + Assert.ArrayEqual(padded, builder.DataBuffer.ToFullArray()); + + // no padding in sized array + byte[] unpadded = new byte[padded.Length - 24]; + Buffer.BlockCopy(padded, 24, unpadded, 0, unpadded.Length); + Assert.ArrayEqual(unpadded, builder.DataBuffer.ToSizedArray()); } [FlatBuffersTestMethod] @@ -569,7 +627,7 @@ namespace FlatBuffers.Test 0, 0, 128, 63, // value }, - builder.DataBuffer.Data); + builder.DataBuffer.ToFullArray()); } private void CheckObjects(int fieldCount, int objectCount) diff --git a/tests/FlatBuffers.Test/NetTest.sh b/tests/FlatBuffers.Test/NetTest.sh index ea16e472..6201549c 100644 --- a/tests/FlatBuffers.Test/NetTest.sh +++ b/tests/FlatBuffers.Test/NetTest.sh @@ -2,8 +2,22 @@ # Testing C# on Linux using Mono. -mcs -out:fbnettest.exe ../../net/FlatBuffers/*.cs ../MyGame/Example/*.cs FlatBuffersTestClassAttribute.cs FlatBuffersTestMethodAttribute.cs Assert.cs FlatBuffersExampleTests.cs Program.cs ByteBufferTests.cs FlatBufferBuilderTests.cs FlatBuffersFuzzTests.cs FuzzTestData.cs Lcg.cs TestTable.cs -./fbnettest.exe +mcs -debug -out:./fbnettest.exe \ + ../../net/FlatBuffers/*.cs ../MyGame/Example/*.cs ../MyGame/*.cs \ + FlatBuffersTestClassAttribute.cs FlatBuffersTestMethodAttribute.cs Assert.cs FlatBuffersExampleTests.cs Program.cs ByteBufferTests.cs FlatBufferBuilderTests.cs FlatBuffersFuzzTests.cs FuzzTestData.cs Lcg.cs TestTable.cs +mono --debug ./fbnettest.exe rm fbnettest.exe rm Resources/monsterdata_cstest.mon +rm Resources/monsterdata_cstest_sp.mon + +# Repeat with unsafe versions + +mcs -debug -out:./fbnettest.exe \ + -unsafe -d:UNSAFE_BYTEBUFFER \ + ../../net/FlatBuffers/*.cs ../MyGame/Example/*.cs ../MyGame/*.cs \ + FlatBuffersTestClassAttribute.cs FlatBuffersTestMethodAttribute.cs Assert.cs FlatBuffersExampleTests.cs Program.cs ByteBufferTests.cs FlatBufferBuilderTests.cs FlatBuffersFuzzTests.cs FuzzTestData.cs Lcg.cs TestTable.cs +mono --debug ./fbnettest.exe +rm fbnettest.exe +rm Resources/monsterdata_cstest.mon +rm Resources/monsterdata_cstest_sp.mon diff --git a/tests/JavaTest.java b/tests/JavaTest.java index 9a5b6763..a9dedf97 100644 --- a/tests/JavaTest.java +++ b/tests/JavaTest.java @@ -21,6 +21,8 @@ import java.nio.channels.FileChannel; import MyGame.Example.*; import NamespaceA.*; import NamespaceA.NamespaceB.*; +import com.google.flatbuffers.ByteBufferUtil; +import static com.google.flatbuffers.Constants.*; import com.google.flatbuffers.FlatBufferBuilder; class JavaTest { @@ -53,7 +55,8 @@ class JavaTest { // better for performance. FlatBufferBuilder fbb = new FlatBufferBuilder(1); - TestBuilderBasics(fbb); + TestBuilderBasics(fbb, true); + TestBuilderBasics(fbb, false); TestExtendedBuffer(fbb.dataBuffer().asReadOnlyBuffer()); @@ -244,14 +247,14 @@ class JavaTest { FlatBufferBuilder fbb = new FlatBufferBuilder(1, new MappedByteBufferFactory()); - TestBuilderBasics(fbb); + TestBuilderBasics(fbb, false); } static void TestSizedInputStream() { // Test on default FlatBufferBuilder that uses HeapByteBuffer FlatBufferBuilder fbb = new FlatBufferBuilder(1); - TestBuilderBasics(fbb); + TestBuilderBasics(fbb, false); InputStream in = fbb.sizedInputStream(); byte[] array = fbb.sizedByteArray(); @@ -271,7 +274,7 @@ class JavaTest { TestEq(count, array.length); } - static void TestBuilderBasics(FlatBufferBuilder fbb) { + static void TestBuilderBasics(FlatBufferBuilder fbb, boolean sizePrefix) { int[] names = {fbb.createString("Frodo"), fbb.createString("Barney"), fbb.createString("Wilma")}; int[] off = new int[3]; Monster.startMonster(fbb); @@ -321,7 +324,11 @@ class JavaTest { Monster.addTestarrayoftables(fbb, sortMons); int mon = Monster.endMonster(fbb); - Monster.finishMonsterBuffer(fbb, mon); + if (sizePrefix) { + Monster.finishSizePrefixedMonsterBuffer(fbb, mon); + } else { + Monster.finishMonsterBuffer(fbb, mon); + } // Write the result to a file for debugging purposes: // Note that the binaries are not necessarily identical, since the JSON @@ -329,7 +336,8 @@ class JavaTest { // Java code. They are functionally equivalent though. try { - FileChannel fc = new FileOutputStream("monsterdata_java_wire.mon").getChannel(); + String filename = "monsterdata_java_wire" + (sizePrefix ? "_sp" : "") + ".mon"; + FileChannel fc = new FileOutputStream(filename).getChannel(); fc.write(fbb.dataBuffer().duplicate()); fc.close(); } catch(java.io.IOException e) { @@ -338,18 +346,24 @@ class JavaTest { } // Test it: - TestExtendedBuffer(fbb.dataBuffer()); + ByteBuffer dataBuffer = fbb.dataBuffer(); + if (sizePrefix) { + TestEq(ByteBufferUtil.getSizePrefix(dataBuffer) + SIZE_PREFIX_LENGTH, + dataBuffer.remaining()); + dataBuffer = ByteBufferUtil.removeSizePrefix(dataBuffer); + } + TestExtendedBuffer(dataBuffer); // Make sure it also works with read only ByteBuffers. This is slower, // since creating strings incurs an additional copy // (see Table.__string). - TestExtendedBuffer(fbb.dataBuffer().asReadOnlyBuffer()); + TestExtendedBuffer(dataBuffer.asReadOnlyBuffer()); TestEnums(); //Attempt to mutate Monster fields and check whether the buffer has been mutated properly // revert to original values after testing - Monster monster = Monster.getRootAsMonster(fbb.dataBuffer()); + Monster monster = Monster.getRootAsMonster(dataBuffer); // mana is optional and does not exist in the buffer so the mutation should fail // the mana field should retain its default value diff --git a/tests/MyGame/Example/Monster.cs b/tests/MyGame/Example/Monster.cs index c554c3cd..b7844fb3 100644 --- a/tests/MyGame/Example/Monster.cs +++ b/tests/MyGame/Example/Monster.cs @@ -203,6 +203,7 @@ public struct Monster : IFlatbufferObject return new Offset<Monster>(o); } public static void FinishMonsterBuffer(FlatBufferBuilder builder, Offset<Monster> offset) { builder.Finish(offset.Value, "MONS"); } + public static void FinishSizePrefixedMonsterBuffer(FlatBufferBuilder builder, Offset<Monster> offset) { builder.FinishSizePrefixed(offset.Value, "MONS"); } public static VectorOffset CreateSortedVectorOfMonster(FlatBufferBuilder builder, Offset<Monster>[] offsets) { Array.Sort(offsets, (Offset<Monster> o1, Offset<Monster> o2) => Table.CompareStrings(Table.__offset(10, o1.Value, builder.DataBuffer), Table.__offset(10, o2.Value, builder.DataBuffer), builder.DataBuffer)); diff --git a/tests/MyGame/Example/Monster.java b/tests/MyGame/Example/Monster.java index 6048dc7b..8a5bb0e7 100644 --- a/tests/MyGame/Example/Monster.java +++ b/tests/MyGame/Example/Monster.java @@ -228,6 +228,7 @@ public final class Monster extends Table { return o; } public static void finishMonsterBuffer(FlatBufferBuilder builder, int offset) { builder.finish(offset, "MONS"); } + public static void finishSizePrefixedMonsterBuffer(FlatBufferBuilder builder, int offset) { builder.finishSizePrefixed(offset, "MONS"); } @Override protected int keysCompare(Integer o1, Integer o2, ByteBuffer _bb) { return compareStrings(__offset(10, o1, _bb), __offset(10, o2, _bb), _bb); } diff --git a/tests/monster_test.bfbs b/tests/monster_test.bfbs index 0093defa39236196ec7a5b46b46b6c25ac81c770..76057281704be584128772e75e929d6ede2867cb 100644 GIT binary patch literal 6112 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 VbLl~AAp4u!_`R@N=EqXn{{a6@Xv+Wq literal 6184 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 diff --git a/tests/namespace_test/namespace_test2_generated.ts b/tests/namespace_test/namespace_test2_generated.ts index 61cf6312..aa623a87 100644 --- a/tests/namespace_test/namespace_test2_generated.ts +++ b/tests/namespace_test/namespace_test2_generated.ts @@ -1,6 +1,6 @@ // automatically generated by the FlatBuffers compiler, do not modify -import * as NS39599748 from "./namespace_test1_generated"; +import * as NS4989953370203581498 from "./namespace_test1_generated"; /** * @constructor */ @@ -39,24 +39,24 @@ static getRootAsTableInFirstNS(bb:flatbuffers.ByteBuffer, obj?:TableInFirstNS):T * @param {NamespaceA.NamespaceB.TableInNestedNS=} obj * @returns {NamespaceA.NamespaceB.TableInNestedNS|null} */ -fooTable(obj?:NS39599748.NamespaceA.NamespaceB.TableInNestedNS):NS39599748.NamespaceA.NamespaceB.TableInNestedNS|null { +fooTable(obj?:NS4989953370203581498.NamespaceA.NamespaceB.TableInNestedNS):NS4989953370203581498.NamespaceA.NamespaceB.TableInNestedNS|null { var offset = this.bb!.__offset(this.bb_pos, 4); - return offset ? (obj || new NS39599748.NamespaceA.NamespaceB.TableInNestedNS).__init(this.bb!.__indirect(this.bb_pos + offset), this.bb!) : null; + return offset ? (obj || new NS4989953370203581498.NamespaceA.NamespaceB.TableInNestedNS).__init(this.bb!.__indirect(this.bb_pos + offset), this.bb!) : null; }; /** * @returns {NamespaceA.NamespaceB.EnumInNestedNS} */ -fooEnum():NS39599748.NamespaceA.NamespaceB.EnumInNestedNS { +fooEnum():NS4989953370203581498.NamespaceA.NamespaceB.EnumInNestedNS { var offset = this.bb!.__offset(this.bb_pos, 6); - return offset ? /** @type {NamespaceA.NamespaceB.EnumInNestedNS} */ (this.bb!.readInt8(this.bb_pos + offset)) : NS39599748.NamespaceA.NamespaceB.EnumInNestedNS.A; + return offset ? /** @type {NamespaceA.NamespaceB.EnumInNestedNS} */ (this.bb!.readInt8(this.bb_pos + offset)) : NS4989953370203581498.NamespaceA.NamespaceB.EnumInNestedNS.A; }; /** * @param {NamespaceA.NamespaceB.EnumInNestedNS} value * @returns {boolean} */ -mutate_foo_enum(value:NS39599748.NamespaceA.NamespaceB.EnumInNestedNS):boolean { +mutate_foo_enum(value:NS4989953370203581498.NamespaceA.NamespaceB.EnumInNestedNS):boolean { var offset = this.bb!.__offset(this.bb_pos, 6); if (offset === 0) { @@ -71,9 +71,9 @@ mutate_foo_enum(value:NS39599748.NamespaceA.NamespaceB.EnumInNestedNS):boolean { * @param {NamespaceA.NamespaceB.StructInNestedNS=} obj * @returns {NamespaceA.NamespaceB.StructInNestedNS|null} */ -fooStruct(obj?:NS39599748.NamespaceA.NamespaceB.StructInNestedNS):NS39599748.NamespaceA.NamespaceB.StructInNestedNS|null { +fooStruct(obj?:NS4989953370203581498.NamespaceA.NamespaceB.StructInNestedNS):NS4989953370203581498.NamespaceA.NamespaceB.StructInNestedNS|null { var offset = this.bb!.__offset(this.bb_pos, 8); - return offset ? (obj || new NS39599748.NamespaceA.NamespaceB.StructInNestedNS).__init(this.bb_pos + offset, this.bb!) : null; + return offset ? (obj || new NS4989953370203581498.NamespaceA.NamespaceB.StructInNestedNS).__init(this.bb_pos + offset, this.bb!) : null; }; /** @@ -95,8 +95,8 @@ static addFooTable(builder:flatbuffers.Builder, fooTableOffset:flatbuffers.Offse * @param {flatbuffers.Builder} builder * @param {NamespaceA.NamespaceB.EnumInNestedNS} fooEnum */ -static addFooEnum(builder:flatbuffers.Builder, fooEnum:NS39599748.NamespaceA.NamespaceB.EnumInNestedNS) { - builder.addFieldInt8(1, fooEnum, NS39599748.NamespaceA.NamespaceB.EnumInNestedNS.A); +static addFooEnum(builder:flatbuffers.Builder, fooEnum:NS4989953370203581498.NamespaceA.NamespaceB.EnumInNestedNS) { + builder.addFieldInt8(1, fooEnum, NS4989953370203581498.NamespaceA.NamespaceB.EnumInNestedNS.A); }; /** diff --git a/tests/py_test.py b/tests/py_test.py index aeef729a..1b76b61a 100644 --- a/tests/py_test.py +++ b/tests/py_test.py @@ -25,6 +25,7 @@ import unittest from flatbuffers import compat +from flatbuffers import util from flatbuffers.compat import range_func as compat_range from flatbuffers.compat import NumpyRequiredForThisFeature @@ -56,9 +57,11 @@ def assertRaises(test_case, fn, exception_class): class TestWireFormat(unittest.TestCase): def test_wire_format(self): # Verify that using the generated Python code builds a buffer without - # returning errors, and is interpreted correctly: - gen_buf, gen_off = make_monster_from_generated_code() - CheckReadBuffer(gen_buf, gen_off) + # returning errors, and is interpreted correctly, for size prefixed + # representation and regular: + for sizePrefix in [True, False]: + gen_buf, gen_off = make_monster_from_generated_code(sizePrefix = sizePrefix) + CheckReadBuffer(gen_buf, gen_off, sizePrefix = sizePrefix) # Verify that the canonical flatbuffer file is readable by the # generated Python code. Note that context managers are not part of @@ -74,7 +77,7 @@ class TestWireFormat(unittest.TestCase): f.close() -def CheckReadBuffer(buf, offset): +def CheckReadBuffer(buf, offset, sizePrefix = False): ''' CheckReadBuffer checks that the given buffer is evaluated correctly as the example Monster. ''' @@ -83,6 +86,11 @@ def CheckReadBuffer(buf, offset): if not stmt: raise AssertionError('CheckReadBuffer case failed') + if sizePrefix: + size = util.GetSizePrefix(buf, offset) + # taken from the size of monsterdata_python_wire.mon, minus 4 + asserter(size == 348) + buf, offset = util.RemoveSizePrefix(buf, offset) monster = MyGame.Example.Monster.Monster.GetRootAsMonster(buf, offset) asserter(monster.Hp() == 80) @@ -810,7 +818,7 @@ class TestByteLayout(unittest.TestCase): ]) -def make_monster_from_generated_code(): +def make_monster_from_generated_code(sizePrefix = False): ''' Use generated code to build the example Monster. ''' b = flatbuffers.Builder(0) @@ -871,7 +879,10 @@ def make_monster_from_generated_code(): MyGame.Example.Monster.MonsterAddVectorOfDoubles(b, VectorOfDoubles) mon = MyGame.Example.Monster.MonsterEnd(b) - b.Finish(mon) + if sizePrefix: + b.FinishSizePrefixed(mon) + else: + b.Finish(mon) return b.Bytes, b.Head() -- GitLab