From ae5b9da61c2d050a35ab8771d0547b00edb274f3 Mon Sep 17 00:00:00 2001 From: Umer Javed <57160083+u7javed@users.noreply.github.com> Date: Thu, 17 Nov 2022 16:47:15 -0700 Subject: [PATCH 1/2] Create 20221117-tf-composite-tensor-layering.md --- rfcs/20221117-tf-composite-tensor-layering.md | 448 ++++++++++++++++++ .../vision_diagram.png | Bin 0 -> 33884 bytes 2 files changed, 448 insertions(+) create mode 100644 rfcs/20221117-tf-composite-tensor-layering.md create mode 100644 rfcs/20221117-tf-composite-tensor-layering/vision_diagram.png diff --git a/rfcs/20221117-tf-composite-tensor-layering.md b/rfcs/20221117-tf-composite-tensor-layering.md new file mode 100644 index 000000000..5baf02dc4 --- /dev/null +++ b/rfcs/20221117-tf-composite-tensor-layering.md @@ -0,0 +1,448 @@ +# CompositeTensor Layering for tf.function + +| Status | Proposed | +:-------------- |:---------------------------------------------------- | +| **RFC #** | [NNN](https://github.com/tensorflow/community/pull/NNN) | +| **Author(s)** | Umer Javed (ujaved@google.com) | +| **Sponsor** | Faizan Muhammad (fmuham@google.com) | +| **Updated** | 2022-11-17 | + + + +## Objective + +This document proposes updates to the tf.function tracing API for layering CompositeTensor and removing dependencies on CompositeTensor for tf.function and its components. It is a part of the tf.function layering effort to reduce the complexity of tf.function and abstract various logic away from tf.function to simplify its mental model. + +Scope of this document + + + +* Updates to tf.function, TraceType, and FuncGraph to Support the layering efforts for CompositeTensors +* A fluid migration from current code to expected changes from proposed solution +* Basic implementation proposals with code snippets + + +## Motivation + + +### **Goals** + + + +* Move dependency on CompositeTensor away from tf.function, tracing\_compiler, and func\_graph +* Reduce the complexity of tf.function by simplifying its mental model and implementation + * Users should be able to design a custom Tensor API and be able to trace it with tf.function + * Inputs should be dealt as TraceTypes and not individual Tensors or Variables +* Move dependencies towards TraceTypes for tracing logic and abstract logic to said TraceTypes + * `_placeholder_value ` + * `_destruct_to_graph_io` + * `_construct_from_graph_io` + * `_cast` + + +### **Vision** + +The vision for this project is a simplified mental model of tf.function and how it handles tracing. Particularly, a function that is wrapped by tf.function should abstract away any dependency on CompositeTensor. Consider the following diagram for creating a ConcreteFunction from a tf.function wrapped function + + + + + +![](20221117-tf-composite-tensor-layering/vision_diagram.png "image_tooltip") + + +The ways in which things currently do not uphold this model: + + + +* Layering Violations: The tracing logic should only rely on the TraceType of composite tensors and input to generate placeholders and not the actual values +* Input Variance: The tracing logic should not need to deal with the inputs being different depending on the input. Instead, the input should be in the form of TraceType and logic should be abstracted to Tracetypes. +* **Placeholder Generation: **The placeholder value generation logic should be dealt with by the input (ideally a TraceType) itself and not within the tracing logic. + + +### **Problems** + + + +* ConcreteFunction, currently, takes in various types of Tensors, Variables, and TraceTypes and deals with them individually, making the logic very messy + * Various uses of `isinstance` to handle logic for different inputs differently + * Refer to [this code](https://github.com/tensorflow/tensorflow/blob/f6287e953b19cc1f0a2b8d20b87741a0df6b62eb/tensorflow/python/framework/func_graph.py#L1507) to see an example of the redundant use of `isinstance` within the tracing logic + * Encoding and decoding also requires checking for types +* CompositeTensors are broken down into their atomic parts using tf.nest, making the individual logic within the tracing function messy and redundant. + * Placeholders: Placeholders are not abstracted to their individual TraceTypes, resulting in the tracing logic having dependencies on CompositeTensors, TensorSpecs, VariableSpecs, etc. + * Operations used by tf.nest should ideally be handled by the TraceTypes and not the tracing logic + + +## Background + + +### **Uses of CompositeTensor, tf.nest, and TypeSpec within tf.function and its codebase** + + +#### **polymorphic\_function.py** + +Currently, when a CompositeTensor has a class method that is the instance of a polymorphic_function.Function and the CompositeTensor has a type_spec, the method type is returned when \_\_get__ is invoked for the polymorphic Function. Refer to [polymorphic\_function.py](https://github.com/tensorflow/tensorflow/blob/f6287e953b19cc1f0a2b8d20b87741a0df6b62eb/tensorflow/python/eager/polymorphic_function/polymorphic_function.py#L1250) on line 1250: + + +``` +if (isinstance(instance, composite_tensor.CompositeTensor) and + instance._type_spec is not None): + return types_lib.MethodType(self, instance) +``` + + +Note that this check also requires a `CompositeTensor`. To have a `type_spec` and there is currently a bug to fix the CompositeTensor classes that have no `type_spec` and remove that check for a typespec. + + +#### **func\_graph.py** + +Within [func\_graph.py](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/framework/func_graph.py), when converting a py\_func to a graph\_func, the `args` and `kwargs` are converted to placeholders and added to the func\_graph. When the func\_graph’s structured\_input\_signature is defined, the existing argument structures are converted to signatures (TraceTypes) on line 1203 where the arguments are encoded by + +def encode_arg(arg, path). When encoding the arguments to a signature, the argument is specifically checked if it an instance of a CompositeTensor on [line 112](https://github.com/tensorflow/tensorflow/blob/f6287e953b19cc1f0a2b8d20b87741a0df6b62eb/tensorflow/python/framework/func_graph.py#L112) + + +``` +if isinstance(arg, composite_tensor.CompositeTensor): + # TODO(b/133606651) Do we need to inject arg_name? + return arg._type_spec # pylint: disable=protected-access +``` + + +Note that the `type_spec` of the `CompositeTensor` is returned as the encoded argument, specifically to create the signature. + +There are also various helper functions for dealing with `CompositeTensors` within func\_graph.py such as + + + +* `def flatten(sequence)` on [line 1409](https://github.com/tensorflow/tensorflow/blob/f6287e953b19cc1f0a2b8d20b87741a0df6b62eb/tensorflow/python/framework/func_graph.py#L1409) +* `def pack_sequence_as(structure, flat_sequence)` on [line 1426](https://github.com/tensorflow/tensorflow/blob/f6287e953b19cc1f0a2b8d20b87741a0df6b62eb/tensorflow/python/framework/func_graph.py#L1426) + + +#### monomorphic\_function.py + +Within [monomorphic\_function.py](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/eager/polymorphic_function/monomorphic_function.py), there are various helper functions depending on `CompositeTensors` such as + + + +* `def _structured_signature_check_arg_type(self, arg, spec, name, signature_context)` on [line 1612](https://github.com/tensorflow/tensorflow/blob/8ce3b0a232928fb7fe0860d47fa475be6688054d/tensorflow/python/eager/polymorphic_function/monomorphic_function.py#L1612) +* `def _call_flat(self, args, captured_inputs, cancellation_manager=None)` on [line 1668](https://github.com/tensorflow/tensorflow/blob/8ce3b0a232928fb7fe0860d47fa475be6688054d/tensorflow/python/eager/polymorphic_function/monomorphic_function.py#L1668) +* `def output_shapes(self)` on [line 1960](https://github.com/tensorflow/tensorflow/blob/8ce3b0a232928fb7fe0860d47fa475be6688054d/tensorflow/python/eager/polymorphic_function/monomorphic_function.py#L1960) +* `def output_dtypes(self)` on [line 1969](https://github.com/tensorflow/tensorflow/blob/8ce3b0a232928fb7fe0860d47fa475be6688054d/tensorflow/python/eager/polymorphic_function/monomorphic_function.py#L1969) + + +#### function\_spec.py + +References of TypeSpecs such as `ResourceSpec` at + + + +* `def cast_numpy_inputs(inputs)` on [line 615](https://github.com/tensorflow/tensorflow/blob/8ce3b0a232928fb7fe0860d47fa475be6688054d/tensorflow/python/eager/polymorphic_function/function_spec.py#L615) + + +#### Helper files + +There exists a helper file to accommodate the use of `CompositeTensors` and its operations. Refer to [composite\_tensor\_utils.py](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/eager/polymorphic_function/composite_tensor_utils.py). + + +### **Placeholders** + +When creating a placeholder, if def func_graph_from_py_func is called with arg_names such as in tracing\_compiler.py, then the arg names are propagated down to the method where placeholders are created and if the argument passed does not contain a name of its own, then the name from arg\_names is assigned to placeholder for that argument. You may be asking why it is necessary to have a user-defined name for a placeholder. In tracing\_compiler.py on [line 203](https://github.com/tensorflow/tensorflow/blob/8ce3b0a232928fb7fe0860d47fa475be6688054d/tensorflow/python/eager/polymorphic_function/tracing_compiler.py#L203) when getting the garbage collected concrete function, it expects the placeholders to have a "_user_specified_name" which is created when a placeholder has a name. + +Another thing to note about placeholders is that for Variables and VariableSpecs, the placeholders are not returned but instead the argument itself. Instead, the Variable’s handle is captured to ensure that placeholders are not duplicated for the same Variable. + + +### **Current implementation** + +Currently, when a user-defined function is wrapped with tf.function, unless an input\_signature is specified, the inputs are passed in as Tensors or Variables. Specifically, when creating a monomorphic ConcreteFunction in TracingCompiler, the arguments to the tf.function and their respective names are passed to FuncGraph. + +When a CompositeTensor is passed to tf.function, during the ConcreteFunction creation, the CompositeTensor is broken down into its atomic components with `composite_tensor_utils.flatten_with_variables_or_variable_specs` before a placeholder is created for each atomic component. The atomic components are then combined and flattened before being assigned as the FuncGraph’s inputs. Refer to the following steps that occur + + + +1. Input arguments and argument names are passed to FuncGraph for generating a ConcreteFunction. +2. The arguments are broken down into their atomic components (Variables or Tensors) and placeholders are generated for each component using CompositeTensor helper libraries and tf.nest +3. Resources Tensors are added to the FuncGraph as resource\_tensor\_inputs +4. The arguments are converted to their signatures (TraceTypes) and flattened +5. Traced variables are captured by their handle to deal with placeholder duplication +6. The outputs are generated and converted to tensors and captured for outputs +7. The FuncGraph is returned + +As a result, it is clear that the majority of the logic that uses CompositeTensor inputs is for placeholder generation and with their TraceType. + + +## Proposed Solution + + +### **Move all dependencies on CompositeTensor for func\_graph away from and towards TraceType** + +Note that all CompositeTensors have a type_spec as their TraceType. Hence, all the logic within polymorphic_function.Function really only requires the TraceTypes of the inputs. + + +### **Abstracting Placeholder logic away from func\_graph** + +func\_graph.py currently relies on checking for specific TypeSpec subclasses independently via `isinstance` to create placeholder values which includes dependencies on Tensors, TypeSpec, CompositeTensors, etc. Instead, the creation of placeholders will be done by the member function of all TraceTypes `def _placeholder_value(self)` which is an abstracted implementation. Note that the CompositeTensor can be broken down into its atomic components with TraceTypes of TensorSpec and VariableSpec. + +However, there are cases where different TraceTypes are handled differently when creating a FuncGraph. VariableSpecs currently need to keep track of `alias_id` which is used to trace Variables and prevent duplicate placeholder creation for same Variables. FuncGraph, to avoid this duplication, captures the Variable’s handle. A solution to this issue is the introduction of a `PlaceholderContext` container class. Consider the following snippet of code, + + +``` +class PlaceholderContext(metaclass=abc.ABCMeta): + """Contains information for scoping placeholders in a FunctionType. + + `PlaceholderContext` is a container class for flags and mappings that contain information of mapped placeholders and their attributes. Different TraceTypes (__tf_tracing_type__) require different information for generating a placeholder. This context will be shared across all _placeholder_value calls when constructing a placeholder for a TraceType. + """ + pass +``` + + + +``` +class InternalPlaceholderContext(trace.PlaceholderContext): + """Container for mappings shared across all calls to _placeholder_value.""" + + def __init__(self): + self._alias_id_to_placeholder = {} + + def has_placeholder(self, alias_id: Hashable) -> bool: + if alias_id in self._alias_id_to_placeholder: + return True + return False + + def get_placeholder(self, alias_id: Hashable) -> Hashable: + if not self.has_alias_id(alias_id): + raise KeyError(f"key: {alias_id} not found in this instance of placeholder context.") + return self._alias_id_to_placeholder[alias_id] + + def add_placeholder(self, alias_id: Hashable, placeholder: Hashable) -> None: + if alias_id in self._alias_id_to_placeholder: + raise KeyError(f"alias id: {alias_id} is already stored in this instance of placeholder context.") + self._alias_id_to_placeholder[alias_id] = placeholder +``` + + +This `InternalPlaceholderContext` class contains a dictionary named `self._alias_id_to_placeholder` which keeps track of which Variable within the function has been traced and to reuse placeholders when the same `alias_id` is traced. This also means that Variables no longer need to be captured by their handle. + +With the implementation of `InternalPlaceholderContext`, an implementation of + +`def _placeholder_value(self)` for VariableSpec can now work. Consider the following implementation of `def _placeholder_value(self)` for VariableSpec, + + +``` +def _placeholder_value(self, placeholder_context): + if self.alias_id is None: + raise NotImplementedError(f"VariableSpec._placeholder_value doesn't " + f"support alias_id=None, got self: {self}.") + if not self.name and placeholder_context.has_name(): + self.name = placeholder_context.get_name() + # Reuse placeholder for variables traced multiple times + if placeholder_context.has_alias_id(self.alias_id): + return placeholder_context.get_placeholder(self.alias_id) + placeholder = graph_placeholder(self.dtype, self.shape, self.name) + if self.name: + placeholder.op._set_attr( + "_user_specified_name", + attr_value_pb2.AttrValue(s=compat.as_bytes(self.name))) + placeholder_context.add_placeholder_from_alias_id( + self.alias_id, placeholder) + return placeholder +``` + + +With the `PlaceholderContext`, we can also implement the `placeholder_value` implementation for TensorSpec. Consider the following implementation of `TensorSpec._placeholder_value(self)` + + +``` +def _placeholder_value(self, placeholder_context): + """Generates a graph_placholder with the given TensorSpec information.""" + requested_name = self.name + try: + placeholder = graph_placeholder( + self.dtype, self.shape, name=requested_name) + except ValueError as e: + # Sometimes parameter names are not valid op names, so fall back to + # unnamed placeholders. + logging.warning(e) + placeholder = graph_placeholder(self.dtype, self.shape) + if requested_name is not None: + # Record the requested/user-specified name in case it's different than + # the uniquified name, for validation when exporting signatures. + placeholder.op._set_attr( + "_user_specified_name", + attr_value_pb2.AttrValue(s=compat.as_bytes(requested_name))) + return placeholder +``` + + + + +Once each TraceType has an implementation of \_placeholder\_value, FuncGraph can call `TraceType._placeholder_value(self, placeholder_context)` to generate the graph placeholder value without any direct dependency to any Tensor type or any specific TraceType but only the generic TraceType. + +With the implementation of the Atomic TraceTypes of a CompositeTensor, we can implement a generic `def _placeholder_value(self) `for TypeSpec (TraceType of CompositeTensor) as such: + +``` +def _placeholder_value(self, placeholder_context): + component_placeholders = tf.nest.map_structure( + lambda x: x_placeholder_value(placeholder_context), + self._component_specs) + return self._from_components(component_placeholders) +``` + +This generic implementation works recursively by going through each of the TypeSpec’s components and getting the placeholders for that component. By doing so, a `CompositeTensor` can be traced and placeholders can be generated without knowing that it is a `CompositeTensor`. + +With the proposed changes, func\_graph.py can now be abstracted to only depend on TraceType. Now, since only the TraceType is dealt with and with the help of the `PlaceholderContext`, the function that creates placeholders can be reduced from + +``` +def _get_defun_input(arg, name): + """Maps a python function arg to a graph-construction input.""" + func_graph = ops.get_default_graph() + if isinstance(arg, (ops.Tensor, tensor_spec.TensorSpec)): + arg_is_spec = isinstance(arg, tensor_spec.TensorSpec) + if arg_is_spec and arg.name: + requested_name = arg.name + else: + requested_name = name + try: + placeholder = graph_placeholder( + arg.dtype, arg.shape, name=requested_name) + except ValueError as e: + # Sometimes parameter names are not valid op names, so fall back to + # unnamed placeholders. + logging.warning(e) + placeholder = graph_placeholder(arg.dtype, arg.shape) + if not arg_is_spec: + handle_data_util.copy_handle_data(arg, placeholder) + if name is not None: + # Record the requested/user-specified name in case it's different than + # the uniquified name, for validation when exporting signatures. + placeholder.op._set_attr( + "_user_specified_name", + attr_value_pb2.AttrValue(s=compat.as_bytes(requested_name))) + return placeholder + # TODO(b/246437883): Investigate how to remove this branch. + elif isinstance(arg, (resource_variable_ops.BaseResourceVariable, + resource_variable_ops.VariableSpec)): + if isinstance(arg, resource_variable_ops.VariableSpec): + name = arg.name or name + with func_graph.outer_graph.as_default(): + placeholder = graph_placeholder(dtypes.resource, [], name=name) + # TODO(b/246438937): Replace this with nest.pack_sequence_as after we + # can expand Variables. + arg = resource_variable_ops.ResourceVariable( + shape=arg.shape, + dtype=arg.dtype, + handle=placeholder, + trainable=arg.trainable) + + # Capture arg variables to create placeholders for them. These will be + # removed as captures after the function is traced (since otherwise we'd + # just add it back with a new placeholder when the variable was referenced). + placeholder = func_graph.capture(arg.handle, name=name) + placeholder.op._set_attr( + "_user_specified_name", + attr_value_pb2.AttrValue(s=compat.as_bytes(name))) + return arg + else: + return arg +``` +To the following, + +``` +def _get_defun_input(arg, placeholder_context): + """Maps a python function arg to a graph-construction input.""" + return arg._placeholder_value(placeholder_context) +``` +The last step to take into account is when Variables that are not inputs are traced within the function. Because the PlaceholderContext keeps track of the `alias_ids` that have been traced, we can use the PlaceholderContext to generate new placeholders if the tf.Variable was not created inside the current graph or, if the Variable was already traced, and return the placeholder value associated with that `alias_id`. + + +### **Deconstruct to graph io** + +The purpose of `_deconstruct_to_graph_io` is to break a complex/composite tensor into its atomic components. The composite\_tensor\_util library has a method called `composite_tensor_utils.flatten_with_variables_or_variable_specs` +that breaks a value into its atomic components + +``` +def _deconstruct_to_graph_io(self, value): + return composite_tensor_util.flatten_with_variables_or_variable_specs(value) +``` + + + +### **Construct from graph io** + +The purpose of `_construct_from_graph_io` is to pack flattened variables and tensors back to their original form such as a composite tensor or any other complex tensor. The idea here is to pass in an iterable with the flattened atomics and recursively obtain values from the iterable depending on the number of components a TypeSpec has +``` +def _construct_from_graph_io(self, iterator): + # base case is when the Spec is an atomic TraceType + if isinstance(self, TensorSpec) or isinstance(self, VariableSpec): + return iterator.next() + + components = tf.nest.map_structure( + lambda x: x._construct_from_graph_io(iterator), + self._component_specs) + + return self._from_components(components) +``` +Note, this function expects the Spec to have the correct number of atomics. + +### **Casting** + +A method in TraceType `_cast`, that takes a value and `casting_context`, and converts value to necessary tf.types. We employ rules on what's allowed and not allowed. + + + +* Cast numpy array to Tensors +* CompositeTensors recursively call \_cast on its components +* TraceType call `_cast` on its components +* `casting_context` may require some information + +The value passed will be converted to the TraceType that \_cast is being called from. For example, Calling cast from TensorSpec will return a value that is a Tensor. Furthermore, only TensorSpec will support casting from a numpy array. An example pseudocode implementation of `_cast` for TensorSpec with a numpy array + + +``` +def _cast(self, value, casting_context): + if value is numpy_array: + value = numpy_to_tensor(value) + else: + value = ops.convert_to_tensor(value) + + ... + + return value +``` + + +For more details on how the conversion occurs, refer to the existing casting code within FunctionType on [line 615](https://github.com/tensorflow/tensorflow/blob/259becca3d3a93f280d8ec920d4c3a1541f4df3c/tensorflow/python/eager/polymorphic_function/function_spec.py#L615) or [line 649](https://github.com/tensorflow/tensorflow/blob/259becca3d3a93f280d8ec920d4c3a1541f4df3c/tensorflow/python/eager/polymorphic_function/function_spec.py#L649) for non-numpy inputs. + + +## Future Possibilities + + +### **Push arg names assignment up the call stack and eventually remove them** + +With the layering of CompositeTensors and dependency only on TraceType, tf.function can assign naming to the inputs higher in the class stack and not in the FuncGraph tracing logic. This reduces complexity and opens a possibility to remove argument names more easily without breaking tracing logic. Note that currently + + + +* Arguments names are assigned at the placeholder level which makes it difficult to remove user-specified names +* Proposed solution moves argument name assignment to the tracing logic and away from placeholder logic via a transformation function +* TracingCompiler relies on user-specified argument names to create a ConcreteFunction proposal (refer to [line 203](https://github.com/tensorflow/tensorflow/blob/259becca3d3a93f280d8ec920d4c3a1541f4df3c/tensorflow/python/eager/polymorphic_function/tracing_compiler.py#L203)) + + +### **Introduction of new CompositeTensor APIs or custom tensor APIs** + +With the implementation of TraceType placeholders, creating graph IOs, and casting, the API opens up possibilities for introducing new types of Tensors or Variables without having to change the tf tracing logic. Particularly, if the TraceType is implemented, the tracing logic would use the TraceType to construct its placeholders within the Function Graph. With the proposed solution, implementing new Tensor types with tf.function will become much more streamlined both for Google, internally, and users. + + +### **TraceType uses by TracingCompiler** + +Once dependencies are removed from FuncGraph, TracingCompiler can be updated to deal with only TraceTypes instead of values directly. + + +# **Alternatives Considered** + + +* Create a utility library to handle all the logic discussed in the proposed solution. + * Making changes to placeholders will still not be trivial as type checking will still occur but within the library + * Making changes to CompositeTensors will not be trivial as instead of tf.function depending on it, the util library will +* For construct and deconstructing graph IOs, create a mapping function that iterate over values given a TraceType to construct and deconstruct values + * Would not work for new Tensor APIs that may be introduced that do not follow the mapping protocol and rules. + \ No newline at end of file diff --git a/rfcs/20221117-tf-composite-tensor-layering/vision_diagram.png b/rfcs/20221117-tf-composite-tensor-layering/vision_diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..6786388bc749e521d0279aeb8944b9b8df77de1d GIT binary patch literal 33884 zcmeFZcUV(h^DYcANqK zB8qg7jua^ZO8eHv=XrnUT-W>kcg}z3dVGZJ?7j9{vu4)J+;fjNvASw!D9%%mkdU0w zP*>3>A%PLW|Kx~M;L33M{2B0r)K_0knWU_jb&-Swfgq@w5ena_S z48V^-NpWj&QSghfn6R*ffTVBYiUg~A>MQB_1qDk5i=l98+Pc2}Mk-E5rjjnI7$ZZs09R90E~K(AQq&!?gF)&wAF*9`$QZf$+MET=2m4$UB&>qTay0+>_Qy(=WFEJd-%TG$!A471~an;ho zsXM5vI0cGHf{}nE{LOu&bc`h&)g>g|!ABn;YBbi)UrW*t?=0eh7B|+Al*CE8Yq&cE zn`oMOiK!|1`#3vlW3`ktgWcVIRGd6@R8>vf&^l78x&gv^%0P+G!KzragqpstkDr&9 zp$lGAOAU(())F$)MSBtO?mikOW*Uy-B08q7{wPh9kg=DRi;07no~EmVJ2Kcz6Q}L# zZsKoZs%H?Wt&1Zd#eMw@ZOxp`z*;oi{e_%FHO!3+2|~(&q7tfD7b#^Uf@6TNri!<5 zfV+tvK3EvzT27VT~?EH3P=>nI}Rk3qT_ zczKv=s-h&ceFF47og6fs)opccm3*D;g9Al;y)aH_U2QjGI};I6q`$L10gDnb_c91l z4z|@*5hI{{4gc<%xs$(+nkv%7*j?K-&{juO*ihHZ%}o=$%q!3Xqhq3~Z>ni;YvQ7h zS99}M*41$fa(4?hQ+8L2BDkoSdKek_m`S-2f(c4a_S(XZ zsz#m;-r|Pp!iL7;?!r2Fb#G0as-Zz(khd>*za7dIgE8_K(?>g-dDuz121%)^n;A(O zU?hdqbR@i;Z0%IU{oRlf8qRoqaJz}Vu?P+=>0yh9Hb7O}Sec+2tgjRVChKNquPOq5 z8e=^Je6Uiwl1QY7t*NiNhqt+>tFM=khlsnsk%PFBkW-+aw`q_A!3`SEQ3z!aplNSp zYNm$@HnR&d6H{}t4G{8l21k;z9w7)Tfpstn5DLJ!YI$h+IU0C);7o#pZ6#d99VJb@ z)E)dK^>yvV3_Ufx{mpP@qPpIC&{P7AMYP3zRNR4@puLoxRUGjm#?HdVx&eM-f!=!N zN|1UOf$s=HBEl#W5iw(DJ&dMlpoAT;!GK_GAB?1~KgPsVJy1&(8?56X?ik?WA?2^5 zg?DoFz-jpg8F=a9O@f?U-GdB$9lRx69E0rx3HBIKZ%HKH%NJwlr6lZya`zK=&{CID zF~A4;2B-vs*992bNn-2_+?BOF4eik01gBu6rZ5tN(X}`52@pjKDQnsKV}vwq^<312 zUA63-l(9wDS-w)0!=XTK7_qEpx4%QOJnYy}q>q$83sbTz0y@d!U5jCW}s7io~i@3Ig6dHIr zWmi#C$k{piJNTMPVZCwx7?6@ARt#MB@Nx38)%3HKa#9wy7Zo>>Fm?^bNtkL&7>oK5 zB=t;89l=dXdXQIv{y+x*uSYs|PtXv@?jLxoQa<$7BkNlxHF&Ri z_j`h1;we(Z+mzOu+&Rvhb02(tTUP6TxX*OlU2QqqYdIP@h&a4>R+ehvmGf9FvI9MJ;P&c>B7LA_=>$yp zN+b=F{gkjDbkzuaFvXGLLl9}ok$61MRxJZG<6v^?v$`*q&7}UF0M8XgJM~+!ANx6= z8A1~hBu#AH>dHyyjv<+vj6tN}psR&Kq;0S1PxY>_V?AM)exz z-&ce&5y{W-YDJO2*|8kp13m162Rrpi@R%MJrwt9=$*m|U`5WmN3oY?jAU2F(te;ru z1;>|&=fJ|XAN85}R3gAUGi1%qfE$ULH0-RFJpH3&Fd7iyhi9{)GCp0sdLW! z=X0_$m^9BhX)Rp_Fz3z`?qVXe6dqViG@t7IJw^6QV6H0g3|mN0Pa;Wfa_~?iwX_9* zv}U?8(jjTwxKDz%8HizKgVE5kv$Aqn#>Igll5M~cbo`bXKsDQa9-)KehLrXbF4P)7=LRL8}dhh>Gp*KNdG6W<_eSV}auT^O*t&uK>HiFJ%Tt zka26}l$?U@dJ5!UcFtw>1n~x#D=m#_Tr9K{7?8me#SVVqIw0j#J_}=LP3*2fa(Z-* zp$HXq@VXd0^Lc29DDql-c~;onNiiUG74&3+AU3;W5-D`N^(vaJTyY(U8G8mEr&Abq z(zfz{l_&WUv=6l6TGs?gtrHd7UeBiUWK{8L5$i?-{2ieKgZ6pyfY_2l}zq zaX&pHD^d_`lXdSM{#Xl>X`w}`^zm2igGF|KOrtqAjXWRliLd>>3|At!ogJ8loGCvU zw9r^cR@Ba(sj{$UCSr3>{(ai{-Zcf3rXFY-hzQ zV&rgtUg4g{pI5g7zM44=8DQjQSJ$WF+03I)ohk7gt6x2OVbwIeJ?!?Pax9m~j`e`a z%dKhM6L?kiQGUd@)ZEB}e|$XmEwz{Go427?CKJ|YyJd@biW6yezgl>ifm7}D{VtQ1 zKSq0d6Gv8kVs+Bem#<}Yvx9nrvduMLW#u$_j9S0cTVZ-Pi7eid5}3AeM_4_f-(zV7$M$p0;kn&jGOTkPqT zoRHNDnbq1iO9RjCZ=V;dB)b^cx;^5hAo1QSe3ON4@1y))&+scZr&MlCHQUi{yUhEL z-KqG1tq!Xq;X9|@01oYkg9hW6UlS2W2cPs2fogdLG`nr51x;JR4>bF${`~qe zKS0bq+MnO!ZXCPpj0UXfgy+OR$U z)YoFcTh4nkshH8+1cqysRPwv6L1%FeP5T?&y)xYS7&e|*4~ti>xEGBZw^ka~n*E1x z_lCZfTC6a(?8Y|jtu}mZ4hsocf5$i$Ul6c1-b>v$8Fkt}k@4mDa?NEX;Vv4RS->Ip|;ao~uROn}> zIXV_#PKP&m?crUf-Q#q-zg|R)%>-dT=l%&Se38f-w14hYFB381cenM!sb8Pe*rYyM ze-QUuGMv{-cG9&v6$E>R$!#{MSzd2rBC?3Pmq(wK?idf6zp%G)uVr~|qetYUTt!;|&;2)&|mKHCpef1 zjimj1O2*;zd3~$X%pt=^HQv)`iF=9M*y(P%LbsO@$)`vs$OjzZ8AVP&A#L)`IuX8Y=?@Dg zb>Xv1TxB|AUtH^uw=1LueW=C%#o)=!j3i-jy|uD4*2aYS0#B2RlW2FHvdKexV4NLBgtl98h^=7{SG5hOM1h>hSFYoakWni|3hp1KY%3N(@SF zohFa-nNGdBKAo_xD!DrW3~UK*753|k=f~_E`=ITCKRat{uA8@6Bzg}DE$e)q?h&8Q zB!TTyh)mDs<6Mb6aTcG|Di^#Z6c(BGY44kTQe8{xJzey}#%SaWa(ZzhT~@#9i!n0a zYofWg{GnV(^^dZh9;x|<)5y&9FZ`Up${JRO_13WCXP9GMhsg?Ol80A~%AB&j*|GeP z04jnrw8+v_xVY1sPb%!brdqBZ@vLe&Sn+x%!0~Bt_6%A4I-J*Dmsv96;D`0t=?agL z>N3ly?Q(cJvhbRY>;podU`W#f`VQ-&)g7f-mZ-V>d$>oN0}tDtJlI+M?4;&`2oii{ zYw6o`_~%DJpuk6&HQ7CIlB^tB4aN9a@NHssT9$zEhwdEx(n24V!tM=|lqDz2lMJgp z%6K9A4ioXmV6PJsUO9a)>3!`~9Lqz!t62-p@vJ`T<9iM>dbju~c*v5?b{3!IuFA3v zPrjfkK4<>XxW;qL(y_q2&o})VnaAN^`^#$m^J4Q{RN8%2G+U>BzC&nlvGATuFtCf4 zWehgC$|q?L*Pj$W+2(YUx)4chyvbpks7NoL{^?m0uPcR)vqC~RDg3GTpf=r$PL7VB zSSA&*7HPkwbEeH4&hme_unV$p3LXrOo_^vk7whTDQ1)TJsqqYR{)+;d%+8#CLFOQN z`e2g_LMu8H2KO(?ur@k=IKMY1(XvP>|3THh6OncgIT+T)G-Kf%bQ^9rM>JCb6 z${{vI>7hNwZhX=C(}N zEjBZsE^nMs+T?M}vHkp^+XG${xT0{lPSw8t^qv(msC_(i^8@xNPvvdJ57t(l+EV1+ zqrld)1N0tk=j{PAIDJ=@W0qvVMByUxnMB8l!o(h#wZ_jnYQH|eWVSwKiM>ggKG2c2 ze|6^f>0oi6#q#4Qh^f&f>k<^wQIXG_AuF~@->z7kzV8vpbB=FK!;vcC(Be`3d~U>e z5dM7<+uHVXpmBZeaxyxWA%5qo4L;{GT8CDQ{7BKD{1nl>`DER2g3sjlsoQ!Zp$-oj zq(7D~&drL$sw4`#CA;>IgpMaq|IX-!R6|;URp=t1x@OE!2VN;Yzr_(=jNKNK@zsmopji!I~wNf3)rs$+vr5Crh*rU03BIh|bF) z$V{%owU09len=DCj5aQwVUr(SY1f}CU9wwLUNJB*hz(;Frl{!Tdt{${4*kJ_Y|ywX z&yZ8d#Jn!?RpiM630oXB8*J0Kbwegv2`1n)6Be-#Y?$(eQ!pGlE>4uEJ|^MoI388$$Q(| ztyh2e&*jq@UH=%mGdsb76@V3)Kf0!Qno(fXMV)K6lR3ZA!qy^lxSEM*>k_vXPs5Z$ zFUL_%_czmNkk4f1ELVy?MHG{$`r%)M&aI{$Fve6l>S%blV1u3s{o;>y&2k*9;t#lv z88`<^zm(TB%RBZ|x=eb{T*o4L_@&D<#Y?_^KOnH>8_JzBwG-icb*cVPBwWo~3K9x> z?~n4cyy{*K@THlHU&xL1iGLLT!ay^tK7=S z*>^8!_Y&g=PJ6iPUbLp(7h_+81LTNE8VREzG`G(3U;IY5G(z%UeKb*fy(mf>7U`hk z$SsuKQ1%StVsn;6rc|RN$G;-5zuG(YK z1=VgmuaP5&9wW}`%=_gU_w2^sCOQ7uCQ0Vq; zT33a;m&p-_f;mx`z0g^rq0iHB!^QTmac5W_k|BM&bj!|H)SGzt-TusfJ+W0(EB6(n zPAlVd0{&;&r5b^&d!gIW1q~vkTTMzZP-qDG&a&H1zygj;mMWdfam#<-gOZrpYWmRi3CA8)am~ z`8h4JsO1R6J^|p+a(!DwxQ@Lrbt!{wPYXfTZWY6yXATb)h84dG&t0=9q`8W*;rJ!` z#-ZYe1Lulge?|NsN!Jrii61P{d9uXV9?p^0UuGA3t_{IozA)O`oJmhze?~$7+qKP6 zp(&^kUtw=V$L98zSp@q%Te)XSAU)eVx9eDASD{aP_+Xuvu=?uN4pD)*(NB`KF|_^ z*>mzq7!*Vy7|vL13;G5&=Y!n4+Q2z8P_b9K}3c8!dG%lrndTg#k&EpRya8s zw^@D3HT}P7Jg5FQ%CpBu?_CISp)H}jPXOOoH}`NZZa9WPSV0Pe+uYR0>D;CJ`EK_T zD{Eb09Vvv-r~v%up?XDSp(Zs5Q%c^N*QtfWn5KU-e>wq+rB!@E!DVb3L5rf8R`o(G zvq#c&yh+xHoF~qc!e+T6t%RAiPP_Hqy;Q+X_3}d0wKGyNZ7SS|b1L8#go$4EI-DW)c0#}I-&-bw zc2i`o5rIQVOCnjT*{GmAPtGY6{C<>!2oDXCqB*-gJ+(0#^fUTYRit7NBF|)YDpP`$ zb;X0}0<80L|`G=Lb)n-k9xI{@l`h(jt2ao3ji}3_WEz$MpmWl98ioi&Mc#YD z_E_<3cn8t!aso*(eUq#(EZ?c;0y{M`sa49|N7tNfX0X%((kS+Gq+7h_3R0wP;TbVW z2^`q#0P!mBR`3mwH~!DlrLyG5(%~Q>rcqDYr_(A`_1prIfBa6zPW@#l^96tmk(0_B z^U#QPms|w{nvXIOKW*R$2o(Uc;%9E4#v+r9u4)sa6qVq8#Zh?r(JVavbw@1;ESzSN zYcXCnIhxJKhN1HkSg0U|7WMf5P4)kzRPo<$a@U_cSj0qVer=OAKXa4gB6;+4#XKyG zi7l2kp+LdsMjT(hGRfGjZDxRcW(ek^*!3ag^BqetUf%GL-X|K^NgBl(iZ&yxQ`_s4 zQ;$U;!yG36`RIFRq@pOiuhhBL)e!8PeRl@{@opi0KGM8fZsw{=o@eoC>OCUy&NWU{ z-X#Evn!tU>AN+jOm2l%M_0?M>^+xBav5Yil&qA8~^B#$yx`IPA>wfZyD)oz`1U~bu z6eikh*64V}C-6We^eu_4$qo)tUTNh#cG!ZkQZ2=5B8{mKQXn!?0gS!Jaa!K+SZR|; z>glt!fzq~T+yzQ|j%E^-e#y3K04QzE<2OKQ3GU3yKxt`6lQ#^a`9um+1#7?6#;|m$?e!y}Pvo#e+R2lP@$Ua9EoY>sDxU#Z{A~9E z^^G(V!4CEHxQnb(F=$ma=%aav|`>>@R;5=sa7jn!vQpyyGsq1BA31z>=n8^?s${2Y zpyA(~=PXA)tUC?A1aNFgQWg?otDTfV(M0ciBHmMB`3WF_yCv2yu$KK+;=O z2(-;sV%>@VyofBL{V_lt#Bp8cwqbDvXf?zPccka6lc6S6+v}%&)8+u+7lQ+&&8|D+ zS`|H?@i!o0Pq)FcS7%tnzrDZB;sLH#1K_mS;MpBM#?OU%oNoP3Zi;!0kDitNsp$5( z;PxxG!Cq`{3zV0QPYHoDUJRscet4v@FyJ_c)oZSxhe}fo~^?{gMh6roO_OeS;$WAptdGC2~B*IBQBJwP9 z$Y-oSbFeNyv&^K2E7O4xLA0p#&c^Oo(0q0^eoFbr=VwX3mcDcYh{5nrYY^JBF|a}> zTl&kzz)4bomQTA+wi0_$>d}h&V6a22l(*DJxVMxX)F7rP-;KAQ>&X&#>|q*t>5_Wp zqU^U*luX!t8!js;fQ&y7vW*gR|JDcMRmZW006}jRfq2DVV3aTR)(eo;a-ky-fhs`P zr`oVl?HzYHJ-|f#XVXpU@g;&fQwuC!ji1b`-Ca^jX*HdxZ=41vi9pJqmLS@*ckVT2 zUIS&XOQg&Z_U(6G>E)yAM8d;7q*DXm-k=dDEMRvY7bvv`z!oyrXovm6FUP&bfLX$* zuSP{8X$6~i?c6>+jy+Av*D$zKuxu9_H&|k3Ki!_h{oq>w@hKsE!8r6}5)Bh5CHNwi z@$)|zC9h?+%I%C!Z|~_ml>EeH{kD|H1=p9SR1g+@u(y*mvX$i(1vF-zL11b!usdl8 z)v8X}c|dLH{f@qDd}5|Eb)_)>&aD-?O@L*X0pQP`SXmLn?~MsY&hmY2W*Qhh zr=mZ8rLbkEY0Yf<{q3=!W(_y#XS)E#e7X4f8MlW^3HK>*x-cPlX3mk5#lux4fThU8 zx9++Etd)->d!V4{_K&ZnZ>Y74BIT|#*3Uk-x%H6YCWmU&G^p6MVqg>oUrH?`?p|!Y z|8|yUwAzE^k*xyTySE=G#xx(QkLCD)Dr71jpC%0`M;G6L1_0K61gDQFXvzJw82Fojsr8 z%^vBQRR^znvcxcDlg0{4q++Dm85>K*FNO!68`w9g8@cTL%LTaOqup%s!pi^WYck)j zcqtoX+#`#la70Rx#pSrX1#nKdlk;0t_XP2#QPRd&MdqI>t%^&(e96nE!GGm(^Mz^d zOp^LnRru5*3s8wRw#&#k3v)S3R_tg7Y}%tEnPZXK|Ax^WfY5^C7UrOpx@3V?n`CS_ zU5C~$0WahQC;<-@&FN5%y$@a9#8cJWvkG?MCeQKvYPJnhhPsx|&(BK>==z=bV*J9& z1C*#t9B5z6HB~YCfjZc?g-`jVAv>#gOVf#|TI}jINWQW;U#kxxZU-6z*MI^RcbD*= zg!j9`bMS5C;x?@$0U4fHxADe0xjzf}+n^rU@ExNpwpLn|!mV@P0XV1P-TFG)ee#%3 zr9HgGzaN@RkAr~{TX%o(^Qj9HMdPBKKIW`6MnVRs+c~(eUO1`>lz;R^P|!(60n3G@ z)8pRl7mT0jUT_;IyekuC-*T|+JADYyN^cE@+_3Ge5qpWC4ToaumgY_apE19|Ahh3fxt%dK%>}`F{yG)@*T)8!1k$7{Ci;a2 zIjxqZpkBApEhzIMFHxR3nu4*$^-C95#`1rwsg=#;P<|-Tc_5vX4;+9;{009^Ip9pc zR^qgv(@^B=R?Bim*qS!Yk9fB5Z+>=x=}zGS_?ZtZ#1K zukO}?hXt5iE59IN;x09!*aE-@=L!58^{RI2p@h^dWfGWUwa=`k4A`WVwTPn-tBYc{ zTU+*L1$!63rKE@RFB}cBvUm&%BwvgQM*P;ACogePd2W@NSk0Xi*mk|FVn%5n6cXKc z#sVgU9k!b!+`rk7T_7YkZT8A+&k9BiZFzl^-AoJvDlbrh13qq*^5g$jLyN7)2q3Hv zmQ2RN9Ps_@$w`VF_4E$#0@e1E$3V@0zl@5AkDQ11Gn_SMGDd&CRx_Gnf_%kHgbJNa z!1z~(S4L_^`W~UiG&qsXAi$A>eDjAak@okA%=UlsI+=Prp<^DZl759sV24(5`Lc0J zY-&LQv#R^=C7NyTS%=p_J~>0+x~o%8P(joBdls3py)KjH?}vvqEe9Tjdoxk&A06Ms zow>en{}eG4PVuSK@>q~O^{SGRxyC=&sDD0G9HvD9xBjEiFI(ELi!W<9QE}xiR2pkA ze$WU!xpBZa9#owkzJ4Z0M8bYe0AY-9_3TYXQ`NT(3=iHb{?b@emL+T-cbWsLVbr{i zCX=zp>>Y`FjxNM?1;S=$)3}9t!hAm1u77{`wZ_ZZqB%6k%9s!dB$nQd(2l;trBS0! zskFmEZ4Yxn!d@-z1CQay9TVg78%*UOl??MfYnyC)dFZqJ;jX=jyIBZ~N?{)#AW+d5 z4vO+Vd#42J7cR+c^`TZiMjTd+U^9$>7jQV-_J%|H$%gZvW8_)dh$EEI4A!* z$11ke0T0!%e%EiT@m#?cdd7;uQcLVL`mVLT<}nV=I7_UhS?GV7&^>wEp2mSIIdooT zq5=x9aVMP;TmK;<&}UtBQ15a!zVYA`ksap!wY29xZz(heV3}|O*t&uvZ{|!81A#*Q z;c%f|{zFDR4jfmk!+lwz9t-h-gqJuDS@f0T3``0By~rZ#mm#V>B@bwJBON=nFU*CU zj4#^c*RKuw8+Ym?IkTE?jf{ghx=i-$8JHM|3f?Kuc@KiwzU$86%tX4PIw1e%@L-S8pQFh@3FI_ZJ;(F9bx*-WId2KxZwKd194;{v0bsxBm#lUV zSW!?Row{f9@3~r??BB+bAgY#~xeRU3`o_E_!Z2IWyzRAgujac9Bg>(kg7cBQ+x%1s znk|M6i!*d98Z(GGSFN^>duq=ul{`3J7g%pbYh0!~Ofx+n#{vQUx-C zktZ6d{*8QwC-idg7k(6SuDpCvYl+MHUIsRHebCxC*$3L$wO4~yt3B3iU2i%v^^GS% z>DE$d3D74#G7~orpD(_7YM`*?B`=y@*{8MzSR?UNpKZ_P&|Fomx%KH}5Xn=P-0(lo zAyP&`UwL9P$l>ZzLuQmBK#*&B*Z0dw5YQJd&d|`C4<_*$A(E8_8v?wX5Uvk8Y~wFD zg3PZ(CPVMt2=3fc1fOw9d2hDN2;>+N-<%exZH0`tl9_m{S~)zNpNWc(;Qb)Gs`0$O z^TT?a=vou9)-<^CA_QO*qlTg{K>YeSo3w;ZHB%~6?!jJYQ z8hjhNXUVmrJnu4nf25D(Ld0+-GjR4j^Sg6VZa9c{ORq~bHfEMNjq!~HC)RiCru8?c z2jS@)*sdzQM1cWO82#h)d)7MWFW~ssd3E~N8`X9dz^i$i9hk3e$$Wb#_?a8Qzec&4 z!p%v7IRXirJ(*Txr8B*>zwX0K1cs8>+O@zOKm^LxPkUD2orRv~&p+iIRX>44tA8}> z-Pe3M)`Grl`vXEds^;-1(xEYe?(bsnqisL}=CLyT%2RomFYrfcP5nU&NI-l~1MCzqZ{^(+2m=DE#57(ffzyC?2SdWySG(6kb20` z%}|SLrTUv zi6n+>Elg3$;b;^9d1iG@{%GG?fpPgy|EU>XQ|B0}Gd*FzteFcJ;%*I$= zt<7k*{Z{J?W!CNIE{qjpH7^| z6R91ogTbt5)U_l{`x*#~-@7yjYvWDE%nPQX>G94`YBu&*xlG#L5O>uurLCqw#K35T zzpJ31xn|TSfv+08nwl6|Pfy6MW-i>$aoxsA1mzgb1ig+r`6!RCyBcIDK|gk`U9TVL z1!#`>-t3q?LGJjD~;Af>v&wVhZp(ZJ6mY7H_dkB z?3C@7!N~`M|k5K)e=%w$Ud5!Sp3vy}&WaMid1>2an=>cvs$OH+WI*t@n3WrTTj% zrzr#KK`C&wBEO@mk$!KbCRZjl&$=ai^>Q*e+Z&S1vDVqj_`~1xBOpigOj0<6Ks3)) zRN>>7P>coGXPyPAR0A{DY5~{IG8dfe59IGl<5bwxFWmL(5pMqma$)yBwO_uzm}{Kt z&Hf=@QlCUISM4$K^$I4(UAm#Rx*)0^ggkwB+UgGFUiWm6!G06?obO2UuDe<9-4D44 zF|%qtdG|*PbXY>>vjaw}E}$m}hL+XbLh3tDxTRH9>SX~e^z4N6`PH{{7=m=#3KwO6 z6POso6O@u0=9Z@|{7)XS2f&@Q>IRagHypOEqG}DE={8Uof1oSWmDXRHd*J0ixM2F+ z#46}rQ2Uma6&sw{U9e@pl1H|fDkD+pf*JjQN&GjyPP?xqW~_$N2NQ=|+9wq}PXn>58#H>>$c@h|k8~_kwN;}BOi$OCq$L?yv%{`m1 zgtOx1sn`;QgDr!ARXkSVg9TetPh(Ed95ds1#?CZ2;j4j9C(|@Sm)#kl6*&*zpy_yO zQCD{GhV9S>)KiaU8;P#R0NtmjA|Y>4Ow)(5_eTYa9VCgkhv+&xHUT9t++CA!|X_rrNLdw7XYcJRIhTXZ_yG`$cKH zzNXjlgC|n@)eet6e5pP!{J#Bmqv#!3<_#-wrf#n0ON8(5n%`DhkxKh?H9rl?ReTnW z%iLxUjIRcQga~Bzax%XL3?O!3IY_N9y==yTVlx2)N{$fbJa>o3g)ipta5_n0+!kyU z&&rvz#VDm8x{w~u9WN?}PTfM%^n0JMNf-4+A)8j+esT&jCuyFTCrxS;BTM#A!$ODY zGKFCPv#6hD-wO=`byNzO?u2z9^VN-WxcF$C(5YXk-uLBREEDB-Cr{L<>1TbE{>9PY zvi7L0_wzH%&OW(gusjW-zckc$ACyOyw&y$fxTn1a3iSjWSd1qsZ?{?wc797`3!OeV3_Qkvd4KI-d3C>eja);Tx9F)2k9<%)Aqd30t9KpqoM@dSBJ?6^qK z)J#QRGv^9V%8m{2mc4YD9`3V0Sl%NHVK-#&@}9^)h~1#jt?Ix#~& zP_U)l?F8?#V4v0r**GgXN%Hx{o&fXAb4}^3#sFHJ#@--b18f&s!82J}H%< zF4v98#p&N56B+_ggN0kmeRN*i7tL*KrfH?ZLSFPT$dku-WK46;1@So$`q{BpiNgfG z9;V^qXHG~17NOj;Cz*+LWuN6uadSV0pXCI19o(n~xz%XJjaN9b!GaK5V82brc#RN7 zB8+{K2Lf!kD40z)PVt_;TP;Gm5|PFzR9Gn9$es+KdwOkd7vK{!1E7e)0yf+-Q0ME! zf^<-KAH=TSO!|vheY9%ziPjkkT=-fB!#oClIR*L7v5s1umXzMZxB|yz<9u{|_<^pb zo@3>1`41UYcg*;8CbH9{~gEUiFnBo(~>{Mp{}K@Ikzr_Yv$UrJ=x<{40K zY4@>Xc}WRBCg1=)1677Ev}N&%>EutugfFu+G!ntdoWo-vUaAvYWW;V_rFb6R1;A3I z30%Gtf=cRM#sVJVNq`>C^&S`vA?S%^E4wdwZ#;cmV;FQMoA>eePgyzd{L!ogs2CYtP6FM#q`{V2iJoVwFK%M)K*#t_;X^7 zW58pU5QIcS|NRPx1h^0o{wtuN@-FXlzu`Q#lU-trU|^onBVDWrP+Zs+#c0agWD3PO z25|E%Vr%hp`_k7^H-iH0=c78s1aA7<#zglEVQSH!TcoeFklZ9Z6hyls^LMDP@&UB9 z;k)7OD#s7^>&}d6cxXnM)p%a`MUu*EgBgtV4C2ka^b7Uhgjq}HG}LcihiR)s4l z23?Yi+8|kKoC4tR-Ubsg=^TWva=8Qaj|*d*iiF^2n8~gy05%FXFSo_do)_)7qH|w`nJLHr z1&F__Zst#Rf=NRKND}yWbwyRLe?j}(%pzA9oX-4c?6-XrH*{aj&3%7&{anF9e= zQu!9^^hmT#D6YK+v_Vmy6JBZEv95%UhO?LB0=a3gz==Nr59Li&(GcKzX9-fd1|5*abQmA zvlq5KFUQ4jsRBfR-3XqxepT@OXq~SI2r|D`dsxV9ba0O4g3^}H&^u6`dWF7y-V7Xu z*-G4RyrE(n;D%eYgg5at1bitnst*0_V^L3dzPAaIo0?Qz>CT}2;To@8-U5CG*riC% z->zz!U;y!_m%cE3g zjstGD0vO^5k?f+g$M8#U@{1Q_{P}mAElG$^=oD*;xNX~Bf3g3V&4FbA)rPc__MOq} z@hLP&61Xc=@7=QjT|@t`3jTkw3f>pZ8Q)j9fFMQz4Lv!oE_37iw};6`F4%XDe#Fu|NWJ zJ{PsIUtp*?vDfjdyIlEn|)G{)G9f=l(Qir1|lYvLc}CM8ntn-Bq5CeV{fAvLJJ`>$_)h~)X4?mc@2PZzYH>uSBaiu z{v#g#UyMwKehpfC0cbyHpK<9m1%fPu9bNz&$lF}d!MKm>px9?G588Abamo#Yy3veV z!oxz24t6}&ns%x|G3YJG@#YRA04%E7d{WT)P9vSSOh$tfVfSp!X+5(d@KyrY+p4bPkY$67dqU`xVHwudG0}fp{{E*Ibp}3j zW_hIM1?U`$ZHlDn1G)$+q$CHrm;|Kt$D#LDH_E0ng$sniNQ(-)Sg1*&+JD7-q}(vkhGUNyiQ)cOcR4RXLEn}QZldyFXJP{Mw=Gf1GlwHdaELDUG~3$ngWwQ=y}AEa zA5rhW;tEPbJ8UszB9~d0iPV`exF$#Bx*kQ-#`Of&uJ)9>DQY&eUFqA!)(2exRGXu$ z2Z~^JPvCk9Xwt!vZ}Pg!MjVDd5OKN#vWsr!J8~i0FUOlgEI`JYO7=35?~?G7L?LDh zSo#$(s>}CR6I914J;g{Gw7=T8scTV-fAk9kW`GWh10|tbp(zQBg4Mtm51*itwSg$# zXFv`Sgm7s9J;5{2Bae&C+o-^QB%);VUkDPfZUVQ}c||+Z25?hef-uGmiUq_OCp@(! zze(H_Vgv3r14Iz^JmOcbJHj-7GD-P7fq2nnjT@SbcYZzPVGWzUEnyCvtj_x+TFw4( zK!4q%YyATVS(SiQ!+#om>Zb7jFEzr6vY^fuUSRg8M2_Z|+l5Y4gw8fzjN(u;)adZa z`BPhLWct{T5Ci`TB936T;2sfM4vQsw`LL%TrD3a-X=~1_F`ePyMNx@7ky<>}a zpdzo#Qei%Cz%+7Vv2H%63IfWPr$C$9^Pc=Y1y*$45z;P>8gW@s@>^2;3C=#~cM)49Q>$N^52EbUdEfS20wOE~t;T4b%=IvK_7mlxL$Hj5p#NZ7yv(9TfIg1> z!8*O$zgz%-Z{^y3O+OEL2x>8O9>lc#M1w`t0v)`$Me_B@m83~<2GO#ezrxCz-7JKJ z^C|-gT*}-WhfB?CzVVQD+~UNqVP#`TSLUWy07Nf+goL0v>6v=VWXBUX-aD=yLm zE+oHCO?FH*d%O=fJT(V;3u~U`hD+0Eu-lUJn9YD3@fAo!E`OS}2XUu7%~o_|{PE77 z`@6GUT8goGGK2*itqlH~e$1J6&kO&9y8>8C zM=lQ>q(iUC*dEqa#R7NOqY=$avR|NA?l)mE`@Il5GWN-DJH%__H zNCbF%!XJNnmRvmk9oClwAF6~rrs}aTi-hMx5X>rg z|2m;T`Fz3t?FV+O6;RLFS+iy5jz^|Gmh&vcED@(+K!#fZ9Yz}-u12{ZY1CM4^VO27 z0q@%+Okfu3h_6#eo`n}F0tZc>H|V1^GYPrTMYyiy6r4rKCQ?T09!QC^(`6xMlZ2Pm zr9RO5AH!q@2YgK+xI6-^%ITxORV!pbTd!%Q+ay|k>&%~722ty>iMpNovT6tHpLX_H zj=ZKw3coHo_2TSESt3OisB6h>-v96 z_r3P;n@q$CMvl|!BE-w_(V$%92%v}tF}JThP@)RDYGPlxe10Fko?!h=iR^-*c!l6! z#MvEm9vdwPC)8cpnk2p8cjvjT07B#==q(@F1}$cF0~S7EnuvwONzm9em`$yGT1}Dr zhAgOASI8S=;_;GZpHBk@28;;0d0Y=bqi9XU;byM?J9?AaKR8Gd-QxLnl=XIHJnb=1 zAWV_WE zn6W=N^(8rr0OxEQc*bv_)aW#HY7BIbd2;85R)Q4j1M|Zn9kwp(!;O1iU%D8`%%&Mw zF7QvMhk)h|hzp9hkC^4Nu7Hk9`vQX3mvb^dTTiTj!>C$5>`!f&3G|>2H}yUs+*Cn@ zzFyF>IDdOU5~%u1&`;hy#@T=if%%n~^oiBSFJ&!$6C5*8yZ%L7;-Wah0YO;of9Ei8 z`8mR8p#Mt)dXIa)CyVY^=_M96P9fw=N=jlE_5au2cZYNR_I>mHeQlWum6biRW$(=F z(U&qqL`tZP#Ftb=_TI^sO=PCBqX-!Z*;$#HJ@1dY?(275_jTOIaUair&++t!qx2c) z`Tm^aJzlTZsje&`@r~#n;wr6SF297scjGe#Bro-ayu&@l>ZQL_Qs#Om1JMFro^`hIqwtpR_r2vv? z`KulCoyE@|8SkwsZr^=nvF*D%pYzvmNDFolD1V;!;1`m!7ZW(6Yu{p<7`+!KWLl4% z6n*^0y*?gE%xE)iBW(UBJI6(cU~$v?b`pSw%G@f1XNnr}8k6sShd#Xw zVFAejrW)TyfP|%RE+Kqys@|`i-*UcJycDcO(2$;MQ>I;XSm1+HLMr%^ks!vKqI@Lf z?%4e95nRdlg-Zpg0X-JTyu}6du{FhV#NNv_IqP$>hd;kwEVS;iHhJY{(^8H#jBdXz=Hm&erG00GPEh(2}zH-8Qx(%hJq!#ltiE|9Q9E} zhIseKT>$CSGTGj821ui^Yu71M>>`y=Wncgem2uYn6o>SZe5LH0jR#fUCt98|I1vw3 zIefg5W3SwjbicH-t&c$0f_%x>5x_Mh(`|$@0Pjp@83JkwEl1IiXi=TtT5sO9)6UQ1 zD0BP%nzA;^mFPQ86>G28^1RL);XJckb!KZsN|2!5P|37EPSAas%jTlfB?KQ+H}k6} zB!Pjf`?fZ)gq&`yh4eC~J5#MmeOIG=A&BarkOM#Y1$YF3=5zWtLlnXuyf#8|mZE_H zBG)&*@8!rJV-^N@dy(v_mDIrntrh}lqwcoDRLQu;XOY3UV!9Xc3r~UJJ=jt zioC#o%R=!$*Fr1sf!NiWP=(MJB|E?dx(?|N$=TRQwII70=Jd?T`x}`|OFt)~%o8=n zZrMHOrC-QSy5YKaIkPK-e9eEB+NwxWMbh%1sh7N?nvq5Aih2X*6W>QT=zP`mnO1e` z2;6g5-V#dBCc8NvOX^U*yHq*&O45lbJyIDmGb`un(*Qzu!*?8tzgD|=g&&HQ%7xj= zzoW?jM9yyH;A?fK&u7}%$iXyYbmT_ud%NxYyke!|gf5#U79-c-M46|WI3F#VihY)x zx&`}9gjFl=mW-;VFXx3-KE?G0bdcGM`-jnd4zn9(LZ~%^Ydw~Fy{-Cc40c`?n>m-9 z$}s-B%LXb1K3x#yHV+S-tvF`YP*# z_rGcx8pLg(7u0M{pPCq#&sCAsf-yU`n zh%<{3A`1vnaIOr;=Y!WvzNixE{^b31^y?>tOb>QT%}wncZa=GE5|8#-MM z3{mLEd2bxdjc^XTxiR#4(3q(&aUaE<2KYG9o~ybN6Au^|4G&T}-sTQCaFjQ?Uo*as zrc&nVNtRYhzYdW^=fg-WbGQj=m~|Jtvg%E4A)XOBqc0ac7lb)K0tRFArf`R?I?w6C zB|ODezN>K-y%v(5D5vGPPU8-ZZ=L1YJ}(@HrXyWrq`e^UxYNark<7WbeK9XitDT$O zl^b33T+s8(^y|W*DQn|OT%jjUZwNyQrsBoXU1qr|EGJK*pK&n1!N#6O4T}``ln#sM zyVZ!in6WV1jH1~2n87i!V7eC*K_K-!9UOg zrv(wSd1m^d<(W-CjrK_s0-B^7&(zqETP&^dZN(UutooRQ6L)o) zgIMYW|F~;J9O<%H9yPXrtY}#*{dt6q*n44^IycHE+9hL(nxQ?n>_SHyInQ)-C%h?` z+gqomLvosj)p&i3hg6{0A)BJ2%+J_MGqp$S$zG~LNE4b@?!pBE?DK~Kw>e4{4q`Ix z(kk?y{)iM+m6YTRx)3>FP_#Hc43)5~xQa)58CUBwqs_emd|CUU&n7Z}LVW$LrYM8H;z z_kUX7&2K#>J~|#EaX>tn%EUmQQ_=%q>zl}?g=}$9kgt{04XDG(U&<=?qAALsCnC)^ zk3E~8E~j|Aqq$qOeu_lZrwI1k#n z4OrxnzD!Sapp@?*wPZ($>5}I4ieB*?sZOKwr=;s_eX5~6{uMn5B_d->EygC;@1_6Z z#yATGJ~ir9yj`aw^W*$WA+sFY+|?J3&*t697`|th=zvhss4qc3e=We%?Zj=Gq36s#}o-=i>7>I|E{gPIboj9y0V3 z89IG=RoSUy#0A<9`2GByCsg#(T)R|KM<5?xE9J0z)ANgwy_Ws{;nvH>+hYBx9+O1k z4E^?frLN%fiM}vS{ivlsytsR9$1x4hJnp@umbNJ4pe_m#opp=|2QH6c?v>O_E!4SUPAN45CvCfE4EFe> z_sT%z!kWT}`q;Y*{J5T(n=+qdFcLMq{62O(4H zPivTK)M|!Ez65IA*2LCXOO0D(@CM4y_N1+BP0%bL<8-S$?cjQ=2+b$8u}Fj2Ge^AN z?p#@@v70M(0{-v&Kx6^grJ`Q?z)y0WjGRg9#Q;316Z@$5YKjVho=O{51FXK?+%^G| zZCiNxM$J3O`WVhc@JgQ^dL1+U{tL6-Mbs@Z)H<}r?moL`Zg+e)k1^N9q1TXRbM-z1 zl8b3HCD%{nGvHBw;>^`CH3=~KCoopT)^3ic6SEim$u*P-3d*;woznV6IYg3U#)WT; zRws*n?ARR_j>n+gKP7JUb>wCQvNC6yzAG+n*j;d;^%y2${b2Z7@GRj27K%X^m-tHd zQr-8@sx-`4or0NgQx-B7w*fvTc0a1PH^g{<7o3~2t)&snHTYo;QQbsU(qSv!&_!@;gm=-sK`3ZkOw z?lH`;V({g>dg}%q_Es#T+atdO={Pq~Gc19qm06Dpcj+}kGU)U&v(cbl`+3CS zrXC^oJQhNFN0pvt7QH)2WL^c(0YeEX0#lmD7b{VA-#Ig^(Hx4wg)Ehjm&m!e!FL)6 zX?j9#o+$W|4DCN}F&e2XPZK3Wq@NsDYO@U5cr2dtRO&|NT^Qj_*DA%N} z&QF6oU;7H7uEg(T01ir;^21mY0@s9^BlEfdiYL1WwW2XZl51y;Uh`09o`JWvn)zul zp%|$?2!*zub_=P8g=x9ErQ+qwF|STC$tjA<6%G-=N#hri0L44iXg;~Ezl&LuS z8GCxKp_HO6)B!(^ap7lf1A)t3>2XN*b1^97a_A34@xa&0qY{4-sGvgBcFF?@xWH}V z^|DO6kzL+_fH`OJw644%)Ou!QYUl`AT%FKdQ!X@*j)Fb$-MJ615hfi#fQ{a*ST3EC z+a7frD78`Z1`w8wkE#oW8dTNpH&@I5?k<2G;DWF(5D9Mq*WxlH++|X)dFE6>ZXVH+ zL;TrNKsd+UbR6R)?$0iKAQkFR;Tb`Q$A7>93b??)*V;YIW z6+-z$px6BrBEVj>L{B>*<>deOLOJ)`D~UVHko88`kU&|(O6bUMBm>V0VTk_J0PRHi z>E=S_@bjpArq6((HY_`DkQ8Z!FywN*{Az3g7hsTPI}k&Rn2SQ>$pb%ev@Ic^^(7)0 z6+Lm}_gCM1qVx006-3qRpXESdo1xszpG=PdHzSKu&%pyJlb5^ytxW#r?IXW(c3p{T zQQ2|FKi&ur5tpegK=#i;6loF{rcWOa=}mdM9IrFqslN5?`fmo^hx4g;W?UY? z{{KzW!(sivYAr}Z_&gbruhME6U+6Dbf}O#={X~N(d+Dghw@`%UV!w~jDC6>sZ!^+i zjoU}lu@C>aqqd69i^pPECz-PfbLPNOZzPXAAHvdlYl86sU@ZrU{T&G|kaTIb%8cAIjh(2_SbVL-~8{!6iJe ziBtxPvd6*kyS}%z1Rq`eJFM2XfdIjG8{c^L=HJ+p{dtD1UR#Uv%^v}__tf3_7UOAF z!R}t0WePzz@5>bgkB%fH$VF`g(S|^;{MbeX;_*_%Fe{s5W(`!j;j0i3{Ur82+|h#NF=J|ch{@}^{>?U&T-go zVvvV%;xxbhUHSd{yPHnOMKSz`roJT%A!7zM{4gvQn9Hb9pm9BpM0)1_hp!HG;yPwt z|AZu%zQ$*or1>wcLLn5yDOf1Dp`IBrY3BliwByK3IR9%i4gH6v{(m$5p2Z6P98LeP znMv}KHWG0lHG$j)cUZNWDIp%GUPRR7s=GIM;$czxQ=rFTr7(pueF6->TdbghEFL6e zNoWhQ!HYfL{1lhN_~K!*gr|WyZ7pgAfzEd1tCvEP6N--U@G*huPXt_pOZb2ll$0fO zHvIkK(1J4ilq6-VYA3qTC<;O~c+_c5FU6({NIi>^L^WN$%nHG=A$X*9k!J+39%J<& zo1kp{j2g{6P6YgZ8A@~?Y+94LaPOh8EgpqBHMCe%BdL-j666?s-v(38{d>2HiL5++ zvNGCE{QeJ$r(mE7iH{^G3#z8oRW-i0W+qcXYUuoFc$7=>93HL!?7CZOe4r58=8qU} z2LYY+JZ3~zdL>E_p++<={QNk_wsP>&(3ff1!iq%aUYxWK%)9lw|M`1 zx9T|jCMLo>!UO;GR{~bx2j9*M5PE3fym`Y^%1q*G`&tV+?*fl{bL$x`y6(5N{~(tB zW^Gue2vxuqh(-hsDisuY{&+jghj8x^{tYV%E!K*vFm*a})UCq*-mTR{oQIF(Clycp z>F)$0Zv2$Go_U-dmz3Q1tv}y>1fB>;HZ&uhZw<1bSp98n|Nn07e;-6|DgH5tD61jc zyp-rvRC?-0^=qUA0+Aqaqmqtvb0H5o0&1j;je$Zo@C+Jgz9Gxi6A89p#RASRhU^V*nO(0N*m_(5&T;JGnU626Ux<@udv9WS{lHp{%{eYx;qxUNm%$Tg@?uz>iqiS2t;6bG{fvVjhGHx2{cvP z7XBpOlptWQ|MV$WPy6QSkf= z{09V>X)Tb>bjBLNYchfzJkKNaKM>H+@k7$|016xmrr})#(8^2jf`&o(;5u}(3P_D3 z4L-GqixKnW8Ze#3fZvoTe)9$>5T_#rG(>e6aBGF54{E5HIDtfL30Qd;w0P$a0Xh-01f>h4)?~lhz8ZzgrL2daLHY*C zRA0VXZ&z^fMH$3rBfVJ{zNED>`PQYl_i7;UOwd&GaVN2|CG=3osb9Om1)zoYfFT8t zfO!x=(j4=0{eM)S`0VjF|LI@UCuUQaKo3a`H5Zd+!1_mef?3ZR^&eFyj_>dxB}b?m zS0akcK;n}?2!`tvKqN-PBfc823BA3!BPb1{@Cr)AzPkd{b3X&t<2ux?fTZsCc!f@8 zA2Kx8n;#Gj08kYXMZ68Zq@&wJ3k6poXgCqqcbGq+G?5$_C4wjqAUdZnvU`L8`2?W! z&Oo`yB5B?2J^r-e53-YEhbQ9!K30N4p?H!x%eN=O#iefQ-E|g_p9Xi>m&!ZA9>>} z*UU1${CX3Z?EE`tZfI-pLYyVMbZYTyqwi>T&pm2Q5W0G4MMTgF_b|dbq&ObTTja8N zh_GCcQ0_7B{^Hud=ub?|vLzThf`HZ!TCpIOA8{tm=nW3k-0U#WE1BUO}KF7WMNSN{*<6RmFW31?9}R$efq{8TW6KhL$XWx!M&U5y{z9s20X}r;X)NIA7$+ zAk6)YIpgUB%;Zx53o0gf!@5MnlI}|L^6ULt*@KO~AaxWGiT1y%Ph=3KW7_+9sg#up za2WtQ1^@&r=SO4=*8xgZ%Kw)kpG{2I{O8h4S)gtlkLEvdW^hRfr(Uzl!W#W-gW|Cy z80Z&g6Ou-S%3qzy34i`U*4)3tDd;(;VVJnJ+iCRk0;3t@63gTZYfAilS1&^9%hpLb z>5Gl6_WuK^=rVo7?mFeV!LvuNUS{Fb-qkRU1xK2gbM+laUVj(;l zdPqu7mD9@ETk}sL3UzKyZQk(k5dyo&3R>}Mq}Gvm4bm~=-Mv{$ zS_<~;x`2;@v@XHPBZ)ZTmKf3cW}}DWqTgEtQwq8y2+1$Nh<0m-)pV)Eb(nLfmK9okH-==P?4Kek!-?aHLS*KGL#gf#@78CD^ByLOj{(dZ_iv6*{(B z81)=Ohn<+#(FLVE#Fi~CtG5Tu?UT+qmq9`>kW-i(+sR+sg~&%=Q4LVwhne(qmX+HJ zvT_U;Drr=a8hOPPF zqb=$d`)@IF9`;sHGK#loIIc*hYewHZEH4RSl&iEKMU2tG{RIG6F#%osMJO`7R3?`d z4Nph~LewZ6Qh)%siXLV?_5Ae19Y7ZiDc}`swXudFB2P;omsn<~Bl#{An2|DZM`(_l z(BC682eN+FetRlisFNZ!0Qyhf<5+_0pg2+vs0)cqqt**@knO1g_{61IgWRU5XBf7J z$9X(=m7BVL%Zg_)2Fq@Jesl0_`*p2eo>-h$8aP2oGA!VhnC2UVuT=texjR zWMp?urUO7iN_w&6O){qBk1D?X=)5l?VvoQmw?H&v*wjA74!%j62nF!OuXW!3(kak* zo%lz`T$B);J-~Dcw(e2-$u+OhNFDvvs%z2r4L&D6 z&qGH91^H@9C@`-azzQ}nyq59g>23|eB8K-QnS^=O7u`F9T~}Nt-fmM)kCXm45PAGrz(Z zq|eRXCZ>lkH?sT+(4o>{&q*(NiizEb;?N#F@%TEc;9xuepw5~MKx1ITJ|Rh~0Af{_ zdYTY*eSm?AIG@j3)sW4a7;cl09K za|S9F?dB#|Px*+2Dg-`$W0524+o3lQcHWM&Q#nr-3t}r~HYZr;s=piageYVcI~i7- zO9GwHu?CP}839evmHXBXR?_bjq=^^jx1iv7gRgTz5OWjsTCy>Yi_0 z(BbpsbJ*+?PC@MnD~4;EnM?<52+$$9M>lIT3y$A%ye~+i|Lp7jjQH}KHcHn(y$fnz zOT1{#D`!~=s}8qGt=P9RXbxv&UXAm`efjQ|(J~vYhT(t9h{jC0WB{Fz;wUh9xl=`|civ zEd|d7^*uU3fL#t*?7X8L|7o*JZ3$6qIAxZ3W5_KsslG~AUZCkOW0HPkk>|;D5!cL{_L6Wf#Bu=J zKlu1^gwCvE%qLoBtscyo%y8EeJe4drb3kX{I#;ItN+z-&`Uq}rYd&p{?)wlH3UC<7 z6`Sm^@-1``AX0N0`aQ0$>%@}Luv1(t=8?*aALUaoz9Q@+{{H+a>>3WDPEdK{(tAP; z0TsKSZB~(S+T06X^9v^NX7k^7#aP~~y`!~s_desby}U&F8o;Vc(XUc@-^*TK@G51h zyfWka8jp5SJ*S6^fVPucr$evJtUR>1>ygn2+3}OnxDs&i$o8Vjm)_%KV*vFURb9O| zZOxM>uv;2md|s7hn$PHsmT8#q+VO0|w@QpLgBITJ>%*oh^>ejw+#f_v@SUCerCZUrE6erU7B6)i)b za7Sb))me9%wh=DEfh8lY&+Ql2d*ts9Jq>o8Bgm@r+!e1}bUnE>cy?w zuPl7yQo#1?=1k=wAg-JiLQIdXTq5eCA?vREddA@pw4O?nCv)knXZWV|Zy9<%%GRmlg;kzKCD%Znuxf4LW zHrvI;Bus^Ull`cTLn{$x(|opz*M6mqnL8qc-!;I`aSs!AfgaVA$YsiR;~W{F#Z~a( zuk2i#QCTc92271kgfHN=w@E>5@XH0`z3b5ihltKuNlG_U^sMfwZaAngV`yi6c2@LR z1?MV&`NW-f2U>=Kq*?RLF*-5zpt&bzhVk5O*+DgJCj6M-h}S$}8Nrwi>G&Q((!@sL zOCs|d#Nu|EZ*$}Ag_0w8^91G%S{-IGL)0d7eX*&B)|))C=bMW~m%UNu51O>Rht?mNG~4_r z&ars4n?}myxl=K#DsYot*AY?U7->tB^tfcl<=$f55LeXu-cF;lLwS9)MVbW!F9gyVW*2nW~|#1kUyguHpn2(jH)?6P6 zP(*Cw7gCx4!q=(a)3vRppNi-$)h^-ZGses=BZ9zO>*r)#rTN#{FzA;{HbN z#Wc-IZrAL$on~jXmPYT1b_l69c+Y)>MLAw5e~1%&a7Wb4SUY=owqT)v0pF(WUzP(A zPK^4XbR$2+Ojh>f`{~X+3=exYVN%B#2KNt&(&25=xy>KpWS%>|_{J4&MJWYRl{{}P zF2C*yIMmTox+F>G|;a5^{riI-h=9^_oHVk3w?CDdV-C2E*i1*L_AFz|R)t1Y_WX0}XS z(|yPM=8U(zp7Na^CyO8wnD!v1V~s%s(EE;)4KT8%&tMuW$|4ivKhvF2DK4` zhZDnSDy|%hYb*72Hoz4f3XI+wE+BkGl?R$ziee&_y0Tq##EJ#cab$iU+NC;(xa^6!`i zY*~W%W<`k!Jg;f4l4>iBDbVLgMe6T4w}vrUp0g1o@`?#wv@&8uP5(KntK+@6gG`E7 zhKp`P<~JU(G>K6)4W?nP;wyckgr8K?&AhUroQ<-Sh?qg>?(@^jd8i;wCUdAn7FAr* za~?^Y7*9`3C~iFT$`vXbM1W_Xf!gss-;xV$;dmh!i8XfFTzq(l;3PDlv=kC(2gV81 zE((7KehyDs?UfTRsEnnCOR6Z$g}&X=UL%Y)ERH5BwAb1DD~6%4c@{b0Yoz1HVtLOn zxUaM(Bj;-G6x9WR+1&bD-!pz2Y&@*Yvo*SU>Maz$5!mu_-HO3ws*PY5mponE!JJs+ zIJIGP`X!s)$8CQg6M>7rArl{XZ=*Z%Fl)PCfMZ+KkVSSOJWl_%!0j+d`bbtORyuFq zOc<_NC{~)U?C&C#ez=7~0_A#YIj`VMQ_7DA-~J zy`B&~k<<#lt2b^t`~$SeiAP=NQE5`E56(9;s7ZamHb(<&gjD<%4F-^vZ>k6k*i6qG zh&w`DM8BFX`hX{3QTLgF-E>6tK&kbaZyC|gY>eC~tj0%hz1s(_U8H3}|lM}2+cb! z+dVCN-u%nrmxLOo^{*Ufq}_VMmbwk-L44c`g*X6m9}Ak zIP0o%Q=Bep{Sw)LmP4MQ{ITSel<9$e6$SD6eqG!lqom837jb9$)81W4!bAr+r7+Yn zVSl0TnWA^89u=HYZhZ5cJb{Uh&V|PR?ze@R>S@=66_i(8f(z=3#X)L;$!yFuQli-b zHUsoN<%g6X=8bC&gvkjB5s(~i+uyG%grMTKRC3s_t)tF)WfknAd@Nss7+37TS6Q9=HgjO*0nxxXgYcVFEnu4 z>f!C9Yd#|wl-Ddtq0p4&C%0FTnW@ad$(dDN-ep8DdybkRUd8HJaxy7)5s!-iBR(ilDSz*$-i@(3 z`i(82SI4w&-YkY8`~htsyHv+&hdX23(L|q|>gs~uMv7HPM2SA+)5W~3k+{EKZB~2d zY}>J{&Du~-o#gP3AN8xSrWPHZ7<{k}X}BSye@l2YRua^=h)W2~8j5b*^In_M7y=%s zS)GT_V-Qymxd4=;vrnEpah>j2BZg}#cij`(b@(C;-8ca}B*mJ(# zeLgZ-`mPQ>KE9*8qN-X*NJ!iGczQChCGBzTZMy}xP+h#<(ik-ZvODZO)nGCstE*R4 zH^K&*oBiPsu>sM`Ki7IWVkai7uQ@x5J!!0}I%lcGN`^k-K8L?UHkrGCsRT?t4$JlyaGyo3|(L3)m;b$A_1e3YCB9EHbav>I=T}YfXt6 zA9p6^tLgL8i+AroCd1}~X^q(P=Z^t|RM?vsb|*}O?=Swn?Ugv-NwufSdQ%PA>uvAw z#&xdEePs1q9mk4_inf8egqEZi1m0rrI+7>}Rs1}sZ)Q7?{ty>G|4_jg_XO5BsPJpL zdDyN-3n))dw?}c7LDpjk3Pn3L*ZMg6%V>cL>2+mME!&&brE-WS7;AJ|G$dtiiG@1YX zeN_li>1FyXfzVaBUfNx)7VRld2N)Eigw=l&cavgIOG=tXq^L zzo;tQBXl*!NeM3PrAv}&9I zKbJ1tvmWhSM1x$a^AwpLqoa&(s0g_%8ew*BctKxFkV^I}7)uO6)0Oq$8`MXu(peXezniohM|rVr@F}K{eEdVpZMGwM4C*`8Z-aX0RA8 z`x8CNTs8$8!fm{xXT1Q6SGk^kygdK9eueHX#e%h z7NP&@**LTvovP5R_K#*<2NMnF-XcXY66uj`anV2Uhp&N#6V zKbir?c%pz9qlp#nVq_1{L#*Zps}DgmpOQ*?B=m2T_UP&=Xz=HbTc=Tsge8O<%tQ~6 z(Sqh_IwSbuE#)~BkAh_U-cetgRKaSYCtI1vGyHUBGBQ}G6At-eG-tl<%ae_gcahvD jU-eG!UBLn&qoc98blptvQ3eSP{LxU+IbWn?<^O*GMIu)r literal 0 HcmV?d00001 From f98187727cead1f5383224cb5c09b4d7eca72150 Mon Sep 17 00:00:00 2001 From: Umer Javed <57160083+u7javed@users.noreply.github.com> Date: Thu, 17 Nov 2022 16:54:18 -0700 Subject: [PATCH 2/2] Update RFC number in markdown file. --- rfcs/20221117-tf-composite-tensor-layering.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rfcs/20221117-tf-composite-tensor-layering.md b/rfcs/20221117-tf-composite-tensor-layering.md index 5baf02dc4..8145cce04 100644 --- a/rfcs/20221117-tf-composite-tensor-layering.md +++ b/rfcs/20221117-tf-composite-tensor-layering.md @@ -2,7 +2,7 @@ | Status | Proposed | :-------------- |:---------------------------------------------------- | -| **RFC #** | [NNN](https://github.com/tensorflow/community/pull/NNN) | +| **RFC #** | [437](https://github.com/tensorflow/community/pull/437) | | **Author(s)** | Umer Javed (ujaved@google.com) | | **Sponsor** | Faizan Muhammad (fmuham@google.com) | | **Updated** | 2022-11-17 |