<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Core Kotlin Archives - Codersee blog- Kotlin on the backend</title>
	<atom:link href="https://blog.codersee.com/tag/core-kotlin/feed/" rel="self" type="application/rss+xml" />
	<link></link>
	<description>Kotlin &#38; Backend Tutorials - Learn Through Practice.</description>
	<lastBuildDate>Wed, 16 Apr 2025 04:50:21 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://blog.codersee.com/wp-content/uploads/2025/04/cropped-codersee_logo_circle_2-32x32.png</url>
	<title>Core Kotlin Archives - Codersee blog- Kotlin on the backend</title>
	<link></link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>kotlinx.serialization in Kotlin- All You Need To Know</title>
		<link>https://blog.codersee.com/kotlinx-serialization-in-kotlin-all-you-need-to-know/</link>
					<comments>https://blog.codersee.com/kotlinx-serialization-in-kotlin-all-you-need-to-know/#respond</comments>
		
		<dc:creator><![CDATA[Peter Lantukh]]></dc:creator>
		<pubDate>Tue, 12 Dec 2023 06:00:00 +0000</pubDate>
				<category><![CDATA[Kotlin]]></category>
		<category><![CDATA[Core Kotlin]]></category>
		<category><![CDATA[kotlinx]]></category>
		<guid isPermaLink="false">https://codersee.com/?p=9008417</guid>

					<description><![CDATA[<p>In this article, we will cover the most important scenarios of kotlinx.serialization in Kotlin and how to use it to your advantage.</p>
<p>The post <a href="https://blog.codersee.com/kotlinx-serialization-in-kotlin-all-you-need-to-know/">kotlinx.serialization in Kotlin- All You Need To Know</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>If you are working with Kotlin, then it is a matter of time before you will face a need to <strong>serialize </strong>and <strong>deserialize </strong>your data.&nbsp;In this topic, I am going to cover the most important scenarios of <strong>kotlinx.serialization in Kotlin</strong> and how to use it to your advantage in your projects.</p>



<p>If you haven&#8217;t heard about it, then Kotlin Serialization is a <strong>cross-platform</strong> and multi-format framework built for this specific needs. It can be used with practically any Kotlin-based project, such as Android applications, Ktor applications, and Multiplatform (Common, JS, Native).&nbsp;</p>



<h2 class="wp-block-heading" id="h-setting-up">Setting Up</h2>



<p>To set up kotlinx.serialization in our project, we must add the following lines in your <strong>build.gradle.kts</strong>. </p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">plugins {

    kotlin("jvm") version "1.9.20" // or kotlin("multiplatform")

    kotlin("plugin.serialization") version "1.9.20"

}</pre>



<p>This will add the plugin. </p>



<p>Following, let&#8217;s add the implementation of the library itself:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">repositories {

    mavenCentral()

}

dependencies {

    implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.1")

}</pre>



<p>Now we&#8217;re ready to go!</p>



<h2 class="wp-block-heading" id="h-basic-serialization">Basic Serialization</h2>



<h3 class="wp-block-heading" id="h-simple-objects">Simple Objects</h3>



<p>You may not used this library yourself but you might have seen a <strong>@Serializable</strong> annotation before. </p>



<p>This is practically all we&#8217;re going to need to set up a serialization for a particular class, like this:&nbsp;</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Serializable
data class User(
  val userId: Int,
  val userName: String
)</pre>



<p>Now, to manually serialize it, we only need to use a <strong>Json.encodeToString()</strong>. </p>



<p>For example:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val data = User(userId = 1, userName = "Alice")
println(
  Json.encodeToString(data)
)</pre>



<p>The output would be the following:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="json" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{"userId":1,"userName":"Alice"}</pre>



<p>On the other hand, to deserialize something, we&#8217;ll use <strong>Json.decodeFromString()</strong>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val data = """  
  {
    "userId": 1,
    "userName":"Alice"
  }
"""  

println(
  Json.decodeFromString(
    User.serializer(), 
    data
  )
)</pre>



<p>The output:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="json" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">User(userId=1, userName=Alice)</pre>



<p>kotlinx.serialization has also some useful functions to work with <strong>InputStream</strong> rather than with <strong>String</strong>. However, they are experimental at the moment and require using <strong>@OptIn(ExperimentalSerializationApi::class)</strong>.  </p>



<p>What am I talking about here? The <strong>Json.encodeFromStream()</strong> and <strong>Json.decodeFromStream()</strong>, which come in handy when we are dealing with Files.</p>



<p>Let&#8217;s take a look at how we can get data from the file without reading it and converting it to String. It saves lots of computation time, particularly on a big scale:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@OptIn(ExperimentalSerializationApi::class)
fun deserializeFile(file: File): User {
  return Json.decodeFromStream(
    User.serializer(),
    file.inputStream()
  )
}</pre>



<p>Similarly, to encode it to a file we will use the <strong>encodeToStream</strong>:&nbsp;</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@OptIn(ExperimentalSerializationApi::class)
fun serializeFile(user: User, file: File) {
  Json.encodeToStream(
    User.serializer(),
    user,
    file.outputStream()
  )
}</pre>



<h3 class="wp-block-heading" id="h-nested-referenced-objects">Nested(Referenced) Objects</h3>



<p>As the next step, let&#8217;s talk about <strong>nested serialization</strong>. </p>



<p>Highly likely, that some of your classes have a property that is another class. </p>



<p>In such a case, there is practically no difference from the previous section, just all of our classes have to have a <strong>@Serializable</strong> annotation:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Serializable
data class Profile(
  val id: Int,
  val user: User
)

@Serializable
data class User(
  val userId: Int,
  val userName: String
)</pre>



<p>Let&#8217;s check it out like this:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val originalProfile = Profile(
  id = 123, 
  user = User(userId = 1, userName = "Alice")
)
  
println( 
  Json.encodeToString(
    Profile.serializer(), 
    originalProfile
  )
)  

val jsonString = """  
  {
    "id":123,
    "user": {
      "userId": 1,
      "userName":"Alice"
    }
  }
"""  

val deserializedProfile = Json.decodeFromString(
  Profile.serializer(), 
  jsonString
)
  
println(deserializedProfile)</pre>



<p>The output:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{"id":123,"user":{"userId":1,"userName":"Alice"}}
Profile(id=123, user=User(userId=1, userName=Alice))</pre>



<h3 class="wp-block-heading" id="h-lists">Lists</h3>



<p>To serialize the whole List, we can use the <strong>ListSerializer</strong> constructor to create a serializer for any type of list, as long as <strong>we provide a serializer for the element type</strong>. </p>



<p>For example:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val originalUsers = listOf(
  User(userId = 1, userName = "Alice"),
  User(userId = 2, userName = "Bob")
)  

println(
  Json.encodeToString(
    ListSerializer(User.serializer()), 
    originalUsers
  )
)  

val jsonString = """ 
  [
    {"userId":1,"userName":"Alice"},
    {"userId":2,"userName":"Bob"}
  ] 
"""  

val deserializedUsers = Json.decodeFromString(
  ListSerializer(User.serializer()), 
  jsonString
)  

println(deserializedUsers)</pre>



<p>That code will give us:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="json" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">[{"userId":1,"userName":"Alice"},{"userId":2,"userName":"Bob"}]
[User(userId=1, userName=Alice), User(userId=2, userName=Bob)]</pre>



<h3 class="wp-block-heading" id="h-generics">Generics</h3>



<p>Basically, generics serialization works the same as nested objects. </p>



<p>The kotlinx.serialization has type-polymorphic behavior, which means that JSON relies on the actual type parameter. It will be compiled successfully if the actual generic type is a serializable class. </p>



<p>To check that, let&#8217;s modify our classes:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Serializable
data class Profile&lt;T>(
  val id: T,
  val user: Wrapper&lt;T>
)

@Serializable
data class Wrapper&lt;T>(val contents: T)</pre>



<p>Now we can check how it will work with different T for user fields:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val profile1 = Profile(
  1, 
  Wrapper(
    User(userId = 1, userName = "Alice")
  )
)  
val profile2 = Profile(
  2, 
  Wrapper(42)
)  
  
val jsonProfile1 = Json.encodeToString(profile1)  
val jsonProfile2 = Json.encodeToString(profile2)  
  
println(jsonProfile1)  
println(jsonProfile2)  
  
val jsonString1 = """ 
  {
    "id": 1,
    "user": {
      "contents": {
        "userId": 1,
        "userName": "Alice"
      }
    }
  } 
"""  
val jsonString2 = """ 
  {
    "id": 2,
    "user": {
      "contents": 42
    }
  } 
"""  
  
val deserializedProfile1 = Json.decodeFromString(
  Profile.serializer(
    User.serializer()
  ),
  jsonString1
)  
val deserializedProfile2 = Json.decodeFromString(
  Profile.serializer(
    Int.serializer()
  ), 
  jsonString2
)  
  
println(deserializedProfile1)  
println(deserializedProfile2)</pre>



<p>There will be the following output:&nbsp;</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{"id":1,"user":{"contents":{"userId":1,"userName":"Alice"}}}
{"id":2,"user":{"contents":42}}
Profile(id=1, user=Wrapper(contents=User(userId=1, userName=Alice)))
Profile(id=2, user=Wrapper(contents=42))</pre>



<h2 class="wp-block-heading" id="h-customizing-serialization-and-deserialization">Customizing serialization and deserialization</h2>



<p>In this paragraph, we are gonna talk about making your objects a little bit appealing with variable behavior to adjust our specific needs.</p>



<h3 class="wp-block-heading" id="h-custom-names">Custom names</h3>



<p>As you have noticed, the basic name of a field is taken by default. </p>



<p>To create a custom name, the only thing we need is a <strong>@SerialName</strong> annotation:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Serializable
data class User(
  @SerialName("id") val userId: Int,
  @SerialName("login") val userName: String
)</pre>



<p>Now let&#8217;s use it as we used in the example at the beginning:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val data = User(userId = 1, userName = "Alice")
println(
  Json.encodeToString(data)
)</pre>



<p>We&#8217;ll get:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="json" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{"id":1,"login":"Alice"}</pre>



<p>But we must be careful- this works both ways. </p>



<p>After the change, we must make sure that the incoming JSON contains the names that we mentioned in the <strong>@SerialName</strong>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val data = """{"id":1,"login":"Alice"}"""         //correct
val data = """{"userId":1,"userName":"Alice"}"""  //wrong</pre>



<h3 class="wp-block-heading" id="h-default-values">Default values</h3>



<p>Now things get a little bit trickier. Default values are not encoded by default. </p>



<p>So, if we want them to, we need the <strong>@EncodeDefault</strong> annotation:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Serializable
data class User(
  val userId: Int,
  @EncodeDefault val userName: String = "user"
)</pre>



<p>This way, we could omit a userName and the serialization library will use the default value:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val data = User(userId = 1)
println(
  Json.encodeToString(data)
)</pre>



<p>Let&#8217;s see:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="json" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{"userId":1,"userName":"user"}</pre>



<p>Excellent, works as expected!</p>



<p>But here is a different situation. What if we want to deserialize a JSON with some optional fields? </p>



<p>For it to compile properly, we must provide a default value for these fields:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Serializable
data class User(
  val userId: Int,
  val userName: String = "user"
)</pre>



<p>Now we can deserialize an object like this:&nbsp;</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val data = """
  {
    "userId": 1
  }
"""
  
println(
  Json.decodeFromString(
    User.serializer(),
    data
  )
)</pre>



<p>Output:&nbsp;</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">User(userId=1, userName=user)</pre>



<p>On the other hand, if we want an optional field to be present in JSON, we may use a <strong>@Required</strong> annotation:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Serializable
data class User(
  val userId: Int,
  @Required val userName: String = "user"
)</pre>



<p>If we use this class with the code before, <strong>we will get an error</strong>, which can be useful in some scenarios:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p></p>
<cite>Exception in thread &#8220;main&#8221; kotlinx.serialization.MissingFieldException: Field &#8216;userName&#8217; is required for type with serial name &#8216;com.example.User&#8217;, but it was missing</cite></blockquote>



<h3 class="wp-block-heading" id="h-nulls">Nulls</h3>



<p>Kotlin&#8217;s language is known for its type safety. The kotlinx.serialization knows it as well. </p>



<p>We cannot decode a null value into a non-nullable property or we get an exception. For example, for this class:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Serializable
data class User(
  val userId: Int,
  val userName: String
)</pre>



<p>We cannot expect to serialize this object below:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val data = """
  {
    "userId": 1,
     "userName": null
  }
"""
  
println(
  Json.decodeFromString(
    User.serializer(),
    data
  )
)</pre>



<p>It will result in an error.</p>



<p>To avoid it, we should do this instead:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Serializable
data class User(
  val userId: Int,
  val userName: String?
)</pre>



<p>This time, our result will be:&nbsp;</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">User(userId=1, userName=null)</pre>



<p>As we can see, default values are not encoded by default. </p>



<p>So to get a missing property from JSON not as an optional but as a null value, we have to use <strong>@EncodeDefault</strong>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Serializable
data class User(
  val userId: Int,
  @EncodeDefault val userName: String? = null
)</pre>



<p>That is what we&#8217;ll see for our class:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{"userId":1,"userName":null}</pre>



<p>However, if we forget the annotation, this is what we will get:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{"userId":1}</pre>



<h2 class="wp-block-heading" id="h-advanced-serialization">Advanced Serialization</h2>



<p>This section is probably what you are looking for if you have a complex project. </p>



<p>These are the most sophisticated tricks of kotlinx.serialization, but the most useful, though. And now we are going to understand how they work.</p>



<p>From now on everything becomes more complex. So we have to establish ground rules and basic terms. </p>



<h3 class="wp-block-heading" id="h-what-exactly-is-a-polymorphism">What Exactly Is a Polymorphism?</h3>



<p>Polymorphism in Kotlin is the ability of an object or a function to have different forms or behaviors depending on the context. A polymorphic object can belong to different classes and respond to the same method call in different ways. </p>



<p>There are two types of polymorphism in Kotlin: <strong>compile-time</strong> and <strong>run-time</strong>:</p>



<ul class="wp-block-list">
<li><strong>Compile-time</strong> polymorphism, also known as static polymorphism, is achieved through function overloading. It allows the name of functions, i.e., the signature, to be the same but return type or parameter lists to be different.</li>



<li><strong>Run-time </strong>polymorphism, or <strong>dynamic </strong>polymorphism, is achieved through function overriding and inheritance. In the run-time polymorphism, the compiler resolves a call to overload methods at the runtime.</li>
</ul>



<p>But there is more. For serialization, we are going to talk about different approaches. To serialize an object, we should know what that object is in the first place and can its behavior can be changed. So there are 2 more types of polymorphism:</p>



<ul class="wp-block-list">
<li><strong>Closed</strong> polymorphism means that the behavior of an object is fixed and cannot be changed by subclasses or external factors.</li>



<li><strong>Open</strong> polymorphism means that the behavior of an object can be modified or extended by subclasses or external factors.<br>This is how the library sees polymorphism for the most part.</li>
</ul>



<h3 class="wp-block-heading" id="h-the-practice-part">The Practice Part</h3>



<p>First things first, let&#8217;s talk about <strong>closed </strong>polymorphism in kotlinx.serialization. </p>



<p>The first and the most obvious thing to do is to make all of our classes serializable:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Serializable
open class User(
  val userId: Int,
  val userName: String?
)

@Serializable
@SerialName("admin")
class Admin(
  val adminId: Int,
  val adminName: String?,
  val adminRole: String
) : User(adminId, adminName)</pre>



<p>Let&#8217;s check it out:&nbsp;</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fun serializeAdmin() {
  val admin: User = Admin(
    adminId = 1,
    adminName = "Alice",
    adminRole = "Boss"
  )

  println(
    Json.encodeToString(admin)
  )
}</pre>



<p>Everything works as expected, our Admin is indeed a user:&nbsp;</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{"userId":1,"userName":"Alice"}</pre>



<p>But what will happen if we try to serialize an Admin object:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fun serializeAdmin() {
  val admin = Admin(
    adminId = 1,
    adminName = "Alice",
    adminRole = "Boss"
  )

  println(
    Json.encodeToString(admin)
  )
}</pre>



<p>Let&#8217;s find out:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{"userId":1,"userName":"Alice","adminId":1,"adminName":"Alice","adminRole":"Boss"}</pre>



<p>So you have to keep that in mind. This may be a bit odd.<br>Following this, I want to cover <strong>sealed classes</strong> as well. Not because I&#8217;m a huge fan of it, which I am, but because of its natural behavior (we know all of its children at the runtime) that helps our process:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Serializable
sealed class User {
  abstract val userId: Int
  abstract val userName: String?
}

@Serializable
@SerialName("admin")
class Admin(
  override val userId: Int,
  override val userName: String?,
  val adminRole: String
) : User()</pre>



<p>We are going to check our first scenario:&nbsp;</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fun serializeAdmin() {
  val admin: User = Admin(
    userId = 1,
    userName = "Alice",
    adminRole = "Boss"
  )

  println(
    Json.encodeToString(admin)
  )
}</pre>



<p>As expected, now we know the type of our user beforehand:&nbsp;</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{"type":"admin","userId":1,"userName":"Alice","adminRole":"Boss"}</pre>



<p>For a <strong>closed</strong> polymorphism, things get different. Now we have to create a <strong>SerializersModule</strong> and provide explicit subclasses that are to be serialized.</p>



<p>Let&#8217;s create an additional class to show this in action:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Serializable
abstract class User {
  abstract val userId: Int
  abstract val userName: String?
}

@Serializable
@SerialName("admin")
class Admin(
  override val userId: Int,
  override val userName: String?,
  val adminRole: String
) : User()

@Serializable
@SerialName("guest")
class Guest(
  override val userId: Int,
  override val userName: String?,
  val guestEmail: String?
) : User()</pre>



<p>Now comes the module:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val module = SerializersModule {
  polymorphic(User::class) {
    subclass(Admin::class, Admin.serializer())
    subclass(Guest::class, Guest.serializer())
  }
}</pre>



<p>We&#8217;ve used a <strong>Json</strong> instance for our needs before. Now we have to create a specific instance with our module:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val format = Json { serializersModule = module }</pre>



<p>With that done, let&#8217;s check it:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fun serializeAdmin() {
  val admin: User = Admin(
    userId = 1,
    userName = "Alice",
    adminRole = "Boss"
  )
  val guest: User = Guest(
    userId = 1,
    userName = "Alice",
    guestEmail = "guest@email.com"
  )

  println(format.encodeToString(admin))
  println(format.encodeToString(guest))
}</pre>



<p>And this time, we get the following results:&nbsp;</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{"type":"admin","userId":1,"userName":"Alice","adminRole":"Boss"}
{"type":"guest","userId":1,"userName":"Alice","guestEmail":"guest@email.com"}</pre>



<p>We can serialize classes as long as we provide corresponding subclasses. </p>



<p>Of course, there is a lot to cover, for example, multiple superclasses or interfaces. But let&#8217;s stop here, maybe I&#8217;ll cover it explicitly in the other article. (Let me know if you are interested in this 🙂 ) </p>



<h3 class="wp-block-heading" id="h-custom-serializers">Custom serializers</h3>



<p>For some classes, happens that the default serialization method does not fulfill our needs. Or we want to create one that reflects a unique class utilization approach. For this purpose, <strong>custom serializers</strong> are our best friends. The most common examples are Date and Color. I&#8217;m gonna focus on Date.</p>



<p>Basically, there are 3 main parts of our custom serializer. Let&#8217;s check how the serializer for Date might look like:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">object DateSerializer : KSerializer&lt;Date> {
  private val dateFormat = SimpleDateFormat("yyyy-MM-dd 'T' HH:mm:ss.SSSZ")

  override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Date", PrimitiveKind.STRING)

  override fun serialize(encoder: Encoder, value: Date) {
    encoder.encodeString(dateFormat.format(value))
  }

  override fun deserialize(decoder: Decoder): Date {
    return dateFormat.parse(decoder.decodeString())
  }
}</pre>



<p>We can already see all the necessary parts.</p>



<ul class="wp-block-list">
<li>The <strong>serialize</strong> function is used to turn an object into a sequence of simple values. It takes an Encoder and a value as inputs. It calls the encodeXxx functions of the Encoder to make the sequence. There is a different encodeXxx function for each simple type.</li>



<li>The <strong>deserialize</strong> function is used to turn a sequence of simple values back into an object. It takes a Decoder as input and returns a value. It calls the decodeXxx functions of the Decoder to get the sequence. These functions match the encodeXxx functions of the Encoder.</li>



<li>The <strong>descriptor</strong> property is used to tell how the encodeXxx and decodeXxx functions work. This helps the format to know what methods to use. Some formats can also use it to make a schema for the data.</li>
</ul>



<p>For our purposes, we can simplify the class. If there is no particular need in the <strong>descriptor</strong>, we can use a <strong>@Serializer(forClass = …)</strong>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Serializer(forClass = Date::class)
object DateSerializer : KSerializer&lt;Date> {
  private val dateFormat = SimpleDateFormat("yyyy-MM-dd 'T' HH:mm:ss.SSSZ")

  override fun serialize(encoder: Encoder, value: Date) {
    encoder.encodeString(dateFormat.format(value))
  }

  override fun deserialize(decoder: Decoder): Date {
    return dateFormat.parse(decoder.decodeString())
  }
}</pre>



<p>To implement our custom serializer we should use a <strong>@Serializable(with = …)</strong> annotation for the corresponding property:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Serializable
data class Event(
  val name: String,
  @Serializable(with = DateSerializer::class)
  val date: Date
)</pre>



<p>Let&#8217;s see that in action:&nbsp;</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val event = Event("Birthday Party", Date())  

val json = Json.encodeToString(event)  

println(json)</pre>



<p>With the result:&nbsp;</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{"name":"Birthday Party","date":"2023-11-23 T 17:12:36.069+0300"}</pre>



<p>As we can see, it has successfully been serialized to the desired date format.</p>



<h3 class="wp-block-heading" id="h-contextual-serialization">Contextual serialization</h3>



<p>Sometimes we need to change how we write objects as JSON at run-time, not just at compile-time, as we spoke before. This is called contextual serialization. </p>



<p>We can use the <strong>@Contextual</strong> annotation on a class or a property to tell Kotlin to use the ContextualSerializer class. This class will choose the right serializer for the object based on the context. We are going to use the previous serializer:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">object DateAsStringSerializer : KSerializer&lt;Date> {
  private val dateFormat = SimpleDateFormat("yyyy-MM-dd 'T' HH:mm:ss.SSSZ")

  override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Date", PrimitiveKind.STRING)

  override fun serialize(encoder: Encoder, value: Date) {
    encoder.encodeString(dateFormat.format(value))
  }

  override fun deserialize(decoder: Decoder): Date {
    return dateFormat.parse(decoder.decodeString())
  }
}</pre>



<p>And our class will be looking like this:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Serializable
data class Event(
  val name: String,
  @Contextual val date: Date
)</pre>



<p>Now we need to create a <strong>SerializersModule</strong> in which we need to specify a serializers should be used for our contextually-serializable classes. </p>



<p>We can simply wrap our serializer in <strong>contextual</strong> function inside the module:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">private val module = SerializersModule {
  contextual&lt;Date>(DateAsStringSerializer)
}  </pre>



<p>Now we create a format out of Json with our module: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val format = Json { serializersModule = module }</pre>



<p>Using our format of <strong>Json</strong> earlier, we&#8217;ll get our run-time serialization:&nbsp;</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val event = Event("Birthday Party", Date())  

val json = format.encodeToString(event)  

println(json)</pre>



<p>With an expected output:&nbsp;</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{"name":"Birthday Party","date":"2023-11-23 T 23:20:03.421+0300"}</pre>



<p></p>



<h2 class="wp-block-heading" id="h-kotlinx-serialization-summary">kotlinx.serialization Summary</h2>



<p>And that&#8217;s all for this article about <strong>serialization in Kotlin with kotlinx.serialization</strong>.</p>



<p>In the upcoming articles, we will get back to this topic and learn how to apply this knowledge with Ktor, so don&#8217;t forget to join the <a href="https://codersee.com/newsletter/">free newsletter</a> to not miss it!</p>



<p>Lastly, if you would like to learn more about kotlinx, then you can find lots of useful information on the official documentation of <a href="https://github.com/Kotlin/kotlinx.serialization" target="_blank" rel="noreferrer noopener">kotlinx</a>.&nbsp;</p>
<p>The post <a href="https://blog.codersee.com/kotlinx-serialization-in-kotlin-all-you-need-to-know/">kotlinx.serialization in Kotlin- All You Need To Know</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.codersee.com/kotlinx-serialization-in-kotlin-all-you-need-to-know/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Scope Control With @DslMarker Annotation. Kotlin DSLs.</title>
		<link>https://blog.codersee.com/scope-control-dslmarker-kotlin-dsl/</link>
					<comments>https://blog.codersee.com/scope-control-dslmarker-kotlin-dsl/#respond</comments>
		
		<dc:creator><![CDATA[Piotr]]></dc:creator>
		<pubDate>Tue, 07 Nov 2023 13:35:19 +0000</pubDate>
				<category><![CDATA[Kotlin]]></category>
		<category><![CDATA[Annotations]]></category>
		<category><![CDATA[Core Kotlin]]></category>
		<category><![CDATA[Kotlin DSL]]></category>
		<guid isPermaLink="false">https://codersee.com/?p=9008328</guid>

					<description><![CDATA[<p>This time, I will show you how to control scope with @DslMarker annotation when creating your DSLs in Kotlin.</p>
<p>The post <a href="https://blog.codersee.com/scope-control-dslmarker-kotlin-dsl/">Scope Control With @DslMarker Annotation. Kotlin DSLs.</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Hello and welcome to the next lesson! This time, I will show you how to <strong>control scope with @DslMarker</strong> annotation when creating your DSLs in Kotlin. </p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p></p>
<cite>Note: this article is based on my Complete <a href="https://codersee.com/the-complete-kotlin-course/">Kotlin Course</a> lesson, which I highly encourage you to check out if you are looking for a comprehensive Kotlin guide. </cite></blockquote>



<p>If this is your first meeting with DSLs, then I would recommend you to check out my other article, in which I explain and show how to <a href="https://blog.codersee.com/kotlin-type-safe-builders-make-your-custom-dsl/">implement Kotlin DSL</a> step-by-step.</p>



<h2 class="wp-block-heading" id="h-video-tutorial">Video Tutorial</h2>



<p>If you prefer <strong>video content</strong>, then check out my video:</p>



<div style="text-align: center; width: 90%; margin-left: 5%;">
<a href="https://blog.codersee.com/scope-control-dslmarker-kotlin-dsl/"><img decoding="async" src="https://blog.codersee.com/wp-content/plugins/wp-youtube-lyte/lyteCache.php?origThumbUrl=%2F%2Fi.ytimg.com%2Fvi%2FuItQGNnbUXo%2Fhqdefault.jpg" alt="YouTube Video"></a><br /><br /></p></div>



<p>If you find this content useful,<strong> please leave a subscription&nbsp;</strong> 😉</p>



<h2 class="wp-block-heading" id="h-uncontrolled-scope">Uncontrolled Scope</h2>



<p>But before we dive into the solution with Kotlin @DslMarker, let&#8217;s understand what problem it solves first. </p>



<p>So as the first step, let&#8217;s prepare a simple DSL with <code>Board</code>, <code>Task</code>, <code>Author</code>, and <code>Comment</code> classes:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">enum class BoardColor {
  BLACK, WHITE, GREEN, BLUE
}

class Board {
  var title: String = ""
  var color: BoardColor = BoardColor.BLUE
  val tasks: MutableList&lt;Task> = mutableListOf()

  fun task(init: Task.() -> Unit) {
    val task = Task().apply(init)
    tasks.add(task)
  }
}

class Task {
  var title: String = ""
  var description: String = ""
  val comments: MutableList&lt;Comment> = mutableListOf()

  fun comment(init: Comment.() -> Unit) {
    val comment = Comment().apply(init)
    comments.add(comment)
  }
}

class Comment {
  var comment: String = ""
  var author: Author = Author()

  fun author(init: Author.() -> Unit) {
    val author = Author().apply(init)
    this.author = author
  }
}

class Author {
  var name: String = ""
}

fun board(init: Board.() -> Unit): Board =
  Board()
    .apply(init)</pre>



<p>With the following Kotlin DSL implementation, we would expect that we could introduce different Boards, with Tasks inside them, which would have some Comments written by Authors. </p>



<p>But let&#8217;s take a look at the following code: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fun main() {
  val board = board {
    task {
      task {
        task {
          comment {
            task { }
            author {
              task { }
              comment {
                task { }
              }
            }
          }
        }
      }
    }
  }
}</pre>



<p>Will it compile? <strong>Unfortunately, yes</strong>.</p>



<p>We invoke a <em>task</em> within a <em>task</em>, within a <em>task</em>, and so on. Moreover, we can invoke the <em>task</em>, or <em>comment</em> functions inside the <em>author</em>.&nbsp;</p>



<p>And that&#8217;s because, <strong>by default, we can call the methods of every available receive</strong>r, which can lead to such situations.&nbsp;</p>



<h2 class="wp-block-heading" id="h-kotlin-dslmarker-to-the-rescue">Kotlin @DslMarker To The Rescue</h2>



<p>At this point, we already know what the issue is and what we will use to fix it. </p>



<p>But what exactly does the @DslMarker do in Kotlin? </p>



<p>Well, in practice, we use this annotation to introduce our new custom annotations. Then, we make use of them to mark classes and receivers, thus preventing receivers marked with the same annotation from being accessed inside one another.</p>



<p>This way, we won’t be able to access members of the outer receiver (like the&nbsp;<em>task&nbsp;</em>function, which is declared inside the&nbsp;<em>Board</em> class from the <em>Task</em> class instances).</p>



<p>Let&#8217;s consider the updated example: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@DslMarker
annotation class BoardDsl

enum class BoardColor {
  BLACK, WHITE, GREEN, BLUE
}

@BoardDsl
class Board {
  var title: String = ""
  var color: BoardColor = BoardColor.BLUE
  val tasks: MutableList&lt;Task> = mutableListOf()

  fun task(init: Task.() -> Unit) {
    val task = Task().apply(init)
    tasks.add(task)
  }
}

@BoardDsl
class Task {
  var title: String = ""
  var description: String = ""
  val comments: MutableList&lt;Comment> = mutableListOf()

  fun comment(init: Comment.() -> Unit) {
    val comment = Comment().apply(init)
    comments.add(comment)
  }
}

@BoardDsl
class Comment {
  var comment: String = ""
  var author: Author = Author()

  fun author(init: Author.() -> Unit) {
    val author = Author().apply(init)
    this.author = author
  }
}

@BoardDsl
class Author {
  var name: String = ""
}

fun board(init: Board.() -> Unit): Board =
  Board()
    .apply(init)

fun main() {
  val board = board {
    task {  // OK
      task {  // Does not compile
        task {  // Does not compile
          comment {  // OK
            task { }  // Does not compile
            author {  // OK
              task { }  // Does not compile
              comment {  // Does not compile
                task { }  // Does not compile
              }
            }
          }
        }
      }
    }
  }
}</pre>



<p>Firstly, we introduce the <code>@BoardDsl</code> annotation, which uses the <code>@DslMarker</code>. </p>



<p>Following, we must annotate every class in our hierarchy with our new annotation- this way, we make the Kotlin compiler &#8220;aware&#8221; of the hierarchy in our DSL. </p>



<p>Lastly, we can clearly see that the code <strong>will not compile</strong> whenever we try to nest the unwanted type inside another. </p>



<h2 class="wp-block-heading" id="h-scope-control-with-kotlin-dslmarker-summary">Scope Control With Kotlin @DslMarker Summary</h2>



<p>Basically, that&#8217;s all for this tutorial on <strong>how to control scope</strong> when implementing a <strong>Kotlin DSL</strong> using the <strong>@DslMarker </strong>summary.</p>



<p>If you enjoy such a short, practice-focused learning approach then do not forget to check out my course and let me know in the comments section. </p>



<p>If you&#8217;d like to learn a bit more about the annotation itself, then the <a href="https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-dsl-marker/" target="_blank" rel="noreferrer noopener">documentation</a> may be useful to you too. </p>
<p>The post <a href="https://blog.codersee.com/scope-control-dslmarker-kotlin-dsl/">Scope Control With @DslMarker Annotation. Kotlin DSLs.</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.codersee.com/scope-control-dslmarker-kotlin-dsl/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Generate Kotlin Client From OpenAPI Specs</title>
		<link>https://blog.codersee.com/generate-kotlin-client-from-openapi-specs/</link>
					<comments>https://blog.codersee.com/generate-kotlin-client-from-openapi-specs/#respond</comments>
		
		<dc:creator><![CDATA[Piotr]]></dc:creator>
		<pubDate>Tue, 03 Oct 2023 06:31:24 +0000</pubDate>
				<category><![CDATA[Kotlin]]></category>
		<category><![CDATA[CodeGeneration]]></category>
		<category><![CDATA[Core Kotlin]]></category>
		<category><![CDATA[OpenAPI]]></category>
		<category><![CDATA[OpenApiGenerator]]></category>
		<guid isPermaLink="false">https://codersee.com/?p=9007627</guid>

					<description><![CDATA[<p>In this article, we will see how easily we can generate a Kotlin client from any OpenAPI Spec (both 2.0 and 3.0) and save hours of work. </p>
<p>The post <a href="https://blog.codersee.com/generate-kotlin-client-from-openapi-specs/">Generate Kotlin Client From OpenAPI Specs</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Hey hey hey 🙂 ! In this article, I will show you how easily we can <strong>generate a Kotlin client from any OpenAPI Spec</strong> (both 2.0 and 3.0) and save us hours of work. </p>



<p>During this tutorial, we will learn: </p>



<ul class="wp-block-list">
<li>what are OpenAPI specs and what problem do they solve,</li>



<li>why and when code generation might be a good idea for your project, </li>



<li>how to generate Kotlin clients using different libraries, like Ktor, Retrofit, or Spring WebClient. </li>
</ul>



<h2 class="wp-block-heading" id="h-video-tutorial">Video Tutorial</h2>



<p>If you prefer <strong>video content</strong>, then check out my video:</p>



<div style="text-align: center; width: 90%; margin-left: 5%;">
<p></p></div>


<a href="https://blog.codersee.com/generate-kotlin-client-from-openapi-specs/"><img decoding="async" src="https://blog.codersee.com/wp-content/plugins/wp-youtube-lyte/lyteCache.php?origThumbUrl=%2F%2Fi.ytimg.com%2Fvi%2FGFNuLkRnUl8%2Fhqdefault.jpg" alt="YouTube Video"></a><br /><br /></p>



<p>If you find this content useful,<strong> please leave a subscription&nbsp;</strong> 😉</p>



<h2 class="wp-block-heading" id="h-what-are-openapi-specs">What are OpenAPI Specs</h2>



<p>OpenAPI, formerly known as Swagger, is a specification for describing and documenting RESTful APIs. </p>



<p>Imagine that each person or team would describe created APIs in their own, custom manner. Confluence pages, READMEs, text files, graphic charts, and many many more. Probably millions of different ways to describe the same thing. </p>



<p>Thankfully, OpenAPI solves this problem and allows us to describe and document HTTP APIs in a <strong>standardized manner</strong> so that both the creators and consumers can be on the same page. </p>



<p>What does it look like? Well, let&#8217;s take a look at the example we will be working with today:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="yaml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">openapi: 3.0.0
info:
  version: 1.0.0
  title: JSON Placeholder API
  description: See https://jsonplaceholder.typicode.com/
paths:
  /posts:
    get:
      description: Returns all posts
      tags: ["Posts"]
      operationId: "getPosts"
      responses:
        "200":
          description: Successful response
          content:
            "application/json":
              schema:
                $ref: "#/components/schemas/PostsList"

  /posts/{id}:
    get:
      description: Returns a post by id
      tags: ["Posts"]
      operationId: "getPost"
      parameters:
        - name: id
          in: path
          required: true
          description: The user id.
          schema:
            type: integer
            format: int64
      responses:
        "200":
          description: Successful response
          content:
            "application/json":
              schema:
                $ref: "#/components/schemas/Post"
        "404":
          description: Post not found

components:
  schemas:
    PostsList:
      "type": "array"
      "items":
        $ref: "#/components/schemas/Post"
    Post:
      "type": "object"
      "required":
        - "id"
        - "userId"
        - "title"
      "properties":
        id:
          type: "integer"
        userId:
          type: "integer"
        title:
          type: "string"
        completed:
          type: "boolean"
</pre>



<p>As we can see, the OpenAPI spec is a <strong>YAML </strong>file (but can be a <strong>JSON </strong>too) which is a language-agnostic instruction of the API. </p>



<p>Moreover, given its standardized structure and format, it can be easily read not only by humans, but machines too, which we will see in this article in action 🙂 </p>



<h2 class="wp-block-heading" id="h-when-and-why-code-generation-might-be-a-good-idea">When And Why Code Generation Might Be A Good Idea? </h2>



<p>As software engineers, we automate things, so that they can be done faster, easier, and with less amount of errors. </p>



<p>You probably see where I&#8217;m going now 🙂 </p>



<p>Whenever we do things manually, we need more time, we make more mistakes, and we distract ourselves from things that we are actually good at. </p>



<p>And among plenty of areas in our codebase, HTTP clients might be a good place to start with. This is the area, where the only thing that we care about is fetching/sending the data in an appropriate format, and where we end up with lots of boilerplate code. </p>



<h2 class="wp-block-heading" id="h-solution-openapi-generator">Solution- OpenAPI Generator</h2>



<p>And in order to generate a client in Kotlin we can use the <a href="https://openapi-generator.tech/" target="_blank" rel="noreferrer noopener">OpenAPI generator</a>.</p>



<p>And although in this article we will focus on the clients, this generator can be used to create servers and documentation for over 50 languages and frameworks, too.  If you would like to check the full list, then you can find it <a href="https://openapi-generator.tech/docs/generators/#client-generators" target="_blank" rel="noreferrer noopener">right here</a>.</p>



<p>But how exactly it is going to help us? </p>



<p>Well, in simple words, with this tool we can convert the OpenAPI specification file into the ready-to-use Kotlin classes with WebClient/OkHTTP/Retrofit implementation of HTTP clients and data classes for response and request objects. </p>



<h2 class="wp-block-heading" id="h-generate-kotlin-client-gradle">Generate Kotlin Client- Gradle</h2>



<p>One of the easiest ways to add the OpenAPI generator to our codebase will be the <a href="https://github.com/OpenAPITools/openapi-generator/blob/master/modules/openapi-generator-gradle-plugin/README.adoc" target="_blank" rel="noreferrer noopener">Gradle plugin</a>.</p>



<p>Let&#8217;s navigate to the <code>build.gradle.kts</code> file and add the following:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">plugins {
    // other plugins
    id("org.openapi.generator") version "7.0.1"
}</pre>



<p>Nextly, let&#8217;s sync our project. </p>



<p>When it&#8217;s done, we will see the following tasks added to our project: </p>



<ul class="wp-block-list">
<li><strong>openApiGenerate</strong>&#8211; to generate code via Open API Tools Generator for Open API 2.0 or 3.x specification documents,</li>



<li><strong>openApiGenerators</strong>&#8211; to lists generators available via Open API Generators,</li>



<li><strong>openApiMeta</strong>&#8211; to generate a new generator to be consumed via Open API Generator,</li>



<li><strong>openApiValidate</strong>&#8211; which we can use to validate an Open API 2.0 or 3.x specification document.</li>
</ul>



<h2 class="wp-block-heading" id="h-add-openapi-spec-to-the-project">Add OpenAPI Spec To The Project</h2>



<p>As the next step, let&#8217;s add the OpenAPI spec to the project.</p>



<p>In our example, we will use the <code>json-placeholder-api.yaml</code> file we saw already and put it inside the <code>$root/openapi</code> directory. </p>



<p>Following, let&#8217;s navigate to <code>build.gradle.kts</code> and alter the <code>openApiGenerate</code> task: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">openApiGenerate {
    inputSpec.set("$rootDir/openapi/json-placeholder-api.yaml")
    generatorName.set("kotlin")
}</pre>



<p>The above configs are the <strong>only</strong> two required settings: we need to specify the input spec and the generator we would like to use. </p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p></p>
<cite>Note: at the moment, we can specify <strong>only one input spec</strong> (and quite possible it will be already fixed by the time you will read this blog post). But if that&#8217;s not the case, then you can use the <a href="https://github.com/kpramesh2212/openapi-merger-plugin" target="_blank" rel="noreferrer noopener">merger plugin</a>. </cite></blockquote>



<p>And if you are wondering what library will the &#8220;Kotlin&#8221; generator use by default, then at the moment of writing, it is <strong>OkHttp 4.2.0</strong>.</p>



<h2 class="wp-block-heading" id="h-change-the-http-client-library">Change the HTTP Client Library</h2>



<p>But can we change the HTTP client library? Yes, of course.</p>



<p>We can use one of the following instead: </p>



<ul class="wp-block-list">
<li>jvm-ktor</li>



<li>jvm-okhttp4 (default)</li>



<li>jvm-okhttp3</li>



<li>jvm-spring-webclient</li>



<li>jvm-retrofit2</li>



<li>multiplatform</li>



<li>jvm-volley</li>



<li>jvm-vertx</li>
</ul>



<p>And the only thing we need to do with our gradle plugin is to set the <code>library</code> property:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">openApiGenerate {
    inputSpec.set("$rootDir/openapi/json-placeholder-api.yaml")
    generatorName.set("kotlin")

    library.set("jvm-retrofit2")
}</pre>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p></p>
<cite>Of course, we can customize plenty of other settings in the OpenAPI generator plugin. To see the whole list of available properties, please refer to the <a href="https://openapi-generator.tech/docs/generators/kotlin/" target="_blank" rel="noreferrer noopener">Kotlin generator docs</a>.</cite></blockquote>



<p>Moreover, it&#8217;s worth mentioning that the generator plugin <strong>does not import </strong>necessary dependencies to the project. It is our responsibility and depending on the library we need to add them to the project.</p>



<p>For example, when dealing with the default client we must import <code>okhttp3</code> and <code>moshi</code>: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">dependencies {
    implementation("com.squareup.okhttp3:okhttp:4.11.0")
    implementation("com.squareup.moshi:moshi:1.15.0")
    implementation("com.squareup.moshi:moshi-kotlin:1.15.0")

    #other dependencies
}</pre>



<h2 class="wp-block-heading" id="h-using-generated-code">Using Generated Code</h2>



<p>With all of that being done, let&#8217;s run the <code>openApiGenerate</code> task, for example, using the gradle wrapper:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""> ./gradlew openApiGenerate</pre>



<p>By default, our tool puts all the files inside the <code>$root/build/generate-resources/src</code> directory. </p>



<p>Moreover, the default package name is <code>main.kotlin.org.openapitools.client</code>, which of course can be customized according to our needs. </p>



<p>When we check the content, we should see plenty of files generated for us:</p>



<p><img decoding="async" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAdMAAANECAYAAADrAsV/AAAgAElEQVR4Xuy9e3Abx73v+QWt9yOOIYKUX4ly7BB6UEfXsZM4EhXSibx1fU6OZMmyK8pma8+ur2NV+W72r723fJNTa6dip/ZWZat266Zs2U5VUnk4UryiqOOT1IllibJIXiWxj6O3wPghy5QtERD9kClRpITZ7gEGGAzm0TMYEBjgi/yhmJju/vWnG/Od369/3RPr6r5LAz8kQAIkQAIkQAKBCcQopoHZsSAJkAAJkAAJ6AQoppwIJEACJEACJFAhAYpphQBZnARIgARIgARiX/jCF7hmynlAAiRAAiRAAhUQoGdaATwWJQESIAESIAGumXIOkAAJkAAJkEAIBOiZhgCRVZAACZAACTQ3AYppc48/e08CJEACJBACAYppCBBZBQmQAAmQQHMToJg29/iz9yRAAiRAAiEQqGsxbbmmBdfFWx27mc1mceHjD3Fl6koIKFgFCZAACZAACQQjUNdiOnf+fHztnvWuPZOC+v677+D44dcxeflyMAosRQIkQAIkQAIVEIi8mBp9v/jJBRx85WVcunipAhwsSgIkQAIkQAL+CTSMmMquU1D9TwCWIAESIAESqJxAQ4mpIagjp0/5JnPqr8OYmpr0XY4FSIAESIAESMBRTGOxGDTN37G9Qcq4DYHKmmlYQ7j397txaXw8rOqaup72nvuwaU0H2sQcGh14Dk/1jzY1D3aeBEig8QnYiuk8kfizedN9GBoaxBtvvqlEQQrpPffcg4sXL6K/v1+pjNdFFFNnQivvfxSbkrGSC07uegLbj5b+zYtx2N9ntRXY8v31WCrmg/xoWgq9P3wBR/L/7ae9bOd9ePzeZEkRLT2IbU/341yA+vy0zWtJgARIwA8BWzH91re24PrF1+Pq1SxefPGfPQXVENJlS5fqbe95+WUcOnTIjx2211JMoyem0uKwPFOKacU/IVZAAiQwTQRsxVQK6ebNmzBr1mxPQbUK6el338WuXb1i/bHyvZ8UU28x1bQ0Bp59BntHa+uRVnO+mr1deqbVJF3/dbfe9Hl85ibg9H8fRobRifofsCay0HHNVEVQqymkcgwophRTSYBi2kR3JJeuZrW5WHLbStw85wOkKKacFHVGwDWb101Qqy2kFFP3mWKsmdIzrbNfFM2pGgGKadXQsuIQCHhujbET1DffektPNjLWSMMM7Zr7VK+eaXtnN3pEturSREI3VwpaerCvkLVqeFLJ4d14bEcaqx7YIJKFErCGKLNtK7CuezWSHa165qteV1qEbXu9w7ZuYmpOTjLaxF2bCxm2WlokBfWKpCARGjZsWCvsy7Vf/M4Yi6zWhlV3rcXyZBzx1lJbU6kh9O87WpIQVNJ+qg8/+O0xvSrr33U2d21A15pcnXrfBce9R0uzf8PyTOcuuhFLbl6ERXPn5sftEi6N/BX/NlJ60Ed2bhxLRCyx9bo5mJcfl4uXxpB5dwSnz5deO/emv8UXRNjxXZEjcPpSaag9u+jz+GpHHOeHD+LE+dx3WS2OFV+5FfEP3sCBk5fQtvTzWBqfC+3SCP7t9RFcyrdnZ4N26RLeTZW2I69bkbyptE8fjODEyfOFuoxxVO2/9b5Sic1O3ApzS5F1a/JLglP5UoY29lcMpsZCuBWyChKojICnmMrqrYJ65r0z+MzNN+stV0tIZd31KKZGUoy88adSw0ijFYlkB5JjuwuiYRbTXqwvZN2axVTW88iG/PaRVAqpEychnk6QiMeBwWc8s3L9iOnAWAcMsTSmi55l++xJLH+omHlb8p0pA9cuEcg87awPCapiamZTbLt8DTgMMTWETQrSWOY8xjEP81uvQ/zSGyU3YymOt98sxE0TQvvBJWQyF4HWeUJYr9OF9eK7h0vEtxIxTeHWgkCYxVTaesfn8+2NCREX9qJ1EebLh4B3DxWFOX/dXExg7IPzSIudXYn54mFBirM2VhIKVe2/3e3ELKZONvvlpv++fbCeK9ZKl8wXZcQ4yP7KsdEfa8bFg4PlYaiyWyJLk0AwAkpiahVUo6lqCmmlYqplNUxcEjdCxc9/3/+S51GE0kNbt/VBdLUOl233aG/TcC6fBFQQ00xGiO2Y8DRzXmDhabytG488tBoJiHqeLf1O0dyCl2cX5rXbNqNar3GdeZuNLvzLMhjYf0L0I+c16h7txvVYm8j1y3y9ipi62aOZvFm9LdN2myAJSG7hwblzNVzKe5TZuTfijlU3Yu7EmRIvMWdDbr3uM3NjJZ5mYDGdEIIg/ndaPJBlTB5twQaIdcFDpd+ZmRWuEx7uv1m8UOM7jBzRhV+1/05jUhBTL5t9cAvCmmFev79iXj+dBJTF1Cqo1RbSSsVUHsAgD2II8+MmpiU3uvzNPwkhQDaZtobYVLIvVNUz1YVOHJywXRyckM2LuBFSzomg+E6EVduFYG417el0O2wh29aG60XZFd0bCh6v+XpVMTXalnZtEQ8Xhb2plr2k1RRT87jJUGLyugnbkK0uqIbYCgEzQouBxVR4V3ahYSOcaQ4N283hXLuXbBNxCqKD3EOB9MIrSdwpiKmLzX65BWFNMQ3zbsa6wibgS0wNQf3Sl76I3/3+d6Fsf3HrUCVh3oKYzp6HWPtnlLlpp0W41eXT3vMQtnbJ9U8R5hXre/1HzpUdIFD0TIfKDhgoCDLKv1M2UlyoKqauIViTaBl2GZ6mVUyl2OqnGuU9UautZm9SRUxV7dJFrELPVH8wM0KKMsz77l9xSoRvjfXJXBvemaJFD63ouQYWUxcv7ua8CJrtK31YK3rJbnPGHOr16r9bPXb9Nq4Pwk1F3O3aVGnLz2+I15JAmAR8i2mYjXvVFYaYxj6zFNds+c9eTRW+v/J//S+e1+rCkl/v1JOPhoewc0cxCce8Zmok3xRvPrkTgpKZOhBTUzjVTUytYeNR8SABEb4eg0zCyidOuSQaOSUgmdkYDymSU1miVghiqguqWGNcll+LzK2JFhN13ASjTDhMYhdYTE3ebbH+fHKSjdDaienNc+Raqdtbki7i1MliUpNb/5XENKDN5Z7yolwSlks/rWXkgwXF1PPWxAtqSIBiaoGvIqZGkXaxbtgj1g2loJQkFxlhXpHNG3UxNYeG9Uzfp4tHA5YIYATE1Bi3uTKDNHmryIAV45bPog3qLdVWTIPtt7Trv5MXnPPaixnI1sxZFYGzPqgEZa3SVg3vpWy6yQlQTCsQU6Oo9Nw2dhTXR908U1nGen2QORhKmFfBMzVn8uYygHMJU3J70KYNq4tbeiIkpgZv67pdkHU8I3xqt8Zp952bMEm7vGww2y63initrbrNLdW2KrXZbq3Zq227MhTTIHcKlpkuAhRTn2JqztoNKqbF7TXBD22vhZi6TUrfa6aWjN1qh3nNWbtOYqqSYSpDq+bEoeKWE+s+0VxmsNxO47TP1G5/pFN9VvZeWb9yT+n8iyOFTGGV/juNr5eYBuKmkDldxlphXXu6bpxshwSsBCimPsS0mDw0jNRYBsfF0uHyhFg3lAcylHh5+XVRmzBvIURsJDLpa65iT+CJjNhnKvasxjvEPtMnQ91nan7LilNykNOaqfXvhv0yrN2b6sAmkYwlP/UspsX1tw8wJrZLlezHtGz699r7eH74sNjnWVynNG+Z0cTBDmMisWlc7PWUBz5c+uADsefT+dAGp8MGnGyYP/c6sc/0j4V9pm62yr2Yhuj76b/dLdJLTGUZv9wqLiNYvytYzxfbi06M8NAGSlvtCdS1mM6YMQOLb1TPxDXjvHJ1CmdH3kXYCUgrxbs6u/Lv6tRFRD+8ofQUIK8wb0FQLScpyb+PinVJ675Uu2kyXZ6pbFsXVHGKk3Hww2hqUCRc9QN3fUfPbK53MZX25Q5Izx2EoNurH94wglPvep8UJK+XJ/lY94Qa46KLlTjJ6DPisIRc3eJGL/aPnprX4XoCktvJPdbTipxsyF13o77+a3xytkqvtCj6fvpvnW8qYqqLo+WEKS9uQcqUseYJSLVXEVqgE6hrMQ1jjMIW0zBsCqMOns3buG/JCWN+sA4SIIHpJUAxtfD2k807vUNV2lq9vhw8TCZ8n2mYNFkXCZBANQlQTCmm1ZxfFdVNMa0IHwuTAAlMIwGKaUTFdBrnCJsiARIgARLwIEAxpZjyR0ICJEACJFAhgYYX0wr5sDgJkAAJkAAJeBKgmHoi4gUkQAIkQAIk4E6AYsoZQgIkQAIkQAIVEqCYVgiQxUmABEiABEiAYso5QAIkQAIkQAIVEqCYVgiQxUmABEiABEiAYso5QAIkQAIkQAIVEqCYVgiQxUmABEiABEiAYso5QAIkQAIkQAIVEqCYVgiQxUmABEiABEiAYso5QAIkQAIkQAIVEqCYKgJsuaYF18VbHa/OZrO48PGHuDJ1RbFGXkYCJEACJNAoBCimiiM5d/58fO2e9a5XS0F9/913cPzw65i8fFmxZl5GAiRAAiQQdQIUU8URVBFTo6qLn1zAwVdexqWLlxRr52UkQAIkQAJRJkAxVRw9P2Iqq6SgKoLlZSRAAiTQAAQopoqD6FdMDUEdOX1KsYXiZaf+OoypqUnf5ViABEiABEigNgQiIaaxWAyapvkiFKSMWwNBxNSXwaaL9/5+Ny6NjwctHtly2bZuPPLQaiSGd+MHvz02rf3Idt6Hx+9NYnTgOTzVPzqtbbMxEgiLQC3mcS3aDItXmPXUvZjOE4k/mzfdh6GhQbzx5ptKfZdCes899+DixYvo7+9XKuN1EcW0SKi95yFs7UqELjz1JqbV6qfXXOP39U+gXudGLYTNrs165VPNmVX3Yvqtb23B9Yuvx9WrWbz44j97CqohpMuWLtW57Xn5ZRw6dKhihhRTimnFk4gVNAyBehULimntpljdi6kU0s2bN2HWrNmegmoV0tPvvotdu3rF+mPlez8pptWfpNPhma7suQ9da4CBH76AIyKCYXxqcROqPlG2MN0EnObXdNlRi3lcizadeNaSf92LqYSmIqjVFFJpg5eYnnvvDM688zamrkzhU9deh1uTyzBz9uxAvyGumVZnzTSrtWHd1gfR1TqMXoppoLnJQs4E3ObXdHGrhbDVok07nrXmHwkx9RLUagupl5imjh3GGydKE2bmzJmDNV//95gzd67v3xHFlGLqe9KwQM0J1PpmLgHUQthq0SbFtMLpbuehvvnWW3qykbFGGmZo12yuk2d64aOPcGDP70S2cXnnbrj5s7jty6t991pVTI2wKAZ/ip8cT2DdxtVYm0jo7Y2mBrFzRz/OiVCmvG6L+G5pIhfWNH9nNi7btgLrulcj2dGKtnwIdDSdwkCvCImOuodEzT8oaUuuvZwtmqij11KH7Y/BIZu3EP6F8CiftdjiYHNq8AD2Hi1m5a68/1FsShb7YLSvpfr0zGG7G4LX34L202jbibfVdv0mqa3Alu+vR1JkOj+2I41VD2wQ/UkItoPY9nRunOWnvbMbPWuKYy3Zy/E7tvw7eFiGt599BntNY+k0OX3ZZho3w7au/BzStDTSw0NiLh4t2GidcyVzxeH6IPNLeT4HsN86N7zmV5AxD1LGSdhy86Kj+JuUnAf7lDLX7Thq6bSYV7m55PU7sWbHy/rCHnNV/r5vxj4KRMYzNfpkFdQzIrz6mZtv1r+ulpDKup3E9J03/4qjr79qi3y28E7XfWOjj+HIXepfTIcwluxAfGwYqXQrEuL/S+HUb7SDrdgqt3wIcU2lkf+u/CZcuFkjI25+Y0idyADLOrBW3rA1IYamsKj7j2cQY+JmHh+WtmSK7VnqUBXTopBmyoTASALJ3bANm1vFw0CH/jBg3ubSLtZKe4S2x8V3iXwfx6QR6QPYLrbCqN4QitcF76cuevmMaBXbrWLai/WFBwOzmJrrTAn+4n6n80+KI6VTwxBc1MTUt20FMRrCQHw1usRDTyol5hHEWIhG24y5aBJ9vU9iO9IjG3LjIe09LuxdnhBz13XOqXH3NZ8D2G+dL17zK8iYBynjNo+lAKbERJDjos+LMe8IkDFG+u8plRL3hZPivrAUiXgcGHwG24/6E9NqjbkKf983Yp8FIiemsn9mQTX6W00hdRPTd0+9hcOv/tEW+5x58/H1v3M/z9euoF8xlRP95K4n9IltfMxPak7fmf8ubz7rHgCOWTwI48Zacq3NnkzjRyzbV2lPRUzNN0SrR1UQ2cxQiWeWE57c2uhacRMv7aO/NVO3G1Mo/fRle94zzUiRGiuPFhiCYFdnfrykcHt5poG45tu2PsBY56L54cacbLbNMufMERfDq/E7v3zN5yD22/0G3Nbk3cbHab4GKWOxyy303N6m4ZxLlMItImT+/So/iJoiANUZc+fft09dDHR5JMXUKqjVFlI3MZWHK+z/w4t6prH189m/uRWdX/ii74HxK6YJtxuoJQxoeASqBxS43dhKbo7GDTsfNvX6sXmJ6WM7kAtrCq/FTgDkw8LGDvvv9D7ahIz9JiC5PuVX0M9gtufFNCAPrzbNwuebq8tNP/dwYzwIFB985EPaw2vGyhLBzA9DXSheb4yFEZYPMr/M80IujRSEOoD9tnPDRUy9+NvN1yBlrHZVso5rPJBbH46tv11VMa32mFfSV983aZsCkRVTQ1C/9KUv4ne//10o21/cgLpl877z1hs4JkK95lOaPnXtp3Fnz9cxc+Ys3+PkW0xtTgyyE0HDELeEgfbOFVghwziIQ0Zy2ow1WNPJQKo/nkJ7iicbFW8o+XBhq71Yqvxo7G7gYYqp3UlJKlt7gtteLkgFvi43ceOa3I3MPcwb2DaP8S3UmxfH99FeiBy4/TjMywtuc9aNu9J89mm/nofgwzMNwtVgZJd5Xhz38jlhZ1chbC/DvGKdtP/IOdv165IHFGNOmR5onMZK5X5gjhZVa8xVOPu+GfsoEGkx9dHPii/12hrz8Ycf4L2R05gSr1679tPX4abP3YKWlpZA7foVU/NTtlXAbL+zuxHoSQHrc2utcg0yM4Yxsago192SInGh5EneJcwbVGTMXoOR/GTnhTh5OmVPyzY3g/oQU2dRLBNHs2dmSkCyHrVo9+Bg5aEmpgFtUxWj/JakQ3kx7RIPSymx1u38yaDfSKJzOe7RNgrhZz77tF/uT/Ynpv65vo/OXGTGJurkOk8cOLWLv28S69Pyt+WVFKb6G3N7OHf2kKs45goPlYFuyIqFKKaKoLzEVLEapcumW0yLIlPuCfoN84YhpvJsXiPJZlSEU5+ynNOr8gTasJ6pXRRCwYtQE1PvNSdbrp5iVComKl5X2cORDzH1PZ992h81z9TMsl08ZPQYD802S0BuXm8Ynqmbp13JmOceALznr9INOOBFFFNFcI0tpsVtF2Vej6IXGjQMZ8Zv9jByWywe1LNW7QQ60HqSz0MbVMJXTva7HdQfzHaXMSr0yyss7rzGbPQjkG1ea442YqW6Hufm/VijMMYLEszbiJTmcwD7/Xim0s4gXIOUcfsdmueqV90qNvvxTI365O/Zaw02yJhTTBWFrB4uawoxtYSUzOscdslGXn9zutk5PuFabrpO7es/HIVMRxlGNCcv1UOYN7jtzmKq12lKALNmSpq3uoSRzVvG1ZQNe3LXcyKrvLi/18lL9MoUlfsi20b7C/ub/TysOYW9HedzEPt9rJkGHvMgc9zGLrusXRUxLcwpFw/WPPe87gfVHHOKaT2opKINjSym5qdGuclf3yOYyO3XhNj/B/mvOftR0Vt1E1O7g8LdMnDlNherh+q1H9J6Y5f2FJMxxGEGop9yj+P2/mCHNpRvRi9/hZzTgeh+bXfztsw3EsnJ2E94XOwnXK7vMx3GwGA8dyax6dCG0Gwr3PTFvGkVm1ozcp+p2I+YWGq759eYF24M5LiUPAj5CPP6ns8B7HcSd6f5VTL3HPZFu85XxTKOa5Vy7+9YpnQvrykj3e9cSMTlPeFJ3/tMqznmbr9vxdt8RZcxzKuIb8aMGVh842cUr67ssrNnTuPKFe/D+V0zdvM3COUEJBEqNE7VkdbLJIVUXx+eH12mv2O0VmKaE4qcV7bUchCD/uOxnOwi/2Z3alNB2GVIVJweJA+j0PtZwQlIlYipX9u9xNQQ1FV3rRWimUs00VnkT8LCXeUnILm9+cQP15Lw/H6xpSm/JqfzlScwWU6jMv86rCc2FcfvgPBKTR6uTzGVXqjyfDafgKRov5OY6t6vzfwqPED4nK++54kNp9zh78U5kXvYGkL/vuKpVJXMBb/LIdUac+M34Ma/sjuze2mKaTXpsm4SqBMCKmG9oKaqbAkKWvd0lIu6/dPBiG14E6CYejPiFSQQaQIqW2cq6WDUxSjq9lcydiwbHgGKaXgsWRMJ1IyA/jKD5WJfpil0Z4S93LKiwzA46mIUdfvDGEPWUTkBimnlDFkDCdScgPmFAPLQf+MoBHmwv75R3yMjs5IORF2Mom5/JWPHsuERoJiGx5I1kUBNCTglDdm90i1MQ6MuRlG3P8yxZF3BCVBMg7NjSRIgARIgARLQCVBMORFIgARIgARIoEICFNMKAbI4CZAACZAACcQWLvuqRgwkQAIkQAIkQALBCVBMg7NjSRIgARIgARLIrZnSM+VMIAESIAESIIHKCFBMK+PH0iRAAiRAAiRAz5RzgARIgARIgAQqJUDPtFKCLE8CJEACJND0BCimTT8FCIAESIAESKBSAhTTSgnWoPw111yD69vFS5gdPtmrWaTHPsTU1FQNrGOTJEACJNB8BCimERzzTy1cgAe/ucHV8qtZDak3T+GVg6/h0sTlCPaSJpMACZBAdAhQTKMzVgVLVcTUuPjDjy/ghRf34ML4xQj2lCaTAAmQQDQIUEyjMU4lVvoRU1mQghrBQabJJEACkSJAMY3UcOWM9SumhqCeeONt3719/UgKlycnfZdjARIgARJoJgIUU5+j3dISQ1asR/r5BCnjVn8QMfVjr/nan/6mDx9f+CRocZYjARIggaYgQDH1MczXLpyP/+N/vR87/zCAfzvxhlJJKaQPP/D3+PiTcfzqxX1KZbwuakYxvfUftuK/3p3AmZe24X/751EvRPyeBEiABKaVAMXUB+7/85H/EbfcfAOuXL2K//bL3Z6CagjpV/7dMr2Vn+96CS8f/IuPFu0vpZhSTCueRKyABEggVAIUUx84pZD+pwc3Y+6c2Z6CahXS42+exv/9s52YDGHvZzOKqY9h4qUkQAIkMO0EKKY+kasIajWFVJrrJaZvvjOCk399GxOTU0gsug5f/HfLMXf2bJ89zV3ONdNA2FiIBEigyQhQTAMMuJugVltIvcR08NVD+NPrR0t6NX/eHHxr499hwby5vntLMfWNjAVIgASakADFNOCg2wnqX1Jv6slGxhppmKFds5lOnmnmg4/wy//vX6Bp5dnGHbcswd9/bY3v3voRU+3GTvzjPV24Y2UrbozF9LbOnD2J3p/vwN4zuf+WH+3Gu/Df/tMa3HBkFzY9O4qvP7QJG/NlNC2N944M4P959gjeyNehl/ni/ej9n5aWJSDd+sW78MDdSdyxOJGrW5bfs5NJSr5HmgVIgAQqIUAxrYCeVVCHT53B8ls+o9dYLSGVdTuJ6aETf8XegT/Z9mje3Ll4+NubfPdWVUw1rRPf+3/vxe3ICDE8j1cPZYBVSWz424QQuJP4yXeFoObFsSimg9jdtgbrkcJrRzI4g1YhxEncuDgG7ewA/vMTewuCaiemxt+0s2lRPqWXv1GUv310F+57rtQ7991xFiABEiABHwQopj5g2V1qFlTj+2oKqZuYHht+E3/Yf9C2RwsXzMd/2HKv7976EdN/fAgYtHiUxpaWV3/xAzz555x3aoip9F7ttrp87T98H//xb0u/s4qpprXhH7/3HaxvT5UItaz/1hs1vGHyhH13mgVIgARIwCcBiqlPYF6CWm0hdRPTjy+M4+e//Wc909j6+dtln8fXu77ku7eqYupUsSGc2PNMIfRa8EzPDZZ4n0YdBS/X9L0fMfXdSRYgARIggQoJUEwrBGgUlx7qN3q+hKd+8y+hbH9xM8stm/ewCPXuG/pzySlNrfFP4/5/+B8wZ9ZM3731K6a3frETa1Ytw41YhOvbIEK2ubVMswdqXjO1C8cWvE4UxdYuzGt4vXqY96Wd2PGncyXrrL47ywIkQAIkEJAAxTQguFoW89oakz7/AU6+9Q4ui1evtbXGsSJ5K64RJzEF+aiKqUw++t7/fK9IBBLrnTIJ6Nx5vC/OVjhzDrhjXRK2nqlIQHIVU1MI1zkB6X78798W66wiZOyUvBSk3yxDAiRAAn4IUEz90KqTa73ENEwzVcS0uH6Zwe7/+hR+bpO5609M88lMLmFeax9vFWL+gCHmluSlMHmwLhIgARKwI0AxjeC8qD8xzYufjadpm4VrbI1xWjM1bZ0xPFcnz9Q6fDJ56ZGV5aIewWGmySRAAhEiQDGN0GAZptatmFrE0fBYN4jQr92aqQzNvvqLbSLLt3jWrpOXa7tmapO1SzGN4ISmySTQAAQophEcxHoTU4nQ2M6iiUMa9D2j7bk9oxD7PyH/tc3mFXtSxXU4l8KrR04A7cty+0xttsw4ZvPKPaqjGRwUa7N3tovDG+S+1sO93GcawXlNk0kgygQophEcvZkzZuLzf5M7HKLan7++dRpTV6Y8m5EepTzJ6D8KMZMfmQz02i934on3VuinHTmtmW76PQqJS3o5Ica7X9qPn5u8Vf3vNicgfe0f7sdGkdxknLaUO7xhADt2l56e5Gk8LyABEiCBCglQTCsEyOL+CXhtjfFfI0uQAAmQQG0JUExry78pW6eYNuWws9Mk0NAEKKYNPbz12TmKaX2OC60iARIIToBiGpwdSwYkQDENCI7FSIAE6pYAxbRuh6ZxDaOYNu7Ysmck0KwEKKbNOvLsNwmQAAmQQGgEKKahoWRFJEACJEACzUqAYtqsI89+kwAJkAAJhEaAYhoaSlZEAiRAAiTQrARiXd13adkEKQUAACAASURBVM3aefabBEiABEiABMIgQDENgyLrIAESIAESaGoCFNOmHn52ngRIgARIIAwCFNMwKLIOEiABEiCBpiZAMW3q4WfnSYAESIAEwiBAMQ2DIuvwR2DWnNz1kxP+yvFqEiABEqhTAhTTOh2YhjEr1gIsWoxY22eBuPh33gJA/k1+tCy0i58AY2ehjb4DnD+r/40fEiABEogaAYpp1EYsQvbGFn8OsY7bgLkL1ay+dAHa8OviBeFvq13Pq0iABEigTghQTOtkIBrJjNjMWYit6hYe6Q3BunX+PWiH9kObmgxWnqVIgARIYJoJUEynGXjDNzdvIWK33y3CuYreqAMQ7aLwUl97CRD/8kMCJEAC9U6AYlrvIxQh+6RHiju/UbGQGl2WgoqDL9JDjdAcoKkk0KwEKKbNOvKh9zuGljvWBQ/tOtkjQr7ZV/eIb3nqZehDxgpJgARCI0AxDQ1lc1cUW7wkt05ahY++fnr2VBVqZpUkQAIkEA4Bimk4HJu7FrHVpWXtvZ5Zu9rVKUyeG8HVj8aQvTKFljnzMPPTizCjVWyZiV3jzFBk+WYP7FLeNpPVVmDL99djaSxWUqempZEeHsLOHUdxzvJdFAYw29aNRx5ajQQyGHj2GewdLe1fJX1o73kIW7sSGB14Dk/1j1ZSFcuSQFMSoJg25bCH2+lY640i6UiEeF0+l8++g/Hjf4Y2WZ6he838BVjQ+RXMuC7hWIP22h5omTNKhhtimsxkkBoby5eJI97RijYhopqWQu8PX8CRiAmqFLyHk0C6tRUY/GmookcxVZpavIgEHAlQTDk5KibQsuJO4CZxl3f4TAohvXBoUHifMcy6fglmtt4gvNI5yE5cwlTmPUy+fxoL7+jBTHGog+NnJIXssYNKthbEdHg3fvDbYyVlDNHQUn1l3ylV7vOilT33oWsNMFCheGe1Nqzb+iC6xnajF+uxMT6EbU/3R9LD9omQl5NAJAhQTCMxTPVtZMtXNzmGeOVe0Q8O7EZMhHUX3HGXrWBqUxOIzcwfMejUVRnqfWWnEgg3MS2IUutw1b3TMNsyQrxjfU/ieWzGYxvioYd6leDyIhIgAVsCFFNOjIoJtNz9baDFfs3z8pm38MmRg5izJIn5S28P3lb2KrIv/VKpvJuYygpW3v8oNnZES0z1EO+aMf0B4BA69TXheMihXiW4vIgESIBiyjlQBQIzZ6Pla990rHj85GuYOJXCp27vxszEjRUZkN37G2DqsmcdQT3TbNsKrOtejWR+bVU2NJpOITV4AHuPlifltHd2o2dNB5Ymcmu9eoLTYJ++likFe1OyPEHIHF52K2/upF1/9AcCh1BvIVFJhLkf25HGqgc2oKuwXmyfhJXtvA+P35tkApLn7OIFJGBPgJ4pZ0ZlBBTFdMGqNZh9vTjsPv/J/uvPK2vXpbSrmBoZsZnSNcfCWqqe8TuG1IkMsKxVCGuHnrRkzXI1xEdLp5FKDSONViSSHUiKNU25Ttsu1kp7hMbGRXmZfSvr1FOh0gewXYitV/kSMc0L3cldT2D70ZxAG+XNfyuwNfooMpcH4qvRhWFho7BB2JgUNrYlRBJWerBkzZViWrXpyIqbhADFtEkGuprddAvzToy8gfGjf8Kcm27B/M4vl4hpi9gOs3CeyEz19cnio/G0awknMZWe4KYN5VtLCp6cRWB10con/qwVAmQIl9taaHubhnP5LStO16mWNzppF5ZWeWCwewiQdRpes/kBgWLqaxLyYhIoI0Ax5aSomIBXAtKHr/Tp+0oX3taNWW25UK/0TK+d347vbvyZcvtZ7Sr6hn6Mo2/vUxJT6z5TWUiGYlN9zxQ8PENcNnY47900h02l16maWBRETK0dcxNNp7Vft4eD3ANCbh9u0vTwQDFVnoa8kARsCVBMOTEqJuC1NebyeyIJ6bDY1iIilLNvWIJZYu10xqF+X2J65eokdh74EVIj3ttj7PeZijDniRM4duRcyXYSFWG0E59CWFiGecU6ab+lXrNX22WTOaxSXq/DJsRrDJjTd1bxLxfo/DYbFEPdFNOKfwasoMkJUEybfAKE0X2lQxuEoI6feE0cWj+lN3ldbEpZTKeuTIh1xsfx9tm/KJnrlc1rrsROKFXER17TLoRu04bcmqrd6UpeQq1aXoaY3T7WPbPKYmoSeYqp0tTiRSTgSIBiyslROQHV4wTFntPL597FlQsfYt7po0piOjH5CZ7f908YSZ9UttOfmOa9NJd9p16C2y6ygHs2iuMLLYk9XmJqdMixfCFZSiQQGQc5WSjE4yLBqbU0RO0tpgzzKk8mXkgCigQopoqgeJk7Ab8H3ausmY5PfIRfv/w9nP3gTV/4/YiprDi39qi+ZupkjLUeVTE16rOWN0LBdhm7Rhk7j9JzzbSQ7Vs8IYqeqa8pxotJoIwAxZSTIiQC/l7B5iWmFy5m8Is9j+L8xyO+7fMrpirZvF0W78+cteskhsGydnOivudce+74QI+TmmyTifJiKcPPJ3c9J5KtintkizZZvFnuM/U9z1iABMwEKKacD6ER8PNycC8x/ePJXfjDq9sC2eZXTGUjXvtMzaJUECS5f3Msg+Nip87yhDi8IZmAdf2ymGiUwoDY6yn3nD6/L50TSpfyXqFaM5gyj7gQHhZJV/JQ/IzcZyrC5Imlnvtm+daYQFOOhUgAFFNOgnAJzFso3iBzN2LiX7ePl5jKsvsP/wqvHFY7QtDcVhAx1QXVcqKR/Js8AWmgV7xhxvK6s9wB9rnkI/nJHd4whP59pa9304VXnEC0Vgitfl3+gH2v8iohXqPP1hBtyQlI+4Et+fXcnJ2iPzYnOjHMG+7PgLU1HwGKafONedV7LD1U/UXhi25wbEtFTCsR1Kp3so4b8OPV1nE3aBoJRIoAxTRSwxUtY2OLP4dYx222b5RRFVMKqv8xp5j6Z8YSJFApAYpppQRZ3p2A2DaDRYsRaxPn8or3lcbmLRCHN7T4PgEpaMi3GYeHYtqMo84+15oAxbTWI9CM7c8S7y6dnFDaZ2rGQ0FVmywUUzVOvIoEwiRAMQ2TJuvyRcDv2bwM+arhpZiqceJVJBAmAYppmDRZFwmQAAmQQFMSoJg25bCz0yRAAiRAAmESoJiGSZN1kQAJkAAJNCUBimlTDjs7TQIkQAIkECYBimmYNFkXCZAACZBAUxKgmDblsLPTJEACJEACYRKgmIZJk3WRAAmQAAk0JQGKaVMOOztNAiRAAiQQJgGKaZg0WRcJkAAJkEBTEqCYNuWws9MkQAIkQAJhEqCYhklzmupquaYF18XFS58dPtlsFhc+/hBXpq5Mk0VshgRIgASamwDFNILjP3f+fHztnvWulktBff/dd3D88OuYvHw5gr2kySRAAiQQHQIU0+iMVcFSFTE1Lr74yQUcfOVlXLp4KYI9pckkQAIkEA0CFNNojFOJlX7EVBakoEZwkGkyCZBApAhQTCM1XDlj/YqpIagjp0/57u2pvw5jamrSdzkWIAESIIFmIkAx9TnasVgMmqb5KhWkjFsDQcTUl8Gmi/f+fjcujY8HLR6oXFZrw7oHNmBtMiFYpzHw7DPYOxoLVBcLkQAJkMB0EKCY+qA8TyT+bN50H4aGBvHGm28qlZRCes899+DixYvo7+9XKuN1UT2KaXvPQ9jalcDowHN4qn/UqwuO3+tCuvVBdLVmkB4ew5i48vj+F3CEYhqYKQuSAAlUnwDF1Afjb31rC65ffD2uXs3ixRf/2VNQDSFdtnSp3sqel1/GoUOHfLRof2lDi2nnfXj83mTFolwxZFZAAiRAAj4IUEx9wJJCunnzJsyaNdtTUK1Cevrdd7FrV69Yf6x872c9iqkPjK6XGh7uyV1PYPvR2oZ2V/bch641wMAPhWcsIgz18KlHm+qBC20ggVoToJj6HAEVQa2mkEpzvcT03HtncOadtzF1ZQqfuvY63JpchpmzZ/vsae7y6V4zlWL6sBSwGq+TFsPNw+itEzGtR5sCTSoWIoEGJEAxDTCoboJabSH1EtPUscN448Sxkl7NmTMHa77+7zFn7lzfvaWYUkx9TxoWIIEmJEAxDTjodoL65ltv6clGxhppmKFds5lOnumFjz7CgT2/Exmw5Z264ebP4rYvr/bdW1UxzdqsdZr/9pPjCWzZuBpLEwndBi2dQm9vMbHIuNZqoJYexLan+/E+OrHl++uRHN6Nx3aksUpk+26S2b7578+JMGy2bQXWda9GsqMVbfmw7KhoZ8DUjlF/e2c3etZ0FO0RWcPpwT49eWrl/Y+KusvDulqqDz/47TFktRWutuCu7zh610Y/7cLYdvZraZHN3PsM0t3/xdUmN4/erk2vPkie8iNtKhk3yWl4CDt3HIVxje9JxQIk0IAEKKYVDKpVUM+I8Opnbr5Zr7FaQurmmb7z5l9x9PVXbXs0W3in676x0XdvwxHTQYytWY348DBS6QwSyZyIaZoQ1HwINdvWjS3d4rzhuPwuhtFUSs/kRfok+vcdLRHTXqwvCEuZ2CKXBZw6kQGWdeS31xTb0QUiL/xSqFKpYaTRqtuUHNuti2W7WCvtEZof7+hAIl9fzpYD2C7E1ixEdrYEEVNp0yMbOvSHANn31ImTwv6lSMTjwOAz6G/d7GpTJWJq1wf94SRvk2SQEmN3PA0sT4jx0bcslTL1PbFYgAQajADFtMIBNQuqUVU1hdRNTN899RYOv/pH2x7NmTcfX/879/N87QqGIaayXqsnZnh/1r87iUJBwDJCLIXMWr1N+f26B4BjFo/JmtDktu7Y3qbhXH4Ljtt1Xrb4FjbxIPHIQ6uFcIuQ8rPO24BcbXdZa3b1TJ14GjaJSMA2C1P54CPtxeBPK9oGVeFPj8VJoK4IUExDGA6zoFZbSN3EVB6usP8PL+qZxtbPZ//mVnR+4Yu+exuGmBrhUXPjdmFh+b2nmAovyU9ykvXGr5rEoySmDrb4FVOnBwvrYFVFTF37MGabfFWwA0N6CJ7hXt8/KxZoQAIU05AGVQrql770Rfzu978LZfuLm1lu2bzvvPUGjolQr/mUpk9d+2nc2fN1zJw5y3dvwxBTu4McDJFLCM9HhlaNj6eYZtxv4O2dK7BChkcRh4yQtuXXaM02GN6qHuYV66T9R86VCYKSmDrY4kdM/QhTVcTUpg9GO2tFuN3tw1Cv758TCzQwAYppBAfXa2vMxx9+gPdGTmNKvHrt2k9fh5s+dwtaWloC9bTuxNQivkancoky6/X1VnkEYTojTk8SC51CL5EUiUbWkGS7WA/clF+j1K+3JNUoiamDLf7ENJ/M5PGQIPtZFTG16YP5FKqUWH92/mTQv4OeaaAfFgs1HAGKaQSH1EtMw+xSFMTUfPO3hoC91vfahQj3GCJszgwuHGtYvjXGnIBk9qq9vGtdEPPJT8ZacXH91TtkOv1iWj/bgsKc06yLBKpBgGJaDapVrpNiWrqP1k3cnNZmrUMk1y03dhTXYyv1TOU5xXbbX+xOeLK27TR9vMTUT5teDwSq67hVnuqsngQiQ4BiGpmhKhpKMXUQU0uo1Lz2V7JmasraNaiGKabFrTe5PbLFPZu5LFi5/cUstE7XW6emq8AXtvsotmnaK2vnXRfWtB0yjOU+3bbRfr6AIIL3D5pcHQIU0+pwrWqtFNNSMZWwDU9KHgaRSontM4lWcXiDWCsV+yMh/81v4ygm/Ig9r2OZ0r2T+UMZzOFa6e3JOgdEnXK/5fb+0kMbbIUoHyKWCTxFe8Q+VnGYxJiwZ2kyWea1FpKi9PVbY5+s2P8q9t1i8MnCOcXF5CmrTbm37ai26eWZSgZONkmukoWfrOqq/iBYOQnUAQGKaR0Mgl8TZsyYgcU3fsZvsUDXnz1zGleueB/O73UCkvW1bIGzeZ0SkISAGaciyY7KpKJUXx+eH11Wticyd1h87oAE/Vr98IYh/XAI8zYP83tV9etsTkCyE1N5bVnZ/ElMe9o262/FsQ0BW05lkvVYT3BysslvmypiqguqbpM8uaqY2Zuz6YDwSoO/ai/QZGQhEqhjAhTTOh4cmkYCJEACJBANAhTTaIwTrSQBEiABEqhjAhTTOh4cmkYCJEACJBANAhTTaIwTrSQBEiABEqhjAhTTOh4cmkYCJEACJBANAhTTaIwTrSQBEiABEqhjAhTTOh4cmkYCJEACJBANAhTTaIwTrSQBEiABEqhjAhTTOh4cmkYCJEACJBANAhTTaIwTrSQBEiABEqhjAhTTOh4cmkYCJEACJBANAhTTaIwTrSQBEiABEqhjAhTTOh4cmkYCJEACJBANAhTTaIwTrSQBEiABEqhjAhTTOh6cRjRNvvVM0wD5Tlavz9Tly0qvf/Oqh9+TAAmQQLUJUEyrTZj1Fwh8fnknRt55G5fGx/H3m7d4kjn05z+K69/yvI4XkAAJkECtCVBMaz0CTdK+FNKO5Sux9/e7KaZNMubsJgk0EwGKaTONdo36agipbJ5iWqNBYLMkQAJVJUAxrSpeVm4WUoop5wMJkECjEqCYNurI1kG/rEJKMa2DQaEJJEACVSFAMa0KVlZqJ6QUU84LEiCBRiVAMW3Uka1hv5yElGLqPijZtm488tBqJIZ34we/PVbDEWTTqgQ4ZqqkGv86imnjj/G09nDWrFlou/4mxzbPnjmt7x2dzq0xhRseMhh49hnsHRWbXUP6tPc8hK1dCYwOPIen+kdta1VtnzdmQIVnSEMXSjUcs1AwNkQlFNOGGMbodWI6xVTeoB9OAunWVmDwp46iF4Siys1ftX3emCmmQeYgy9QHAYppfYxDw1iRaF+MW5IrPPuzqK3N85owDm3Iam1Yt/VBdI3tRi/WY2N8CNue7sc5eRTTNHz8tF9NMV3Zcx+61gADP3wBR6ap7254682eoFPB75g1Sr+D8mrkchTTRh7dGvTtps/+DVZ98cuhtByKmObXIcf6nsTz2IzHNsRDD/W6dda42aq07/fGrAq5IOitw+itAzGtN3tUOdpd52fMGqnflTBr1LIU00Yd2Rr1q97EVA+xrhnTReQQOrHl++sRDznU64baT/t+bsx+hrfebuL1Zo8fltZr/YxZI/W7EmaNWpZi2qgjW6N+1ZOYZrUVungmTdmxK+9/1DHUa74xPrYjjVUPbEBXRyvaRFhU09JIDw9h546jJSHibOd9ePzepG0C0nS0L4e5vbMbPWs6sDSR0Eddt3WwT18blv3dlCwPaWupPj1j2Gyj0edNyQS09GAhHJ5tW4F13auRzLOQbYymUxjoFSFjm2Quu+u1dFpc/wzS3f/F3R43ng52pAYPYO/R0uQv87j85HgCWzauLvIRtvfa2O7G0enn5CSmxaQzEQ149gXAo981+rmy2RAJUExDhMmqAFUx/ZcXnq86LuOGenLXE9h+NCcodn8zDCneGIcwEF+NLgwjlcogjVYkkx1oSwhRNYmMuT67bN7pbF+KVSo1rNuaELYmxRqxFMt2sVbaIzQ23tGBhMhmTg+PYUwanj6A7UJszWIq15QN4TX6+X7em0/my6ZOZIBlHVgrBVcTomQJG8s+P7JBsBIPIKOpFFInTorrlyIRj4vkr2fQ37rZ3R4HMTUSvXIPNWOiXmmHGBfRL70tSzZ1UUwHMbZmNeLDYizTGZ2NfOiw2m5c78TRj5jaZW97jUPVfwxsoOoEKKZVR9xcDfgR05bYNVg4T2TY+vpk8dF4WqmE7oV2lK4T2nmLVjG1uznLawwvz3zjdvNMq92+W9iwvU3DubzX6HZdgUdGPjSMlXmb8vt1DwDHLB65IW4lDyrGPlnxECK9MTuvVX8AMZLCbNZw7XgWxClTnjxm1LVWPOjYPTTJ9sx/N4+j8XdVjnaTzuqZFnjabMNimFfpZxvZiyimkR26+jTcj5heO78d3934M+WOZLWr6Bv6MY6+vc+zjJto2omcfpM3xMDmpp0TgXzY2PS9k5hOR/vvoz2XqeyRWKQkpj734BqszFuNjIcNq3hZB8uvmObGy3mPsF2oteBp5sPZZhusY1aJyJUuDSC3rODAspJ2PCc8L6g5AYppzYegsQyolpheuTqJnQd+hNTIQSVgruHcfCjRetP3SiYp3AxR9JAcxdShDV2UQ2y/EP6UYV6xTtp/5FzZth8lMXV4gDBgt3euwAoZrkUcMmLbll+fNbx0OzZOA+VHTFUEyM9DTslDk2ktXYWju2eaXxpodRF9F49caVLzoromQDGt6+GJnnHVENOpKxNife9xvH32L0pAzKE/twJGEo5xjbKYmjxB27Bk/qYpQ4/Vbl/W3y7EeVN+ndIuUUpJTB2OMJTJRFs2rhfrjPkkrIxYcxWLrkK7kRRJT4Znaido4YhpeTTA0dNVeMhxElMVjm5iKpcG5Mc6p8xlVB4MlCY4L6pLAhTTuhyW6BoVtphOTH6C5/f9E0bSIpFF8VMM14qkEz3bpvwTj4uEHIsX4S2mamHe6Wzf3LN2IXw9hvCZs3Hd1ihtMp4LDxeFcuXeljXMWz0xzR+64RLKDsMzVeHoJqbyPGUjgWtUhJafsjlbmWKq+AOO6GUU04gOXL2aHaaYjk98hF+//D2c/eBNX921S44p82ZsskY910xtDqK380yns307MNY1xqCeqWuylg0/r7XNcpEuP0TCjqdXvW5rprZZ1oovFPBq1+rl5rYWPahnRNu2yzCvr99x1C6mmEZtxOrc3rDE9MLFDH6x51Gc/3jEV49Vn/5tvZn8TVaG7E7uek5spynuXSzWW+qlBU1mCat9c9auASp0MbWsp5rD6HaZzdbtQ2UPMlXI5u2yRhlc96uWv51HhaOXZ5rbt5vzpGWIv2y7DsXU1285ahdTTKM2YnVub1hi+seTu/CHV7f57q1XqNZcYZnoFLJ5xTYReSh+Ru4zFeHlxFKF/Yy5t8ZMZ/vFpB8Zzs7guFjHXJ4Q+yjlHlBLFmsxwUYctiD2zso9p9v7Sw9tsHvtm5Ghq4mDDvQ9t4nc3k6IfZuQ/1pOk3LaD5oQYXUMPlnY7+toT8B9pmUPPz7EVJWj3UsNbL1iF0F16rfvic4CdUeAYlp3QxJtg8ISU0lh/+Ff4ZXDv/QFRCXEWgg3Wm64Jdsc9ottDvn1R3m9FJMBj5N2pJhOd/u5g9NzBxfk7JSHNwyhf5/lpCZ5gxcnOsnDFvTrbE5AshNTKTTyJCh5KpJeThyakOrrw/Ojy/R3r9q9hcd6kpAsZz0xSRcwO3tcRFClXqexNU8iOwFU4agqprItI/Kw1HKghFO/fU1yXlyXBCimdTks0TUqTDENKqhB6fnxKoO2wXIkQAKNSYBi2pjjWrNehS2m0ymoFNOaTRs2TAKRJ0AxjfwQ1lcHqiGm0yWoFNP6mku0hgSiRIBiGqXRioCtM2bMwMzZsz0tvTQ+Dr/HCQZZQ/U0xHQBxdQPLV5LAiRgJkAx5XyoGQG/YlptD5ViWrOpwIZJIPIEKKaRH0J2gARIgARIoNYEKKa1HgG2TwIkQAIkEHkCFNPIDyE7QAIkQAIkUGsCFNNajwDbJwESIAESiDwBimnkh5AdIAESIAESqDUBimmtR4DtkwAJkAAJRJ4AxTTyQ8gOkAAJkAAJ1JoAxbTWI8D2SYAESIAEIk+AYhr5IYxgB2bNyRk9ORFB42kyCZAACZQToJhyVlSXQKwFWLQYsbbPAnHx77wFgPyb/GhZaBc/AcbOQht9Bzh/Vv8bPyRAAiQQNQIU06iNWITsjS3+HGIdtwFzF6pZfekCtOHXoZ19W+16XkUCJEACdUKAYlonA9FIZsRmzkJsVbfwSG8I1q3z70E7tB/a1GSw8ixFAiRAAtNMgGI6zcAbvrl5CxG7/W4RzlX0Rh2AaBeFl/raS4D4lx8SIAESqHcCFNN6H6EI2Sc9Utz5jYqF1OiyFFQcfJEeaoTmAE0lgWYlQDFt1pEPvd8xtNyxLnho18keEfLNvrpHfKuFbjErJAESIIGwCFBMwyLZ5PXEFi/JrZNW4aOvn549VYWa66vKbOd9ePzeJEYHnsNT/aP1ZRytIQEScCVAMeUEqZyA2OrSsvZez6xd7eoUJs+N4OpHY8hemULLnHmY+elFmNEqtszErnG2Q2T5Zg/sCrxtpvDSb2Qw8Owz2Dsaq7zP+Rraex7C1q6EqwBm21ZgXfdqJDta0RbLta1paaSHhzGwvx9H8vbYialK/aF1hhWRAAkEJkAxDYyOBQ0CsdYbRdKRCPG6fC6ffQfjx/8MbbI8Q/ea+QuwoPMrmHFdwrEG7bU90DJnAkGXgvRwEki3tgKDPw3V63MTu6zWhnUPbMDaZK5fWjqN1NiY/v/j8Q60JWLib4PY9nQ/zgmRpZgGGl4WIoG6IEAxrYthiLYRLSvuBG4SauXwmRRCeuHQoPA+Y5h1/RLMbL1BeKVzkJ24hKnMe5h8/zQW3tGDmeJQB8fPSArZYwd9g9IFbeuD6BrbjV6sx8b4UEG8fFfmo4DR7lohmKOpPuzccVQXTPMn57G24tgOZzH10WSol67suQ9da4CBH76AIxa7Q22IlZFAgxCgmDbIQNayGy1f3eQY4pV7RT84sBsxEdZdcMddtoKpTU0gNjN/xKBTR2So95WdvrtphHjH+p7E89iMxzbEQw/12hm18v5HsSkphNTH+me9rJkWHkBah9FLMfU951igOQlQTJtz3EPtdcvd3wZa7Nc8L595C58cOYg5S5KYv/T24O1mryL70i99l9dDvGvGdFE4hE5s+f56xEMO9VqNKqzRDu/GD357TNlmiqkyKl5IAnVHgGJad0MSMYNmzkbL177paPT4ydcwcSqFT93ejZmJGyvqXHbvb4Cpy8p1ZLUVungmTaImPUanUK9ZBB/bkcYqsd7ZlU8ayiUMDZWFa53WOR+WIVKfyU52dbkJrAwTb9m4GksT+TVZBRt/cjxRWiadQm+vCOXmk6AMj9oKWROhaj8PBsqDxAtJoEEIUEwbZCBrmX5foQAAIABJREFU1g1FMV2wag1mXy8Ou89/sv/686qbbAjRyV1PYPvR3Hql3d8KNrV145GHViMhRHMgvhpdGEYqlUEarUgmyxOGzPUZ4dxKQqR+xFRe+8iGDiREhnJKZAUfTwPLEx1YKpKdNE0IpCk8W6x3EGNrViMurk+lM0iIPkkhNl/fLtZKe4Q2xztydaeHx6CnTKUPYDu361R9zrKB6BKgmEZ37OrGcrcw78TIGxg/+ifMuekWzO/8comYtojtMAvniQxbX58sPhoXyqHw0b3QjtJ1Pztv1SqmcvuK3Vqn3TqoVQAL9Wf8JzqpiqnZg95mSWwyvjNnLRv1yn6aHyzkfxt9KnngMJK2uGaqMMt4CQnkCFBMORMqJuCVgPThK336vtKFt3VjVlsu1Cs902vnt+O7G3+m3H5Wu4q+oR/j6Nv7PMu4iaadyOo2GZ6pgxDaCWUtxNS8DmzNtC14xiiKuWGjXajWVsAppp7zixeQgJUAxZRzomICXltjLr8nkpAOi20tItI6+4YlmCXWTmcc6vclpleuTmLngR8hNaK2PcY1nJs/acjqpXklDrkJVVmY1yRmqoBVPFPzlhu3es2hW/d1VyO0XUyWqiRUrdpXXkcCjUaAYtpoI1qD/igd2iAEdfzEa+LQ+indwutiU8piOnVlQqzXPY63z/5FqXfKgmNJqlEWU1P4006ocp6v/9OW/IhpV6tcK80dAGH/yaBfYf+qXZ8ppkrTjBeRQAkBiiknROUEVI8TFHtOL597F1cufIh5p48qienE5Cd4ft8/YSR9UtnOYrhWJNo46I08gSghBMmccestpvnsYFMYWEUAVQ1XqSuI0NEzVR0BXkcCwQlQTIOzY0kTAb8H3ausmY5PfIRfv/w9nP3gTV+sjSP+rGFccyW2wuW1ZlrI9jWFRG0Opy+srfo8C1hFTGUf7JKG3ABRTH1NH15MAoEIUEwDYWOhcgL+XsHmJaYXLmbwiz2P4vzHI75gq3putslEebGU2bwndz0nttMU39xSrNfizTq86aVk60pfX0ldRodUjhN0FX2xdaf32eIeUaPe9s5utI26H6BftIFrpr4mGC8mAQcCFFNOjdAI+Hk5uJeY/vHkLvzh1W2+bfMK1ZortK5tFsPDYn+lPBQ/I/eZivByYql444vYZ2qzZUbF6zPeFDMqDkjInXMfF/s4c2+Q8Tro3ql+w/vOHSYxhtSJDLBM7IfN7w8tCV+7vNrNiVehfmHzgNhrK/ecbu9XP83J98CxAAlEnADFNOIDWHfmz1so3iBzN2LiX9fQo8LWmP2Hf4VXDvs7QlAlxFvwyiwiU3IC0n6Ik4LWi0MN8q9Mk6IyeAB7Td6qrMfrCEDp0a66ay26knHxlpjiW3FGxRtkxlJD6N9XPABfNcxr9kB7xCEMho3y71KwB3oPiBONTF51ADEte+MNT0Cqu58aDaovAhTT+hqPhrBGeqj6i8IX3eDYHy/P1CgYRFCDQvTj1QZtg+VIgAQakwDFtDHHtS56FVv8OcQ6brN9o4yqmMqOTJegUkzrYtrQCBKIJAGKaSSHLUJGi20zWLQYsTZxLq94X2ls3gJxeEOL7xOQpkNQKaYRmlc0lQTqjADFtM4GpCnMmSXeXTo5obTP1Myj2oJKMW2K2cdOkkBVCFBMq4KVlaoQ8Hs2b7VDvhRTlVHjNSRAAnYEKKacFyRAAiRAAiRQIQGKaYUAWZwESIAESIAEKKacAyRAAiRAAiRQIQGKaYUAWZwESIAESIAEKKacAyRAAiRAAiRQIQGKaYUAWZwESIAESIAEKKacAyRAAiRAAiRQIQGKaYUAWZwESIAESIAEKKacAyRAAiRAAiRQIQGKaYUAWdwfAfEKT2iaOPt+/nzPglOXL+PKlSue1/ECEiABEqg1AYpprUegidr//PJOjLzzNi6Nj+PvN2/x7PmhP/9RXP+W53W8gARIgARqTYBiWusRaJL2pZB2LF+Jvb/fTTFtkjFnN0mgmQhQTJtptGvUV0NIZfMU0xoNApslARKoKgGKaVXxsnKzkFJMOR9IgAQalQDFtFFHtg76ZRVSimkdDApNIAESqAoBimlVsLJSOyGlmHJekAAJNCoBimmjjmwN++UkpBTTGg5KEzbNl7034aDXsMsU0xrCb8SmZ82ahbbrb3Ls2tkzp/W9o9O5NaZwU0UGA88+g72jYrNrSJ/2noewtSuB0YHn8FT/qF5rVluBLd9fj6VyU63lM5pOYaD3BRwJ0YaQutJw1VBMG25I67pDFNO6Hp7GNW46xVQK3sNJIN3aCgz+tCB6YdB1E9NkJoPU2FihmXi8A22JnMCe3PUEth8NT9TD6Euj1UExbbQRre/+UEzre3wiZ12ifTFuSa7wtHtRW5vnNWEc2pDV2rBu64PoGtuNXqzHxvgQtj3dj3M2XqOnQYoXGJ5pcng3fvDbYyWlCjf4TPXtUDS3YS/zK6Yre+5D1xpg4IciclDF+dGwwJu8YxTTJp8AYXf/ps/+DVZ98cuhVBuKmLZ145GHVmOs70k8j814bEM89FCvtbNuYiqvXXn/o9jYEX7IORToDVSJHzEtPHS1DqOXYtpAs2D6ukIxnT7WTdFSvYmpHuJdM6bfIA+hU1/LjIcc6vUrpjmbhAcU8vptU0wwH52kmPqAxUsrJkAxrRghKzATqCcxtfMQda/QIdRrvvk+tiONVQ9sQFdHK9pEyE/T0kgPD2HnjqMlIeJs5314/N6kbQKSbZjXCDs7eEDZNpG8tHE1liYSOlanduV37Z3d6FnTUXrtYF8xESrvlSdEuFm1P8ZYSjvWda9GMt9/+XeZPJUaPIC9R3OJVoVrTQx+cjxRar8o02uTcOVlu9kOVR5lDzWm/pvD7cWENOGFPvsC0P1fsClZvn6tpfrKwvT8tZOAEwGKKedGqARUxfRfXng+1HbtKjOEzpzsY/e34o07FxJOCNEciK9GF4aRSmWQRiuSyVzykJYeLFlz9SumdglLZlF6ZEMHEiLrODU8jONpYHlCiGUyIURViJIp/Gi0q6XTwsZh3caEsDEp1oYN4Sg+HKj3RxfpfIZyTsjHkDqRAZYJBh2CgXiwMGcuy+uLDAYxtmY14sL2VDqj2yMfCoLYbtSrysN2/G3E1C6zu12slfaIZ5e46J9kL/usp42lD2B7PkO76pOVDUSeAMU08kNYXx3wI6YtsWuwcJ7IsPX1yeKjcaEyCp/c2mTpGphKcpCdYMjmZH3SgynZBuPmmVqzeQ0xEh7PU06JScKL3Gb1fvOiYGQiu63vtbdpOJffdmMIh6/+GAJkkyBltLtWPFTYPaBIRtYsZYOZ8Xe/tkuv2ouH01SwhnkLY2+zRYprpgo/KF7iSoBiygkSKgE/Ynrt/HZ8d+PPlNvPalfRN/RjHH17n2cZN9G0E1ndE3IREv37/P7RpElo3DxT6z5T6ek5rZOa13atmaSFGz1yGcDvoz2XoeyRLBOkP17JUXbrkAUv2SYsauWjKlp+eDhlZpeG7aGvlycd9hqr2uU58XhB0xKgmDbt0Fen49US0ytXJ7HzwI+QGjmoZLhrODfvTVq9KK+EFauoyZu4aphXrhFu2iBCyCJ0bM0WNXt8bp0zh0sLoVgZ5hXrpP1HzpVt9/HbHxWRVn2gMPphZ4OX7UF42HErC3O3OmdQU0yVfla8yIUAxZTTI1QC1RDTqSsTYu3qcbx99i9KtirfjC2elLL4mDxCVTHVPdu8iFsTW4o3crlWWjzkobyzGfTvKO6RbRf1bRJrrE4JUn77Y2Q7mz1vqw2qDxRuYiq/c7M9KI8yW/ORBslHftwSiiimSj8tXkQx5RyYLgJhi+nE5Cd4ft8/YSR9UrkLxfCmSIRx0CZ5GlHC4ql4i0/umEDVMK81m9dxzdEjw9er4+0i87Znozi+0JIg5bc/0+WZmvtjZ7uKHV5M9IcXUwKSPLBDX++2Wa/Wr61wDFTs4TWNTYCeaWOP77T3LkwxHZ/4CL9++Xs4+8GbvvphhBHdjuyz9Si91kztskP9bo1xaMOaqOOrw/mLreudnmumNv2pZM3UmuVrFTTraVDmPlrbDYNH+VanB8sSyAoeNMU0yJRjGRMBiimnQ6gEwhLTCxcz+MWeR3H+4xFf9ql6GLZrf6aw4Mldz4mzc4v7Kc2hR3MSkZ8wr9ER26xgQ9jkmqrY+2g9CF+uubaN9hf+bs7aNddrPlnJnM2r3B+FbN4uq0dv80BRECkbwfZju77GrMDDbpKUZ/PmjpaU2chl23sopr5+Z7y4nADFlLMiVAJhiekfT+7CH17d5ts2r9CmmzdU9OTEXkN5KH5G7jMV4eXEUoU9luVvjbE7tCEXUsyHiy3JSG77O+X+R0PEi+uWMoydKd2PaloHDtIfaZ/XPtMyYfYhpqq2e9lh5mG+tmTbkl0kIS+adoJaTIwSb/YR+4tlG9v7S89W9j0hWaBpCFBMm2aop6ejYYmptHb/4V/hlcO/9GW4Soi34DVZRKAkLLhfbKXIr0PK6zX56jSP03+sr2BzEtMSobAkQeVOBpInIBVP5Mm9tu2A8EqLnnLuUPZc8lHOPnl4wxD69xVPaArSH4ON9YQi+Xen18fZeecFxnahZAXbS+3w5mH79h6nE5BMr8grfXWe8FzFqVdrxSEZOlOegOTrt9fsF1NMm30GhNz/MMU0qKAG7ZIfrzZoG9NZrtH6M53s2BYJ+CVAMfVLjNe7EghbTKdTUBtNfBqtP/zpkUA9E6CY1vPoRNC2aojpdAlqo4lPo/Ungj8HmtxEBCimTTTY09HVGTNmYObs2Z5NXRofh9/jBIOsoXoaYrqg0cSn0frjZyx5LQlMNwGK6XQTZ3sFAn7FtNoeaqOJT6P1hz8dEqhnAhTTeh4d2kYCJEACJBAJAhTTSAwTjSQBEiABEqhnAhTTeh4d2kYCJEACJBAJAhTTSAwTjSQBEiABEqhnAhTTeh4d2kYCJEACJBAJAhTTSAwTjSQBEiABEqhnAhTTeh4d2kYCJEACJBAJAhTTSAwTjSQBEiABEqhnAhTTeh6dRrVt1pxczyYnGrWH7BcJkECTEaCYNtmAT3t3Yy3AosWItX0WiIt/5y0A5N/kR8tCu/gJMHYW2ug7wPmz+t/4IQESIIGoEaCYRm3EImRvbPHnEOu4DZi7UM3qSxegDb8O7ezbatfzKhIgARKoEwIU0zoZiEYyIzZzFmKruoVHekOwbp1/D9qh/dCmJoOVZykSIAESmGYCFNNpBt7wzc1biNjtd4twrqI36gBEuyi81NdeAsS//JAACZBAvROgmNb7CEXIPumR4s5vVCykRpeloOLgi/RQIzQHaCoJNCsBimmzjnzo/Y6h5Y51wUO7TvaIkG/21T3iWy10i1khCZAACYRFgGIaFskmrye2eElunbQKH3399OypKtTMKqebQLbzPjx+bxKjA8/hqf7Rqjbf3vMQHl4DDDz7DPaOxqraFisnAYop50DlBMRWl5a193pm7WpXpzB5bgRXPxpD9soUWubMw8xPL8KMVrFlJnaNsx0iyzd7YJfytpms1oZ1Wx/E2kT5DXQ0ncJA7ws4Yrm5yhvv1q5ExTf5rLYCW76/Hktjdm2nMZYaQv/xozg3jTf3sPpW+UQBVMS08FJzZCoSQoppGCPGOlQJUExVSfE6RwKx1htF0pEI8bp8Lp99B+PH/wxtsjxD95r5C7Cg8yuYcV3CsQbttT3QMmeURsEQ067WDFLDY4Uy8XgH2oTAalq67CYdluAYYprMiLbHim0jHsfSRK5/sv3UYB+2V9kzMzoeVt+U4HtcpCKmuggmgXRrKzD408AeLMU0jBFjHaoEKKaqpHidI4GWFXcCN4m7n8NnUgjphUODwvuMYdb1SzCz9Qbhlc5BduISpjLvYfL901h4Rw9mikMdHD8jKWSPHVQahYKYYgjbnu7HOZOX2C7CjFtFmFFL9eEHvz2mVJ+fiwpiOrzbtv72zm5s2rAabcKm6Qh1+rF9Oq71EtPC2I3tRi/WY2O8fAxV7ayVmK7suQ9dMrz8QxEBsYlQqNrP66JFgGIarfGqS2tbvrrJMcQr94p+cGA3YiKsu+COu2wFU5uaQGxm/ohBpx7KUO8rO5X67yambt8pVe7leeXDvEkHMZXFC4JbYRgzDHunuw5PMW3rxiMPrcZY35N4Hpvx2IZ44FBvLcS0GBUZRi/FdLqnV03bo5jWFH9jNN5y97eBFvs1z8tn3sInRw5izpIk5i+9PXiHs1eRfemXSuXrXUx1QZ3GRBwlaNN0kVe/cwI4pgvRIXTq68/xgKFeiuk0DSqb0QlQTDkRKiMwczZavvZNxzrGT76GiVMpfOr2bsxM3FhRW9m9vwGmLnvW4Sqmec/HuhbndpOXodmeNavFmmcuqUjLJzEdW/6dsmxRrzCvYXxxbbU8jJltE0lMG2V7xTXW9PAQdu4QiUs2YUN5/bru1Uh2tOrh45yNYl24N5fFatc3I8lHcvjJ8QTWifbW5tsbTQ2KtnLhcXldzpZcvebvzANhZ4NdspcbZzt2K+9/1DPU62d89AcZG162tubnSkJEGR7bkcaqBzagK89Yrntbx0TauilZnnhmXVJQHV8zD6P9TcmEGNvBsuULzx8FL6g6AYpp1RE3eAOKYrpg1RrMvl4cdp//ZP/151UD4ySmxnplImMjYA6eopG8oycNDQ9DaBQSyQ4kRW5MahhCwEq3XqiLaS7juKu1NBwoxeaRDR1IiBCwbO+4aG95ogNL5U1US5WFDo3r9TXYVAqpEyeBZUuREAlPGHwG2496iekQxkQn4mPDSKVb9b5J4dRv2IOt+vqyFNBUvt9S4K03c3PYOi0SvlInMsKGDqy1sdlVTPNjcHLXE7rduvDZ/M08cQKPj+DraWtBTIcwEF+NLghGKVEOrUgKTnoym0nY2sVaaY94/ol35MZP1q+noKUPFJLN/IyveS7J9WNDqCmmVbt1VFQxxbQifCwsCbiFeSdG3sD40T9hzk23YH7nl0vEtEVsh1k4T6iSr08WH42LO7vLx3VrjEg8svPw3Lw3N/G1ZgZXIqaFLSHCE9pm8ULNnqSxP7O4hUQI8rPl230KDy42DwpGWSnCZvGSZcweltN3JYIn1onXPQAcs9hsCJ2dONolX+leaIfl4cJlDbrQf5eHI7vxUbY1L6ZOyWIGJ3Nf3NZMfY+v0XeRGS42Vdlu6fL10+HFVSVAMa0q3uao3CsB6cNX+vR9pQtv68astlyoV3qm185vx3c3/kwZUla7ir6hH+Po2/uUxNRta0yqT2xNOVo8NMBOTHM3d+e9jnbfVyKm5vVCaxaonbdt3MytgmeFE/hBwSac6LXmaW7b9gHAIQLgxs1OZA3R9zs+ThPH9WHFRqz1OVwQu2Kkw01M/Y5vMyeqKd8U6uhCimkdDUZUTfHaGnP5PZGEdFhsaxGRu9k3LMEssXY641C/LzG9cnUSOw/8CKkR7+0x7mumwovauF6EV0tF0ioSKlmZdgku6mKaO9whmb9Rv492x4MmzPPCCPUeyl/fZbP9x5eY2mQd2wmLm5drfNfeuQIrZIgZcbmtVoRBc2u+JZ6bk5i6hHPtQr1Bx8eXraY1U7ttVHbzzMkut2iJ3fjKhym3dfWo3isa2W6KaSOP7jT1TenQBiGo4ydeE4fWT+lWXRebUhbTqSsTYs3pcbx99i9KPfLa/qLiMancyCoSU8uN2umgifIOZ9AvkoPez2e6GmJsl5jkJoCugumQpKV7Y7YhY5kwJU59yh+Ikc6ItUKxWCjXl5NrxKKyKRvXtrzLiVUlQmPaGxx4fPTkLkVbVcXUtO7tJabWaInT+OrJXwrbrJR+ELxoWghQTKcFc4M3onqcoNhzevncu7hy4UPMO31USUwnJj/B8/v+CSNpkVij+FEVU5mlaXgcjp6pi+dXiZhaQ7Qqnpa5+ypiMh1ian4IsJ6Bq/LQogu0IVoZkeBjOjTK3F95elXCFE3wGmNZ1jo+vm31FNPS6EJOAB0Syxz+7jalKaaKP/g6uYxiWicDEXUz/B50r7JmOj7xEX798vdw9oM3feHxutHaekcWj8vtxqsLQOHmaAkXK3gTRvvWrEzVNVADhtea7vSIaV5Q7MLFdl6szd/sEpWsA+53TdtufNzEye+6cslDgPmhzEU0/Y4vxdTXz77mF1NMaz4EjWKAv1eweYnphYsZ/GLPozj/8YhvQF5rpjLMl/RYM9Vvlvkbv9wnaM2uNW/JMHtkrjdscaNdddcGbBIH6ttuczE8IbEFwy47V27taRvtLxzS7yTKKkIUVpjXyUM2rxG6rZmqeuS2yT4+x8e3raZs3pO7nitNWHN8mLL3TEvEV3V8FR7MfP84WKBqBCimVUPbfBX7eTm4l5j+8eQu/OHVbYEgOq4/mg6bt27N8FrLk4cgpMTG0uNij+FyfZ/pMAYG47kzWE2v+HI66N44ZF92SB760Pu0/bmtZpEu7oMU+xrzexetoVSn6xMiLIrBJxX2mZYfJO83AcnwuGS/9H2YiZy9EPtkIf91WTM1bxfxOivZ6ombBVsfH7FXNp3fK+s0Pr5sLYSfRZ/kofsyDJ0Syw2JpXr/nLbMFMZEHu4heMg9p9v7c+dA+xlfeqaBfv41K0QxrRn6Bm143kLxBpm7ERP/un28xFSW3X/4V3jlsNoRgua2XPeZyhv+4AHsNW2LMXuhZSKre5NrhWjmbp7yY5wChLucT0CyvoItd2KOEOD9J4Rn6f4eT+uJPnqb+qlLB2zL5q6Xhy0U37pjPtHH6wQk63tF/Yqp5C1PB5Kn8+gPC/KAC7H16PnRZfo5u25iqhLiNcbW6YHH3/j4sNV8AtJ+FBKXjAeiAZt5pM8l6bUKHvLQCv1ay0sVVMeXYhqteyTFNFrjFQlrpYeqvyh80Q2O9qqIaSWCOh2gVNcsp8MWthE+AT9ec/its8aoEaCYRm3EImRvbPHnEOu4zfaNMqpiWq+C6iebNkJDRlNNBCimnA5+CFBM/dDitf4JiG0zWLQYsTZxLq94X2ls3gJxeEOL7xOQgoZ8/RtcLKEf8r5c7OvcV3rAfC6s+aB+VmozvpO0EqZRKksxjdJo1d5Wimntx6D5LJgl3l06OaG0z9QMZ7oFtXj2renQcmGQPMhcrp/ywPHGnroU08Ye37B7RzENmyjrUybg92zeWoR8nZJ77JKYlDvOCyNBgGIaiWGqGyMppnUzFDSEBEiABEggqgQoplEdOdpNAiRAAiRQNwQopnUzFDSEBEiABEggqgQoplEdOdpNAiRAAiRQNwQopnUzFDSEBEiABEggqgQoplEdOdpNAiRAAiRQNwQopnUzFDSEBEiABEggqgQoplEdOdpNAiRAAiRQNwQopnUzFDSEBEiABEggqgQoplEduSjbLY8TlB9xpCA/JEACJNAIBCimjTCK9dwHh4PudZO1LLSLnwBjZ6GNvgOcP6v/jR8SIAESiBoBimnURixC9rq9gs22G5cuQBt+HdrZtyPUS5pKAiRAAuJlWF3dd2kEQQJhElB5Obhre+ffg3ZoP7SpyTDNYl0kQAIkUDUCFNOqoW3SiuctROz2u8V7SxdWBEC7KLzU114CxL/8kAAJkEC9E6CY1vsIRcg+6ZHizm9ULKRGl6Wg4uCL9FAjNAdoKgk0KwGKabOOfOj9jqHljnXAohvCrVmEfLOv7hF1cjUiXLCsjQRIIEwCFNMwaTZxXbHFSxBb1V0VAvr66dlTVamblUabQHvPQ3h4DTDw7DPYOxqLdmdofaQJUEwjPXx1YrzY/tKy9l5grvs6qXZ1CpPnRnD1ozFkr0yhZc48zPz0IsxoXYxY7Brnzogs3+yBXcrbZrJaG9ZtfRBrE+U319F0CgO9L+CI5cYrb8pbuxIYHXgOT/WPBgab1VZgy/fXI5kZwran+3Euxhu8HcxsWzceeWg1EshUJIQU08BTlQVDJkAxDRloM1YXa71RJB2JEK/L5/LZdzB+/M/QJsszdK+ZvwALOr+CGdclHGvQXtsDLXNGCa8hpl2tGaSGxwpl4vEOtAmB1bR02Q2cYqqENrSLdBFMAunWVmDwp4EfYCimoQ0JK6qQAMW0QoAsDrSsuBO4SdwZHT6TQkgvHBoU3mcMs65fgpmtNwivdA6yE5cwlXkPk++fxsI7ejAzvtgZ50gK2WMHlXAXxBTl3mF7533Yem8SWqoPP/jtMaX6/FwUpme6suc+dMkQ5g+FJ91AHm5hfMZ2oxfrsTEe3IuvlZg26tj4meu8tpQAxZQzomICLV/d5BjilXtFPziwGzER1l1wx122gqlNTSA2M3/EoJM1MtT7yk4lW93E1O07pco9LgpLTIve9TB6G01M8yHesb4n8Tw247EN8cCh3lqIaSOPTRi/gWatg2LarCMfYr9b7v62cE/t1zwvn3kLnxw5iDlLkpi/9PbgrWavIvvSL5XKU0yVMNXsopwAjukPCYfQqa8xxwOGeimmNRtGNmwhQDHllKiMwMzZaPnaNx3rGD/5GiZOpfCp27sxM3FjRW1l9/4GmLrsWYermOa9Ius6XVaEfx8X4V+7BKT2zm70rFmNpfmEJi2fxHRs+XfKMkmdPFNz/T85nsCWjbK+3BqxrK/XlBS18v5HsSlZnrhkDU1n20Syk7kesRacHh7Czh1HbROf/PTDgKzaRqHfw7vx2I40Vj2wQfQhIfo2WJKIZb7OCLPL/nqFev3aLu1e170ayY5WtOVD5HbJZ4VEKJPdXfkycm3dyjPssVHl5jnpeUHNCVBMaz4EETdAUUwXrFqD2dd/ttDZ7L/+vGoddxJTeUPetEFkkNpk2jqJqZGYJG+sqeFhpNNAItmBpMibSQ1D3KxLt2V4i+kgxoQwx0VdqXRGr0uKqqYJQc2Hc9vFWmmP0Nl4R4ee7ZoWSVR6GlX6ALbnM42lvY9syH0v7Tou7FqeEHVJATPVZUD22w9Zzk/KN4xQAAAgAElEQVQbZlGQ66DGw0CZmOYfWk7uegLbj+YeGAz25r+ZJ4df2wu25NmlTmSAZR1Ya8OmKKZDGIivRhfEuKQEc7QiKcZGT1gzPRCEPTaq3Kr2Y2HFoRGgmIaGsnkrcgvzToy8gfGjf8Kcm27B/M4vl4hpi9gOs3CeUCVfnyw+GhfK4fJx3RojEo/sPDc7MS3caF3E15oZ7CWm0myraBjeTonA5Lf3dLWWr5mavaltFi/U+M7seQfqh7F1RXhsSm0UtgRJIRqz3X4k+657oR2lfbLzVo3hDWS7sGXdA8AxCxtDlEs45/spvVe7qIQxNubv3NZMfY+NIjdfPxFeXBMCFNOaYG+sRr0SkD58pU/fV7rwtm7MasuFeqVneu38dnx348+UYWS1q+gb+jGOvr1PSUzdtsak+vqEZ1TcT2onprkbv/M+SLvvvcTULovYVshdxNS85mjN8rXzyoP0w28bZm/Q6QAFN9G0E9mi+PobA6fJ4fdBQ5+nNvuG3cS0GtyUfyC8sKYEKKY1xd8YjXttjbn8nkhCOiy2tYio3uwblmCWWDudcajfl5heuTqJnQd+hNSI9/YY9zVT4bVsXA8ptOabvlXQVDI27ZJfvMTUzvsxezPGOqJT+25et3k2GaHeQ2jXD7Cw83CN66398NuGFHSVLGa3cK7dd0HHoNCvzhVYsWypCIXHEY9DhGxza9QlXqbJA7fbKmU3l8IaG1VujXGXaPxeUEwbf4yr3kOlQxuEoI6feE0cWj+l23NdbEpZTKeuTIi1wsfx9tm/KPXFa/uLrYdiSUBSEYdaiqnV6y4Hk0H/jn68n8+WdTuRyUlMVduQpzy5eZ05D8/5VKqShwDT/t/AY6AnZq3XE8b0JKKMWHMWi85yvTu5RixymzKH7R5kzPbYCaeXmIbJTWnC86K6IEAxrYthiLgRqscJij2nl8+9iysXPsS800eVxHRi8hM8v++fMJI+qQxJVUwTYj2w4AmWiWnu5t9lc/CDk0eXEw374wTdsoWDeKZunqatGPjoh4pHaB0MTzE1PMCMSPApHkpVUo08oSphihh4jaMs7PYgYA03u4Z5TXOhlF/5eHqLqfreYC9uypOeF9acAMW05kPQGAb4PeheZc10fOIj/Prl7+HsB2/6guR1E7Zdo3QSU0s42DDEfGRhSbi4ymIq27dLWHIC5GSnVz/8tFHyEOEgSnbJP2WCbLM9yW29165vrslMNvW7JTjp/bIJA7s9bITNzdfE58U1JUAxrSn+Rmrc3yvYvMT0wsUMfrHnUZz/eMQ3JK81UxkCTHqsmeo30vzNVyYNWTNazds1pltMi4fECw/oWZtD+8UWoLbR/sJh/oH6UTiIXrEN4yHCRkxVPV3bZB+fY+AYGTCFme3WTGU278ldz5UmpRWSwCzr6yqZ1mKLjdLYuHDzPfFZoKYEKKY1xd9Yjft5ObiXmP7x5C784dVtgQCZPRbzQfcyC8U4KMGaCOSWUSvfPqOJBbeU2Fh6XOw/XK7vMx3GwGA8d3au6fVfYYV5jRCmfJONfkiE2Pso95Ru78+dJ2wWc7kPNbeXUuyNzO9NLbWpuF6p2g//beTDoXZi6pHkYx5kqydqXmvVbR+Te31b83t97cfA8A4lN33PaCLHBWI/LuS/dmumGXGdPHRfhqFTYkkhsVQv47RlpsC/4rFx5hZo8rNQzQhQTGuGvkEbnrdQvEHmbsTEv24fLzGVZfcf/hVeOax2hKC5Ldd9pvIGO3gAe03bYsxeaJnICi9k1V1rhWjmbqzyM5oaFHtV+4G7gp2AZH3Fm1MSjN4PcZKQPGxAfqzbaqynAum26aczHRBeaelr5GRdfvph8FRtwy28qhLiNdpzeqjxY7ve1/wJTDo3eeCG2Ar1/Ogy/bVvTglIj+1HIXFJLydZ2swVfb6ENDZcM22c+yDFtHHGsm56Ij1U/UXhi25wtElFTCsR1OmA4bV/czpsCKONRulHEBZe2bxB6mSZ5iRAMW3OcZ+WXscWfw6xjtts3yijKqb1Kqgq2zamBXKFjTRKP4JioJgGJcdyVgIUU86J6hIQ22awaDFibeJcXvG+0ti8BeLwhhbfJyAFDflW0jl5o92yXOzX3Fd6cHwujPigfv6s3SEMlbRZjbKN0o9qsZGhX/M2qWq0wzobnwDFtPHHuP56OEu8u3RyQmmfqdn46RbUYtas6bB5YZA8gF6un1oPca8/0DmLGqUf1eBLz7QaVJuzToppc457XfTa79m8tQj55hJwcm92MT4yyccuiakuoDoY0Sj9CJsxxTRsos1bH8W0eceePScBEiABEgiJAMU0JJCshgRIgARIoHkJUEybd+zZcxIgARIggZAIUExDAslqSIAESIAEmpcAxbR5x549JwESIAESCIkAxTQkkKyGBEiABEigeQlQTJt37NlzEiABEiCBkAhQTEMCyWpIgARIgASalwDFtHnHvnY9lycgyY84BYkfEiABEmgEAhTTRhjFeu6Dw9m8uslaFtrFT4Cxs9BG3wHOn9X/xg8JkAAJRI0AxTRqIxYhe93eGmPbjUsXoA2/Du3s2xHqJU0lARIgAfH+jq7uuzSCIIEwCai8z9S1vfPvQTu0H9rUZJhmsS4SIAESqBoBimnV0DZpxfMWInb73eJVawsrAqBdFF7qay8B4l9+SIAESKDeCVBM632EImSf9Ehx5zcqFlKjy1JQcfBFeqgRmgM0lQSalQDFtFlHPvR+x9ByxzrxIvAbwq1ZhHyzr+4RdXI1IlywrI0ESCBMAhTTMGk2cV2xxUsQW9VdFQL6+unZU1Wpm5VGg0B7z0N4eA0w8Owz2Dsai4bRtLKpCFBMm2q4q9RZsf2lZe29wFz3dVLt6hQmz43g6kdjyF6ZQsuceZj56UWY0boYsdg1zsaJLN/sgV3K22ayWhvWbX0QaxPlN135Yu+B3hdwpE5vyIWXVSPTEMIRVn8oplX67bLa0AhQTEND2bwVxVpvFElHIsTr8rl89h2MH/8ztMnyDN1r5i/Ags6vYMZ1CccatNf2QMucUYJsiGlXawap4bFCmXi8A21CYDUtXbdCpYtGEki3tgKDP8VT/aNKfa7Xi8LqD8W0XkeYdhkEKKacCxUTaFlxJ3CTUACHz6QQ0guHBoX3GcOs65dgZusNwiudg+zEJUxl3sPk+6ex8I4ezIwvdrZlJIXssYNKthbEFEPY9nQ/zol2jU97533Yem8SWqoPP/jtMaX67C5a2XMfumTY8YfCyzXVH7hCUbBg99hu9GI9NsbL7a+k/ukuG2Z/aiWm1Rjn6R4Htjc9BCim08O5oVtp+eomxxCv3Cv6wYHdiImw7oI77rIVTG1qArGZ+SMGnUjJUO8rO5U4uomp23dKlZtFr3UYvWGKaVs3HnloNcb6nsTz2IzHNsTr1oNWYWWEeMPoTy3EtBjhCHecVdjxmugRoJhGb8zqzuKWu78NtNiveV4+8xY+OXIQc5YkMX/p7cFtz15F9qVfKpWPqpjmBGNMF+hD6MSW769HPMKh3jD7QzFVmvq8qIYEKKY1hN8QTc+cjZavfdOxK+MnX8PEqRQ+dXs3ZiZurKjL2b2/AaYue9bhKqZ578+8Hrny/kexKRnDyV1PYPvR8qSlQhLNcC78Kq+1fqxh42zbCmzZuBpLE7l1YLlOmx4ews4dR0vCzkY9WU1cL8QzKdowws/SLqdQr/n6x3akseqBDcKuBLT0oB7afj8vxrI+u+9l6FvauK57NZIdrWjLh6qtCVp+2JjD5n77Y3Bo7+xGzxrJLcdYyyeMHVv+HdtsXpU+yHrMY2jw6Mr3225sjH6HNc5e42VeivCc4LygLglQTOtyWCJklKKYLli1BrOv/2yhY9l//XnVOukkpvJGvWnDaiQypWuR5hut3Tqq2Ss6tnwzeoQ+xjs6kBAZt2mR4KSnOKUPYHs+WSgr1mUf2ZD7PjU8jONpYHmiA0ul2Gkp29CwLPO4WMs1C7rd3+zE1yzwdmLq+n2+D6kTGWBZB9ZabPTDxrxlxW9/ZL8k561dklFa55YW3BLJDiRFLlZqGEL0S7fGFATKow+lYjqEgfhqdGEYqZQYP7QiKSrWE9PyDyJS2NrFmniY42wWU7vxoJhW7XYwbRVTTKcNdeM25BbmnRh5A+NH/4Q5N92C+Z1fLhHTFrEdZuE8caf09cnio3Fxl3X5uG6NEYlHVu/QbW3MTphdr897vgnhEW6zeKGGMNll6epeaEfp2pydd1cmphkpCGNl230KZV2+X/cAcMxioyFohqj7ZWPY57s/BjfLg44uhPkHDWsWtuyjSh/MYio98NGB58qypA1P1PxdmOPsNR6+fgK8uC4JUEzrcliiZZRXAtKHr/Tp+0oX3taNWW25UK/0TK+d347vbvyZcmez2lX0Df0YR9/epySmbltjUn19IqRb3HZi3LCtN1q7v7vdZM3rhNYsXyeP2U007URJ52eEhR32o3p97wTQTvD9sCmxzRSydhNZ+V2un857a72+N/fHtg8uYl1is0nMwxznoOOh/OPghTUnQDGt+RBE3wCvrTGX3xNJSIfFthaxDDb7hiWYJdZOZxzq9yWmV65OYueBHyE14r09xn3NVHgzG9dDCq35NJ2i51AaArb3sHKHQnRZsnndPGLzKFtDva7hXJvwr9PNv0RQDLG18fTM17V3rsCKZUtFSDqOeBwi3Jlb4/3/2Xvb4Ciuc130HRkBFii2B42Esc8xOTlbI0BctsveJw6ISKSg6tw6KWOw44qrUvePy4nvdVX+eyepslPJzq/8uVW5NrZTldx8EIgPQq6c2icxBoE+Lk7MjQEBGt042I5sC80wNgaBkGD6vqt7eqanZ3X36pkeTffM03+wpdVrvet5l/rp97NLLbR8PNc2lyPRO8isyy1zZ+ebbNjxLJHTpQOS0h4sHgOZK9+PB6ISPTudr+j/9WMHJgIgU5yFqhFQatrAhDp34RQ3rV/U17sntqhMpou35jke+SJdnHlXSVav8hcnd6vd+nGyGJ0sFqdmEeVCZ2j4oFH/qvxgttXFulmzXtah/ns9QepRPdFHT8DJcOyXg78iTpncxsFJWxaxX2xk3adKXigs+1EhGlk2r589eMV+ZToNVs/lCWZKhxmDIoMAyDQyqgqxoKrtBLnm9Oalf9Ctq59R24cTSmQ6v3CN9h/7AU2nJ5UBUCVTEdcsyUC1Zfo6lWN4P2TV6xILD/kMJ8QUmzWV7FV0bko4WdISV6oXmVpJ397r1ulFw/5zR2wK7lT1/XjpS+zHvp7fPXiTabn1HaieJdnaygcaAyOBAMg0EmoKv5B+G92rxEzn5q/Qb9/6Hs18+p4vALwezo4xQNPdqHdOukCbhCtX0kXJLZbmVUpi34g94Ue2UXnc1t3SUUpekhBxtdhUuh+3mKiMOF33l3cll7iqvWKmEjdwkHr28iT4OuAYHEoEQKahVEsUhfL3CTYvMr16PUO/OvI8Xf582jcYXjFT4d5M2iw9c5FCTG90jOJc7yi699hrT5WyPLn0YvDV8ob6ojync3ZYb7TvNo910zI3qNfDWYlM7SVClg8EyDJevbCpaj9mxi67f+1Z0NaSGdOSdnINW93mMjIV2byTh18rTT4rxGztcXR5bNxwkxvdqhIKevbyFPg+4LghlAiATEOplmgK5efj4F5k+vbkYfrTO/sqAsIxdskZNmYTBRlZWB96PfzQdaoJNd2Oek2kaCrA9YqipvTAsNHr1/rwF3WoRg0n1zPma1MLhOCRFGPdvGrMsvBS4OFWNC1oIb9eb5kw5COu7yTxr6TzkklgTth4uVLd91P80o/GgdtUVtSZduTrTKdodCxu9EK2fILNzx6K7nTeq/iIgHCrpzh0kOjR9+1UMlPQZRV6BplW9GccuZtAppFTWcgFbmvnL8jsohj/63Z5kam49/iZ39CJM2otBEstOfdPsKXGRuiopSzGLmfhIe3SDF8nbO46JJociMveAcneyUeMMboLjbBVapTkqLhEC+Roc11WY5kaD/fOQtckXX7RKIHLhfbPbtAtLqcv1rhhU81+CjLt2M6kaZCbjllqjOuCh4l2lHdA8rOHkg5Ix6mQfKXvXejF4UwEoWeQacifWQGJBzINCEhMU0RAWKj6h8LXrHOERYVMqyHUavThp6axmnWieG9UsfFjNUdRL5C5/giATOuvg4aVILb2ixTrflD6RRlVMl1qQi26A6P9+bNaHKooYwMyrcWJwJxWBECmOA+1RYDLZmjNWop1cl9e/l5prG01N29o8d0BqVKXr9/N+c3G9Tt/lMdHGRuQaZRPXjRkB5lGQ0+NJeVy/nbpwrxSnal147UiVLOpuWgBJBKUqv1weCMpq1GwAZk20qkM515ApuHUS1NI5bc3b61cviVfKxkbp+Fj8s+kNYVSbJtsFGxAps14epd2zyDTpcUbqwEBIAAEgEADIgAybUClYktAAAgAASCwtAiATJcWb6wGBIAAEAACDYgAyLQBlYotAQEgAASAwNIiADJdWryxGhAAAkAACDQgAiDTBlQqtgQEgAAQAAJLiwDIdGnxxmpAAAgAASDQgAiATBtQqdgSEAACQAAILC0CINOlxRurAQEgAASAQAMiADJtQKWGeUviy1qaxr3vV63yFHPx5k26deuW5zgMAAJAAAjUGwGQab010ETr/9PGXpr+4CLdmJuj//bEU547P/2Xt3n83z3HYQAQAAJAoN4IgEzrrYEmWV8QaffGzXT0398AmTaJzrFNINBMCIBMm0nbddqrSaRieZBpnZSAZYEAEKgpAiDTmsKLya1ECjLFeQACQKBREQCZNqpmQ7AvO5GCTEOgFIgABIBATRAAmdYEVkwqI1KQKc4FEAACjYoAyLRRNVvHfTkRKci0tkrBB7Briy9mBwJuCIBMcT4CRWD58uXUee/9jnPOfPShXjtay9KYnLaJnvr+o9Qjiloll5Yeo30vD9Mlh98HCsgSTgYyXUKwsRQQsCEAMsWRqAsCS0GmyUyGUtls+f7SkzR8bAJkWhfNY1Eg0JgIgEwbU69121Wiay19KbnJc/01nZ2eYypt2mBapsmpN+iHvz/nuU6jDPBrmW4eeJz6thGN/uh1OttgVnqj6BT7iA4CINPo6CoSkt7/wH+iLf/y5UBkBZn6g9EPmea0Ttr57NPU1zFFgyBTf0BjNBCQIAAyxbEIFAGQaaBw+poMZOoLLgwGAoEiADINFE5MFjUytbqEXziYpi1P7qa9yQSZSUqfUK+ezCRcxrLfm0lMuc5NtLN/KyW7O6gz7zKdTacoNTZCRydmSw6G15pizq7efhrY1k09iYR+r6alKT02RC8Nl85lndiJTAs/J7ZCX32dqP9feY/lyVlaaqip3OL4awUCQSIAMg0STcxFqmT6P17fXzO0/MRMrWMH6dECycjIVPZ7nfgGnqFn+5iABeFNZSl1IUO0oYOJtVsn1tnR10pI0HPNzU/Qi48lmdDTlEpNUZo6KJHspmTWPQYsI9MikWZo9NVX6OiskPdxGmCOjrN8CcroMutpWukROuBC1jVTGCYGAg2AAMi0AZQYpi34IdOW2B3U3tbhU/wcXZlLu97jVRozefjHdGDCsMwKxMaZv2mmlNFBTsZhwjEvz9939tNzz2ylRGa8rNzGjEtuT8RIdU23WGZXp0aXLLLZQbCTaUF2JkyTSIv7QszU58HDcCDgigDIFAckUAT8kOldq7rou3t+obx+TrtNQ+M/pYmLx5TI1Kk0Jn38dd1CKyFTCeGo/H7zN56nPd3lZFUgLZNsLZnFtSI5K5m+cJAM97TjvkCmygcPA4GAAgIgUwWQMEQdgVqR6a3bC3Ro5CeUmj7pKUxFbl6JZVlquTpbnm4ZsUXLtni/7GfWTRXcxsLNy3HS4bOXlGpii2Q6TqPxrZyp60LyyOb1PEcYAAT8IAAy9YMWxnoiUAsyXbw1z7G8F+nizLue65cQoEKdqRfxuv3eixQNWfIWIEnI1EW+rt7Hae9uI+ZqxGLH6dBB90YTJpmaCVBuCUUojVE6ShgEBJQRAJkqQ4WBKggETabzC9do/7Ef0DR3LVK9vAjSOo/XWHcy9XaVulqmCmTfxVnCA3u4NSLHXb3aIFrdvGay1Cxn6L4kaVwBMlU9TRgHBNQQAJmq4YRRiggESaZz81fot299j2Y+fU9xdWOYF0EGRaZinqpipgpkasrqtY6+b0t81ijjeVrPTrZnE5dYzGja4OtsYTAQcEIAZIqzESgCQZHp1esZ+tWR5+ny59O+5VtKMi0QmEs2rz126SWfLGvXL5mKNorWbOLy8hxvq9o38LgBCDQxAiDTJlZ+LbYeFJm+PXmY/vTOvopEtJazSBvdc4br8EHjqzFexOb1eyGgV53p5OHXuBSn2GxByXXMDRZS2Qyd5yqgjQlu3iAaSViaKphrWklSWmeaj9mK8hw7oRYTnVI0msroNacHhpunl3FFhws3AQEHBECmOBqBIhAUmQqhjp/5DZ0482vf8nnVmWpaqtCP1ossvX5vCmfvWCR+Ljog2etWDRer8Yk4p0b8RgN6I/lIXEbzhvGSL92okql1PfFJuhLyFUTLHZ+2M1Hr66ADku+zhhuAgIkAyBRnIVAEgiTTagg10E1hMiAABICABwIgUxyRQBEImkxBqIGqB5MBASBQIwRApjUCtlmnrQWZglCb9TRh30AgOgiATKOjq0hIumzZMmpdscJT1htzc+S3nWClMVRPYTAACAABIFAlAiDTKgHE7ZUj4JdMYaFWjjXuBAJAoLYIgExriy9mBwJAAAgAgSZAAGTaBErGFoEAEAACQKC2CIBMa4svZgcCQAAIAIEmQABk2gRKxhaBABAAAkCgtgiATGuLL2YHAkAACACBJkAAZNoESsYWgQAQAAJAoLYIgExriy9mBwJAAAgAgSZAAGTaBErGFoEAEAACQKC2CIBMa4svZpchsHyl8dOFeeADBIAAEGgIBECmDaHGEG8i1kK0Zi3FOh8givO/bauJxM/EpeVIu36NKDtD2uwHRJdn9J/hAgJAAAhEDQGQadQ0FiF5Y2u/SLHuB4nubFeT+sZV0qb+StrMRbXxGAUEgAAQCAkCINOQKKKRxIi1LqfYln62SNdVtq3LH5N2+jhpiwuV3Y+7gAAQAAJLjADIdIkBb/jl2top9tAuducqWqMOgGjX2Uo99SYR/4sLCAABIBB2BECmYddQhOQTFik98vWqidTcsiBUOvkHWKgROgMQFQg0KwIg02bVfOD7jlHLwzsrd+06ycMu39w7R/i3WuASY0IgAASAQFAIgEyDQrLJ54mtXW/ESWtw6fHTmfdrMHM4psz1Pk4vPpak2dHX6KXh2XAIFSIpugaeoe9sIxp99RU6OhsLkWQQBQgUEQCZ4jRUjwCXurRsf8wza1e7vUgLl6bp9pUs5W4tUsvKNmq9ew0t6+CSmdgdznJwlm9u5LBy2Uyus5+ee2YrJabeoB/+/lz1+6vxDDIyzWmb6KnvP0o9sXLymE2nKZsap+HzE3QpxORS0ANlqiJCkGmNDyCmDwQBkGkgMDb3JLGO+zjpiF28LtfNmQ9o7vxfSFsoz9C9Y9VqWt37FVp2T8JxBu3UEdIyHykB3UhkmsxkKJXNFvcdj1NPwsBJ09KUGhuiAyG1ZnUSTBKlOzqIxn5esdUNMlU69hhUZwRApnVWQCMs37LpEaL7+anpcC0wkV49PcbWZ4yW37ueWjvWsVW6knLzN2gx8zEtfPIhtT88QK3c1MHxmk5R7txJJbgaikwdrOuu3n7au3srdTKm1bqHNw88Tn3Cjfqj1+msxBJWAt02KKd10s5nn6a+7Bs0SI/Snvg47Xt5mC5VMH+9yLQWuFSCJe6JBgIg02joKdRStnx1r6OLV9SKfjryBsXYrbv64R1SwtQW5ynWmm8x6LRT4eo9cUgJh2YgUwGE6QpOVuFGLZBexxQNBkmmeVd7dujfaD89QS/sjlfs6q0HmdYKF6UDjEGRRABkGkm1hUvoll3fImqRxzxvfvR3unb2JK1cn6RVPQ9VLnjuNuXe/LXS/c1CpjqhVpm8VCvSMAgwqxP0aerV47/xCl29IFOlY49BdUYAZFpnBUR++dYV1PK1bzpuY27yFM2/n6IvPNRPrYn7qtpu7ujviBZves7hl0xznZtoZ/9WSnZ36G5Tcc2mUxyPHKGjE/LsWtk9GicGjQ4WM06d5h0dZHeqJXHILQEp6ZFEVbBOM6VuVJW1N3/jedqbLE9w0lJDJYlbYq6n9mwtidWmp8bp0EFOgJK4bQsyWWQXa3m5eoXremCbWMeQSWMdCKzObfy2NJtXZY/6C4clIe2Fg2na8uRu6svrWsSd7XsJGhcrHub6e5MJ3t9Yxa5vzz8CDFhyBECmSw55gy2oSKart2yjFfdys/v8lfvjL2sGhB8yFVbPs338YNMfqllKXcgQbehgYu12jEcK8ntud/73KSbdC5N8Tw8lODmIxl6hAxOxEhdscd5u2i4eolqqxKVaHZnmY5MWN63V/eu2dhfHSgc4lynOe02wq1iM1VOd0iOFpCZzr+L3qakpOp8m2pjoph7JPgq6zVvLk4d/rGNhtaCtP7MeAKsexDr8XkKJZDclOXcpNUWsj9LSGNU9lpLpOI3Gt1IfTVEqxfsl1jNP3MnkbSW2oHGxkqmIH5svMCDTmj0C6jIxyLQusDfWom5u3vnpv9HcxJ9p5f1folW9Xy4h0xYuh2lv46elrytHV+b4SetyqZJpYZzNqtMfwPkEmu38oC0hBdPK4Qfy4KulFqZVJPEA3fkk0Tmb9WaShoxorIlEMutOtmWZm9bX2maikCRmasVxn20f5u9kWbq6FdpdGoN124+rHvLELF52rHWmvvaY15lTspZpiZbiX/6SUnhZsFi6KrgUvQeCwLO6tW31TPg6/hgcWgRApqFVTXQE80pA+uzEkF5X2jTJ7uMAACAASURBVP5gPy3vNFy9wjK9a1UXfXfPL5Q3mtNu09D4T2ni4rFAyNR46DvXQMpI2XzwOllYXpuRkVDQlqmTDNK1XcjUGve0Z/kWSJxs7uV8fazMPS0jWSGrlx68fl/yEpMnOivJu5G18eJk1PQmLS9VbrFkv7gEkSjmda7w+/ojADKtvw4iL4FXaczNjzkJ6QyXtbDHb8W69bScY6fLTg/7ItNbtxfo0MhPKDXtXR6jYpmqJN7YH7KfUJdR7mEjEDcFdvVuok3CBUxxEl7gznyNaIkVJEkiUrdMy4nAlEdpbQcytVrmbvtzclnLXjbMl4YSq9yFzAv7cOmApLRHjyYeshcDp/NRCS5Oce3I/+FjAyUIgExxIKpGQKlpAxPq3IVT3LR+UV/vntiiMpku3prnGN6LdHHmXSVZ1cjUmYTMRewP2U/yWalWC8bZChRJO9zBSMTjRDw2w/FIDkiKWGByGwcALZmtVVmmEqIwEoYU1/Yg074OESu1NI0o23CGhg8a9aPKRGNJcFIhGlk2r689qpJpSdxZ7uYtkqwfXPJnLSIduZT+yDCoDAGQKQ5F9QiothPkmtObl/5Bt65+Rm0fTiiR6fzCNdp/7Ac0neYkH8VLjUydY2JFMi0lXFUytT5w7f1kg3bz2t3Ovtf2JFP1+tOiO5UTfBz4Nx7nZCcmaBMXJ3exVdV2MvW9R08yVXfzqng07MdU1cugeLwxLKQIgExDqpioieW30b1KzHRu/gr99q3v0cyn7/mCQ4VMxYResTinmKlbnFXM65psI3PpVujmNS1aa1ao77Vd3Kx+48Oy5KoyYpHs1U0PMuL0vUeTTCWJZrq+ZNZ9gLiATH39+UZ2MMg0sqoLm+D+PsHmRaZXr2foV0eep8ufT/veqCqZqmTzCjdnSRapmV3qUiPoWPtpyRCuJmYqCGbLjt20Vy/psZXZSJJpDII3LHGRnew7a9Uhc1nUhXbODuuZqaoWmzTZx8SU3b/27FhryUzRmpW76B33aMnmnTz8GpfrFGuHnaxct/0UG/jLM7qtuHi9XPk+3LghtAiATEOrmugJ5ufj4F5k+vbkYfrTO/sqAqFIkrYm8eZsljpKrzpT+8NXTOF0T4JdmDT2b3ptpWnVicYDek1jwqhdJa6hJPGvaszU1uheuElFXaS4xNyDL5f30/Wzdsl+RJMEllXUlB4YNr6244aPGFcgOB9f6rFbolYSFI0vUllRZ9qRrzOdotGxuNE72PIJNj97tJ4Hvel+RtSZctgg0eNaT1zYexW4gEwr+hOO5E0g00iqLcRCt7XzF2R2UYz/dbu8yFTce/zMb+jEGbUWgta1zIen2c3ILoe9w4/ReYcbEeQzbcV40QHJrR7Q6x7deuROO6LTjU584gsvQ0O0f3aD/nk4VTK1f4LNaC7BBHP8AluEDt2ZfKxtPOzZamVZRUMJXVZbByR7Z6IiPiMFGVRcvKYe5AlXwtrezqRpNMPQ10iNcZelYaId5R2QfOFr7YB0nArJWfpehZ4dOl0FgQvINMTPqoBFA5kGDCim4wqY1uXGh8LXrHOEQ4VMqyFU6AEIFMjbh9UM1IBApQiATCtFDvd5IhBb+0WKdT8o/aKMKpmCUD1hxgAPBFRj6AASCFSDAMi0GvRwrzcCXDZDa9ZSrJP78vL3SmNtq9l0bfHdAalSl6+3gBjR6AiATBtdw+HYH8g0HHpoLimW87dLF+aV6kytwIBQm+uYBLVbkGlQSGIeNwRApjgfdUPAb29euHzrpqpILwwyjbT6IiM8yDQyqoKgQAAIAAEgEFYEQKZh1QzkAgJAAAgAgcggADKNjKogKBAAAkAACIQVAZBpWDUDuYAAEAACQCAyCIBMI6MqCAoEgAAQAAJhRQBkGlbNQC4gAASAABCIDAIg08ioCoICASAABIBAWBEAmYZVM5ALCAABIAAEIoMAyDQyqoKgQAAIAAEgEFYEQKZh1UwjyyXaCYqLWwriAgJAAAg0AgIg00bQYpj34NDoXhdZy5F2/RpRdoa02Q+ILs/oP8MFBIAAEIgaAiDTqGksQvK6fYJNuo0bV0mb+itpMxcjtEuICgSAABDgj2H19e/QAAQQCBIBlY+Du653+WPSTh8nbXEhSLEwFxAAAkCgZgiATGsGbZNO3NZOsYd28XdL26sCQLvOVuqpN4n4X1xAAAgAgbAjADINu4YiJJ+wSOmRr1dNpOaWBaHSyT/AQo3QGYCoQKBZEQCZNqvmA993jFoe3km0Zl2wM7PLN/fOEZ4T0YhggcVsQAAIBIkAyDRINJt4rtja9RTb0l8TBPT46cz7NZk7DJPmeh+nFx9L0uzoa/TS8GwYRIIMASLQNfAMfWcb0eirr9DR2ViAM2OqMCEAMg2TNqIqC5e/tGx/jOhO9zipdnuRFi5N0+0rWcrdWqSWlW3UevcaWtaxlmKxO5x3z1m+uZHDymUzuc5+eu6ZrZSYeoN++PtzoUdVRqY5bRM99f1HqSdW/vCdTacpmxqn4fMTdCkkD2dBGM/2JZSwnjz8YzowESPznrC+RBTOEWWqIkKQqdKxiPwgkGnkVVj/DcQ67uOkI3bxulw3Zz6gufN/IW2hPEP3jlWraXXvV2jZPc4PY+3UEdIyHylttpHINJnJUCqbLe47HqeehIGTpqUpNTZEB0JgzXb19tPAhg6LfuIU7+6gBBNRasoiP49IH39dt9DCTqY6CSZZ3g7e19jPK/YagEyV/mwjPwhkGnkV1n8DLZseIbqfnzoO1wIT6dXTY2x9xmj5veuptWMdW6UrKTd/gxYzH9PCJx9S+8MD1Bpf67yZ6RTlzp1U2mxDkamDdS3Ia+/urdTJmFZr2W0eeJz6hBvyR6/TWYklrAS6bZBpWScz47Tv5WG6FNC8lchSyT05rZN2Pvs09WXfoEF6lPbEK99Hvci0FnqtBMtmuQdk2iyaruE+W76619HFK2pFPx15g2Ls1l398A4pYWqL8xRrzbcYdJJTuHpPHFLaRTOQqQCiQFhVuCELpNExRYMg08L5Ms9QdujfaD89QS/sjlfs6q0HmdZKr0p/gE06CGTapIoPctstu75F1CKPed786O907exJWrk+Sat6Hqp82dxtyr35a6X7m4VMdUKtMnmpVg/dqFumBgFm9ReM09Srx6/jFbp6QaZKf7aRHwQyjbwK67yB1hXU8rVvOgoxN3mK5t9P0Rce6qfWxH1VCZs7+juixZuec/gl01znJtrZv5WSHOMTblNxzaZTHI8coaMT8uxa2T0aJwaNDhYzNp3mHR1kd6olccgtASnpkUTlRFoqa2/+xvO0N1me4KSlhkoSt8RcT+3ZWhKrTU+N06GDnADl4L5VIVPpvvPJYyJG+bPzCdrJ627Px4hnU2O8puEyFjo2ZMrry/I7+wHxK39Bdgv2AisvV68eN95WlEnjMyR0fW7jt6XZvCo60l+YLAl1LxxM05Ynd1Nf/qyKuLldF0Hr1YqHuf7eZIK09FgkXfieD5AKB4BMKwQOt+URUCTT1Vu20Yp7Hyi60f74y5pB6IdMzSQY46GUpdSFDBEn0iS7ux3jkYIEntud/32KSffCJN/TQwlODqKxV/RMVasLtjhvN20XDyEtVeJSrY5M87E9i5tWde0ujpUOcC5TnPcqEoWEnHqqUHqkkNRk7tVIJJqi82mijYlu6pHsw6rQ6sl0nLLJbopnpyiV5kQm/m9BnPoDfKyDnhWlREygKZbH+J384V6J/KY+zKxjqwfA+jPrfq3nSODE71W6XEnOXUpNEZ+n0tIYVR2Vkuk4jca3Uh8xJinWF/E55Yk7TVzysemg9WolUxE/Nl/AQKaljzCQac0e6c0zsZubd376bzQ38Wdaef+XaFXvl0vItIXLYdrbrBmgKpjl6MocP6lcLlUyLYyTJMmY7s/t/KAqeaiaVgI/0AZfLbUw7WSy80miczbrzXzoyh7U1kQimXUk27LMTSvuVV7bTLSRxEytOO6z7cP8nVOWa7VkKjwEduKyWlxOv5Pqii1MP/LrVmh3aQzZTR+u5yjvhhcva9Y6U186yp85p2QzE5fS81P+kmWeH796LepSEHhWt7atnhWVv9pmGAMybQYt13iPXglIn50Y0utK2x/sp+Wdhqs3x5bpXau66Lt7fqEsXU67TUPjP6WJi8cCIVPjoelcQygjZfPB5WSheG1GRkJBW6ZOMkjXdiFTa9zQnuVbIHGSZ7lWS6YJ2QuOSUwS96IMw0rkdyNNGckKrL3OkdfvS17CLG5us4GHG1nrf0v5mmRr5rRbLNwvLkEkunn9XTTC70GmjaDFOu/BqzTm5sechHSGy1o4vLVi3XpazrHTZaeHfZHprdsLdGjkJ5Sa9i6PUbFMVRJv7A+pT6jLKJdwIBCZGrp6N9Em4QImrrtkL3CnGf+zdDuqjkyN5g6yEhSltR3I1GqZux0vu8u6YP1IHvD2edxiprKGG27WsH2uSuWXuXgLe8qTeYn16/IyYt7nloCkpCOPJiSyFxun810JLiovRnV+BIVieZBpKNQQbSGUmjYwoc5dOMVN6xf1zd4TW1Qm08Vb8xzDe5EuzryrBJQamTqTUJEQ8q6yPHl+ks/qVKmdNJJeuIORiGeJeGyG45EckBSxtOQ2DqBZMkOrIlPJg9bX2h5k2tdR3nShVAkZGs4nBZVYWFWSqcx9XAmZ+pFfmWgsCVoqRCMjU186UiXTkri53M1bJFl1vaqGHJT+OBt4EMi0gZW7ZFtTbSfINac3L/2Dbl39jNo+nFAi0/mFa7T/2A9oOs1JPoqXGpk6x5ScrCtVMrU+sOz9WIN289rdzr7X9iTTyupPVUjGK5vX3qe4MjJVl7/oTuUEn9KmTYWTF49zsha/YJh69XJ3ixvtZOpbR55kWv5i6GWZ9vmoKwaZqj14QKZqOGGUBwJ+G92rxEzn5q/Qb9/6Hs18+p4v/FXIVEzoFctyipm6xVnFvK7JKpK60EotU/M+a1al77Vd3JTVxIfrTaamfkXmqWp8W5YcZj94Ml25nSMZcfrWkUmmDt2kZOfULYzhV68gU7XHD8hUDSeM8kTA3yfYvMj06vUM/erI83T582nPlcseeIqN7lWyeYWbsCQL0yUJxsmiNWsxrW7EksxLGcGablJJnamYZ8uO3bSXG8uXldk4uFcd11bJ5nXIXBZ1lZ2zw9LMzjCQabFRvTzz2iq/Sgy95EXJQmyFlxp2/9qzhq0lM0VrVh5icNSRJZt38vBrXHpVrH12snLd9uMHF6+XQ99/nA18A8i0gZW71Fvz83FwLzJ9e/Iw/emdfRVtoUiStibx5myWOkqvOlP7w8t024kvpNhrUxPsAqSxf9PrTM23f1G4r9cEJozaVeIaRBL/qsZMbY3uhZtR1BWKS8w9+HJ5P10/a5fsRzQZYFlFTemBYeNrO274iHFOnxULA5n6kV/VmyHzaFhJUDTuSHFtbDpfG5tkd+roWNzofWz5BJsfHVnPs950PyPqTDnskehxrYcu6K5KvcIyVXsMgUzVcMIoVQTa2vkLMrsoxv+6XV5kKu49fuY3dOKMWgtB61rmw8fsZmSXw97hx+hcYxT+m5fogORWT+d1j249cqca0SlGJz7xhZehIdo/u0H/PJwqmdo/wWYQOD+gj19gi9ChO5OPtQ3Lg+PHLKtoKKHLauuAZO/sI8YY+Iy4yKCQ4CWzyCWlIaZO/MRMrTpXkV/FxVuQQ+pJEN6C7UyaRjMPHaN8VybaUd4Bydf5sHZAOk6FxDZdV0IPDp26gtIryFTt4QcyVcMJo3wgICxU/UPha9Y53qVCptUQqg9xMRQIhBoBP1ZzqDfS4MKBTBtcwfXcXmztFynW/aD0izKqZApCracGsXYYEACZhkEL3jKATL0xwohqEOCyGVqzlmKd3JeXv1caa1vNzRtafHdAqtTlW43ouBcIhAEBkGkYtOAtA8jUGyOMCBqB5fzt0oV5pTpT69Ig1KAVgfmigADINApaYhuhr3+HFg1RIWWjIeC3Ny9cvo12ArAfFQRApioo1X8MyLT+OoAEQAAIAAEgEHEEQKYRVyDEBwJAAAgAgfojADKtvw4gARAAAkAACEQcAZBpxBUI8YEAEAACQKD+CIBM668DSAAEgAAQAAIRRwBkGnEFQnwgAASAABCoPwIg0/rrABIAASAABIBAxBEAmUZcgRAfCAABIAAE6o8AyLT+Omg+CUQHJHFxFyRcQAAIAIFGQABk2ghaDPMeHHrz6iJrOdKuXyPKzpA2+wHR5Rn9Z7iAABAAAlFDAGQaNY1FSF63r8ZIt3HjKmlTfyVt5mKEdglRgQAQAALozYszUAMEVL5n6rrs5Y9JO32ctMWFGkiHKYEAEAACwSMAyzR4TJt7xrZ2ij20iz+11l4VDtp1tlJPvUnE/+ICAkAACIQdAZBp2DUUIfmERUqPfL1qIjW3LAiVTv4BFmqEzgBEBQLNigDItFk1H/i+Y9Ty8E7+EPi6YGdml2/unSM8J74UGCywmA0IAIEgEQCZBolmE88VW7ueYlv6a4KAHj+deb8mc3tNmtM6aeeTu2l7MkGalqbRV1+ho7Mx/Ta333nNi98DATsCXQPP0He2UckZA0rRQQBkGh1dhVdSLn9p2f4Y0Z3ucVLt9iItXJqm21eylLu1SC0r26j17jW0rGMtxWJ3OO+Ps3xzI4crKpsRhHfv5g00sK2behKJwhpaOk2p1DgNH5ugSzGDHO2XTpbPPk19HRlKT2UpywPOH3+dzjKZuv1uKRWV0zbRU99/lHoke5jlPWbFHs/zHvMvAEspm2wtQRjP9hX14CbP5OEf04GJGJn3zI6+Ri8Nz9Z7C+XnpLOfnntmKyUoUxURgkxDp1pfAoFMfcGFwTIEYh33cdIRu3hdrpszH9Dc+b+QtlCeoXvHqtW0uvcrtOwe54esduoIaZmPfCkgxw+5p/ZsZRI1yHI2naKsYMR4nOIdHdTJBGS3Nq0L5HofpxcfS5LsIe72O19CVjnYJNNkJkMpfXP5i/dovjyIPabGhuhACIioq7efBjZ0WHbNuuju0IkoxS8s1ivNLy7CCxB2MtVJMEmU5jNFYz+vmPBBplX+MdT5dpBpnRXQCMu3bHqE6H5+mjhcC0ykV0+PsfUZo+X3rqfWjnVsla6k3PwNWsx8TAuffEjtDw9Qa3ytMxzTKcqdO6kMlyBS01pwIpIuJsu9u7sdLQrzIW5aSNbF3X6nLKSPgZsHHqc+4QL8EVvGFiu0QKZTb9APf3+ubEZBXnt3b9VfHKq17Jxk8LGNsqHFl4Fx2vfysKOXoJo1anlvwUORfYMG6VHaE698H/Ui01rotZaYh3VukGlYNRMhuVq+utfRxStqRT8deYNi7NZd/fAOKWFqi/MUa823GHTat3D1njikhIr5gNvOFqmMCK2TFEg3U/4QdHu4LeWDr+hSnqJBn2Qq9logrCrckG4yKCnFYVDkyTT/0pYd+jfaT0/QC7vjFbt6l/JMmeqolV6rORNRvRdkGlXNhUjull3fImqRxzxvfvR3unb2JK1cn6RVPQ9VLnXuNuXe/LXS/aYLVksNSa01+ySbv/E87U2WE2+jkKlOqC4uaxVQa/XQjTqZGmckq7/knKZePX4dr9DVCzJVOYnhHQMyDa9uoiFZ6wpq+do3HWWdmzxF8++n6AsP9VNr4r6q9pQ7+juixZuecwhy3NOtngxSsE7zrlKTeOwLaekxenm0g/73PeUubfE7002pxwUtCU8iZpnmmKU9eSbXyclDekzXiBXr46bG6dDBYlKUSfRlsuRfFLzcvEULxEhUStoscCHDzv6tlOS4pXAFi0vElkcHjUQrcXnJUFhDYT/2faiQqexFwNSZiFH+7HyCdjKO2/M4zqbGGEPDZVwWN7f8rkwWn/LLsNfPnoer1zgfxVi+lsf73MZvS7N5VXSkvzCZoQ0+xy8cTNMWzkLvy+u1krPlV69WPMz194oseMvfhucfb4QHgEwjrLxQiK5Ipqu3bKMV9z5QEDn3x1/WRPxKLCj7A/2TrgF6qp+TSeIiA5hjjSlOXBLSpifp2LkO2jEg/53IDP5k8xN60pKRLTxFaeLkmmQ3JTmmZo1pCoJ4Lh+vTU1N0fk00cYEr6eX4KQK7twujpUOMNfGu43YrplVTOkRPaFInUzNzOSiq9jq/hXzpi5kiDZ058uA1GXQH+SK+wmeTMcpy/jGs1OUShtYC53pD/CxDnpWJJAxgaYYX+N38od7JfKbJG8NJch+Zt2zGWvXk8JY73xMjPPBR4qPC7/UlJbGqOqolEzHaTS+lfqIMUnxmeEzmOSJO01c8rFpr7PlV6/Wsyjix8Lbo78kgkxr8qzDpA2IgJubd376bzQ38Wdaef+XaFXvl0vItIXLYdrbrJmdKuDk6MocP4EcLhVLR/WB7tfN60bkXZ1aoTzFakHss1ih1geiNSu02pipPm+hzKeUTHc+SXTOJoMsucpVBotFpLIfK/4q+nKzTIU1bY+LWy1pp9+VEGCF8hsekNI4ttvLjVt8vhCaKKtlZs+Bqo7y+3BKNjNxsSaiBalXa2Y5F2WVeDdU/rKjPgaWadQ1GAL5vRKQPjsxpNeVtj/YT8s7DVevsEzvWtVF393zC+Ud5LTbNDT+U5q4eCxyZGq3Tsw4mzUzt4T0qJgQVSsydXwhyT+UVQndGjdU2U+QZJqQJI4ViEliEcmIuRL53UhTRrJiz17hB6/fl+Am05H5UiDBxDhb5a5+1xdASzxYRa9BJLopPwxCOBBkGkKlRE0kr9KYmx9zEtIZLmthr8+KdetpOcdOl50e9kWmt24v0KGRn1Bq2r08pio3r628xK9lKvRWcOMJNy/HSYfPXiop97BmGrvp2erqDYZM5TFTXebeTbRpQw+7kbnmM07sDjRiuCoWTCX7CZRMJSVB1nhqWZzalohVqfxu7lyp+1fiGbDr3/W8qejIYmHLyqQK50jhRa0SXFS8DFF7tvmRF2TqBy2MlSKg1LSBCXXuwiluWr+oz3FPbFGZTBdvzXN88EW6OPOukgb8vOHrb+ySt3yTGJ3au7k/+Iz6VbMphDWpyNo5yd6koHRzGRo2k2hcHsTKMVPJg9ZIgOLuSSKWJpKfMtzliYPDIo6X5AQqFcu0kv0ESaayJgmVkKnocuVXH6L0yvWFyJJNrkI0sjPlS0eqZNphdfWXx9INK7bY/Usdl/wLm0PNs9Ifb4QHgUwjrLzQiK7aTpBrTm9e+gfduvoZtX04oUSm8wvXaP+xH9A0J/+oXn7LQJzItxLL1CpjF5PVgElWeZfjJ9SVb1FYXjPqtL8gLFN7+Y/1YWntN+z0cuEkQyWegHCSqQ99FNypnOBT2rSpsLU4J68lmKBNbGVWoZdl6ltHnmSq7uatRK+qL3aqf8dRGwcyjZrGQiqv30b3KjHTufkr9Nu3vkczn77na9d+Yjdu8bVqydQU2k7WTnWttSJT2R5dE2UkNaluD1e/+wkTmQpZ/Mqv0v1K9kLn5jGREadvHXnFTGXeCRevh19cQKb9O/BtK1+PagyWI+DvE2xeZHr1eoZ+deR5uvz5dEWAl7QTHOK+tBPlDdKL7QTlVkklZGrN2nUi06JsvO6rxXpOc7yoQ+ycHS7UeVZqmYr7tuzYTXu5sbw1Bmu48RzqTvMPV+HCVImZWi3ZBJdiqOwnbGTqRx+qFps02Sf/kiKaidiznq0lM0Vr1qeOLNm8k4dfKznzTlauUjavol5BpiDTih7WuKkcAT8fB/ci07cnD9Of3tlXFczmQ7IYuzS+/CKybAqNErhgftDSoKDETevySSxpfMt8yxf1fdlMae2orRuT9eFZrPHkesB8Pand9VpMbOKGClw7KGpODwyfs5BiaaN74WYUdYXiEk0BBl8u7elrtcjE7/V6xISxPnH9I4l/bZ18nGQQc/ndj4mzSizRq2lDeTMMoy+zNJ7q0AlKVX57gw+3A2q3RK1JPXodMtfGpvO1sUmOY46OxY3+y5bP/JnWoYqOiqU3rEvRdD8j6kw5PJLo0fXqVDITlF5BpiDTqh7YuNmGQFs7f0FmF8X4X7fLi0zFvcfP/IZOnFFrIei0lmGdbae+fNG6OU50+UmNjdA5W7ZtNWSqE5TekN54cBlE5vypN3snHDHe6D40wlZpqSWtP4jz31XV57V1QLJ/gs3oeMMP6OMXyuYqEhljw3OKLjX6nKKRAFvx+2c3SMnISQZzPj/7CRuZ6i8Ets5EMn2ouHgLe3Nwl+vn0XJGzI5NtKO8A5J+fhV1VNIB6TgVksuMc8jnis/7UYmHJii9gkxBpuDDgBEQFqr+ofA16xxnViHToAg14O1hOiAQSgT8WM2h3EDEhUICUsQVGGbxY2u/SLHuB6VflFElUxBqmDUM2cKEAMi0vtoAmdYX/8ZfnctmaM1ainVyX17+XmmsbTU3b2jx3QEpCJdv44ONHTYzAiDT+mofZFpf/Jtz9eX87dKFeaU6UytAINTmPC7YtRoCIFM1nGo1CmRaK2QxrycCfnvzwuXrCSkGNDECINP6Kh9kWl/8sToQAAJAAAg0AAIg0wZQIrYABIAAEAAC9UUAZFpf/LE6EAACQAAINAACINMGUCK2AASAABAAAvVFAGRaX/yxOhAAAkAACDQAAiDTBlAitgAEgAAQAAL1RQBkWl/8sToQAAJAAAg0AAIg0wZQIrYABIAAEAAC9UUAZFpf/LE6EAACQAAINAACINMGUGLktiDaCYqLWwriAgJAAAg0AgIg00bQYpj34NDoXhdZy5F2/RpRdoa02Q+ILs/oP8MFBIAAEIgaAiDTqGksQvK6fYJNuo0bV0mb+itpMxcjtEuICgSAABDgj2H14ePgOAcBI6DycXDXJS9/TNrp46QtLgQsGaYDAkAACNQGAZBpbXBt3lnb2in20C7+bml7VRho19lKPfUmEf+LCwgAASAQdgRApmHXUITkExYphMEJ3gAAIABJREFUPfL1qonU3LIgVDr5B1ioEToDEBUINCsCINNm1Xzg+45Ry8M7idasC3Zmdvnm3jnCc2rBzovZgAAQAAIBIgAyDRDMZp4qtnY9xbb01wQCPX46835N5sakpQjktE7a+eRu2p5MkKalafTVV+jobAwwAQEg4IEAyBRHpHoEuPylZftjRHe6x0m124u0cGmabl/JUu7WIrWsbKPWu9fQso61FIvd4SwHZ/nmRg4rl83ktE301PcfpZ5YKQkIckhPjdOhgxN0yfa76kHwP0OucxPt7N9Kye4O6szLY8g4RaPHh+nsEpOYTqTPPk19HRmWIUtZ3tL546/T7MZv07N9CZodfY1eGp71v1HcAQSaAAGQaRMoudZbjHXcx0lH7OJ1uW7OfEBz5/9C2kJ5hu4dq1bT6t6v0LJ7Eo4zaKeOkJb5SGkrJpkmMxlKZQUliCtO8TxpaVqKBn/0Op2tE6FarT8hmZZOF+SMx7upMxHjn43RvpeHl5T0c72P04uPJctIs2vgGZCp0snDoGZGAGTazNoPaO8tmx4huj/pONsCE+nV02NsfcZo+b3rqbVjHVulKyk3f4MWMx/TwicfUvvDA9QaX+ss0XSKcudOKklcINOpN+iHvz9Xco9JDFpqqOx3SpMrDNo88Dj1bSMalRC2af1tZ8KcZRlkVrJhsXbQuYNLS6YmNpOHf0wHJuDaVVA1hgCBAgIgUxyGqhFo+epeRxevqBX9dOQNirFbd/XDO6SEqS3OU6w132LQSRrh6j1xSElWNzItujKnamKdes2/+RvP094kE2kIXaaCTL8jXgIQJ1U6ZxgEBKwIgExxHqpGoGXXt4ha5DHPmx/9na6dPUkr1ydpVc9Dla+Vu025N3+tdL8bmYoJBKHt6V56Ms119tNzz2ylhMRiVtpYjQeBTGsMMKZvaARApg2t3iXYXOsKavnaNx0Xmps8RfPvp+gLD/VTa+K+qgTKHf0d0eJNzzkqsUxlyUCz6RSNDnJs1ZIIZJ37hYNp2sKZr3tF5ivHOI9c3kq7esrdo6ZLuVqycpIxNTZCRydKE4Os8c+fnU/QU3u2Uk/CiElrvK9By77MsXZgzbjtJ5ufkMZSxfiu3n4a2CbmNvYt5haYneOkJVi5nkcVAxoIAZBpAymzLltRJNPVW7bRinsfKIiY++MvayauK5ma1mFmvJDgUxhPRhZr6kKGaEN3vjykNFnJOvcgPaq7bA0SGaPXUx20mfkq3t1NifxcevpTeoT2H6N8pmxlFnEh1qtn+5oydnAmMCcscSza7jYukukYZZns4pwhnEpnKJHs1knVmoQlLOanOEbLguukOJtK6Zm8lJ6k4WMT5ESmVplSPD/nUenzJ3mq1BSxbHAZ1+yQY+LQIQAyDZ1KoieQm5t3fvpvNDfxZ1p5/5doVe+XS8i0hcth2tv4yevrytGVOX5qu1xOZCqsqL272c3KRGeNC4rxO58kTvgpLZmRJeRYM4XTTDnllqtZXlJKmsX7iiSuuu2Ce9jyAmDea01osiYOWa1Ne0KRGbe1/9zJcpZl+brKlM8KRp2qqoYxrhEQAJk2ghbrvAevBKTPTgzpdaXtD/bT8k7D1Sss07tWddF39/xCWfqcdpuGxn9KExfZzFMgU3udqbhFPOBTQ68oZauahEFjPy/UV1qtWFmijlMCUjVkasR4S18ArNuXxWJNApRlLbuVwMhcs7LxXjJ5/V5Z6RgIBCKCAMg0IooKs5hepTE3P+YkpDNc1sIe0RXr1tNyjp0uOz3si0xv3V6gQyM/odS0d3mMvM6UXbgXLtC5s5ccaze7ejfRpg09bLlyTWqcuN7TiDFaXahepOhMpnmLlfxZpl7ZwfqLSb5JRdLqunaoGdXHOyRCqVqmKjJVGx8O83mHbEBAhgDIFOeiagSUmjYwoc5dOMVN6xf19e6JLSqT6eKteTow/CJdnHlXSVavbF77JCKx56k93DFJNEsQMckMd//hoKGIASa3ceBPZpk6ZOS6EU0l1poXeRtkWk7UTtZnMGRqdJiykrcdU5Cp0lHFoAZCAGTaQMqs21ZU2wlyzenNS/+gW1c/o7YPJ5TIdH7hGifv/ICmORlG9fJDptYWena3raubtwIydSM4p72pWIF1s0xdrGyQqeppxbhGQQBk2iiarPM+/Da6V4mZzs1fod++9T2a+fQ9X7vzR6Z5K0tCjtLEG9OlWgmZmvfaEqC8Nudl0brFTGXNIYJz88rjuG4vKF57xe+BQFQRAJlGVXOhk9vfJ9i8yPTq9Qz96sjzdPnzad87rYhMbZmyJW3/LN2KvOb2siQFQT+32yidSQ0NcSJUeeN4eztBlWxe0Zy+JEO5hjFT3VVsZuxyS8R9DlnQyOb1fXRxQ4QRAJlGWHlhE93Px8G9yPTtycP0p3f2VbRFL8KzT2qWioiGA6kUJyoljPpN4tpJEv/6iJmKuQv1l6KBAc8niPPAcLFHsEmO5pdiRHMIox+/pRm/rdG9V53p5OHXSoi5ljFTnUzzcVrRY1hv1M+Fpeepgzbqdab81ZuxuNGfGK0JKzrDuCl6CIBMo6ezcEvc1s5fkNlFMf7X7fIiU3Hv8TO/oRNn1FoIWtfyS6aCGMxORmIeo3xmiPbPbtDb//kl07Kvwkia6utr7thOfcl4IWtYrD3LxJRNjevNEuyfiTO6DRlNF8xL1qXJajnWws1rrl3YA8tUeDFIjXHz/mGiHeiAFO4/VEgXNAIg06ARxXzctH658aHwNesc0VAh02oIFWqoLwJecd76SofVgUDwCIBMg8cUM+YRiK39IsW6H5R+UUaVTEGo0TtOKuU80dsVJAYC7giATHFCaosAl83QmrUU6+S+vPy90ljbam7e0OK7A1KlLt/abq55Z9f7+W7MlLmjDZf506H9zFzzagw7rzUCINNaI4z5yxFYzt8uXZhXqjO13gxCDc9hKmQYWxv6s3iiyb+In5pfnLHHfcOzA0gCBIJFAGQaLJ6YzQcCfnvzwuXrA9wlGOqUECX7JNwSiIMlgEBdEQCZ1hV+LA4EgAAQAAKNgADItBG0iD0AASAABIBAXREAmdYVfiwOBIAAEAACjYAAyLQRtIg9AAEgAASAQF0RAJnWFX4sDgSAABAAAo2AAMi0EbSIPQABIAAEgEBdEQCZ1hV+LA4EgAAQAAKNgADItBG0iD0AASAABIBAXREAmdYV/iZdXHRAEhd3QcIFBIAAEGgEBECmjaDFMO/BoTevLrKWI+36NaLsDGmzHxBdntF/hgsIAAEgEDUEQKZR01iE5HX7aox0Gzeukjb1V9JmLkZolxAVCAABIMDf7+jr36EBCCAQJAIq3zN1Xe/yx6SdPk7a4kKQYmEuIAAEgEDNEACZ1gzaJp24rZ1iD+3iT621VwWAdp2t1FNvEvG/uIAAEAACYUcAZBp2DUVIPmGR0iNfr5pIzS0LQqWTf4CFGqEzAFGBQLMiADJtVs0Hvu8YtTy8kz8Evi7Ymdnlm3vnCM+JaESwwGI2IAAEgkQAZBokmk08V2zteopt6a8JAnr8dOb9msyNSaOFQE7rpJ1P7qbtyQRpWppGX32Fjs7GorUJSNuQCIBMG1KtS7wpLn9p2f4Y0Z3ucVLt9iItXJqm21eylLu1SC0r26j17jW0rGMtxWJ3OAvNWb65kcPKZTM5bRM99f1HqSdW/pCdTadodPB1OosHsOchyXVuop39WynZ3UGdeSwFgaWnpmj0+PCSY6gT6bNPU19HhmXIUpZ3cP746zS78dv0bF+CZkdfo5eGZz33hQFAoBYIgExrgWqTzRnruI+TjtjF63LdnPmA5s7/hbSF8gzdO1atptW9X6Fl9yQcZ9BOHSEt85ESsiaZJjMZSmXFI9e44vFu6kwYBDt5+Md0YAIWjQxQq/Unfq+l0wUcTQy19Bjte3mYLkleWJSUVMGgXO/j9OJjyTLS7Bp4BmRaAZ64JVgEQKbB4tmUs7VseoTo/qTj3heYSK+eHmPrM0bL711PrR3r2CpdSbn5G7SY+ZgWPvmQ2h8eoNb4Wmf8plOUO3dSCd8CmU69QT/8/bmSe3Kd/fTcM1spkRlfcjJQEn4JBm0eeJz6thGN/ogtdBsZmtbfdn7pmE0N0aGDE2WEaVisHXTu4NKSqUmaeBFagkOCJXwjADL1DRlusCPQ8tW9ji5eUSv66cgbFGO37uqHd0gJU1ucp1hrvsWgE7zC1XvikBL4bmQqJtj8jedpT3emKeNtRVfpFA1KyFRgszfJRBpCl6kg0++IlwDESZX+DjBoaREAmS4t3g25WsuubxG1yGOeNz/6O107e5JWrk/Sqp6HKt9/7jbl3vy10v1eZNrMD2U3Mi1Y7RKLXgn4Gg9qZr3VGFpMHwACINMAQGzqKVpXUMvXvukIwdzkKZp/P0VfeKifWhP3VQVV7ujviBZves7h6uYtJLHILTPhwnxqz1bqSRjxWyPhZlzq7hS/7+rtp4FtYrwRf9XyCU7nOCnGbkW5kYEZD5S5MP3IZMjTXSr/2JCemGNanXYANXbnCnd4tWQlS1gSCV+psRE6OlGaGGSNf/7sfKIUc75n0JIkZo4tkzsft/1k8xPSWKpf/XgeLAwAAi4IgExxPKpDQJFMV2/ZRivufaCwVu6Pv6xuXZe73cjULVlFPLSf291NCeLEJc5YPZ8m2phgYtLLMPgBb3OLmnMJwhXjOU+HEkmDyGb5fxIdpS7JSsjUj0wm6egJQymWhzp0eZJZI3bcxbHSAX5HiHcbezQzYik9QvuPUT5TVv6S4aUsKxZi3tSFDNGGDs4E5qQvjsva3cZFMh2jLL+MxBm/VDpTwM+Kt7CYn+IYLQuuv7TMplJ6Ji+lJ2n42AQ5kamTfpI8FcPDssFl7KVX/F4dAZCpOlYY6YCAm5t3fvpvNDfxZ1p5/5doVe+XS8i0hcth2tv4yebrytGVOWYtFTK1Z/OaD3a2xF5ySkxiF+c+W9KN6f6ksZ8XSi/cEpkKpGarg/RLpla3q5dMbu7brk6NLuVLgZzGFTOg/SdmuWKR9wSIhCar1W21Nu3WuGlB23/uhJ8sy7cS/fg6hhgMBGwIgExxJKpGwCsB6bMTQ3pdafuD/bS803D1Csv0rlVd9N09v1BeP6fdpqHxn9LERTajFMjUXmfqVuRvPKiz0qScAgFRkWi8kphkv/dLpn5k+oS6lCzLWpCpFxayWGzhhSPvYraq060ERpaAJBvvJZPX75UPJQYCgTwCIFMchaoR8CqNufkxJyGd4bIWDiuuWLeelnPsdNnpYV9keuv2Ah0a+Qmlpr3LY2RuXhFL3LubS2Ko3I1pLQdxA8N0PZ5WIC4ZcfohU78yiRKXgltTuHk5Tjp89lJ5WYtDzFj2wqByMLyyg/UXp3wTjaSlHMmJMPXxZvmSLRFK1TJVkana+LAKNhjTXAiATJtL3zXZrVLTBibUuQunuGn9oi7DPbFFZTJdvDVPB4ZfpIsz7yrJ7xQzdbKGrJ11Uhzvc74yNMy1lZ9Qr95hyUoO9nuCIlPR7UdFJrN5QhfHffdy3FfEKWXJU25EU4m1puIelhF1bcnU6IDlVz9KhwuDgIADAiBTHI3qEVBtJ8g1pzcv/YNuXf2M2j6cUCLT+YVrnBzzA5rmZBPVy5FMneJ3Hhm+9nVVrLjgyLTChCDOSh7Ywy0VOVZp7VbkWhrj0GHIDXcVK7BulqnFLa/ysqN6vjAOCMgQAJniXASCgN9G9yox07n5K/Tbt75HM5++50vGSjogOSW9OC3sZsVZLV1rgwG3Dj6y3/mVSSarXU5XMjXdsZzp66cxgpdF6xYzlTWHCM7NK9+Hk358HTIMBgI2BECmOBIBIeDvE2xeZHr1eoZ+deR5uvz5tG/5vJo2yLr8FB7gIqb6ankjfBFz7ZwtNne3uoztmbbWkgwrKRVLV0r72pprC9dsScarGTtUlMmatWuC5odMxT0lpThDQ9y/uLxxvL2doEo2r3BXy7CoBZma+xB9fEUNrap+fB803AAELAiATHEcAkPAz8fBvcj07cnD9Kd39lUkmxeZFn5vS0Zyq5UUdZklZMCu4S1PPq233jPrOs9zXedGUdfZwV9VGYsb/W8tre+sSUWiuUMqxbWeXMcqvsqS5TrLnmSyrAG/qkxF1zPXa2YzpTWytozZYqISf0GHZRB7OzBc7GFsJXehANF4wfheQJxLPY0vyNgb3XvVmU4efq2EmGsZM9XJ1OLSV9VPRYcNNwGBPAIgUxyFYBFoa+cvyOyiGP/rdnmRqbj3+Jnf0Ikzai0ErWt5kakYW3j424nG1tHIJJPRwRH+5Jiti48g1B3bmTSNhB99bGpM/zyZ+CyYtIzD8j1OMd7smHSk0+jiI+uAZO+y5CST0cC+KItBIuN6YwPr113KvgojK08x95aM85d2il/zEc0ospI5dUxt3ZeKcpZb+rUmU5NQZfo5xElktEOun2D/GDBbMyEAMm0mbS/RXoWFqn8ofM06xxVVyLQaQl2irToug9KLemvAfX2vOG+4pYd0YUQAZBpGrTSITLG1X6RY94PSL8qokmlUCRVkGt5DrFLOE17pIVlYEQCZhlUzjSIXl83QmrUU6+S+vPy90ljbam7e0OK7A1KlLt96wQgyrRfyxrp6P9+NXBcscXGbse4wfmauvqhh9WoQAJlWgx7urQyB5fzt0oV5pTpT6wJRIlSQaWVHI6i7itnZlob+PLlo8i9LoApqXczTvAiATJtX93Xfud/evFFy+YJM6368HBOiZJ+Eq7+0kCDqCIBMo65ByA8EgAAQAAJ1RwBkWncVQAAgAASAABCIOgIg06hrEPIDASAABIBA3REAmdZdBRAACAABIAAEoo4AyDTqGoT8QAAIAAEgUHcEQKZ1VwEEAAJAAAgAgagjADKNugYhPxAAAkAACNQdAZBp3VUAAYAAEAACQCDqCIBMo65ByA8EgAAQAAJ1RwBkWncVNKEAop2guLilIC4gAASAQCMgADJtBC2GeQ8Oje51kbUcadevEWVnSJv9gOjyjP4zXEAACACBqCEAMo2axiIkr9sn2KTbuHGVtKm/kjZzMUK7hKhAAAgAAf4YVl//Dg1AAIEgEVD5OLjrepc/Ju30cdIWF4IUC3MBASAABGqGAMi0ZtA26cRt7RR7aBd/t7S9KgC062ylnnqTiP/FBQSAABAIOwIg07BrKELyCYuUHvl61URqblkQKp38AyzUCJ0BiAoEmhUBkGmzaj7wfceo5eGdRGvWBTszu3xz7xzhORGNCBZYzAYEgECQCIBMg0SzieeKrV1PsS39NUFAj5/OvF+TuTFpNBDI9T5OLz6WpNnR1+il4dm6CI0PvtcF9sgsCjKNjKpCLCiXv7Rsf4zoTuc46Y2L5+j2NXn8847V7XTnFzc5b5CzfHMjh5XLZnLaJnrq+49STyxWNudsOkWjg6/T2dny34UY4SURzYqblhqiH/7+nNK6gmSe7UuQlh6jfS8P0yUJ7koTuQwCmVaLIO6vNQIg01oj3ATzxzru46QjdvG6XJ//+QgtZuUWRWu8k77wX9zv104dIS3zkRKaJikkMxlKZbOFe+LxbupMGCQ6efjHdGAChGoFtIRMtRQN/ohfOjyIseQekKnS+cSgxkQAZNqYel3SXbVseoTo/qQSmbb/8zaKrch3QMrf0bKsle5oj7vLPJ2i3LmTSvsqkOnUG2XWVa6zn557ZislMuM1s6KUhKzjoM0Dj1PfNqJRG1laX0LSHR1EYz/3dKmaVqnYThCWqaNscPPW8cRgaRUEQKYqKGGMKwItX93r6uIVN5uW6T0Du6ll5Sr/iApX74lDSve5kamYYPM3nqc93RkaffUVOtpk7t6c1kk7n32a+jqmyizPIplOUYq6KSkZU2rJ5uei/Hiq7gXFVTaQqdLZx6D6IQAyrR/2DbNyy65vEbXcoWSZCiI1PYctd7axe3eXGg6525R789dKY73ItJkTSdTIdJwGU920l+Ogbu5wM445efg1Sm9jggaZKp1PDGpMBECmjanXpdtV6wpq+do3PdeTxUzvuHMV3d2/2/Nec0Du6O+IFm96jnd187pYZmLiXCcnL+3ZSj2JhL6OpqUpPTVOhw5OSBNrunr7aWCbGG/EX7V8gtO5jd+m7whXqsX6dSPxIjGVx3L9yGTI010q/9iQ7q4VFvneZHmc2Ew2KlqmwsLM0AAncSUd3OGlpDxCCWHtOpCpivyeslks05+dT5TqiDEfdEgqE2vv7N9Kye4O6sy/xYkktNTYCB2dkMfw/ejU8zBiQNMgADJtGlXXaKM+ydR08+b++MsaCcSEmM/mTUpipmaMT1ZiIQjtud3dlCBOXJqaovNpoo0JJqYkZ6pKEnIKWaxMuGJ8mscnkgaRzfL/JDjsWC2Z+pHJJGSN106lWB7q0OVJZo3YcRfHSgf4HSHebewxPZUlPT0rPUIHmGxLyXSYOp/8V0d3uBl7FnHVnx0jw3UsIVNV+T1lK5DpGGX55SXOeKfSmQLeXvoRe01dyBBt6GBi5UQ0JlbZGXDSaZJ1yZDyvaU6rdkhxsSRQwBkGjmVhU9gP25eK5m2xO6g9jZ+Svm6cnRljlnL5XLM5jUfolz28ZKt7KOQmMQEvM9mhVqJw6xxdEtkKpAak2w1ZOpHJjf3bVenRpfysWFVN68ocfmka8BI1pK8lFjjzkcudUnJ1I/8ulfALZ6bJ1Mxzu56Nq1a689d9ZNfZzt7E5Tvya8vPBXNGGv39SfapINBpk2q+CC3XUkCkrBM71rVRd/d8wtlUXLabRoa/ylNXGRTSIFM7XWmbg9CwwWblZaDFB7yFsvLK4lJ9nu/bl4/Mn1CeUJTTRpyTUAqJhLJ9mElSWHxyvAR6vEjv6hNVSFTWf1r4eXFUhvrpR/7HoS8Xvd4/V75IGNgQyIAMm1ItS7tpiopjbnjz//TF5neur1Ah0Z+Qqlp7/IYmZtXxMH27mYrizNP7fWT5kNcWCpul+lKPK1AXDLi9EOmfmUS9aDF5gns5uU46fDZS2VxXj+WqU5wkixa+z5kZFqJ/CpkKnXPm+VOeQvabR5Tv3aXtsrLSDMnri3tEyWaq4FMo6m3UEldSdOGe2KLymS6eGueY3ov0sWZd5X27RQzlVkwpe5FESstNnkoXyxDwwfZ/Um9eoclp+ScolVWecy0SAhqMpldh7qY/PZy3FfEBGXJU77J1OZ6PS3ZuxuZ9nWoyx8cmRodsNz0Y5e5Up0qHUgMagoEQKZNoeYab7KCdoJtH6eUyHR+4RrtP/YDmk5PKm/CkUydYmUeGb72hZ3cmtZxQVmmsnpQFSC6OIt1YA+3VGRr29pMwS+Zmi8Gol2giC/upyf0HrklsUYTP4sbXMU6dMRV5oJ2qTN1dDu7uLwdLVOX8h5Ypionr3nHgEybV/eB7txvo3uVmOnc/BX67Vvfo5lP3/MlayUdkGRJLG6LusXPrFalPQHJJCV7K0PTRWslKb8yyeS1y1kJmVqJZ5S2ljV8cHq58Ct/UJapwMErvuk3ZuqkU18HE4MbGgGQaUOrdyk35+8TbF5kevV6hn515Hm6/Pm07014NW0wH/LW+Fvh4Spiqq+WN8IXMdfO2eFCg3yry9ie/Wstr7CSabF0pbQhvLm2cM1Ks0sVZbJm7ZqgBUGmVutU/Lc9bulEpr4xVcjmVYmZChlVsnmFC1qqH05kUtWp78OJGxoWAZBpw6p26Tfm5+PgXmT69uRh+tM7+yrahBeZFn5vS0aykqC9LlHUZZY8ePnBv+XJp/UmCGZd53mu69wo6jrZvTg6Fjf631qaNliTckRzh1SKaz25jlU0FMhy3WRPstR9aiUxI/5ZWitplalIaFx/mc2U1sjavgBTTFTiL+iwDGKeA8MiK9c51lhCjGU9fc22guXtBP1gWrJf0fzCKpsPN695aNzWNl5cXuOPHRQbN5Tqh5O4sqJ2OF+r66DTig4obmpIBECmDanWOm6qrZ2/ILOLYvyv2+VFpuLe42d+QyfOqLUQtK7lRaYlD2070dg6GumWmN7VaISt0tKOOeLhu2XHdiZNI+FHH5sao9HjwzQr6YCkW0zC+npyN23nRhDiMjsmHeksj0UWSEFRJqNJfFEWg+THafhYafemMhnyGLiRqZBFt3JJ8vEASczUqg97RyEvTEvwMWWrgEx1Pds6QhXXln+Gz0mnhzjxjHaUd7Wq418alg4ZAiDTkCmkEcQRFqr+ofA16xy3o0Km1RBqvXFEskq9NYD1gcDSIgAyXVq8m2q12NovUqz7QekXZVTJNKqECjJtqqOOzQIBApniENQWAS6boTVrKdb5ADeF5X/bVhPxz/yQaRQJFWRa22OF2YFA2BAAmYZNI80gz3L+OPjCvFKdqRWOSmOo9YAUZFoP1LEmEKgfAiDT+mHf9Cv77c0bJQsVZNr0xxsANBkCINMmUzi2CwSAABAAAsEjADINHlPMCASAABAAAk2GAMi0yRSO7QIBIAAEgEDwCIBMg8cUMwIBIAAEgECTIQAybTKFY7tAAAgAASAQPAIg0+AxxYxAAAgAASDQZAiATJtM4dguEAACQAAIBI8AyDR4TDEjEAACQAAINBkCINMmU3i9tys+rqJp3K531SpPURZv3qRbt255jsMAIAAEgEC9EQCZ1lsDTbT+P23spekPLtKNuTn6b0885bnz0395m8f/3XMcBgABIAAE6o0AyLTeGmiS9QWRdm/cTEf//Q2QaZPoHNsEAs2EAMi0mbRdp72aRCqWB5nWSQlYFggAgZoiADKtKbyY3EqkIFOcByAABBoVAZBpo2o2BPuyEynINARKgQhAAAjUBAGQaU1gxaQyIgWZ4lwAASDQqAiATBtVs3XclxORgkzrqBQs3fQI5Dr76blntlJi6g364e/PNT0eQQMAMg0a0Safb/ny5dR57/2OKMx89KFeO1rL0pictome+v6j1COKWm3XbDp8CcJMAAAgAElEQVRFo4Ov09nZ8t81ueqq2r4b5mJiLT1G+14epksSnVS1cB1vFh+Af7YvQbOjr9FLw7N1lERtaZCpGk6VjgKZVooc7qsKgaUg02QmQ6lstiBnPN5NnQmDRCcP/5gOTIBQq1Ki5WaTTO2YF4akJ2n42ATINCjAK5gHZFoBaD5uAZn6AAtDvRFIdK2lLyU3eQ5c09npOabSpg2FB7vEnVV4oGTGG85S8gS0hgPcMK9m2c0Dj1PfNqLRH7E3oYGs2mowqfRev2QK7P0hDTL1hxdGeyBw/wP/ibb8y5cDwakWZCoE2/yN52lPd4ZGX32FjsLdG4iuakGmOa2Tdj77NPV1TNEgyLRqPfkhU2DvH26QqX/McIcLAlEgUxHr+o6wdkCmgZ1lkGlgUNZsIpBpzaDVJwaZ1hbfpps97GTq9cad6+TkpT1bqSeR0HWnaWlKT43ToYPl8b6u3n4a2NZdOnZsqJCMYn14vXAwTVue3E193R3Uye5Kt3nFukKOnf1bKZkfL34mkqdSYyN0dKI02SXX+zi9+FhST4T52flEqfx8z6Ak4cpLdvPgquKhSqZubnZrQs9o4mnamyyPaWupoZJMVGX5aoCRFXd7AlJY9Gd9ADmRaeHnxB6AV18n6v9XJeyb7uHmsWGQKU5EoAiokun/eH1/oOuWPDTy2bxJSczULQNTPByf291NCeLEpakpOp8m2phgskwmmPyYlCyuRvNBqqXTlEpNUZo6KJHspmS2WHZQfHiN02h8K/XxwyqVyuhjkzxWJEPJslxNGQ3CzVLqQoZoA9/TzfcwEduzR4sP9THKbttKcZY9lc7o8oiXgkpk1wndDx4umNsVbe7PmgRWTGAyYtm04wka4PeZOO9Z6EPgoKeSpUfoQD5z1pd8BTINDiMnMg2L/uy4y8i0SKTFsEcXx6m9sK/ZH2+EJwaZRlh5YRTdD5m2xO6g9rYOn9vI0ZU5ZjmXyymzVDyYdTJi6+YlW52d9UGzz2aFmr+jsZ/rVqebddvVqdGlfBzWvE9GgEJ8EbsV1peVHN0sN3Pd7UzCJUSUJwoxpz1L2VzD/Llf2UVNohceOvG6lCPZ5bITpyiXkcWx3WT1oy/zxUBY74FiZLF2Tcs0LPqT/XnYybSgB35ZsYc8vDw4Pv9om2I4yLQp1Lx0m/RDpnet6qLv7vmFsnA57TYNjf+UJi4eUyJTe52psPSc4qRGHDUrTXQpPFjIsJo+oS6lxBivzGFVUrFuVmpd5B/qdheolURMwlZ9SPrBQ5ChV2lM+vjrJclepa7pDXozAfNlxdyvK/H70JcuXw0wklmmXsltS6U/LzJ94SDptdhJCZEaL0dI/lJ+MOUHgkz9IobxrgjUikxv3V6gQyM/odT0SU8NyOJ3Ika4dzd3fxFxIVtmqNXic5vc6i4tuPKEm5fjpMNnL5XVUHolfFRC0jICdo/dlXe98ZK9EjxUY6ZWfE3iSWfYRZ5/UbE2dXB6oFckn8SKLJC2pDOQF0aVvqgshf6cznBZ2KHDOaMdZOr5mCkbADL1jxnucEGgFmS6eGue42Qv0sWZd5Wwd3qwO1knxQeHiJUWmzyUL5ah4YPFLj5d/IDeyzFWp4QiZTLNl36cpl7DWnCpgbUTsNXqknXicZLBTfZK8KiETGXxuhIr3ME6qkg+n2Qq5PDUr21OGVHaz9BS6M+LTMV5FZfMk6HiFVD6I2zCQSDTJlR6LbccNJnOL1yj/cd+QNPcQUf1ciTT/MO5LOZYpUurizNvB/Zw+0JbQpE3mRptD03yVHEfB2HZWHGUya4iRzlJ5Pfio++raf05Pdi9LFM/9ad+rXcvjGQvMSrW3FLoz6llo/U8DtKjRrxekj+gW91V/k2o/q020jiQaSNpMwR7CZJM5+av0G/f+h7NfPqer51V0gHJnqjja8H8YHu8zDNmKnEvVhNz82OZ2vdnX9cvHn4tUyu5HaLdeo9be/KU2wPdt3wVWKZeGAUdMw1Sf7LzW16qZZQfSdcFmfp+BIBMfUOGG9wQCIpMr17P0K+OPE+XP5/2DbjXg901izZfa2dvhC9irp2zw4UG+dasXVNAJzIVbrXJw69xL+BifajVVWlNilLJBu2zxbr8Wl1+ZNdjzFx76IWHF+ZWJdqtMydLWCmbV1U+n2SqhFGF2bxLoT8vMhVfjbHGnsvKrUCmvp87IFPfkOGGpSDTtycP05/e2VcR2F4P9mJJQGkyklt9oKh1NEmvGPfies5sprQe1dJUoEiMXCfZwSVAGVFnyu7qRI9jzajYsFedYhkx+yAKVdm95LDiYbgFTZd16ccFigosxpulZTAOnwcrJgLx1364Rlese2DY+HyYqr50+WqAUaV1pkuhP1k9tTST2BL6sBOqG/YV/WE2+E0g0wZX8FJvLyjLVMh9/Mxv6MSZX/vegheZljyIbR11jM5AogNSsfuO8dm2EbbOipal0QTcSD4Sl9G8YbzkyyglbrXjXIqQj6sa43lOSTcjc7P2DkXi506fj/NDFGIeFdlL5fDGw6vO1MyEPr35Cb1bkyz5Rea61cmfO0dt58YZOm4V6qsWGLnNWW/9qZKp9UVIlJKV1Dx7YO/7D7PBbwCZNriCl3p7QZJpNYS61PuWreeVgBQGGSEDEAACwSAAMg0GR8ySRyBoMo0yoYJM8WcBBJoHAZBp8+h6SXZaCzKNKqGCTJfkyGERIBAKBECmoVBD4wixbNkyal2xwnNDN+bmyG87wUpjqJ7C1GgAyLRGwGJaIBBCBECmIVRKs4jkl0yjZqGCTJvlJGOfQADfM8UZAAJAAAgAASBQNQKwTKuGEBMAASAABIBAsyMAMm32E4D9AwEgAASAQNUIgEyrhhATAAEgAASAQLMjADJt9hOA/QMBIAAEgEDVCIBMq4YQEwABIAAEgECzIwAybfYTgP0DASAABIBA1QiATKuGEBMAASAABIBAsyMAMm32E4D9AwEgAASAQNUIgEyrhhAT+EVgZatxx/yi3zsxHggAASAQTgRApuHUS8NI1cKf+7w/rtF/5s9R3nePRnfdSSR+Jq6cRnTlBtFHn8bob2mi6WxM/xkuIAAEgEDUEACZRk1jEZK3u4vokS9pdPedagz52Y0YnXwvRlOXIrRJiAoEgAAQYARApjgGgSOwslWj/9qr0X+MVzb1h1mi/zkRYzdw3oStbBrcBQSAABBYMgRApksGdXMsdHebRo/+Mylbo06oCCv1jXeJPrsOQm2Ok4NdAoFoIwAyjbb+QiW9sEif/JfqidTclCDUg38RiUog1FApGsIAASBQhgDIFIciEAQE3e1+MFexa9dJCOHyHfprC6lFXQPZCiYBAkAACPhGAGTqGzLcIEPgnzo1+l8314by/v1sjP6/2eaxTnO9j9OLjyVpdvQ1eml4FgcOCACBCCAAMo2AksIuoih1+dZXvLN25xdz9OGlBfr02i2Ksa151+pl9B8SK6htRYvrFoW799f/j/+yma7OTTSwZyvFOzqoM2aQsZZOU2psiA5M1I6kugaeoWf7EhWToYxMq50z7GcI8gGBqCMAMo26BkMg/wNrNNr9z+5WaWp6nk6lrtItWyHpMubRB7vbacN/4AJUl2vo3Rh9cFndOt38jWdob5KLW/maTacoy+5iisepJ5EgTUvR4I9ep7N5gg0awmqJD2QatEYwHxCoPQIg09pj3PAr7OjRaPN9zmQqiPTtC5/rzRp616+ie9e0sl0ao48u36TJD27QbSbYf+lxJ9SzH8Xo2KQamZpkpKWGaN/BCbpkIc2c1klbdmwgOjZcMzKtVuFw81aLIO4HAkuPAMh06TFvuBX/t63OLt6bt3L0349fpluaRrseupvuvWd5yf6nMwt09N3PaBnz5J7tHXTncrnLV7h6/+9xNTLd/I3naU93hkZffYWORjDWCjJtuD8RbKgJEACZNoGSa73F/2NHjoS7VnZNsVV6kq3SB7pWUv//8gXpmKPvXqHp9E368oZ2St4vd/cyJ9P/dcw9tmpODjKttcYxPxAAAnYEQKY4E1UhIJrWf/urzHQO19uT1yj1j+v0cLKdNv5HOVGeY1fvqamr1MNx0//C7l6n65UTLUrN8c2YpczN67bZHCcsPcUJSyKuKi5NS1N6apwOlbmKedz3H6Xk1Bv0wsE0bXlytx6f1dJjtO/lYfpk8xPSbFwx/87+rZTsLiZEiXju6CDHby0WtMwytf8spxky9LjEfe3ZwEHtz+o2r+rw4GYg0EAIgEwbSJn12IoXmf558ipN/uMGPcRJRpseKJLp//mWmpVZyZ5EXHTns0/T9gTnDAuyGhuhox7Zu4KsntvdTQnKUGpqis5z4/2NiW7qESRpS1gyiUyQ6SA9ykRqZgo7k2nhHp4/PZWl1IUM0YZu2i6bX1IaU06mvMcnt7O8tstMsuJ48Q9/f67wyyD3BzKt5FTinkZHAGTa6Bpegv25uXlT0zc4+egq3c8lMF/757sK0ggybYndQe1tHT4lzNGVOWY6j0tPNMpbjLqV6UKquc5+eu6ZrZRgcixLWMr/jsZ+Xqj5LBBjhomRsmqWJVuSO58kOmezck0revLwj7lcxyBlFctUtn3zJaKvY6okWzno/Xlhj98DgWZEAGTajFoPeM9uCUg3FnI0OJLhBCRiMr2b7u8wEpAEmd61qou+u+cXytLktNs0NP5Tmrh4TP2evGtVWIDimk2Nsdt2uCTDVxDad7ZlpeUyBYKicd2FK6wyq5UpS3Lyk0BkEl0JWStYpjIAZMQsxgW9P2XwMRAINBECINMmUnattupVGnOB3bx/YXfvHVwb08Ou3vvWrKCD/+8KX2R66/YCHRr5CaWmT1a0DT1euefRvOvXcMcaxFh0CbtNbHX1Fi3TIsFa73Uj067eTbRpQw+7Z+Oi7JU68/FZa3yzEsvUac1a7K8iBeAmINDgCIBMG1zBS7E9laYNglD/yklGIitXXJ+1rFUm08Vb83Rg+EW6OMOfkanyEpm+IsZpklfRNSpipaKzg9OVoeG8RWuNmVrjkuadUjLUk5s4YUjEcUViUyarN5LghkyU3NZN1VimbuRei/1VqQLcDgQaEgGQaUOqdWk3pdpO8PrNHP2DS2CucDvBkx/dpUSm8wvXaP+xH3DpzGQgm7IToVOc0W0xv2RqJTS7W7haN6/b3GIPtdhfIIrAJECgwRAAmTaYQuu1Hb+N7lVipnPzV+i3b32PZj59L7BtyYjQtFatSUDBkmmxlMZuyaq6dJ3cuE5xUqv8Qe8vMGVgIiDQQAiATBtImfXcit9PsHmR6dXrGfrVkefp8ufTvre1eeBxovMjXLtZ2szemuFbkj1rZvMSZ8G+WlrzKRbv6u2nzlluP5ivBfVvmebJNFMaY7XGMyuJmVqzdGXu5oLbOeD9+VYIbgACTYAAyLQJlLxUW/TzcXAvMn178jD96Z19FYluWmLi5kKTe5Hwk2+WIJo52Mmn0OhBb9Rg1oF2cIMFo/bU6p71S6ZCDlMmUaKTSnFJTcKYm7imlcS/1tIbhWxea9OG2RQ38pcglT7+eqGdYpD7q0gpuAkINDgCINMGV/BSb+/uNo0e/Weiu+90/4qMF5kKuY+f+Q2dOPNr31sodBqKc6chTvgxL0GsKZcGDsICHdgmOiCV3jM6WGrlVkKmZXWvTNqpoSHaP7tBr3H1S6bWFwYngOxu66D251shuAEINAECINMmUPJSb1FYqP+1V6P/yKUfTpcKmVZDqEu9Z6wHBIBAcyMAMm1u/dd0991dRI98Sf5FGVUyBaHWVEWYHAgAgYAQAJkGBCSmkSMgymbuj2v0n7kB0X33aHQXt+cVP/NDpiBUnC4gAATCjgDINOwaakD5RHP8+UVSqjO1br/SGGoDQogtAQEgEDIEQKYhU0gzieO3Ny8s1GY6HdgrEIgWAiDTaOkL0gIBIAAEgEAIEQCZhlApEAkIAAEgAASihQDINFr6grRAAAgAASAQQgRApiFUCkQCAkAACACBaCEAMo2WviAtEAACQAAIhBABkGkIlQKRgAAQAAJAIFoIgEyjpS9ICwSAABAAAiFEAGQaQqVAJCAABIAAEIgWAiDTaOmrMaRdvtLYx8J8Y+wHuwACQKDpEQCZNv0RqDEAsRaiNWsp1vkAUZz/bVtNJH4mLi1H2vVrRNkZ0mY/ILo8o/8MFxAAAkAgagiATKOmsQjJG1v7RYp1P0h0Z7ua1Deukjb1V9JmLqqNxyggAASAQEgQAJmGRBGNJEasdTnFtvSzRbqusm1d/pi008dJW1yo7H7cBQSAABBYYgRApksMeMMv19ZOsYd2sTtX0Rp1AES7zlbqqTeJ+F9cQAAIAIGwIwAyDbuGIiSfsEjpka9XTaTmlgWh0sk/wEKN0BmAqECgWREAmTar5gPfd4xaHt5ZuWvXSR52+ebeOcK/1QKXGBMCASAABIJCAGQaFJJNPk9s7XojTlqDS4+fzrxfg5mjOWXXwDP0nW1Eo6++QkdnY9HcBKQGAg2GAMi0wRRal+1wqUvL9sc8s3a124u0cGmabl/JUu7WIrWsbKPWu9fQsg4umYnd4Sw6Z/nmRg4rl83kOvvpuWe2Eo39nF4annWcV0ZKOW0TPfX9R6knVk5Ss+kUjQ6+TmdtBGbek8yM076Xh+mS5F4hhClXgjJVESHItC6nHIsCAVcEQKY4IFUjEOu4j5OO2MXrct2c+YDmzv+FtIXyDN07Vq2m1b1foWX3JBxn0E4dIS3zkZKsQZBpMpOhVDZbWC8e76bOhEGwk4d/TAcmimSrSqY6CSaJ0h0dnkTvtlGQqdIxwCAgsKQIgEyXFO7GXKxl0yNE9zNLOFwLTKRXT4+x9Rmj5feup9aOdWyVrqTc/A1azHxMC598SO0PD1ArN3VwvKZTlDt3UgnAQMh06g364e/PlaxXsCxtFqgKmea0Ttr57NPUl32DBulR2hN3t2LDSKabBx6nPuFe/hFb5w7Wt5KCMAgINCACINMGVOpSb6nlq3sdXbyiVvTTkTcoxm7d1Q/vkBKmtjhPsdZ8i0En4YWr98Qhpa3VikzF4pu/8Tzt6S510yqRad71nB36N9pPT9ALu+MVu3rrYZkWXgY6pmgQZKp0DjGouRAAmTaXvmuy25Zd3yJqkcc8b370d7p29iStXJ+kVT0PVb5+7jbl3vy10v21JFO3OKtbzNS4L6sT0Wnq1eOycY+YrtNmQaZKxwCDgMCSIgAyXVK4G3Cx1hXU8rVvOm5sbvIUzb+foi881E+tifuqAiB39HdEizc956gVmTpZZ16WaeH3FtexbuF6uHq7evtpYNtW6snHarV8AtS5jd+WZvPmOjfRzv6tlOzuoM68G1aWNFVwV7M8LxxM05Ynd1Nf/h5NS1N6apwOHZwoJFIJWfcmyxOytNRQiStcrP/UHiGvEfuWzSV+bsXDXH9vMkFaesw1gctT8RgABOqIAMi0juA3xNKKZLp6yzZacS83u89fuT/+smbbrxWZCovw2b4EzY6+VpIl7EmmvY/Ti48lSxKXcpKfWQEx1xKElJqaonSaKJHspiTnLqWmiAmztDSmIANnCqenspS6kCHa0E3bBUlpqRLXbJFMx2k0vpX6aIpSKb6POijJE4tEKyuxdXGsdID5Md7dTSITWcyvp2alR+hAPlta7Oe53cbvhbznWd6NiW7qka2fz5hOMpmL+LFJ1CDTmv1JYOIlQABkugQgN/oSbm7e+em/0dzEn2nl/V+iVb1fLiHTFi6HaW9jdvB15ejKHD+pXa5AyNSezctEIqy9WbbGXrInJpnk4FAaY8RZS2ONMmu18KKRj68mJPOZJCxI1lpnKubb+STROYtFKeYzSdmagWzio+/H9mIg7jEtUevv3GKmVkt3n219mS6KLx+CwLPSciNfRwKDgUAIEACZhkAJURfBKwHpsxNDel1p+4P9tLzTcPUKy/SuVV303T2/UN5+TrtNQ+M/pYmLx2pOpvY6Uzt5WQVws0zdSFNGsiaZ2ZOcrOvJkqCcAJGSmQtZ67qRvBy4kak1HmzP8i3cR8XsZasVjcYTyscfA0OOAMg05AqKgnhepTE3P+YkpDNc1sJhtxXr1tNyjp0uOz3si0xv3V6gQyM/odS0d3lMIJapJb4pYpd7d29lF6Y8k9WVTF3cuTJXr0rWrFsCUlfvJtq0oYdljVM8TuyyNeKXJVamSaaS8h+DTPNlPCUEmP+ZLZvXHLs9H9d1Oq9WV7OXWzwKZx4yAgE7AiBTnImqEVBq2sCEOnfhFDetX9TXuye2qEymi7fmOTb3Il2ceVdJVqvb0V4r6mXhOVmSBfeqLenGyZKzkpIn0VjmVCEaaUaxnvzDnZtEvFMkEWU4rsmBTRFrTW7jAKslc9gLHxmhOydfmSQrYqXFJhflisrQ8EGjO5Sbta6kYAwCAiFEAGQaQqVETiTVdoJcc3rz0j/o1tXPqO3DCSUynV+4RvuP/YCm05PKsKgQkmdmrs1qs1pgqh2Qik0eOMHHgWdEZ6VER7FuVWYV2jduJ9PiXsrbFLq6eR0tU6OlorXUx5tM1etPQabKRxkDI4QAyDRCygqzqH4b3avETOfmr9Bv3/oezXz6nq+tu5GLOZFnN6MAOiDJkn/sGzEtXqsb1i0mKtubazJT3s0sdfM6JEzJLFc397OZsGR/yXBSGsjU13HG4IggADKNiKLCL6a/T7B5kenV6xn61ZHn6fLn0xVtvVBawrWLg4PDJc3plaxMB6tNnumqbsmVkaks2SdPgKKO054day2ZMZN3nCxx6z5lZCqyeScPv8Z9hosfA3B6EVHK5hUx5VfLPwQgYs6ds0UdgEwrOtK4KeQIgExDrqAoiefn4+BeZPr25GH60zv7qtq+tdmAaF6g963nrByzqYBrmYuXC9SSjCTNfvVI8rFuzG6JWklQ46BnKivqTDvydaZTNDoWN3rkWj7BZu5VNHbQa0YTXDPK5TzENZ8k/pXFTLn8R2+6nxF1puxGT/To9ziVzBRfUPjrObyGqCk9MGz0L7aSfLHO1ZDB/pUckGlVxxo3hxQBkGlIFRNZsdra+QsyuyjG/7pdXmQq7j1+5jd04oxaC0GntbrYytvLCTjmF1/EOEGsqbEROmqxyMz7VR70BeLIJw7JyFTFxVtYU+aK5YzaLTu2M2ka5KbLnRrjzkTDRDvKOyAJAhadjEQnIXHpzR6Ghmj/7Iayz9GVdEA6ToXEJf0+0WXJERtONuI1RCMIfawtGcvescnEenRwhD0DVus3b8k7vLBE9uxD8KZGAGTa1OqvzeaFhap/KHzNOscFVMg0KEKtzS6jO6tXNm90dwbJgUD9EACZ1g/7hl85tvaLFOt+UPpFGVUyBaEGf0xApsFjihmBAMgUZ6C2CHDZDK1ZS7FO7svL3yuNta3m5g0tvjsgBeHyre1GozM7yDQ6uoKk0UEAZBodXTWOpMv526UL80p1ptZNg1CDOQIg02BwxCxAwIoAyBTnoW4I+O3NC5dvMKoCmQaDI2YBAiBTnAEgAASAABAAAgEiAMs0QDAxFRAAAkAACDQnAiDT5tQ7dg0EgAAQAAIBIgAyDRBMTAUEgAAQAALNiQDItDn1jl0DASAABIBAgAiATAMEE1MBASAABIBAcyIAMm1OvWPXQAAIAAEgECACINMAwcRUQAAIAAEg0JwIgEybU+/YNRAAAkAACASIAMg0QDAxlSICop2guLilIC4gAASAQCMgADJtBC2GeQ8Oje51kbUcadevEWVnSJv9gOjyjP4zXEAACACBqCEAMo2axiIkr9sn2KTbuHGVtKm/kjZzMUK7hKj/f3tnFxvHVcXx/27jJDg20M2u7aaVCELyOrWrqEokiuNgByVvKG5cWrUSb6hQqRLvFSC1iI8nntvQIoH4CAlVHEe8QEPqxB8K0EgkcRKvBbQUNyTerduQutjeeJd7Z3d2Z3fvzNz1ztYzmf++WNnM3Dn3d2f3v+fcc86QAAmQgHgY1sDggTxBkICXBHQeDu54vfdvIH/pHPLZVS/N4lgkQAIk0DQCFNOmoQ3pwK3tiOw5JJ5b2t4QgPzHwku9+AYg/vJFAiRAAn4nQDH1+woFyD7pkeKxrzYspOaUpaDiwu/poQboHqCpJBBWAhTTsK685/OOILr3ILB9h7cji5Bv7q0zYkzuRngLlqORAAl4SYBi6iXNEI8V6dqJyO7BphAw9k9vvtOUscM6aOfQs/jWPmDy1Z/i7EIkrBg4bxLwjADF1DOUIR5IlL9E9z8OfMp5nzS/lsXqrXms3V5E7m4W0a2taPnsdmyKdyESuc8eoMjyzU2c0i6byXUM4vln+4Gpn+Hl8QXbcVWC0tC5+V48893DSGamcfSVcdyKFEQqV3y/p/hvq0EL6TQWU9MYvzaDWxqiZtqXQKYhIaSYhvjzyqk3hQDFtClYwzVoJP6gSDoSIV6H18rNf2Hp2l+RX63N0L1vWxva+r6ETfcnbEfIXzyDfOY9LbANCWIjQuwipslMBqnFxfIcYjH0JApzzufTSE2N4biD+MvjDBFMAul43PXHghMsiqnWrcSDSECbAMVUGxUPtCMQ7X0MeEh8w9u8VoWQ3rk0JbzPCDY/sBMt8R3CK92K3PL/kM3cwOp/3kX73iG0xLrsIc+nkLt6QWsRfCumc6fx/d9drZlDZ98gRob70SH4LEy+ZutN5/IdOPjcNzCweBqjOIwjsUoPWAtO8aCNEtNHhp7AgAwv/+B1XFF46vXMgceSgJ8IUEz9tBoBtSX65RHbEK+sFf1g4jQiIqzbtveAUjDz2WVEWootBu0YyFDv+ZNahIImpnJSZig46RC+Nee1OPYjHMPX8OJwbN2h3o0Q09KPgfgcRimmWvcyDwoOAYppcNbKt5ZGD30diKr3PFfe+yc+unIBW3cmsa1nz/rnkFtD7o1faZ0fRDE1BLXvCbz0eNLWOy0I4KIhRJfQZ+zPxlz2he2AUaR5ZxIAAAdlSURBVEy1biUeRALaBCim2qh4oJJAyxZEv/K0LZyl2YtYfieFT+8ZREviwYYg5s7+FsiuuI4RWDG12XOt8FwtoeJHnnzBNdQrQ8hD+/rF3mwhGSqfTmFy9HVcffibymzeXEcvDg72I9kdN8LO8rVQPOeKJUGqlAgl7HnxRBq7nxrGQPEcuf+bnpvGyRMiqao4hrR1JFmbNZxPjVWEvuX1nzki7S3vJVePVc3DvP5IMiHmN1WR/OV6s/AAEvCIAMXUI5ChHUZTTNt278OWBz5XwpT7wy+ahiy4YlrcE1WEQU2vdfbUD3F8ppglXPRkre9ZoUrv87kBITAyuWluDiJxGIlkN5Iidyk1ByGYlaUx1lBzem4RqesZYFc39kuRyqcqQrNlMZ3GZKwfA5hDKpVBGnEkxcAdQrytwtYp9kqHhD7GurshM5Hl+EYqVnqilHQl5/j8cOH/pb3XhL0PJ7rRo7q++cNDiLncPzaFmmLatI8VB3YhQDHlLdIwAacw7/L837E08xdsfegL2Nb3xQoxjYpymPZW8c1e1yuH20viW9bhdS+KqeGFdlfuNZbET5HYVBK7qjIdw6srirAUWWudqRzv4FPAVYtHKY83RblCyItZz3ZJU6Ynak2octoztXq6R6uur1rP0txFhrQoLjK8bavnXNctxYNJwAMCFFMPIIZ9CLcEpA/Pjxl1pe2PDmJzRyHUKz3Tz2zrxLeP/FwbXy6/hrHpn2Dm7TdDJaZOoqkSWQmn8L59Larb/1sBK8WsKKYJhVgb66sIWTuJqXU/uDrLt3QeytnLOglb2jcWDyQBDwhQTD2AGPYh3EpjVm6IJKTLoqxFRCe37NiJzWLvdNOl8brE9O7aKk5O/BipeffymOB6pjZNHxzCucrwr1lC45A165SA1NnXi95dPSLcGoMohRUh28L+ZYWXaYqpTbmPWgDVYWzz2P3FfV27z5M11KwS67B/Djn/jSVAMd1Y/vfE1bWaNghBXbp+UTStzxpzvj+S1RbT7N1lsa/2Et6++TctXtaQoaqu0xxE5Z01dK5b0wYb4THtUV1bW2gsiTw6QqPu/iSTfw4byUpGElFG7GuKjU2515rcJzZYLZnDbpxUXqidZ1p+X+6VWppa1Kx2BuMnCp2lnLx1rZuEB5GAxwQoph4DDeVwuu0ERc3pyq1/4+6dD9H67oyWmC6vfoRjb34P8+lZbbQ6YmL/xa72DivCnjaen911db/4zX1G1d5kIiMSfGx0JhYTSTvxckhX5RVWw6sWU6ugVffrdQzz2nqmtRzdxVS//lSXqfZNwwNJoEECFNMGAfL0AoF6G93r7JkuLd/Gb/70Hdz84B91YXYShhovsKaPrhmKtN9vtEvuaURMS0lBVaUdquSfahiq+lSnPVEVH8dkJkX9q1OCk7TPycseUISfVT8knBadYlrXR4IHfwIEKKafAORwXKK+R7C5iemdjzP45ZkX8P5/59eFr1QWIsRpdHS8ItPTGjpVlZWs99z1iKm0ZfeBYYwYJSxV5Scae5+GcKmSfcyMXRH+rc6OtZbMmF6ove2FHxdyP1O1ZyqzeWdPvSbKdcoPFLD7MaOVzStKbEZfrc3MlfWyHQvldaSYrutjwZOaSIBi2kS4YRu6noeDu4npn2dP4Y9vHW0IobVRgGw8YPSYtzSXXxBC87KiV6686HrOdRXTqkb3Mjwr6zHlSzZTGH2lsl+t276kFU61J2r9wZAXm56pRVlnGi/Wmc5hcipW6JFreQSbOWdpi1EzmhA1o6IuFKLmE/Kvas9UlqbIpvsyDJ0SofhEj3GOXclM+YeKaB4hriFrSo+PF/oVW0W+XOdasKH6KTkU04Y+Gjy5CQQopk2AGuohW9vFE2QOISL+OobpNEpjzl3+Nc5f1mshaHetTuGhjYjkGVO05HFSWFNTEzhr8aZU59d7rpuYVj+CrdApSAjbuevCc659VJxOiNe0WxXqLXi9+4VoFsTNmHtqSnQmGgcO1HZAMo4XnYxkJyFD4GWzh7ExHFvYVfNIu4oOSOdQSlwyfxhM2vA1RF5cQzaCMI6t6oBU3bHJXK/J0YkKRhTTUH/L+HLyFFNfLkuwjZIeqvGg8O07bCfi5pmaJ3ohqMGm6U/r6/Ga/TkDWkUC3hKgmHrLk6NZCES6Po9I96PKJ8roiqkcjoLqv9uKYuq/NaFFG0uAYrqx/O/9q4uyGWzvQqRD9OUVzyuNtLaJ1N9o3R2QKKj+ulUopv5aD1qz8QQophu/BuGzYLN4dunqsladqRUOBdU/twrF1D9rQUv8QYBi6o91CKUV9fbmZcjXP7cJxdQ/a0FL/EGAYuqPdaAVJEACJEACASZAMQ3w4tF0EiABEiABfxCgmPpjHWgFCZAACZBAgAlQTAO8eDSdBEiABEjAHwQopv5YB1pBAiRAAiQQYAIU0wAvHk0nARIgARLwBwGKqT/WgVaQAAmQAAkEmADFNMCLR9NJgARIgAT8QYBi6o91oBUkQAIkQAIBJkAxDfDi0XQSIAESIAF/EPg/X6LL0zoAnfIAAAAASUVORK5CYII=" alt=""></p>



<p>Of course, this will vary depending on the library we use, but for Retrofit, we will see among others this: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">import okhttp3.Call
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Converter
import retrofit2.CallAdapter
import retrofit2.converter.scalars.ScalarsConverterFactory
import com.squareup.moshi.Moshi
import retrofit2.converter.moshi.MoshiConverterFactory


class ApiClient(
    private var baseUrl: String = defaultBasePath,
    private val okHttpClientBuilder: OkHttpClient.Builder? = null,
    private val serializerBuilder: Moshi.Builder = Serializer.moshiBuilder,
    private val callFactory : Call.Factory? = null,
    private val callAdapterFactories: List&lt;CallAdapter.Factory> = listOf(
    ),
    private val converterFactories: List&lt;Converter.Factory> = listOf(
        ScalarsConverterFactory.create(),
        MoshiConverterFactory.create(serializerBuilder.build()),
    )
) {
 // code
}</pre>



<p>And the interface handling two endpoints: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">import org.openapitools.client.infrastructure.CollectionFormats.*
import retrofit2.http.*
import retrofit2.Call
import okhttp3.RequestBody
import com.squareup.moshi.Json

import org.openapitools.client.models.Post

interface PostsApi {
    /**
     * 
     * Returns a post by id
     * Responses:
     *  - 200: Successful response
     *  - 404: Post not found
     *
     * @param id The user id.
     * @return [Call]&lt;[Post]>
     */
    @GET("posts/{id}")
    fun getPost(@Path("id") id: kotlin.Long): Call&lt;Post>

    /**
     * 
     * Returns all posts
     * Responses:
     *  - 200: Successful response
     *
     * @return [Call]&lt;[kotlin.collections.List&lt;Post>]>
     */
    @GET("posts")
    fun getPosts(): Call&lt;kotlin.collections.List&lt;Post>>

}</pre>



<p>Can we start using it already? <strong>Not really.</strong></p>



<p>If we try to use these classes now in our code, they won&#8217;t be found. </p>



<p>In gradle, we <strong>must </strong>add the generated directory to the <code>sourceSets</code>: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">sourceSets {
    main {
        java {
            srcDir("${buildDir}/generate-resources/main/src")
        }
    }
}</pre>



<p>And with that done, we can finally make use of the code: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">import org.openapitools.client.apis.PostsApi

fun main() {
  val api = PostsApi(basePath = "https://jsonplaceholder.typicode.com")

  api.getPosts()
    .forEach(::println)
}</pre>



<h2 class="wp-block-heading" id="h-make-generation-a-part-of-compilation">Make Generation a Part of Compilation</h2>



<p>Before I wrap this article, I would like to show you one more thing. </p>



<p>Whenever we try to run the code without the generated files, it will fail. There&#8217;s no point of doing that manually each time either. </p>



<p>So, as a solution, we can alter the <code>compileKotlin</code> flow: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">tasks.compileKotlin{
    dependsOn("openApiGenerate")
}</pre>



<p>In simple words, the <strong>openApiGenerate</strong> task will be always invoked before the <strong>compileKotlin</strong>. </p>



<h2 class="wp-block-heading" id="h-summary">Summary</h2>



<p>And that&#8217;s all for this article on how to generate a Kotlin HTTP client using the OpenAPI generator. </p>



<p>I hope that this introduction will convince you to give it a try and will be a good help in your first steps. </p>



<p>As always, you can find the source code in <a href="https://github.com/codersee-blog/kotlin-openapi-generate" target="_blank" rel="noreferrer noopener">this GitHub repository</a>. </p>



<p>Have a great week and don&#8217;t forget to <strong>leave a comment </strong>🙂 </p>
<p>The post <a href="https://blog.codersee.com/generate-kotlin-client-from-openapi-specs/">Generate Kotlin Client From OpenAPI Specs</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.codersee.com/generate-kotlin-client-from-openapi-specs/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>How To Implement TriFunction in Kotlin?</title>
		<link>https://blog.codersee.com/how-to-implement-trifunction-in-kotlin/</link>
					<comments>https://blog.codersee.com/how-to-implement-trifunction-in-kotlin/#respond</comments>
		
		<dc:creator><![CDATA[Piotr]]></dc:creator>
		<pubDate>Wed, 19 Jul 2023 12:48:19 +0000</pubDate>
				<category><![CDATA[Kotlin]]></category>
		<category><![CDATA[Core Kotlin]]></category>
		<category><![CDATA[Functional Programming]]></category>
		<guid isPermaLink="false">https://codersee.com/?p=9007564</guid>

					<description><![CDATA[<p>In this article, I will show you how to implement your custom TriFunction in Kotlin and how SAM conversions, and lambdas can help us with it.</p>
<p>The post <a href="https://blog.codersee.com/how-to-implement-trifunction-in-kotlin/">How To Implement TriFunction in Kotlin?</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading" id="h-1-introduction">1. Introduction</h2>



<p>Hi! If you&#8217;ve ever been wondering how to implement a custom Trifunction in Kotlin, then you just came to the right place. </p>



<p>In this, short article we will cover the following:  </p>



<ul class="wp-block-list">
<li>what is a TriFunction? </li>



<li>what is a functional interface and how can we implement it in Kotlin? </li>



<li>how can we utilize SAM conversions to make our code more concise? </li>



<li>and finally- a slightly different approach, which may be better in some cases. </li>
</ul>



<h2 class="wp-block-heading" id="h-video-tutorial">Video Tutorial</h2>



<p>If you prefer <strong>video content</strong>, then check out my video:</p>



<div style="text-align: center; width: 90%; margin-left: 5%;">
<p></p></div>


<a href="https://blog.codersee.com/how-to-implement-trifunction-in-kotlin/"><img decoding="async" src="https://blog.codersee.com/wp-content/plugins/wp-youtube-lyte/lyteCache.php?origThumbUrl=%2F%2Fi.ytimg.com%2Fvi%2F23KLMMr58kw%2Fhqdefault.jpg" alt="YouTube Video"></a><br /><br /></p>



<p>If you find this content useful,<strong> please leave a subscription&nbsp;</strong> 😉</p>



<h2 class="wp-block-heading" id="h-2-what-is-a-functional-interface">2. What is a Functional Interface? </h2>



<p>Let&#8217;s start with defining what exactly is a <strong>functional interface</strong>. </p>



<p>Well, it is nothing else than an interface with <strong>exactly one abstract method</strong>. </p>



<p>In Kotlin, we can define it using the <strong><em>fun </em></strong>keyword: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fun interface MyFunctionalInterface {
  fun method()
  fun anotherMethod() // Compilation Error!

  // OK!
  fun nonAbstractMethod() {

  }
}</pre>



<p>As we can see, such interfaces can have multiple non-abstract members. </p>



<p>However, the code won&#8217;t compile whenever we try to implement more than one abstract method:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p></p>
<cite>Fun interfaces must have exactly one abstract method</cite></blockquote>



<h2 class="wp-block-heading" id="h-3-trifunction-and-kotlin-implementation">3. TriFunction and Kotlin Implementation</h2>



<p>The <strong>TriFunction </strong>interface is nothing else than a functional interface with <strong>three input parameters</strong> and <strong>one output.</strong></p>



<p>To better understand it, let&#8217;s take a look at the following code:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fun interface CustomTriFunction&lt;T, U, V, R> {
  fun someFun(t: T, u: U, v: V): R
}</pre>



<p>In this example, we declare a generic functional interface <em>CustomTriFunction</em> with exactly one abstract function- <em>someFun</em>. </p>



<p>This function has 3 parameters of type T, U, and V, and returns a value of type R. </p>



<h2 class="wp-block-heading" id="h-4-test-function">4. Test Function</h2>



<p>Following, let&#8217;s declare an example test function:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fun &lt;T, U, V, R> example(
  t: T,
  u: U,
  v: V,
  function: CustomTriFunction&lt;T, U, V, R>,
): R {
  val result = function.someFun(t, u, v)
  // some logic here
  return result
}</pre>



<p>As we can see, the <em>example</em> is a generic function, which we will invoke with 3 values, and as the last one, we will pass the implementation of <em>CustomTriFunction</em>.</p>



<p>And although this example is a bit trivial, we may want to use this strategy in real-life scenarios to keep our code <strong>open for extension and closed for modification</strong>. </p>



<h2 class="wp-block-heading" id="h-5-implementation-no-1-class">5. Implementation No 1- Class</h2>



<p>With all of that done, we can finally use the interface and implement the code responsible for invoking the <em>example</em>.</p>



<p>Let&#8217;s start with the most basic idea- adding a new class: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">class CustomImplementation : CustomTriFunction&lt;String, Long, Int, Double> {
  override fun someFun(t: String, u: Long, v: Int): Double {
    // some logic
    return 10.0
  }
}</pre>



<p>The above code shouldn&#8217;t be surprising even if we are pretty new to Kotlin. </p>



<p>We implement the <em>CustomTriFunction</em> just like every generic interface and provide the body for <em>someFun</em>.</p>



<p>Nextly, the only thing we need to do is to create a new instance of our class and pass it as the last argument: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val customImplementation = CustomImplementation()
val result = exampleOne("", 0L, 0, customImplementation)</pre>



<p> Of course, depending on our case the <em>CustomImplementation</em> could be a Kotlin object. </p>



<h2 class="wp-block-heading" id="h-6-idea-2-anonymous-object">6. Idea 2- Anonymous Object</h2>



<p>But sometimes, we don&#8217;t want to explicitly define a new class. Maybe we want to pass a very specific logic, which definitely won&#8217;t be used anywhere else in the code. </p>



<p>For such a one-time operation, we can use the anonymous object:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val anonymousObject = object : CustomTriFunction&lt;String, Long, Int, Double> {
  override fun someFun(t: String, u: Long, v: Int): Double {
    return 10.0
  }
}
val result = exampleOne("", 0L, 0, anonymousObject)</pre>



<p>As we can see, the instance of an anonymous object (also known as an anonymous class) looks almost the same, as in the previous example. With one, important difference- it does not have a name. </p>



<p>And as I mentioned previously- this approach may be really helpful for one-time use.</p>



<p></p>



<h2 class="wp-block-heading" id="h-7-implementation-3-better-sam-conversion">7. Implementation 3 (Better)- SAM Conversion</h2>



<p>In Kotlin, <strong>functional interfaces</strong> are also known as <strong>Single Abstract Method (SAM) interfaces</strong>. </p>



<p>And instead of defining anonymous objects, we can make use of <strong>SAM conversions</strong>, which allow us to use lambda expressions instead: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val samConversionOne = CustomTriFunction { t: String, u: Long, v: Int -> 10.0 }
val resultOne = exampleOne("", 0L, 0, samConversionOne)

// or alternatively:
val samConversionTwo = CustomTriFunction&lt;String, Long, Int, Double> { t, u, v -> 10.0 }
val resultTwo = exampleOne("", 0L, 0, samConversionTwo)

// or even:
val resultThree = exampleOne("", 0L, 0) { t, u, v -> 10.0 }

// Note: in Kotlin, if the last argument is a function,
// we can put it outside of round brackets- (). </pre>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p></p>
<cite>With a SAM conversion, Kotlin can convert any lambda expression whose signature matches the signature of the interface&#8217;s single method into the code, which dynamically instantiates the interface implementation.<br><br>Source: <a href="https://kotlinlang.org/docs/fun-interfaces.html#sam-conversions" target="_blank" rel="noreferrer noopener">https://kotlinlang.org/docs/fun-interfaces.html#sam-conversions</a> </cite></blockquote>



<p>And to put it simply, with this approach we can implement our <em>TriFunction</em> in a much more concise manner (which is often the case with Kotlin ;). </p>



<h2 class="wp-block-heading" id="h-8-approach-4-high-order-function-without-interface">8. Approach 4- High-Order Function Without Interface</h2>



<p>As the last example, let&#8217;s take a look at the high-order function. </p>



<p>In Kotlin, a <strong>high-order function</strong> is a function, which <strong>takes another function as an argument</strong> or <strong>returns a function</strong>. </p>



<p>So at the end of the day, instead of explicitly creating a custom TriFunction interface, we can <strong>define a parameter</strong> of <strong>function type</strong>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fun &lt;T, U, V, R> example(
  t: T,
  u: U,
  v: V,
  function: (T, U, V) -> R,
): R {
  val result = function.invoke(t, u, v) // or simply function(t, u, v)
  // some logic here
  return result
}</pre>



<p>As we can see, the <em>function</em> parameter simply informs the compiler that we expect a function with three input arguments (T, U, V) and return type R. </p>



<p>And then, we can invoke it by passing a lambda to it: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val lambda = { t: String, u: Long, v: Int -> 10.0 }
val result = example("", 0L, 0, lambda)

// or even: 
val result = exampleTwo("", 0L, 0) { t, u, v -> 10.0 }</pre>



<p>And this approach might be a great choice whenever we would like to have a TriFunction without explicitly defining a new interface.</p>



<h2 class="wp-block-heading" id="h-9-summary">9. Summary</h2>



<p>And that&#8217;s all for this article about how to implement the Kotlin TriFunction interface in Kotlin. </p>



<p>I hope you enjoy my content and if you&#8217;d like to learn more about Kotlin and support my work, then I highly encourage you to check my <a href="https://blog.codersee.com/kotlin-handbook-learn-through-practice-course/">Kotlin Handbook Course</a>. </p>
<p>The post <a href="https://blog.codersee.com/how-to-implement-trifunction-in-kotlin/">How To Implement TriFunction in Kotlin?</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.codersee.com/how-to-implement-trifunction-in-kotlin/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Kotlin Type-Safe Builders Explained. Implement Your Own DSL.</title>
		<link>https://blog.codersee.com/kotlin-type-safe-builders-make-your-custom-dsl/</link>
					<comments>https://blog.codersee.com/kotlin-type-safe-builders-make-your-custom-dsl/#comments</comments>
		
		<dc:creator><![CDATA[Piotr]]></dc:creator>
		<pubDate>Wed, 17 May 2023 08:18:54 +0000</pubDate>
				<category><![CDATA[Kotlin]]></category>
		<category><![CDATA[Core Kotlin]]></category>
		<category><![CDATA[Kotlin DSL]]></category>
		<guid isPermaLink="false">https://codersee.com/?p=9007512</guid>

					<description><![CDATA[<p>In this publication, we will learn how to implement statically-typed, type-safe Kotlin builders which we can use to implement our own DSLs.</p>
<p>The post <a href="https://blog.codersee.com/kotlin-type-safe-builders-make-your-custom-dsl/">Kotlin Type-Safe Builders Explained. Implement Your Own DSL.</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading" id="h-1-introduction">1. Introduction</h2>



<p>Hi! 🙂 In this publication, we will learn how to implement <strong>statically-typed</strong>, <strong>type-safe Kotlin builders</strong> which we can use to implement our own DSLs. </p>



<p>Firstly, we will discuss what exactly DSLs are, their benefits, and why Kotlin is a good choice for creating them. Then, we will learn more about function literals with a receiver. And finally, we will put together all this knowledge and implement our own DSL. <br></p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><strong>Note:</strong> This article has been created based on my course <a href="http://codersee.com/kotlin-handbook-learn-through-practice-course/" target="_blank" rel="noreferrer noopener"><em>Kotlin Handbook. Learn Through Practice</em></a>. If you are looking for high-quality, step-by-step Kotlin learning path, then you should definitely check it out.</p>
</blockquote>



<h2 class="wp-block-heading" id="h-video-tutorial">Video Tutorial</h2>



<p>If you prefer <strong>video content</strong>, then check out my video:</p>



<div style="text-align: center; width: 90%; margin-left: 5%;">
<a href="https://blog.codersee.com/kotlin-type-safe-builders-make-your-custom-dsl/"><img decoding="async" src="https://blog.codersee.com/wp-content/plugins/wp-youtube-lyte/lyteCache.php?origThumbUrl=%2F%2Fi.ytimg.com%2Fvi%2Fg4ioA_LcBWE%2Fhqdefault.jpg" alt="YouTube Video"></a><br /><br /></p></div>





<p>If you find this content useful,<strong> please leave a subscription&nbsp;</strong> 😉</p>



<h2 class="wp-block-heading" id="h-2-what-is-a-dsl">2. What is a DSL?</h2>



<p>A DSL is an acronym for Domain-Specific Language.</p>



<p>It’s nothing else than a specialized language designed to solve problems or tasks within a specific domain.</p>



<p>Unlike general-purpose languages (like Kotlin itself), which are designed for a wide range of applications, DSLs focus on easy-to-understand syntax tailored to a particular problem domain.</p>



<p>Great examples can be:</p>



<ul class="wp-block-list">
<li>HTML for creating web pages, </li>



<li>Gradle for building automation, </li>



<li>or SQL for querying databases.</li>
</ul>



<h2 class="wp-block-heading" id="h-3-the-purpose-and-benefits-of-dsls">3. The Purpose and Benefits of DSLs</h2>



<p>The main purpose of DSLs is to help programmers to deal with complex hierarchical data structures in an easy way.&nbsp;</p>



<p>So, a well-designed domain-specific language provides (among others) the following benefits:&nbsp;</p>



<ul class="wp-block-list">
<li><strong>expressiveness</strong>&#8211; helps us to express complex ideas and logic using a more concise and natural syntax,</li>



<li><strong>readability</strong>&#8211; the code we produce is simply easier to read and understand,&nbsp;</li>



<li><strong>maintainability</strong>&#8211; a modular, and organized code structure makes it easier to maintain and extend our programs.&nbsp;</li>
</ul>



<h2 class="wp-block-heading" id="h-4-is-kotlin-a-good-choice-for-dsls">4. Is Kotlin a Good Choice For DSLs?</h2>



<p>Short answer- <strong>yes</strong>.&nbsp;</p>



<p>Kotlin is designed to be a concise, readable, and expressive programming language.&nbsp;When we combine together properly named functions and function literals with receiver, we can implement truly type-safe Kotlin builders.  </p>



<p>Additionally, lambda expressions, scoping literals, extension, or infix functions help us to organize everything in an even cleaner way. </p>



<p>If you are looking for real-life usage examples, then we can find type-safe builders for example, when configuring routes in <a href="https://blog.codersee.com/category/ktor/">Ktor</a>, or in Gradle&#8217;s Kotlin DSL. </p>



<h2 class="wp-block-heading" id="h-5-function-literals-with-receiver">5. Function Literals with Receiver</h2>



<p>With all of that being said, let&#8217;s start the practice part by explaining the concept of <strong>function literals with receiver</strong>. </p>



<p>In simple words, it is nothing else than a combination of <strong>lambda expression</strong>: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val hello: (String) -> String = { name -> "Hello, $name" }

fun main() {
  val greeting = hello("Pjoter")
  
  println(greeting)  // Hello, Pjoter
}</pre>



<p>And <strong>extension function</strong>: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fun String.hello() : String = "Hello, $this"

fun main() {
  val greeting = "Pjoter".hello()
  
  println(greeting)  // Hello, Pjoter
}</pre>



<p>Which combined together form:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val hello: String.() -> String = { "Hello, $this" }

fun main() {
  val greeting = "Pjoter".hello()
  
  println(greeting)  // Hello, Pjoter
}</pre>



<p>In our example, the String object, for which we invoke the function is a&nbsp;<strong>receiver&nbsp;</strong>and it implicitly becomes&nbsp;<strong><em>this&nbsp;</em></strong>inside the function. This way, we can access all its members, like public fields, inside our function (even without <em>this</em> keyword). </p>



<p>Great, but how does this relate to creating DSLs in Kotlin? </p>



<p>Well, we can pass function literals with receiver as arguments to <strong>high-order functions</strong> (functions that take other functions as parameters). </p>



<p>I know, a mumbo jumbo, but everything will become clear by the end of this tutorial 😉</p>



<h2 class="wp-block-heading" id="h-6-implement-custom-kotlin-dsl">6. Implement Custom Kotlin DSL </h2>



<h3 class="wp-block-heading" id="h-6-1-add-high-order-function">6.1 Add High-Order Function</h3>



<p>As the first step, let&#8217;s take a look at the example class: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">enum class BoardColor {
  BLACK, WHITE, GREEN, BLUE
}

class Board {
  var title: String = ""
  var color: BoardColor = BoardColor.BLUE
}

fun main() {
  val board = Board()
  board.title = "Important Tasks"
  board.color = BoardColor.GREEN
}</pre>



<p>Nothing spectacular, right? Just a simple class with mutable properties.</p>



<p>So as the next step, let&#8217;s add a higher-order function, which expects the function literal with a receiver as an argument: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">enum class BoardColor {
  BLACK, WHITE, GREEN, BLUE
}

class Board {
  var title: String = ""
  var color: BoardColor = BoardColor.BLUE
}

fun board(init: Board.() -> Unit): Board {
  val board = Board()
  board.init()
  return board
}

fun main() {
  val board = board {
    title = "Important Tasks"
    color = BoardColor.GREEN
  }
}</pre>



<p>The <em>board</em> function is pretty straightforward- firstly, we create a new <em>Board </em>instance, and then we invoke the <em>init</em> function on it. After that, we return the updated object instance. </p>



<p>When we look at the <em>main </em>function, we can see that the only thing we do is the <em>board</em> function invocation.</p>



<p>But there is no parenthesis- &#8220;()&#8221;- right? </p>



<p>Well, technically we could use them: <code>board ( {/*some code*/ } )</code>. But in Kotlin, when the last parameter of a function is a function, then a lambda expression passed as the corresponding argument can be placed outside the parentheses (<a href="https://kotlinlang.org/docs/lambdas.html#passing-trailing-lambdas" target="_blank" rel="noreferrer noopener">docs</a>). In our case- the function has only one parameter, so we don&#8217;t need parenthesis, at all.</p>



<h3 class="wp-block-heading" id="h-6-2-kotlin-type-safe-builder">6.2 Kotlin Type-Safe Builder</h3>



<p>And although at this point our logic looks like overkill, life isn’t always that easy and we may need to add more hierarchy to our code. </p>



<p>Let&#8217;s consider the following code snippet: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">enum class BoardColor {
  BLACK, WHITE, GREEN, BLUE
}

class Task {
  var title: String = ""
  var description: String = ""
}

class Board {
  var title: String = ""
  var color: BoardColor = BoardColor.BLUE
  var tasks: MutableList&lt;Task> = mutableListOf()
}

fun main() {
  val taskOne = Task() 
  taskOne.title = "Task 1"
  taskOne.description = "Task 1 description"  
  
  val taskTwo = Task() 
  taskTwo.title = "Task 2"
  taskTwo.description = "Task 2 description"   
  
  val tasks = mutableListOf(taskOne, taskTwo)  
    
  val board = Board() 
  board.title = "Important Tasks"
  board.color = BoardColor.GREEN
  board.tasks = tasks	  
}</pre>



<p>In this case, every <em>Board </em>object can contain multiple <em>Tasks </em>instances. </p>



<p>When we look at the <em>main</em> function, it&#8217;s pretty hard to see the hierarchy of objects at first glance.  </p>



<p>And now, let&#8217;s analyze the Kotlin type-safe builder approach: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">enum class BoardColor {
  BLACK, WHITE, GREEN, BLUE
}

class Task {
  var title: String = ""
  var description: String = ""
}

class Board {
  var title: String = ""
  var color: BoardColor = BoardColor.BLUE
  var tasks: MutableList&lt;Task> = mutableListOf()
  
  fun task(init: Task.() -> Unit) {
    val task = Task()
    task.init()
    tasks.add(task)
  }
}

fun board(init: Board.() -> Unit): Board {
  val board = Board()
  board.init()
  return board
}

fun main() {
   val board = board {
     title = "Important Tasks"
     color = BoardColor.GREEN
    
     task {
       title = "Task 1"
       description = "Task 1 description"  
     }
    
     task {
       title = "Task 2"
       description = "Task 2 description" 
     }
  }  
}</pre>



<p>We brought back the <em>board</em> function and implemented a new <em>task</em> method inside the <em>Board</em>. </p>



<p>When we implement our lambda inside the <em>main</em> function, we can access the <em>task</em> function, just like we access the <em>title</em>, or <em>color</em> property of the <em>Board </em>object. </p>



<p>To better visualize, let&#8217;s use the explicit <em>this</em> and parenthesis: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val board = board {
  this.title = "Important Tasks"
  this.color = BoardColor.GREEN
    
  this.task( {
    this.title = "Task 1"
    this.description = "Task 1 description"  
  } )
    
  this.task( {
    this.title = "Task 2"
    this.description = "Task 2 description" 
  } )
}  </pre>



<p>To rephrase- the object, for which we invoke the function is a&nbsp;receiver&nbsp;and it implicitly becomes&nbsp;<strong><em>this&nbsp;</em>inside the function</strong>. </p>



<p>So, our <em>board</em> function first creates a new object and then invokes passed lambda on it- which sets the <em>title</em>, <em>color </em>and invokes the <em>task </em>method twice.</p>



<p>On the other hand, the <em>task</em> function also creates a new, &#8220;plain&#8221; object and also invokes passed lambda on it- this time, setting the <em>title </em>and <em>description</em> values for it. </p>



<p>And basically, we&#8217;ve just created our first, simple Kotlin type-safe builder 🙂 </p>



<h2 class="wp-block-heading" id="h-7-summary">7. Summary</h2>



<p>In this article, we&#8217;ve learned not only how to create our custom Kotlin DSL, but also the key features which make this possible. </p>



<p>Of course, this is just an introduction, and if you are interested in learning more, for example about scope control, then let me know in the comments section 🙂</p>
<p>The post <a href="https://blog.codersee.com/kotlin-type-safe-builders-make-your-custom-dsl/">Kotlin Type-Safe Builders Explained. Implement Your Own DSL.</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.codersee.com/kotlin-type-safe-builders-make-your-custom-dsl/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>How Can Kotlin Operator Overloading Help You?</title>
		<link>https://blog.codersee.com/how-can-kotlin-operator-overloading-help-you/</link>
					<comments>https://blog.codersee.com/how-can-kotlin-operator-overloading-help-you/#comments</comments>
		
		<dc:creator><![CDATA[Piotr]]></dc:creator>
		<pubDate>Tue, 14 Mar 2023 07:00:42 +0000</pubDate>
				<category><![CDATA[Kotlin]]></category>
		<category><![CDATA[Core Kotlin]]></category>
		<guid isPermaLink="false">https://codersee.com/?p=6004415</guid>

					<description><![CDATA[<p>Check out this article to learn how Kotlin operator overloading- a custom behavior for operators, like +,-,*, and unary plus- can help you.</p>
<p>The post <a href="https://blog.codersee.com/how-can-kotlin-operator-overloading-help-you/">How Can Kotlin Operator Overloading Help You?</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2>1. Introduction</h2>
<p>In this article, I will show you <strong>what exactly Kotlin operator overloading is</strong>, how we can use it, and what&#8217;s even more important- what value can it bring to your project?</p>
<h2>Video Tutorial</h2>
<p>If you prefer <strong>video content</strong>, then check out my video:</p>
<p>&nbsp;</p>
<div style="text-align: center; width: 90%; margin-left: 5%;">
<p><a href="https://blog.codersee.com/how-can-kotlin-operator-overloading-help-you/"><img decoding="async" src="https://blog.codersee.com/wp-content/plugins/wp-youtube-lyte/lyteCache.php?origThumbUrl=%2F%2Fi.ytimg.com%2Fvi%2F3Xcv4QpWm2Y%2Fhqdefault.jpg" alt="YouTube Video"></a></p>
</div>
<p>&nbsp;</p>
<p>If you find this content useful,<strong> please leave a subscription </strong> 😉</p>
<h2>2. What is Kotlin Operator Overloading?</h2>
<p>Well, <strong>operator overloading</strong> is nothing else, than a possibility to provide a custom implementation for a predefined set of operators on Kotlin types.</p>
<p>Let&#8217;s take a look at the following example:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">data class Example(
    val value: Int
) {
  operator fun plus(otherValue: Int): Example =
    Example(this.value + otherValue)
}

fun main(args: Array&lt;String&gt;) {
  val example = Example(10)
  val addedExample = example + 11
  addedExample // Example(value=21)
}
</pre>
<p>When working with Kotlin, we can implement our own <code class="EnlighterJSRAW" data-enlighter-language="raw">plus</code> operator function, and later simply make use of the <strong>+</strong> sign in our code. (And of course, this is only one of the many operators we can work with).</p>
<p>What&#8217;s worth mentioning here is that we can implement our operator using both <strong>member functions</strong> and <strong>extension functions</strong>:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">operator fun Example.plus(otherValue: Int): Example =
  Example(this.value + otherValue)
</pre>
<p>And I am well aware that this feature will never be a deal-breaker when selecting the right programming language for your project. Nevertheless, I still think that when properly used, <strong>it can help us maintain code readability and achieve a more expressive and natural codebase</strong>.</p>
<h2>3. Invoke Operator</h2>
<p>With all of that being said, let&#8217;s start the practice part and learn Kotlin operator overloading.</p>
<p>And as the first one, let&#8217;s take a look at the invoke operator, which simply<strong> translates parenthesis into the call to the <code class="EnlighterJSRAW" data-enlighter-language="raw">invoke</code> function</strong>:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">class SomeHandler {
    operator fun invoke(): String = "Some String"
    operator fun invoke(value: String): String = "Some String with String value: $value"
    operator fun invoke(value: Int): String = "Some String with Int value: $value"
}

fun main(args: Array&lt;String&gt;) { 
  val handler = SomeHandler()

  handler()        // Some String
  handler("one")   // Some String with String value: one
  handler(1)       // Some String with Int value: 1
}
</pre>
<p>As we can see, with this approach we don&#8217;t have to specify the function name anymore. When dealing with classes, which truly have a single responsibility and a descriptive name, this becomes an interesting syntactic sugar.</p>
<p>Of course, when overriding <code class="EnlighterJSRAW" data-enlighter-language="raw">invoke()</code> we can implement functions taking multiple arguments, as well.</p>
<h2>4. Unary Operators</h2>
<p>Nextly, let&#8217;s take a look at unary operators:</p>
<ul>
<li><code class="EnlighterJSRAW" data-enlighter-language="raw">+someVariable</code> -&gt; <code class="EnlighterJSRAW" data-enlighter-language="raw">someVariable.unaryPlus()</code></li>
<li><code class="EnlighterJSRAW" data-enlighter-language="raw">-someVariable</code> -&gt; <code class="EnlighterJSRAW" data-enlighter-language="raw">someVariable.unaryMinus()</code></li>
<li><code class="EnlighterJSRAW" data-enlighter-language="raw">!someVariable</code> -&gt; <code class="EnlighterJSRAW" data-enlighter-language="raw">someVariable.not()</code></li>
<li><code class="EnlighterJSRAW" data-enlighter-language="raw">++someVariable / someVariable++</code> -&gt; <code class="EnlighterJSRAW" data-enlighter-language="raw">someVariable.inc()</code></li>
<li><code class="EnlighterJSRAW" data-enlighter-language="raw">-- someVariable / someVariable--</code> -&gt; <code class="EnlighterJSRAW" data-enlighter-language="raw">someVariable.dec()</code></li>
</ul>
<blockquote><p>Note: when incrementing/decrementing we have to remember about the way postfix and prefix approach differ. In a moment, I will show you an example.</p></blockquote>
<p>So, let&#8217;s see an example class with the first 3 operators:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">data class SomeText(
    val value: String
) {
    operator fun unaryPlus(): SomeText =
        SomeText(this.value.uppercase())

    operator fun unaryMinus(): SomeText =
        SomeText(this.value.lowercase())

    operator fun not(): SomeText =
        SomeText(this.value.reversed())
}

fun main(args: Array&lt;String&gt;) { 
  val someText = SomeText("This is My text")

  +someText // SomeText(value=THIS IS MY TEXT)
  -someText // SomeText(value=this is my text)
  !someText // SomeText(value=txet yM si sihT)
}
</pre>
<p>This time, for each unary operator, we simply return a new instance with an appropriately modified <code class="EnlighterJSRAW" data-enlighter-language="raw">value</code>.</p>
<p>When it comes to the <code class="EnlighterJSRAW" data-enlighter-language="raw">inc()</code> and <code class="EnlighterJSRAW" data-enlighter-language="raw">dec()</code>, the class implementation looks, as follows:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">data class CustomPoint(
    val x: Int,
    val y: Int
) {
  operator fun inc(): CustomPoint =
    CustomPoint(this.x + 1, this.y + 1)

  operator fun dec(): CustomPoint =
    CustomPoint(this.x - 1, this.y - 1)
}
</pre>
<p>And although this looks just like a previous example, this time we <strong>have to return instances o CustomPoint in both cases</strong>.</p>
<p>Additionally, there&#8217;s a bit of a &#8220;magic&#8221; happening depending on whether we decide to use a suffix or prefix form:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">fun main(args: Array&lt;String&gt;) { 
  var point = CustomPoint(0, 0)

  ++point    // CustomPoint(x=1, y=1)
  point++    // CustomPoint(x=1, y=1)
  point      // CustomPoint(x=2, y=2)
  --point    // CustomPoint(x=1, y=1)
  point--    // CustomPoint(x=1, y=1)
  point      // CustomPoint(x=0, y=0)
}
</pre>
<p>So basically:</p>
<ul>
<li>when using the <strong>prefix</strong> form, the <code class="EnlighterJSRAW" data-enlighter-language="raw">inc()/dec()</code> function is invoked first and then the result is simply returned,</li>
<li>however, when using the <strong>suffix</strong> form, then the result is firstly stored in temporary storage, returned as a result of the expression, and assigned to the initial variable.</li>
</ul>
<h2>5. Binary Operators</h2>
<p>Following, let&#8217;s learn operator overloading with Kotlin binary operators.</p>
<p>As an example, let&#8217;s learn how do the comparison work:</p>
<ul>
<li><code class="EnlighterJSRAW" data-enlighter-language="raw">x &lt; y</code> -&gt; <code class="EnlighterJSRAW" data-enlighter-language="raw">x.compareTo(y) &lt; 0</code></li>
<li><code class="EnlighterJSRAW" data-enlighter-language="raw">x &gt; y</code> -&gt; <code class="EnlighterJSRAW" data-enlighter-language="raw">x.compareTo(y) &gt; 0</code></li>
<li><code class="EnlighterJSRAW" data-enlighter-language="raw">x &lt;= y</code> -&gt; <code class="EnlighterJSRAW" data-enlighter-language="raw">x.compareTo(y) &lt;= 0</code></li>
<li><code class="EnlighterJSRAW" data-enlighter-language="raw">x &gt;= y</code> -&gt; <code class="EnlighterJSRAW" data-enlighter-language="raw">x.compareTo(y) &gt;= 0</code></li>
</ul>
<p>So, our previously implemented class- <em>SomeText</em>&#8211; can be a great candidate for that:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">data class SomeText(
    val value: String
) {
  operator fun compareTo(other: SomeText): Int {
    val thisLength = this.value.length
    val otherLength = other.value.length

    return thisLength - otherLength
  }
}

fun main(args: Array&lt;String&gt;) { 
  val textA = SomeText("123")
  val textB = SomeText("456")

  textA &gt; textB  // false
  textA &lt; textB // false 
  textA &gt;= textB // true
  textA &lt;= textB // true
}</pre>
<p>As we can see, with such a simple approach the code become much more readable and intuitive.</p>
<p>Of course, there are much more binary (and not only) Kotlin operators, which we can use for operator overloading and I will add a link to the documentation at the end of this article.</p>
<h2>6. Infix Notation</h2>
<p>And although the infix notation is technically not a part of operator overloading, I feel obliged to mention it.</p>
<p>Basically, the infix notation is nothing else than the possibility to implement custom infix operations. And even though they do not bring as much, as the operators overloading, I still believe they are a pretty good syntactic sugar.</p>
<p>Let&#8217;s take a look at the following code:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">data class SomeText(
    val value: String
) {
  infix fun codersee(other: SomeText): SomeText =
    SomeText("Codersee ${this.value}, ${other.value}")

  infix fun codersee(other: String): String =
    "Codersee ${this.value}, $other"
}

fun main(args: Array&lt;String&gt;) { 
  val anotherText = SomeText("another")
  
  anotherText codersee SomeText("value")   // SomeText(value=Codersee another, value)
  anotherText codersee "value"             // "Codersee another, value"
}</pre>
<p>This time, we can see that instead of invoking the <code class="EnlighterJSRAW" data-enlighter-language="raw">anotherText.codersee()</code>, we can simply use an infix notation.</p>
<p>Nevertheless, we have to keep in mind some limitations:</p>
<ul>
<li>they must have <strong>only one parameter</strong>,</li>
<li>and the parameter itself <strong>cannot accept a variable number of arguments</strong> and or <strong>have a default value.</strong></li>
</ul>
<h2>7. Kotlin Operator Overloading Summary</h2>
<p>And that&#8217;s all for this article about<strong> Kotlin operator overloading</strong> and <strong>what this feature brings to the table</strong>. As promised, <a href="https://kotlinlang.org/docs/operator-overloading.html" target="_blank" rel="noopener">right here</a> you can find the documentation, where you can learn more about this functionality.</p>
<p>Lastly, if you enjoyed this article, then you might want to check out my other <a href="https://blog.codersee.com/category/kotlin/">Kotlin articles.</a></p>
<p>The post <a href="https://blog.codersee.com/how-can-kotlin-operator-overloading-help-you/">How Can Kotlin Operator Overloading Help You?</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.codersee.com/how-can-kotlin-operator-overloading-help-you/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Micronaut With Kotlin and MongoDB Video Tutorial</title>
		<link>https://blog.codersee.com/micronaut-with-kotlin-and-mongodb-video-tutorial/</link>
					<comments>https://blog.codersee.com/micronaut-with-kotlin-and-mongodb-video-tutorial/#comments</comments>
		
		<dc:creator><![CDATA[Piotr]]></dc:creator>
		<pubDate>Fri, 25 Nov 2022 07:47:33 +0000</pubDate>
				<category><![CDATA[Micronaut]]></category>
		<category><![CDATA[Core Kotlin]]></category>
		<category><![CDATA[MongoDB]]></category>
		<guid isPermaLink="false">https://codersee.com/?p=5504010</guid>

					<description><![CDATA[<p>Finally, I've released a new Micronaut with Kotlin and MongoDB video tutorial for free, so it's time to learn something new. </p>
<p>The post <a href="https://blog.codersee.com/micronaut-with-kotlin-and-mongodb-video-tutorial/">Micronaut With Kotlin and MongoDB Video Tutorial</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Hello friends 😀 This blog post is a bit different than the other how-to articles I publish because I simply wanted to let you know that I published a new<strong> Micronaut with Kotlin and MongoDB video tutorial.</strong></p>
<p>If you would like to learn:</p>
<ul>
<li><strong>what exactly the Micronaut Framework </strong>is and what problems can you solve with it?</li>
<li><strong>how to create REST API</strong> using Micronaut and Kotlin programming language?</li>
<li>how to set up a <strong>MongoDB instance with Docker</strong> and view the data with <strong>MongoDB Compass</strong>?</li>
<li>and furthermore, how to set up all of the above step-by-step?</li>
</ul>
<p>Then the Micronaut with Kotlin and MongoDB video tutorial will help you with all of the above. <strong>12 free videos</strong> with around <strong>56 minutes</strong> of the condensed knowledge are a great way to start your journey with the Micronaut framework.</p>
<p>&nbsp;</p>
<p><a href="https://codersee.com/newsletter/"><img fetchpriority="high" decoding="async" class="aligncenter wp-image-3002956 size-large" src="http://blog.codersee.com/wp-content/uploads/2022/05/join_newsletter-1024x576.png" alt="Image shows two ebooks people can get for free after joining newsletter" width="800" height="419" /></a></p>
<p>&nbsp;</p>
<p>As always, you can find it entirely for free on this blog, by simply clicking the <em>Video Tutorials</em> tab in the header, or by navigating to it with <a href="https://codersee.com/courses/rest-api-with-micronaut-kotlin-and-mongodb-course/">this, direct link</a>.</p>
<p>Alternatively, you can find it on the YouTube platform as a playlist <a href="https://youtube.com/playlist?list=PLvN8k8yxjoetVCPwyc9KyS4zZMjD9X3do" target="_blank" rel="noopener">right here</a>, but right there I cannot guarantee that you won&#8217;t see the ads, or that everything will be displayed in the correct order.</p>
<p>&nbsp;</p>
<p><img decoding="async" class="aligncenter wp-image-5504011" src="http://blog.codersee.com/wp-content/uploads/2022/11/drake_meme_prefer_codersee_over_playlist-1024x1024.png" alt="The image is a Drake meme joke showing that it's better to use the Codersee internal courses page for Micronaut with Kotlin and MongoDB video tutorial." width="600" height="600" srcset="https://blog.codersee.com/wp-content/uploads/2022/11/drake_meme_prefer_codersee_over_playlist-1024x1024.png 1024w, https://blog.codersee.com/wp-content/uploads/2022/11/drake_meme_prefer_codersee_over_playlist-300x300.png 300w, https://blog.codersee.com/wp-content/uploads/2022/11/drake_meme_prefer_codersee_over_playlist-150x150.png 150w, https://blog.codersee.com/wp-content/uploads/2022/11/drake_meme_prefer_codersee_over_playlist-768x768.png 768w, https://blog.codersee.com/wp-content/uploads/2022/11/drake_meme_prefer_codersee_over_playlist.png 1200w" sizes="(max-width: 600px) 100vw, 600px" /></p>
<p>&nbsp;</p>
<h2>One more thing&#8230;</h2>
<p>Finally, I just wanted to thank you for being a part of the Codersee community and ask you about one thing: <strong>I would be forever thankful if you share your feedback with me. </strong>Of course, regardless of whether you enjoy the course or you think it&#8217;s just a piece of s**t. I would love to hear your thoughts and how could I improve my content to better suit your needs. You can do it wherever you want: by using the contact form, using a comments section below, or even on YouTube.</p>
<p>Thank you for your time and have a great week!</p>
<p>The post <a href="https://blog.codersee.com/micronaut-with-kotlin-and-mongodb-video-tutorial/">Micronaut With Kotlin and MongoDB Video Tutorial</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.codersee.com/micronaut-with-kotlin-and-mongodb-video-tutorial/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Kotlin switch&#8230; ekhm.. when expression</title>
		<link>https://blog.codersee.com/kotlin-switch-when-expression/</link>
					<comments>https://blog.codersee.com/kotlin-switch-when-expression/#respond</comments>
		
		<dc:creator><![CDATA[Piotr]]></dc:creator>
		<pubDate>Tue, 11 Oct 2022 05:00:46 +0000</pubDate>
				<category><![CDATA[Kotlin]]></category>
		<category><![CDATA[Core Kotlin]]></category>
		<guid isPermaLink="false">https://codersee.com/?p=5503779</guid>

					<description><![CDATA[<p>In this article, I will show you how the Kotlin when expression (aka Kotlin switch) works and how to use it in your Kotlin projects.</p>
<p>The post <a href="https://blog.codersee.com/kotlin-switch-when-expression/">Kotlin switch&#8230; ekhm.. when expression</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2 class="article-heading-introduction">1. Introduction</h2>
<p>Hello friend :D. In this article, I would like to show you how <strong>Kotlin when expression</strong> works.</p>
<p>After reading this post, you will precisely:</p>
<ul>
<li>know what is<strong> Kotlin when</strong> and what are the differences when used as an <strong>expression</strong> or <strong>statement</strong>,</li>
<li>when does the <strong>else branch is mandatory</strong>,</li>
<li>how does it work with <strong>enums</strong> and<strong> sealed classes</strong>,</li>
<li>how can we replace the <strong>if-else-if</strong> block with it, make use of smart casts, and many more&#8230;</li>
</ul>
<h2 class="article-heading-introduction">2. What is Kotlin When?</h2>
<p>With that being said, let&#8217;s start with answering the question- <strong>what exactly the Kotlin when is</strong>?</p>
<p><a href="https://codersee.com/newsletter/"><img decoding="async" class="aligncenter wp-image-3002956 size-large" src="http://blog.codersee.com/wp-content/uploads/2022/05/join_newsletter-1024x576.png" alt="Image shows two ebooks people can get for free after joining newsletter" width="800" height="419" /></a></p>
<p>&nbsp;</p>
<p>Basically, it&#8217;s a conditional expression, which lets us specify more than two branches. Just like with <code class="EnlighterJSRAW" data-enlighter-language="raw">if</code> we can specify what should happen when the expression <strong>is either true or false</strong>, Kotlin <code class="EnlighterJSRAW" data-enlighter-language="raw">when</code> lets us do the same for <strong>many expressions</strong>.</p>
<p>Its basic syntax looks, as follows:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">when (someNumber) {
  1 -&gt; println("Value is equal to 1.")
  2 -&gt; println("Value is equal to 2.")
  3 -&gt; println("Value is equal to 3.")
  else -&gt; println("Value is greater than 3.")
}</pre>
<p>As we can see, if the value is equal to 1, 2, or 3, then the appropriate println statement is invoked. Otherwise, the <em>&#8220;Value is greater than 3.&#8221;</em> text will be printed.</p>
<h2 class="article-heading-introduction">3. Is The Else Branch Mandatory?</h2>
<p>As the next step, let&#8217;s answer the question: <strong>is the <em>else</em> branch mandatory</strong>? The answer is- <strong>not always</strong>&#8211; and here comes the explanation.</p>
<p>So, the <em>Kotlin when</em> can be used as either:</p>
<ul>
<li><strong>expression- </strong>simply, when the result of a branch is returned, for example, assigned to a variable,</li>
<li>or a <strong>statement- </strong>when it does not return any value.</li>
</ul>
<p>When we use it as an expression, we have to make our compiler &#8220;happy&#8221; that all possibilities are covered (exhausted).</p>
<p>To get a better understanding, let&#8217;s look at the following snippet:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">// Simple statement:
when(someNumber) {
  1 -&gt; "Value is 1"
}

// Expression:
val someText = when(someNumber) {
  1 -&gt; "Value is 1"
  else -&gt; "Value is not 1"
}</pre>
<p>As we can see, in the first case we have a simple <strong>statement</strong>, which means that it works without the else branch. On the other hand, in the second case, <strong>we have to provide the else branch</strong>, because otherwise, the code will not compile with the following error:</p>
<blockquote><p>Kotlin: &#8216;when&#8217; expression must be exhaustive, add necessary &#8216;else&#8217; branch.</p></blockquote>
<p>To rephrase it in an even more human way- if we want to assign some String value to the <code class="EnlighterJSRAW" data-enlighter-language="raw">someText</code> variable based on our <em>Kotlin when</em> instruction we have to make sure that the compiler will always be <strong>100% sure, what value it should assign</strong>. In the code snippet above, the <code class="EnlighterJSRAW" data-enlighter-language="raw">someNumber</code> can be whatever number. What String value should the compiler assign if we do handle only one case without the <code class="EnlighterJSRAW" data-enlighter-language="raw">else</code> branch? What if the <code class="EnlighterJSRAW" data-enlighter-language="raw">someNumber</code> will be let&#8217;s say 23? And that&#8217;s the main reason why the else branch is mandatory in such a case.</p>
<h2 class="article-heading-introduction">4. Exhaustive Kotlin When</h2>
<p>But with that in mind, we have to remember that in Kotlin there are a few possibilities to make branches exhaustive without the <code class="EnlighterJSRAW" data-enlighter-language="raw">else</code> branch:</p>
<ul>
<li><strong>enums</strong> &#8211; we can specify a branch for each value of the enum class,</li>
<li><strong>sealed classes</strong> &#8211; we can handle each subclass separately,</li>
<li><strong>booleans</strong> &#8211; simply replacing else with false will be exhausting.</li>
</ul>
<p>Let&#8217;s see a couple of examples below.</p>
<h3 class="article-heading-introduction">4.1. Kotlin When With Enum Class</h3>
<p>As the first one, let&#8217;s take a look at the <strong>Kotlin enum class</strong>:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">enum class UserType {
  STANDARD, MANAGER, ADMIN
}

fun getUserTypeLabel(userType: UserType): String =
  when (userType) {
    UserType.STANDARD -&gt; "Standard User"
    UserType.MANAGER -&gt; "Manager User"
    UserType.ADMIN -&gt; "Admin User"
  }</pre>
<p>As we can see, when we cover each enum value, the compiler has no &#8220;doubts&#8221; about what String value should be returned.</p>
<p>Nevertheless, please keep in mind that we will have to update this function if we add more values to our enum class.</p>
<h3 class="article-heading-introduction">4.2. Kotlin When With Sealed Class</h3>
<p>Nextly, let&#8217;s see the example with a <strong>sealed class</strong>:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">sealed class User

class StandardUser: User()
class ManagerUser: User()
class AdminUser: User()

fun printAndReturnText(user: User) : String =
  when (user) {
    is StandardUser -&gt; {
      println("It was a Standard User.")
      "Standard User"
    }
    is ManagerUser -&gt; {
      println("It was a Manager.")
      "Manager User"
    }
    is AdminUser -&gt; {
      println("It was an Admin.")
      "Admin User"
    }
}</pre>
<p>Similarly, all possibilities are covered and logic is invoked based on the subclass type.</p>
<p>Furthermore, there&#8217;s one interesting thing happening here- a <strong>smart cast</strong>, and we will get back to it later.</p>
<h3 class="article-heading-introduction">4.3. When Expression With Boolean</h3>
<p>Finally, let&#8217;s check an example with a<strong> Boolean value</strong>:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">val someBoolean = true

val someText = when (someBoolean) {
  true -&gt; "It's true."
  false -&gt; "It's false."
}</pre>
<p>Although we used a <strong>false</strong> as a second branch here, we could achieve the same with an <strong>else</strong> in this particular case.</p>
<h2 class="article-heading-introduction">5. Kotlin When Smart Cast</h2>
<p>At <code class="EnlighterJSRAW" data-enlighter-language="raw">4.2.</code>, I&#8217;ve mentioned one of the coolest things in Kotlin when expression- <strong>smart casts</strong> (you can read more about them later <a href="https://kotlinlang.org/docs/typecasts.html#smart-casts" target="_blank" rel="noopener">right here</a>).</p>
<p>Let&#8217;s rewrite our example a bit and add a few functions to classes:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">sealed class User

class StandardUser : User() {
  fun onlyStandardUserFunction() {}
}

class ManagerUser : User()
class AdminUser : User() {
  fun onlyAdminFunction() {}
  fun onlyAdminFunction2() {}
}</pre>
<p>With that being done, our when expression can look, as follows:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">fun printAndReturnText(user: User): String =
  when (user) {
    is StandardUser -&gt; {
      user.onlyStandardUserFunction()
      "Standard User"
    }
    is ManagerUser -&gt; {
      "Manager User"
    }
    is AdminUser -&gt; {
      user.onlyAdminFunction()
      user.onlyAdminFunction2()
      "Admin User"
    }
}</pre>
<p>As can be seen, our <strong>user</strong> instance <strong>has been automatically casted to the desired types</strong>. To put it simply, when the compiler checks that the user is an instance of AdminUser class, we can use its functions without casting.</p>
<p>So that this:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">is AdminUser -&gt; {
  user.onlyAdminFunction()
  user.onlyAdminFunction2()
  "Admin User"
}</pre>
<p>Can be done without this:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">is AdminUser -&gt; {
  (user as AdminUser).onlyAdminFunction()
  (user as AdminUser).onlyAdminFunction2()
  "Admin User"
}</pre>
<p>It&#8217;s worth mentioning here, that <strong>we can do that with any class, not only with sealed class instances</strong>:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">fun someFunction(argument: Any) {
  when (argument) {
    is Int -&gt; {
      val subtracted = argument.minus(2)
      println(subtracted)
    }
    is String -&gt; {
      val upperCase = argument.uppercase()
      println(upperCase)
    }
  }
}</pre>
<p>As we can see, when the argument is of an <strong>Int</strong> type, we can invoke a <strong>minus</strong> function. Alternatively, when it&#8217;s a <strong>String, we can transform it to upper case</strong>.</p>
<h2 class="article-heading-introduction">6. Kotlin When As if-else-if Replacement</h2>
<p>As you might have already noticed, in the above examples all branches were invoked based on the same check.</p>
<p>But that&#8217;s not always the case. When creating an if-else-if statement, we can perform completely different comparisons:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">if (someNumber == 1)
  println("Value is equal to 1.")
else if (anotherNumber == 55 &amp;&amp; someText == "some")
  println("Completely differentn comparison.")
else
  println("Else branch invoked.")</pre>
<p>As we can see, we do check for completely different conditions, and based on them the appropriate logic is executed.</p>
<p>But can we do the same with a Kotlin when (not switch! :D) statement? Of course, we do. The above logic can be rewritten to:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">when {
  someNumber == 1 -&gt; "Value is equal to 1."
  anotherNumber == 55 &amp;&amp; someText == "some" -&gt; println("Value is equal to 2.")
  else -&gt; println("Value is greater than 3.")
}</pre>
<p>Please note, that this time <strong>we don&#8217;t have the expression inside the curly braces</strong>. Moreover, the else branch could be skipped in this particular case (and if you know why, please type a comment! 😀 ).</p>
<h2 class="article-heading-introduction">7. Kotlin When Variable</h2>
<p>As the last thing, I would like to show you one more case.</p>
<p>The Kotlin when expression <strong>allows us to assign our check result to a variable</strong>, which then can be used inside the when. Moreover, this particular variable <strong>scope will be limited to the when expression only. </strong></p>
<p>And again, this might sound confusing, so let&#8217;s see an example:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">when (val someNumber = 10) {
  10 -&gt; {
    val anotherNumber = someNumber * 10
    println(anotherNumber)
  }
  else -&gt; {
    val anotherNumber = someNumber - 10
    println(anotherNumber)
  }
}
val someNumber = 20  // No conflicting declaration error</pre>
<p>As we can see, we declare the <code class="EnlighterJSRAW" data-enlighter-language="raw">someNumber</code> inside the curly braces and we can then utilize it inside our branches. Finally, we can declare a variable with exactly the same name just right after the when expression.</p>
<h2 class="article-heading-introduction">9. Summary</h2>
<p>And that would be all for this article on the &#8220;Kotlin switch&#8230; ekhm.. when expression&#8221;.</p>
<p>Let me know whether you enjoyed it and whether you would like to see more core Kotlin articles in <strong>the comment section below</strong>.</p>
<p>Finally, as a reminder, if you&#8217;d like to check your Kotlin knowledge, you can visit my <a href="https://blog.codersee.com/programming-quizzes/">quizzes page</a>.</p>
<p>&nbsp;</p>
<p>The post <a href="https://blog.codersee.com/kotlin-switch-when-expression/">Kotlin switch&#8230; ekhm.. when expression</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.codersee.com/kotlin-switch-when-expression/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>All You Need To Know About Data Classes in Kotlin</title>
		<link>https://blog.codersee.com/data-classes-in-kotlin/</link>
					<comments>https://blog.codersee.com/data-classes-in-kotlin/#respond</comments>
		
		<dc:creator><![CDATA[Piotr]]></dc:creator>
		<pubDate>Tue, 10 May 2022 06:46:01 +0000</pubDate>
				<category><![CDATA[Kotlin]]></category>
		<category><![CDATA[Core Kotlin]]></category>
		<guid isPermaLink="false">https://codersee.com/?p=2502750</guid>

					<description><![CDATA[<p>In this article, we will take a look at a concept of data classes in Kotlin and how they can help us in a day-to-day work.</p>
<p>The post <a href="https://blog.codersee.com/data-classes-in-kotlin/">All You Need To Know About Data Classes in Kotlin</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2 class="article-heading-introduction">1. Introduction</h2>
<p>In this article, I would like to introduce you to the concept of <strong>data classes in Kotlin</strong> and how they can help you in your day-to-day coding. Together, we will learn their purpose, possibilities and a few rules we have to remember about when using them.</p>
<h2 class="article-heading-introduction">2. What Are Data Classes and Why Do We Need Them?</h2>
<p>Oftentimes, when implementing any program we may encounter the need for a class, which main purpose will be holding and transferring the data. Database queries results might be a great example here.</p>
<p>For such a case, the creators of Kotlin came up with <strong>data classes</strong>:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">data class Person(val name: String, val age: Int)</pre>
<p>Although we can&#8217;t see it, adding a <strong>data</strong> word before a standard Kotlin class results in a few functions being generated automatically:</p>
<ul>
<li><strong>equals()</strong> and <strong>hashCode()</strong></li>
<li><strong>toString()</strong></li>
<li><strong>copy()</strong></li>
<li><strong>component1()&#8230;componentN()</strong> &#8211; for each property declared in the primary constructor</li>
</ul>
<p>Given these points,<strong> data classes</strong> allow us to write less verbose, less error-prone and easier to maintain code.</p>
<h3 class="article-heading-introduction">2.1. equals() and hashCode()</h3>
<p>With that being said, let&#8217;s have a look at the first two functions-<strong> equals()</strong> and <strong>hashCode()</strong>:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">val firstPerson = Person("Peter", 40)
val secondPerson = Person("Peter", 40)

println(firstPerson.hashCode()) //-1907803204
println(secondPerson.hashCode()) //-1907803204

println(firstPerson == secondPerson)// true</pre>
<p>As we can clearly see, both functions work, as expected and the hashCode for two structurally equal instances is exactly the same.</p>
<p>If you would like to learn a bit more about Kotlin equality, then I highly recommend <a href="https://kotlinlang.org/docs/equality.html" target="_blank" rel="noopener">this article</a> from their official documentation.</p>
<h3 class="article-heading-introduction">2.2. toString()</h3>
<p>As the next step, let&#8217;s let&#8217;s have a look at the <strong>toString()</strong>:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">val person = Person("John", 20)

println(person) // Person(name=John, age=20)</pre>
<p>As can be seen, the default Kotlin <strong>toString()</strong> implementation uses the following format:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">ClassName(propertyOne=valueOne, propertyTwo=valueTwo)</pre>
<h3 class="article-heading-introduction">2.3. copy()</h3>
<p>Nextly, let&#8217;s check out the <strong>copy()</strong> function, which allows us to create a new instance of a data class changing some of its properties:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">val beforeCopying = Person("Peter", 30)
val afterCopying = beforeCopying.copy(
    age = 35
)

println(beforeCopying === afterCopying)  // false
println(afterCopying)  // Person(name=Peter, age=35)</pre>
<p>A copy function created a totally new instance of Person class (referential equality <strong>===</strong> returning false is a proof for that) with age set to a new value.</p>
<p>From the technical side, the copy implementation for our class would be as follows:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">fun copy(name: String = this.name, age: Int = this.age) = Person(name, age)</pre>
<h3 class="article-heading-introduction">2.4. Destructuring Declarations with componentN() Functions</h3>
<p>Finally, let&#8217;s take a while to understand componentN() functions.</p>
<p>As I&#8217;ve mentioned previously, such a function will be generated for each property declared in the <strong>primary constructor</strong>:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">data class Person(val name: String, val age: Int) {
    lateinit var email: String
}

val person = Person("John", 20)

val personName = person.component1()  // John
val personAge = person.component2()   // 20
val personEmail = person.component3() // ERROR</pre>
<p>As we can see, we can reference to the Person name and age using <strong>component1()</strong> and <strong>component2()</strong> functions (and yes, in case of more properties, functions <strong>component3()</strong>&#8230; etc. would be generated).</p>
<p>However, the most important thing here is that these functions allow us to <strong>destructure an object into variables</strong>:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">val person = Person("John", 20)

val (personName, personAge) = person
println(personName)
println(personAge)</pre>
<p>This syntax in Kotlin is called a <strong>destructuring declaration</strong> and allows us to keep our code even more concise.</p>
<p>If you would like to learn a bit more about it, then I recommend <a href="https://kotlinlang.org/docs/destructuring-declarations.html" target="_blank" rel="noopener">this article</a> from JetBrains.</p>
<p>&nbsp;</p>
<p><a href="https://codersee.com/newsletter/"><img loading="lazy" decoding="async" class="aligncenter wp-image-3002956 size-large" src="http://blog.codersee.com/wp-content/uploads/2022/05/join_newsletter-1024x576.png" alt="Image shows two ebooks people can get for free after joining newsletter" width="800" height="419" /></a></p>
<p>&nbsp;</p>
<h2 class="article-heading-introduction">3. Data Classes Limitations and Behaviour</h2>
<p>So for now, we&#8217;ve learned what data classes are in Kotlin and what do they bring to the table. Nevertheless, we have to keep in mind that there are a few rules we have to remember about when working with them.</p>
<p>In this chapter, I will walk you through all of them.</p>
<h3 class="article-heading-introduction">3.1. Open, Sealed, Abstract, Inner</h3>
<p>First of all, data classes <strong>cannot</strong> be open, sealed or abstract. If we declare it with either of them, the code won&#8217;t compile informing us with the following message:</p>
<blockquote><p>Modifier &#8216;XYZ&#8217; is incompatible with &#8216;data&#8217;</p></blockquote>
<h3 class="article-heading-introduction">3.2. Primary Constructor</h3>
<p>Nextly, we have to remember that primary constructor has to contain <strong>at least one parameter:</strong></p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">class One()      // OK
data class Two() // ERROR</pre>
<p>As we can see, the second line will result in a pretty descriptive error thrown:</p>
<blockquote><p>Data class must have at least one primary constructor parameter</p></blockquote>
<p>Whatsoever, all primary constructors has to be marked as <strong>val</strong> or <strong>var</strong>, so the following code:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">data class Person(var name: String, age: Int)</pre>
<p>Will lead us to again to the compilation error:</p>
<blockquote><p>Data class primary constructor must have only property (val / var) parameters.</p></blockquote>
<h3 class="article-heading-introduction">3.3. copy() and componentN() Implementations</h3>
<p>Following, we have to keep in mind that we <strong>can&#8217;t</strong> implement our own <strong>copy()</strong> and <strong>componentN()</strong> implementations.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">data class Person(val name: String, val age: Int) {
    fun copy(
        name: String = this.name,
        age: Int = this.age
    ) = Person(name, age)
    
    fun component1() : String = ""
}</pre>
<p>As we can see, both declarations will prohibit our code from compiling because of the <strong>conflicting overloads.</strong></p>
<p>On the other hand, we can provide our custom implementation for <strong>toString()</strong>, <strong>hashCode()</strong> and <strong>equals()</strong> functions.</p>
<h3 class="article-heading-introduction">3.4. Default Constructor</h3>
<p>Another thing worth remembering when working with JVM is that we have to specify default values for all properties if we would like the default constructor to be generated:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin">// default constructor won't be generated
data class One(val name: String = "", val age: Int)
// default constructor generated underneath
data class Two(val name: String = "", val age: Int = 0)</pre>
<p>Although it might seem like a trifle, some libraries might require us to do so to work properly. A good example here is Jackson and &#8220;<strong>No Creators, like default construct, exist&#8221; </strong>error</p>
<h3 class="article-heading-introduction">3.5 Inheritance</h3>
<p>Finally, let&#8217;s see a few rules related to the inheritance:</p>
<ul>
<li>first of all, data classes in Kotlin<strong> can extend</strong> other classes (although cannot be open)</li>
<li>secondly, please keep in mind that if the superclass contains a final implementation for <strong>toString()</strong>, <strong>hashCode()</strong> or <strong>equals()</strong>, then none of them will be generated in our data class</li>
<li>lastly, if the supertype declares open componentN() functions with incompatibile types, then the error will be thrown</li>
</ul>
<h2 class="article-heading-introduction">4. Summary</h2>
<p>And that would be all for this article covering <strong>data classes in Kotlin</strong>. I know, that all these rules and limitations above seem like plenty of things to deal with, but trust me, you won&#8217;t event notice them in real-life scenarios. Data classes are a great feature in Kotlin and sooner or later you will find them useful and this article is definitely worth <strong>bookmarking</strong>.</p>
<p>I would be happy if you would like to spend one minute and let me know if such materials are useful for you in the comments section or with the <a href="https://codersee.com/contact/">contact form</a>.</p>
<p>The post <a href="https://blog.codersee.com/data-classes-in-kotlin/">All You Need To Know About Data Classes in Kotlin</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.codersee.com/data-classes-in-kotlin/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>

<!--
Performance optimized by W3 Total Cache. Learn more: https://www.boldgrid.com/w3-total-cache/?utm_source=w3tc&utm_medium=footer_comment&utm_campaign=free_plugin

Page Caching using Disk: Enhanced 

Served from: blog.codersee.com @ 2026-05-12 04:04:09 by W3 Total Cache
-->