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^DYcANq~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*>mz q7!*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`6 lQ#^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?A1aNFg QW g?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%pb Yh0!~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!#`>-t3 q?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_eTY a9VCgkhv+&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>eePgy zd{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^b7 Uhgjq}HG}LcihiR)s4l z23?Yi+8|kKoC4tR-Ubsg=^TWva=8Qaj|*d*iiF^2n8~gy05%FX FSo_do)_)7qH|w`nJLHr z1&F__Zst#Rf=NRKND}yWbwyRLe?j}(%pzA9oX-4c?6-XrH*{aj&3%7&{an F9e= zQu!9^^hmT#D6YK+v_Vmy6 JBZEv95%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@Kyr Y+p4bPkY$67dqU`x VHwudG0}fp{{E*Ibp}3j zW_hIM1?U`$ZHlDn1G)$+q$CHrm;|Kt$D#LDH_E0ng$sniNQ(-)Sg1*&+JD7-q}( vkhGUNyiQ)cOcR4RXLEn}Q ZldyFXJP{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=#~c M)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%!XJNnmRvmk9oCl wAF6~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>-v9
6 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 zA WV_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;wr6 SF297scjGe#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!rJ V-^N@dy(v_ mDIrntrh}lqwcoDRLQu;X OY3UV!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(wSd1 m^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$q Oeu_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=|2Q H6c?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)&snHT Yo;QQbsU(qSv!&_!@;gm=-sK`3ZkOw z?lH`;V({g>dg}%q_Es#T+atdO={Pq~Gc19qm06Dpcj+}kGU)U&v(cbl`+3C S zrXC^oJQhNFN0pvt7QH)2WL^c(0YeEX0#lmD7b{VA-#Ig^(Hx4wg)Ehjm&m!e!FL)6 zX?j9#o+$W|4DCN}F&e2XPZK3Wq@NsDYO@U5cr2 dtRO&|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+Ub R6R)?$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=}m dM9IrFqslN5?`fmo^hx4g;W?UY? z{{KzW!(sivYAr}Z_&gbruhME6U+6Dbf}O#={X~N(d+Dghw@`%UV!w~jDC6>sZ!^+i zjo U}lu@C>aqqd69i^pPEC z-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|WyZ7pgAfz Ed1tCvEP6N--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#RASRh U^V*nO(0N*m_(5&T;JGnU626Ux<@ udv9WS{lHp{%{eYx;qxUNm%$Tg@?uz>iqiS2t;6bG{fvVjhGHx2{cvP z7XBpOlp tWQ|MV$WPy6QSkf= z{09V>X)Tb>bjBLNYchfzJkKNaKM>H+@k7$|016xmrr})#(8^2jf`&o(;5u}(3P_D3 z4L-GqixKnW8Ze#3fZvoTe)9$>5T_#rG(>e6aBGF54{E5 HIDtfL30Qd;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{8TW6Kh L$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+l aUVj(;l zdPqu7mD9@ETk}sL3UzKyZ Qk(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 zv T_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!VhnC2 UVuT=texjR zWMp?urUO7iN_w&6O){qBk1D?X=)5l?VvoQmw?H&v*wjA74!%j62nF!OuXW!3(kak* zo%lz`T$B);J-~Dcw(e2-$u+O
hNFDvvs%z2r4L&D6 z&qGH91^H@9C@`-azzQ}nyq59g>23|eB8K-QnS^=O7u`F9T~}Nt-fmM)kCXm45P AGrz(Z zq|eRXCZ>lkH?sT+(4o>{&q*(NiizEb;?N#F@%TEc;9xuepw5~MKx1ITJ|Rh~0Af{_ zdYTY*eSm?AIG@j 3)sW4a7;cl09K za|S9F?dB#|Px*+2Dg-`$W0524+o3lQcHWM&Q#nr-3t}r~HYZr;s=piageYVcI~i7- zO9GwHu?CP}839evmHXBX R?_bjq=^^jx1iv7gRgTz5OWjsTCy>Yi_0 z(BbpsbJ*+?PC@MnD~4;EnM?<52+$$9M>lIT3y$A%ye~+i|Lp7jjQH}KHcHn(y$fnz zOT1{#D`!~=s}8 qGt=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^>ej w+#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;lL wS9)MVbW!F9gyVW*2nW~|#1kUygu Hpn2( 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_7D A-~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}_V Mmbwk-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*0nxxXgYcVFE nu4 z>f!C9Yd#|wl-Ddtq0p4&C%0FTnW@ad$(dDN-e9(~_E)7^#%O+}GD9!}?hRfAVy+ zC(U-<6-v6 p8DdybkRUd8HJaxy7)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>j 2BZg}#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*!NeM3PrA v}&9I zKbJ1tvmWhSM1x$a ^AwpLqoa&(s0g_%8ew*BctKxFkV^I}7)u O6)0Oq$8`MXu(peXezniohM|rVr@F}K{eEdVpZMGwM4C*`8Z-aX0RA8 z`x8CNTs8$8!fm{xXT1Q6SGk^k ygdK9eueHX#e%h z7NP&@**LTvovP5R_K#*<2NMnF-XcXY66uj`anV2Uhp&N#6 V 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 |