From 227710d25b044096fc47c104ad8fd9c3e9f999da Mon Sep 17 00:00:00 2001 From: Quinton Hoole Date: Tue, 5 Jan 2016 17:53:54 -0800 Subject: [PATCH] RFC design docs for Cluster Federation/Ubernetes. --- docs/design/control-plane-resilience.md | 269 ++++++++++++ docs/design/federated-services.md | 550 ++++++++++++++++++++++++ docs/design/federation-phase-1.md | 434 +++++++++++++++++++ docs/design/ubernetes-cluster-state.png | Bin 0 -> 13824 bytes docs/design/ubernetes-design.png | Bin 0 -> 20358 bytes docs/design/ubernetes-scheduling.png | Bin 0 -> 39094 bytes 6 files changed, 1253 insertions(+) create mode 100644 docs/design/control-plane-resilience.md create mode 100644 docs/design/federated-services.md create mode 100644 docs/design/federation-phase-1.md create mode 100644 docs/design/ubernetes-cluster-state.png create mode 100644 docs/design/ubernetes-design.png create mode 100644 docs/design/ubernetes-scheduling.png diff --git a/docs/design/control-plane-resilience.md b/docs/design/control-plane-resilience.md new file mode 100644 index 0000000000..8becccec19 --- /dev/null +++ b/docs/design/control-plane-resilience.md @@ -0,0 +1,269 @@ + + + + +WARNING +WARNING +WARNING +WARNING +WARNING + +

PLEASE NOTE: This document applies to the HEAD of the source tree

+ +If you are using a released version of Kubernetes, you should +refer to the docs that go with that version. + +Documentation for other releases can be found at +[releases.k8s.io](http://releases.k8s.io). + +-- + + + + + +# Kubernetes/Ubernetes Control Plane Resilience + +## Long Term Design and Current Status + +### by Quinton Hoole, Mike Danese and Justin Santa-Barbara + +### December 14, 2015 + +## Summary + +Some amount of confusion exists around how we currently, and in future +want to ensure resilience of the Kubernetes (and by implication +Ubernetes) control plane. This document is an attempt to capture that +definitively. It covers areas including self-healing, high +availability, bootstrapping and recovery. Most of the information in +this document already exists in the form of github comments, +PR's/proposals, scattered documents, and corridor conversations, so +document is primarily a consolidation and clarification of existing +ideas. + +## Terms + +* **Self-healing:** automatically restarting or replacing failed + processes and machines without human intervention +* **High availability:** continuing to be available and work correctly + even if some components are down or uncontactable. This typically + involves multiple replicas of critical services, and a reliable way + to find available replicas. Note that it's possible (but not + desirable) to have high + availability properties (e.g. multiple replicas) in the absence of + self-healing properties (e.g. if a replica fails, nothing replaces + it). Fairly obviously, given enough time, such systems typically + become unavailable (after enough replicas have failed). +* **Bootstrapping**: creating an empty cluster from nothing +* **Recovery**: recreating a non-empty cluster after perhaps + catastrophic failure/unavailability/data corruption + +## Overall Goals + +1. **Resilience to single failures:** Kubernetes clusters constrained + to single availability zones should be resilient to individual + machine and process failures by being both self-healing and highly + available (within the context of such individual failures). +1. **Ubiquitous resilience by default:** The default cluster creation + scripts for (at least) GCE, AWS and basic bare metal should adhere + to the above (self-healing and high availability) by default (with + options available to disable these features to reduce control plane + resource requirements if so required). It is hoped that other + cloud providers will also follow the above guidelines, but the + above 3 are the primary canonical use cases. +1. **Resilience to some correlated failures:** Kubernetes clusters + which span multiple availability zones in a region should by + default be resilient to complete failure of one entire availability + zone (by similarly providing self-healing and high availability in + the default cluster creation scripts as above). +1. **Default implementation shared across cloud providers:** The + differences between the default implementations of the above for + GCE, AWS and basic bare metal should be minimized. This implies + using shared libraries across these providers in the default + scripts in preference to highly customized implementations per + cloud provider. This is not to say that highly differentiated, + customized per-cloud cluster creation processes (e.g. for GKE on + GCE, or some hosted Kubernetes provider on AWS) are discouraged. + But those fall squarely outside the basic cross-platform OSS + Kubernetes distro. +1. **Self-hosting:** Where possible, Kubernetes's existing mechanisms + for achieving system resilience (replication controllers, health + checking, service load balancing etc) should be used in preference + to building a separate set of mechanisms to achieve the same thing. + This implies that self hosting (the kubernetes control plane on + kubernetes) is strongly preferred, with the caveat below. +1. **Recovery from catastrophic failure:** The ability to quickly and + reliably recover a cluster from catastrophic failure is critical, + and should not be compromised by the above goal to self-host + (i.e. it goes without saying that the cluster should be quickly and + reliably recoverable, even if the cluster control plane is + broken). This implies that such catastrophic failure scenarios + should be carefully thought out, and the subject of regular + continuous integration testing, and disaster recovery exercises. + +## Relative Priorities + +1. **(Possibly manual) recovery from catastrophic failures:** having a Kubernetes cluster, and all + applications running inside it, disappear forever perhaps is the worst + possible failure mode. So it is critical that we be able to + recover the applications running inside a cluster from such + failures in some well-bounded time period. + 1. In theory a cluster can be recovered by replaying all API calls + that have ever been executed against it, in order, but most + often that state has been lost, and/or is scattered across + multiple client applications or groups. So in general it is + probably infeasible. + 1. In theory a cluster can also be recovered to some relatively + recent non-corrupt backup/snapshot of the disk(s) backing the + etcd cluster state. But we have no default consistent + backup/snapshot, verification or restoration process. And we + don't routinely test restoration, so even if we did routinely + perform and verify backups, we have no hard evidence that we + can in practise effectively recover from catastrophic cluster + failure or data corruption by restoring from these backups. So + there's more work to be done here. +1. **Self-healing:** Most major cloud providers provide the ability to + easily and automatically replace failed virtual machines within a + small number of minutes (e.g. GCE + [Auto-restart](https://cloud.google.com/compute/docs/instances/setting-instance-scheduling-options#autorestart) + and Managed Instance Groups, + AWS[ Auto-recovery](https://aws.amazon.com/blogs/aws/new-auto-recovery-for-amazon-ec2/) + and [Auto scaling](https://aws.amazon.com/autoscaling/) etc). This + can fairly trivially be used to reduce control-plane down-time due + to machine failure to a small number of minutes per failure + (i.e. typically around "3 nines" availability), provided that: + 1. cluster persistent state (i.e. etcd disks) is either: + 1. truely persistent (i.e. remote persistent disks), or + 1. reconstructible (e.g. using etcd [dynamic member + addition](https://github.com/coreos/etcd/blob/master/Documentation/runtime-configuration.md#add-a-new-member) + or [backup and + recovery](https://github.com/coreos/etcd/blob/master/Documentation/admin_guide.md#disaster-recovery)). + + 1. and boot disks are either: + 1. truely persistent (i.e. remote persistent disks), or + 1. reconstructible (e.g. using boot-from-snapshot, + boot-from-pre-configured-image or + boot-from-auto-initializing image). +1. **High Availability:** This has the potential to increase + availability above the approximately "3 nines" level provided by + automated self-healing, but it's somewhat more complex, and + requires additional resources (e.g. redundant API servers and etcd + quorum members). In environments where cloud-assisted automatic + self-healing might be infeasible (e.g. on-premise bare-metal + deployments), it also gives cluster administrators more time to + respond (e.g. replace/repair failed machines) without incurring + system downtime. + +## Design and Status (as of December 2015) + + + + + + + + + + + + + + + + + + + + + + +
Control Plane ComponentResilience PlanCurrent Status
API Server + +Multiple stateless, self-hosted, self-healing API servers behind a HA +load balancer, built out by the default "kube-up" automation on GCE, +AWS and basic bare metal (BBM). Note that the single-host approach of +hving etcd listen only on localhost to ensure that onyl API server can +connect to it will no longer work, so alternative security will be +needed in the regard (either using firewall rules, SSL certs, or +something else). All necessary flags are currently supported to enable +SSL between API server and etcd (OpenShift runs like this out of the +box), but this needs to be woven into the "kube-up" and related +scripts. Detailed design of self-hosting and related bootstrapping +and catastrophic failure recovery will be detailed in a separate +design doc. + + + +No scripted self-healing or HA on GCE, AWS or basic bare metal +currently exists in the OSS distro. To be clear, "no self healing" +means that even if multiple e.g. API servers are provisioned for HA +purposes, if they fail, nothing replaces them, so eventually the +system will fail. Self-healing and HA can be set up +manually by following documented instructions, but this is not +currently an automated process, and it is not tested as part of +continuous integration. So it's probably safest to assume that it +doesn't actually work in practise. + +
Controller manager and scheduler + +Multiple self-hosted, self healing warm standby stateless controller +managers and schedulers with leader election and automatic failover of API server +clients, automatically installed by default "kube-up" automation. + +As above.
etcd + +Multiple (3-5) etcd quorum members behind a load balancer with session +affinity (to prevent clients from being bounced from one to another). + +Regarding self-healing, if a node running etcd goes down, it is always necessary to do three +things: +
    +
  1. allocate a new node (not necessary if running etcd as a pod, in +which case specific measures are required to prevent user pods from +interfering with system pods, for example using node selectors as +described in dynamic member + addition. +In the case of remote persistent disk, the etcd state can be recovered +by attaching the remote persistent disk to the replacement node, thus +the state is recoverable even if all other replicas are down. + +There are also significant performance differences between local disks and remote +persistent disks. For example, the sustained throughput +local disks in GCE is approximatley 20x that of remote disks. + +Hence we suggest that self-healing be provided by remotely mounted persistent disks in +non-performance critical, single-zone cloud deployments. For +performance critical installations, faster local SSD's should be used, +in which case remounting on node failure is not an option, so +etcd runtime configuration +should be used to replace the failed machine. Similarly, for +cross-zone self-healing, cloud persistent disks are zonal, so +automatic +runtime configuration +is required. Similarly, basic bare metal deployments cannot generally +rely on +remote persistent disks, so the same approach applies there. +
+ +Somewhat vague instructions exist +on how to set some of this up manually in a self-hosted +configuration. But automatic bootstrapping and self-healing is not +described (and is not implemented for the non-PD cases). This all +still needs to be automated and continuously tested. +
+ + + +[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/design/control-plane-resilience.md?pixel)]() + diff --git a/docs/design/federated-services.md b/docs/design/federated-services.md new file mode 100644 index 0000000000..6febfb2137 --- /dev/null +++ b/docs/design/federated-services.md @@ -0,0 +1,550 @@ + + + + +WARNING +WARNING +WARNING +WARNING +WARNING + +

PLEASE NOTE: This document applies to the HEAD of the source tree

+ +If you are using a released version of Kubernetes, you should +refer to the docs that go with that version. + +Documentation for other releases can be found at +[releases.k8s.io](http://releases.k8s.io). + +-- + + + + + +# Kubernetes Cluster Federation (a.k.a. "Ubernetes") + +## Cross-cluster Load Balancing and Service Discovery + +### Requirements and System Design + +### by Quinton Hoole, Dec 3 2015 + +## Requirements + +### Discovery, Load-balancing and Failover + +1. **Internal discovery and connection**: Pods/containers (running in + a Kubernetes cluster) must be able to easily discover and connect + to endpoints for Kubernetes services on which they depend in a + consistent way, irrespective of whether those services exist in a + different kubernetes cluster within the same cluster federation. + Hence-forth referred to as "cluster-internal clients", or simply + "internal clients". +1. **External discovery and connection**: External clients (running + outside a Kubernetes cluster) must be able to discover and connect + to endpoints for Kubernetes services on which they depend. + 1. **External clients predominantly speak HTTP(S)**: External + clients are most often, but not always, web browsers, or at + least speak HTTP(S) - notable exceptions include Enterprise + Message Busses (Java, TLS), DNS servers (UDP), + SIP servers and databases) +1. **Find the "best" endpoint:** Upon initial discovery and + connection, both internal and external clients should ideally find + "the best" endpoint if multiple eligible endpoints exist. "Best" + in this context implies the closest (by network topology) endpoint + that is both operational (as defined by some positive health check) + and not overloaded (by some published load metric). For example: + 1. An internal client should find an endpoint which is local to its + own cluster if one exists, in preference to one in a remote + cluster (if both are operational and non-overloaded). + Similarly, one in a nearby cluster (e.g. in the same zone or + region) is preferable to one further afield. + 1. An external client (e.g. in New York City) should find an + endpoint in a nearby cluster (e.g. U.S. East Coast) in + preference to one further away (e.g. Japan). +1. **Easy fail-over:** If the endpoint to which a client is connected + becomes unavailable (no network response/disconnected) or + overloaded, the client should reconnect to a better endpoint, + somehow. + 1. In the case where there exist one or more connection-terminating + load balancers between the client and the serving Pod, failover + might be completely automatic (i.e. the client's end of the + connection remains intact, and the client is completely + oblivious of the fail-over). This approach incurs network speed + and cost penalties (by traversing possibly multiple load + balancers), but requires zero smarts in clients, DNS libraries, + recursing DNS servers etc, as the IP address of the endpoint + remains constant over time. + 1. In a scenario where clients need to choose between multiple load + balancer endpoints (e.g. one per cluster), multiple DNS A + records associated with a single DNS name enable even relatively + dumb clients to try the next IP address in the list of returned + A records (without even necessarily re-issuing a DNS resolution + request). For example, all major web browsers will try all A + records in sequence until a working one is found (TBD: justify + this claim with details for Chrome, IE, Safari, Firefox). + 1. In a slightly more sophisticated scenario, upon disconnection, a + smarter client might re-issue a DNS resolution query, and + (modulo DNS record TTL's which can typically be set as low as 3 + minutes, and buggy DNS resolvers, caches and libraries which + have been known to completely ignore TTL's), receive updated A + records specifying a new set of IP addresses to which to + connect. + +### Portability + +A Kubernetes application configuration (e.g. for a Pod, Replication +Controller, Service etc) should be able to be successfully deployed +into any Kubernetes Cluster or Ubernetes Federation of Clusters, +without modification. More specifically, a typical configuration +should work correctly (although possibly not optimally) across any of +the following environments: + +1. A single Kubernetes Cluster on one cloud provider (e.g. Google + Compute Engine, GCE) +1. A single Kubernetes Cluster on a different cloud provider + (e.g. Amazon Web Services, AWS) +1. A single Kubernetes Cluster on a non-cloud, on-premise data center +1. A Federation of Kubernetes Clusters all on the same cloud provider + (e.g. GCE) +1. A Federation of Kubernetes Clusters across multiple different cloud + providers and/or on-premise data centers (e.g. one cluster on + GCE/GKE, one on AWS, and one on-premise). + +### Trading Portability for Optimization + +It should be possible to explicitly opt out of portability across some +subset of the above environments in order to take advantage of +non-portable load balancing and DNS features of one or more +environments. More specifically, for example: + +1. For HTTP(S) applications running on GCE-only Federations, + [GCE Global L7 Load Balancers](https://cloud.google.com/compute/docs/load-balancing/http/global-forwarding-rules) + should be usable. These provide single, static global IP addresses + which load balance and fail over globally (i.e. across both regions + and zones). These allow for really dumb clients, but they only + work on GCE, and only for HTTP(S) traffic. +1. For non-HTTP(S) applications running on GCE-only Federations within + a single region, + [GCE L4 Network Load Balancers](https://cloud.google.com/compute/docs/load-balancing/network/) + should be usable. These provide TCP (i.e. both HTTP/S and + non-HTTP/S) load balancing and failover, but only on GCE, and only + within a single region. + [Google Cloud DNS](https://cloud.google.com/dns) can be used to + route traffic between regions (and between different cloud + providers and on-premise clusters, as it's plain DNS, IP only). +1. For applications running on AWS-only Federations, + [AWS Elastic Load Balancers (ELB's)](https://aws.amazon.com/elasticloadbalancing/details/) + should be usable. These provide both L7 (HTTP(S)) and L4 load + balancing, but only within a single region, and only on AWS + ([AWS Route 53 DNS service](https://aws.amazon.com/route53/) can be + used to load balance and fail over across multiple regions, and is + also capable of resolving to non-AWS endpoints). + +## Component Cloud Services + +Ubernetes cross-cluster load balancing is built on top of the following: + +1. [GCE Global L7 Load Balancers](https://cloud.google.com/compute/docs/load-balancing/http/global-forwarding-rules) + provide single, static global IP addresses which load balance and + fail over globally (i.e. across both regions and zones). These + allow for really dumb clients, but they only work on GCE, and only + for HTTP(S) traffic. +1. [GCE L4 Network Load Balancers](https://cloud.google.com/compute/docs/load-balancing/network/) + provide both HTTP(S) and non-HTTP(S) load balancing and failover, + but only on GCE, and only within a single region. +1. [AWS Elastic Load Balancers (ELB's)](https://aws.amazon.com/elasticloadbalancing/details/) + provide both L7 (HTTP(S)) and L4 load balancing, but only within a + single region, and only on AWS. +1. [Google Cloud DNS](https://cloud.google.com/dns) (or any other + programmable DNS service, like + [CloudFlare](http://www.cloudflare.com) can be used to route + traffic between regions (and between different cloud providers and + on-premise clusters, as it's plain DNS, IP only). Google Cloud DNS + doesn't provide any built-in geo-DNS, latency-based routing, health + checking, weighted round robin or other advanced capabilities. + It's plain old DNS. We would need to build all the aforementioned + on top of it. It can provide internal DNS services (i.e. serve RFC + 1918 addresses). + 1. [AWS Route 53 DNS service](https://aws.amazon.com/route53/) can + be used to load balance and fail over across regions, and is also + capable of routing to non-AWS endpoints). It provides built-in + geo-DNS, latency-based routing, health checking, weighted + round robin and optional tight integration with some other + AWS services (e.g. Elastic Load Balancers). +1. Kubernetes L4 Service Load Balancing: This provides both a + [virtual cluster-local](http://kubernetes.io/v1.1/docs/user-guide/services.html#virtual-ips-and-service-proxies) + and a + [real externally routable](http://kubernetes.io/v1.1/docs/user-guide/services.html#type-loadbalancer) + service IP which is load-balanced (currently simple round-robin) + across the healthy pods comprising a service within a single + Kubernetes cluster. +1. [Kubernetes Ingress](http://kubernetes.io/v1.1/docs/user-guide/ingress.html): A generic wrapper around cloud-provided L4 and L7 load balancing services, and roll-your-own load balancers run in pods, e.g. HA Proxy. + +## Ubernetes API + +The Ubernetes API for load balancing should be compatible with the +equivalent Kubernetes API, to ease porting of clients between +Ubernetes and Kubernetes. Further details below. + +## Common Client Behavior + +To be useful, our load balancing solution needs to work properly with +real client applications. There are a few different classes of +those... + +### Browsers + +These are the most common external clients. These are all well-written. See below. + +### Well-written clients + +1. Do a DNS resolution every time they connect. +1. Don't cache beyond TTL (although a small percentage of the DNS + servers on which they rely might). +1. Do try multiple A records (in order) to connect. +1. (in an ideal world) Do use SRV records rather than hard-coded port numbers. + +Examples: + ++ all common browsers (except for SRV records) ++ ... + +### Dumb clients + +1. Don't do a DNS resolution every time they connect (or do cache + beyond the TTL). +1. Do try multiple A records + +Examples: + ++ ... + +### Dumber clients + +1. Only do a DNS lookup once on startup. +1. Only try the first returned DNS A record. + +Examples: + ++ ... + +### Dumbest clients + +1. Never do a DNS lookup - are pre-configured with a single (or + possibly multiple) fixed server IP(s). Nothing else matters. + +## Architecture and Implementation + +### General control plane architecture + +Each cluster hosts one or more Ubernetes master components (Ubernetes API servers, controller managers with leader election, and +etcd quorum members. This is documented in more detail in a +[separate design doc: Kubernetes/Ubernetes Control Plane Resilience](https://docs.google.com/document/d/1jGcUVg9HDqQZdcgcFYlWMXXdZsplDdY6w3ZGJbU7lAw/edit#). + +In the description below, assume that 'n' clusters, named +'cluster-1'... 'cluster-n' have been registered against an Ubernetes +Federation "federation-1", each with their own set of Kubernetes API +endpoints,so, +"[http://endpoint-1.cluster-1](http://endpoint-1.cluster-1), +[http://endpoint-2.cluster-1](http://endpoint-2.cluster-1) +... [http://endpoint-m.cluster-n](http://endpoint-m.cluster-n) . + +### Federated Services + +Ubernetes Services are pretty straight-forward. They're comprised of +multiple equivalent underlying Kubernetes Services, each with their +own external endpoint, and a load balancing mechanism across them. +Let's work through how exactly that works in practice. + +Our user creates the following Ubernetes Service (against an Ubernetes +API endpoint): + + $ kubectl create -f my-service.yaml --context="federation-1" + +where service.yaml contains the following: + + kind: Service + metadata: + labels: + run: my-service + name: my-service + namespace: my-namespace + spec: + ports: + - port: 2379 + protocol: TCP + targetPort: 2379 + name: client + - port: 2380 + protocol: TCP + targetPort: 2380 + name: peer + selector: + run: my-service + type: LoadBalancer + +Ubernetes in turn creates one equivalent service (identical config to +the above) in each of the underlying Kubernetes clusters, each of +which results in something like this: + + $ kubectl get -o yaml --context="cluster-1" service my-service + + apiVersion: v1 + kind: Service + metadata: + creationTimestamp: 2015-11-25T23:35:25Z + labels: + run: my-service + name: my-service + namespace: my-namespace + resourceVersion: "147365" + selfLink: /api/v1/namespaces/my-namespace/services/my-service + uid: 33bfc927-93cd-11e5-a38c-42010af00002 + spec: + clusterIP: 10.0.153.185 + ports: + - name: client + nodePort: 31333 + port: 2379 + protocol: TCP + targetPort: 2379 + - name: peer + nodePort: 31086 + port: 2380 + protocol: TCP + targetPort: 2380 + selector: + run: my-service + sessionAffinity: None + type: LoadBalancer + status: + loadBalancer: + ingress: + - ip: 104.197.117.10 + +Similar services are created in `cluster-2` and `cluster-3`, each of +which are allocated their own `spec.clusterIP`, and +`status.loadBalancer.ingress.ip`. + +In Ubernetes `federation-1`, the resulting federated service looks as follows: + + $ kubectl get -o yaml --context="federation-1" service my-service + + apiVersion: v1 + kind: Service + metadata: + creationTimestamp: 2015-11-25T23:35:23Z + labels: + run: my-service + name: my-service + namespace: my-namespace + resourceVersion: "157333" + selfLink: /api/v1/namespaces/my-namespace/services/my-service + uid: 33bfc927-93cd-11e5-a38c-42010af00007 + spec: + clusterIP: + ports: + - name: client + nodePort: 31333 + port: 2379 + protocol: TCP + targetPort: 2379 + - name: peer + nodePort: 31086 + port: 2380 + protocol: TCP + targetPort: 2380 + selector: + run: my-service + sessionAffinity: None + type: LoadBalancer + status: + loadBalancer: + ingress: + - hostname: my-service.my-namespace.my-federation.my-domain.com + +Note that the federated service: + +1. Is API-compatible with a vanilla Kubernetes service. +1. has no clusterIP (as it is cluster-independent) +1. has a federation-wide load balancer hostname + +In addition to the set of underlying Kubernetes services (one per +cluster) described above, Ubernetes has also created a DNS name +(e.g. on [Google Cloud DNS](https://cloud.google.com/dns) or +[AWS Route 53](https://aws.amazon.com/route53/), depending on +configuration) which provides load balancing across all of those +services. For example, in a very basic configuration: + + $ dig +noall +answer my-service.my-namespace.my-federation.my-domain.com + my-service.my-namespace.my-federation.my-domain.com 180 IN A 104.197.117.10 + my-service.my-namespace.my-federation.my-domain.com 180 IN A 104.197.74.77 + my-service.my-namespace.my-federation.my-domain.com 180 IN A 104.197.38.157 + +Each of the above IP addresses (which are just the external load +balancer ingress IP's of each cluster service) is of course load +balanced across the pods comprising the service in each cluster. + +In a more sophisticated configuration (e.g. on GCE or GKE), Ubernetes +automatically creates a +[GCE Global L7 Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/global-forwarding-rules) +which exposes a single, globally load-balanced IP: + + $ dig +noall +answer my-service.my-namespace.my-federation.my-domain.com + my-service.my-namespace.my-federation.my-domain.com 180 IN A 107.194.17.44 + +Optionally, Ubernetes also configures the local DNS servers (SkyDNS) +in each Kubernetes cluster to preferentially return the local +clusterIP for the service in that cluster, with other clusters' +external service IP's (or a global load-balanced IP) also configured +for failover purposes: + + $ dig +noall +answer my-service.my-namespace.my-federation.my-domain.com + my-service.my-namespace.my-federation.my-domain.com 180 IN A 10.0.153.185 + my-service.my-namespace.my-federation.my-domain.com 180 IN A 104.197.74.77 + my-service.my-namespace.my-federation.my-domain.com 180 IN A 104.197.38.157 + +If Ubernetes Global Service Health Checking is enabled, multiple +service health checkers running across the federated clusters +collaborate to monitor the health of the service endpoints, and +automatically remove unhealthy endpoints from the DNS record (e.g. a +majority quorum is required to vote a service endpoint unhealthy, to +avoid false positives due to individual health checker network +isolation). + +### Federated Replication Controllers + +So far we have a federated service defined, with a resolvable load +balancer hostname by which clients can reach it, but no pods serving +traffic directed there. So now we need a Federated Replication +Controller. These are also fairly straight-forward, being comprised +of multiple underlying Kubernetes Replication Controllers which do the +hard work of keeping the desired number of Pod replicas alive in each +Kubernetes cluster. + + $ kubectl create -f my-service-rc.yaml --context="federation-1" + +where `my-service-rc.yaml` contains the following: + + kind: ReplicationController + metadata: + labels: + run: my-service + name: my-service + namespace: my-namespace + spec: + replicas: 6 + selector: + run: my-service + template: + metadata: + labels: + run: my-service + spec: + containers: + image: gcr.io/google_samples/my-service:v1 + name: my-service + ports: + - containerPort: 2379 + protocol: TCP + - containerPort: 2380 + protocol: TCP + +Ubernetes in turn creates one equivalent replication controller +(identical config to the above, except for the replica count) in each +of the underlying Kubernetes clusters, each of which results in +something like this: + + $ ./kubectl get -o yaml rc my-service --context="cluster-1" + kind: ReplicationController + metadata: + creationTimestamp: 2015-12-02T23:00:47Z + labels: + run: my-service + name: my-service + namespace: my-namespace + selfLink: /api/v1/namespaces/my-namespace/replicationcontrollers/my-service + uid: 86542109-9948-11e5-a38c-42010af00002 + spec: + replicas: 2 + selector: + run: my-service + template: + metadata: + labels: + run: my-service + spec: + containers: + image: gcr.io/google_samples/my-service:v1 + name: my-service + ports: + - containerPort: 2379 + protocol: TCP + - containerPort: 2380 + protocol: TCP + resources: {} + dnsPolicy: ClusterFirst + restartPolicy: Always + status: + replicas: 2 + +The exact number of replicas created in each underlying cluster will +of course depend on what scheduling policy is in force. In the above +example, the scheduler created an equal number of replicas (2) in each +of the three underlying clusters, to make up the total of 6 replicas +required. To handle entire cluster failures, various approaches are possible, +including: +1. **simple overprovisioing**, such that sufficient replicas remain even if a + cluster fails. This wastes some resources, but is simple and + reliable. +2. **pod autoscaling**, where the replication controller in each + cluster automatically and autonomously increases the number of + replicas in its cluster in response to the additional traffic + diverted from the + failed cluster. This saves resources and is reatively simple, + but there is some delay in the autoscaling. +3. **federated replica migration**, where the Ubernetes Federation + Control Plane detects the cluster failure and automatically + increases the replica count in the remainaing clusters to make up + for the lost replicas in the failed cluster. This does not seem to + offer any benefits relative to pod autoscaling above, and is + arguably more complex to implement, but we note it here as a + possibility. + +### Implementation Details + +The implementation approach and architecture is very similar to +Kubernetes, so if you're familiar with how Kubernetes works, none of +what follows will be surprising. One additional design driver not +present in Kubernetes is that Ubernetes aims to be resilient to +individual cluster and availability zone failures. So the control +plane spans multiple clusters. More specifically: + ++ Ubernetes runs it's own distinct set of API servers (typically one + or more per underlying Kubernetes cluster). These are completely + distinct from the Kubernetes API servers for each of the underlying + clusters. ++ Ubernetes runs it's own distinct quorum-based metadata store (etcd, + by default). Approximately 1 quorum member runs in each underlying + cluster ("approximately" because we aim for an odd number of quorum + members, and typically don't want more than 5 quorum members, even + if we have a larger number of federated clusters, so 2 clusters->3 + quorum members, 3->3, 4->3, 5->5, 6->5, 7->5 etc). + +Cluster Controllers in Ubernetes watch against the Ubernetes API +server/etcd state, and apply changes to the underlying kubernetes +clusters accordingly. They also have the anti-entropy mechanism for +reconciling ubernetes "desired desired" state against kubernetes +"actual desired" state. + + + +[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/design/federated-services.md?pixel)]() + diff --git a/docs/design/federation-phase-1.md b/docs/design/federation-phase-1.md new file mode 100644 index 0000000000..baf1e47247 --- /dev/null +++ b/docs/design/federation-phase-1.md @@ -0,0 +1,434 @@ + + + + +WARNING +WARNING +WARNING +WARNING +WARNING + +

PLEASE NOTE: This document applies to the HEAD of the source tree

+ +If you are using a released version of Kubernetes, you should +refer to the docs that go with that version. + +Documentation for other releases can be found at +[releases.k8s.io](http://releases.k8s.io). + +-- + + + + + +# Ubernetes Design Spec (phase one) + +**Huawei PaaS Team** + +## INTRODUCTION + +In this document we propose a design for the “Control Plane” of +Kubernetes (K8S) federation (a.k.a. “Ubernetes”). For background of +this work please refer to +[this proposal](../../docs/proposals/federation.md). +The document is arranged as following. First we briefly list scenarios +and use cases that motivate K8S federation work. These use cases drive +the design and they also verify the design. We summarize the +functionality requirements from these use cases, and define the “in +scope” functionalities that will be covered by this design (phase +one). After that we give an overview of the proposed architecture, API +and building blocks. And also we go through several activity flows to +see how these building blocks work together to support use cases. + +## REQUIREMENTS + +There are many reasons why customers may want to build a K8S +federation: + ++ **High Availability:** Customers want to be immune to the outage of + a single availability zone, region or even a cloud provider. ++ **Sensitive workloads:** Some workloads can only run on a particular + cluster. They cannot be scheduled to or migrated to other clusters. ++ **Capacity overflow:** Customers prefer to run workloads on a + primary cluster. But if the capacity of the cluster is not + sufficient, workloads should be automatically distributed to other + clusters. ++ **Vendor lock-in avoidance:** Customers want to spread their + workloads on different cloud providers, and can easily increase or + decrease the workload proportion of a specific provider. ++ **Cluster Size Enhancement:** Currently K8S cluster can only support +a limited size. While the community is actively improving it, it can +be expected that cluster size will be a problem if K8S is used for +large workloads or public PaaS infrastructure. While we can separate +different tenants to different clusters, it would be good to have a +unified view. + +Here are the functionality requirements derived from above use cases: + ++ Clients of the federation control plane API server can register and deregister clusters. ++ Workloads should be spread to different clusters according to the + workload distribution policy. ++ Pods are able to discover and connect to services hosted in other + clusters (in cases where inter-cluster networking is necessary, + desirable and implemented). ++ Traffic to these pods should be spread across clusters (in a manner + similar to load balancing, although it might not be strictly + speaking balanced). ++ The control plane needs to know when a cluster is down, and migrate + the workloads to other clusters. ++ Clients have a unified view and a central control point for above + activities. + +## SCOPE + +It’s difficult to have a perfect design with one click that implements +all the above requirements. Therefore we will go with an iterative +approach to design and build the system. This document describes the +phase one of the whole work. In phase one we will cover only the +following objectives: + ++ Define the basic building blocks and API objects of control plane ++ Implement a basic end-to-end workflow + + Clients register federated clusters + + Clients submit a workload + + The workload is distributed to different clusters + + Service discovery + + Load balancing + +The following parts are NOT covered in phase one: + ++ Authentication and authorization (other than basic client + authentication against the ubernetes API, and from ubernetes control + plane to the underlying kubernetes clusters). ++ Deployment units other than replication controller and service ++ Complex distribution policy of workloads ++ Service affinity and migration + +## ARCHITECTURE + +The overall architecture of a control plane is shown as following: + +![Ubernetes Architecture](ubernetes-design.png) + +Some design principles we are following in this architecture: + +1. Keep the underlying K8S clusters independent. They should have no + knowledge of control plane or of each other. +1. Keep the Ubernetes API interface compatible with K8S API as much as + possible. +1. Re-use concepts from K8S as much as possible. This reduces +customers’ learning curve and is good for adoption. Below is a brief +description of each module contained in above diagram. + +## Ubernetes API Server + +The API Server in the Ubernetes control plane works just like the API +Server in K8S. It talks to a distributed key-value store to persist, +retrieve and watch API objects. This store is completely distinct +from the kubernetes key-value stores (etcd) in the underlying +kubernetes clusters. We still use `etcd` as the distributed +storage so customers don’t need to learn and manage a different +storage system, although it is envisaged that other storage systems +(consol, zookeeper) will probably be developedand supported over +time. + +## Ubernetes Scheduler + +The Ubernetes Scheduler schedules resources onto the underlying +Kubernetes clusters. For example it watches for unscheduled Ubernetes +replication controllers (those that have not yet been scheduled onto +underlying Kubernetes clusters) and performs the global scheduling +work. For each unscheduled replication controller, it calls policy +engine to decide how to spit workloads among clusters. It creates a +Kubernetes Replication Controller on one ore more underlying cluster, +and post them back to `etcd` storage. + +One sublety worth noting here is that the scheduling decision is +arrived at by combining the application-specific request from the user (which might +include, for example, placement constraints), and the global policy specified +by the federation administrator (for example, "prefer on-premise +clusters over AWS clusters" or "spread load equally across clusters"). + +## Ubernetes Cluster Controller + +The cluster controller +performs the following two kinds of work: + +1. It watches all the sub-resources that are created by Ubernetes + components, like a sub-RC or a sub-service. And then it creates the + corresponding API objects on the underlying K8S clusters. +1. It periodically retrieves the available resources metrics from the + underlying K8S cluster, and updates them as object status of the + `cluster` API object. An alternative design might be to run a pod + in each underlying cluster that reports metrics for that cluster to + the Ubernetes control plane. Which approach is better remains an + open topic of discussion. + +## Ubernetes Service Controller + +The Ubernetes service controller is a federation-level implementation +of K8S service controller. It watches service resources created on +control plane, creates corresponding K8S services on each involved K8S +clusters. Besides interacting with services resources on each +individual K8S clusters, the Ubernetes service controller also +performs some global DNS registration work. + +## API OBJECTS + +## Cluster + +Cluster is a new first-class API object introduced in this design. For +each registered K8S cluster there will be such an API resource in +control plane. The way clients register or deregister a cluster is to +send corresponding REST requests to following URL: +`/api/{$version}/clusters`. Because control plane is behaving like a +regular K8S client to the underlying clusters, the spec of a cluster +object contains necessary properties like K8S cluster address and +credentials. The status of a cluster API object will contain +following information: + +1. Which phase of its lifecycle +1. Cluster resource metrics for scheduling decisions. +1. Other metadata like the version of cluster + +$version.clusterSpec + + + + + + + + + + + + + + + + + + + + + + + + + +
Name
+
Description
+
Required
+
Schema
+
Default
+
Address
+
address of the cluster
+
yes
+
address
+

Credential
+
the type (e.g. bearer token, client +certificate etc) and data of the credential used to access cluster. It’s used for system routines (not behalf of users)
+
yes
+
string
+

+ +$version.clusterStatus + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Name
+
Description
+
Required
+
Schema
+
Default
+
Phase
+
the recently observed lifecycle phase of the cluster
+
yes
+
enum
+

Capacity
+
represents the available resources of a cluster
+
yes
+
any
+

ClusterMeta
+
Other cluster metadata like the version
+
yes
+
ClusterMeta
+

+ +**For simplicity we didn’t introduce a separate “cluster metrics” API +object here**. The cluster resource metrics are stored in cluster +status section, just like what we did to nodes in K8S. In phase one it +only contains available CPU resources and memory resources. The +cluster controller will periodically poll the underlying cluster API +Server to get cluster capability. In phase one it gets the metrics by +simply aggregating metrics from all nodes. In future we will improve +this with more efficient ways like leveraging heapster, and also more +metrics will be supported. Similar to node phases in K8S, the “phase” +field includes following values: + ++ pending: newly registered clusters or clusters suspended by admin + for various reasons. They are not eligible for accepting workloads ++ running: clusters in normal status that can accept workloads ++ offline: clusters temporarily down or not reachable ++ terminated: clusters removed from federation + +Below is the state transition diagram. + +![Cluster State Transition Diagram](ubernetes-cluster-state.png) + +## Replication Controller + +A global workload submitted to control plane is represented as an +Ubernetes replication controller. When a replication controller +is submitted to control plane, clients need a way to express its +requirements or preferences on clusters. Depending on different use +cases it may be complex. For example: + ++ This workload can only be scheduled to cluster Foo. It cannot be + scheduled to any other clusters. (use case: sensitive workloads). ++ This workload prefers cluster Foo. But if there is no available + capacity on cluster Foo, it’s OK to be scheduled to cluster Bar + (use case: workload ) ++ Seventy percent of this workload should be scheduled to cluster Foo, + and thirty percent should be scheduled to cluster Bar (use case: + vendor lock-in avoidance). In phase one, we only introduce a + _clusterSelector_ field to filter acceptable clusters. In default + case there is no such selector and it means any cluster is + acceptable. + +Below is a sample of the YAML to create such a replication controller. + +``` +apiVersion: v1 +kind: ReplicationController +metadata: + name: nginx-controller +spec: + replicas: 5 + selector: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx + ports: + - containerPort: 80 + clusterSelector: + name in (Foo, Bar) +``` + +Currently clusterSelector (implemented as a +[LabelSelector](../../pkg/apis/extensions/v1beta1/types.go#L704)) +only supports a simple list of acceptable clusters. Workloads will be +evenly distributed on these acceptable clusters in phase one. After +phase one we will define syntax to represent more advanced +constraints, like cluster preference ordering, desired number of +splitted workloads, desired ratio of workloads spread on different +clusters, etc. + +Besides this explicit “clusterSelector” filter, a workload may have +some implicit scheduling restrictions. For example it defines +“nodeSelector” which can only be satisfied on some particular +clusters. How to handle this will be addressed after phase one. + +## Ubernetes Services + +The Service API object exposed by Ubernetes is similar to service +objects on Kubernetes. It defines the access to a group of pods. The +Ubernetes service controller will create corresponding Kubernetes +service objects on underlying clusters. These are detailed in a +separate design document: [Federated Services](federated-services.md). + +## Pod + +In phase one we only support scheduling replication controllers. Pod +scheduling will be supported in later phase. This is primarily in +order to keep the Ubernetes API compatible with the Kubernetes API. + +## ACTIVITY FLOWS + +## Scheduling + +The below diagram shows how workloads are scheduled on the Ubernetes control plane: + +1. A replication controller is created by the client. +1. APIServer persists it into the storage. +1. Cluster controller periodically polls the latest available resource + metrics from the underlying clusters. +1. Scheduler is watching all pending RCs. It picks up the RC, make + policy-driven decisions and split it into different sub RCs. +1. Each cluster control is watching the sub RCs bound to its + corresponding cluster. It picks up the newly created sub RC. +1. The cluster controller issues requests to the underlying cluster +API Server to create the RC. In phase one we don’t support complex +distribution policies. The scheduling rule is basically: + 1. If a RC does not specify any nodeSelector, it will be scheduled + to the least loaded K8S cluster(s) that has enough available + resources. + 1. If a RC specifies _N_ acceptable clusters in the + clusterSelector, all replica will be evenly distributed among + these clusters. + +There is a potential race condition here. Say at time _T1_ the control +plane learns there are _m_ available resources in a K8S cluster. As +the cluster is working independently it still accepts workload +requests from other K8S clients or even another Ubernetes control +plane. The Ubernetes scheduling decision is based on this data of +available resources. However when the actual RC creation happens to +the cluster at time _T2_, the cluster may don’t have enough resources +at that time. We will address this problem in later phases with some +proposed solutions like resource reservation mechanisms. + +![Ubernetes Scheduling](ubernetes-scheduling.png) + +## Service Discovery + +This part has been included in the section “Federated Service” of +document +“[Ubernetes Cross-cluster Load Balancing and Service Discovery Requirements and System Design](federated-services.md))”. Please +refer to that document for details. + + + +[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/design/federation-phase-1.md?pixel)]() + diff --git a/docs/design/ubernetes-cluster-state.png b/docs/design/ubernetes-cluster-state.png new file mode 100644 index 0000000000000000000000000000000000000000..56ec2df8b3fc7eee98f9a19d6149253f28608a37 GIT binary patch literal 13824 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 MYI&{X%Kaz*3pg1s2LJ#7 literal 0 HcmV?d00001 diff --git a/docs/design/ubernetes-design.png b/docs/design/ubernetes-design.png new file mode 100644 index 0000000000000000000000000000000000000000..44924846c5df6d4828e932bf7eab0920026f3560 GIT binary patch literal 20358 zcmeIacTiJl`#&5&MMXr{0!q_GK}DLB(6h=Sq7+@FNQ;PoN(n`32w_)+6)7tyMVg3$ ziV&nFkWd5x5eR620D**>P!k|PAf&t}!TmnZZ|3*cJM+%Ge|(wINlwnW&t0x|e?HfB zKe=jSA-VhLZV(70X?f}QKR_U{Mi5A}XXg&!3N-9UB?x3|ZTb888{tFqBjVX|o}U}X zu898GBewgLdF`!6G&?pjXW2&pb5H()Aay>6b~IX^#7{lv8a&+1MUieN%gDWpbkdB=RaAHaY{-0uSXVY=(TgpR69F6Pg)&t zX9SbYVo>O7*>HMI1T%7V_C*ewQNKy;GFs^|BaP&$qHyIS5d{|$zh!{~MjJ!Xv^EGY z5X;=FKN^FJ5SM>&6^o7-^h~cZVkCmeU$ejurh7tROd5nAfn}O*wA)gX=qd+mc*PbMp3)qQ!gCKnX|LA%T(9MnYRo6ww&m%hxpuc%t#hJ2drU=U-0WL zb8lXz)@@L;1|tp~IuyYy#f--Tomgy^>dumGsMlsz58Qr=i}21vgknkBcfS6Ei|}Ym z>cT&z#MLl)%jpf3SQ86H!~-(UHFWT#5sc)A?#c?AeP2|KHL*3_xI@ORbMrohFOB0O zxa?J*FnE&5+5j#Bn01d(@?N9)f541K2W;+!!4;wwKjR`Qyu0!EEHKQCjLU-6*8tPZ zTc2Q3R~JZNBN#0w44);9uB%(vU^Vb_z_9PH%?Bg2z44t{=<>V~mAoimbxNv-K8)mz z9E%az77(^EMLiD!ZPSba(b?nV%OH@*9^ePy0!UN_WLWT2z4q(F7|@P=ji4U2rq->G zx!b<$$_IC9DLmTCX8h7N`uQPojy-Oq@Gy_N^A<=XLFN1im9mUCVpy356)ACzh(uzX z6mq>;cA>g@&?{?l!tI=*cV+3?kPoV-r>D#f9o(95q`i&&vArRf%9}@1qVqp}`qX!B zso+~2^vI$*!pz z8XCfRj;~b>CnZ#0fY~KmL_`2`FyV*Bm2^(&Yp??2Sr9x4&ZtY>>{(v=mYqx*=wCyJ zIQz&p)&ydsHkS1o;v5b)E@}DCnW9&9e_#CF~iu}a@PIub@Pafz6E;m+r> zq=5D6P?vtVQae{FVQaE_qufPVM_Sz_|!1F0yGuCl2#XJy(%hOUqOS|nm~O_I+h zHZ&nvBk8Oq7p>pnYx75P!^fZ8;Q%szbIN1C5+g=z@7=Iy7YYi=oeP+Gn@%0+_s1@z z4bv2Pi*aM(koEKWfHI}doIH85ea-(<%i*!*4vlVqB;5l!SAvcW#v7<`*4rR^^Ei_# zOn+6f4X(~wZ}3jtjsQ5N*>C$|V4J+OLgaLQK>Nw`M_piwF@qiGG+ckc)>tbWu{Jm; zkV+e#~XT1DX3495p z7}9$!0##h{@#7vS`$u~J=@32gL;6%`moWZ#$?i{q+EeZb8xqgY*x^r~B zcJj#q6+rf{i7ZiWg^23ME^{`Rh~Qnf1O{m!^_XEAhNWA-3lOsr&ve)23+nY+b{r3j zY-!eOYCQajc3ev<_}#ZhC6nLinjLFZOwH`Ccm45zPt*WX@!8Zm*2yF(VCyU*(Hd=_5u~ zndeR#nY7-gPo%*c&f$%jos+eh&4naqbtMHag>;HJj^OpNS(Q6X7ME1mh4mW}xsJy-g5<3=Sgd1y) zgYN?#i4|IW;g5iFOh4a^+aYWOV-&eDm2R>VBy7 zsZ8ZOXnjy4X8YFagKEJ)2j|8h*8$zwdCN>-nL)4KvSXdL-u&@BMtsPT`>7+&bn@vA zM{mIH(w(5_!b0V<>X~T?wd^6uqm6GX&NTf+ObdBm_ObY*RKC^;VKcRvhtS*+$A?Qa zSl;wgFQu7?Z@m1`wTT4vb9#e;#Wu{U^d}v7o%?e>{ijM_Yk{q$Jos8BI(jl`G6Sh_O*O`7p4B=i9{X33jZW>ifqdJd z_1cbk*PMo^pzy$TrmU}AV6VFmV#Hm;Bwdp7*!+6)-(WW>b8~Z_Lyh03=Za1e?q8m3 zdLBnprpewvS}uaSV-;9zQkbfkk-D4K`=+-tke~g`>M4y@k2!I(wEClZrhQeVvX!D{ zgI!EoSBX_xG0KL5Zvs1J_u^&&ww{!|qouY;ZnIMt!d=FHGF+{-f@3`vjpsR5|&kt4F!Z(#rCDrG7)< z8}*yf{R9cYI$i`x+}c(KqU)bgRZT5(DT}(Cq3M1hL+9R)9Y>bD`9p4DE7RXC*Z0b; z+z1EaunX?)?!VA|jy48%GuEBGy^31y=CCgr#>@qaV)E4y(KDEot2(;!PX=Z1yV~E~ zu{XcI{?-G1Kf*fbYhXF=#;vx1TxQew)lX%HnQ5lbK6-AS45k1DGePB7yN|5(R__^g zNcUtoC#)}Tw^OZ)?wAR&TXp|o@_5G2<}q)*5VHIC1N7`Fdw8N?y$&}5A}s+37wkF6 z?S_t8Z(rYA(T{--6OcS+9iY&d~;&V+0O2Tl`{boAMgDlP;Ncjeh30uVl)Uo-XZ@pi3TV zymC=mrNeXWE*hJYxIwz9{~%CrR9;l_Sj>JvodDrBiUI+VRM=O)gwM{-&RLR_;hnAo zvsV-3!5R%U%fc3uPmjCR@bnhnBaIzoHOuYp*9;X%JF$I|qbEJ$m-ilUyXROs9^IEl zjLUpD1gX^b_ujK+w>@CEHQs!t?#J8UGvy-LN3OI$N7U7M3BCauHQx^)sZddR}~tU(yV*BSo8nck8Jf8haYBVGhkt}^pGGc&sD zqHz>8n1w*E0r3$?kx2GA1bc<08zY$~21KX(0rPYi_(wh^f;%3q`}Cr~jM3L^m+N*o zf|O#mmkECbLRL}C+>QXhF<+5kbJqu434tBlvV|F?ijC%BBZn_5z{6j3lysBS>lu`; zbXY^g!&roa)F`_~sj2bg@s*86|FPG8kyY5?{n94i={Rkk<|V-Hg&zWfI`J*b1uP33 zL`**zH#Bp-VotrDg}-6f7dIQ|abf0q^5fX$@~gb@9y@aA-N^Bp52WIw8(!}+jo(KM z$)k6UhWsJDm%loCwI`U=<3rF+Jq`D*Fb`k(Zqe-5ZEd9vVNWC68&KRcd&1d+lgq3I zR@dUy`#hN9ksKE?*CXz+1#B}ILn}EX7?kX@y9WjSgIokigg4~5@!Hj28mBZ&@^Z+I z4p=96OhN0=&{g(i!Qe4}w=lC)wVP{`Ixxo6vgaVk-#2pHiTy=MG+ffJW-4v$wW~x^ zn1cFcbx71gUX!#<-KqJIZ;DxIr~Jrb!&hZPA^azLERf>zi>z&cmEN+{ny%m&pK&tf z21n1{!IK4|?FiU2`0_NPWTm>89HH8K7{B{aGjylq$rkG|7vh;1hgxy{5T}*A8z;az zJ4dVZ&$!=c(D2mA<0OZr5U8M18`1EV^`Z&r(F>o8N-YcPIbTQqYyIeGag6`>rmIFi ztwReY{_mtbALi{o$yNO7KXFt%AT&8R2jpf(MDS_(K`meArzG$OYT2PfcJBk7LY<6} zfqYBr^j4MhD}T^-kRO-_@!rDu&(S!L-nM`_h|VsdPZ{;66+^lA)Ax*iznl zpd^d_v=_=sXQHRcJ&xB?ai8s|i?dcBhx!etGnGXWqoo)XCxN)075Xd8oV@>#ohWAV z*=EI@-^WrnY(Vs8;)y8jbX7Nn!?WocQg4$X!%My~^EDKd2v8^7^gp__kc>!kv>E3jH3xUtqT zl*^FZrBz*7lNh*^;mPMjJBd;CgN?F(38iFoFKieS2;5BgEQWbkZ7j!c&2zSf%uhj! zk~?j=toOYez_7r*v9YbOIM0d7@G_ny%rz%Rui?J=I~ZFZ6>d=KVQFm{#7j<9+{-^5 zrG@o%7LkJ$=YP_2(Ocq81~tssJ|>WBOmBK;tN$w@J4gKiBX_w_#dg|g;*?B}*7!oB zw8mwH4q|#kdQNrMsCLTY!qN@)Khs@1a#FSh9F%%t>eHJzws7P3mI$q=O=E5juCDHF z$cwQ>2le)>(8*$c`j=2+KJ9dJES!q#^#`@Bk07R{mP`4`M;@k<;z>H?cOx-(IXS>c zh0)4G5M4pU<@)th>e=U9xyf8rzdOc7v#$fLGY z+S!)}Ta)BvTay(j_bz^J-;DiBrG9Yig8Ib;yX%Tlo08a9eRF>Td(BLf7PSH}T@9a2 zp*_xf^fI<~lJn{@45bqzo3*AxE4>aZDiELm0ovM}T-~lT5P2uix<=M7_kDcKJUBA% zZO$3~@QKkz5faCJBD4wK!1UPghmlBdRL z;;R8%N&;R;=*m+99gEo>;6UCq3Z{S2^j`Whxoi5%d&Z;JDV_>4zzav!r5lCF2f7k~ zbm045_V)M30$YK&nP9SYZcGxeDLD(Jca;e(o2KA3R?;I9#>ji@MOsQq%A|b$mirOz z8C`9nx)_|dgjAJRo}Qix`-JTuX{2!JVceJtKRuXmX2Q6jwc;ZJwZ_hAfTjNWcfJI1 zyI_+3^E!d?5LmjLb1{n1>+XY;C(tro_cpc26Y1hO?6FK&9roB{P%$Waj(vxXX_u6q-yY^HW(7B7bIyMISP`&J`Gdx?#UqW$=@JZE>Y*Za z{#fNo=-GXZbCVAhIj>>fxm&j272saHu89o0riLcSN;jMi$S#eQIFbtbL;keEM!}w4pHzG8NW- z&lw)m&54|i+(c-YG~DW#eDH;onpMgln|v@dzC5||9hyCW^Q$w>{xWyoA=y@4Djarg zXMw+@$I~pL$#{Q73c-MZJ9w0|bCkep_w{B^{H=HT693w*Z%rwa573?6uRlbLfi-T# z^*A2bom6uYk)x!6FZGUdO|r3(wv)Ie+;jFD#7NMJ#4s4lfY`4wq?PYd^J&@mC^pO8 z%?3nSE0MQ1iczc`wI~tA+{PD=p->-pN*;RJe4bdJWd)fx+eAC6%a1HfrFM@>o8lHw9jG&70eUH|mL%@9N} zh}Z63BQh*QE=|BaoP{SV3FsBwT(jwtL-aDO2$hhlvg^h&wc5Gx&qDE zbmDQV(lWgy!5e52*lXgWwtAjvM%Fat!E+z@!7gEAVxHW6w>oaI<}h0@FJ@ zhF}x&)&#a{573OzhbsZM0OKhW_#VOMp3`FCPt~e_Viv+S2)ps7ng@+TUVpc1-HQOg zHzN8cwm?tfFom}O&kMWcn2hHPv$*GO+7=XV4~T=O7>_#Vk5WCFVR;S54;rtmCZQ1& zK1O)+&oKZUK@}}EF6EC_Ph9vsK{+VgRJfjt0dH$4*c!O_Vr;n5a~nm#vwxNk!~(+; zcrCrH3C~&4{hFHrOd5cEYIdzM9M1>4u#Ki*qVM}kAN4@KZqCuAf%0!8$g_BdbB3=3=9k`P`3F1 zh(U8g(cuU0DHEz>Rmnc{s&;{)7+5?C3=&mQ`|Y-fZ{_aMmoH!1XzQ(vb0dA6=!jhLI2&RU=1G zvTEiF6aM`8clQQ&=||t#FUz_mAcLoD-`PgZ%`UEjdB4Vhe*?^lul#*+{;B6T;xq%6 z$Mw>0>TD#1qL6*}Hh11qf~^eQE53nT*I+^cREc0-o#wF-?>X39r49c;RF0XjYa<&g zW!l%h*0YMf>mOAAsq~XU3>13!=zUo;GeV{QMJPnAm#A|>sr62F|5egIPTu$7v$Dv)~#B`$cFdAxIU$#HShzkTx^%KuW@)1vmstTew%B^oxe z!4sA9mFBRLOKFLus`AYv4Crv7J=1C1;_%p&=J?YyenN~x4}H#nPhZeZ4f*1i6Hc7h zoXR%<0D}=+j_%2-b`PD6&jy3{mZHzX(I-Nw$r<3KpMYWmoy`3r zdHdmoRF=sJ*~SLr*Rb_PUYvg~DB5%I%bgXu@Sq@r0*1DCNnZm?s+FU?a^H!_mJ5`H zIvGZnl)}l=S;WY!bB7(Iy^9dAUTaz2-~WiH#BOi7ZrJA&V?;Xj-m$W^q2o5rdI179 zQrj`xYeDsDRyzP7U$TFowJMCyD%^Zt7o9NriJy@x*?!{E+|iVo%zJhnKII*)jtB<1 zNpp!lI2hon^kle36QPgjtk#=AAq_M zftIJBS6_rdQWs{3a(p#(MUZ94FROvckqIN6E2nm>X2=$nEGeG;sl6v+CN_T5e#31X zkxbkm%wF$4cxJZP%+CxF>V$L4*24x_p7YE4?0qN6?TTx|@l1PrhZnUruCtZrYD#1a zrK}2*ZOj9+9SDw!xlZd|=N8z#I1KM@RJ*ST?kH7~+fe3-avPiWNcPLcjF*(P*&wo% zHb$wakvRx9?3AU+jPoD*CcU(Ik@|(+zY>3GG!ZXs=7gmx>};#!wc!d5j5lzHb_Ddo zdrr@(Z3D}%FWkw2D8QYAwlz}W9_Io{h;{w?8%DU!i%o z=eL4;#wOucWjLJ#ACtmPxtv5w-~r0+>qRz_Fz6=vC|A80082Ys(?6bz(T@Ag7V*IC zof=9)0B_YtnIwTI)u{rOV6?v}DNAR8J4)9E_2>sD;CS_Z39f-H) zOjITuwlCRPghTk9`cSe{Q9jiDTnQgXY|2xHq#&9`XfupSlZ~XvsrkB&FZBM0w%w)7 zESOs#Rbf=-OrinnbTIcr>`=g5=kYZV>O3f2BU46?OFl3N>51}hFg@-D{|fECryXNE z97fZV`jhM^VqAPXaGGdiMcuI&+MS)r`F>JcgST`dH=5VbaD~DsgnXRjeOFde7*{N^ z)qu);m?glg*1~xf03A(Cds_;Xzx=X)u>WslnZepB1^v=3o2~HP&x*g9tv$;a3~7a| z_r9s7wVa$F4Ht^Jac=6f8`2+Jz70-gv`tSIG8$@LbX;)tFg(gLp8Br4ceGP6aXd1( z!FIw!Ua@Glm(}-jUPOJsovDfBaWr9okK@ry&w1F{oe{Qxd20_ z8M!iDcBef>a~YOOoZUBV$vWsI^=Gc>t@BtBIok=@OD%P!HSXzHycNj%qO%Cj_kyM4 z%36Hi?*11Gy7I`mgcE-Svu>lS>aBE8EBmHztfU>bKS7f&ss_}vU4bH7^fau2uM>Ac3i7!)|(18?3{#Mg9L zBQcxO>)8+QI1MI918h7*qqo1P*=KWPuOxJUpE1dChr>-qDZz}wQFAeLiorL zv6mD{qk6o7zpY;cn_ZFT{M-eiF3U>U@~YTdAR7I1;xp{MS<4825Ljp7xI*RP!eVQD zdskesX~>VG+ZTO0C=#}3WuE1b3uacnZ=m9wy-ZWVCg8o*N28pAYDqncCyKJ(G%2z6 z0pRQB20h}jmMhJ$b#OC{j>P z4I!x8d;CPJ1vOy0bL`#s?$(iKF66+k2JNe_pIKkiD!6^kaL090%@u;1p~!HR==vit zFGczZG<;!MPfVY;|3vU~bd*WBatykCdrcr3YzLK?30XfiHwx+ifbw`p zUVr~OenZ|chBThs>*}-fR*cQQMy-H0e(*)I?5)Y%?rn>3)*&y-aV_ofwjGnvU(V~i zotcn1%n7@>9GQd3J(Wu>h1AhUt;_6xrJr`R*E9NfDi2ErPzL1Q0Bb+<<=+jWz21SM zk-)k?rPQfz8V<-7N$oZ=h1*2S9qhhq`1;l#zdT<`d^fImBM7P?Yo=AIQh~>`>C>wc z`3t-#!$hV%DSDp7wAEN8>F93TGZ_b72{XCDmf|hVQE6NoSEf@yrJ{<>>$Z#22#=7 z1Wr>y72J!+u#4heU4CO4at z!fzqAtX(-vNOnG;g4_m;z*InNSIsj`YOb^%Jh>zbxuO}Zcgv+PJTk&@ojO}*Hrcv+ zG>oTrvQsU4_^l~8$ozZx3brCLsGdEME!K?lWQ4>cDNQYm&{~!hOMEP< zU+-U4ki5LS48#^&V6pEPP||)`2;bjMWSE2hJ8^6T*=4mRu>Z=RWi6tt8LywIUa$`I zi`zZ=jA*l$i`3QMqhPFW3?zTe`56PbNq#m+YNmG+K&GR~7dh_|ZZZkyS9%*o#vV(% z?F^>jCAZr~-mbqm(V6^MTp|3JOX#3ye!w;M5^g+RwdsX}+u+#6;ns?7QzPRZeo_Dn zfsPfVG37M4O%RcsA-QvRzV1-m-o`kzTY(#kssTXmoS6{j7S9v@0wv=A&TkLX?dA|? z5DvDIm|_+$i|W&70GHM|Ux|^{2PaH$I#;EOF6h@Qd9;kr;*u}jopV(Iw;u0-xtSb) z{`|S`^J~|xJu}|#3{{H0(faPYQnMh#qtGfdWq#^!xRJ3IlnGES4PEO?6V0w+BQG9# zarWRnJJLch`ytW~W_#bevvFGP%O9_~Z!AyEaYAl7IlYWhYeD5nn(W52Gn5Yg1TvfZ#O2ey$`A})Y- z?-AM46CpN01EJ~w0j(e)_WZ%&jI0mVclf-de9~inS6|W&^O2n`CtR65V_#Fh%$_Yn z5ZZbtldQ!NM#c?ye8caMkrjkom&J<%oEgR=trqR(T`-<*=GyP~oxFJ0P&{R0Z1{t< z0+;b1=_ITPgKe~D!|fb5RfEegMDF`H~3TOl~`Rupqf39;t~8{k}5gHU<9 zMsspaz#G{=ba#yciVwL-yvZ0Im<_E)P!kqA!WercKG>fi-1bi+I-J~}Rl^N82p(BK zQsOLSsusn5ai!_U%al7#I69h)JA=iqZxk*~`1Q~7Hs$_nrw%~Q79g0>dcuiw6B|G% zxtLF@rvTxUOgfO=6Brfnbub^GQ*K%a=$dXW3*Ao3ZteC?R06DM0M$?hw~;=%^3{Q_ zaifp;$XYzw2K{{#o=&6hIAN&Qh&7daI?k#85OLm&;H*Z zg;)rHY^^Cf0++&wpdA9C`Om}PvhN;6VNW)%)!&UrcJ4je2;Cea{=_{%LVyG{Buk7| zK6}>?$$ct8++>Fh&8;K`L5@l%IF(G5B0LuQkz0Va24n%*3;UO1T28R*a9!ZbDYG(6ah^6G2XRg{Pa**$tb*W6}H-+-y zW88M!q4yoq(R$o)Jdlwf%m@0pAYeBT62Uh~>Bu@fpPOxpoKZ<3T!G*a?_gFMo17}| zN7AMI^BDdhuj_N|COv<&tl>?AxGB;yl${IJujn#qMDl0z^Q-e`E)2rQV!_wldmVqN zHW{PjFP0u?TAppyWIV}J5s4Zu-EK`GAlKlw2L7RKyeJNGt2O7Pq>k=aZFpuDRd!Rf@5t zs8qNjUMf_mr4pv5blYeAGxN+}JRXZ5)8gDW`|J&~g3<<5%jae)`b66AnIooC{tF`; zc9;6o2C3+mn@wJPTLPp{*g4DWHcexrRR`2V@(q0(oDJo)MdVl@@2Kgo*M}rWKeBI* zO(GMo;CZ(jIahTTIc1n%?})9F6uWng#=b5iPN7bwBcs~h1bu%8eD(`i;cKj^i%xi8Bv*06hI|`F;Wk^Hj2r(}YcIm7Pzn~qXzj6W zLL15jTJp0&HYHehcm3rdG=an!O_9NG<+dJ&fv!q^&>ub z8)(ZLVX)!>K>n&3KfMk8@^I?MPY*6fM)RpA^-4u*l4h|DnPeq7nhD!6{A>vOcR~;$ z{l*(su6jmxt?@BqBX>(?ys8)4iPH20MRis9#}HCRxoHWC`w`KO6X|{{b+c4GN)E{Sw16-q?Qikjkgh`(`-5^^lzT+8*SpI z1ddGMMdhWmE*W{YRFoDFTf23;F_sFayflhC0VupLld}D&$e!O)ZReLD$1j$Bq8D^< zgSb>vd4HD&-3$Qf-%c6EHv2iF9)|wX*z;JBTKJpvsKd@2a}N)XjD|a2%iAg|D|-Pp zBmc^d#ea^Q84n1sbgM98PtQK;+3Yl95w$aCmSc9_nobd!chD9PW?@9Azrr@a(16Ru zqeE}KduNT{F9csBC6iva7gy!RA4-n>Fi$c=U09l5jfS+^LVM`A=1_`qXYn#j4FIu0 z!UUh~0bu(BdLvXMQ>D-0@n8kvPbWK^{ziSL3*N3eDv-P~49Ycu-}+m8AsI3LVdad^ znN&~OS@kPiv$Il)!)Ls6B>M)L5`Prcp+`>FxVTc}2und;lQycQ{$F$Xy*C|V2PM)T zeM@;emd)LLVerQw5N6$1o&DDIcUJufZbbDk+R4_LB_)y|KnsN^IW}czylilL_v4;{ zelt_`v43( z0Zt)Y4<#MPelV%e;eZq5)141k=p>j0kE|IQ!$!&`!iOlDL>Eftg#7aVRE_m zPvqV>`Ott2=pR`wxxAsSu^!v`zS&5MNf0`qhX>c`W26L3e})(JGvEJXTt4-*DOwS7 zLN0pUBDK3S5fUk7bT&lRgL>j=Iv%br7u7>)-?QjC?N8Frowv}lX(=1 zHeydP-9F|4N1Te9d4q~eR@kiTx$1BrbeK^V&;-rxQfESpd=J@RUn9dO{-ng2F0Ius zR;?s#*v7h651g&xPOlXFK|=gy__sK3xuAU|HxKhw`Y(X00dlJVKv=-L{O9u`d#9|F zo=}=0adJU_iwjs90hkHG6t!Rw1-7p0GMq-#k3 zOJ{37NCYwjF1mvIrhlDyW}&bp;(%oRbjC6QDHBEm0OKt1BGZ?I$y^c^!ep*Rf6Um9 zpQO`Peo+9CmRA%4(s0xhP$j}l7a$=5(3qX0LjE1dYzOE&0ZRm+7{IvbwIaq1r(-(4 zeKQ6KrrJ9o*v_V(Nv_&>{bm6r7T}DOGu&*vy4d^VqQeoRm4BVu79AyQNyxbXJp`Pc ztLFb?dHmN6z;J-+k)F!40Nx9H`8WCi0to>hDu|GPO8`{`{F(reGy&d{qmt+Ke5;ucLoS82Q8rj&!)zr&;EWu` zGdz+6SqXsJJ_zf$ey!?VxYP2s2lv`PUcGsJ{CtF>=z6y4_I%D#MU!lYYE$-)l}aGJ z{&8TcS0NF5+ijV>s$Y_?WrF(XLK21ALnLvhfRF3QP#%_P{ ze$`%G0-M83UhJKs#eRqc#B|gyQ_CavUt(^=B*tU0oG|jtc_|gOxR#D!0TiReP8Q;b=5Ecq|vZi$kL4#%FSZz-cg`Z z=*GW9r%@}A2BHxISs7+EKc4WHq9yU#BA-@k)bTcZ_8leq>|B!z{{wTZDu<$oU^=<- zB~Y&Q{pcJm0JIJrnqrs?a55xD{Q)kx0F`&xYp+vAT{gUaY9Pbi1mH>BJFN-C%}8$u z`qV+w2K|JZK&LfR^9ldlPxf=NaOR5U#-9cPV?el;yKUDkk>L?h{np9&q2+*ymGfim z+hK2hWlpXh_II$3h^i~`Y4h&3q>~yS!``-%#?k>At#$6MOWQFBkiQink}caNieYXG z2yxwT5?{n1@n6*`1N)l3@H^@IL|mXZ70Go7YNV_8Ea~L)&W}6IuXkJ+9R7yetg05l zJ#YzhG%N)2%Ykgr0HPw2xAr7QFUDu?zM04DpuhJKVBdAc=W^3RMQruU`ggUbbl&tI zVvVoej~@@ODbH8#EwZ7g=8(?t&dm8Vsdwi{=Q?Wsdb7||hUd$XZ?Dv6BohJra+>8h*^ z%lcfTvc&)KW2xQGf@B)(6~qm@vOCptycgDhSU9>pAi2oqvO+;^EBlT-;D|FH_o=4% zohdEZ*T^7r^MI*?5V zMnWvR6*mV)C_NhNR{yr+u9v*3a=J1>dBi!xwe*gCWKJgOuJ6%`Tua7_(kteHUW3=T zKhWCV1LO0N+C-So^X}q302%8Co(~q&XDxMPC&LSzd4J}AD%FA+%@xc3Kv%swgUtaF zpkM4|zl_y{Pmix4oSPvhej58SkXxJzGbixl%<&$rZ{tYu`tWN(8$WijVja?~FX8h{ zm)V-N;aRIPCFPM)X~GL*mAQ%(#x>wAJ{UrN|oB(|a7~>^|6E zS-l48hDY2xm6JpE*(7rx=NDG0%XTaU%-GSd*=(N%(&Ky8~f(^#B0(8cRzfAP(6!h_j!qq#ibTi}td$TrY;VJwE zI*MJ1yZ2B!v6BQJ0mwD@Lm(?~;<6Xb8tX~b9(#P!gJ>AzVN5$yTI|Sbeq&?_a| z?A{#vxJ?21u{j!MyfK+NxajJra}vj%RdsKPKjb6Vs1+3au%ZrxH_6sN0I!KJOfM=T z>XokSn;i!E&-E;%iQsMr-6RJM)^%}z#Q9rP>_GF`Q$yvongD`bwRiMR)`uV98=uN* zM?gu)J$L6!TR^$lyTjss160uv$dsuP!+iRrb=JB1Z0AeeVnSjSLV6m&NRpn6YF_;CAzaiB1hHP4b`u!?0fCp7q7pou2N)1|@KU`m?|70MP z(pgOT1}(td`m#Jv9r9wUJ=E_qv$Ge067sRqI<0-B{@C> zC4JAh<_3KsoqYt2j|_dgUz%cET$ry8ufdg`fx*{gL(iWxsn6A$NITMff}oxij$|$n z?MfavTO87DC|yhl^S@MR4P^DWl)`-XWJwxU^@UOuMCGM2@n3N}Fu+tSHI09od3D7^ zn^HOx^4V|UeRRm+7u-GQ{m8_id#;|LL*9QpBfA1z{wWO&DIo2_vI!_{DeTMb)ddKp zBerUn+&W~t9n@@5#ScQwnPl=%>^!@TVyGmWTLb^Ijf03Jy9)x}Ct+Rw!BUIUb6HUB z>(UgzE}*dA@w9s|>Ks_F3>3(zxogTocEUe?|&rR*qb` zIJFHqEapnda5b%P(1*)#Q||vv>&uXoZj9{~p+A69<`#<$6b8TdV{11#EWEZEZngCM5MNgPXvBDX=Qamh+P7Smj!~lHQVC>WAJ4eo(jgF_E@<+*cm-j6E>;_LM1Yb3(=N}R zBl&D$dDsFrJ5pqLMZE_=1&z+QMZ7l%zn<=_PH}Y2@kN@Mn}=os%6Qc0K2D-im~|vf zYbwMV@0xusG9N5h*#V#mOjy=6FI?CEDiHex*mMYDVW2F`yGM`#3@qIio+8)<0Mjan z{=G~v3&Ryda)K+e_-hvOC%1Ywa|&4e9eUZKu)jP7j%lm)kM9pXrH1bt(h5s!yZCS9 z1WfgsN#&0EHJUegnw_46Ib#JI-k01ZQtWp3^Q#`lprs%Fe$<*M^wz&YUTE7crn=vyT=Icnc~Q$^b&s?J z&BCcejJL9zU31O2P8OS3+My1|dx!4He{lO<=a(MbW`zijv0bW=2bHF(t4Y{$X0Yv* z@0(FJeu#=ZWMuN>N`0O}-Zs`r=-IpMi1LV_p@LV(U{Z^Z!xAppNUhJG1Y-C8_Ki;t zNag1$G%|k2qIq7I3+(CSN``4&1$rZyU@EKp=5Q7mk)mNd5Z=8XBs2?F1h@VYDI198 ze4P)w(t&~7h?7J3;@@txD~wjgmMz$dE7PJ^S>DY@@&*ltjea$OjbT)p{8G){q0~Dh zMy2`D5g(qa#OAT`Qmp1!KT@(oH1=v8Pq%?<8Jp&x#RU+gvJ7i65zeLI?<1C$pN%PD z!HT)rvW-RvK7DfKFDOsRICyn%=80|xlTKvp9mJmg+ICV!O$_6ZCE~JwuMvy#{$7?c zLBYs}cy+KWQpDKrp7lC~fK1JXMAEvV#{Lu-KR`7)TkVecH*nV`U5pbg&NCi-?Q5Ts zM=!|R8*`tQeZ1FRfr>D_saz3tn=Cunv7HoUV8A71Zr&k=v3wp6ZX}a~;WFBApxUKw z|HEY>;ms6#Vgs%i@v8ySf`HrJ(l@yAFgDpX?>(v$>%WoU;9NrES%_Chz{U7R$Klb# zb*t0mP&xi*d|*xZ!)jeJ{jdN%Uja1=Ch?lVAyO`ZQu zpwWg8DcOrv{zmnjCt?T@(43O5@y;#n71W>#6V`LLiHv$f1e^{~m|Es`HtQf=&36OA zt_q-OG#qe){_(O_M`b=_(l%uVTH|+dd52wcr_13a-q*u(Q3MnFW#+AG8?z+^`8s^v z+U<4n)s+1RpiGZ-OaNU7EXJ$W*sCrsa%bj#Nb?b`7O5S5RWsm6A4*S2o~*c7eWbCA zf(mZ3qs+@6eJL8=zX09UF?ZByw)LZd$VhoD>}ZAk_uiI z9)DhB6E;-6;rdba+YjbA)~s7WTZeNyU^eJ}v+Cu`O{LC{Zq2(+&??pc=IpV z{LaNXBa14mxIQ>$!dntnMN;_zkC}+P?oJ9ObUBZZ+uu)lIHec9)_&Bqh|j(eg;$hg zn?O`Mqi3j-6$lN}vJHzBdjm)*GKx?($&3fmt7@<6LR|E45p{}IYSPVB<+bY1)9g+V z_BJdoO|JZX7_zJ_!kG`DT&eaPTq$b)7!Eak!JD7Vf} z#k}=TwW^Y%4_}JvKN3flA%AIQ*mxPItOo z{ow_&NM>!ihkM>5iDZA`J0NSFL^w~ofdKVv-XVYM5cuaY;#R`4%&X$sg>u;AiKLAv z{a3Fn932Puv3;HPc^y=O_5iLoRbL z;KxRTRgTXkhDfR0zBQxuzso3V&a{#KN8bKBor|J53anLXcM|W50x9kxi+wAIS5L|P zCtF?K=v0Dbj$71lV7`M3Pip2LwSmy|#mCK%{pZB3SmdbW0LE8?vH0utFWl&0)(Jw` zkniT=QbD~;^?*Bia=GbK*dvc*(_;p|Z@%d@+?=lr!+3we^}d}g8=;FomZC@7zsvm& zsp27;B^>e&gqkc8>NUxEWlKVl4PXIm_h$IMS6KjAf^8mQL1zEl!r`{cp_2u85>R;k zTTxZZVdwCDTLmIwAc0ox0Rig+TmS%N!54YepV~IebqQ)esjv;WC~yi}W!u05KP#;N zZBp2Vm3UCgAqSvh8@L&04LBP?(3+voz}BlUo2LQz`xtPmFt1lwRt{8a{#*b3vrr$j zrTqT@=U;q&2oknC%#{mh6lr%G>->5MqOBiB22NHfXL{kYGra%Qp-j4IC6e>w*KpU{s#nW;G~$G zFfwo+%En-KbQ%~o{^iMF1gwD@O2$>-4U0z>fSf#6;P{&IcICl{rKr++#3pb63oQ>B zO~y4fHO=D$+d7!==!j6X3Qu-2KH1XCE$U;CA9^Ho!M{7xJ2w*y11S8#2;dBa_AC}q z9{2%h6$zBaP*(wp5BMBP@&me&YHMl$bMy1_3nc>wWIO{ifU{4`u%zIg^Ws%Ts4xaO zf>}+DoCD5~S)WLTg^{@|N*)*mZHQhVQ{Cg_`{}s#x-_5SlIr^`y<`JwMks9r2t^{8 zyj2v^lh)Fv6-NGUp;$LWssPRj@uIaLi7plj5qE$$OeBJVLv2R?6fb99zI=I^+OpY4 zUh@SG-~rCq0gf7>ugL*N$N*!30tbrVBE-b^cH*5e0q$fR3bEh=oPLAjx&&?lhu^Ht z*9<|h8V#IfT!cpb`fF$?AS(a+_rEjn|EC#P=dX>%Yy*1qTMwVe-FfK$PksB}zWnbD h{O=6>e>nrAYKZ%-1C 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%0DHfVr@|C8VxDc@36G6Hh_XW4GNYv#<|SLw<9F- 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