From 2cf3f24de370b3ea7350fb0f8c5c44354a0a12cb Mon Sep 17 00:00:00 2001 From: Payne Chu Date: Tue, 4 Jun 2013 09:53:55 +0800 Subject: [PATCH 01/40] - adjusted the User-Agent to fit standard format --- Request.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Request.cs b/Request.cs index 3d13b7c..1b5afdd 100644 --- a/Request.cs +++ b/Request.cs @@ -274,7 +274,7 @@ public void Send( Action< HTTP.Request > callback ) } if ( GetHeader( "User-Agent" ) == "" ) { - SetHeader( "User-Agent", "UnityWeb 1.0 ( Unity " + Application.unityVersion + " ) ( " + SystemInfo.operatingSystem + " )" ); + SetHeader("User-Agent", "UnityWeb/1.0 (Unity " + Application.unityVersion + "; " + SystemInfo.operatingSystem + ")"); } if ( GetHeader( "Connection" ) == "" ) { From 19f9d5e091088acd79211475f34850a8d8b676d8 Mon Sep 17 00:00:00 2001 From: Yongkang Chen Date: Mon, 10 Feb 2014 11:11:06 +0800 Subject: [PATCH 02/40] fix socketException Unhandled Exception, aborting request.System.IO.IOException: Read failure ---> System.Net.Sockets.SocketException: Connection reset by peer at System.Net.Sockets.Socket.Receive (System.Byte[] buffer, Int32 offset, Int32 size, SocketFlags flags) [0x00000] in :0 at System.Net.Sockets.NetworkStream.Read (System.Byte[] buffer, Int32 offset, Int32 size) [0x00000] in :0 --- End of inner exception stack trace --- at System.Net.Sockets.NetworkStream.Read (System.Byte[] buffer, Int32 offset, Int32 size) [0x00000] in :0 at System.IO.Stream.ReadByte () [0x00007] in /Users/builduser/buildslave/monoAndRuntimeClassLibs/build/mcs/class/corlib/System.IO/Stream.cs:168 at HTTP.Response.ReadFromStream (System.IO.Stream inputStream) [0x0030d] in Scritps/http/Response.cs:217 at HTTP.Request.GetResponse (System.Object unused) [0x00142] in Scritps/http/Request.cs:166 --- Response.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Response.cs b/Response.cs index a06a1e2..9474069 100644 --- a/Response.cs +++ b/Response.cs @@ -248,8 +248,8 @@ public void ReadFromStream (Stream inputStream) } int _b; - while( (_b = inputStream.ReadByte()) != -1 - && ( contentLength == 0 || output.Length < contentLength ) ) { + while( ( contentLength == 0 || output.Length < contentLength ) + && (_b = inputStream.ReadByte()) != -1 ) { output.WriteByte((byte)_b); } From 49515d0b24f5ee3e8608467b51e0aa62670e16b2 Mon Sep 17 00:00:00 2001 From: Andy Burke Date: Mon, 10 Mar 2014 19:25:31 -0700 Subject: [PATCH 03/40] Integrate @rmalecki patch to avoid problems parsing large integers This is basically #12 with some minor formatting changes. --- external/JSON.cs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/external/JSON.cs b/external/JSON.cs index 5c3fb00..b9914ab 100644 --- a/external/JSON.cs +++ b/external/JSON.cs @@ -271,14 +271,20 @@ protected static object ParseNumber (char[] json, ref int index, ref bool succes int lastIndex = GetLastIndexOfNumber (json, index); int charLength = (lastIndex - index) + 1; - float number; var token = new string (json, index, charLength); - success = float.TryParse (token, NumberStyles.Any, CultureInfo.InvariantCulture, out number); index = lastIndex + 1; - if(token.Contains(".")) - return (float)number; - else - return (int)number; + if ( token.Contains( "." ) ) + { + float number; + success = float.TryParse (token, NumberStyles.Any, CultureInfo.InvariantCulture, out number); + return number; + } + else + { + int number; + success = int.TryParse(token, out number); + return number; + } } protected static int GetLastIndexOfNumber (char[] json, int index) From f64b0883298e6728252f5c76561b1d5b221b5fca Mon Sep 17 00:00:00 2001 From: Ignacio Calderon Date: Fri, 6 Jun 2014 15:32:58 +0200 Subject: [PATCH 04/40] ADD default value for Send method ADD virtual keyword to Send method to make it testable --- Request.cs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/Request.cs b/Request.cs index 3d13b7c..427fa64 100644 --- a/Request.cs +++ b/Request.cs @@ -137,13 +137,7 @@ public void SetHeader (string name, string value) headers[name].Add (value); } - // TODO: get rid of this when Unity's default monodevelop supports default arguments - public void Send() - { - Send( null ); - } - - private void GetResponse() { + private void GetResponse() { System.Diagnostics.Stopwatch curcall = new System.Diagnostics.Stopwatch(); curcall.Start(); try { @@ -239,7 +233,7 @@ private void GetResponse() { } } - public void Send( Action< HTTP.Request > callback ) + public virtual void Send( Action< HTTP.Request > callback = null) { if (!synchronous && callback != null && ResponseCallbackDispatcher.Singleton == null ) From 308ca8d260b4ae7b42eecb4c23647ec39535fd00 Mon Sep 17 00:00:00 2001 From: Ignacio Calderon Date: Fri, 6 Jun 2014 15:34:41 +0200 Subject: [PATCH 05/40] -- clean up --- external/Ionic.Zlib.dll.meta | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 external/Ionic.Zlib.dll.meta diff --git a/external/Ionic.Zlib.dll.meta b/external/Ionic.Zlib.dll.meta deleted file mode 100644 index 601984d..0000000 --- a/external/Ionic.Zlib.dll.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 1 -guid: 06feffd45e72b4ca28c6ffadef2e2683 From b1784df8ad683a2d81d3ecf665baf8ff8cf3a02b Mon Sep 17 00:00:00 2001 From: Ignacio Calderon Date: Fri, 6 Jun 2014 15:34:51 +0200 Subject: [PATCH 06/40] ADD ignore file --- .gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f867683 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.meta \ No newline at end of file From d80226642ef2630b5d34e8487e8aca1d84350fb7 Mon Sep 17 00:00:00 2001 From: Ignacio Calderon Date: Fri, 1 Aug 2014 11:20:32 +0200 Subject: [PATCH 07/40] ADD Serialization method to static arrays. --- external/JSON.cs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/external/JSON.cs b/external/JSON.cs index b9914ab..c5c4457 100644 --- a/external/JSON.cs +++ b/external/JSON.cs @@ -401,6 +401,8 @@ protected static bool SerializeValue (object value, StringBuilder builder) builder.Append ("false"); } else if (value == null) { builder.Append ("null"); + } else if(value.GetType().IsArray) { + success = SerializeArray((object[])value, builder); } else { success = false; } @@ -457,6 +459,29 @@ protected static bool SerializeArray (ArrayList anArray, StringBuilder builder) return true; } + protected static bool SerializeArray(object[] anArray, StringBuilder builder) + { + builder.Append("["); + + bool first = true; + for(int i = 0; i < anArray.Length; i++) { + object value = anArray[i]; + + if(!first) { + builder.Append(", "); + } + + if(!SerializeValue(value, builder)) { + return false; + } + + first = false; + } + + builder.Append("]"); + return true; + } + protected static bool SerializeString (string aString, StringBuilder builder) { builder.Append ("\""); From aed88d2240b2668122f3cc7788d157d6e3aa3d5f Mon Sep 17 00:00:00 2001 From: Ignacio Calderon Date: Fri, 1 Aug 2014 15:58:58 +0200 Subject: [PATCH 08/40] FIX restoring format --- Request.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Request.cs b/Request.cs index 427fa64..3f8c41f 100644 --- a/Request.cs +++ b/Request.cs @@ -137,7 +137,7 @@ public void SetHeader (string name, string value) headers[name].Add (value); } - private void GetResponse() { + private void GetResponse() { System.Diagnostics.Stopwatch curcall = new System.Diagnostics.Stopwatch(); curcall.Start(); try { From f8a31c612575c8bf57f69748359a018a8d5b82da Mon Sep 17 00:00:00 2001 From: Ignacio Calderon Date: Thu, 14 Aug 2014 15:37:05 +0200 Subject: [PATCH 09/40] FIX Gendarme issue with empty strings --- DiskCache.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DiskCache.cs b/DiskCache.cs index f1c31c8..d7e88a7 100644 --- a/DiskCache.cs +++ b/DiskCache.cs @@ -70,7 +70,7 @@ void Awake () public DiskCacheOperation Fetch (Request request) { - var guid = ""; + var guid = string.Empty; // MD5 is disposable // http://msdn.microsoft.com/en-us/library/system.security.cryptography.md5.aspx#3 using (System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create ()) { @@ -98,7 +98,7 @@ IEnumerator DownloadAndSave (Request request, string filename, DiskCacheOperatio if (request.exception == null && request.response != null) { if (request.response.status == 200) { var etag = request.response.GetHeader ("etag"); - if (etag != "") { + if (etag != string.Empty) { File.WriteAllBytes (filename, request.response.bytes); File.WriteAllText (filename + ".etag", etag); } From ed4ed713e1bf45807afc749d178b6b156e33ffb1 Mon Sep 17 00:00:00 2001 From: Andy Burke Date: Thu, 21 Aug 2014 14:08:05 -0700 Subject: [PATCH 10/40] Switch tabs to spaces. --- CookieJar.cs | 508 +++++++++++++++++----------------- DiskCache.cs | 186 ++++++------- Request.cs | 398 +++++++++++++------------- Response.cs | 208 +++++++------- ResponseCallbackDispatcher.cs | 2 +- 5 files changed, 651 insertions(+), 651 deletions(-) diff --git a/CookieJar.cs b/CookieJar.cs index b097d06..8d6cc7a 100644 --- a/CookieJar.cs +++ b/CookieJar.cs @@ -6,209 +6,209 @@ namespace HTTP { - public class CookieAccessInfo - { - public string domain = null; - public string path = null; - public bool secure = false; - public bool scriptAccessible = true; - - public CookieAccessInfo( string domain, string path ) - { - this.domain = domain; - this.path = path; - } - - public CookieAccessInfo( string domain, string path, bool secure ) - { - this.domain = domain; - this.path = path; - this.secure = secure; - } - - public CookieAccessInfo( string domain, string path, bool secure, bool scriptAccessible ) - { - this.domain = domain; - this.path = path; - this.secure = secure; - this.scriptAccessible = scriptAccessible; - } - - public CookieAccessInfo( Cookie cookie ) - { - this.domain = cookie.domain; - this.path = cookie.path; - this.secure = cookie.secure; - this.scriptAccessible = cookie.scriptAccessible; - } - } - - public class Cookie - { - public string name = null; - public string value = null; - public DateTime expirationDate = DateTime.MaxValue; - public string path = null; - public string domain = null; - public bool secure = false; - public bool scriptAccessible = true; - - private static string cookiePattern = "\\s*([^=]+)(?:=((?:.|\\n)*))?"; - - public Cookie( string cookieString ) - { - string[] parts = cookieString.Split( ';' ); - foreach ( string part in parts ) - { + public class CookieAccessInfo + { + public string domain = null; + public string path = null; + public bool secure = false; + public bool scriptAccessible = true; + + public CookieAccessInfo( string domain, string path ) + { + this.domain = domain; + this.path = path; + } + + public CookieAccessInfo( string domain, string path, bool secure ) + { + this.domain = domain; + this.path = path; + this.secure = secure; + } + + public CookieAccessInfo( string domain, string path, bool secure, bool scriptAccessible ) + { + this.domain = domain; + this.path = path; + this.secure = secure; + this.scriptAccessible = scriptAccessible; + } + + public CookieAccessInfo( Cookie cookie ) + { + this.domain = cookie.domain; + this.path = cookie.path; + this.secure = cookie.secure; + this.scriptAccessible = cookie.scriptAccessible; + } + } + + public class Cookie + { + public string name = null; + public string value = null; + public DateTime expirationDate = DateTime.MaxValue; + public string path = null; + public string domain = null; + public bool secure = false; + public bool scriptAccessible = true; + + private static string cookiePattern = "\\s*([^=]+)(?:=((?:.|\\n)*))?"; + + public Cookie( string cookieString ) + { + string[] parts = cookieString.Split( ';' ); + foreach ( string part in parts ) + { + + Match match = Regex.Match( part, cookiePattern ); + + if ( !match.Success ) + { + throw new Exception( "Could not parse cookie string: " + cookieString ); + } + + if ( this.name == null ) + { + this.name = match.Groups[ 1 ].Value; + this.value = match.Groups[ 2 ].Value; + continue; + } - Match match = Regex.Match( part, cookiePattern ); - - if ( !match.Success ) - { - throw new Exception( "Could not parse cookie string: " + cookieString ); - } - - if ( this.name == null ) - { - this.name = match.Groups[ 1 ].Value; - this.value = match.Groups[ 2 ].Value; - continue; - } - - switch( match.Groups[ 1 ].Value.ToLower() ) - { - case "httponly": - this.scriptAccessible = false; - break; - case "expires": - this.expirationDate = DateTime.Parse( match.Groups[ 2 ].Value ); - break; - case "path": - this.path = match.Groups[ 2 ].Value; - break; - case "domain": - this.domain = match.Groups[ 2 ].Value; - break; - case "secure": - this.secure = true; - break; - default: - // TODO: warn of unknown cookie setting? - break; - } - } - } - - public bool Matches( CookieAccessInfo accessInfo ) - { - if ( this.secure != accessInfo.secure - || !this.CollidesWith( accessInfo ) ) - { - return false; - } - - return true; - } - - public bool CollidesWith( CookieAccessInfo accessInfo ) - { - if ( ( this.path != null && accessInfo.path == null ) || ( this.domain != null && accessInfo.domain == null ) ) - { - return false; - } - - if ( this.path != null && accessInfo.path != null && accessInfo.path.IndexOf( this.path ) != 0 ) - { + switch( match.Groups[ 1 ].Value.ToLower() ) + { + case "httponly": + this.scriptAccessible = false; + break; + case "expires": + this.expirationDate = DateTime.Parse( match.Groups[ 2 ].Value ); + break; + case "path": + this.path = match.Groups[ 2 ].Value; + break; + case "domain": + this.domain = match.Groups[ 2 ].Value; + break; + case "secure": + this.secure = true; + break; + default: + // TODO: warn of unknown cookie setting? + break; + } + } + } + + public bool Matches( CookieAccessInfo accessInfo ) + { + if ( this.secure != accessInfo.secure + || !this.CollidesWith( accessInfo ) ) + { return false; - } - - if ( this.domain == accessInfo.domain ) - { + } + + return true; + } + + public bool CollidesWith( CookieAccessInfo accessInfo ) + { + if ( ( this.path != null && accessInfo.path == null ) || ( this.domain != null && accessInfo.domain == null ) ) + { + return false; + } + + if ( this.path != null && accessInfo.path != null && accessInfo.path.IndexOf( this.path ) != 0 ) + { + return false; + } + + if ( this.domain == accessInfo.domain ) + { return true; - } - else if ( this.domain != null && this.domain.Length >= 1 && this.domain[ 0 ] == '.' ) - { + } + else if ( this.domain != null && this.domain.Length >= 1 && this.domain[ 0 ] == '.' ) + { int wildcard = accessInfo.domain.IndexOf( this.domain.Substring( 1 ) ); - if( wildcard == -1 || wildcard != accessInfo.domain.Length - this.domain.Length + 1 ) - { + if( wildcard == -1 || wildcard != accessInfo.domain.Length - this.domain.Length + 1 ) + { return false; - } - } - else if ( this.domain != null ) - { + } + } + else if ( this.domain != null ) + { return false; - } + } return true; - } - - public string ToValueString() - { - return this.name + "=" + this.value; - } - - public override string ToString() - { - List< string > elements = new List< string >(); - elements.Add( this.name + "=" + this.value ); - - if( this.expirationDate != DateTime.MaxValue ) - { - elements.Add( "expires=" + this.expirationDate.ToString() ); - } + } + + public string ToValueString() + { + return this.name + "=" + this.value; + } + + public override string ToString() + { + List< string > elements = new List< string >(); + elements.Add( this.name + "=" + this.value ); + + if( this.expirationDate != DateTime.MaxValue ) + { + elements.Add( "expires=" + this.expirationDate.ToString() ); + } - if( this.domain != null ) - { - elements.Add( "domain=" + this.domain ); - } + if( this.domain != null ) + { + elements.Add( "domain=" + this.domain ); + } - if( this.path != null ) - { - elements.Add( "path=" + this.path ); - } - - if( this.secure ) - { - elements.Add( "secure" ); - } - - if( this.scriptAccessible == false ) - { - elements.Add( "httponly" ); - } - - return String.Join( "; ", elements.ToArray() ); - } - } - + if( this.path != null ) + { + elements.Add( "path=" + this.path ); + } + + if( this.secure ) + { + elements.Add( "secure" ); + } + + if( this.scriptAccessible == false ) + { + elements.Add( "httponly" ); + } + + return String.Join( "; ", elements.ToArray() ); + } + } + public delegate void ContentsChangedDelegate(); - public class CookieJar - { - private static string version = "v2"; + public class CookieJar + { + private static string version = "v2"; private object cookieJarLock = new object(); - private static CookieJar instance; - public Dictionary< string, List< Cookie > > cookies; + private static CookieJar instance; + public Dictionary< string, List< Cookie > > cookies; public ContentsChangedDelegate ContentsChanged; - - public static CookieJar Instance - { - get - { - if ( instance == null ) - { - instance = new CookieJar(); - } - return instance; - } - } - - public CookieJar () - { + + public static CookieJar Instance + { + get + { + if ( instance == null ) + { + instance = new CookieJar(); + } + return instance; + } + } + + public CookieJar () + { this.Clear(); - } + } public void Clear() { @@ -222,8 +222,8 @@ public void Clear() } } - public bool SetCookie( Cookie cookie ) - { + public bool SetCookie( Cookie cookie ) + { lock( cookieJarLock ) { bool expired = cookie.expirationDate < DateTime.Now; @@ -287,73 +287,73 @@ public bool SetCookie( Cookie cookie ) } return true; } - } - + } + // TODO: figure out a way to respect the scriptAccessible flag and supress cookies being // returned that should not be. The issue is that at some point, within this // library, we need to send all the correct cookies back in the request. Right now // there's no way to add all cookies (regardless of script accessibility) to the // request without exposing cookies that should not be script accessible. - public Cookie GetCookie( string name, CookieAccessInfo accessInfo ) - { - if ( !cookies.ContainsKey( name ) ) - { + public Cookie GetCookie( string name, CookieAccessInfo accessInfo ) + { + if ( !cookies.ContainsKey( name ) ) + { return null; - } - - for ( int index = 0; index < cookies[ name ].Count; ++index ) - { - Cookie cookie = cookies[ name ][ index ]; - if ( cookie.expirationDate > DateTime.Now && cookie.Matches( accessInfo ) ) - { + } + + for ( int index = 0; index < cookies[ name ].Count; ++index ) + { + Cookie cookie = cookies[ name ][ index ]; + if ( cookie.expirationDate > DateTime.Now && cookie.Matches( accessInfo ) ) + { return cookie; - } - } - + } + } + return null; - } - - public List< Cookie > GetCookies( CookieAccessInfo accessInfo ) - { - List< Cookie > result = new List< Cookie >(); - foreach ( string cookieName in cookies.Keys ) - { + } + + public List< Cookie > GetCookies( CookieAccessInfo accessInfo ) + { + List< Cookie > result = new List< Cookie >(); + foreach ( string cookieName in cookies.Keys ) + { Cookie cookie = this.GetCookie( cookieName, accessInfo ); - if ( cookie != null ) - { + if ( cookie != null ) + { result.Add( cookie ); - } - } - - return result; - } - - public void SetCookies( Cookie[] cookieObjects ) - { - for ( var index = 0; index < cookieObjects.Length; ++index ) - { - this.SetCookie( cookieObjects[ index ] ); - } - } - - private static string cookiesStringPattern = "[:](?=\\s*[a-zA-Z0-9_\\-]+\\s*[=])"; + } + } + + return result; + } + + public void SetCookies( Cookie[] cookieObjects ) + { + for ( var index = 0; index < cookieObjects.Length; ++index ) + { + this.SetCookie( cookieObjects[ index ] ); + } + } + + private static string cookiesStringPattern = "[:](?=\\s*[a-zA-Z0-9_\\-]+\\s*[=])"; - public void SetCookies( string cookiesString ) - { - - Match match = Regex.Match( cookiesString, cookiesStringPattern ); + public void SetCookies( string cookiesString ) + { + + Match match = Regex.Match( cookiesString, cookiesStringPattern ); - if ( !match.Success ) - { - throw new Exception( "Could not parse cookies string: " + cookiesString ); - } - - for ( int index = 0; index < match.Groups.Count; ++index ) - { - this.SetCookie( new Cookie( match.Groups[ index ].Value ) ); - } - } + if ( !match.Success ) + { + throw new Exception( "Could not parse cookies string: " + cookiesString ); + } + + for ( int index = 0; index < match.Groups.Count; ++index ) + { + this.SetCookie( new Cookie( match.Groups[ index ].Value ) ); + } + } private static string boundary = "\n!!::!!\n"; @@ -384,24 +384,24 @@ public void Deserialize( string cookieJarString, bool clear ) Regex regex = new Regex( boundary ); string[] cookieStrings = regex.Split( cookieJarString ); - bool readVersion = false; + bool readVersion = false; foreach ( string cookieString in cookieStrings ) { - if ( !readVersion ) - { - if ( cookieString.IndexOf( version ) != 0 ) - { - return; - } - readVersion = true; - continue; - } - + if ( !readVersion ) + { + if ( cookieString.IndexOf( version ) != 0 ) + { + return; + } + readVersion = true; + continue; + } + if ( cookieString.Length > 0 ) { this.SetCookie( new Cookie( cookieString ) ); } } } - } + } } diff --git a/DiskCache.cs b/DiskCache.cs index f1c31c8..f634ed9 100644 --- a/DiskCache.cs +++ b/DiskCache.cs @@ -6,71 +6,71 @@ namespace HTTP { - public class DiskCacheOperation - { - public bool isDone = false; - public bool fromCache = false; - public Request request = null; - } + public class DiskCacheOperation + { + public bool isDone = false; + public bool fromCache = false; + public Request request = null; + } #if UNITY_WEBPLAYER - public class DiskCache : MonoBehaviour - { - static DiskCache _instance = null; - public static DiskCache Instance { - get { - if (_instance == null) { - var g = new GameObject ("DiskCache", typeof(DiskCache)); - g.hideFlags = HideFlags.HideAndDontSave; - _instance = g.GetComponent (); - } - return _instance; - } - } + public class DiskCache : MonoBehaviour + { + static DiskCache _instance = null; + public static DiskCache Instance { + get { + if (_instance == null) { + var g = new GameObject ("DiskCache", typeof(DiskCache)); + g.hideFlags = HideFlags.HideAndDontSave; + _instance = g.GetComponent (); + } + return _instance; + } + } - public DiskCacheOperation Fetch (Request request) - { - var handle = new DiskCacheOperation (); - handle.request = request; - StartCoroutine (Download (request, handle)); - return handle; - } + public DiskCacheOperation Fetch (Request request) + { + var handle = new DiskCacheOperation (); + handle.request = request; + StartCoroutine (Download (request, handle)); + return handle; + } - IEnumerator Download(Request request, DiskCacheOperation handle) - { - request.Send (); - while (!request.isDone) - yield return new WaitForEndOfFrame (); - handle.isDone = true; - } - } + IEnumerator Download(Request request, DiskCacheOperation handle) + { + request.Send (); + while (!request.isDone) + yield return new WaitForEndOfFrame (); + handle.isDone = true; + } + } #else - public class DiskCache : MonoBehaviour - { - string cachePath = null; + public class DiskCache : MonoBehaviour + { + string cachePath = null; - static DiskCache _instance = null; - public static DiskCache Instance { - get { - if (_instance == null) { - var g = new GameObject ("DiskCache", typeof(DiskCache)); - g.hideFlags = HideFlags.HideAndDontSave; - _instance = g.GetComponent (); - } - return _instance; - } - } + static DiskCache _instance = null; + public static DiskCache Instance { + get { + if (_instance == null) { + var g = new GameObject ("DiskCache", typeof(DiskCache)); + g.hideFlags = HideFlags.HideAndDontSave; + _instance = g.GetComponent (); + } + return _instance; + } + } - void Awake () - { - cachePath = System.IO.Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.LocalApplicationData), "uwcache"); - if (!Directory.Exists (cachePath)) - Directory.CreateDirectory (cachePath); - } + void Awake () + { + cachePath = System.IO.Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.LocalApplicationData), "uwcache"); + if (!Directory.Exists (cachePath)) + Directory.CreateDirectory (cachePath); + } - public DiskCacheOperation Fetch (Request request) - { - var guid = ""; + public DiskCacheOperation Fetch (Request request) + { + var guid = ""; // MD5 is disposable // http://msdn.microsoft.com/en-us/library/system.security.cryptography.md5.aspx#3 using (System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create ()) { @@ -79,50 +79,50 @@ public DiskCacheOperation Fetch (Request request) } } - var filename = System.IO.Path.Combine (cachePath, guid); - if (File.Exists (filename) && File.Exists (filename + ".etag")) - request.SetHeader ("If-None-Match", File.ReadAllText (filename + ".etag")); - var handle = new DiskCacheOperation (); - handle.request = request; - StartCoroutine (DownloadAndSave (request, filename, handle)); - return handle; - } + var filename = System.IO.Path.Combine (cachePath, guid); + if (File.Exists (filename) && File.Exists (filename + ".etag")) + request.SetHeader ("If-None-Match", File.ReadAllText (filename + ".etag")); + var handle = new DiskCacheOperation (); + handle.request = request; + StartCoroutine (DownloadAndSave (request, filename, handle)); + return handle; + } - IEnumerator DownloadAndSave (Request request, string filename, DiskCacheOperation handle) - { - var useCachedVersion = File.Exists(filename); + IEnumerator DownloadAndSave (Request request, string filename, DiskCacheOperation handle) + { + var useCachedVersion = File.Exists(filename); Action< HTTP.Request > callback = request.completedCallback; - request.Send(); // will clear the completedCallback - while (!request.isDone) - yield return new WaitForEndOfFrame (); - if (request.exception == null && request.response != null) { - if (request.response.status == 200) { - var etag = request.response.GetHeader ("etag"); - if (etag != "") { - File.WriteAllBytes (filename, request.response.bytes); - File.WriteAllText (filename + ".etag", etag); - } - useCachedVersion = false; - } - } + request.Send(); // will clear the completedCallback + while (!request.isDone) + yield return new WaitForEndOfFrame (); + if (request.exception == null && request.response != null) { + if (request.response.status == 200) { + var etag = request.response.GetHeader ("etag"); + if (etag != "") { + File.WriteAllBytes (filename, request.response.bytes); + File.WriteAllText (filename + ".etag", etag); + } + useCachedVersion = false; + } + } - if(useCachedVersion) { - if(request.exception != null) { - Debug.LogWarning("Using cached version due to exception:" + request.exception); - request.exception = null; - } - request.response.status = 304; - request.response.bytes = File.ReadAllBytes (filename); - request.isDone = true; - } - handle.isDone = true; + if(useCachedVersion) { + if(request.exception != null) { + Debug.LogWarning("Using cached version due to exception:" + request.exception); + request.exception = null; + } + request.response.status = 304; + request.response.bytes = File.ReadAllBytes (filename); + request.isDone = true; + } + handle.isDone = true; if ( callback != null ) { callback( request ); } - } + } - } + } #endif } diff --git a/Request.cs b/Request.cs index 426532c..e1781c4 100644 --- a/Request.cs +++ b/Request.cs @@ -13,67 +13,67 @@ namespace HTTP { - public class HTTPException : Exception - { - public HTTPException (string message) : base(message) - { - } - } - - public enum RequestState { - Waiting, Reading, Done - } - - public class Request - { + public class HTTPException : Exception + { + public HTTPException (string message) : base(message) + { + } + } + + public enum RequestState { + Waiting, Reading, Done + } + + public class Request + { public static bool LogAllRequests = false; public static bool VerboseLogging = false; - public CookieJar cookieJar = CookieJar.Instance; - public string method = "GET"; - public string protocol = "HTTP/1.1"; - public byte[] bytes; - public Uri uri; - public static byte[] EOL = { (byte)'\r', (byte)'\n' }; - public Response response = null; - public bool isDone = false; - public int maximumRetryCount = 8; - public bool acceptGzip = true; - public bool useCache = false; - public Exception exception = null; - public RequestState state = RequestState.Waiting; + public CookieJar cookieJar = CookieJar.Instance; + public string method = "GET"; + public string protocol = "HTTP/1.1"; + public byte[] bytes; + public Uri uri; + public static byte[] EOL = { (byte)'\r', (byte)'\n' }; + public Response response = null; + public bool isDone = false; + public int maximumRetryCount = 8; + public bool acceptGzip = true; + public bool useCache = false; + public Exception exception = null; + public RequestState state = RequestState.Waiting; public long responseTime = 0; // in milliseconds - public Action< HTTP.Request > completedCallback = null; + public Action< HTTP.Request > completedCallback = null; - Dictionary> headers = new Dictionary> (); - static Dictionary etags = new Dictionary (); + Dictionary> headers = new Dictionary> (); + static Dictionary etags = new Dictionary (); - public Request (string method, string uri) - { - this.method = method; - this.uri = new Uri (uri); - } + public Request (string method, string uri) + { + this.method = method; + this.uri = new Uri (uri); + } - public Request (string method, string uri, bool useCache) - { - this.method = method; - this.uri = new Uri (uri); - this.useCache = useCache; - } + public Request (string method, string uri, bool useCache) + { + this.method = method; + this.uri = new Uri (uri); + this.useCache = useCache; + } - public Request (string method, string uri, byte[] bytes) - { - this.method = method; - this.uri = new Uri (uri); - this.bytes = bytes; - } + public Request (string method, string uri, byte[] bytes) + { + this.method = method; + this.uri = new Uri (uri); + this.bytes = bytes; + } public Request( string method, string uri, WWWForm form ) { - this.method = method; - this.uri = new Uri (uri); - this.bytes = form.data; + this.method = method; + this.uri = new Uri (uri); + this.bytes = form.data; foreach ( DictionaryEntry entry in form.headers ) { this.AddHeader( (string)entry.Key, (string)entry.Value ); @@ -88,53 +88,53 @@ public Request( string method, string uri, Hashtable data ) this.AddHeader( "Content-Type", "application/json" ); } - public void AddHeader (string name, string value) - { - name = name.ToLower ().Trim (); - value = value.Trim (); - if (!headers.ContainsKey (name)) - headers[name] = new List (); - headers[name].Add (value); - } - - public string GetHeader (string name) - { - name = name.ToLower ().Trim (); - if (!headers.ContainsKey (name)) - return ""; - return headers[name][0]; - } + public void AddHeader (string name, string value) + { + name = name.ToLower ().Trim (); + value = value.Trim (); + if (!headers.ContainsKey (name)) + headers[name] = new List (); + headers[name].Add (value); + } + + public string GetHeader (string name) + { + name = name.ToLower ().Trim (); + if (!headers.ContainsKey (name)) + return ""; + return headers[name][0]; + } public List< string > GetHeaders() { List< string > result = new List< string >(); foreach (string name in headers.Keys) { - foreach (string value in headers[name]) { + foreach (string value in headers[name]) { result.Add( name + ": " + value ); - } - } + } + } return result; } - public List GetHeaders (string name) - { - name = name.ToLower ().Trim (); - if (!headers.ContainsKey (name)) - headers[name] = new List (); - return headers[name]; - } - - public void SetHeader (string name, string value) - { - name = name.ToLower ().Trim (); - value = value.Trim (); - if (!headers.ContainsKey (name)) - headers[name] = new List (); - headers[name].Clear (); - headers[name].TrimExcess(); - headers[name].Add (value); - } + public List GetHeaders (string name) + { + name = name.ToLower ().Trim (); + if (!headers.ContainsKey (name)) + headers[name] = new List (); + return headers[name]; + } + + public void SetHeader (string name, string value) + { + name = name.ToLower ().Trim (); + value = value.Trim (); + if (!headers.ContainsKey (name)) + headers[name] = new List (); + headers[name].Clear (); + headers[name].TrimExcess(); + headers[name].Add (value); + } // TODO: get rid of this when Unity's default monodevelop supports default arguments public void Send() @@ -142,8 +142,8 @@ public void Send() Send( null ); } - public void Send( Action< HTTP.Request > callback ) - { + public void Send( Action< HTTP.Request > callback ) + { if ( callback != null && ResponseCallbackDispatcher.Singleton == null ) { ResponseCallbackDispatcher.Init(); @@ -154,27 +154,27 @@ public void Send( Action< HTTP.Request > callback ) completedCallback = callback; - isDone = false; - state = RequestState.Waiting; - if (acceptGzip) - SetHeader ("Accept-Encoding", "gzip"); - - if ( this.cookieJar != null ) - { - List< Cookie > cookies = this.cookieJar.GetCookies( new CookieAccessInfo( uri.Host, uri.AbsolutePath ) ); - string cookieString = this.GetHeader( "cookie" ); - for ( int cookieIndex = 0; cookieIndex < cookies.Count; ++cookieIndex ) - { - if ( cookieString.Length > 0 && cookieString[ cookieString.Length - 1 ] != ';' ) - { - cookieString += ';'; - } - cookieString += cookies[ cookieIndex ].name + '=' + cookies[ cookieIndex ].value + ';'; - } - SetHeader( "cookie", cookieString ); - } - - if ( bytes != null && bytes.Length > 0 && GetHeader ("Content-Length") == "" ) { + isDone = false; + state = RequestState.Waiting; + if (acceptGzip) + SetHeader ("Accept-Encoding", "gzip"); + + if ( this.cookieJar != null ) + { + List< Cookie > cookies = this.cookieJar.GetCookies( new CookieAccessInfo( uri.Host, uri.AbsolutePath ) ); + string cookieString = this.GetHeader( "cookie" ); + for ( int cookieIndex = 0; cookieIndex < cookies.Count; ++cookieIndex ) + { + if ( cookieString.Length > 0 && cookieString[ cookieString.Length - 1 ] != ';' ) + { + cookieString += ';'; + } + cookieString += cookies[ cookieIndex ].name + '=' + cookies[ cookieIndex ].value + ';'; + } + SetHeader( "cookie", cookieString ); + } + + if ( bytes != null && bytes.Length > 0 && GetHeader ("Content-Length") == "" ) { SetHeader( "Content-Length", bytes.Length.ToString() ); } @@ -186,66 +186,66 @@ public void Send( Action< HTTP.Request > callback ) SetHeader( "Connection", "close" ); } - ThreadPool.QueueUserWorkItem (new WaitCallback (delegate(object t) { - try { - var retry = 0; - while (++retry < maximumRetryCount) { - if (useCache) { - string etag = ""; - if (etags.TryGetValue (uri.AbsoluteUri, out etag)) { - SetHeader ("If-None-Match", etag); - } - } - - SetHeader ("Host", uri.Host); - - var client = new TcpClient (); - client.Connect (uri.Host, uri.Port); - using (var stream = client.GetStream ()) { - var ostream = stream as Stream; - if (uri.Scheme.ToLower() == "https") { - ostream = new SslStream (stream, false, new RemoteCertificateValidationCallback (ValidateServerCertificate)); - try { - var ssl = ostream as SslStream; - ssl.AuthenticateAsClient (uri.Host); - } catch (Exception e) { - Debug.LogError ("Exception: " + e.Message); - return; - } - } - WriteToStream (ostream); - response = new Response (); - response.request = this; - state = RequestState.Reading; - response.ReadFromStream(ostream); - } - client.Close (); - - switch (response.status) { - case 307: - case 302: - case 301: - uri = new Uri (response.GetHeader ("Location")); - continue; - default: - retry = maximumRetryCount; - break; - } - } - if (useCache) { - string etag = response.GetHeader ("etag"); - if (etag.Length > 0) - etags[uri.AbsoluteUri] = etag; - } - - } catch (Exception e) { - Console.WriteLine ("Unhandled Exception, aborting request."); - Console.WriteLine (e); - exception = e; - response = null; - } - state = RequestState.Done; - isDone = true; + ThreadPool.QueueUserWorkItem (new WaitCallback (delegate(object t) { + try { + var retry = 0; + while (++retry < maximumRetryCount) { + if (useCache) { + string etag = ""; + if (etags.TryGetValue (uri.AbsoluteUri, out etag)) { + SetHeader ("If-None-Match", etag); + } + } + + SetHeader ("Host", uri.Host); + + var client = new TcpClient (); + client.Connect (uri.Host, uri.Port); + using (var stream = client.GetStream ()) { + var ostream = stream as Stream; + if (uri.Scheme.ToLower() == "https") { + ostream = new SslStream (stream, false, new RemoteCertificateValidationCallback (ValidateServerCertificate)); + try { + var ssl = ostream as SslStream; + ssl.AuthenticateAsClient (uri.Host); + } catch (Exception e) { + Debug.LogError ("Exception: " + e.Message); + return; + } + } + WriteToStream (ostream); + response = new Response (); + response.request = this; + state = RequestState.Reading; + response.ReadFromStream(ostream); + } + client.Close (); + + switch (response.status) { + case 307: + case 302: + case 301: + uri = new Uri (response.GetHeader ("Location")); + continue; + default: + retry = maximumRetryCount; + break; + } + } + if (useCache) { + string etag = response.GetHeader ("etag"); + if (etag.Length > 0) + etags[uri.AbsoluteUri] = etag; + } + + } catch (Exception e) { + Console.WriteLine ("Unhandled Exception, aborting request."); + Console.WriteLine (e); + exception = e; + response = null; + } + state = RequestState.Done; + isDone = true; responseTime = curcall.ElapsedMilliseconds; if ( completedCallback != null ) @@ -257,7 +257,7 @@ public void Send( Action< HTTP.Request > callback ) if ( LogAllRequests ) { #if !UNITY_EDITOR - System.Console.WriteLine("NET: " + InfoString( VerboseLogging )); + System.Console.WriteLine("NET: " + InfoString( VerboseLogging )); #else if ( response != null && response.status >= 200 && response.status < 300 ) { @@ -274,44 +274,44 @@ public void Send( Action< HTTP.Request > callback ) #endif } })); - } + } - public string Text { - set { bytes = System.Text.Encoding.UTF8.GetBytes (value); } - } + public string Text { + set { bytes = System.Text.Encoding.UTF8.GetBytes (value); } + } - public static bool ValidateServerCertificate (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) - { + public static bool ValidateServerCertificate (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) + { #if !UNITY_EDITOR System.Console.WriteLine( "NET: SSL Cert: " + sslPolicyErrors.ToString() ); #else - Debug.LogWarning("SSL Cert Error: " + sslPolicyErrors.ToString ()); + Debug.LogWarning("SSL Cert Error: " + sslPolicyErrors.ToString ()); #endif - return true; - } - - void WriteToStream (Stream outputStream) - { - var stream = new BinaryWriter (outputStream); - stream.Write (ASCIIEncoding.ASCII.GetBytes (method.ToUpper () + " " + uri.PathAndQuery + " " + protocol)); - stream.Write (EOL); - - foreach (string name in headers.Keys) { - foreach (string value in headers[name]) { - stream.Write (ASCIIEncoding.ASCII.GetBytes (name)); - stream.Write (':'); - stream.Write (ASCIIEncoding.ASCII.GetBytes (value)); - stream.Write (EOL); - } - } + return true; + } + void WriteToStream (Stream outputStream) + { + var stream = new BinaryWriter (outputStream); + stream.Write (ASCIIEncoding.ASCII.GetBytes (method.ToUpper () + " " + uri.PathAndQuery + " " + protocol)); stream.Write (EOL); - if (bytes != null && bytes.Length > 0) { - stream.Write (bytes); - } - } + foreach (string name in headers.Keys) { + foreach (string value in headers[name]) { + stream.Write (ASCIIEncoding.ASCII.GetBytes (name)); + stream.Write (':'); + stream.Write (ASCIIEncoding.ASCII.GetBytes (value)); + stream.Write (EOL); + } + } + + stream.Write (EOL); + + if (bytes != null && bytes.Length > 0) { + stream.Write (bytes); + } + } private static string[] sizes = { "B", "KB", "MB", "GB" }; public string InfoString( bool verbose ) @@ -344,5 +344,5 @@ public string InfoString( bool verbose ) return result; } - } + } } diff --git a/Response.cs b/Response.cs index a06a1e2..93724ae 100644 --- a/Response.cs +++ b/Response.cs @@ -8,29 +8,29 @@ namespace HTTP { - public class Response - { - public Request request; - public int status = 200; - public string message = "OK"; - public byte[] bytes; + public class Response + { + public Request request; + public int status = 200; + public string message = "OK"; + public byte[] bytes; - List chunks; - Dictionary> headers = new Dictionary> (); + List chunks; + Dictionary> headers = new Dictionary> (); - public string Text { - get { - if (bytes == null) - return ""; - return System.Text.UTF8Encoding.UTF8.GetString (bytes); - } - } + public string Text { + get { + if (bytes == null) + return ""; + return System.Text.UTF8Encoding.UTF8.GetString (bytes); + } + } - public string Asset { - get { - throw new NotSupportedException ("This can't be done, yet."); - } - } + public string Asset { + get { + throw new NotSupportedException ("This can't be done, yet."); + } + } public Hashtable Object { get { @@ -68,14 +68,14 @@ public ArrayList Array { } } - void AddHeader (string name, string value) - { - name = name.ToLower ().Trim (); - value = value.Trim (); - if (!headers.ContainsKey (name)) - headers[name] = new List (); - headers[name].Add (value); - } + void AddHeader (string name, string value) + { + name = name.ToLower ().Trim (); + value = value.Trim (); + if (!headers.ContainsKey (name)) + headers[name] = new List (); + headers[name].Add (value); + } public List< string > GetHeaders() { @@ -89,79 +89,79 @@ public List< string > GetHeaders() return result; } - public List GetHeaders (string name) - { - name = name.ToLower ().Trim (); - if (!headers.ContainsKey (name)) - return new List (); - return headers[name]; - } + public List GetHeaders (string name) + { + name = name.ToLower ().Trim (); + if (!headers.ContainsKey (name)) + return new List (); + return headers[name]; + } - public string GetHeader (string name) - { - name = name.ToLower ().Trim (); - if (!headers.ContainsKey (name)) - return string.Empty; - return headers[name][headers[name].Count - 1]; - } + public string GetHeader (string name) + { + name = name.ToLower ().Trim (); + if (!headers.ContainsKey (name)) + return string.Empty; + return headers[name][headers[name].Count - 1]; + } - public Response () - { - //ReadFromStream (stream); - } + public Response () + { + //ReadFromStream (stream); + } - string ReadLine (Stream stream) - { - var line = new List (); - while (true) { - int c = stream.ReadByte (); + string ReadLine (Stream stream) + { + var line = new List (); + while (true) { + int c = stream.ReadByte (); if (c == -1) { throw new HTTPException("Unterminated Stream Encountered."); } - if ((byte)c == Request.EOL[1]) - break; - line.Add ((byte)c); - } - var s = ASCIIEncoding.ASCII.GetString (line.ToArray ()).Trim (); - return s; - } + if ((byte)c == Request.EOL[1]) + break; + line.Add ((byte)c); + } + var s = ASCIIEncoding.ASCII.GetString (line.ToArray ()).Trim (); + return s; + } - string[] ReadKeyValue (Stream stream) - { - string line = ReadLine (stream); - if (line == "") - return null; - else { - var split = line.IndexOf (':'); - if (split == -1) - return null; - var parts = new string[2]; - parts[0] = line.Substring (0, split).Trim (); - parts[1] = line.Substring (split + 1).Trim (); - return parts; - } + string[] ReadKeyValue (Stream stream) + { + string line = ReadLine (stream); + if (line == "") + return null; + else { + var split = line.IndexOf (':'); + if (split == -1) + return null; + var parts = new string[2]; + parts[0] = line.Substring (0, split).Trim (); + parts[1] = line.Substring (split + 1).Trim (); + return parts; + } - } + } - public byte[] TakeChunk() { - byte[] b = null; - lock(chunks) { - if(chunks.Count > 0) { - b = chunks[0]; - chunks.RemoveAt(0); - return b; - } - } - return b; - } + public byte[] TakeChunk() { + byte[] b = null; + lock(chunks) { + if(chunks.Count > 0) { + b = chunks[0]; + chunks.RemoveAt(0); + return b; + } + } + return b; + } - public void ReadFromStream (Stream inputStream) - { - //var inputStream = new BinaryReader(inputStream); - var top = ReadLine (inputStream).Split (new char[] { ' ' }); + public void ReadFromStream (Stream inputStream) + { + //var inputStream = new BinaryReader(inputStream); + var top = ReadLine (inputStream).Split (new char[] { ' ' }); - if (!int.TryParse (top[1], out status)) - throw new HTTPException ("Bad Status Code"); + if (!int.TryParse (top[1], out status)) + throw new HTTPException ("Bad Status Code"); // MemoryStream is a disposable // http://stackoverflow.com/questions/234059/is-a-memory-leak-created-if-a-memorystream-in-net-is-not-closed @@ -264,21 +264,21 @@ public void ReadFromStream (Stream inputStream) } } } - } + } - byte[] UnZip(MemoryStream output) { - var cms = new MemoryStream (); - output.Seek (0, SeekOrigin.Begin); - using (var gz = new GZipStream (output, CompressionMode.Decompress)) { - var buf = new byte[1024]; - int byteCount = 0; - while ((byteCount = gz.Read (buf, 0, buf.Length)) > 0) { - cms.Write (buf, 0, byteCount); - } - } - return cms.ToArray (); - } + byte[] UnZip(MemoryStream output) { + var cms = new MemoryStream (); + output.Seek (0, SeekOrigin.Begin); + using (var gz = new GZipStream (output, CompressionMode.Decompress)) { + var buf = new byte[1024]; + int byteCount = 0; + while ((byteCount = gz.Read (buf, 0, buf.Length)) > 0) { + cms.Write (buf, 0, byteCount); + } + } + return cms.ToArray (); + } - } + } } diff --git a/ResponseCallbackDispatcher.cs b/ResponseCallbackDispatcher.cs index f938cec..f87c31c 100644 --- a/ResponseCallbackDispatcher.cs +++ b/ResponseCallbackDispatcher.cs @@ -4,7 +4,7 @@ namespace HTTP { - public class ResponseCallbackDispatcher : MonoBehaviour + public class ResponseCallbackDispatcher : MonoBehaviour { private static ResponseCallbackDispatcher singleton = null; private static GameObject singletonGameObject = null; From f17e22e0c85500377f19efa22f208f0c47e14967 Mon Sep 17 00:00:00 2001 From: Andy Burke Date: Thu, 21 Aug 2014 15:46:47 -0700 Subject: [PATCH 11/40] Fix reading chunked gzip data. --- Request.cs | 26 ++++++++-------- Response.cs | 86 +++++++++++++++++++---------------------------------- 2 files changed, 43 insertions(+), 69 deletions(-) diff --git a/Request.cs b/Request.cs index 58fa569..8da731b 100644 --- a/Request.cs +++ b/Request.cs @@ -167,11 +167,11 @@ private void GetResponse() { return; } } - WriteToStream (ostream); + WriteToStream( ostream ); response = new Response (); response.request = this; state = RequestState.Reading; - response.ReadFromStream(ostream); + response.ReadFromStream( ostream ); } client.Close (); @@ -305,25 +305,25 @@ public static bool ValidateServerCertificate (object sender, X509Certificate cer return true; } - void WriteToStream (Stream outputStream) + void WriteToStream( Stream outputStream ) { - var stream = new BinaryWriter (outputStream); - stream.Write (ASCIIEncoding.ASCII.GetBytes (method.ToUpper () + " " + uri.PathAndQuery + " " + protocol)); - stream.Write (EOL); + var stream = new BinaryWriter( outputStream ); + stream.Write( ASCIIEncoding.ASCII.GetBytes( method.ToUpper () + " " + uri.PathAndQuery + " " + protocol ) ); + stream.Write( EOL ); foreach (string name in headers.Keys) { foreach (string value in headers[name]) { - stream.Write (ASCIIEncoding.ASCII.GetBytes (name)); - stream.Write (':'); - stream.Write (ASCIIEncoding.ASCII.GetBytes (value)); - stream.Write (EOL); + stream.Write( ASCIIEncoding.ASCII.GetBytes( name ) ); + stream.Write( ':'); + stream.Write( ASCIIEncoding.ASCII.GetBytes( value ) ); + stream.Write( EOL ); } } - stream.Write (EOL); + stream.Write( EOL ); - if (bytes != null && bytes.Length > 0) { - stream.Write (bytes); + if ( bytes != null && bytes.Length > 0 ) { + stream.Write( bytes ); } } diff --git a/Response.cs b/Response.cs index 5cb5743..7a1a9d7 100644 --- a/Response.cs +++ b/Response.cs @@ -15,7 +15,6 @@ public class Response public string message = "OK"; public byte[] bytes; - List chunks; Dictionary> headers = new Dictionary> (); public string Text { @@ -143,19 +142,7 @@ string[] ReadKeyValue (Stream stream) } - public byte[] TakeChunk() { - byte[] b = null; - lock(chunks) { - if(chunks.Count > 0) { - b = chunks[0]; - chunks.RemoveAt(0); - return b; - } - } - return b; - } - - public void ReadFromStream (Stream inputStream) + public void ReadFromStream( Stream inputStream ) { //var inputStream = new BinaryReader(inputStream); var top = ReadLine (inputStream).Split (new char[] { ' ' }); @@ -171,10 +158,10 @@ public void ReadFromStream (Stream inputStream) while (true) { // Collect Headers - string[] parts = ReadKeyValue (inputStream); - if (parts == null) + string[] parts = ReadKeyValue( inputStream ); + if ( parts == null ) break; - AddHeader (parts[0], parts[1]); + AddHeader( parts[ 0 ], parts[ 1 ] ); } if ( request.cookieJar != null ) @@ -197,52 +184,38 @@ public void ReadFromStream (Stream inputStream) } } - if (GetHeader ("transfer-encoding") == "chunked") { - chunks = new List (); + if ( GetHeader( "transfer-encoding" ) == "chunked" ) { while (true) { // Collect Body - string hexLength = ReadLine (inputStream); - //Console.WriteLine("HexLength:" + hexLength); - if (hexLength == "0") { - lock(chunks) { - chunks.Add(new byte[] {}); - } + int length = int.Parse( ReadLine( inputStream ), NumberStyles.AllowHexSpecifier ); + + if ( length == 0 ) { break; } - int length = int.Parse (hexLength, NumberStyles.AllowHexSpecifier); - for (int i = 0; i < length; i++) - output.WriteByte ((byte)inputStream.ReadByte ()); - lock(chunks) { - if (GetHeader ("content-encoding").Contains ("gzip")) - chunks.Add (UnZip(output)); - else - chunks.Add (output.ToArray ()); + + for (int i = 0; i < length; i++) { + output.WriteByte( (byte)inputStream.ReadByte() ); } - output.SetLength (0); + //forget the CRLF. - inputStream.ReadByte (); - inputStream.ReadByte (); + inputStream.ReadByte(); + inputStream.ReadByte(); } while (true) { //Collect Trailers - string[] parts = ReadKeyValue (inputStream); - if (parts == null) + string[] parts = ReadKeyValue( inputStream ); + if ( parts == null ) break; - AddHeader (parts[0], parts[1]); + AddHeader( parts[0], parts[1] ); } - var unchunked = new List(); - foreach(var i in chunks) { - unchunked.AddRange(i); - } - bytes = unchunked.ToArray(); - + } else { // Read Body int contentLength = 0; try { - contentLength = int.Parse (GetHeader ("content-length")); + contentLength = int.Parse( GetHeader("content-length") ); } catch { contentLength = 0; } @@ -256,12 +229,13 @@ public void ReadFromStream (Stream inputStream) if( contentLength > 0 && output.Length != contentLength ) { throw new HTTPException ("Response length does not match content length"); } + } - if (GetHeader ("content-encoding").Contains ("gzip")) { - bytes = UnZip(output); - } else { - bytes = output.ToArray (); - } + if ( GetHeader( "content-encoding" ).Contains( "gzip" ) ) { + bytes = UnZip( output ); + } + else { + bytes = output.ToArray(); } } } @@ -269,15 +243,15 @@ public void ReadFromStream (Stream inputStream) byte[] UnZip(MemoryStream output) { var cms = new MemoryStream (); - output.Seek (0, SeekOrigin.Begin); - using (var gz = new GZipStream (output, CompressionMode.Decompress)) { + output.Seek(0, SeekOrigin.Begin); + using (var gz = new GZipStream(output, CompressionMode.Decompress)) { var buf = new byte[1024]; int byteCount = 0; - while ((byteCount = gz.Read (buf, 0, buf.Length)) > 0) { - cms.Write (buf, 0, byteCount); + while ((byteCount = gz.Read(buf, 0, buf.Length)) > 0) { + cms.Write(buf, 0, byteCount); } } - return cms.ToArray (); + return cms.ToArray(); } } From 9c0b6601ddb157eb6c142e61ffd17ca88ebe5d87 Mon Sep 17 00:00:00 2001 From: Chris Johnston Date: Thu, 2 Oct 2014 16:47:32 +0900 Subject: [PATCH 12/40] Added ability to parse long values. This fixes an issue where numeric values longer than 10 digits would trigger a parsing failure. --- external/JSON.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/external/JSON.cs b/external/JSON.cs index c5c4457..19944a7 100644 --- a/external/JSON.cs +++ b/external/JSON.cs @@ -279,11 +279,17 @@ protected static object ParseNumber (char[] json, ref int index, ref bool succes success = float.TryParse (token, NumberStyles.Any, CultureInfo.InvariantCulture, out number); return number; } - else + else if(token.Length <= 10) { int number; success = int.TryParse(token, out number); return number; + } + else + { + long number; + success = long.TryParse(token, out number); + return number; } } From 41432f03378e827099cc6df5c52dcdea29ce75c4 Mon Sep 17 00:00:00 2001 From: Chris Johnston Date: Thu, 2 Oct 2014 16:51:46 +0900 Subject: [PATCH 13/40] Updated comment. --- external/JSON.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/JSON.cs b/external/JSON.cs index 19944a7..ae06abd 100644 --- a/external/JSON.cs +++ b/external/JSON.cs @@ -12,7 +12,7 @@ /// Spec. details, see http://www.json.org/ /// /// JSON uses Arrays and Objects. These correspond here to the datatypes ArrayList and Hashtable. -/// All numbers are parsed to floats or ints. +/// All numbers are parsed to floats, ints, or longs. /// public class JSON { From c67ebe2fe7b33da8519364aafd5897df6dbd51c7 Mon Sep 17 00:00:00 2001 From: Dawson Reid Date: Mon, 1 Dec 2014 15:55:08 -0400 Subject: [PATCH 14/40] I have updated the renamed external to libs because this makes it more clear these are external libraries. I have also added an AssemblyInfo.cs though have not populated. The missing AssemblyInfo.cs was the first reason I was not able to build this using Mono Develop. I have moved the source files to a src directory rather than leaving them top level. I have also now excluded the bin directory from the repo because these files can be generated locally. Any files that cannot be generate locally and are used as tools should be added to a directory called tools. I have also updated the Ionic.Zlib dll to the latest version to allow it to be compiled with more up to date version of .NET / Mono. --- .gitignore | 6 ++- AssemblyInfo.cs | 37 ++++++++++++++++ HTTP.csproj | 41 ++++++++++-------- external/Ionic.Zlib.dll | Bin 98304 -> 0 bytes libs/Ionic.Zlib.dll | Bin 0 -> 102400 bytes {external => libs}/JSON.cs | 0 CookieJar.cs => src/CookieJar.cs | 0 DiskCache.cs => src/DiskCache.cs | 0 Request.cs => src/Request.cs | 0 Response.cs => src/Response.cs | 0 .../ResponseCallbackDispatcher.cs | 0 11 files changed, 64 insertions(+), 20 deletions(-) create mode 100644 AssemblyInfo.cs delete mode 100755 external/Ionic.Zlib.dll create mode 100755 libs/Ionic.Zlib.dll rename {external => libs}/JSON.cs (100%) rename CookieJar.cs => src/CookieJar.cs (100%) rename DiskCache.cs => src/DiskCache.cs (100%) rename Request.cs => src/Request.cs (100%) rename Response.cs => src/Response.cs (100%) rename ResponseCallbackDispatcher.cs => src/ResponseCallbackDispatcher.cs (100%) diff --git a/.gitignore b/.gitignore index f867683..44f9206 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,5 @@ -*.meta \ No newline at end of file +*.meta + +# these will be generated in compilation +bin +.DS_Store diff --git a/AssemblyInfo.cs b/AssemblyInfo.cs new file mode 100644 index 0000000..89dae49 --- /dev/null +++ b/AssemblyInfo.cs @@ -0,0 +1,37 @@ +using System.Reflection; +using System.Runtime.InteropServices; +using System.Runtime.Serialization; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Unity.HTTP")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +// generated from : http://www.guidgenerator.com/online-guid-generator.aspx +[assembly: Guid("080f69d5-28bf-4813-adb9-023785939711")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("0.0.0.0")] +[assembly: AssemblyFileVersion("0.0.0.0")] diff --git a/HTTP.csproj b/HTTP.csproj index 1d43640..1cce68b 100644 --- a/HTTP.csproj +++ b/HTTP.csproj @@ -1,5 +1,5 @@ - + Debug AnyCPU @@ -10,42 +10,45 @@ HTTP HTTP v3.5 - 0.3 - true + True full - false - bin\Debug + False + bin\ DEBUG prompt - 4 - false + 0 + False none - false - bin\Release + False + bin\ prompt 4 - false + False - - False - ..\..\..\..\Unity\DMU\Assets\DMU\DLL\Ionic.Zlib.dll + + libs\Ionic.Zlib.dll - - False - ..\..\..\..\..\..\Applications\Unity\Unity.app\Contents\Frameworks\Managed\UnityEngine.dll + + ..\..\..\..\..\Applications\Unity\Unity.app\Contents\Frameworks\Managed\UnityEngine.dll - - - + + + + + + + + + \ No newline at end of file diff --git a/external/Ionic.Zlib.dll b/external/Ionic.Zlib.dll deleted file mode 100755 index 7c29e8cc75d79eea60a087075068543d8600e641..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 98304 zcmeFa37nionLl3rUVYAF-t?q6)rln1wMn^K=a$ZLW4yY|MA+*v(AKeEoiV+fTBCB9A5%?Q#j*8@mLeBZZYXxD-_ z$qnwCp+FiJ{xXy+6{FnMjY1m9O5G7t8QlKn!kC&GiQX+(R0=IY~2VUmD%N%%_121#nWe&W|ftNY(G6!Dfz{?zXnFIen;=qkuSL5Q^)KR`V@GsZ{ z7*Q%Iu}$yPqEchc+nqw+s^9q9wb!q^Z|R5bzIgD4xrZ)YvfzZ4mH+VYE4N(Ua&`Kd zqo-c^r4pl#gruc-!GUkKBLD$eI8BfiFy+^Q9?2`RpSnc6KiOMDMfj zc>2Ho`3tpcK6Akp>4(33<@A+Dz3+1ae>}o@X!X7Op7*y^eD2UGod*_9 zSn-}E-#PZ#dtPz%`!m_OdcBTTh03Wp*cnKbRWOV3Eub0^jK@mfJ694Am!0dX)<&A! zUP5YM60>tX^)aMjk0exX`_@=)Yb@)9USE0`Ra`XkBv99@BL39%GnI;^1WY@*wRP6* z2Dx~3ic+bJhrE(8n$&06G$z6>SniR)$#@p0>wQDu%*F+OadG@uEBv^sytVD zK_%_z`g>OC^5Pryy)Je6Q#UWKll3adS5kq$)k85~HC*rw7iLL+R8gPL`c$!a&1ZfK zwu0T)?*|T#k}oHid(&Oyzl3bOIQ64xY#QSRiP*?Oqnok z%Ff2ac%MJ;D9}vrX55x|P8hQ#pY`%tzud0kp&xo%LNC7}>#5MsSF(QSvmVL*loP~D zDYnar2O99QxUsQeU>hmuNhe4Mxfvv^$_8Pen<i)}h;F^pCU)uvIglS?ev*jCM1VjJ}!5(M5<{dFpLw7b*;upK@v> zL7Hz=%TZB|>11?2wUw7^DZf_7M3_31j{BM?g5<{6KquAM64wi~+M;5yDsPg`>UxPP z=nquFC>ipvZ1}BwodHa4p!*u#mh5Zg$FZh)V%p4ltI$WOre5AYy?Zz5*rV0?2Te<= z)5tLJ-%)cwV_Ne!!a1}KBe7LeSM8DfNzJN;{@aC2_Nb8p@~od2qT{MXsao0z9Fa%m zlqA-4anP4B6>Hp?kgPF^IJz78T*WW~4?b&G0DsU`VJ_u`Jlm6Q|c zG_=uka&^ceB(f(4iNuKVoEm*ESKS{mGxeQQBW}GGv&l}41=lY{gqk(zxKnev(*9W(q#;t2;2l>hwMX!4GB0Oh=BfXB%X~8~%#W4s}9sScBQC=M)W z31wr>LY*UEQmPJl_b`R*=hO&kLY$hgri6?Ev4UzZQ1zVZlx8EMG!qevWr}$iGcvPQ z_hWG-U0hDb1y$Uqf;x;JPo^cOMg+=iv^JZ8Q8XWwBj}f)2C}>=BqKG`$=8WTd{V7jbT*VFnV=h-j`wE$5~MAKIl6{k z_GagGICV~|2DCv@j^#-0;Js)x%mo=yaTy^S*2HU*ka5VL8%~HR$NY@z=}3)~C_&^> z%1;cnL3dVQIP^;9M5WF$G?Fc)+3Z0T@6dy|SDKQqNI!t_uds}dmmsVu;b?mJI}P3| zRX$fi;}60DskYU~C0|x*=O1K^zzokrgOrD=9|)BYi5un+kd}rYi&K zO5JnFc!COc#6DN+`#9tT!_|v&GZ1bf>o{JPVe^j9gH|UJw$W&0tc`6vSgm`ne&olt zT(+aOIOX%4yl$}_&%0_*=|J)|TA5Ru4w|b6u_K)tSW6=kGYEBFwMc96 zkI^)3VhXf^=d_DXamEdqDtf`%Urxhzl6GTQcVR3^y@yB*I;X&DRyXGU&!Meg0sD^u0D#!A65s=7NGA3uBmCJV2@1Q~N-Gic2 zN}-m4|9~2yhG`783EbL)l9E!;#VDvahPH`;)FMU^wWgj)wMm5KlGiSlPw3_9m%##J zc)5g0F_CzGg}&dgrd}7QtJ(*1ic78h9IU_~6_!EyVLzrW3ccEuKrBIJr}V^_+^`0b z%spgmYj$%tIL=X=%tg|5|Ekcd&Jmj}UWKRyTDtX!lqpY|IP^SubvV~_HN<+o*`yV* z$Rx|EQcf6b&DJ^ZlDSE%$<&ij$w!UcLK}};uGiGv zh`R^waKJF;V^%j{u?8J_3Fl;3DK(e_UOMQ_dgJtV2gVb)2z~!buxh;wp-du>*%snX zVKvK$pahIyX3(WYH=&s#LqLl$Tje!d^@^4TOM)G+gq0?pWP~F@GcPA86@yXaV5j8t zs&2BQu2(&G+vX?KC0D3du)VYmFGbt4(q1vQv4Id&4?yQB3^>YE;7U_Ot`J3WLKFtA zXG98!B2qKKDGFb1ZaNTY(V~TYh9`m!!AQG7Z4?-5>eK~!z4_1$8didacA>$k!OHQL ziVE&~4cM?RZW|M3=~du#bpgCo&~tWArE~;9H9QSs8@wIrH&!~55uRTON$leFG-oy^xQ5+Sk;F$>w^O;_|O(fF zZ)&atF-Dij8piX--%j-#skby1@NON{=Cjd7S4M zUt0<0H`l6;!n9!9vjFMfy4b{rf}bPDqHXJSKDW+{DAbmTA=4;x&A2jMHN0nK)>b1Q zb{M6?(^(+~bFkhm(h{}{l;ZHMNO7fWB|&%caUe~jTlz>ugg#iv4f-w^N8etwnHf!) z*!#5mJHp51NUE)G7EHeE5Qoxk7*08dJZgTUL&$J6zNFmQY26HP1F9Htu#Z?x!#*M^ z#2E9lOIs|ZU{V-+DW(oSgj)pc8@*ouI@osR(W59mJh4A(=Yy>1#>I}uz+RTu7z~=0 zJ(Ml8+hGTc&Raoy(5OZqt^mDgjBXER_+}?)2KSjL;x)|aad^73{M=gU4O<)cfiSD+ zea~I<4C74pm&WCfma{*~F}lI&Wql#&nY_Bu5rvETo-y zsZ$hj^#r73o@@&sAyB9Bz}l4w$fwq4aW!>@K8?5AGQ0kkGF{n=!uBKjgw&DH{0Qh0 zGP_aauIWptY`3LPmnCi9L0MDxqAbcS#=7d%vI4ze_az)Pz1bfab`9Ou=`?hkTW1Ea zQ1n`)9H>59j;B7g2jwt>Q=^X_(puCX7(+%KIeY*rt-cyun<5Htn!*+bu_a-+pQ$Gz zwaz%3M`BMxtS&D-dvq2iFSwc4dZt;-|VDMYRtE@`9{jz#eB1?GGD0qM$;FWZ!nnc+#vMr zW^QQWOqd(av~mUkU_+oi4%2f3voz+00+JbFCI@rlVbIjswOlka_jc2T(GxLs!onTS z7lwDTmk=2vQrF)yU+liTozE90ujtQ-wCr%cfSB6(LijswzUbCGs!7L?=}rw+qPMn^ zDi4~Zaq~toiqCn&++PfknI=vmsGIZ1IS9da&RK?jdEz*c{>D7w)Q&+0;PkQ22tz3d z^?1PTl~!|H+8F42uXL`A)F53}@mY4_v7w=14MH;q?TUvrwinA6ty#)eq5=q!j%q{A zr7_f3C#O_7uJjtmV6qL3IgHN^zkLAu2b1RGC}EjGXj*ha)?0AlSQ`Wx2ho+OloZ4;(AAMVtKI3N6a zq3se|<_l<-tTkl55O#?zYj5n5cN9O4DKekW<#PEEDE8DCWn*{0vEnm4FV=`91oiQDw3lX&#aa{b?w~UX2GKtmS z!?;}i9tQdPhZ*Q+*LcWvDegKJ>+;^ol#bEkba^)RA9U=o<73~2ShL3T8qfQb)8W*{ zkg~Y`M&_zr3m=bd-h!Ysgho@F-OQU$vYpoxr}QC!+#TJ>yIlS4I=G2}GkOVv{7`SI zz8OGJ-=Gt3)WMq(%yO~jxk|W42G)dkHMXQa8x-q^(M163*p9-zaJ0ro83aa*zNU#F ze6F#527wWyr!^3Abx=%7?`F_b|3?O;x3U%JPMHTlrhXoVhhTW1OlpFT#kt$%ah3F! zJgxefP9`mpWU@b+OiCij><68!3m&};=^cynx9dk=AHZFr{(kuS{)2M=Uicu6a};W` za};I8+l*r&E7Ik4D(=+YjfewgxK52JI4H8&KnN*AC8$--4p^aL&I;r#3Xc5j7zr3o zxuny;b}4c5mN*ZftVr9+0oYq(u&}WbxeY=9uF9PNABTcJrHB@EmMf*6+#&)TUIC+(^u*;@j9wekXPv zU5q90u2S4~rBb)&QUl;Frq7Ivo?`r_7935fVAn774@f4GQi|Ow4b(t8utN_UlU!Oz z=`_vQVTq2#4PaB~RaW1w2GA*5Q~a$A+&qHRMmruO6W_Y)E@0jD0b9I3n~&jmFnxWLCdVq)`ro{7|Yq z-L_^wLnZ?@)IMB!eteXFhZf3@DE=Qy` zTC5X#okJalHRV$xf(xM(ncWWCGLjuVN{O9-QAiI>GX=gVQu_|*2&YyPfvm&#wOs{C zlDkTsftBs)V30%Ef!c!B3N{t_cIr|dQ!t<=)#CpI_$|cuFf-OTpNvBMykJO%PC7n_ zi4G<9);@$-sAXal3QJe$VplI)t*0VQo~EcbgJ)%=3H`}jkKbmf-*Ix!N+7sWt1f;B z<*zd3_DY3;qz+YNzEe0cxm$WnK9d8pB6a#3(2}H#tI>6!E5E|@tRoZH=qVikB705= zqa;vyr^cDJQb<)SWl6gyygy`Nj|x%FG?|~laLy0!$Jm-CG?*TJA8K%FoE>o#35Q1; z+^UUB$yeNF%AJio6>_&%vV-X?h0okM6<~?d2fZNUeP?=m85zmx8F?8%FSJ43Q$>vK z4{mrjjvkMo!kK6Xir*0%#w~pp%-SIWswYXsZ3T!RkBZUo>M-*r4q$@BOASuv3LG^N z`>RItYbcGUsr#s4t*!%e*`~GKYe(^9%}Z=vTUlILlfwDbN+uzuqB*ShSkSo=rLZN2 zqe~9JoZYcRI*pSiYxMFhIQ*&+oZ4ML&JWFLi{6WQ5jmrGAo{F_eTD_0G>H7g(au46 zdWWLeQy>v1N42Df{>GjaMa6+t_kwj?*Rb%wIOoQjXmlGq_El<-tfCJ;RtNq?afBkaP|iMfN( zvd)deagE$iy}JG2H=FNlgKp7-$54WCY;3{GCN1@}_r^dxBtV}FM!#lRjS0s)XGnw<*hoz4#3G9jgrDv>w{S!wIEi@2%DM5;i^1NqKY9^@^XjAUVb^); zUKCW+<4;sso85olQ$FbzqovYDiGi9ODX|I3qQu6T<*NK@tu%VJauepY4p#5NA0(x}-bJGfpVW6UZ9>P>8W^qirw z1QQAthF+cU0Y50cXlJEvH%T=3>j`UjOpAAJLnlt`HSb($7YrVZ9URLoVIJe^$b}3X z0UG5(DwR#{0C!3mYY4*Ql#pAxUD}`{^}4WjIk2kpu}NjtTCQ3bQ{3mrw-q?orce?& zw_#1UoJ7;t#6iQ{&I|FN173xViI#z9VU;^BPVMX*Iqi1Mak0kg$dm=l zmt&o>+}Z%ugB@2)<9;6z@)bLsV@XwlH7p&(Irj+gPU|1&Z%#p4%F&!vXe3p`=rBCd z1Z<;IdWUYmtmL(|Z&vN*ri6Wi0ELMuUzt{sd57!XPPs|P1L;;Lo>Ewoc-@uWG|mHb zRf4&Ji-#||TWR0Jn8T6+*6sjy5)`s=?gkCB8|KBt#)+9SdMdPY2~9!H@~ObBqVDY( z5n0&eVZz)BBw5YmE0}Fc*dmY>0F|wtW=)A^D}iGcq$DAmGL((H`|30pnEO!P!M!(1 zW=hYHmZc$N!F~$`jWa$|w8Yx^w-vd@5Zj^#4nfBx!4DwF)SSk-%OS)U5U-2SsM@bs z0VD3*d2T+a|nNL^NI2o3<}YqV}{boUdnL73vcioO05o zS(!iZIYrhnO=~{OM)pG`S?!13NG>cYpX%>?YVfm4t_Duu}E4?G6}wuN$gk2-4*l8ne*wa;t?T9a*DE45JQ z+(uAf=&^Hc4_r--j6=IUdZ*DSKx=br=k(~?U`VgCbhjJ%ceMKGK?|U#_yh%wngr5= z(t9wZWrvc@!}#`0x1xDC!XnLMk2*CD1q|2*%1{Zro7hv=lA#mKq##I6jXR~akHVXa z?L_HM%{d`v@Nr>Yui)l~Gzn&6f*mDw{_k@Z1hK)gtso?dy^Mhh_M8k`c09qVyt+BJ zGGAkE<;@E_Lih$FG}kpOSX8GObK`mid?nu}P#G8c`*uI$9xpTQy?@>9jN7g_BkN*4 zOuLgXU5}r7(b+OiJ;gK6GEOG}wnK_`fQ(a7>ab3uw#{}URgmJjmVpydM0BW1fzt8cw=ZOe=j%U&R@5;q?!W07}>+DhFc z?5~MBF-9Q8vLfh18SsF^JrC_dHXvw}HBrehAwSfRYTkAX2_x;mLc_M`c2*c zGkTgd>K2ejLUN4R%=?3fQlaGPSaysTh4I6eqgVQ%v~!DD(m6n|B*!&ymy9$PY%^CU zXpj8RIQ`M61Y3N@EN?Q{nn3JBt6?S@{tXJS9R`CFyC-?wFl|g(4X-B;QwX$8)*JZM zbKpWPO6$yB(`r}-(|G5r0wE`7wUpd>9WBsPEloYue2*LNSzx;FrJgdQ?_+2xCTEH% zj5+pPwlPbO;ZD!9b79!QT9LU+tS%ir#7!O<#P>2I7JHo7@f2S$M_-SdN*4PY)aBTC zsh}^iFx%|y#w==Pm8Ou70EF3<2{U+_6?Cjj;mu#I1ZAK~0!m}=@L>_w94sk;f;Wb# z{#Q0{QBRocpKT)W`nc4%vA@g2U?^p5EDSX+LUK~NKY%AYcx9?0TTmSQk`wr8gO9}m z@-BEtlPk~D1;>-ajSzQP zTNWmj-Uq8r@Hk&jVKUyO?zrD^E zHvB?ze#$RQGSf^>PIBQ*19Pyt)yvOsZS_W1NqeEczzCpp4c`wGiPdMT7h@mAo~@QD z>SHJzuZv%Wj1D&D8S*(qeT)&>K8EJuSj4-p(<*hyoFFn3M6T$7$N-33pWu$EGI3#? zO1PxXm5nJ7=MQG`^a5qxMCoG+>|axsj^K*W$+vn_D^k~8I-Nn6DTCWT$ik>Pdc|`v zH}ht3{Z8I_b#6>Jt$v+0y;J%i`i0*>(C-2Ga=rj;rw(hfJhv9d5_py@sOuAA&3=F$ zQ^$U1eRf=poE2= z-ScwPYRHn7fg1BmNptWRS#DVR94r&$=6u}9mIwMdP=&22>@~L6g&pm6;ahuM_}Q-c z94P`C*eN`3|~c|<;{l~>EWbn z$5vD_YV1Hahs@3X3`D@2hB-}&G^)XTGloL#>e3n&Q$Tq$K82!!p|o-_(Om=VTwu0X z0&PG9dUw<$?!lHp-r$T|MPsFL&d%202_YXx$##@ct6WT!Q~q~keGQxGkNh8is=>`XqY zxd#2LMlX=$tKjzxb*-rMtbqAL+0J8|0qINgD>I2sJ^hh(r!x~zOkJ_e>>Hc1`V#R` zjDBxfI$kK?|Lh@bFpEMFO#)J7Y?}@FEY9$VCJN*6?RWB{sdx&ZZ756g=RnfVOEdhV zoEL$&ZE2yS`RsK2%EzN`Q%ehNdyEd=ER8&v-F4x@NNEduY`jKAYp9ehBM-qnk@V99 zLm^*q1cJrEW56lWt+}i}@EHd!L6`SdC15)3ia-H>IhH8k*e*`(Tn%=G3Tg-73uEpe5NcCzu;l-$w2xy@ULW%mQSWm_6Z)`XeK}Y6ELyogbZa3w zMjNna>>T)o)b$6#&caLV!!tZ}(Vanl_$UcGhKD5V99|+}*YL#>b`M`C;nd;xNH}fy zYZCShKP_P)X)=yc?G}n-R9J;sV^oTTi^pi66mP*08KWTfj8QM<#x8`PA6o~%W2`DM z7fH;;5;F|H&^89U!0Q~l1b)#$H;=s@kSraH64?+hmAtRma9pAwS|jQnt`+_V2scfX#vk*mV|2b6HL5CTZOb!66z78m6-+}wn2cv zL%BwP8i0{qT|HfSbJNk)U1;mEcb#2R3&ldw-gb3$71|1I9R|0%2X{!e_fv6S97AQ| z+1P14g`$pS6K!lGk{l|c8I6=e68I9UlR&Y}G{&~^`K*2y7&T#+K_4i-kF7TF=LwH| z5sjC-4`rtmya zOHu!9Z3BE2i7AVet3RN#Jjg&k_3|*FMExtgudzIw925<$!uDmuFgzxOTOZDa@LvYQ`JZv~_BdQpskyCq>@rEIAHW?7-VJP`cPp@Q z7LW7MS!c>Sog)kXni9kY2k5ho08U-_q=Qf84xMc2@T$qAaeE_MA zN}Z{?7MNenxK15+RWz=U)Y2(647d2|BC#P0&*P-li`51El*hpDAr3En@4pGP?nUp* zcly}K>ZM}rdVm2+8@y`{XqUarkcGO z$gM_?b0Bljyb6mh>~4LAt%YtbOq)9?=w2z1-CL9avfbFe@Ff}BPhi3nONPW%G-ddb zU=52_Z#I?`46$QkPM+q3RIKF!ZICckm2oe4*h?AWn@K8OXvG{}E;(sUhsu!b^v2NSwKd~9THMRyai_HK+Vf$vx)m!Wg3_dUxk1E*Rh1AN5 z5r!0mp^Qh{!ls=TmD^$pC}efMzDJ$feJCk6ZHrSA+fWM7kxor)$eI|1GXAQMVP=Nm ztY?eCF|s;ni@Am8^*WrR6`PLjb#|MbNnShy=xW$ww*R|r|DOe84Xq@9AZ6s%cG73s zj+cTC0kYx1=G03sG!F)QB{Y1l0v3w}=a_C`7v(m`N56wG*u1pTi8rA(qv5*KwomP- zY|gfXErm9{y~!S%gX45fqfQIJ_Hr1uY*7PSW#VfoOvb0ES}^>|v1xeomG^EZcA(SQ z%uCP2D`1)Lh5ih}v>i03(-dkpJH6xOg#Z)hX6{f>XWjnc= znT# zQDKHBe=->6cFO#b6Q)HU@nQAkf!laCMzlk2$`)(;PYI{sQz%=)DUDSCW2Q0!%Yi{` zTVz{Jh%I_EKB;r$)h(GF@@9H4^l{D58Ui_@f&O&|8fe$*2MX%Nv;ReZM3*s|*swK+ z_b^FzI4QSTFKCom$>9C{7kD`$>nO*qKB%=Z_V#2J#S@jrTJcQB*jutreBsv3+K7rs z3dBk85)AwZx&p8Ca7B$Kk6*p+ja{qP>Dmr9Eqf77(>bKN$55Sr5k&`^59-BSo0iWj zY<=;_FY~j9lLx;3A9yO?HVgfs_k=L@(>6yy*_UTT`%v*g_sF|>OvE>w51)2 zZuann1=%=}v>_Zcr#U$;#;om7L|(at=WKZ{Rw!;};FYKaWyr|kR=Zf$z{RA{h)V^t zQ#Pj@^u%(NLQVuc20^Z1NIvLjqedBpZ61cv-LN?t0jm>kf$61=ZdD);C?{-=MG*`+ zdEgD-|g4|;?pCLkW5s!IUKJg21uY$W0ZW|pCwgF)q5Viq< zuib3}0^cm>n<*;_p(!74_?q%*VByyQa`mSH*ez5wYb$y46r%U~^JzoD6L%;rO z2H2^7Mnb=i6+Z5R`fnMw*Z&Ox_pOua=!{Yr6Od`X2aml2S9&X(3RAMjiA8Nno?>P3 zDaQwqt;LlM&aCI^?E$>F?Mi3PPrG`DGmafj9Tmp8!=UX97qk{o;j#VR)`o19p? z%Pwb_3IqLR)0E!b#Me`FQ|#6zFnrn9#OWWsuj$l;eKlcTO?X!m&eeo(HFC`jQ>8C) zmUCV}&d8Q6TGEFH`CfjGS4hIFl|CJ~3vK640V%8hJ3PRoO!^Km>C*y{mkj(i57ANs z*OM!$vf zQU4jT!^n9G!N3|wPomJqFM|pLphFUcNlWWLCyptLd49_K4xQ&9$+LiYY&N`Im(Yxl zcP?pWs|eEvJjqaOR089}blk5Yz+8ZmmM}H^tB8&5{Qa`p?1bxBPmPUwDY|?bYWv%} zythVXH~U<8pOp2F*+4_baP(P8=eVg3Tw9 z`PV~pCJK8YzegiOL`tXQG?RU1@q$X}&!E;{Iw`#rwf*hg)mtM=BT_22VbSbcZ=LPSB5=p0fOY0JxzyO+RkooZgPx9zIRM7X@%E$49sNe~(~mD^w2zV+_2o zvKdDUuw;J8vS?MqD@ZT4L)L({z8^nUW|qL3tAx8;w=NkKVmJO#+o}&Lvb8Z zK)0&agkC=c0OWu~96vwvAQ+YP06ajz2klml@NgFGVAn58U5-$5)vn#gy8Iw*l?Sd@@&yc?ZO4tyHZ z(9W|a&D@R}2A_b+QAt>*ExL%%lg1@w8#wfmG>2Jl5>@^Ujhz%}Y^%eqB9NNj(VYz!&Dycz3wb~XH&yW$51w-%6*MeS}jVVLvLY(i4OE~*b2YZ zpsNA&e}gy`G7kk87`UMgKnePVi3RB`VJ4|n9XtL_k~xEZ&De&q;jQ|#GtB{JKM0!- z;{?s#S=#wB{y35SrYi5>$kS{`(zXL1Mnx^~TXQWqD!`K*ny+Zr_VpjK+xo|E*puc* zcg)E!V@bgC3(~-#6|Xm`fp38q$)@qjLiSgImKS^>E;1%kk&%jT5Nsq9TNA?#>(%HQ z>^p$1e&@$2%Gf%fW@^O;U1blU72kc8J%rYT z*+ZZf@Cn#;D~fNt9?5If;Lv;T(Z$|kkEXU02h7Ut^&nwy0yCdA-H z1S0UvD$4WJi3sOG8NfpR9W#oLcbC$#O&m980-2=WA;W7*(0@Uni*r%A`hQ85|AAk{ z(U)MRekqE3>ieNwm;@}B$vAh3SB$WIEx33@j+d6&>%3{aM-|9>JvxtDZxUnb)!1Io z{FFED4K{q!zVubrJ$w?@vgW-sul_74b1kv$h- zZ}LLy3J?xiz*Nlld8&;Xa_PcznSl==0~$y!@bJ|!(5kYbJQcG3B;0vW3x9;;&-+gE zlsX#jn{Y$06Mg}A2^QlAqKpB$li_Lh%Q!XW2rG^!S_Y0rY8?C{UwQ=rOB;QlQ%CXe zX5Jp+H097RvRSCbdb2RFMSX?AM%>hYkJ7NUI%#Q-X(QgMEVP(zWx2z*qRCE;c+Hpp zWW&JeuKx+K19x&mK@hrD_TWP{WW1j4NIJfqFuuHBG|D6TPRcx)W#)y9fg`1S(y}AA z;H|a2V2f~1x^<^q(J$NJGy|L5vm(GdgJ)X-z`NDs8`B*(yC;?zH=|RX0GfBU+rb@O zO2)t#BX!m6un8S|K2l%UjxBVoSX+c7ZdLbZKJN?vj|(UnF9BKntF>SX#O@El*;6?wm1SL+Xpc7%ggsE5b-e zn5tj!oGPSsv{A*HE-I^G3eR=h~mOc41(S`&k3O1mHi zj~-tX){K{V5h#&)BY61EuN6~~kKq$0XxQ?>O_?kA<7=S@437ZCNZW)LHY4xf!qD>u z7X8n*ZAlnDe2?^9XkdYJeU5L>;&>9}WvaX#5`Aws-+WKk)NwUbxS-*E>E|=$Gjw$0 zO%fTral8c2d5{K&d~+|y@73Cv{7@QI#&Ik_4=y)|S3igG#V1Lm0x#Ms{%n)jXRn1+ z^lO`hX@wSWif;$Pu(F)e13KE7jgOoWGg){JZ?LsAWsjBs8qC={Q$Ee+qpc9%IQnPA zCh!Fc&Uwt8kXLe5c^}h!jb>Bv8ax)zf$B;OW#lnDzo@N(*+HU9f6jqL;8R*n69xO{ zGM7geRXQrJ-#L+F{UjI9;YcLP(zL|EacqYiV~U`~gI95+IG$<114C`n>9}OXcEv(Z zPCXa~qY(Yh+qmDa7t<6+QzPG8aOHQg4+Q_a<3hThM93F)~bKDz4swsr(?3 zsch2c7p`kPAj`#ub!GDngE)=Wdolfd8Kg>x{Y0zU~Lc zWwE%&$+y--F1IC@ois2Fb>U_+PQIZvIGxL?LVq)RhWJi-3ieTXHr;;kL88AG`sh}y zclB9JVg_JE7Ob6w_bsOynnN#I5U9iU7AA%Wjo%GDuB(lyXUf5+R!CGB-;zhQ5dLgS zxgTc$8`R;9ANJW;j!=_ghfW$;gvlO62(>MFWWo}iA6{Xp4>odpn|GWWjBZdJ;d0ob z*^J-H1!wX(d3_YB3lrCq%{LujPfi&@6oinky4d3u)895N^ zp_h|WTEh4_JONsiSVX0;bu+LHvzl#kfJ4OJ=KTPEfDx;HyorUAqH!FnOyCeHcCA{& z_*^e+EjwWxhas^Ck_H>4b9(s!Uu~+haZ7L}H(wb_hXMCcLY(=xty`eV_(h@oie6A6 z+ya+ySaUNzio%Rexd)?KCv3)N2-uUTf+a}$m$A$?;?UZf!fRKpmEs)`-)7ZD4o;BS znr%%IuQ!|8f-u5QKBq%-^CA@>+42V_a*o-7Siv(SzSX5qW<4 zeFbz)7V;bV%Xz-T&zr&+W6w~qT|YJ`c{$L$0@@={?vM|NN^fM-kpvc(SgIvIxw)zF z9#h!TAF`k8M5%)v{5fFrj3~e-$BcXq{uegg!j{?i5@^4CmE^hXB%n>` z2u_#T5;hz$%hs?w#~9ng+@aV%Ie%d18(YO(yu%L?&i9;fbJYfzSGZ*<{8?(C|CUexHz`M@yJfr zTRQmS^(l?Fn5FMs{r(Rnz$vup8)`MDQ^OoAPGOS1p_*u5QE994WhkGSH>`0*ccKP- zPd8GkNzb|F$Bsm2<_c~0Rz@S_QtJ~7bP!;5Iear}NRF}US;A(Ny*xBgErY{05o`;3 z`n=<*8kDn-ZGc~E;ztm^29Ef!gXO|eA9Ya#o@-$6PCWp}vWTC8<3;>s1aJ{962L|L zI|$%nyuApInH$0j3{3o|;B5KW(~*lfl?dEnVB+5hcN!e&ISh^$@h=ld!vh8;{$p^9 z;D{f>@gn|efizq)F!Aq=#1oGf!?y^e;o}WV{QrVG6^`X&oXbUg@|zdocDU0G{4_#K ze;F_@;#?w-h7U9_%l|5zrN1SDvnm4bYhdDkFcKf7=Z%s0qa*mg1Z?Ri9lRKxC6I=v z8kpt(1037N_Oczkh<}AZ8h(X=iT`~#D{uJ-&IJ*8wt3>1pJ-s>{|}s{ zA3Gs(ksj8`i|}MP%m2FoTmH`g%!@d~0%>@@fm!~S;Vl2t5u6nfcpn23|GklT=qb5a z{?!rqNCOl9-{CC%tDAY&*G__lyXf1N;CS<9S*B_v>4Ue?tU5*uX6R zpW!V3aeP`XmUC_do@rp>-xGXU0D@yAB+e*@Uk&-}bt{_6zNaF2nRejA+S|H=r? zXaqjoz{LMCoaKLa1ZQ0Y#ybXb5&!cBCJlV7z>Dw(fi!%wfri^3P4)G5)F!3LUBQMAw@_`p|)(E8G{S8d~k4NHp&x`nP z6-dJ;7?|n5hqLs15ghWH7xPYmBMxDHW5v=R)&H+Y8ZY7;B#`F+*8yAlqx%0GgG2n@ z2>yp6@zL@4rbzrT5&T~Rw)C?sUJTC`NW;?%%=X>_XXT&m;6?npKpK9ffr1pJ`#UY1phC9E&Xl;CrVou@$3(l`4F7t{|vyq7(XJA zhWian`X7d~{EzDYl@WYf4)Na~iFYILH4*qI0~7z}aF%`XquQo98{~ONIACi_d1`1?ihKN5+L^7GA+_~Rn@{{h(2&-!?g zo}~h5*y>59Z-KM?Um3x(Bg?NE9Kr_}nD}3a#7EnELnQu`2>w>U z%iyG~M&Ytdwuu+vHaOBucm&SUW81~}i{N+>o-2?Zj}HQ7Su8)Q|CiyO7x9Y(aFPD^ z2&Cf;C^%!0_yqcbTg{Cy($?~BAc5%}r|d}IXwXMipJGKO(a zdKMcT!d(U?JvYNy{vT!HiL*We4;q;G-+?19SaueU7xC8$q~TcxCjLJ~;-lmJZISqe z5&S;^w)98!{}~bd9N-7wST8Tj|9*Wd@o$L02OF65JPK#|AJvEFM(}4w@IM@hkLr_a zBk{*Z@P7-~($D&Mk{-F{4ZviGR$RF~7 z7inH2kcRg+F#GEhk$B$oBK}(i((nleX8IrCEd5b^OMdfW-YIazA-uQt|2L4w(jV3T z=OCUJ%j^|M_t)J9W_)x!z9|xaOa%WKz?OdI;l=Q5fiyhLz-;fWa8~}=54?z97f8de zG%)dh1ZU+fs{b#H;P*xF?~BAo+k1T^{-g;0bAT=VZUiSvTNd$F{wdE)qdd%j<3;*M z1k!N7fl2=(aF+j3{l7ATZ_6S62O{xq1imH$A7xe{}@^S-_V5sJxvS!OsJJ z0FL$Yvi!GvX8fg+qHzu}FzNXwoaKL1|DPAZ-!Fpy(MWuhpKp%D9~Z&@Pr#Ob*2jzV zEEPz@R!=hh-EfxwDIiC4ND(d>3)F%OxJh4f#NL zIvnjqi7)E*5+;4LV99z~bA4N9kzbZmM^?!qYECwhKEQkHupdXWm zrGGi%8}u)0mQVfMpdXE~^v^?lgZ{Zq`l){!^urjn^goFB2jHY#%k=jjST^rLhS0@+ zW&1g2avZTN_9y#-KH2H{h%+7N6~`bjpPrI;1u3c5;`>!Oe{=?^k@5$-@j;C+ zt&bl_3H|_n_89! zkUUShuCQ)xm{@C5*A5A^X)S(iUN~tI*l*@T00<)Nxf-v#ku!~#^1+S4vp}qt`#`OM z{KDSYmHeIw_GhNxOF6mvyU{PM^hcdSh@U4pK?TW<#lmPbtgmcZi+&|84@4y-SC~km z^;_K9dk~$>;n%%!vH>|M#L$#DzLmr;VUam~A8zn$2c?95$9x=i!AU+jY=z>tgb4_{ zh!47q#e)O48M(vDA`O9K*;9SFmEk30r1YE^WsBs9G=p`-X7B@&%-^S^U zzXpsSd5}Y5Eb-^4-84GC86OMc_{*D-s+j;9K?d0oCN^(zgS;-tpl;@ug=Ad!%D|?S zB!s(Q8Thr6Bpm#bHVgOh${_kcL{_)ou=&Qv4MV&eA1`5sPvtA;-KM!NS@M-ISlydV z-X12wI-xw&?-Mu4MB7L@c*DVj77w;Ue0EBgDP}WH8I`_Ae&M}CJse6u;H{NAj*|h( zooKmyMSijhKPr^Zl&7d55$DevZ>r>1tnN*lU&o24Lmckx`yqtyIOT{4ZHgSyWSUdn zp9yGVWbDdIKzhjIESp#QA;`g~5z%wCnq}U5_?;-1zX!p&oadzRMY8x?({3yBS`OjNL-kwwViWt;#joTv>CGZ_$f9j9!+XHne=T;RN<>cRPXI+uiPx`AFOy z`#Cl^rtNsKw!F3BX}hQ3Xs2_}6w3v9=7J@InhIBhE5TvuAkT&tAUqXr8Qev1V{muC zJplI@jYE9ihd=HlG( zDp_f8eZqDAp^V2XG{(N;8*4PdjzZM+$D>8~oe|Hkz7D0O%||8WeKl`NOSynoUeazN zNZj=JZSq@l9*%Nj^?@RO6>t77t%C~W`CF(;OHqzf#a>IwEO#(3>U2C`X{0Z+>9%di z&)>`8-U6?}q%kgI3fZw^g)w8tAt;Ju9M6bpV<#XOC7iE}60VFbggc4Gyyw&gCSq&y~P= zn*`paPT(9(0?*VEI3JTh=O)zK;1%adbq#9 z1#s8G9Sip`+)TLl!<`HFbGRJbJK)ZM`!3wUaG!#E1KfYZwZd(HI~nd@;O4-61a2MN zf57#?ZGn3o+>>yJ!+im66mBbA4DKqpBj6r{n-2FLxaDv^g$v;}!YzXPSGaj_AA`FX z?ssrWxVOTc0QWVx{o(!*ZVlY8;5y;n1vdou1Gq!sJ_~m_+@IlmxHrKa1NRlUUby$c zodfqXxG8Wq!<`QI9k_$w{t52&aDRepfx8~=B)CW6`rtkccOl$w;ikdC$i$vm0?(@w z>XmT!!`0!Qhs&Y`*;rEDgzzSWry)EI;kOWe3t>OPeuSSu_z8p~2uBe90pTAIrV*wQ zUWf2Hgs(>UYJ}fF_zi?*gk^+xBfJ~o`3TQP_zc2l5OyQ%MtCd2TM;fnxCG&k5dH|^ zVF(XHcpt+15Y`aZ5I%?SIfQY9afEM1_-2I1Av_M@BM2WsxF5p(5PksR2N0fz@H~XS zK==!Ud4zd{??m`cgl8f=6XEv|eh=Xx2oFK{X@s9fcqzh55k8CXS%i}iPC|GC!W$5t zg76fC-$eLLga;rz0O3aweiUI9VHM$jBK%K;1%w5J??(7;gi8@FMfekhKSB5^gs(#Q zMTB2OcqPIs5pF}c4IwSe1#m^UWpHh9r^3yJy9h1;cRXAPZZ%v7Tm^0b?lL$J?r6Au z;a0)5!@U;nK)6fbT$FGP+);23!OeiX3vMOc({S89Y!fN=QMQlre3ap14)vjXeCQV+ zI>d*b@SzKQjCUVn+Q+!{F*bdSKYYmvE(zBO$G<6XEpXG|T(~S;8m=2I4wr{>u|FmI z5ul*BfV10?GVi?uT2W7)rvNIv!bHEb5q&Dv<|q?KIlWr#Oua0tu#ul(?KHNCw?rM~ zWSbkMW{)Jl2Dj~_oN#la)cvDW=sM?VfS?8WKI#WyA7IZH^IGJK6LGv)jmcR#`WKT@ zc;R4`2Gja=FMo6~ikKglpd9lveqyN29e5TERe|f_y`eT|V+FsURZ0JU{uZBp#Y?F0 z^$HzR`r!ZI?JU0IF7x}o+pz?%whr~$-yEO`@T3YxhrrOYQ*j+alDMypC3A^I3e27)t zf>mIvH{!?e!u=AIDe|G;Q$;o0pJHrnCA_FTG86S+gfsmtB%#rG{UkknHr}8aITod_ z*ZJH!Gh*|B-;$w?qirl*=9+P3x^fm~56Y~qMm|WbR0spae1yd}|Sb960Q6L(eZrET)TizJv zfY6e1`CFf?5|rcBCB$KGn)lTrI|H8|As=yY4?kAwmaw&r4*Id0#b*!>s5S|hxdUsj*U``Y;|y$dBp=;xYWc-;67j>B)w?|FGx*fh&?U=!_;98{;VL9=?) zNCCil%7Y`%#PFP>!S5BISKHWVPu2*Ybb@AZpNS%#{&m-hcs#h^whHWcj!IGV!=(@5^*W7O=JipGFpH zLh~cPHe`0A$X(M1o2}c@r^}Ky@1QI^E!yLB6Fg^@D(c#CN6Ex zW9Ze-kz236ilJXW7eT96yaOU8ZyREG<4fHmSXBmf(k4IJ%64#P&FDB5LA_a4f!_NZ zMcOO0jFMj6M(lO2fF5BzqN|a?8R-G{ben1{MGppfC)BAiYfzmIjG1_I6j`P1H8!sP zCU`c2BnQ>~1S9klVv`Uei|~ z4Zm^28x9OGiLb@7GxX0rBRL8FGosv~6Hpss)59a2P@Y7F^?dnV$NB>>WbhfTIB0k4 zmkJGRq-Vb9K-ia$Rbdm^G`Ex>%W4hWoc?_X!yL9_!y5hT6{P@}R6m+;oWH8D#)5J< zE~*bv>G>5Ra%ZwWoICfDPbReH(t|V zQ0qV)(i+6XT#gt^Rpd9}@d_-SeTsBY`1%u?2u;z9NZy`))1(QRp^3=q!EeFdfS#dk z=t5jyHBk=DQ@>xk;JkF5?hZx|wqxXR!(LbC>@BY`e#z@D&1OuC`c88=KPTX(3K}F7 ztVO>|2aV_QH^Ai*#!kxQ7GCQCB-!%AKLSP~KG6zD3_rJv{@K1uV4Z;&DU!cUzDFHs z*dm`3+p8XwYWBDfi9L8ZzYm}%+lW-iz>(6BcY;`rcK<;aD%qAbhxrh1SMYlc3CS|fx0+(J(z zhQF(+8yGD(48$tHV>mqcHT}P@8eW11NAlt`4b2bC=`pU#_=uaXZ+k*Qf5RH{!3U64 zS^=(S@dkdQKk$Ix@6yp2;|*3wH{dG`p?zfCGkiY?36oNJn3yQz_yj`A(A+b8NE(=F zjhUK=DZO|XFbwgs7I3itW#=qWxq4V(hI7jE^{gJP$X~ZgnNNE$#Ev8$rtg>bsFuh{VHCgXGj`807NO_xfvPd{UVn{&SN>24^E! zz%j*iFP|Uvj5~f~5nS9nZyqP5ZR*6D52Up2*?Xy|KQ+Vw4@tsPym=8QYEV+{Qwoe{wv( zv3MN_=}*KvHe#e;<}j!*Q%sM?wYar7qp(GBtYUH^c|mD4>Z@Ob>VpK9_MIEMmf{0R zYz-?~Vt5tLb!fr_DYuceaWS>HvYN};##j~I;p3|*jfUWCjHUVJ1|cj3zlFWAhhK`c zb>Zu9r8bB|eI0qxxe?#D#_D_fWZ2D2?pUg=3!!ro?3PGx&J1uw1V=W&Z(l9LoQ5fn zYlCq%$!gO!Swo36^4kW1Sg#RR8zDLKWz6w<4LLCQol;1WFD7!0K3ao+B*yXcUccbX zY3hZZluCMAYC#yN0oA z8SA;Z>iGbgX|Hdl`4yyIz*Nq66LQkx;6QgH_LLW~r+o7>V8k)T0F@tz7ab;+4D=jZ zqRGdHF(fG$G2pbsYqO|f9f^n;W;egcf|g%y z9!w(16wo@8&zub2H=P;hL|T;8-+BVQ~v`XZPO}VZ`3OtfWOdR~ zO`H9WH54S};%bPgELX3_FL_;q8+>G^{zis5y+GC{RAtEynR4VE6RfSmU8B1gRrp5_ z_h6XqCqqi#r-%PU%_^%{d{fKS2C+dbjzjEkZ6cwJUqeiT9=(r1-huB#Kp~bV2T!t1)k$vk>&>jv)`LKYnU|Y+WiFbSxB69P zg@s8x`xz`LBeL(;ECZ}h4{uk-KilfbXP&p#e9D(*H#n&KfWmKiDDo3QVczZ1y=DRpIHpGcHblU9g4 zIW_JPRo@@wMIY!jRPAmY@!xQVQ zevnPk<3sN`?jfyS_3kFIr1jV)twvVBM@(hBajV}DNLqS$Qk#`& zZ0SkgVBHesU9Aq0PGNDtIa6kERDpBJyp>;_*PPX-t99wM8nSFyV{Wd%&Ag+W8h5f7 zc?H6G{X4@9D)aFn*eGs*<0q&CCIu?)SHmZO;&Hi+A;WeFu@l#b5#$I-x)M!Jpx3nc zMJy7B-(F>)aS;Xj8HE4{T-i5%B6h-$$dUp?5g)%ROMGFr#GnP5QCwpZ5!-pdkoBA| z-^ww1gSKWW@U5-n_?F2~BmBDC8$bkcPz3{BSoKbHC&~v-k$RRBhGRbCei@PFXKLlk zyQp5T>lyDNHS5kBA;$O5#5b$(Y-q;mr>PsULIbE~9C!K&up87J zxbH~g{>TfeD~OB>`X+YfyYDO~0jR&k`uV_zwZ9sUHqbk9(+`Jrp2Wivz&RG|vcRDz z&g-&_#lE2E8|L-lI3E$FBTOv9;2^$1+~x$TG?kR!Ih8bgN&Ib7pPCw|mTB~-i+`y2Cr)Fo zMdDY)Un~CA)0p=?0)J~7TlAFp&r3|UhcWw!e^3ug7y>*)T>wT0>K2Llp!i?vxd1hO zPcZ)~F*ue5{9f@Fh<}Rs>k8z?ZQ_4NVz!E(E)suV@n?x&6aQ01Quq~tQ~MBS)(raZ z6aPN(|8qtUCB^h5C6&F}i8CQQ7s0gzzxW4645)Z2Yh z@=l4rOZ|6uWt4Or$d)|fH1FkoAj1}-q)6~y7+ zExA4(v;h7@d=dOd<7iid@|M^cV~@G?dlU5Mia#j+a}s~Fz$c0S8u8B(f0g)a;k)Y6 z#MSUMSFcHslPi-yKwTFlvGSGFm|}cPU6rJNWAdj+y+wRd-mmUT{yQe3hmyYp4ZlII zGsgZReg@CS&ln5E?-75N_=k#rtoW}H|9tq(b|sxN#>P_g-y;6?;%|a)ao&|`LF%32 z-y{C#;M>%%q(Y>AL;T0!&r{z)`SaA%@MG#vsVRu@)1C0MX~q}CpC$f5;vXsgN#ZXS z|2*+87Jt3?SBw94@oyIY-QxeF_@5U4LHMrvM*55JDU+^xJbfShA4>es#s5Qkn&YbH z1x{p$GfDiM_|r1P-&f$dnIbR`5`R!)7Kp!4{MU;AI`P-QkEz#Z_67bG67yE^H;eyX z@jop7XT^U={BLGlNWxQ@MezS9wQLnX(ZYJ$T1xPziC-3fP~wkjnT`14TS)mL@fWwu zMa(jR*NMMg{Ae0wC)*Ub^!c{4Q1X}Be%Fw_pQ83N#(pmTGvfbV{QnVutN30> zoRs*j;%DLaU!~S68v{b{QCsH8}Onrj*&%U91-MgKkzlLzABjC49S5f z#D4}cG4=b9y>{$mQgY(tL)>|4$z*6|qqQ!d-0xy^i~lC^uM>Zx`0o_|cJc2L|3l(` zO#IJ?|3&dzLza_;uX}&d7`4qJ(Kd_5sBIRFJq#KajZx<;8l%oxH1;nNL(Q{j?1z9) z8~e5Re-Qt#@cUIPI~#qG58vG9C0n}A#VPG6 zY|CWvyTzX&{%r9N75@nFPZIxh@t2B!{*)qGdad}Ir+fjW-7fwI;JfPMh{tG}!nQvQ zd{;dt{&(TeQ%{NiGl}7BrRO6{;qRv??~Ji$#oq=W=Yw-!gq0J|wFA!Pk`7J*=NLaT z_dVBFhveKCY#`VSzB)X2AAHW*zB)@b?Sk_L@t#LUP~*vOcNN!SH~lOG5nypq5l$U-)|n6rf6B*3zP1cx}m z*{}q5$%Z5(z-|(pgoXdB>b^6hhrJ}{ zc}_0_tUo;icN6fixaACv*?I<-{lpoM13q@fHvxZj z#xsD{BF-~s5$CyN(Y(M+l|%RlJVK&t`~y}w+ROeSV|%SRz})cqfYB$d{{<{$u!9yB z+VqOS?zI+UE&r}y`|+lKCE9Z)ygn}Xk5(<7>^>;iO>hMErEwHe` zer~PDF5akM*U-CGC!W2!0;_0HnY+RjfggOM#{4(A%7HzYPul_P|K_pFshp1HvHjTH zbAQO8@(C=XYX#c}nxBHdKA_Y5UvkaCPWb_Y{f+B3V0Rkq>#jS1Js{ZA^sMV1JWbww z7Snv1j<{+mM3-yK{{xg;M7JC4Uj=*2V80UVho;;g(4s~3x=B;+a$skkEj0bp1ZyzZ zJolH8)}}G4c0Ys_+XV(&iL|q5t6;CHweAQG)8i&BCfE&vX~~~Ww+qJdd=fe5FLvaz z18c)2c`T@w(7Ac+ay(nsmdEC)<+LS_ouO*zn8y5vz01@}dQ-4{{%?D0fE_n!|LmQE zw;yKk<{~ufm)?4{isl*&0~l`*R2giBuU^&Dc7rWI+G@%fY_YE#*!6<#qw{2<-bp^F47;|FZ;~0AZ|1RE)dlok9=ltGX)$l`)6;>!@;|7yP^-Z{ z>;EdS%LTgzuZYaS`$@MOjC*q{&0opot`QB{Mr#bl8nTUs1$#PhzrP&s>l`%L-wAd| zFx?Lq(OlVSds@cWb_yGe<++^(48{`NPWNg|`h7e7z@)J}x6>;IV|i|;X1rR@y~6U` zPVE{Kd0tFc8I0w530-e6mS-;=G#HQm7(FN0XXqRLL#mHLc>R#@p4oT(kE?#l8SEAR zQ)++?8|-bQC1~2YobwugMc|0Kl+HBRIf0|V!Un5D+8`wj)`+x0sya`XFOS`-E~Ak=cDKsWErRLZ+(m~B#=W_V-q1OvH+R#tHM&0T&E0gpV7kZl z&_f2}9@|4l1=BsYhg#3)a=OR%(p3iI9@|T|7>s*tFCEpG^w?hVengk!9@|T02IC&v zOV=5Udu%Tq)R^?x<>cYbPK;^pv5(VqgK>}Tqqzp-9=nom6l@XjQj5Z-7A>vYkK z{M|b3h0;Om3v^|V#$HCwFVcMmdlT6GbUe&y`{;epe1NuW);Uj^F=#ztK6|&HP6hTL z-51emi)Li3uh4L>VE&6|+=d;*0|whQ;|^d4HAXkj*l9gP59P5@>#KA$kA1@WJ35}n zK4U#f$+)f|iCN}xde>lg%$Ngg*ygl-boUHSdr7eU^pzR+SdY{8K3(q6j4xY<=~%zU zo}Tfr^#s)pF{ZWW8yti;%r^NE%fX&jKSBGRG-*#OU)k5Kr}Eg$vVXLmp;dS$0JWps zcdUP+0l_{)7nB{dzC%|DrfYbfwxl^H>*sH*=jkPlVOD$3dVyN`_yAh)t+EWT*Y;`b zg|Z0V-F(+zhi23QTY9BVd$DW|-l1(b*dJUO>jxCRiqmv`FVfe>VBZ!@kB%4V#~PzY zf-_t%Qs`<;^IK)7x&DQQZ_?Of!82Sxren7V=ATx68{V^g%V6h}-vR9Rf@$yYb((f7 z=Va^-dYu*vwjb@AgLh{~4aPn8Gy0mrZk}t|GZo35{?{9)@C6uMhu++%OhGX^_Q zG6!$KF1}Z%y;#=d`X#jrrd#_f$_ciQ*32Ao;a%bXqjRpGd6nyTbfdwx&Ai$59=-Bq zPP>_gXWr-XscBGV)}E_o)~jg>U5G#3qUmbj8OC%C(^b8s-AwPyd=z_r!-DOn(`S9d zRjR6<JWdRCj%!F0@Y;{u} zyFs0!?#yGis-^00^4Q&KxjG`4p8r;;w+zPf-wJi+kEK4D|7umU!Fc|wRZj}0=f67j zy1{tKTLajMu1U{hQ9oGhUOrM6msS_B@)^LBY6J=DC~I;@3Fm)&9@SxsBRXvtaxD_su!m z-KLHh>??DY0h{&{&Z)ihHuc=UGq#To&xugGdg6bT~+;pG3}+dtAhq(f4*Ja zV=!)QyZW-hxV0VXF~RoH_vRc?ovQr}P4kU8bMQX(W53iic^%iO7QZc+c$M9%)nMF5 z-D<#K+(+H&fWf#|y44p9#=X+59yA#DO1C;B7)!Ut-J|^f!8NcyxZ1r*wHxdee}j9o za{s4Jd)wdU-m2~t>>B@%PMw1jphFsibR)oC%44?sA~o=9E_V(66gju619@!FyK%>bX2N?EVWi_cyv6+qz3s*kHc{m8iPKVD7n$9Whv$U~lBH9qy=__FGM*Z0_am zUbQrj?RUpjIFEh8-KQ=WY#*I5chH?sFPSu+|1MQ?-_cagM-79j%V4c@Bft(AY}4F( ztU>jp!Pq7bskz6w+cA$e%8$t9+B|ld1%p7Md3oK&gn9#oX3gLWuKQ)Ulp3gwNH%EIXRC- z-y)Y3@38+p3wKtW7+C@LlQnq z;5h2MNZ7o`B*v~4=KPRCE5#o=MZTeMU1{3YPn z)N3U5fTUgo%8F`da(b#-El8z*Grrg)8g>$$<&Z{LxYt;1;{v4o7`p9i&nR^kV=wX3hoy`;;1LPACZru?;5B&fTIw=%b z!(H?|?2Oyg_5YWJ(cC^Ea^Uge7Txxk8E2x6oj4;*%%e4sbwRy?U0>yf0cN5@Ib*sR;1l}+3VS$edd_v$q0Y>oED9-;wfv*bu8Q>lGdK6AG+)Ax*)vEv? zPD=ofs(FBS(CL7edV;b_2+D~?0Qn=-AbElk4ifK02Z=r3AhE|Al+{QOU)e5)KQA<8 zx4cbiyg*`@LIlr4YWTT|=RI51gB9QROrygUa}fWniXVES$n%JmP`{}7iKiMlkE+Y0 z)NZwC!EJbIZ25vWJlCo77QF4@Jnwn-skMmNr`9d-diSXf67B-LNyU*rD7*4EDc-lA zMmrZQ@Xn&E7gPb>gw)+C>AQ{YQg4CJPdeLJ*r+_@NsW|-ogRl6DqjyYVQ;3 zi0gX5B?~_VShsKu{ZR71D*5kH{R{8){!C(iruHse=H~D}c<)mC7d{X8$%RJ&Z(jJ% z-nZ3V3xDiQ(1QzK^UkNgUw9iu>6;7RMtFtmdCz=$c43t_N-r<`t@n58mkaTEDeJ+7 zZeJ9s3w#Nh8(QMKPF01feO%-1zH_W&A+LY6HRFt1{Vb~p)~uXmP8&ZWfiUrKuyMv(KyMRp)cw=LQmXtP)X7YMvgy|^f2U8jBm z$Ti*w3cP;WiqtO#_R+hGj^JbJZfGfg1@60mUD)OEQyAaS^5gp-uK;eBZ;4$ZUu28p z2|Pc3dzN!PCpnKu&ZCm&7;OW!m+%cLKT5^{U!w%z>+sb1i*i}Ow`dpOujvZFrRpuf zDuK0%Y1S*QeU0MU*Q(zjwORchuvNVe*sk0bI8K0FU0i#;i>a+~F}1ZW{u*7gi`(AnvRvTA z#Vze}`4HYBWw%S&OQdXE$__}`q?8?&vNSnN{>m*8$#zTq4R5@b6n`W zD|E=sJhuDa zy8i;H^=_8%8aGRLtviO8W;e^Z)jfc4yHM_udc$t+sRM5A*~3EZNrBG@&F2Ij5z0s1 zEVpBBmfK5G_7&mzHG!`S=Wht-ZwdWh3w&3ok%u{Sdziy%9_G1BVs?2vZhUpnQvx{Z znE`l2QjbdNG32krH{_0&RN^UycEJ7gCg5pwJWz>~)BwUuC*xH-=~ zZchECdnPn$t%u)pEM?Eey&3n#xZ`y#ypN&e z+n^uD{c^-F!F?C*OL5QPz6^J`NoWD`Tl^a#vIwRs+(+H~toRiK)m0~{7wE2{}%tn{%ic7_kYFz zzJFF=LEx-FW#GI(YhWm_FK|oXPCOBQ7>}|m_%SZ{Wv8GoXTuv?h;O$oL1-zRj+QLK zS9d-{A4O|cyJCQ?F5WOtxH-Jn&Eb!`9|62h;7tN=6?nJgxnJNfefY){{np3%J${B| z0_XUdjxMDsOe|{!o<&(*O4FGZ;8L>$p1j^41>Qi}e-o%{ET;Cs>3nAfxABs4hJP9b zUAym8rZD@|ZfL=&r)~i}IsZSOjgL)855c2?2g>hM`2c64pZFcAQ;;?rkl!Ml4mc0b zXIS_SA6^y1(-AWPE0C`62EuHFKa8&@DfI2B2rormtW^N{+f}C_yd2Pij#dETxlF*1 zLIW&X3mvei0a{?;El+$-fSP0kGy_`rE+uP!hrlk-v+#vP*8gtMv*-eWJ)p;5RmE2c z=t8Ok+)S$gx6o?9ZTN;B{B@k_E6igI`%trmr`H+wqh|P#fEK>F*#wxvDZ9dV7F!S= z#xwGYE(5eEgA;ZO7GeY72>7yS2YA6c1YB779%m2W9^&VG_X@lRTv+%PD#LH$d|Y9V znBkk?#iCycd<);zRP;8Wg|DGT0RI!dgoQ72#sGf{9xZ$+lKbd);7-vWV5cnly+F4b zLfEU)fIf8@pkHMHXQ~mvS!yTXY@FR%G)L_PJXKu*3UdL`YwF_|la08Z@htZK-1|M> z)`0&i>@KQdz-!g<2k@(w>iCn;AGPag!gKD&0Y9mB{Ug!!>Mg*(QlmIy_-l0>@CG$} zgy=?f81N=_4DeIx*b6uvP{+PUbWn92#cva;xi4ZzRNe9;evidH%6@nN7r&{1UygS# z1cWKe|0(hb%3p-^!FtSq)hNToPXWz=ww(#BIUCQxEXH*Xt`Fl{f@>+RWwdy5$^-V2Du8`DZ4Hi-I2~X*v4oo+HYs5DLpitv9sBABdHjW zR9~W>+ET)bkjRd~&~O_OIXjbzCQY_N?fHnfoiFCpW6}(2==6m%woL*YJ`(9vyS>AP zFb!jfKvU6<{@ulKLV+9KvMXi}=a7qf2BH}|zA2YTa_ySO0&^^jL`>>xh$qoYR7U0t8D8;2TO;yH7Bye>1?z& zX;VvTWQaD7B*95En`^d{c0cz}p$(0j)~##lj`Xx`YoUHS7YV0x(PZQ9oSp5qqj8CX zQmv@zwzHr@>+PJN`9MP|-jp8Jk{Zd`Ix$j^#t@Xt#P%ddGQ-lxR2hpwL8-s5CNdPo zi)Xtcxx^6quqYyX*$AY|Jz>B;tZQoSv%Km zr}}dP?TMj8jv|Rv%67&~#Iz$>oFQpPci5f7c50lUq+NDiR+8GD&x>jz1x$pxIg>yi zu(X?^se+iJsUF)NbmDa;8DEAX^D4ovbT%Oh$h7ka7w*g?`V&x0rqkoJFRvj5y{Obd z3{_DTh&h?gVqoMu-)R%%Kn3m{c5#;~aMx^VK~kQV-jTjOXnf2JDF_Glf{jlM^b)DK zy$cYUA&S2qVe~Bbs^ST+Ljh ztus=j^O5G3bq$-^!;Xxa(lCuN7H+n3y$yv(p#6z#?viSX45#tcl1MslEF&p|2XG$OkBJ&8TGLpMBtp&4f;V30NXo z8;fdPIujm9WP9xXAt?nu5Zex;3)Rg^|HV0EdKBTlL?)XPjx_1v7)5gV9`4GdW2g(_ zi8x}{c2HZFN(?FM3Q95;_of}9)QqG(SJt_p9E|JFS>6F$u zP5j7UB+?j-4MIxm5;mUASu?hA6Vjc6G&Y|>rN!Dfjcche+Gz9eFZ8*DHb-IJoZ%ot z1uETV$9Biig*{r|pr@(WfG!C=V`ZgCZ(%};#I>Q&R!&4EvlI740pqR^8`4%}BO#G| z?Pwg20f!mgMB0>cG|;3MB211#6%Kj1GimAm^pFe+<_5GS%<&kSc1LtbD^(up7)gq` z!I*A_PKKf7)Q;H^4NCMSct8xG`F4f{+?2*JFhhwgwH`@%Qu*2bQcvcs9TgL;BAr4 z4FEmi?v{p)k(Q2TARR3&&5`D|rf^Y0cXwwu(B_74L!`wZuzM!VqX2Aa>9S5aI- zgg(JzCxVnR=4xowTuK zW2C+1!j|^P#)d6Lm}8L5_+mFv=DJ8rCX>!=gu23wq^|Cko|dp~bX!MT7y@Ysw@~Az zo~13aqXR*8yZ?$8kz~9OFLHRCQ~77 zExU5YZW7NRUD}2^aa!Zz(Ofi=W4}5HiADO@&8D5Y=ADsV_Rx32b;=IXPEiP<%E z&Y&GG6xK0WVgz#@mLohlF^0jT{gEsh1cCDi1{1>qxG6d?gz*)JCqF=@d7XWIFd&pn z~e?n2*|{dvY7$!W_8m(OwBrOx+{6djUSbbrB{m_} zE1Jo-nNCP?M|u$MX+st>u~}_N7z_GjFFXj6$-ONl*-)totxu=pTHWDV?qa2)4)|$> zsHTBv0s~D}4`#L5j&X?|(#xlf4INvlH=V(ZM? z+SNksEge0^I#alzu^rZ&?J_kBZ0c-g6Ahc(+}VL7*w_3DA65{CygSS!_-fe_rslRD z4H#+a?Al80ZDHEn(9=phX`(z+L|ap0GX!7>$Sac+W;M0~+`?=)y&g7!M?WQHgv14E z(8Q0nNEACskNnP zL#@88(6<_WtHvA(Kcu4*cb@tkpX9=p?w+>J4ukh4c8M7v6NpnIdj}fJC7nQ=V#A`D ze1n@68H zHv7(0Pn)`X#N}W&nH_5=J>O)hi+u<--3^&cbT`5O}|Pph#l+yixs7=vK$7~C!0 z4edQV{MUzDomg|1a_zckcS~1fMPw!6z72uuDjlk>j#RIxXM2Ed!KRkuU$A_+18~BI zzA0c%dcK#kgpSu;sofA=N)(}>64J5Qg~RNCj?~#h!)$rF#U9t+Ee;2kvVsJ%m|a_I;$Ux7nF= z*vlgm`8`*Nlyl;>z~W*h*xntCa}4v*pkgXk4}Q3+mUjxEA5g))pe>ykK+N*l{Pxka4*bVMYBqi9tp z!g4Ydd@c7QaDKHMSHc( zi>x+e0!v`x%^>d0Tkoixd^r7!`9UlbWMXU;Se}F-;*mavML3Im=26*=Lo2;MOAXk( z9O_N(=CKt`?JjhwlK^KkJ`&4KOyC0xXy3pjN!Y`S+w2rgQVQEIBN_O%j_Nq|T!@Jk zEt{CYc6CCcX-JO^B}wFVQ$rHFA<#_TVM*=|XGYM@IQ#sdI+0|UXZeZI`W$Tp<7QGu zup1l8B;?SlP`0VPheel6K-Ps=!(MYD+Mh~iv9{%-z}}JmeqIk0vgtSs8}84nZ0KPR zpKI^7lhIugDq`PkCQDc461@p{*F_!X^sU)(7F(7c&TlxcA4y8!^IMFEpWjASy93~Jh8^IS@1yhHtBu(Vi_@~n*`GOdUOc99`2 zM^@2fL2_oBxrnfdLB*}uvSJ4c4M=6v*rzskoX>zWUgzLE#O}{PzBqs6INhb<1+?>l zp-gr<39H`zB4yO)rf{`+GAWWNDDr%<(T1C{8!h8mE1cGHY-8Kl*$1k_NvIgl%-PKe z>>YJQ0l;wHheB993F&n-1CGpyKJ4qjt|vEE$MCju4-6Njha){By_oa#J}2i8-vSl_ zQWLiljfeNnz1j@rhGn%atDBZJtXxqGP+i~Lu)1nR^}6~iNO+Zj6TztsD8xh_ z>}GIm4|YP&U$v6XJX5c2t9Grds;a84i7%@rGv-_EB=jNcpmGRebgtm6Xd$1tik0;f zs<2VTNeWcg){ZZ-qUxkYR@6^cqUI!(RM$*aV#Or&)}E9~)g&eACW%{#9Uf@gMr>T3 zxaHMQgK^!lq8bgK7*{h%+=`P?UOh>HleMg_da^3&PEtip-DJ#97Po2=Uh0XLiZaGF zh1b>d_}~Z}^_@_6tE=nA^H>#+O%NBy)xa2NBLlj|@WJ>y!_=8f_;jgY_?%d*5jy+2 zqu8V@q=8I(dMD1A*oZN+W;v)$53hqT;Q1C#!`$$LKrLZB@nus8&s3%GjMoTUwGjN) z9QHbFJbyI=YzVO&6GD!(+Yz5(}$KY z?<|LYIu~`&X?yX^)Va9$-xY}I!n3KJc)E?#nv2R{;}Inti4|nJ6Y|nEG0pKZNkFP0 z)S1llz8g5UK0ynuxS|=QQ+TqAC9fr(1$Qj*-AE7N**eWtFL0Jb7Ekeg6!Dvc22-1*kt~rC{+t3M~ZY>aXUkxmcc*nJ=C+J2O+MD zInw&UpC`gAtSJ8R^}wI`$o)?3~C+(+PIUa@YEsqq}9z-=EwZ|D)OWgHT%f$L}5 zLm%Rt+!IN}aC5J*oVOe@B7z@yw5$&LjL2}jH^x0zOrFT-ur_LJMYd>ki^uF#V4 zg`PD^>PG#jtAUOe*z(A3}Vj)JPaW&hLV%@ zJzE7mCZVtEop!MPv%cvXD4FaVWMv4>#d%=-jkGQ z;JIZO(&BM?;(S`$S^vh4W{lI>+aPc5xgOIS+-tOItaq|mdRO;J6!VE5lOa6SuQiSN z?&q=N;ShOP_h{xM-pY)zakNltGJ7(MQ3vY^&mek+hkkp+$Jy%Cuj?spjh-vC-5fvW z^c?2+gKVFN@sGy}^Dkalv$Rb+=bN#}o{Ehz&9;n3p&keI zM7y1l)C6fY;hl#XFy$ZpW7*|BYZTD@$WPFy3WqOMJ2HKDkNPGk{3K<}*I1UZdwX$by8C#{2& zw8U8JwdY!pXR!r@R#taNA8T*3c znmt<{&20G!b;un4N0nyU4u?{DMH^y@^<**|xeg;Uid@VABsqG+RuLXIBr4|E>8zNr z%%+9Oj&B6V6)Inh!8EqZoYKrBFV7~UQ7mE`=HeV?Xb~&D&R?J(5;M=vmW@IECo?^< z!attri489>J(m7BrdLniFs%vWOBVbWG?mypHeVqJ{?Adpqp6$6U_n8fSO3_J|H06y>R^3zp$8JPKy<(-dG z_*J5X=akPwXg;^3JP?dCQNCLxA-4pA17L@O1I&AHfSD1F<^#9N%Q$;*erW|$8*nd1 zKD=Ix`tacqLNS1~3`QC7>uUJ%QU+j*n{d6UH5t&gCiC?to%#_a^)HqBm*Snb3QsA1 z0HnfG;Q>+#S)kUXkXkA8R*FUjm#JX2!s`z}$hi3{++OYjzn|m%6<(+T z)J2p6<#ihRSp}%J3Rk9M`95nZ^pOW%$jobQLU z0&X8mBmiJ}J*R}cAW$Ly(H4Jsv%f6F6m?X2GnfXYEuhlOe6jYSZocD3BtYjB2KfFD zx$&VFazncByWeH-dw@BiQBtQIhuR?n1}t$CLsWrZwX#$x3g8KsxTy9^D?WYuExBKR>G+MSPEGw))%RXrymrlNpQ}pU z^34BMPqbWnTh)iZ|HAk0yY}|p_a1rlr9W(V|5>%Rd!unO;sG{FI7!gFfh9WHBrIQPx}QybMO(*5?mN25F2{L z^56>$e#__c1n_5heeQriV7Yyk-SD#dT10anZx&gXO6mU_umS~?$L3uT$eZ_1&& zGKo}p0w$uA1;eJ#UkV)qLkL=>Xjmz5v6b2$LVJSMcr!gX`d`6n*u@Y{_plZ9&-6`W z1x8N*c#sT9Obc-b@n3KsTiNouQXXg`J22?=f*+l(dk$gC3iwPM_aVnH<9;89gH_UX z9EooCTfqGRh#lhqp&7pE4lzu%PzV;Rh@h5Bm#_6(rwHj_6%&ALDoO#$*Ln~tUn`p9 zw*pp${|w(8L#bdh5W$E)*lGoEXB7gK01x)tArEd;aNj&e?=1I~<{1$a=eK72%DM2^ zKhe&T65U=axCL!t{z^)?&5-FV6dLyjwo${q4DMs_0E36hebZr>jA=p%NCb`dcs!-P z5>5~z&|_4E=>!;NCY1XcgF_4+V{rHb4#^g{0PIs>xbfiQn+3Hfufq^!JITD`Hy(qd zPii3r&}lA=lYAGulA=c7h8rd%T+rWzRI^12`lfv3CjMg)8Q->0bV_p~l@2uxBqvU(<)<3#023<`7`F48M2DW;krk*_??E=AK(mef5bqK9c^}qc8uo?b&C;16(3@?)E$n z+jkfl6h(2vx8nh`?RYN7##6=HMKbym0>klMIsp34-yIwdIoR0yjrn|dlqJ)gOm2+g z%`kZ--L~ap1f2i<51~B1FgNx0=aB&acB6c1XLKxmJ-=f(Oo-=vt+=*~qAU!K^H=7s zMesr_gCl?~*putQlDZS8QW4xcXdS}*_jUK1@3HUWeDlJ&^OtYQzC0meL|q=Jmencg`U}q)vM5nl-ebaKJjH(i``qu zfR5mMDGGaxyc^2rPP`(;4lnBA{avn=PoYBjU6b)^W#)=cC$?eT+lG_R6P;#MB4q%y z`Q-3ioXRZ6*$4ltls(iqYSw%ByG+awa_~8E4)W#QBz+$tCr#*Zs#-~voxO3b1uUXdVyvfl7e)!BSi&XwCUH-<6BR6iPb3Va4|FaUfL}B$u^w3BCXW5vleM$mT5}1;}lmw`EH^#ro+UHgAxvn}Ob7``GoXa9hE)hlPXH&G1hTL+%z$8; z9ws1)vL+5H7y^Pj?)wuLeCYG3&!^&o&jnEwTyT55Cl8V2_x+x#>b^7CWqI%O|8r-m z>fEYRRi{p!IwZVS1iBy;>uDZ9V@G=Kp=D^Dwc$ot)bKw6+9GJ&>H6G4Q9Ticfzbm!! zwMxasw_&|Hk12BFb%)SnM?HMq$%Cst_08J5|8}Q;`d=?T@@L-bDkon)^DpIVroHCw zH}?GIqioZ^9(9`_ao`v%^d~W$A0}rab zlD}Se(p{VXd}i&Mqto+TbvdX*sRE}kO{oOR<=!+4J~jAxuA65$&d!#*mv$^ICmdgg zIS6w`pH<4QVcPCFRoY&r;x{ROwtjP}M58F1VgnM}b) zN+5%;-sIOA87~|>0f{D-CVXAuLKof=nPl-`BugBpDiu=|<`$x0Wt45nub^fUz+sZn3i3c&(QG*x z^|yGbSpS!u%qW5qwSZ}i<{@7-B<(rVYhV@~l#>qVq63<|IZCDHMbyWcJn7FQoGR*= z{7y%LNWVXda)QrW($ze?+l}`OkCc`oX{Xwb5J|92 zIR#W1q$OLUCjv8m0i^iIdwR;LlGMx=jhsYGzNb|2P*d&-n34!(5L4Mi=?So3v!wzO z5-F#z%A#h=Qep&=tFa0QPBh1*Y2CagUPXbu!N|N|ichgAlJ??`q)&HMqu_@ae@6U`p1yZBc*8!t2 z8w6{r{hQZBtBf_MsRd>i_)ab1XBvT(eGmhrR+6IpoGRtBGL4eTc80d+swzqVeZn?o zBrzGS%VD({Xdnh&PVua|wBU7?sb=jbbqy8FmIhhVEkLZf48=mRISwno(&)?XPZh^a(4+p01211$KQCMZrv9i-;3QcyBTeV(VD zL09b%l=1DSJkcwe% zU29PjIaR9eY+2{l{~D7(Upi7aK+@0|#7y7tNIZz>#DA*%nASt2V;bT$$~Qfsimm?i zMz9l0l&)bp&=-)aaT%Rt;#FuEPq$#*aN|`}pwV`f92&8L;$`J&1-P~>H5t!{Qgq@~ z7D0DD(uKuCA`%VfpFwpM9k7uMv8=rj`cAp~r8N(nDtj-X*;LxV=|F%Gu{!58fzOV* zK<%?p%YmaFQ^9}fp(kbHZzvwx48|6hVQAtclor>dbegG{FMUMD7p-2&O38e7)BbEf zrqvZo?o>Hc>Pvfu`@WRWkXF~(DM$NDf2&X@o~;vITYYJNQtgFX4$=Jvx>VYH)bwoi z$YIT>Mf60W{6mULx|O&SH=XjNY}F$enPJRzAbE6>+UGLO7f0QsGWS~eTdMc>8m2b> z*&_>EFm)abw;EfdPitPkFtB1Qbh81p>!?Y=r55% z4Q#>8qfR4~Drux|^;}epE3Ta4I~Bm02YqpxCFbv(Dmh>$;9Zm7(9 znky!y>8g?4OS3wRco>^XhDS2P`$7CVHyQ0<-`e4$?HbrH@2}=!4|e z={tWCeS1)5Ml@-n_p)^@d^{UL)yo89<5bCT6utljnbgGq zH!xs>A37aoQy&u$6(WxDj_Lf-@tA(INxkA=nXXBFqVwZcFUxM~6D@4p`mCM@vMLL$ z!0LM4wtYBikJ3Yqx}ofmY*mgxG&Ki}WD$UMI&K-|0F&xssz7sG(u93wE2(_sM@G+2VhXGM%P8vj9IeFzw0!g z{zuYuMHVo~1fNEa(S&A4p+AJo|AD)6`eG{GZRyi#Ntw5k)-!vM7TX=h1PT*Q)*nR4 zt|2&TW}`l!%Idl;ic!7MZElSbz(Ub$p>!5D((%-%cOxA}aH_OXLt2YQO5=#AJx6+w zY2{dO4MQfh?;hoZ0!C&s^f-jpn1YQXzKh{&wQ?UR?}G=lG7)vWMyhF>YT@{LT1J1d zY)zU+kbBJ|u0^5K0dBa{3BRJ#v9Du|P6xfs-O)yG^GcG8Z0dc3>2K)2v;JlWby8)# z9rZVo=1%&Xou&Cg^*5TnP=6EB`$FF?`i2J1l)m9C@X+=REC}S}P~A5$O1*E$K|bhV zItTOe3)EtbRm<5CV{g-47(LOX79YRe{=)E1`ioE-k-Ywq{$khZ?YO@%alwJ)$W&Uk z+h1G+-kJVF_&ce;=+-={O2v@rP8DM{Z*4hI956wX`i*=TpZ$h;zW^X3P3=TP_C0kT zT#UD=hYbB#-`ke{dOzY+F^u6FU_a}OFqDE&zZw}8pz<*{Gd^qRgWd-%)lU{xwBB9X z4#?232Cm3Zordl5u*&jwSWQ*567?8T*UAPfeoo8Z{ox zxkRiSFLSCbOJ(UuChZ52!0*eJ(|#_usSf9F08x$C-c6ZwR40!%luic8{#X#rwJm>$ z-Xy|$M}ufDed{R&(M`@(81j3C6Hx?-+U68a0z7&$tQvz1!YOzkLj`$-R}(chEmk-c zz?yVCh!;)+lwqn}g(UzL0MJ~|Cet7`zm>GdQ3;aU-YP2b;@LqP6X4{yoN!xgU$A2h zY=Bd+jX-e#7({@6^BP@~gwhxr1qs&a4#y?vrC#uHiB0nb9G9R|e8I*gHmyAwm%KIq zadeT{Y$lV*j-HM>AE#`L9E%>ja0Xx5JiurdYo{Lrzxg<$p9R&mn<-Qpyrlu&N^tCO z)LOQD6GkmfwGH&?7&{7HOW}t(aZ_#MWIwdNrrK@v%hc|sldZjzj@<|wy8v$;OLcl^ zHB9daou2i*QTr~O?0XY@P22a>WuP6+A8o(Gsp7?3TDy|5su;_A8K-&`oWhxuduX#a z@dc#&we`d)yb&Om5wGK0rZ%n}_(B`TQXL^v+YAp-dKaDE+MRR? z=d%=A7kUars4V$`b%s_)sPQ|NX72Q}<%BQwwS^0{zt+K|B@|5dhl5E;D46x2gLT4V z7b3i4Y4%RX$@Haa@4#EEb_Z@!- z8iVI=mc4``XzUPqayyo8OgJdt#-tye-|j~jG)LT9Bi^kN6TJj!k@Y3+husDt>}0&@ zNjJN(8LPrQ=}1@Fr#7XEgnI8!sr;Lfd^*yZ_LYma1m2bNTd!8?&P<|o3{p_>l#808 z|HkG37+5L{BKyZ4+S z$E#S>P&A{CdCL)KM}3#l&X!lNr>n!pKo^*>op4n=E%0&)>@G3Yy-oIG$L<(^FN=d! z?;WHG#>J9hrnQ8bR?HbrNR|mTL-Vp2Q<~cl63V%!_rE~azz49#tJ_9IK@g1mY5CPH zv^o>S6fky?0gtGhDjR0lzbY-W@+l&Xu^D6s6UCXfG~Mv*KXTeC@DALvMT(5K08rVCNHn503f zp>@+{!A0u%XQ~9<(h%T94FS$fiOtAqOhZI!!^t{<*E!f>SW`SDB)AYtk=bpqEhAac zW0cq_7`fzNk4f-Fk=nOHM>thT0PIU)NAxHRk|b~C8XYU!Gr=HKAJ(@!mO^X!8}s~v zX2^rQ8BmjI@qZ3{=_fqyzp+0VTLsG>l%|u64nX2jHGNg~I8e*P$mNEHb+W6Mt=3(U zCQnn;m%{crX+nK6)%7Fa@ENXBK?&n-9E|Cm(ano^mnQ_Z`bsgcqRsV zMauPSQ4&2b85;&&*CNKUXb>_107pjMnjX8i ziM8dWB_WtOzJI^u9QD@z(GfW7jK;*9<_ycTdXdF^gAhDc|Xh{zu8+wQHYAZ@@ zJ+kEuGOZd~1`2gsW-Z37cao*y$i}4IkI8S;HL9?5E%T8oiQd}m#BHsZ@UafCB|gE@ z+1MEs9qSd}K`h{6<4`&f-5E)JAr&L+!qlm;{W0vyBF#aZgs8`c>eb~3zgc`|D|Cx) zJcbgqV>1>kZ`4xH@!mLypCSCimLKXh&2%VakeZDsHM(l$_iXX7sQhaLViZ^pOzOZq zlMsYoY(KVeL?bw{Xvd0q(XsQ8K`}D663(jH2yBe&JoQl|)T7&Q_?B&a2`2#^O|nmi9)Qo<8J*Ds^m~_ zI8{zCvs)a5RR~ZiebvjvTYY5jkO# zE!*xKQ>p^`dZ{4xxtPux{R92Yxqtnn*-8|Ws$mRsXMHAwWpoM{fwTNFlh>ntN9F>K zc`2Z%J`$6me7UDA{SN27o$|tSm8@1LiW4$1<#m_)k~k~SRrcrkE;e6uwPLLTOPGb% zF)vj@1t>(L{zuIH>cfkvg_B{**zwTL1yGKd#a9D&1@hjO5uu4q7DJd@fF!e-Y#F^x z;Q}e7R<^pEH7S~<1h!d_5{GO`Q#SG*QA-@9a+G(l=t`uig?3QO(jcN>y@i6t9-nfh zCD!)8Er`Vhnr2lx7!?x_o!?0+EG)tweGibdR1;N4C|dzzM>p`SmO{2}9jseAvSy6> z5cv)D@WGnEwzUvzP|JItY5Ce~Tw+`WJK^)J7F2+T70kYr89$>Hi5EHsM%W+188h%8 z=Gd6;_1R;l9BzC;qv^Cz*HhCHuiZ@xhfA4fnfgQ;r<{Um4EQ3Y&w(vEO!LFCk@ZlH zSK6Sr63`fY^~<`|%Zn^?nQ_#~oK9-SvJT9^r3MAX%>i+$SL22AfG}cxjI-RSjv;(V zqL3bDC$+afw#}yyZckx-G2SkZ&$&dO(&0_~7(QYp1i=-5V3FwkS=+8TgH@-Q5v z>=?8=!*3dm0<<=>c5bhJ^#}DlOIN#*e@Cm2UX;?zu2(2oylW6> zsujh12ig>ir&|@90vc=`Ww3w=8y2gzWat3XDF~8NU5^;mdtuGPa-!6y=9~~S@Q^UC zPjIt?vPfz>CXAyb&;NbSqI4{vZg0B1gqj|TLjIIdf&=Kz{wY| zg%l4#hq;{;C)Eo0O1@8_GOD%ou6x|$q{sc}-*?&Lw)49Q(+_#*c3aV1PwskA+0sru zrDmFT+6ve7} zU(h+Jz2|xK#m>IcnUhie*{Q2UAAHWT9Qi z1~~P!rYac*WC!a~&DV}WVWe$%T=ZOMGTn-e9mD z0uT$`T62R4ytS*=yOj!-DI}eixv`yM8{q|XKVG^ygcTTHe8HUC?o)ri= z8LOq_&Fg4}o@#FBsb;-=13l%b&pAr%MLlI&-@8#%bk6LRFqmV_rR%*khgZ6vori%P zMk~6%YfX{>Lscfi6+8Fi7yu+6@1NF!%vX%e{y zAckG3Acfs5zhedW<+T!&hAII_jkUwgBFs6MQVa=i2oeik*?2`hL43h}#$$uYal?Wx zeVEsbBi5LW4I$4C2 zNS))HO^}?!{#KtcbhRA66Zmq56wS$%{dB?c;)r=uEdSY&Jv zNn{F8BN_o=#K~-f)8d7Z*q&A)k!d=Q8VB=wNZ(%LmtB!ue10O5Yc<_WMow~_%QJ)b zBd2vOUUq&^=B5D@7KB4>0!qyt3GPw>W2>A28N#XY;mnT<&h=MQFqWi`sY z@zTc>WL&S)(jGFZ&$f6o%97XHbObtGCJk9k)9cH%+Zl|$nc+)oZ{?d;%PJA%vu~v;8`-irca15NY?}OD7RqXT%w)3={N<&DDkE$kX+Aumar-A~)*O7Xfb!%sHgM z_bdwiO{06$%8yA;2jva_1d{RxlgdR$$L4@fZt24~VN z8Z(Xab~Fc%3Hdlmw!Mg2<)Wjc0@%qcJBA6i>>Fuj=mlCCL0pf~19p7a)?OV^s;|-3 zs{Fcszj=nS{Ib5k*}QQ1g{xh4L0{l=+=4+e6+HGx`tjwi)c@GoAgt>S(UBu*S6yOK zpw29uHAUNn)?6hKPW357l1Pt9J_b{SFX3`cS<9TrN?Z~1W?+WJ60DUnD>p&2G{-yU#^aq*9NQwWb~(nFT3X`!#pC)6unot~x~6ps zC$J8!IUxo75VDHvk8DK1ksCJm8y@}mOsRmb&j-U6V#OPr0^=vd z*iqXtEcw4G?UNXkt+9Ao)cal0gb|ElBXX|pX_Rs{bZag?&M{!`_#o_D;-)X?t%WGd2(fZas z$)P-oQ4h(*fiJ!~2{;4E8>Nd=yauFZkJ^t^<+HIUD$ znHQr}dBX-q7y?ttb9I8*L2)p1tN}1feyHtKneBW8uslIzun3S|0C51$FU>{LNS5VG z2SIRj0bL_u1Ll@2U9V`isIvqA-wunz|4v`l%55i7CMYlM2^z2 z>`mZTcRFs|M1VDgARb_fKtc-;R9?(P!3?6Ai690O&)ks-60jVpRdJJ}CVs#Nnl{{p*nH9@Ks=Z>s++R{#0A zwiSBAEUFzNwCj{JnT<0eF9jR_35we>l+^BnP~dcY5>q6C+#9Eq%F%@$9BgG0BaRkLzLS+vp_>UXaYNO;JxGugOJ+dlgxY1=The7Xt zm{QQiiitUSs!7FM&esDHhN>do1rKW}XL2n?MRP6agK{nCgfg`c0mtc*DlDqfk11L& zeJ%bqwnw!X?u>QW#@^3j^i^3J$Sf8E2nFpE=&Lu|jt_jGFSaUJ-MPeyvJr*^w0e>E zbCF>?Oe(Y4B#=w%c>UjUs_2WoOwVSgDq}-QKzlmXk0Qva%Aio%Uj>=_7&z4=+;e&!PBFvati47mY)|sysgY|i9<%k|ZR`IW4AxLe@&{5zZfzrdrtJ7A=wKil z4ooCodZGC;Cf$3`^trDB7Rw0ERtu{rGZ7v8I$VEZsN9J!p(appU1{5fc9bX5%|Uan zO)qb<#^&NUU1LzE1z=k_44OBq(iZ9Xnsd|UMv+F#V6mwOU%v9)?ZgUnGM#$qnRpdO zntQ^;AZZ)T85{~ViXNmi8-pbHm`+85q~=PHgqjgaN~5b6!3vT=s=SR{%}bN93lc#x zYt)&{=~-nQsZMPex=$Oq_a#xoXJT|u>UcyHrCEo7 zX`j?N^68fJ4q4MZ82UJ8XbFHE(m)`58x6E`^#cX0-9k{z^W zCiH|xnVAf}-+zI}RWgrq+{$LHjj^^T9X@tc>T|`jFpZV*R(+27!pxiXASxs&5GTD# zQ2GgU1wQHFj2cCrJbT@fajl-G>v6Ct*^4+dolB~F4b|BfQFOivh45m|O^d5?TV6c! zi*Zo|-}obT<=f_CgCKnfb_`!lK zoJiOp4w`c~ImyS&?T|!Pxw&U;dM;Xwn<~8$xgZT`Ib3R&Q8jSUDb)QE{(cD?Q=d9z zWR1`#yHx(5T={CfWHTDeJaogWVRJPCW+z+%(;U;K@@0c^%HmiU!H}b`xE9LfVnD-f zp|!6nUS+v55Q9ywfZ=pA9m_hhY(d;GRTpI+wrP!{*+v}8q$tAZtBU*z9bb#{w&V^u zD7+kJHe9_^i+aL?1uImXoQdG8T=s`CoLqv4p%6#*vI2#97#Bn3t|$)Ynqi>8cpo8U zNiLim&ZVVO>HE$NU}2$**y9{RLyY7h9^*27tkUotzQR;VT@AC91_)b$uoVbffxu7i zIG5tr<@^$KI2V}oZ>*=!LDrmOP~e9F*kx2TXAAlBeR{bM)qYCXd#Ls^x{=x=bg)|e zb8#cJN5%DPzo6S*`ym{zUB}f?DaE_ZAlLjB9_t6L)L1$ZBxIcv6WfIBN~LktBNr5# zU0LKzd#+w0z{lIJROtMqt5-RrSmo4SL6obUvC@yoS*J=`d4#6E$~gzj=m9g@!Sx3* zo_Z^4qk+58dW91=sOX~Dre zmDWIdV!1Zn94eU5Be7iTQ0>RWF=;W*5BT1p;~XS$7BY^FhA-@5n(@)jvm4RM!t|0S z5%Tp+FaR+X_d5tMC!wSzNQ^uj8fQDtUsfBHa0BzHvQRHYmG^L=;UBK@zABmBsB__c zT;@P#5e*f?)@LQ1?aoR%Tc4Kn&X-)$XG2Z@4YleTz=uIhfyV5K{1)JFV~jr5$}2g)##P}n*xqGKg3V!NLQFsWe5F` zsVU3v2Y?%RJ$lQ9Ev6l>z1&g3tpYfj6G62`o{wPbQK)VRW-#!=%4QTLz_gtzxTvxy z^z$BzHaK}7_=uVM3z=qdDJJJHXo8%NH<$ANh52|A^KM@aqQmS*wW^kwoG}Q9{1)eRMir`V6|E9Y>9uz8yIX{EW&i zj?rneP9pH6aB*1*4!k&r!^}61EdPPRwuTCu97?pHwD{SVMrqM??WllZDu*}=7Ap6g z2HeOa{Qlau1;o&AQUP&NBL((h`L$U`8n_erLL~>ygXtEo$_{1@Xzmce>@j8~?PJvB z>acGuteln&o9w%;Ec<3dgH*?08b3tTUr(jQqQpA%GDZ;VKrII?uv-keDm@q?P6doZ z!373hI0m2uJz;!7dUKG9YgNaJzfK~jP_HRlFc!Q;pLphQfYA@a;=?3Cvu~Dmevm&& zWWTM7`_|($$`QBaz~!jO1$IlO8DkABZJ6v)u5I%_c$fK4UbH98-`YMWgOnu!dl;mF zP76M9Ql;;K7xBj6m5J<&U&fL)gQ_Og?YN~TsnlhFSK831l!KJRUhR}k$Uu6xUC1%zTsKt2f%dQ~+ z!hf2eKP3^$7ubl1ia_ zz2=wb^?uCw=%DXg>O|Aqy)Ag))MlDPdBD@`&q&#)~H-15xU zt^bR(X3}jqq}w(J#7_Cv>~|1dS*Vt8&G?4J!fcH|W3g~}iVr?UAcFZ`$WtdG-MQ?y zo$9X{QEYs_l$537s5uwNAoKl_Q@9(eVf`-7MrCThk|71 z2IK4{J~P4+w&1=MxZIxPOZ{6aU%u_paok#i7?ZEY_Il?hyh&fN;a>Z~yP5aMp_t2> z4==ph?@5_!iES@7Iayhp8hs0JC1a=Xt_I2At*;)z7-s(lFJxQ+!XXRjiup~?x%C_} z$=tK4(t8mBj3XC#0PAQj7)M}cK-M3DSp~K5Uohk7?Rz|>j)M6%%pj1SfVm8l@dJ@Y ziRNTjn*H``0Gn|%)?7LYp;7Sf*T}0+5HPjThdQ+v4{&DfK~9qn2SzpuwHSVw2nRg~ z1^x!S)E-A_SXylz>NRD=mzB9@Q>{#QUH|E+_~>*NR?T zW<$p7?v6ae{RxxP`$0WDqVFKhlbL2#$S5t6^hwM1*n%(D_JA$IJ*n0maz%e|gA)yp zBgfuhAKwk0YwH2uS5GcXJZe@?EHiG4fN(#TAKK6D;EFCKqcl!Woi!^Aso4Zsu@@lp zg{|0J$MD)bq;TuSLl@P40}60{RS0<+qPJs0eu>cCC#0_`DeneHb8W+*24D7+H8EY9 zn6*14=8PAKm|oDbRn=+f*0el=_PJxmd>x@L24l3S8LkK;9bu~e$a98}*3n!#p2SU- zJARCz8(~HoVQx!vX_l0M8Z}nA4T>!lv*#4p4zbT*lh9F0zk^<~D^$dAqWE1%qXj6J z-$OV`Z8SEud+iCzlBj>thuGK5rG!e{81^opV@CWd3j8gEcPQ}dbixw;!f3K>1s==r zLP=z&l>8Yg`o*Z&sS=+{Xlk&VyA!?)zev)irrs1r;u6_-6XKRPjvhUH_Uy8gCTex3eGQB81$# zm*JhY)+aldM3zw;4bY9t^`n)yp?z^DiB#ZYTmC8@$9tYS9a1q*k4YGoYX+zI4JZa| zmQ%Vxhbyyw(HSx0xo7beTXRG9*#D!z?7dUPB{m+%3egQ?e}Hccw@|Q)V(gfFmaB?; znc{0S8;VciF@g3~S8OmPTk%+f$DN`3`7!*$v;B$=*J-i))-x)spYvtXq)K~5^>-%{ ztaoy;4@V-AmZl{Nj$=9GXp;m-JUCV)$?;qRHVpNUPW#0}V^>V{JsSZGRmwcs^@H<3;H~F2$9Vf$3S?PIEbv?TB`65&4c!alH zSEqq2{GxEYJaG%A)VRN$cDB5p4%UpYimi_lVmZbP3)+IV{(sRCGZPVA5A;i8a*xw* zEwM~yb0*zd>Oo$3nZW5clm;hsnN<*(V9gNUDNe^aD$l3eOCQAh;UI!)#e7$v$0Vi? zR;0n&R(x}bpTgA%dEtaW9hSGyNrY(pVc>CIZH9U#9bC6UqJrq=EV700r<;ola1O9e z9nSe-osH=TH3?Q|Yw1)EOg7XuXAucgbY8x~RKHx0?M-YyHW*!}I>hCmS+g0x9t_T8 zGq?OhM4Q5`cj(T01xnMMZ0dZ^|2^yVOX z9#4U`i!ZzqSh^`~MXzRy?BgKu_xWDJk4|CP0bgU`v}hDZD`PlFidCzYAUe+rT8d5( z#eqnyfh563shmDu;;V=1EZo^RmzymQCIg>qC;`s>+tMvmMf|EzcDN6e2)Do`9N3(| z#VCyE6noLCb-)C!B4AA-3#K69U%@onh(k+D0-s*Bl=F8(d>dICIan;cHOm?&USB$~ z8E%N5h$&4+egcPCuQ4@=W`q;vX>uuutTJFWh_2d<)n2e;u<&`bYu*qL5PJvvFH+Ai??v5v&b&>a{Cg7K-Kmwn&{ZX-#enzhIc z=lPCE)+9zBdxnDL`l&(5%Aw|AXpdO2LoN}O+DIou0ZcA7q$NK-(a?C`QCQL+v{!Z_ z)qxJ&M9FPl?h)bFkL8OU`u`b=Zb9>YxWRLQ+)VOpx)u7p75fq?wGOO@tg*XH7jQlu zy=)a9N}`QzcHB%ZolCd3N4yqHlj)0JQHEXkAUgryjGyuA5N)a@GP2$dMO1ONpL=$0 z5(nY6LPT`|30ohLk?&e0T#sUYjEj9kO5vAy3?2DAz^SA}GOnCU9>aaY-WWP-uf=b{ z-o|#w>QA*y$@x`kGOh8E&X}1XsA89&`@8(;1?Y>94A}rpUkP7hC?`x&#Pu>`EhM6q zL_}L6+b1H^63I;TH*2b;DzJ8~8L@O5a_+Rbs^TGFozyWnhCVGm@~{mfMN_Da$LpsP zgqvPQe%_3~8IT9z;3Mjlr@-Az_h!(Y0Lk}6GGn+s#kclsbMx2C)cW9s3z)IRNAU|CDLc)o7cFaJCOtK)D5L- z!ZWV@jfpO$XJpjYBh@XJrL;Pg~@DR=uz(f4I3E-i> zeF%@67s3k-O#DY-Z2DN!k%u_t5Zqy4;@=9h1cvk+3d4u^R|=%zl7Wf;9hg&Lh|e>j ze2BkVAPpA`O#F|A{E5eh?)3s`_&5U-|IaY5hGF^~&hQ~V`OSxLJIomdehjXqzX+HQ zaV`@`!v`9e>HjN?rN23ZvoZwlZD8WRFXSJl=k+1~qeA$<0c`0f9en7XBantMUy_IE zza55UV|iH)KE%IDAPpa8VB-G>#>!hZgmYmC-p|0q|7^%V6@qUJ!6zD+`2PcA=|@|a zhx9N{K7^;iSpMG&*z$iCU_Qhd5lF-H4b1ev0%Q4~4B-ri;Jpk?{C9=?F|3h?>0c9q z7a5rNzk;#!lc#)$zf>R%cNv)Y6EK$lM}~0N-|=DG0fBUT{61jvf@!CXKXKNEV9q)D zF#S&oq|*tv_cw?9k2f&!{|m;_kN#F3rVoWxhckd4fT2Gh%l`%XRs3HYf?r`^rvGm+ zmj66o&4=lnFOY_38<_YX4Ecxk$s0oc$As{o1Z?SNd_GM7H3Dgvb3r}~-vnd%zk;54 zh(9KfhF@i1;{O!J^1nNTb8!g9K8!rX|Ga^jCbt#%5WZO;4WDda;{P3H8H~sdIz~Rk zC(rm04q&YOUkljM6W0Hi!k-WE4-iO~_n!e<{)FXWxxpd+%n<%PA%8=Tq`5xie?$oX zmw;{h;rbd3;dh4cHv+cu6W0H)3*jFU!hZ-bc|rb=4}3`T8i6#tuYt+WkB9vE&WHGK z5=g^~4b1TWgt7E{Asq6X593aUAr4{QvtsEF>;KCU#)miu38eY|4ZxQEu>L>K;1Itr zg#Uq%f4Dtf7xF(kg#SChmVTzihwixoX}HJ0EbkpKR{mKIKE$sHq~TW@nD{@2ISq#V z59|Mn@Xm*E`vubF{hWd6A1?1rA^(#?_32goVcOF0XMHfu2VpG#X94Cz|51T7 zyuiSu|6gD%|HJx!MF`)fL;UxI{M`_IZ3sTnz{GzX#?mis81JO#Y#2U-t==I1TVX8! zZ92rM!tfz%+XeA|2xIwAKJX#V1p;Z<$|3PT9r6#C_lA)F2?i$qUtui$VR<_%gwJ|^ z0EYSUvHZ7urvDWZqHzv3Fw_5c7|Z{#{$CZs-zS9s;gElrpKlEL9~;8|BVbEE^W#H$ zh6K{E)sqb03}gAfB7}2w2tM4v#D4_F^551Y)2|pD!uuPT_+Je9hs%3Q$p4fO{uaQ? zV5F=@;WAB@i4Wm67}8956vonH%SHc7VE7Q8Cy;KBUk1#yn0{FQFT*<@;^ztAA^qS zaKXUD|5(VMczozyFOY_hGcfW00%Pe9>wof_597AOSpD-DU`xMkcf`32h7aKb1=9Td zI$%qGSRbx5IKp?i)%8lGWbmiKlTmW}eja_}Mk zRRU@FFas0+KVYo9Q4jDT{)GZ*cs~OZ|DQtssStc)2tLuk#D50H((i_Fm?t0RH4Vn{ z|6ahB|FZz|AO*# z{~NHSKdk@H4B=-0KLEpg`B?rh(68eE+7SE-1CyR_!C3x>_2Ky;{MjM=4~6{0`s58E z|6@YEouK7<39GYot!TuV<_|6dA!KEyvjAgzBM1Z?>emWSmA zhxju?`1gkV4LOqL`jGz-A^gVx+w{ZrH5kJ04B@{8u$7;%{(oHv|Bw*=_W+X@v?t=^t*7*Mz*u<;>;H>F`28XL`$PWW^4=8kKPiO&EMQB&8^Q_GmWIETf66n%C=at>_>lfl zfi%3pz@-0cFqZ#e{l6lFZ_^?Edqe(i2);H1A8BCXKLKOuCrx}v&)EWLxZA+Qe;bVD zzfFhuRf9wLPy-YHVHnGQ@_`R=E)Yn=MFSK6Ga>(Qd2a~$pAf=-8nC55EN^Fp@Uws) zfMLFTEdMQ^>3@ZUXq;5A%S5o0c`wN0N2=*N5n*{;$)I$pGbn>9Bt5^rQ2z z^e=~ho&IHw^r@fg^rJAA{sZ7&r+;39e(Ik({TPf|`o9eS2VkUJ%Vdv9*8cepGK4PH zE6dM5lkJFUu|8QBY=>+Ul!qM5ESMq;+ryzSN5Zh~R=|wHTnlqA%!4qG!LSe6lZWVG zLq3O%i}$c0pTdUa3LCu2eDM+jc$hZRV;YP{T-FWC&vLWOtizcwN*x z2{23(5@|vrO-Q5(jBElEo51%b$ZQkpy(tfa`e|ASvrKLCAc;CHmL5x!rOVclttZmS zy0Z0U>&(_0>kcG{VOeNg>_gh|Se`X5TZ4Vyxe1$f`i2m0NamIqZ+sPOytzM_%Ng%m z>fYS@t$W{E_vUVJuGe61sC#phw(h;L?#*r6Ip4tHdfC%#ugP|1drdYn+iS9i*~ z%k~=gEzPF_b5I_hH=_&wVXrh#cmDJ-9A@_fc6wyDzkF*kDxS`*=AabM&VLMyhTL+G zHIE25V6hjR>dCNhYDC~u0OJI^z^?|3V?hF+2AEfnBr`ZA(B@V*Kzi`;^qu&;mmdtp z#tsL9-tFh_@H~PGNj3t-txmw6=)ethnLG6h@FVh75k4Cx3eH2NeIJJfh_q2Gouoat z#Pm`)fPif9!^Zfq(BKC6JqrHb)67XZJH^W^b+;S=HuYUfJ6m48o-WSo1U|odW1=y9 zCltqZXK_hzV>;pX$&b?Fqy;`$#_y!p?f`vJY()!tH-g_mf)n^kN$Au_^s^_UB4b%n zBk2!x<3f!fsgEB>3X#%$R2PpH@vMcfKaIB3ZsbWGlJy(w6Q+Mq({F?Di}t1p$g}cl z@K$QX+fJMyiBITo;s=z-k0cFLNf+2zdJBj_E$F)3nD&d8)a!(|y`f_8x%;*ZJ|2hD zbopb3ZRHTc|(oT-154{i*c17fw@ z`)Up3_rRUY@2OyaYC3Mp$<$Cf&z1V9Q3&x9C5x3G$FHW7(I{Ad(UcbTN?aa@ib<>> z7DwqfyVcv^9natwzHzbvF)75*lsLW>$FE^Y8Xv0jY&)q0k&gK|?1Gbga@Y#VZw_J* zb`c*`8IuPGHW|6Y$0BusBYo42z*%t{tcj?(LM^US5(3uq8Z|Zn<9&8>vDx+Gl~wHC z_=~{!p$9o6#uOh%?xxV$30xM$_Lns+RWkuJf()`Fh)ryE{j5&Npib~+A!*lr(y%Ed zG2t#)27c`z2nWBU%))(qGRR-9r^xE^8#dqikn!+teW-wuLLysUwMlbbqGZc~zq&6S zzcYvVG|yMg!^yy;WRsXY#ugko2E_A z#^)H|`HTa0l>hGflRnbMF$kZwV48|W<32u8_fl@N)6!&S08RK|axW4=m*z+D#LN>n zPh!fGobsf0@igz^X?dPc>+^hsGt<&IvDe-{9gqG+jZ7wMo{lL`=adIOrLohedl%1) z=lS$J&j$lz{4l+bdXL8wiDZ)1$tq*DkhN{*!B?yDOfyf~Jmg#WArHfk<)?KmU#&ZZ zz1zG_VfQw#J7qoscg23T4Yq09UaT&#ZI@&B1PsUNTrld;dv^oMlfO6V zkhj%C>aze7^7eX251=|dx7WS#OCAk+?x=g`0L|&ula4uaoWj|<%I3^PKiOws_B-S& zScdt8i*v^-Wv0RT3FrCP7YO+KduDvcuh%#PI}%S2AA8F~o8;p;sHrn`YS_c`(95qk{tRN(u3f8(3jqgHqIM%1? z;n*k8;kImu&)>{B9WI|->o}(|x%Bu#Va)guaPlGF?}0fV=5d$|%v)j3g!v)ND_}ki^IDj{!nDBL40AHfzr)Oh`7q4IFn@&U zh1m@A8kk35UIp_-m@$|wFikM)VUB?LGR#bvcfu@(`2|b>vjOH*nD4?I0P``JOJV*3 z6Nh;d%wm|Y!|V(5ewZ~dzlG_9xgBN@=09K#f%zwx*TFmk6M?x7=4hC&!t}ws8|FNi zU&Bm?xeewFm><9#1oJ7F%VGW-rWxiYn3G_>1=A1nA()F`{s7YhgFzfV%+hC*Xbp?kL<*xKF`-3T_f^67CIf zZ-9FO+!Nq_6Ye+R7U34*-Us(SxEH{^0PgSM{vK{O+-|ttKx8d#&cYnAaf%_4-6}T0+e}elbxH-5vxOc(53+@oyA-F$>`*XO5!#y1Cm*9R0 z?$vOwhPxH+R=6BtE`-U$EQ4u-c{R*Dm`h+{Fvr0ZU{=F)z?5N1FjvBOFh{}c4YLxa z9p-eH17R+MagoBcFh{~X2r~=jUYHdykHK)X-X>BULD~_d7eN{k==unBPXziU0v!^8 zo`^sfM9|(NXwwn2+X&ib1nmzuIl;tXI$`)X9i|zk2gZd-!z5w4VWKcu7#HhPoM-XL zFJ$j_g!FswfL7F<=VCy)!;JT)y7%!^n_~f3!lDM+Pv~EROQGD6$FOy-y znfbq9%VnI{`HxNq#EPg7Yz8n;pOGniL(ePc@HH~|bw;EfI_4D87(JkxftBBkSzwDd z`b$Kuoq;q(KJ<60m<4iumA=(;VTH#dvr*%iLo)nK1fkIQ{3JPY0=}Rb#W{q;Ivvlg zF(MWpc$W;vIFPP-nky!y>B?D{-AJ=KjChb*$q*wKa|w%^2l2{&36mdr6GB|M@IwOh z)gOn0H2Y(@ESFm&5r)1D=tB~9`p!m>TufMBcW#m&m)-`4-})MyZj8Z>vb-_O0igxu z^7lTOB`C+IOYpj-x!9Dz7sawD@2rB5OY7X}x9B}Ow2g`O2_~`Kd z9L@nkyq8~BpUV5{c}#sFQVP+}Ilu6@eh&l zgCl!lkcm3K&jG!9jE(Z7jo?WoXa@HiFXHK6c%6!O8A1}pNM@~+*yhG@{C=Qw+OBzq z7Ew9Ume9txF4N)q)NaTq)7eLg4E%1y!yJP9Z-E+xbR@90h0n-F{}qic=|l^EWxMq& zM%byPTuo0U6HMJ;nV0bn$Ya%*9@8e z19#{2Va(QT>COFOjNNrz zVRMR7ggdw?IZj?J#JLf+d;FN_EU>n=l5nPWzIHC8V^w5E6c}!?Vq@aeW;tE2HYBfJ z?KN~GwPkQxy!_p0Uh=genm2Ch9?gTI8flXs_GCG@vS#FmNl@7(Z( z4Ff9*{4AE0p?~rj!Ex}P9>oqFfZX7l99hl|<$e@q9Y228zL65TL0rT2D|oxLON9m& z(la+Y5RS-YRaite#V!1rEW5mpo6)}!VVJ{m+`LBrf<@smU{d{PzOnzRG=bt`Fv$yB zt$s4PpC1MDq0d3={*I0s9l0Gu7b7Eg!5MisEFG~b*M$tBRoNa$WJ>sp-;UQb7}P6} z>!8*k#%B~hma5S2!s8QI?0t%KQ1}+aG!dGjS)sVS3rvxwM203Js|UV^@rLw+7zaaK z51T57X4mfz5Z-zXAtt>C+8s#CKhA5kU-G(3vl-o@e$yPz&h@#df&vKzYfP8|irMt-}K`q{QhFgi1Z#?_II^su_-c2a>x1m!xh zJ*q*We7EaRYT|XgA3%4uA*s+GxpPBym0_PP#PJ}mt~;?oPKk^cP6Hz|T~_=gJb<`Q zzj$a3eonAH8}gPLX^QqTBcl4I$US1QAqLJ&wL{p*Q5i zpV!o745uCVGBChKCH8*JUh&>)WO1V2yh#CWYS1EfR=t_4BJOe1`E5%`5V?7cx$^;J z6_z1Z8Xw`;s|0)ekuL3xW?tup)C4YS2<)zP@5t9cND!CIgV#;(kNiM*k*f*D~s#0KBvS60HSdF&|6IO3W3&1)*>;T<>P;6w%P zk?<5EVm%P_WD@vA_gNUFVEVvfM>A1i9|`RG&y;XGJeI+)d}EG<2`OuuUdfSD>NG|( z8*;e?)1ui8`5QpUf>^X;1MXl%?_p5aH&C^_H9KR-1V<~T#o`wh&PRT=waDI&VS3-W zp=$`2B(XHi=xoEQXr@CGCPjYxXCId=o5gBtk=49Q5VF6mdQ}`oEz5p~iRoW;G{t+0( z&wM?>-V@m{E$B)a_AF?&($yID5chuII#rHPF`X1`iF9;l&)`i6cI)HDjN|gHAG>(Qnj+WMWr^ zqb>Z*Td1TnN4|-YZd#5w^#Q-H2mHRdOGU2(p}BE>Ac~w# zt1*ArHvGa}golg!Ax!q(Hj$i~M+ei7hx)&>2Xn;!rdg{tqZoj`mysa!wfLq+X_ zS9C;eJUxeUMWc3Jj&98KIjyQKXXm}1%vDh)>>1+Bij#3dX>e|jSyW?g-$=t%ZRtiD zw<7H$n1(D~iRw(q)?iW=5K_v;@h1$rVtyuWC^Y19A|*AOhC9p4X@+WT=ViW zxZv?5x`kq}6IVEa;;5gAZHHpJF3R3hD5e-mUm62ZXoXw}iOL#D^CQ#bBqLE9wGlV8 zWmNG9OWQPc(vYUj-erx1C>K{jOhx3b!LNDM@PdnWYGZUWdXii~iBRhp9q6^H8eDh< zJ4biXs_>5*?nN{6q)F-bD$-Ao9Zsk2;dh}WXc?Z4|0f|_i9Mx)hqJ!MZdmB+fha-0qM5e}-zG!OP z%DWjABTVL@l?}?kG(u~CyU4%tew#hxHP`u+EyU{_)M--qHIH2_KOq#x-6q^?B*F0R zsqsBs6`^E=_8s9x8p#1KBK!W6c`UNDy20Sl6)0PcwdhD)x|MNwpiacgsY)vld2*^; zC#qZ<<^|V-O!`I;Y#lz+$ik%iW*ZT4SXQo??lNw>kY-k;8}VFS_l-O;0Z5Ka&9ibH zi=x|yUU%GOewtRVa(#nX(#mjoVix{qUj#1kUb#`%|$~eoU4W^a%<0eOa>2WJeGs(2U|7lZY8fQRZ_I zxi81)4URPve#DNIoQP#I)Cg~Qdo73{4zi%56RTW}>O}g$$@Awi*5D)$j0%g@!y z?YqccPweUMB4i1>4kRjg`u=;oac_d<6t_MWN)?NWV|?Vw zSu>-1+6(Os#l(5z$B^EUY%^vWAX|~ikq0T1eV}Wd%HvPz0fm4`C$qN3yfJ==>iL^= zy%-DhC%k%RjS>(kh7!;%;--Cs6|%^l1Et-M$y>l>i?ja=jxJl{9Mq(;d4){4Y;H(r zR$otgz2$N#?$D#RxxFiwYYveI=m@w6HV8QTOB!;RMR`Exc z$?#mq%GmN|R6JjLhaJf={^)JXYxLlc-{>GsK?rr_R8*W@#*fSJl1_5;dc((v;iJ}B zo>~T)kJh@*kb|}vBF0^wm_m%dBVt0RhL{Gb%ynK$I@_pa3NGWf4VsA+$$ zoS!^a=a+XJM=ed{+ZK9FNk2N2@;ioc3++&I9-D7XF?>aXxDVCWX!N&O$4Q+DUv4@H zLxLJ56F=UqqKV!Vq{Pn->7gEW^jh%-uB->fa@;+M?YZpA1XgUagAZ{n#{tT>>-B+` zELh9rqJ?fW1i#P)8<(y6C@wG-?*5xWw4f2?8VALgAU(! zqqi+jc-fV0j{K;#(WQw0ux~B{=Qmb)q#^wl+DqX2j_3Ke6?#a7h;%N$#eqc|xq*w4Jzgt~13tWp8JFndR_4Zs zNX$s$KkE3=LN5qVPSn?chiOpV7k9OqQVM$9@nb@73IQv5iED@!r+9EZk!|8dC&g=g z+QaG8t+Dv>loLB&6hTqpBx$BFlQbzcXOWZ7U;EiVxP`rp#~sde!LvV*gPlXRH|!^} z+)iPJ;LVw>4BnjMo$S~f5ahNO_BCl7?|4(a^tb~0T=o+2Q!{mRE|inyGE6#&8gEpz zzSc7lnVWJ<sTngeQHcuf>MW#fcsLWPa261< z8o`1E2^IF54&X@0XFX>fY*aVT{GP6TLMVgDXhgGI^t&5f!#ziq7ej&iI<4#)QU7DO z$kbi@YKC;3G1K|6-zr+#c?d|?VI94`YpPSOpDwUGGi7FIWg)m8=2_IHYev`Gi&I}i z;i9>uas=xRb)wIQKp}Jf7UC8NMC->Qm0({adB!z{$=v3%-TJhLDyF)qEWNVNJ@F>_ zPFa_&P#{50RjO4^&q&7NJ7+dzZk+9ga=vKE@r#<+Q{kaJymtQFd2e+60S^f=ck~C+zih(Gp)iIAx1@R=;g!ILnh!Y?2=X$K2H&P>?z1wL5p#bPfJ+joDD&>{C^tV2aS z!o%Jo&sWby7%LiM3e&_MiJc$w)y5Y3+$HusY2sYpNuN8rZ|L^br^WuZ*uN7yGK2oT zVjnE_${DB6@YS0Iey7+Ei2bt}OvmqeYR1*7tB0lAw}+H07JF3>LoXEgjRM~;_NT=D zzSzGNySJB^ePSQfd$Q}RMPd)ZC#Obxnescu=aXW8N9Aw7<;A4u5Oc~=YG{wQzX;7kl}&&t~`)!h;gi_M_r zkGwS%VLeUE{WVi$gYtG5-@unOc$<#X z$)5v-Z8#Op91d^#ywG{AdHXVQ$IVvqwz%n^kwcrhTi%v5eMM4v58mSHjHa&%=Ev~X zj1$6IR{OA`zzk!>J3eMBZgAf z<;mR}nhtA9zSx&KEr2f=k<-w+Ns4 zSP*Sei^RUz-5>C^?gH4i2+r+dzh6S{7yD~se_!m!#r}i)3gAB@v6{U@0cXVS^%enM z;2jP7B5yJ5t357oZuFS`?cOP{v;M;vQg8I1RA-Lg;hzHgF0tPy_Q%A&U+k}n{qJHw zEcRIu;{ROW--`Vgv7Z)OMH%`^!HEmpE_N?$SM3#DjH@Q*M#+IgqXlrXJ9anZq7Z8_ zq1wMm9TFqW$Hm@<(9^_bsTZiTWA`;JP}SH+n$8@57h;_`{&BItBKFtC{-M~v6#Fk? zZxK5YC;lwhEIZ*+{F_MU2(eEPdl0q_T^avALf492fqj6w3~>)o*T8O46Y(Fx=Uwri z!v47Ue^KnOi~W7Ee_~we52U6CmscF?-lsNVt-2P&x`$_;D1BlA0{3H=1;_aRD2#6`_E$kO>8g8 z99v;GsqW+xz~4)J_7{6V?Bm5=BKDBjYs9`hc{Jj_A^9-uJCe-nU1EP&>`y0u51$9c z{;t@MivMque}exXC55NOR;j1p>rE$3$Y&;`;THj zCHB)||6Od=#xiCByDBDds*U9h1fC)GOtJgK-e2qk+a3c42E<+{_{WI{p6?q}YqaK1J*^#6Cyt6=JUy`%x_S zuhVXIE%)y5-~a#G`yTK(t19nv-}xWX(3vJ}k*1wOf$*nk(k5*RRGKDf6Um>_Oq;d@ zr<3GOGTX^aIy31%ili3WvaoB>iWP7zf(jyTS=qG+E}+N);%609P(*lS{XpspiYp+> z_dDm_cV^P0e7euG&wk(Yq>%I8bN`%s?>Xn5d+wk29rXIoA%;_e487ABo&uQ9(*z3{ zn#S-nfoBRlPhhpcI)Rr6Tq&?!;97y*0(%8!03FIJr~Mc-cM9AC=){xn9<HhxAawnpDVo! z@MVcVUV0D0e=2Q4D$o9S|Ei4NwBi{bF%mwl?0kf)F&8V^Vl75^ZrPpil@${!F&0OJ;t_4etf< z)ii*3XHNg6_$1pUC--`qdL#V5ebZEA?tcRAo4ejWP2E5D3c%Oq_5i*ou=4jaS@^FR*U0*}@W4-r)SUv%%HAe}DQZvTDm-N5FV zv`5_guvWd;V9&U(2bM6{|3=z0y2fDtiL_~S)LO$H~Dn5tP9-}J++b`H&>J{uZ z!5#&67&*Ue(l&cKvFf@8y9rEli|6xrBk&M!CIGv}b2n~0Jj2^Fzz%qh;O)Ql7ijEr zo`1o+g3k)}nExxDhiEPxH`vz&)1R4t%>S5R<@34RWB#Yn+qqO>uonbtGT3XLZy~Ks zWAv8iajc!z8qDuKhPB@n2Aksj7Opzlg55at&n0(S6|_w-)`E6bL3?x9I&~g>GKXza z^XZNp7FSjDlwgkqntWMRL&pu)>DvJ;T*t|`!(sF~bG;8T$gRzDzrWXyy8nT#5 z7f5ddG2a2aty*WWA;G!@({fls59%~O^Q?~EG8pr-j*6>^k4Is)1%MWGXk&A>R$Ek@^gF7t)&Oh+upDKlFV{t)#~d_LA=wU~d`h*GOAMQx`Fn zz5aKQwu+uH7>|x-I<7I1W;6XUhpkf|q9W{F=@Gt3wb5xgEUs45#e!*RMyT6hEX@cV z&^bk#Yw3u=Sek38s+MU!CK6jm5reVB*3ovsw8YlYah)a->!J!iaDZO3#JcEWgR#zc z(RPiA#JcE9CXFT5MfVwuCDujrWryxDKTE8O>NF-JU_ISsFqYWmbg#i!Vpq_E24jhR zm}>B1E05Iu{(S`dhOJGO5z8+|-3DX%_0SQ6vHW`JU4yaw`l$ILE~iJ8O~ZoifgBE! zO;vb3LhM8_V@C|OSFq){MohGaZWio$gMGR99c9xfU#r31$=8aNH9$uN+e6<(+Ggrr z&S`t-sp5TjL;hWZ{iOI5YlwE$>$F#qbC^zTU~D)2uJ{n%nXD6R5B;e)WR1|E!F*Fr zv$j!$w=6+3IOQPT>VMW?r%#za??_oMl}}Pp#6}MaX#-t;ewzmunHMl((FK ztr6^~!Mdl+x2~e@59zdlDTis4zHG4VQ);Z;batywy9PNwO05R_B(Q7g);3PtO`iwN z{q$~!&Ur7&?Wa3BHTDf)*HPhax2j z>t^$@);;v$lB{(r?b@WNBuaK#pP^@M#0QBCKfh_+O{0UHa}RCy ze8>6<9XHsvQ!fIxf2U5n`qYE;k962zA1*lr?3lr>Idvbtr184Jx;z(I|3vTZ;&Qsa zuTu9_h1iH-dUSl1_GygzrvB3UDm`wnZKwX$x}RqLt*$*j^=<0`8og04|NT=R!W;aD z4ECd`hk<=gFy`4o>@(h%!wv&GrgNfy`|xFoijQlWEU|A>x51W{gk0aI=M6@|oz}n6 z<2UP^EV0LF_!f;#3GT!9F^*xQl6iK`sUL7XL9Yv@d;28K`V6P-rvC_D;(C&fd`{Yz4efOOg61(GFADYv zx+`?O>s6ZhP0qQ8o(>&!{feG_RAVmydyQ8A8)KiKS3@_uj??P~`(5aE*Kerhe{q_w z;SC!8E@QfeH|Vl4Y27*O7WD=V3U(9SJneSZZ)wzE_e{Ij^(MU{7;M(GtJPcN{~pu) z1bu7T1FpB}EWvbr?@*Osy1sYlfMBe<-*ml0N1w^J#Km@!So zrHTd9R9x!3Tw1$wsiiq=o${#W9JWdMRaXv+t5ei=!Swuhsybvap8rl&PwAX8|4miL z4aW1|RF!y^+oI>cpgLeMp8taCKEd?-7gVLsNluynLTa_ac>W8iK7;Z67gC2cCi7oN z{lKL0{1;Ns8;s|_kXrr|O_S%pkZRVL%zx9=sKI#to38d7jOV|Z>VUy`{yR-QE|{M2 zW~o^}Wtuk;&v@l(*kC;4%~lT@jAy(#%Ktp)+~a4@BdjhKjHU7)uCO{L*tP!dvWMs_ zbzHFB{$$x7U1zE7KjU({{n;|*K19m*oTfea3e{mS?rnwYG8p&vJT)lTZu)fDr*MhwErb12**<*DW$>4p3VV6yt7l#n zOk`B4-ZU7?s8W^wN~f`mDpifaSSpq3GJ~;HD%A#qu~aHmpJ2>guX};I&tTX2rnsxs zTLwGiD|0VWM_%I^Zlb$<JFM-9fd?qY@G6|RpS0+nT|(O^#sw##5Y66{b8`;dE? zI-0{)yFaL&&0$^cQax%g*NlDm=FPhX zE17W+Sk3F2%IPx_)+#k@Ft*7p>QTY=&;`i(AyxNV&bfy!obfoY7X{nv@0f9b+SFSH z>p=}|s`Pi7W_m`yyG>OY?8+Glce{GsVAs#cx>u{>H#N;eGj_Vys2aic(pP32qKJCM zVE4}$b$6-A?={W)XI$%EuU;4IM*7x_>)jjGrvKzL#tyhISGNkbo4$uucPsrpl-=}; z8J~1_t6hKKoV)4G8MnGWtnL(SFL`I4W^Gbmc#G4t)yTje9ex)(Y zc7SH*f-om>R$w73;nozi+WwB`LCUM zfJW5RcZ8<@mYMs2RT=E|nGXSLHrTy04+Dz`_Lx|yt?IbJ*b?nf^Zv+G9+UC6OEnsd z$KNis-e5fbcBv7KiH+Q)t}$sm8h5FO4aTE!m-?B(cr@-(|8B~$ow!Q<+F)!au2#Pn z>?QTk%!4?6lb=%Oj7@vY41fQnAbL5so#;j;_E z9Pgs>F`AB!uaf+QFlup)i>2%`No^3=CQ#Sgg|J0eNKC)LxWKf;Zv%AEMNXKwb-KM97ebHgv^1r+#<6C>XwDa=<`@tWDQ%8n{ zb^Uj=|G%&0#Z#HvUz8r{@LdSI=x#u_Tu@P@;~xrfPwzpzMfXXb2LQ*WeoIonEvbG` zR`kmt=VuCf6;Y|z)pN4ovy54yRTQnj) z%D2bDFM4y!IaN`Oz>6g3N{Md=#5WxQJv0cYjLz#e#6;&)68{RgialwBEz;a(sVUO& z8HwKt=%O8fZrTOtp=$xLiwuZ!Y2o=_n%_sP`F{Fo8JE@kyiw@rw&_;so@zemoIFx2 z`Vw-wh+F6uIv!~`zLJl4AAJ?jFZvdse@3_nr!IW+=w<1n)*oC>1%)a=x8(7dmK;TX ziyi=UiKe-U`|cs`yI1<|lV0P?e~7_%@udCZ`NN!XX#Ok0ida9DwAO+7Q2^Z&-FOr^ zEu6yTb3P$4TBD9h_$5G>$jD9FioSvvMZXugy_6|@6p+t4xOX=J;{5IS8zjDP{^dR@(mmDVJu0O%?34VPB_<`|trFfM+|X9{d}+f@N!4MNjuI~d zU&|^8>-<`F93DH{=40G+t<=J0wQY9^H78z6YPg!21P0BJc@;-v>NM&q??tfv*aD1Mo1uANqjxv^$_4u&&3-nRDVBnSeoo zb0y|nz-v9#0*fWSRNzweNcmw;y?UkJQ7|B4zOc?CgEG-8p6U z5l<` z%>ILC7To|kv*^(5hj4T5%YfIZ2WL2Y+xeb*(o*p*j2L zF12XR<=(s0GEWa++nhnbt~qz&9u#}Fk4S5S#J=kj68^qW*rGl=XQwwveBKchulG5V zlUJ@UN%$r8ojJQSPDf93kz9RdU=V$&c^o2A31MnZu{GFe<`hmdP>b*11 z!Fx6AZ`Vl98j)8GeP>QnU<>)?T^fi}a9%7>FVtApx2O$j;k=8i4Qe?c*Si%Icuf!_ z_VJfm6WZKvUO7SVkx^^$~H>bW+~e$W%s+LfX)pP^PtdqSm-<| zbRHKvPYIo4LgyKw^Q_Q$UP`?vbY6DNb@}NP*V%x_UFQS7j?aqw=}i~+?k%DGu23d7 z_s;ER4*T8A!(un{aH_i&`Agl*$(im85uWAd-i6)V_jzuX#d^0N@PM29d(h3iIwaI? zbu+IHyO~#aO6r#d9+5ov2|Ow}AC#OAOU_4y^5bsi>Qe%bxtX`mxS6-lO6|`Jd|9Zy zB6N-moi`=sEs5FW`3YLv=lMC{pyy@4qaJSIgC1_-!yfK0c`sCzIIHM6rIOC1k)lfM zZfrof6PjF!F9@$j_|0dTh>O)?)dm3UI+@Em07HDukZQTcWz3YWQuf+5s=1qh-X1ANm z-Y!t#o82ULiW~7f2lE$>%8Bnij3Rh0p1Tl_FYd_iAM;(tEbt5PoQCIoJTX%NaGr$6ZZ2>%AWdJWw zBgj7=5WH2}0ISswz=i5cz#4TGV6D0uc@_iW18bIxKH>SaM|q$0-tW64a0G_udNuPZ zq8rrV&*MdAb@&@Zf3M*F;2YGS8oB{tRDUz#+h3F4AHI1J<6VY0Dpe`L1*PM6bxJLAGA==v2ps1 z4mWi56liHN{z{;YA!y-T=-=7UoOAG3fxmO{cOL%E$KM6`n~%Rr{4Ky=75?z=;jU|x{FF5sX?#zOYQ(|Qzwl$S@u(nt-Hejcz zAvH9dwlkTPBgtMM$^Q5NwIrnhLLxH;LvL(EWbJe^mN41!b><@a>|8OY9+PHJL#IEI zwr%tcU}a(?GZ@)1Z0A}OPbFLJt#+a?0$oLq26hz22`%n?)An9_IE!M`IT%aZeQUGv z1h+%CHs4Iq*$uGt%FW_V*eY+I`fE>f^~idpo7leQ^j07_?}`j;x)j-x`Z2q+Gth zNfMwZmAz;@wRA*RtX;XXX-%}VWn)vcv1w)f+SUlIkcwBw;_1w4JKc~<+fGj!Qc&Su zmO`d-m7TQH@m^|;XR@2BDLR}=B`BJ(V_WTxVLM6oP&}K(YkL$;5k*2_lh5u5v;O-Y3uV8Z;&#u6fe)#+3(Mj_Yb2uCZwR+q{(Bgt%h$gbpC zyx5wR;YU}vMyKRvX- z&OE{?ZDS?E=_f>SE-f^X6Xz&EIaPB=^06uwbhjlL&&Fd3$agi=qod!kj2SY_63ehM zo{Zz8cTqvKu^EU3L=m9lBrB-V;=oVxs>ey3=IUnq_2ZmT@gaO*r3L6??$xhqe z?1a}q)10tw5BH(fP7Y)TC4O}(gZ9JbaHn&K6k|Fa>G(h#28l^_+F4WZVu#ru+#HRr zi1luUh*rk!L?2rLErk;}T)$w#E`8b~H-uto7}w>{{qt zwXjX}g8A3P7E_{D*xY!IlR?6P&du>*iK&MIx5oSJ-W|Qry-p~vSl%7U-a*)0o`rhz zwp`0n6P9*GVw-JZ649Q#agD~4Fc`)VM*GChVMH*;MebsDna_EQ(;_^IT9T4a!VqU} zf&euzH-~CI(%Pgm%1nAb!sN(T;gHXf<~lJBMSZw6PFUKBf!H1!vPB&*$TiYFk`TiS zBhU!(Mlh186($88iucEP&<{e->@*9tA%&rC>=TPpo2MM9Ty4>jWPE$ma0=`;HX>qg z&r%b5Cblu2N!8WWF71nD2DN;fr3&VRv^+<#3-d*48~YZ}Im%-gD>2MNv@zOoDL`jr zO;deaw5h!jNPAOLW3;iQAySaAW=+Q$ppEsB`e>6uFn5?R4{Hb_ug4DgaS3fuxpv#` zYvWl(d=O!Qwg8yB(^)V~W0KH`c?$jm*h!s<)HZ5sYKyiut!rwHw$-mMz?`|u*Z_8T zWZ*`d(&<#X4GIj0h*qy@>THVWzO}TsM9}a0NE5AC+quC6S0cKz*&yg|)5=!lXr#_a z#~N^DMQcaHr9kQ1q)0!l(9j5&1T zw0`x)vax8E-7TKlqW$cB(Kg+HZP6ZfG`C?Y&TOV_q8{d_U%YU6Y#BV;!vN2dJ<82GH8Wo0Czk?j9`ut zd!{iA6>U{B=n(kM;}wk<7QkK6fgy~hJ~*V9wRFQe`ukxnC=t)HQzNn#<|BgG+DR2A zQ))OXln@C|P=eBN%=l8qPW4D+Pn>BH9x&{27?S*S+8W!rqfK~O5EA9f`JNI)`{IlBP^=EUCHDGZIhqMI9bxFv&)dMba`bcR+=C@U@~nJjd%eR!bcc zwLl(}iVwhzLI`#{vBSxy*C94n!M++>*1VRYgIY%sV2vCZh5`-mFnJ|Ohoh+^NSZM& zlN?u+VH@F4=7@q4Y-0`v&U4ssu_k#7dE{VG*)=9fJXa!PG<99*C7!kF4a->g;9)Jv2Dd z4~qmHqcm7spQUZ=x#QV8X!maJPwFSkQNQS*aW82lkMBY0G;y0W zT*h#2697g#4dy`*bkcHdO_An~M#5ye3S4c7)CgQ8aG^jrPl&G~nPEGrp}DEy(i;81 zo285`)Q@URtMEYDJMd(0!0|@bHLdAv>1a22e|)=`1Tuj>TEPy3#GMZ5yir5kwA8A9;6dEq284)1Q{ z5XrYLWow|25!SQTk@V$D;^wd$g4npQ^_MHdsE8xg3k(xK|=X!W8xHWXM{ z)+hTM|ATqXLdl46$YV}=PIB1t%ljoP6J1J_Bd;bRY-}oF_JDA;Ho!`CHc>k(zwC!$ zD`R78%L+1{Ev?$vvYMhh39~2^a!6KTdIEKVvatyH=cJ$$5-dfEZYy;CWkUyhA(|FN zSM7`s=awRZL71{Y5u}ZGJt#VWT=_{=yRf|6if+TC>quXw+MNQ&R@sjM1@|_Y8iE%f z`(YyMjdnT}vC~7?CWB#wXUGf1C~E=uzmDB0#B=*}&FDyBWjkqXC92hFy<^@`go+;#6ug8s3T8@ zMKU-F)_B4!CsW?%FjF489!`*rw-e51G)@V7lNfEXC+zIzI7y)41Z9iHLGmt*@n*D3 z=B!+xY4F$J+7@g-N^A4|W=Tnu?1&hb2GgkCAaMeaWdl4#*#W?Gs1tMTWya)UI};=6 zVey7(?Jx@;8@tdHF=jG^WJ442+P~3$%|QP`_6pPS?NQcMIDGkt%$AWD)~2YW2f9Fg z+g7I%JD`Sa6!o@+2wgg2jHcAn%lnC%JdEi8qzRQeq2q;}UYo>}tOs*z9R8@Y;?M{W zlzd_7B=nMFK|`Lcxh+|q+Vhy%SSZ+XuEeZ?-Dhmt=e8~#f=n!5RF*fr#v*97!;lB> zuz4Tfj&&*oJOp#c79zhREW1;b(hDWMvSLqATV>3_#|%2mYig`J zwPi*o-gTGNFJxk;`bn=#%nAd!2wTZ!oxqfO&C*!}J7f=OUi9Vt_LM#e=ylxiwD!#h z@_sj4YWBNvg5>z!h${5E;cW2P&Nk}9l9YP-2>wepVI0IP&^{B^Zr}tC9~6|GQX5wR z28St`Ao$u_jS%5C;8daq{mrCC(!F-UoC(%IkxaZXp*^{|GbYC?juv2cmU#g@F?xX} zPtYJ@J3FR{@Q8R?PRUL_jyPB7odn|bA#Vs^@X=P@{m|o$Wj~xBX)>DNee$_WK~f|QUxMA;2})tfHIl}v#nC{g zo^|k+z?|_3JTZ<-G#%-*p=a^z4&FsgZ8NS`Vn-y6Q2{p}+61cONk-Up8y~Gt{zfoB zCu|5#3wqOWIb6$^ZD{R;WgAY!A+CI^XWO3BR3I?6qK1T>c8oNZi8)562S(VZ$RC5$n;6WU z9sO%!Sls8+nvz@N=~Pmj5Vn$LHJQRW7jN~n#jvHro0Ro^eV8G)@aYa_dD(x#v6g0G zo|@QMDcET1yc{EEzh;itzNO4NGE=cl%Pq?FVHY2bkenl}&Dd#P8wde2;2^wSsC)zL zDE93!RJjotTdQy|mdB(a`jm^>Qd@0yMzC2B&*~+a1UoQGwc(_iOGnZ>%t^p@*jN+f zbGCvqn8d+%oI0`KVu?J*b+h#(qw6#=Xj3z`3)wm4l9?0^56lxshp3ikpq22`2GU>} zrf!adcLAqVJgiopNX3!RNjSpj92p)?@vd;5>DY%DD9|2#*lMP(!fbk;0F4&tvCR@M zq|#=?VcY>G%L#l+%c+I!WJf>RFr2`dJo`wQt~gX;HR}bsm-A*3mg!x%fKJ1ugr=|< z+ObW|PaVU@0iDCKB&CLAjfuM=X%)^T(p{}cOR;@FRrSp zs$NtxznaY0ZMG8_9T^9e^Dd)$d52Q-_~cbAt{YcHEvk5*0@XD&LqXXyFE? zai1-Q8(}cWL`&8ooIsk58&E@d;vfW}9>Hr6N+Dkucgf(-A!k;~R}z&K((44Zok*dz z6UC0FJC<6Q9aGRwqMmBpu3CtjeB6Q^QXAU1pg~e$MWtKEdV|GNq?t8o*s12^qBt+AjCc9v06_Zak=B4{7; zCtnlOI}3e;8ED%yy$!()5qT7Vnv-9&R+ zq#c;Tr2S!Vk6Xr^h8K<}m2vMjkvnL_Oj> zTFTsyG-xvaIJ^{Xs|2N5K)RG`8p1718#}K!Mfj^IRSPADi*$OS1jC?~#(%8KsAo|p zLR=T?oz@RWdfe{}VzoprH!`^bmt#91Ypgv47HWCE{(O{c(l z8_&x3t+7S8KiAYpb8tHg|Mh_eHnUNh#|Ud?4BXiPNpou)-Dl3Rd~waP%+ZNLZqjKd z=63i@Wqr~o*4jMx=^W;F#*7=TJuWq{-fHQyjL?eH3Uzx7g>#t#_k9S`&?8*)I4oMj zR!#SZ&f=Ub30#$v{&Kz)%5Fw&S=2I&x@qZ&xwuE%3eBU!GI~S|Abk+E&??TCl9sbZ z^Jp*3;n+^*vX(Hno3%cJyx7k`*#y&BbYcs5lshAtM+(=+;|5>5!XNjUmYi6I`>3rm z_jkbwEpc>(&Ofo-_}1m}&Rv1JSWgN^Ik#S0dyJ&>ThQ;5kBKDY%=V3~8(lhryu2O5 zwu0?}BSY>Nj+8-_wNUE;_n5VtM^hDMFKxNkV{W*LN6a{mP255*t*t7`%;%nSovfie zYM8@p*SU|{p7sjP`awA@E6knO=z^Sc94=`Yvkb=6+mXuYJzE7mCZVsZoPMzWv%cvXdA9kh=rp~5yWU@)a;;f5aclm<(o5gJ4dZn) zS8w&i^}bJudY)T`!7U!AC(oy~U5~iJ(Ts6gwh{bh$#oiOu+(VDSns4uq^o6uuYQPh zc&=UpNwKDJy9am{!n=M+K-N8)Hi5Tt>ex7%qcxd5nF`dwy23Mvp5dY29`SKDIQ8p# z3VWmH3T-z}9CO-taXc)x&%^kS#|rnPkK21y8``eNsrG(2m1n=aHO^}zdmAnAue9Fk zxsb;gTY@HxXSQQJ0`(ZELu}sbVNYfNb@TYteMaq9I-?BR_ISHu5iEhOJB)WKPF`09 zc+T~V;FΠ6l8sQ73kU=S2I2*09B>hL`B%;rZFA+p&EA)tcFMoxDy?MQv-xYD%F5 zPi8Uy0_m+<3pt(GSC&Nw-hk0_OI|w*d0J>8A&2UABN?983+L9n6xa^3e(~r)iMbB< z@;OeR*)?(7wC6D&_4UKs%zGc2wlk7W-d43FBKDkTtbB_cf6dW#hnnN5p~bahN3Vr<5ci(7yiM?bbfn8zK7iMe)!)hkWrg#nX2u@fAZue<_-X{^Yc(%eX1zD-1< zki|9(#<|>}Gg;|%{yhD#OattU*%;LSSirJ(m6njb1u&$FwG#STgV5 zpu3y7&O*8JoT!<>HoihEJg*!yvnyp)=lHU$3Jr|=W7tb^Qdvg0W4x}{mrzr zw|U~2&aXHfRna>bc@LCuqgk)w^Ilxxh-GDSc0W!^V@jb%fKLP!-FC{~ue+!D>xmaX za^q{C`!)H$wzGTPX*Dli=kk_&@FRC_Z)kLXAnaED;QC;<-{&n0m8+27@>(u$D1blw z_RuWObb}X3XDOr`*EC;|(PQJ%188w~W6wtlh6kKomy~*h}qNLvu>30M#pO$+{ybQ}d zKuXFz-0TSYRl@x(0sn*5Dp+fIOVFoU@P8?~QsTzPb?}3~T<@P4{1E`@VYdtM2+Tvq z3n0-F%ZuM)E%ySg!ry9y{rGd^moZo{1-pyG9uxKlyFo^j3SEb+7zV)xOU;^z z!l7lsNT`06&<-sNggs2$ADjo?gsOt;(J$rpmWQg`hdt86I&^0_{#u2@qx)yE>IB?K zB>Z$1fR8}{!18)d341}VT>eMD{h=EF)G*W6QK1@i0bFYay&7&MP-v3kr@M&h;0r?J zE@m)=!Mn`!cL1h`PhlENsPMlMblbr}qcj{iAqyg>lF5UN5uz z&yY<9a~CSEA5a_@Fr6kQ!5<2M8s~@nEq}nnO3p#$@w-U{FhGH#bf7#SCZrqzPWHq6 zl;cNZ*{JYf=Z6_nMHY+^n-!}F)M1xEGB~<>^e|reCHE-a)`iHt7{H9L>8!8DsKuaG z^z`6eU;V?3mX93$*M}FWKRkE(dF;(0?VvGn972q-vAk(JVX9sp9`r5K~ZZK3q;MD z;)8JjJxf{@^!Y#S;=5gszl^;K2%sGOvP!=mlc?m$M%7aj-3iSs9ek)*=`_J%AHnWGK7pFU2REn3A$(gq9Wa2E7**_aQljixX<8h zDXYZTe`q#pILzP<26r;}a>zG@XOUb5;0Tn%y_w=*%qC#Nac zn98=>S$r@c+#2sm^D86LuH0p&@Hg)Y7ZeIFtg2cZo{vX$we$=9C|2aFu3TDKU5W3h zoTjL>g+FU>PA071>+cKm>+<+GA%50(jodFF+N9`mL~?y$+{+7_`=4RFToC4K#$o3& z7;cbMh6l6R;R_cm*tTt3C10N7EB6QtEy%aMLce3OOw)(s4<`G-atW|sNrc~+Rur+O zcco*)cm*hTxQZ(%scjj_i(DnYUDnRId76Ue($Tb{qdf}qRb!|3n$0r@NnZx{@Pls>ZOXo%u-_6PMy9I6HBi>%zn9YC+-(u$bO?+=u z^FiOm;kv4Dj+Cdl4mk>L0V196hVo5Qe)891m*eZB3S49va9*aHC}@4Y?n>}O*HejF z`7Rs(OJMVxzZUA;mu0CAqyK!bYe2Y9BI&VlVY&@yA#-{^N1N zZS63$S?jp14*wX_9RI(yxe?#FRJf7Dw_y8l(#f}C+H<8@UgLG375(W!33D?Py3BkY zOXEatpUCSvDN_#_^8E+C^~m>~!x)KUrF3FBVe}-J Date: Tue, 2 Dec 2014 18:53:09 +0100 Subject: [PATCH 15/40] FIX Gendarme issue with empty strings --- src/DiskCache.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/DiskCache.cs b/src/DiskCache.cs index f634ed9..5c0dc0b 100644 --- a/src/DiskCache.cs +++ b/src/DiskCache.cs @@ -70,7 +70,7 @@ void Awake () public DiskCacheOperation Fetch (Request request) { - var guid = ""; + var guid = string.Empty; // MD5 is disposable // http://msdn.microsoft.com/en-us/library/system.security.cryptography.md5.aspx#3 using (System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create ()) { @@ -98,7 +98,7 @@ IEnumerator DownloadAndSave (Request request, string filename, DiskCacheOperatio if (request.exception == null && request.response != null) { if (request.response.status == 200) { var etag = request.response.GetHeader ("etag"); - if (etag != "") { + if (etag != string.Empty) { File.WriteAllBytes (filename, request.response.bytes); File.WriteAllText (filename + ".etag", etag); } From c3837479a1e9d5509df0f9de07306bb95155127a Mon Sep 17 00:00:00 2001 From: kronenthaler Date: Tue, 2 Dec 2014 18:55:49 +0100 Subject: [PATCH 16/40] FIX white spaces compability --- src/DiskCache.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DiskCache.cs b/src/DiskCache.cs index 5c0dc0b..45ac010 100644 --- a/src/DiskCache.cs +++ b/src/DiskCache.cs @@ -98,7 +98,7 @@ IEnumerator DownloadAndSave (Request request, string filename, DiskCacheOperatio if (request.exception == null && request.response != null) { if (request.response.status == 200) { var etag = request.response.GetHeader ("etag"); - if (etag != string.Empty) { + if (etag != string.Empty) { File.WriteAllBytes (filename, request.response.bytes); File.WriteAllText (filename + ".etag", etag); } From 0d1ca8268bf41b886a448c6a6a5f6f5c164289c3 Mon Sep 17 00:00:00 2001 From: Dawson Reid Date: Sat, 6 Dec 2014 12:09:02 -0400 Subject: [PATCH 17/40] I have added a nuspec file and am working on getting this project into NuGet. I have not yet tested. #25 --- .gitignore | 2 ++ HTTP.pidb | Bin 9354 -> 0 bytes HTTP.csproj => UnityHTTP.csproj | 13 ++++++++----- UnityHTTP.nuspec | 29 +++++++++++++++++++++++++++++ {libs => lib}/Ionic.Zlib.dll | Bin {libs => lib}/JSON.cs | 0 6 files changed, 39 insertions(+), 5 deletions(-) delete mode 100644 HTTP.pidb rename HTTP.csproj => UnityHTTP.csproj (91%) create mode 100644 UnityHTTP.nuspec rename {libs => lib}/Ionic.Zlib.dll (100%) rename {libs => lib}/JSON.cs (100%) diff --git a/.gitignore b/.gitignore index a83251f..1f2b190 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ bin .DS_Store obj +*.pidb +*.nupkg diff --git a/HTTP.pidb b/HTTP.pidb deleted file mode 100644 index 2fbce9c92cf5fb217dbc901494b2af4c85bd25c2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9354 zcmcgyZF3yO5xy7Q-t9@khk+2@%-P0)fPE($I~W-QvR-U~WGU7e2o5E$P9tgY-R`lw zCtFTPlvfCZd`wlUQc0>(1AjuXy%!?`m9FZ!nVz2Ro}THR zxw%WFQ>oM*fS-gBRvum1@dMSYOuLPSst2~~_?1hRzZF<(4V4E&aly6L=d60*dimFs z=Yyj#?KWGMr@R6=SM1wrxE7|XeD0L>ZOzcFpqx72^(8d#W0 zm4KA2frO`kH6RV#1Wr`1`tU~8x0|k0^|zgB+rgY~sok1X3btsxa2`ZS*9c@9_%K&( z#}6#0E;HO^$NfOfv`5P#cd$1GWNHF)Q#Y*}GG02%DD`+!NT8RF0qLP6IB4ePR8SW) z#m7&Al#oEeY2X>4NYG}vpd8emTxu!L;x+}f7dVL)Fz;atDnF2ZE$1EfT#5BacUVyS z6H%L9KQQCobQ;+CQ_lK|wcVZibLdPMPQv$rSAe16K57U1!;03?q|y0Vr`_Z%+(GM0 z;hcm(!uW_7eNuCojW)2bVKNe2WvYhos*ri3%uf4!g7a}4Jz6mVM z$M(au_r% zCCeOgZ_~PEH`~oCD)4Zaww*xF`AD4EWL7C!b%w*m+jdKH9gTBkB}=q@l|1a8NboRO zn5r+Zj>Vbs%nA7|Wv%1T>v16AshP!s77Di=}hFI7zSgA{U>}fO-5lq4f zU%0DB7q< z_C`z_nV8rFeuT29C3h3s66guhBvgS{fg)P(N^Wt{(Yw3p%$QzEI7(i^kAdb&-;7=d zIiZ#W`fn9D)PH2^^&e^4f4dyLqMUWTP!=c&MI`X#`8`>IN%#qx56NZT3e<}7wv{)n zyujYD>mX37q~Skx_% zO%bB|*xvyTe~b0^fCqfPvFtYN`p&H9xgIk=1ko$^b!@+^f=XmRh5rh8U}eB4&?BIV z&?Zzq0FJ+o>8qN%5_rmL((%IjSCm<)bqW%m0saHnT~4a~5IE+xgH}5Tg`f>fe~rTI zSUSH%#*ctTj0MdIDE+~xL0+!$NKM_+XIp{2e*h+|iii)O@+Y8Jmg(BZ{s{hv3VZnZ zQbfe(Dd?k0-XI5jq0l?rM8AYTJ_SfP47>+O!JELZ`2CM|2ym7*u=hGJ3Yzvnmbup4 z@Z4td@E%Jr@e&n%_0f|VkF)5zKQnc7r$qHm@OiH5HGQAa;%R2WS0r$O{{oDBRo&l} zJG@r)-MO`^C{A33Z?i$Wn{g9UG#>|-HjgW&y_lgFd#<4e;tY3t4eh%G-3w_)fC76A zzc081xnLP|3F1)By9NBBOHdv>ylf^9RS?2WtEV3kPN4D>knRkD3&{N~kddmK`qw)o ztT4OFQIpr#K}X-ypeNLkz;w;4il`HxL=)T3(MJhKfdWj80}k_3AScw4z!~zZm#CE; zO0}GZKqf^deVDUPZ<|>_lF?4PO!}YRHAWiY0R)Z`4C_A;sPg z6u5~J;bpBa;4z4%2$kt8F*Oos$}7O+)M$%<7(wf(x)(TJ>*Otcj5_gpCvSIJ?*e)f zE+By}y#@?dlG%n@c(vvPZHH+w0`^1@c}m)Mw2oTjIzralzpHU2vgbm~;k!KXYj)&_bdyg(> zlVXui`{7-7O!>Y_o`a8o+^2&?Ubr3y#&mEqvv~+OPzUHCaN^iu`XRVP0*7{=WKC&O z%m^ni=#_ZN^Q;|yL8F1WRUgm5#wxBDO~0^;TOJ>ZVMn1Lk__-r%NVm&iEo@UYFjnj z79O5Gm7|C=aq67Mc zzVthIC46J&acqvED3-VcM3d*G$&=CK>1UQu6pLw2h_m5%o@3#7*35%!mZ*yi2KV?~ zUw;gSz};R142IHOKG+!yjc50B<6yWo*BU$X&W4LyM~Qxv&C2_W$xt;J#wIgTiH>9> z7>vGB=enz(APolJL$T-lO5z#6#1-IZ^D!0@p^RYC~ZwcQ!dAXLQ}dZ!(sz z@TisMt}+<^--{+ONm1ofm9vx81$)iIi%NCQLm1q2y&Ha&ot2HKUG4mi<5$67ZP;to zCi>BssCFi{-e{z`LujN?Mse+H*3deAIb>4OCdgaYXD7Uo;Ju<}nsa6YLx+JIg)ljOG6|2>%PIod&!ikn+ZL0Nwdu`!H zT1L-jck@ zNsxZ=sfE#7XGM1;w8HclM(W&y!^2^&`!I6dq=V-SesC>z{OZ zzD=H|$-{UR9%h2w&))m(o4Xwz-Vlmu#vp@H7U+1Vl4ek9>WPTT_2Us^R#-?)R+(0R za3|;fpM6WqI;U@V6zek>8SPMf2@@wP7WkU1OQB%$q8>q>3nC7pOGZu(6_DJ#)7*Tr zdu6S8?Ke+S5EoDuI<6$g6}@}WJckM`*SGoG&lrz-xeXv=%DI0q*lFP>QRcb;Z%uqQ zFZ%7ZPF&Yb7HJwS! zfs*{G83bs!h>{vI*r@4CsAvuIXlM Debug AnyCPU - 9.0.21022 + 8.0.30703 2.0 {8E94F9A4-3E1E-42F4-86E8-58270D44A4D8} Library @@ -31,12 +31,12 @@ - - libs\Ionic.Zlib.dll - ..\..\..\..\..\Applications\Unity\Unity.app\Contents\Frameworks\Managed\UnityEngine.dll + + lib\Ionic.Zlib.dll + @@ -45,10 +45,13 @@ - + + + + \ No newline at end of file diff --git a/UnityHTTP.nuspec b/UnityHTTP.nuspec new file mode 100644 index 0000000..f53f1e5 --- /dev/null +++ b/UnityHTTP.nuspec @@ -0,0 +1,29 @@ + + + + 1 + 1.0.0 + UnityHTTP + Andy Burke, Dawson Reid + Andy Burke + https://github.com/andyburke/UnityHTTP/blob/master/LICENSE.md + https://github.com/andyburke/UnityHTTP + false + A TcpClient-based HTTP library for Unity. + First push to NuGet + Copyright 2014 + Unity HTTP Web Game + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libs/Ionic.Zlib.dll b/lib/Ionic.Zlib.dll similarity index 100% rename from libs/Ionic.Zlib.dll rename to lib/Ionic.Zlib.dll diff --git a/libs/JSON.cs b/lib/JSON.cs similarity index 100% rename from libs/JSON.cs rename to lib/JSON.cs From 70299a48a45b0c007d2c385c9b5173e6d3d9a4e5 Mon Sep 17 00:00:00 2001 From: Dawson Reid Date: Sun, 7 Dec 2014 17:36:17 -0400 Subject: [PATCH 18/40] Add a license which closes #29 --- LICENSE.md | 340 +++++++++++++++++++++++++++++++++++++++++++++++ UnityHTTP.nuspec | 2 +- 2 files changed, 341 insertions(+), 1 deletion(-) create mode 100644 LICENSE.md diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..8cdb845 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + {description} + Copyright (C) {year} {fullname} + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + {signature of Ty Coon}, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. + diff --git a/UnityHTTP.nuspec b/UnityHTTP.nuspec index f53f1e5..ce6f944 100644 --- a/UnityHTTP.nuspec +++ b/UnityHTTP.nuspec @@ -1,7 +1,7 @@ - 1 + UnityHTTP 1.0.0 UnityHTTP Andy Burke, Dawson Reid From 581323b15626f4763724032662f73c9ed65db83d Mon Sep 17 00:00:00 2001 From: Godefroy Date: Mon, 8 Dec 2014 16:00:49 +0100 Subject: [PATCH 19/40] Fixed User-Agent when using UnityHTTP in a thread --- src/Request.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Request.cs b/src/Request.cs index 24532ac..a5fec2d 100644 --- a/src/Request.cs +++ b/src/Request.cs @@ -270,7 +270,11 @@ public virtual void Send( Action< HTTP.Request > callback = null) } if ( GetHeader( "User-Agent" ) == "" ) { - SetHeader( "User-Agent", "UnityWeb/1.0 (Unity " + Application.unityVersion + "; " + SystemInfo.operatingSystem + ")" ); + try { + SetHeader( "User-Agent", "UnityWeb/1.0 (Unity " + Application.unityVersion + "; " + SystemInfo.operatingSystem + ")" ); + } catch (Exception) { + SetHeader( "User-Agent", "UnityWeb/1.0" ); + } } if ( GetHeader( "Connection" ) == "" ) { From 0669cb67513db1a136899bf4a6605f98f24ec534 Mon Sep 17 00:00:00 2001 From: D Date: Fri, 13 Feb 2015 16:54:28 +0100 Subject: [PATCH 20/40] to avoid access to Application and SystemInfo in Request thread --- src/Request.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Request.cs b/src/Request.cs index a5fec2d..c9b358d 100644 --- a/src/Request.cs +++ b/src/Request.cs @@ -28,6 +28,8 @@ public class Request { public static bool LogAllRequests = false; public static bool VerboseLogging = false; + public static string unityVersion = Application.unityVersion; + public static string operatingSystem = SystemInfo.operatingSystem; public CookieJar cookieJar = CookieJar.Instance; public string method = "GET"; @@ -271,7 +273,7 @@ public virtual void Send( Action< HTTP.Request > callback = null) if ( GetHeader( "User-Agent" ) == "" ) { try { - SetHeader( "User-Agent", "UnityWeb/1.0 (Unity " + Application.unityVersion + "; " + SystemInfo.operatingSystem + ")" ); + SetHeader( "User-Agent", "UnityWeb/1.0 (Unity " + Request.unityVersion + "; " + Request.operatingSystem + ")" ); } catch (Exception) { SetHeader( "User-Agent", "UnityWeb/1.0" ); } From d2ce2e6e79ae45979362cc5583258285274b10dc Mon Sep 17 00:00:00 2001 From: Deniz Piri Date: Fri, 29 May 2015 20:47:05 +0200 Subject: [PATCH 21/40] ResponseCallbackDispatcher should be marked with DonDestroyOnLoad() This patch allows ResponseCallbackDispatcher to survive when a new level is loaded in. --- src/ResponseCallbackDispatcher.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ResponseCallbackDispatcher.cs b/src/ResponseCallbackDispatcher.cs index f87c31c..2f857aa 100644 --- a/src/ResponseCallbackDispatcher.cs +++ b/src/ResponseCallbackDispatcher.cs @@ -33,6 +33,7 @@ public static void Init() } singletonGameObject = new GameObject(); + GameObject.DontDestroyOnLoad(singletonGameObject); singleton = singletonGameObject.AddComponent< ResponseCallbackDispatcher >(); singletonGameObject.name = "HTTPResponseCallbackDispatcher"; } From cd76bd5d75fe8551254664cd4367ef8faeb8cf4a Mon Sep 17 00:00:00 2001 From: Yakov Borevich Date: Mon, 8 Jun 2015 15:15:41 +0300 Subject: [PATCH 22/40] StreamedWWWForm for UnityHTTP --- src/FormDataStream.cs | 158 +++++++++++++++++++++++++++++++++++++++++ src/Request.cs | 35 ++++++--- src/StreamedWWWForm.cs | 62 ++++++++++++++++ 3 files changed, 246 insertions(+), 9 deletions(-) create mode 100644 src/FormDataStream.cs create mode 100644 src/StreamedWWWForm.cs diff --git a/src/FormDataStream.cs b/src/FormDataStream.cs new file mode 100644 index 0000000..71da5ed --- /dev/null +++ b/src/FormDataStream.cs @@ -0,0 +1,158 @@ +using System; +using System.IO; +using System.Text; +using System.Collections.Generic; +namespace HTTP { + + public class FormPart { + string fieldName; + string mimeType; + byte[] header; + Stream contents; + int position = 0; + + public FormPart(string fieldName, string mimeType, string boundary, Stream contents, string fileName=null){ + string filenameheader = ""; + if (fileName != null){ + filenameheader = "; filename=\"" + fileName +"\""; + } + header = Encoding.ASCII.GetBytes( + "\r\n--" + boundary + "\r\n" + + "Content-Type: " + mimeType + "\r\n" + + "Content-disposition: form-data; name=\"" + fieldName + "\"" + filenameheader + "\r\n\r\n" + ); + this.contents = contents; + } + public long Length { + get { + return header.Length + contents.Length; + } + } + public int Read(byte[] buffer, int offset, int size){ + int writed = 0; + int bytesToWrite; + if (position < header.Length){ + bytesToWrite = (int)(header.Length - position) > size ? size : (int)(header.Length - position); + Array.Copy ( + header, // from header + position, // started from position + buffer, // to buffer + offset, // started with offset + bytesToWrite + ); + writed += bytesToWrite; + position += bytesToWrite; + } + if (writed >= size){ + return writed; + } + bytesToWrite = contents.Read(buffer, writed + offset, size - writed); + writed += bytesToWrite; + position += bytesToWrite; + return writed; + } + } + + public class FormDataStream: Stream { + long position = 0; + List parts = new List(); + bool dirty = false; + byte[] footer; + string boundary; + + public FormDataStream(string boundary){ + this.boundary = boundary; + footer = Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n"); + } + + public override bool CanRead { get { return true; } } + public override bool CanSeek { get { return false; } } + public override bool CanTimeout { get { return false; } } + public override bool CanWrite { get { return false; } } + public override int ReadTimeout { get { return 0; } set { } } + public override int WriteTimeout { get { return 0; } set { } } + public override long Position { + get { + return position; + } + set { + throw new NotImplementedException("FormDataStream is non-seekable stream"); + } + } + public override long Length { + get { + if (parts.Count == 0){ + return 0; + } + dirty = true; + long len = 0; + foreach (var part in parts){ + len += part.Length; + } + return len + footer.Length; + } + } + + public override void Flush(){ + throw new NotImplementedException("FormDataStream is readonly stream"); + } + + public override int Read(byte[] buffer, int offset, int count){ + dirty = true; + int writed = 0; + int bytesToWrite = 0; + + // write parts + long partsSize = 0; + foreach (var part in parts){ + partsSize += part.Length; + if (position > partsSize){ + continue; + } + bytesToWrite = part.Read(buffer, writed + offset, count - writed); + writed += bytesToWrite; + position += bytesToWrite; + if (writed >= count){ + return count; + } + } + + + // write footer + bytesToWrite = count - writed > footer.Length? footer.Length : count - writed; + Array.Copy (footer, 0, buffer, writed + offset, bytesToWrite); + position += bytesToWrite; + writed += bytesToWrite; + return writed; + } + + public override long Seek(long amount, SeekOrigin origin){ + throw new NotImplementedException("FormDataStream is non-seekable stream"); + } + + public override void SetLength (long len){ + throw new NotImplementedException("FormDataStream is readonly stream"); + } + + public override void Write(byte[] source, int offset, int count){ + throw new NotImplementedException("FormDataStream is readonly stream"); + } + + public void AddPart(string fieldName, string mimeType, Stream contents, string fileName=null){ + if (dirty){ + throw new InvalidOperationException("You can't change form data, form already readed"); + } + parts.Add(new FormPart(fieldName, mimeType, boundary, contents, fileName)); + } + + public void AddPart(FormPart part){ + if (dirty){ + throw new InvalidOperationException("You can't change form data, form already readed"); + } + parts.Add(part); + } + } + +} + + diff --git a/src/Request.cs b/src/Request.cs index c9b358d..1e4d988 100644 --- a/src/Request.cs +++ b/src/Request.cs @@ -26,6 +26,7 @@ public enum RequestState { public class Request { + public static bool LogAllRequests = false; public static bool VerboseLogging = false; public static string unityVersion = Application.unityVersion; @@ -34,7 +35,7 @@ public class Request public CookieJar cookieJar = CookieJar.Instance; public string method = "GET"; public string protocol = "HTTP/1.1"; - public byte[] bytes; + public Stream byteStream; public Uri uri; public static byte[] EOL = { (byte)'\r', (byte)'\n' }; public Response response = null; @@ -46,6 +47,7 @@ public class Request public RequestState state = RequestState.Waiting; public long responseTime = 0; // in milliseconds public bool synchronous = false; + public int bufferSize = 4 * 1024; public Action< HTTP.Request > completedCallback = null; @@ -69,25 +71,36 @@ public Request (string method, string uri, byte[] bytes) { this.method = method; this.uri = new Uri (uri); - this.bytes = bytes; + this.byteStream = new MemoryStream(bytes); + } + + public Request(string method, string uri, StreamedWWWForm form){ + this.method = method; + this.uri = new Uri (uri); + this.byteStream = form.stream; + foreach ( DictionaryEntry entry in form.headers ) + { + this.AddHeader( (string)entry.Key, (string)entry.Value ); + } } public Request( string method, string uri, WWWForm form ) { this.method = method; this.uri = new Uri (uri); - this.bytes = form.data; + this.byteStream = new MemoryStream(form.data); foreach ( DictionaryEntry entry in form.headers ) { this.AddHeader( (string)entry.Key, (string)entry.Value ); } + } public Request( string method, string uri, Hashtable data ) { this.method = method; this.uri = new Uri( uri ); - this.bytes = Encoding.UTF8.GetBytes( JSON.JsonEncode( data ) ); + this.byteStream = new MemoryStream(Encoding.UTF8.GetBytes( JSON.JsonEncode( data ) )); this.AddHeader( "Content-Type", "application/json" ); } @@ -267,8 +280,8 @@ public virtual void Send( Action< HTTP.Request > callback = null) SetHeader( "cookie", cookieString ); } - if ( bytes != null && bytes.Length > 0 && GetHeader ("Content-Length") == "" ) { - SetHeader( "Content-Length", bytes.Length.ToString() ); + if ( byteStream != null && byteStream.Length > 0 && GetHeader ("Content-Length") == "" ) { + SetHeader( "Content-Length", byteStream.Length.ToString() ); } if ( GetHeader( "User-Agent" ) == "" ) { @@ -298,7 +311,7 @@ public virtual void Send( Action< HTTP.Request > callback = null) } public string Text { - set { bytes = System.Text.Encoding.UTF8.GetBytes (value); } + set { byteStream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes (value)); } } public static bool ValidateServerCertificate (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) @@ -328,8 +341,12 @@ void WriteToStream( Stream outputStream ) stream.Write( EOL ); - if ( bytes != null && bytes.Length > 0 ) { - stream.Write( bytes ); + long numBytesToRead = byteStream.Length; + byte[] buffer = new byte[bufferSize]; + while (numBytesToRead > 0){ + int readed = byteStream.Read(buffer, 0, bufferSize); + stream.Write(buffer, 0, readed); + numBytesToRead -= readed; } } diff --git a/src/StreamedWWWForm.cs b/src/StreamedWWWForm.cs new file mode 100644 index 0000000..f8ed954 --- /dev/null +++ b/src/StreamedWWWForm.cs @@ -0,0 +1,62 @@ +using System; +using System.IO; +using System.Text; +using System.Collections; + +namespace HTTP +{ + public class StreamedWWWForm { + string boundary; + public FormDataStream stream; + + public Hashtable headers { + get { + return new Hashtable { + { "Content-Type", "multipart/form-data; boundary=\"" + boundary + "\""} + }; + } + } + + public StreamedWWWForm(){ + byte[] bytes = new byte[40]; + var random = new Random(); + for (int i=0; i<40; i++){ + bytes[i] = (byte)(48 + random.Next(62)); + if (bytes[i] > 57){ + bytes[i] += 7; + } + if (bytes[i] > 90){ + bytes[i] += 6; + } + } + boundary = Encoding.ASCII.GetString(bytes); + stream = new FormDataStream(boundary); + } + + public void AddField(string fieldName, string fieldValue){ + var contentStream = new MemoryStream(Encoding.UTF8.GetBytes(fieldValue)); + stream.AddPart(fieldName, "text/plain; charset=\"utf-8\"", contentStream); + + } + public void AddBinaryData(string fieldName, byte[] contents=null, string mimeType = null){ + var contentStream = new MemoryStream(contents); + if (mimeType == null){ + mimeType = "application/octet-stream"; + } + stream.AddPart(fieldName, mimeType, contentStream, fieldName + ".dat"); + } + public void AddBinaryData(string fieldName, Stream contents=null, string mimeType = null){ + if (mimeType == null){ + mimeType = "application/octet-stream"; + } + stream.AddPart(fieldName, mimeType, contents, fieldName + ".dat"); + } + public void AddFile(string fieldName, string path, string mimeType=null){ + if (mimeType == null){ + mimeType = "application/octet-stream"; + } + var contents = new FileInfo(path).Open(FileMode.Open); + stream.AddPart(fieldName, mimeType, contents, fieldName + ".dat"); + } + } +} From d5482828f3aa721fb9897943f6d80dd91c21fbab Mon Sep 17 00:00:00 2001 From: Yakov Borevich Date: Wed, 10 Jun 2015 18:48:44 +0300 Subject: [PATCH 23/40] Fix request with empty body --- src/Request.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/Request.cs b/src/Request.cs index 1e4d988..62acff6 100644 --- a/src/Request.cs +++ b/src/Request.cs @@ -208,11 +208,17 @@ private void GetResponse() { } } catch (Exception e) { +#if !UNITY_EDITOR Console.WriteLine ("Unhandled Exception, aborting request."); Console.WriteLine (e); +#else + Debug.LogError("Unhandled Exception, aborting request."); + Debug.LogException(e); +#endif exception = e; response = null; } + state = RequestState.Done; isDone = true; responseTime = curcall.ElapsedMilliseconds; @@ -341,6 +347,10 @@ void WriteToStream( Stream outputStream ) stream.Write( EOL ); + if (byteStream == null){ + return; + } + long numBytesToRead = byteStream.Length; byte[] buffer = new byte[bufferSize]; while (numBytesToRead > 0){ @@ -348,6 +358,7 @@ void WriteToStream( Stream outputStream ) stream.Write(buffer, 0, readed); numBytesToRead -= readed; } + byteStream.Close(); } private static string[] sizes = { "B", "KB", "MB", "GB" }; From e4c297598dddb80b146ec97c5427c86d5aca8311 Mon Sep 17 00:00:00 2001 From: Yakov Borevich Date: Mon, 15 Jun 2015 12:09:57 +0300 Subject: [PATCH 24/40] Close input bytestream even in request with errors --- src/Request.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Request.cs b/src/Request.cs index 62acff6..b665a2d 100644 --- a/src/Request.cs +++ b/src/Request.cs @@ -223,6 +223,11 @@ private void GetResponse() { isDone = true; responseTime = curcall.ElapsedMilliseconds; + if ( byteStream != null ) + { + byteStream.Close(); + } + if ( completedCallback != null ) { if (synchronous) { @@ -358,7 +363,6 @@ void WriteToStream( Stream outputStream ) stream.Write(buffer, 0, readed); numBytesToRead -= readed; } - byteStream.Close(); } private static string[] sizes = { "B", "KB", "MB", "GB" }; From bfe3a1a4e50147ceb8aea28ffd72d1ecf7a9aeec Mon Sep 17 00:00:00 2001 From: Yakov Borevich Date: Tue, 16 Jun 2015 11:54:57 +0300 Subject: [PATCH 25/40] Move to compact version of Ionic.Zlib --- lib/Ionic.Zlib.CF.dll | Bin 0 -> 74240 bytes lib/Ionic.Zlib.dll | Bin 102400 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100755 lib/Ionic.Zlib.CF.dll delete mode 100755 lib/Ionic.Zlib.dll diff --git a/lib/Ionic.Zlib.CF.dll b/lib/Ionic.Zlib.CF.dll new file mode 100755 index 0000000000000000000000000000000000000000..949f8047f3df186ae7c11033e244bc1e85a6e2ca GIT binary patch literal 74240 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 E17drsp8x;= literal 0 HcmV?d00001 diff --git a/lib/Ionic.Zlib.dll b/lib/Ionic.Zlib.dll deleted file mode 100755 index 0afce7f255db09bfd630fff75801480102e5d770..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 102400 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Π6l8sQ73kU=S2I2*09B>hL`B%;rZFA+p&EA)tcFMoxDy?MQv-xYD%F5 zPi8Uy0_m+<3pt(GSC&Nw-hk0_OI|w*d0J>8A&2UABN?983+L9n6xa^3e(~r)iMbB< z@;OeR*)?(7wC6D&_4UKs%zGc2wlk7W-d43FBKDkTtbB_cf6dW#hnnN5p~bahN3Vr<5ci(7yiM?bbfn8zK7iMe)!)hkWrg#nX2u@fAZue<_-X{^Yc(%eX1zD-1< zki|9(#<|>}Gg;|%{yhD#OattU*%;LSSirJ(m6njb1u&$FwG#STgV5 zpu3y7&O*8JoT!<>HoihEJg*!yvnyp)=lHU$3Jr|=W7tb^Qdvg0W4x}{mrzr zw|U~2&aXHfRna>bc@LCuqgk)w^Ilxxh-GDSc0W!^V@jb%fKLP!-FC{~ue+!D>xmaX za^q{C`!)H$wzGTPX*Dli=kk_&@FRC_Z)kLXAnaED;QC;<-{&n0m8+27@>(u$D1blw z_RuWObb}X3XDOr`*EC;|(PQJ%188w~W6wtlh6kKomy~*h}qNLvu>30M#pO$+{ybQ}d zKuXFz-0TSYRl@x(0sn*5Dp+fIOVFoU@P8?~QsTzPb?}3~T<@P4{1E`@VYdtM2+Tvq z3n0-F%ZuM)E%ySg!ry9y{rGd^moZo{1-pyG9uxKlyFo^j3SEb+7zV)xOU;^z z!l7lsNT`06&<-sNggs2$ADjo?gsOt;(J$rpmWQg`hdt86I&^0_{#u2@qx)yE>IB?K zB>Z$1fR8}{!18)d341}VT>eMD{h=EF)G*W6QK1@i0bFYay&7&MP-v3kr@M&h;0r?J zE@m)=!Mn`!cL1h`PhlENsPMlMblbr}qcj{iAqyg>lF5UN5uz z&yY<9a~CSEA5a_@Fr6kQ!5<2M8s~@nEq}nnO3p#$@w-U{FhGH#bf7#SCZrqzPWHq6 zl;cNZ*{JYf=Z6_nMHY+^n-!}F)M1xEGB~<>^e|reCHE-a)`iHt7{H9L>8!8DsKuaG z^z`6eU;V?3mX93$*M}FWKRkE(dF;(0?VvGn972q-vAk(JVX9sp9`r5K~ZZK3q;MD z;)8JjJxf{@^!Y#S;=5gszl^;K2%sGOvP!=mlc?m$M%7aj-3iSs9ek)*=`_J%AHnWGK7pFU2REn3A$(gq9Wa2E7**_aQljixX<8h zDXYZTe`q#pILzP<26r;}a>zG@XOUb5;0Tn%y_w=*%qC#Nac zn98=>S$r@c+#2sm^D86LuH0p&@Hg)Y7ZeIFtg2cZo{vX$we$=9C|2aFu3TDKU5W3h zoTjL>g+FU>PA071>+cKm>+<+GA%50(jodFF+N9`mL~?y$+{+7_`=4RFToC4K#$o3& z7;cbMh6l6R;R_cm*tTt3C10N7EB6QtEy%aMLce3OOw)(s4<`G-atW|sNrc~+Rur+O zcco*)cm*hTxQZ(%scjj_i(DnYUDnRId76Ue($Tb{qdf}qRb!|3n$0r@NnZx{@Pls>ZOXo%u-_6PMy9I6HBi>%zn9YC+-(u$bO?+=u z^FiOm;kv4Dj+Cdl4mk>L0V196hVo5Qe)891m*eZB3S49va9*aHC}@4Y?n>}O*HejF z`7Rs(OJMVxzZUA;mu0CAqyK!bYe2Y9BI&VlVY&@yA#-{^N1N zZS63$S?jp14*wX_9RI(yxe?#FRJf7Dw_y8l(#f}C+H<8@UgLG375(W!33D?Py3BkY zOXEatpUCSvDN_#_^8E+C^~m>~!x)KUrF3FBVe}-J Date: Tue, 16 Jun 2015 16:49:48 +0300 Subject: [PATCH 26/40] FormDataStream cleanup --- src/FormDataStream.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/FormDataStream.cs b/src/FormDataStream.cs index 71da5ed..5e11922 100644 --- a/src/FormDataStream.cs +++ b/src/FormDataStream.cs @@ -5,8 +5,6 @@ namespace HTTP { public class FormPart { - string fieldName; - string mimeType; byte[] header; Stream contents; int position = 0; @@ -51,6 +49,11 @@ public int Read(byte[] buffer, int offset, int size){ position += bytesToWrite; return writed; } + + public void Dispose(){ + header = null; + contents.Close(); + } } public class FormDataStream: Stream { @@ -151,6 +154,13 @@ public void AddPart(FormPart part){ } parts.Add(part); } + + public override void Close(){ + foreach (var part in parts){ + part.Dispose(); + } + base.Close(); + } } } From 45dd8cd068285d7a28e5d42790f45c33d83e7eed Mon Sep 17 00:00:00 2001 From: Andy Burke Date: Mon, 22 Jun 2015 15:06:58 -0700 Subject: [PATCH 27/40] Add license to README Closes #36 --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 444376f..081b288 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,13 @@ Based on Simon Wittber's UnityWeb code (http://code.google.com/p/unityweb/). +# LICENSE + +UnityHTTP falls under the GPL due to its basis on Simon Wittber's UnityWeb code, +which is licensed under the GPL. + +You should be aware of this license and determine if it is acceptable for your project. + # About This is a TcpClient-based HTTP library for use in Unity. It should work in From 7e6349dcfc61619763e81112fe6bc1189d68c598 Mon Sep 17 00:00:00 2001 From: wangwang <3wangyongwang123@163.com> Date: Tue, 30 Jun 2015 11:27:54 +0800 Subject: [PATCH 28/40] Fixed Request.cs line:92 Cannot convert type 'System.Collections.Generic.KeyValuePair' to 'System.Collections.DictionaryEntry' --- src/Request.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Request.cs b/src/Request.cs index b665a2d..6cf22f9 100644 --- a/src/Request.cs +++ b/src/Request.cs @@ -89,11 +89,10 @@ public Request( string method, string uri, WWWForm form ) this.method = method; this.uri = new Uri (uri); this.byteStream = new MemoryStream(form.data); - foreach ( DictionaryEntry entry in form.headers ) + foreach ( KeyValuePair pair in form.headers ) { - this.AddHeader( (string)entry.Key, (string)entry.Value ); + this.AddHeader( pair.Key, pair.Value ); } - } public Request( string method, string uri, Hashtable data ) From 120de6ef1e52b310ec5d0821471832e94443f3f3 Mon Sep 17 00:00:00 2001 From: codeMonkeyWang <3wangyongwang123@163.com> Date: Tue, 30 Jun 2015 18:33:48 +0800 Subject: [PATCH 29/40] Align the code --- src/Request.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Request.cs b/src/Request.cs index 6cf22f9..528c5fd 100644 --- a/src/Request.cs +++ b/src/Request.cs @@ -89,10 +89,10 @@ public Request( string method, string uri, WWWForm form ) this.method = method; this.uri = new Uri (uri); this.byteStream = new MemoryStream(form.data); - foreach ( KeyValuePair pair in form.headers ) - { - this.AddHeader( pair.Key, pair.Value ); - } + foreach ( KeyValuePair pair in form.headers ) + { + this.AddHeader(pair.Key,pair.Value); + } } public Request( string method, string uri, Hashtable data ) From c9471b5c4d2c6980e1f10367fd4e6d653b0b902d Mon Sep 17 00:00:00 2001 From: Yakov Borevich Date: Wed, 8 Jul 2015 02:55:45 +0300 Subject: [PATCH 30/40] Support both unity 4 and 5 WWWForm.headers type --- src/Request.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Request.cs b/src/Request.cs index b665a2d..ac21887 100644 --- a/src/Request.cs +++ b/src/Request.cs @@ -89,10 +89,17 @@ public Request( string method, string uri, WWWForm form ) this.method = method; this.uri = new Uri (uri); this.byteStream = new MemoryStream(form.data); +#if UNITY_5 + foreach ( var entry in form.headers ) + { + this.AddHeader( entry.Key, entry.Value ); + } +#else foreach ( DictionaryEntry entry in form.headers ) { this.AddHeader( (string)entry.Key, (string)entry.Value ); } +#endif } From 7e1b8b73e2d95f8096afba15976d53dec94c61e5 Mon Sep 17 00:00:00 2001 From: Adrian Rudnik Date: Thu, 31 Dec 2015 15:35:26 +0100 Subject: [PATCH 31/40] Increased verbosity on SSL authentication exceptions --- src/Request.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Request.cs b/src/Request.cs index 68069f8..7c3126f 100644 --- a/src/Request.cs +++ b/src/Request.cs @@ -184,7 +184,13 @@ private void GetResponse() { var ssl = ostream as SslStream; ssl.AuthenticateAsClient (uri.Host); } catch (Exception e) { - Debug.LogError ("Exception: " + e.Message); +#if !UNITY_EDITOR + Console.WriteLine ("SSL authentication failed."); + Console.WriteLine (e); +#else + Debug.LogError ("SSL authentication failed."); + Debug.LogException(e); +#endif return; } } From fd501eaf8afe7a21eebec90d31a0439e435d94e9 Mon Sep 17 00:00:00 2001 From: Alejandro Huerta <1011415huerta@gmail.com> Date: Tue, 14 Jun 2016 13:29:13 -0700 Subject: [PATCH 32/40] Change namespace to prevent name conflicts --- src/CookieJar.cs | 2 +- src/DiskCache.cs | 5 ++--- src/FormDataStream.cs | 2 +- src/Request.cs | 6 +++--- src/Response.cs | 2 +- src/ResponseCallbackDispatcher.cs | 4 ++-- src/StreamedWWWForm.cs | 2 +- 7 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/CookieJar.cs b/src/CookieJar.cs index 8d6cc7a..d226e5c 100644 --- a/src/CookieJar.cs +++ b/src/CookieJar.cs @@ -4,7 +4,7 @@ // Based on node-cookiejar (https://github.com/bmeck/node-cookiejar) -namespace HTTP +namespace UnityHTTP { public class CookieAccessInfo { diff --git a/src/DiskCache.cs b/src/DiskCache.cs index 45ac010..f5357e3 100644 --- a/src/DiskCache.cs +++ b/src/DiskCache.cs @@ -2,9 +2,8 @@ using System.Collections; using System.IO; using System; -using HTTP; -namespace HTTP +namespace UnityHTTP { public class DiskCacheOperation { @@ -91,7 +90,7 @@ public DiskCacheOperation Fetch (Request request) IEnumerator DownloadAndSave (Request request, string filename, DiskCacheOperation handle) { var useCachedVersion = File.Exists(filename); - Action< HTTP.Request > callback = request.completedCallback; + Action< UnityHTTP.Request > callback = request.completedCallback; request.Send(); // will clear the completedCallback while (!request.isDone) yield return new WaitForEndOfFrame (); diff --git a/src/FormDataStream.cs b/src/FormDataStream.cs index 5e11922..02b44ca 100644 --- a/src/FormDataStream.cs +++ b/src/FormDataStream.cs @@ -2,7 +2,7 @@ using System.IO; using System.Text; using System.Collections.Generic; -namespace HTTP { +namespace UnityHTTP { public class FormPart { byte[] header; diff --git a/src/Request.cs b/src/Request.cs index 7c3126f..2d86473 100644 --- a/src/Request.cs +++ b/src/Request.cs @@ -11,7 +11,7 @@ using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; -namespace HTTP +namespace UnityHTTP { public class HTTPException : Exception { @@ -49,7 +49,7 @@ public class Request public bool synchronous = false; public int bufferSize = 4 * 1024; - public Action< HTTP.Request > completedCallback = null; + public Action< UnityHTTP.Request > completedCallback = null; Dictionary> headers = new Dictionary> (); static Dictionary etags = new Dictionary (); @@ -271,7 +271,7 @@ private void GetResponse() { } } - public virtual void Send( Action< HTTP.Request > callback = null) + public virtual void Send( Action< UnityHTTP.Request > callback = null) { if (!synchronous && callback != null && ResponseCallbackDispatcher.Singleton == null ) diff --git a/src/Response.cs b/src/Response.cs index 7a1a9d7..22d51f1 100644 --- a/src/Response.cs +++ b/src/Response.cs @@ -6,7 +6,7 @@ using System.Globalization; using Ionic.Zlib; -namespace HTTP +namespace UnityHTTP { public class Response { diff --git a/src/ResponseCallbackDispatcher.cs b/src/ResponseCallbackDispatcher.cs index 2f857aa..d49a31e 100644 --- a/src/ResponseCallbackDispatcher.cs +++ b/src/ResponseCallbackDispatcher.cs @@ -2,7 +2,7 @@ using System; using System.Collections; -namespace HTTP +namespace UnityHTTP { public class ResponseCallbackDispatcher : MonoBehaviour { @@ -43,7 +43,7 @@ public void Update() { while( requests.Count > 0 ) { - HTTP.Request request = (Request)requests.Dequeue(); + UnityHTTP.Request request = (Request)requests.Dequeue(); request.completedCallback( request ); } } diff --git a/src/StreamedWWWForm.cs b/src/StreamedWWWForm.cs index f8ed954..0510e48 100644 --- a/src/StreamedWWWForm.cs +++ b/src/StreamedWWWForm.cs @@ -3,7 +3,7 @@ using System.Text; using System.Collections; -namespace HTTP +namespace UnityHTTP { public class StreamedWWWForm { string boundary; From bcee48fa41d53d8ddd4684cc8bdb013a85857246 Mon Sep 17 00:00:00 2001 From: andzdroid Date: Wed, 29 Jun 2016 16:03:41 +0100 Subject: [PATCH 33/40] Don't read body in HEAD requests --- src/Response.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Response.cs b/src/Response.cs index 22d51f1..f57b342 100644 --- a/src/Response.cs +++ b/src/Response.cs @@ -210,7 +210,7 @@ public void ReadFromStream( Stream inputStream ) AddHeader( parts[0], parts[1] ); } - } else { + } else if (request.method != "head") { // Read Body int contentLength = 0; From 3c8db7b606a9d13acb9c86bc4893a001ae6332a5 Mon Sep 17 00:00:00 2001 From: andzdroid Date: Wed, 29 Jun 2016 16:15:51 +0100 Subject: [PATCH 34/40] Fix case-sensitive request method check --- src/Response.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Response.cs b/src/Response.cs index f57b342..ac48e70 100644 --- a/src/Response.cs +++ b/src/Response.cs @@ -210,7 +210,7 @@ public void ReadFromStream( Stream inputStream ) AddHeader( parts[0], parts[1] ); } - } else if (request.method != "head") { + } else if (request.method.ToUpper() != "HEAD") { // Read Body int contentLength = 0; From f623acf0f1e6565c581e7f3c0dd51920bc2520ce Mon Sep 17 00:00:00 2001 From: Dmitry Radkovskiy Date: Wed, 19 Jul 2017 20:04:11 +0300 Subject: [PATCH 35/40] Fix Unity 2017 compiler define --- src/Request.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Request.cs b/src/Request.cs index 2d86473..e61bdfa 100644 --- a/src/Request.cs +++ b/src/Request.cs @@ -89,7 +89,7 @@ public Request( string method, string uri, WWWForm form ) this.method = method; this.uri = new Uri (uri); this.byteStream = new MemoryStream(form.data); -#if UNITY_5 +#if UNITY_5 || UNITY_5_3_OR_NEWER foreach ( var entry in form.headers ) { this.AddHeader( entry.Key, entry.Value ); From bf07dfaa34b9f1ccdb548298e1d44a62db673e17 Mon Sep 17 00:00:00 2001 From: "d.radkovskiy" Date: Fri, 8 Sep 2017 17:03:33 +0300 Subject: [PATCH 36/40] Added ILogger, ConsoleLogger, UnityLogger --- src/Logger.cs | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 src/Logger.cs diff --git a/src/Logger.cs b/src/Logger.cs new file mode 100644 index 0000000..cdf9f0e --- /dev/null +++ b/src/Logger.cs @@ -0,0 +1,52 @@ +using System; + +namespace UnityHTTP +{ + public interface ILogger + { + void Log(string msg); + void LogError(string msg); + void LogException(Exception e); + void LogWarning(string msg); + } +#if UNITY_EDITOR + public class UnityLogger : ILogger + { + public void Log(string msg) + { + UnityEngine.Debug.Log(msg); + } + public void LogError(string msg) + { + UnityEngine.Debug.LogError(msg); + } + public void LogException(Exception e) + { + UnityEngine.Debug.LogException(msg); + } + public void LogWarning(string msg) + { + UnityEngine.Debug.LogWarning(msg); + } + } +#endif + public class ConsoleLogger : ILogger + { + public void Log(string msg) + { + Console.WriteLine(msg); + } + public void LogError(string msg) + { + Console.WriteLine(msg); + } + public void LogException(Exception e) + { + Console.WriteLine(msg); + } + public void LogWarning(string msg) + { + Console.WriteLine(msg); + } + } +} \ No newline at end of file From 5663f4a0e5b8d17a22e74291bb8d776fc40ba25a Mon Sep 17 00:00:00 2001 From: "d.radkovskiy" Date: Fri, 8 Sep 2017 17:04:03 +0300 Subject: [PATCH 37/40] refactored Request to use UnityLogger/ConsoleLogger where appropriate --- src/Request.cs | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/src/Request.cs b/src/Request.cs index e61bdfa..38970b1 100644 --- a/src/Request.cs +++ b/src/Request.cs @@ -30,7 +30,14 @@ public class Request public static bool LogAllRequests = false; public static bool VerboseLogging = false; public static string unityVersion = Application.unityVersion; - public static string operatingSystem = SystemInfo.operatingSystem; + public static string operatingSystem = SystemInfo.operatingSystem; + public static ILogger logger = +#if !UNITY_EDITOR + new ConsoleLogger() +#else + new UnityLogger() +#endif + ; public CookieJar cookieJar = CookieJar.Instance; public string method = "GET"; @@ -184,13 +191,8 @@ private void GetResponse() { var ssl = ostream as SslStream; ssl.AuthenticateAsClient (uri.Host); } catch (Exception e) { -#if !UNITY_EDITOR - Console.WriteLine ("SSL authentication failed."); - Console.WriteLine (e); -#else - Debug.LogError ("SSL authentication failed."); - Debug.LogException(e); -#endif + logger.LogError ("SSL authentication failed."); + logger.LogException(e); return; } } @@ -220,13 +222,8 @@ private void GetResponse() { } } catch (Exception e) { -#if !UNITY_EDITOR - Console.WriteLine ("Unhandled Exception, aborting request."); - Console.WriteLine (e); -#else - Debug.LogError("Unhandled Exception, aborting request."); - Debug.LogException(e); -#endif + logger.LogError("Unhandled Exception, aborting request."); + logger.LogException(e); exception = e; response = null; } @@ -253,19 +250,19 @@ private void GetResponse() { if ( LogAllRequests ) { #if !UNITY_EDITOR - System.Console.WriteLine("NET: " + InfoString( VerboseLogging )); + logger.Log("NET: " + InfoString( VerboseLogging )); #else if ( response != null && response.status >= 200 && response.status < 300 ) { - Debug.Log( InfoString( VerboseLogging ) ); + logger.Log( InfoString( VerboseLogging ) ); } else if ( response != null && response.status >= 400 ) { - Debug.LogError( InfoString( VerboseLogging ) ); + logger.LogError( InfoString( VerboseLogging ) ); } else { - Debug.LogWarning( InfoString( VerboseLogging ) ); + logger.LogWarning( InfoString( VerboseLogging ) ); } #endif } @@ -340,9 +337,9 @@ public string Text { public static bool ValidateServerCertificate (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { #if !UNITY_EDITOR - System.Console.WriteLine( "NET: SSL Cert: " + sslPolicyErrors.ToString() ); + logger.LogWarning( "NET: SSL Cert: " + sslPolicyErrors.ToString() ); #else - Debug.LogWarning("SSL Cert Error: " + sslPolicyErrors.ToString ()); + logger.LogWarning("SSL Cert Error: " + sslPolicyErrors.ToString ()); #endif return true; } From 51b0b3da5d348ab783aaeffac2844981aa25dc60 Mon Sep 17 00:00:00 2001 From: "d.radkovskiy" Date: Fri, 8 Sep 2017 17:05:59 +0300 Subject: [PATCH 38/40] added loggers for every request --- src/Request.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Request.cs b/src/Request.cs index 38970b1..78a9478 100644 --- a/src/Request.cs +++ b/src/Request.cs @@ -55,6 +55,8 @@ public class Request public long responseTime = 0; // in milliseconds public bool synchronous = false; public int bufferSize = 4 * 1024; + + public ILogger logger = Request.logger; public Action< UnityHTTP.Request > completedCallback = null; From 2ba38524bdc5cd46134389f63d4e6361a8717a25 Mon Sep 17 00:00:00 2001 From: "d.radkovskiy" Date: Fri, 8 Sep 2017 17:19:25 +0300 Subject: [PATCH 39/40] compiler errors fixes --- src/Logger.cs | 4 ++-- src/Request.cs | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Logger.cs b/src/Logger.cs index cdf9f0e..193096f 100644 --- a/src/Logger.cs +++ b/src/Logger.cs @@ -22,7 +22,7 @@ public void LogError(string msg) } public void LogException(Exception e) { - UnityEngine.Debug.LogException(msg); + UnityEngine.Debug.LogException(e); } public void LogWarning(string msg) { @@ -42,7 +42,7 @@ public void LogError(string msg) } public void LogException(Exception e) { - Console.WriteLine(msg); + Console.WriteLine(e); } public void LogWarning(string msg) { diff --git a/src/Request.cs b/src/Request.cs index 78a9478..429a52d 100644 --- a/src/Request.cs +++ b/src/Request.cs @@ -31,7 +31,7 @@ public class Request public static bool VerboseLogging = false; public static string unityVersion = Application.unityVersion; public static string operatingSystem = SystemInfo.operatingSystem; - public static ILogger logger = + public static ILogger Logger = #if !UNITY_EDITOR new ConsoleLogger() #else @@ -56,7 +56,7 @@ public class Request public bool synchronous = false; public int bufferSize = 4 * 1024; - public ILogger logger = Request.logger; + public ILogger logger = Request.Logger; public Action< UnityHTTP.Request > completedCallback = null; @@ -339,9 +339,9 @@ public string Text { public static bool ValidateServerCertificate (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { #if !UNITY_EDITOR - logger.LogWarning( "NET: SSL Cert: " + sslPolicyErrors.ToString() ); + Logger.LogWarning( "NET: SSL Cert: " + sslPolicyErrors.ToString() ); #else - logger.LogWarning("SSL Cert Error: " + sslPolicyErrors.ToString ()); + Logger.LogWarning("SSL Cert Error: " + sslPolicyErrors.ToString ()); #endif return true; } From f41bad5587ab6fdb7703c1c60e4bd5490f638665 Mon Sep 17 00:00:00 2001 From: "d.radkovskiy" Date: Fri, 8 Sep 2017 17:21:30 +0300 Subject: [PATCH 40/40] added DiscardLogger --- src/Logger.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/Logger.cs b/src/Logger.cs index 193096f..d466a6f 100644 --- a/src/Logger.cs +++ b/src/Logger.cs @@ -49,4 +49,23 @@ public void LogWarning(string msg) Console.WriteLine(msg); } } + public class DiscardLogger : ILogger + { + public void Log(string msg) + { + // discard logs + } + public void LogError(string msg) + { + // discard logs + } + public void LogException(Exception e) + { + // discard logs + } + public void LogWarning(string msg) + { + // discard logs + } + } } \ No newline at end of file