From b35bef74e475a3735d105d440bd0f5f6f2382c42 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Joaqu=C3=ADn=20M=2E=20L=C3=B3pez=20Mu=C3=B1oz?=
+Fernando Cacciola, Darren Cook, Beman Dawes, Jeremy Maitin-Shepard and Daryle
+Walker from the Boost mailing list provided useful suggestions for improvement
+on the first alpha releases of the library. Gang Wang discovered several
+bugs in the code. Thomas Wenisch brought out the idea of "sequence sets"
+from which sequenced indices were designed. Giovanni Bajo, Chris Little and
+Maxim Yegorushkin tested the library on several platforms. Rosa
+Bernárdez proofread the last version of the tutorial.
+
+Pavel Voženílek has been immensely helpful in thoroughly reviewing
+every single bit of the library, and he also suggested several extra
+functionalities, most notably range querying, safe mode, polymorphic key
+extractors and MPL support. Thank you!
+
+The Boost acceptance review took place between March 20th and 30th 2004.
+Pavel Voženílek was the review manager. Thanks to all the people
+who participated and specially to those who submitted reviews:
+Fredrik Blomqvist, Tom Brinkman, Paul A Bristow, Darren Cook, Jeff Garland,
+David B. Held, Brian McNamara, Gary Powell, Rob Stewart, Arkadiy Vertleyb,
+Jörg Walter. Other Boost members also contributed ideas, particularly
+in connection with the library's naming scheme: Pavol Droba,
+Dave Gomboc, Jeremy Maitin-Shepard, Thorsten Ottosen, Matthew Vogt,
+Daryle Walker. My apologies if I inadvertently left somebody out of this
+list.
+
+Boost.MultiIndex could not have been written without Aleksey Gurtovoy
+et al. superb Boost MPL
+Library. Also, Aleksey's techniques for dealing with ETI-related
+problems in MSVC++ 6.0 helped solve some internal issues of the library.
+
+The internal implementation of red-black trees is based on that of SGI STL
+stl_tree.h file:
+
+ Revised May 7th 2004 Copyright © 2003-2004 Joaquín M López Muñoz.
+Use, modification, and distribution are subject to the Boost Software
+License, Version 1.0. (See accompanying file
+LICENSE_1_0.txt or copy at
+www.boost.org/LICENSE_1_0.txt)
+
+In relational databases, composite keys depend on two or more fields of a given table.
+The analogous concept in Boost.MultiIndex is modeled by means of
+
+
+
+Composite keys are sorted by lexicographical order, i.e. sorting is performed
+by the first key, then the second key if the first one is equal, etc. This
+order allows for partial searches where only the first keys are specified:
+
+On the other hand, partial searches without specifying the first keys are not
+allowed.
+
+By default, the corresponding
+See Example 7 in the examples section
+for an application of
+The
+This possibility is fully exploited by predefined key extractors provided
+by Boost.MultiIndex, making it simpler to define
+Note that this is specified in exactly the same manner as a
+In fact, support for pointers is further extended to accept what we call
+chained pointers. Such a chained pointer is defined by induction as a raw or
+smart pointer or iterator to the actual element, to a reference wrapper of the
+element or to another chained pointer; that is, chained pointers are arbitrary
+compositions of pointer-like types ultimately dereferencing
+to the element from where the key is to be extracted. Examples of chained
+pointers to
+
+
+
+
Boost.MultiIndex Acknowledgements
+
+
+
+
+Copyright (c) 1996,1997
+Silicon Graphics Computer Systems, Inc.
+
+
+
+Permission to use, copy, modify, distribute and sell this software
+and its documentation for any purpose is hereby granted without fee,
+provided that the above copyright notice appear in all copies and
+that both that copyright notice and this permission notice appear
+in supporting documentation. Silicon Graphics makes no
+representations about the suitability of this software for any
+purpose. It is provided "as is" without express or implied warranty.
+
+
+Copyright (c) 1994
+Hewlett-Packard Company
+
+Permission to use, copy, modify, distribute and sell this software
+and its documentation for any purpose is hereby granted without fee,
+provided that the above copyright notice appear in all copies and
+that both that copyright notice and this permission notice appear
+in supporting documentation. Hewlett-Packard Company makes no
+representations about the suitability of this software for any
+purpose. It is provided "as is" without express or implied warranty.
+
+I would like to dedicate this piece of work to Rosa Bernárdez, my very first
+C++ teacher, for her unconditional support in many endeavors of which programming is
+by no means the most important. In memory of my cat López (2001-2003): he
+lived too fast, died too young.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Boost.MultiIndex Advanced topics
+
+
+
+Contents
+
+
+
+
+ctor_args_listmulti_index_container
+
+ multi_index_container
+
+
+ Composite keys
+
+composite_key, as shown in the example:
+
+
+
+struct phonebook_entry
+{
+ std::string family_name;
+ std::string given_name;
+ std::string phone_number;
+
+ phonebook_entry(
+ std::string family_name,
+ std::string given_name,
+ std::string phone_number):
+ family_name(family_name),given_name(given_name),phone_number(phone_number)
+ {}
+};
+
+// define a multi_index_container with a composite key on
+// (family_name,given_name)
+typedef multi_index_container<
+ phonebook_entry,
+ indexed_by<
+ //non-unique as some subscribers might have more than one number
+ ordered_non_unique<
+ composite_key<
+ phonebook_entry,
+ member<phonebook_entry,std::string,&phonebook_entry::family_name>,
+ member<phonebook_entry,std::string,&phonebook_entry::given_name>
+ >
+ >,
+ ordered_unique< // unique as numbers belong to only one subscriber
+ member<phonebook_entry,std::string,&phonebook_entry::phone_number>
+ >
+ >
+> phonebook;
+
composite_key accepts two or more key extractors on the same
+value (here, phonebook_entry). Lookup operations on a composite
+key are accomplished by passing tuples with the values searched:
+
+
+
+phonebook pb;
+...
+// search for Dorothea White's number
+phonebook::iterator it=pb.find(
+ boost::make_tuple(std::string("White"),std::string("Dorothea")));
+std::string number=it->phone_number;
+
+
+
+phonebook pb;
+...
+// look for all Whites
+std::pair<phonebook::iterator,phonebook::iterator> p=
+ pb.equal_range(boost::make_tuple(std::string("White")));
+
std::less predicate is used
+for each subkey of a composite key. Alternate comparison predicates can
+be specified with
+composite_key_compare:
+
+
+
+// phonebook with given names in reverse order
+
+typedef multi_index_container<
+ phonebook_entry,
+ indexed_by<
+ ordered_non_unique<
+ composite_key<
+ phonebook_entry,
+ member<phonebook_entry,std::string,&phonebook_entry::family_name>,
+ member<phonebook_entry,std::string,&phonebook_entry::given_name>
+ >,
+ composite_key_compare<
+ std::less<std::string>, // family names sorted as by default
+ std::greater<std::string> // given names reversed
+ >
+ >,
+ ordered_unique<
+ member<phonebook_entry,std::string,&phonebook_entry::phone_number>
+ >
+ >
+> phonebook;
+
composite_key.
+Advanced features of Boost.MultiIndex key
+extractors
+
+Key Extractor
+concept allows the same object to extract keys from several different types,
+possibly through suitably defined overloads of operator():
+
+
+
+// example of a name extractor from employee and employee *
+struct name_extractor
+{
+ const std::string& operator()(const employee& e)const{return e.name;}
+ std::string& operator()(employee& e)const{return e.name;}
+ std::string& operator()(employee* e)const{return e->name;}
+};
+
multi_index_containers
+where elements are pointers or references to the actual objects. The following
+specifies a multi_index_container of pointers to employees sorted by their
+names.
+
+
+
+typedef multi_index_container<
+ employee *,
+ indexed_by<
+ ordered_non_unique<member<employee,std::string,&employee::name> > >
+> employee_set;
+
multi_index_container
+of actual employee objects: member takes care of the
+extra dereferencing needed to gain access to employee::name. A similar
+functionality is provided for interoperability with reference wrappers from
+Boost.Ref:
+
+
+
+typedef multi_index_container<
+ boost::reference_wrapper<const employee>,
+ indexed_by<
+ ordered_non_unique<member<employee,std::string,&employee::name> > >
+> employee_set;
+
employee are:
+
+
+In general, chained pointers with dereferencing distance greater than 1 are not
+likely to be used in a normal program, but they can arise in frameworks
+which construct "views" as employee *,const employee *,std::auto_ptr<employee>,std::list<boost::reference_wrapper<employee> >::iterator,employee **,boost::shared_ptr<const employee *>.multi_index_containers from preexisting
+multi_index_containers.
+
+In order to present a short summary of the different usages of Boost.MultiIndex +key extractors in the presence of reference wrappers and pointers, consider the +following final type: +
+ ++ ++struct T +{ + int i; + const int j; + int f()const; + int g(); +}; +
+The table below lists the appropriate key extractors to be used for
+different pointer and reference wrapper types based on T, for
+each of its members.
+
+
| element type | +sorted by | +key extractor | +applicable toconst elements? |
+ read/write? | +
|---|---|---|---|---|
T |
+ i |
+ member<T,int,&T::i> |
+ yes | +yes | +
j |
+ member<T,const int,&T::j> |
+ yes | +no | +|
f() |
+ const_mem_fun<T,int,&T::f> |
+ yes | +no | +|
g() |
+ mem_fun<T,int,&T::g> |
+ no | +no | +|
reference_wrapper<T> |
+ i |
+ member<T,int,&T::i> |
+ yes | +yes | +
j |
+ member<T,const int,&T::j> |
+ yes | +no | +|
f() |
+ const_mem_fun<T,int,&T::f> |
+ yes | +no | +|
g() |
+ mem_fun<T,int,&T::g> |
+ yes | +no | +|
reference_wrapper<const T> |
+ i |
+ member<T,const int,&T::i> |
+ yes | +no | +
j |
+ member<T,const int,&T::j> |
+ yes | +no | +|
f() |
+ const_mem_fun<T,int,&T::f> |
+ yes | +no | +|
g() |
+ + | |||
chained pointer to T+ or to reference_wrapper<T> |
+ i |
+ member<T,int,&T::i> |
+ yes | +yes | +
j |
+ member<T,const int,&T::j> |
+ yes | +no | +|
f() |
+ const_mem_fun<T,int,&T::f> |
+ yes | +no | +|
g() |
+ mem_fun<T,int,&T::g> |
+ yes | +no | +|
chained pointer to const T+ or to reference_wrapper<const T> |
+ i |
+ member<T,const int,&T::i> |
+ yes | +no | +
j |
+ member<T,const int,&T::j> |
+ yes | +no | +|
f() |
+ const_mem_fun<T,int,&T::f> |
+ yes | +no | +|
g() |
+ + | |||
+The column "applicable to const elements?" states whether the
+corresponding key extractor can be used when passed constant elements (this
+relates to the elements specified in the first column, not the referenced
+T objects). The only negative case is for T::g when
+the elements are raw T objects, which make sense as we are dealing
+with a non-constant member function: this also implies that multi_index_containers
+of elements of T cannot be sorted by T::g, because
+elements contained within a multi_index_container are treated as constant.
+
+A key extractor is called read/write if it returns a non-constant reference
+to the key when passed a non-constant element, and it is called read-only
+otherwise. In order to use multi_index_container::modify_key, the associated
+key extractor must be read/write. The column "read/write?" shows that most
+combinations yield read-only extractors.
+
+Some care has to be taken to preserve const-correctness in the
+specification of the key extractors: in some sense, the const
+qualifier is carried along to the member part, even if that particular
+member is not defined as const. For instance, if the elements
+are of type const T *, sorting by T::i is not
+specified as member<const T,int,&T::i>, but rather as
+member<T,const int,&T::i>.
+
+For practical demonstrations of use of these key extractors, refer to +example 2 and +example 6 in the examples section. +
+ +member_offset
+The member key extractor poses some problems in compilers
+that do not properly support pointers to members as non-type
+template arguments. The following compilers have been confirmed not
+to work correctly with member:
+
member_offset
+has been provided that does the work of member at the
+expense of less convenient notation and the possibility of
+non-conformance with the standard. Please consult
+the reference for further information on member_offset.
++ +
+The following test program can help determine if your compiler +properly supports pointers to members as non-type template parameters: +
+ ++ ++#include <boost/multi_index_container/member.hpp> +#include <utility> +#include <iostream> + +using namespace std; +using boost::multi_index::member; + +typedef std::pair<int,int> pair_of_ints; + +int main() +{ + pair_of_ints p(0,1); + int i=member<pair_of_ints,int,&pair_of_ints::first>()(p); + int j=member<pair_of_ints,int,&pair_of_ints::second>()(p); + if(i!=0||j!=1){ + cout<<"WARNING: compiler does not properly support\n" + "pointers as non-type template parameters"<<endl; + return 1; + } + + cout<<"test succesful"<<endl; + return 0; +} + +
+If you find a compiler not listed here that does not pass the test, +please report to the maintainer of the library. As an example of use, +given the class
+ ++ ++class A +{ + int x; +} +
+the instantiation member<A,int,&A::x> can be simulated then
+as member_offset<A,int,offsetof(A,x)>.
+
+For those writing portable code, Boost.MultiIndex provides the ternary macro
+BOOST_MULTI_INDEX_MEMBER. Continuing with the example above, the
+expression
+
+ ++BOOST_MULTI_INDEX_MEMBER(A,int,x) +
+expands to either +
+ ++ ++member<A,int,&A::x> +
+or alternatively to +
+ ++ ++member_offset<A,int,offsetof(A,x)> +
+depending on whether the current compiler supports pointer to members as
+non-type template arguments or not. The alternative expansion is driven by
+the defect macro BOOST_NO_POINTER_TO_MEMBER_TEMPLATE_PARAMETERS,
+which has been proposed for inclusion in the
+Boost Configuration Library.
+Until the defect macro is accepted, Boost.MultiIndex treats it as if defined for
+
BOOST_MULTI_INDEX_MEMBER by manually defining
+BOOST_NO_POINTER_TO_MEMBER_TEMPLATE_PARAMETERS prior to the
+inclusion of Boost.MultiIndex headers.
+
+
+const_mem_fun_explicit and
+mem_fun_explicit
+MSVC++ 6.0 has problems with const member functions as non-type
+template parameters, and thus does not accept the const_mem_fun
+key extractor. A simple workaround, fortunately, has been found, consisting
+in specifying the type of these pointers as an additional template
+parameter. The alternative const_mem_fun_explicit extractor
+adopts this solution; for instance, given the type
+
+ ++struct A +{ + int f()const; +}; +
+the extractor const_mem_fun<A,int,&A::f> can be replaced by
+const_mem_fun_explicit<A,int,int (A::*)()const,&A::f>. A similar
+mem_fun_explicit class template is provided for non-constant
+member functions.
+
+If you are writing cross-platform code, the selection of either key extractor
+is transparently handled by the macro BOOST_MULTI_INDEX_CONST_MEM_FUN,
+so that
+
+ ++BOOST_MULTI_INDEX_CONST_MEM_FUN(A,int,f) +
+expands by default to +
+ ++ ++const_mem_fun<A,int,&A::f> +
+but resolves to +
+ ++ ++const_mem_fun_explicit<A,int,int (A::*)()const,&A::f> +
+in MSVC++ 6.0. An analogous macro BOOST_MULTI_INDEX_MEM_FUN is
+provided as well.
+
composite_key in compilers
+without partial template specialization
+Much of the power of composite_key derives from the ability
+to perform searches when only the first elements of the compound key are
+given. In order to enable this functionality, std::less and
+std::greater are specialized for
+
+composite_key_result instantiations to provide
+overloads accepting tuples of values.
+
+In those compilers that do not support partial template specialization,
+tuple-based comparisons are not available by default. In this case,
+multi_index_container instantiations using composite keys
+will work as expected (elements are sorted lexicographically on the
+results of the combined keys), except that lookup operations will not
+accept tuples as an argument. The most obvious workaround
+to this deficiency involves explicitly specifying the comparison
+predicate with composite_key_compare: this is tedious as
+the comparison predicates for all the element key extractors must be
+explicitly typed. For this reason, Boost.MultiIndex provides the replacement
+class template
+
+composite_key_result_less, that
+acts as the missing specialization of std::less for
+composite_key_results:
+
+ ++typedef composite_key< + phonebook_entry, + member<phonebook_entry,std::string,&phonebook_entry::family_name>, + member<phonebook_entry,std::string,&phonebook_entry::given_name> +> ckey_t; + +typedef multi_index_container< + phonebook_entry, + indexed_by< + ordered_non_unique< + ckey_t, + // composite_key_result_less plays the role of + // std::less<ckey_t::result_type> + composite_key_result_less<ckey_t::result_type> + >, + ordered_unique< + member<phonebook_entry,std::string,&phonebook_entry::phone_number> + > + > +> phonebook; +
+There is also an analogous
+
+composite_key_result_greater class to substitute for
+specializations of std::greater.
+
ctor_args_list
+Although in most cases multi_index_containers will be default constructed
+(or copied from a preexisting multi_index_container), sometimes it is
+necessary to specify particular values for the internal objects used (key extractors,
+comparison predicates, allocator), for instance if some of these objects do not have
+a default constructor. The same situation can arise with standard STL containers,
+which allow for the optional specification of such objects:
+
+ ++// example of non-default constructed std::set +template<typename IntegralType> +struct modulo_less +{ + modulo_less(IntegralType m):modulo(m){} + + bool operator()(IntegralType x,IntegralType y)const + { + return (x%modulo)<(y%modulo); + } + +private: + IntegralType modulo; +}; + +typedef std::set<unsigned int,modulo_less<unsigned int> > modulo_set; + +modulo_set m(modulo_less<unsigned int>(10)); +
+multi_index_container does also provide this functionality, though in a
+considerably more complex fashion, due to the fact that the constructor
+of a multi_index_container has to accept values for all the internal
+objects of its indices. The full form of multi_index_container constructor
+is
+
+ ++explicit multi_index_container( + const ctor_args_list& args_list=ctor_args_list(), + const allocator_type& al=allocator_type()); +
+The specification of the allocator object poses no particular problems;
+as for the ctor_args_list, this object is designed so as to hold
+the necessary construction values for every index in the multi_index_container.
+From the point of view of the user, ctor_args_list is equivalent
+to the type
+
+ ++boost::tuple<C0,...,CI-1> +
+where I is the number of indices, and Ci is
+
+ ++nth_index<i>::type::ctor_args +
+that is, the nested type ctor_args of the i-th index. Each
+ctor_args type is in turn a tuple holding values for constructor
+arguments of the associated index: so, ordered indices demand a key extractor object
+and a comparison predicate, while sequenced indices do not need any construction
+argument. For instance, given the definition
+
+ ++typedef multi_index_container< + unsigned int, + indexed_by< + ordered_unique<identity<unsigned int> >, + ordered_non_unique<identity<unsigned int>, modulo_less<unsigned int> >, + sequenced<> + > +> modulo_indexed_set; +
+the corresponding ctor_args_list type is equivalent to
+
+ ++boost::tuple< + // ctr_args of index #0 + boost::tuple<identity<unsigned int>,std::less<unsigned int> >, + + // ctr_args of index #1 + boost::tuple<identity<unsigned int>,modulo_less<unsigned int> >, + + // sequenced indices do not have any construction argument + boost::tuple<> +> +
+Such a modulo_indexed_set cannot be default constructed, because
+modulo_less does not provide a default constructor. The following shows
+how the construction can be done:
+
+ ++modulo_indexed_set::ctor_args_list args_list= + boost::make_tuple( + // ctor_args for index #0 is default constructible + modulo_indexed_set::nth_index<0>::type::ctor_args(), + + boost::make_tuple(identity<unsigned int>(),modulo_less<unsigned int>(10)), + + // this is also default constructible (actually, an empty tuple) + modulo_indexed_set::nth_index<2>::type::ctor_args(), + ); + +modulo_indexed_set m(args_list); +
+A program is provided in the examples section that +puts in practise these concepts. +
+ +
+The concept of Design by Contract, originally developed as part
+of Bertrand Meyer's Eiffel language,
+revolves around the formulation of a contract between the user
+of a library and the implementor, by which the first is required to
+respect some preconditions on the values passed when invoking
+methods of the library, and the implementor guarantees in return
+that certain constraints on the results are met (postconditions),
+as well as the honoring of specified internal consistency rules, called
+invariants. Eiffel natively supports the three parts of the
+contract just described by means of constructs require,
+ensure and invariant, respectively.
+
+C++ does not enjoy direct support for Design by Contract techniques: these +are customarily implemented as assertion code, often turned off in +release mode for performance reasons. Following this approach, +Boost.MultiIndex provides two distinct debugging modes: +
+The idea of adding precondition checking facilities to STL as a debugging aid +was first introduced by Cay S. Horstmann in his +Safe STL library and later +adopted by STLport Debug +Mode. Similarly, Boost.MultiIndex features the so-called safe mode +in which all sorts of preconditions are checked when dealing with iterators +and functions of the library. +
+ +
+Boost.MultiIndex safe mode is set by globally defining the macro
+BOOST_MULTI_INDEX_ENABLE_SAFE_MODE. Error conditions
+are checked via the macro BOOST_MULTI_INDEX_SAFE_MODE_ASSERT, which
+by default resolves to a call to
+BOOST_ASSERT.
+
+If the user decides to define her own version of
+BOOST_MULTI_INDEX_SAFE_MODE_ASSERT, it has to take the form
+
+ ++BOOST_MULTI_INDEX_SAFE_MODE_ASSERT(expr,error_code) +
+where expr is the condition checked and error_code
+is one value of the safe_mode::error_code enumeration:
+
+ ++namespace boost{ + +namespace multi_index{ + +namespace safe_mode{ + +enum error_code +{ + invalid_iterator, // default initialized iterator + not_dereferenceable_iterator, // iterator is not dereferenceable + not_incrementable_iterator, // iterator points to end of sequence + not_decrementable_iterator, // iterator points to beginning of sequence + not_owner, // iterator does not belong to the container + not_same_owner, // iterators belong to different containers + invalid_range, // last not reachable from first + inside_range, // iterator lies within a range (and it mustn't) + same_container // containers ought to be different +}; + +} // namespace multi_index::safe_mode + +} // namespace multi_index + +} // namespace boost +
+For instance, the following replacement of
+BOOST_MULTI_INDEX_SAFE_MODE_ASSERT throws an exception instead of
+asserting:
+
+ ++#include <boost/multi_index_container/safe_mode_errors.hpp> + +struct safe_mode_exception +{ + safe_mode_exception(boost::multi_index::safe_mode::error_code error_code): + error_code(error_code) + {} + + boost::multi_index::safe_mode::error_code error_code; +}; + +#define BOOST_MULTI_INDEX_SAFE_MODE_ASSERT(expr,error_code) \ +if(!(expr)){throw safe_mode_exception(error_code);} + +// This has to go before the inclusion of any header from Boost.MultiIndex, +// except possibly safe_error_codes.hpp. +
+Other possibilites, like outputting to a log or firing some kind of alert, are +also implementable. +
+ +
+Warning: Safe mode adds a very important overhead to the program
+both in terms of space and time used, so in general it should not be set for
+NDEBUG builds. Also, this mode is intended solely as a debugging aid,
+and programs must not rely on it as part of their normal execution flow: in
+particular, no guarantee is made that all possible precondition errors are diagnosed,
+or that the checks remain stable across different versions of the library.
+
+The so called invariant-checking mode of Boost.MultiIndex can be
+set by globally defining the macro
+BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING.
+When this mode is in effect, all public functions of Boost.MultiIndex
+will perform post-execution tests aimed at ensuring that the basic
+internal invariants of the data structures managed are preserved.
+
+If an invariant test fails, Boost.MultiIndex will indicate the failure
+by means of the unary macro BOOST_MULTI_INDEX_INVARIANT_ASSERT.
+Unless the user provides a definition for this macro, it defaults to
+
+BOOST_ASSERT. Any assertion of this kind should
+be regarded in principle as a bug in the library. Please report such
+problems, along with as much contextual information as possible, to the
+maintainer of the library.
+
+It is recommended that users of Boost.MultiIndex always set the +invariant-checking mode in debug builds. +
+ +multi_index_container
+Academic movitations aside, there is a practical interest in simulating standard
+associative containers by means of multi_index_container, namely to take
+advantage of extended functionalities provided by multi_index_container for
+lookup, range querying and updating.
+
+In order to simulate a std::set one can follow the substitution
+rule:
+
+ ++std::set<Key,Compare,Allocator> -> + multi_index_container< + Key, + indexed_by<ordered_unique<identity<Key>,Compare> >, + Allocator + > +
+In the default case where Compare=std::less<Key> and
+Allocator=std::allocator<Key>, the substitution rule is
+simplified as
+
+ ++std::set<Key> -> multi_index_container<Key> +
+The substitution of multi_index_container for std::set keeps
+the whole set of functionality provided by std::set, so in
+principle it is a drop-in replacement needing no further adjustments.
+
+std::multiset can be simulated in a similar manner, according to the
+following rule:
+
+ ++std::multiset<Key,Compare,Allocator> -> + multi_index_container< + Key, + indexed_by<ordered_non_unique<identity<Key>,Compare> >, + Allocator + > +
+When default values are taken into consideration, the rule takes the form +
+ ++ ++std::multiset<Key> -> + multi_index_container< + Key, + indexed_by<ordered_non_unique<identity<Key> > > + > +
+The simulation of std::multisets with multi_index_container
+results in a slight difference with respect to the interface offered: the member
+function insert(const value_type&) does not return an
+iterator as in std::multisets, but rather a
+std::pair<iterator,bool> in the spirit of std::sets.
+In this particular case, however, the bool member of the returned
+pair is always true.
+
+The case of std::maps and std::multimaps does not lend
+itself to such a direct simulation by means of multi_index_container. The main
+problem lies in the fact that elements of a multi_index_container are treated
+as constant, while the std::map and std::multimap handle
+objects of type std::pair<const Key,T>, thus allowing for free
+modification of the value part. To overcome this difficulty we need to create an ad
+hoc pair class:
+
+ ++template <typename T1,typename T2> +struct mutable_pair +{ + typedef T1 first_type; + typedef T2 second_type; + + mutable_pair():first(T1()),second(T2()){} + mutable_pair(const T1& f,const T2& s):first(f),second(s){} + mutable_pair(const std::pair<T1,T2>& p):first(p.first),second(p.second){} + + T1 first; + mutable T2 second; +}; +
+and so the substitution rules are: +
+ ++ ++std::map<Key,T,Compare,Allocator> -> + multi_index_container< + Element, + indexed_by< + ordered_unique<member<Element,Key,&Element::first>,Compare> + >, + typename Allocator::template rebind<Element>::other + > + +std::multimap<Key,T,Compare,Allocator> -> + multi_index_container< + Element, + indexed_by< + ordered_non_unique<member<Element,Key,&Element::first>,Compare> + >, + typename Allocator::template rebind<Element>::other + > + +(with Element=mutable_pair<Key,T>) +
+If default values are considered, the rules take the form: +
+ ++ ++std::map<Key,T> -> + multi_index_container< + Element, + indexed_by<ordered_unique<member<Element,Key,&Element::first> > > + > + +std::multimap<Key,T> -> + multi_index_container< + Element, + indexed_by<ordered_non_unique<member<Element,Key,&Element::first> > > + > + +(with Element=mutable_pair<Key,T>) +
+Unlike as with standard sets, the interface of these multi_index_container-simulated
+maps does not exactly conform to that of std::maps and
+std::multimaps. The most obvious difference is the lack of
+operator [], either in read or write mode; this, however, can be
+simulated with appropriate use of find and insert.
+
+These simulations of standard associative containers with multi_index_container
+are comparable to the original constructs in terms of space and time efficiency.
+See the performance section for further details.
+
std::list
+Unlike the case of associative containers, simulating std::list
+in Boost.MultiIndex does not add any significant functionality, so the following
+is presented merely for completeness sake.
+
+Much as with standard maps, the main difficulty to overcome when simulating
+std::list derives from the constant nature of elements of an
+multi_index_container. Again, some sort of adaption class is needed, like
+for instance the following:
+
+ ++template <typename T> +struct mutable_value +{ + mutable_value(const T& t):t(t){} + operator T&()const{return t;} + +private: + mutable T t; +}; +
+which allows us to use the substitution rule: +
+ ++ ++std::list<T,Allocator> -> + multi_index_container< + Element, + indexed_by<sequenced<> >, + typename Allocator::template rebind<Element>::other + > + +(with Element=mutable_value<T>) +
+or, if the default value Allocator=std::allocator<T> is used:
+
+ ++std::list<T> -> + multi_index_container<mutable_value<T>,indexed_by<sequenced<> > > +
multi_index_container
+Boost.MultiIndex provides a number of facilities intended to allow the analysis and
+synthesis of multi_index_container instantiations by
+MPL metaprograms.
+
+Given a multi_index_container instantiation, the following nested types are
+provided for compile-time inspection of the various types occurring in the
+definition of the multi_index_container:
+
index_specifier_type_list,index_type_list,iterator_type_list,const_iterator_type_list.MPL Forward Sequence with as many elements as indices
+comprise the multi_index_container: for instance, the n-nth
+element of iterator_type_list is the same as
+nth_index_iterator<n>::type.
+
+
+
+A subtle but important distinction exists between
+index_specifier_type_list and index_type_list:
+the former typelist holds the index specifiers
+with which the multi_index_container instantiation was defined,
+while the latter gives access to the actual implementation classes
+corresponding to each specifier. An example will help to clarify
+this distinction. Given the instantiation:
+
+ ++typedef multi_index_container< + int, + indexed_by< + ordered_unique<identity<int> >, + sequenced<> + > +> indexed_t; +
+indexed_t::index_specifier_type_list is a type list with
+elements
+
+ ++ordered_unique<identity<int> > +sequenced<> +
+while indexed_t::index_type_list holds the types
+
+ ++multi_index_container::nth_type<0>::type +multi_index_container::nth_type<1>::type +
+so the typelists are radically different. +
+ +
+Although typically indices are specified by means of the
+indexed_by construct, actually any MPL sequence of
+index specifiers can be provided instead:
+
+ ++typedef mpl::vector<ordered_unique<identity<int> >,sequenced<> > index_list_t; + +typedef multi_index_container< + int, + index_list_t +> indexed_t; +
+This possibility enables the synthesis of instantiations of
+multi_index_container through MPL metaprograms, as the following
+example shows:
+
+ ++// original multi_index_container instantiation +typedef multi_index_container< + int, + indexed_by< + ordered_unique<identity<int> > + > +> indexed_t1; + +// we take its index list and add an index +typedef boost::mpl::push_front< + indexed_t1::index_specifier_type_list, + sequenced<> +>::type index_list_t; + +// augmented multi_index_container +typedef multi_index_container< + int, + index_list_t +> indexed_t2; +
Revised May 7th 2004
+ +Copyright © 2003-2004 Joaquín M López Muñoz. +Use, modification, and distribution are subject to the Boost Software +License, Version 1.0. (See accompanying file +LICENSE_1_0.txt or copy at +www.boost.org/LICENSE_1_0.txt) +
+ + + diff --git a/doc/compiler_specifics.html b/doc/compiler_specifics.html new file mode 100644 index 0000000..bbfc475 --- /dev/null +++ b/doc/compiler_specifics.html @@ -0,0 +1,314 @@ + + + + + +
Boost.MultiIndex Compiler specifics+Boost.MultiIndex has been tried in different compilers, with +various degrees of success. We list the limitations encountered, +along with suitable workarounds when available. Up to date information +on compatibility of Boost.MultiIndex with several compilers can +be found at the +Boost Compiler Status Summary. +
+ ++Currently, Boost.MultiIndex cannot be used with BCB 6.4. The +number of problems encountered during the tests makes it unlikely that +future versions of the library can be made to work under +this compiler. +
+ ++No problems have been detected with this compiler. The tests were +performed under Cygwin 1.5.7. Most likely Boost.MultiIndex will work seamlessly +for GNU GCC 3.3 or later under any platform. +
+ +
+member not supported,
+replace with
+member_offset or
+use the cross-platform macro
+
+BOOST_MULTI_INDEX_MEMBER.
+
+Altough Koenig lookup seems to be officially supported by this compiler,
+some issues have arisen seemingly due to bugs related to this facility.
+In these cases you might need to explicitly qualify global names with
+::boost::multi_index.
+
+No problems have been detected with this compiler. +
+ ++No problems have been detected with this compiler. +
+ + +
+member not supported,
+replace with
+member_offset or
+use the cross-platform macro
+
+BOOST_MULTI_INDEX_MEMBER.
+
+const_mem_fun not
+supported, replace with
+
+const_mem_fun_explicit
+or use the cross-platform macro
+
+BOOST_MULTI_INDEX_CONST_MEM_FUN.
+
+mem_fun is not
+supported, replace with
+
+mem_fun_explicit or
+use the cross-platform macro
+
+BOOST_MULTI_INDEX_MEM_FUN.
+
+No support for index retrieval +and projection +nested types and member functions: +
nth_index,index,nth_index_iterator,nth_index_const_iterator,index_iterator,index_const_iterator,get,project.::boost::multi_index.
+
+
+
+The lack of partial template specialization support in MSVC++ 6.0
+results in some inconveniences when using composite_key that
+can be remedied as explained in
+"composite_key
+in compilers without partial template specialization" on the advanced
+topics section.
+
+MSVC++ 6.0 presents serious limitations for the maximum length of
+symbol names generated by the compiler, which might result in the
+linker error
+LNK1179:
+invalid or corrupt file: duplicate comdat
+comdat. To overcome this problem, you can restrict the maximum
+number of elements accepted by
+indexed_by,
+tag and
+composite_key
+by globally setting the values of the macros
+
BOOST_MULTI_INDEX_LIMIT_INDEXED_BY_SIZE
+ (default in MSVC++ 6.0: 5),BOOST_MULTI_INDEX_LIMIT_TAG_SIZE
+ (default in MSVC++ 6.0: 3),BOOST_MULTI_INDEX_LIMIT_COMPOSITE_KEY_SIZE
+ (default in MSVC++ 6.0: 5).
+Under some circumstances, the compiler emits the error
+
+C2587: '_U' : illegal use of local variable as
+default parameter, inside the MSVC internal header
+<xlocnum>.
+This problem is a recurrent bug of the compiler, and has been reported in
+other unrelated libraries, like the
+Boost Graph Library,
+Boost.MultiArray,
+Boost.Regex,
+CGAL and
+MySQL++.
+The error is triggered, though not in a systematic manner, by the use
+of multi_index_container iterator constructor. Two workarounds exist:
+the first consists of avoiding this constructor and replacing
+code like:
+
+ ++multi_index_container<...> s(c.begin(),c.end()); +
+with equivalent operations: +
+ ++ ++multi_index_container<...> s; +s.insert(c.begin(),c.end()); +
+The second workaround has not been confirmed by the author, but it is given
+on the Internet in connection with this error appearing in other libraries.
+Replace line 84 of <xlocnum>
+
+
+ ++ #define _VIRTUAL virtual +
+with the following: +
+ ++ + ++ #define _VIRTUAL +
+Warning: it is not known whether this
+replacement can result in unexpected side effects in code implicitly
+using <xlocnum>.
+
+In general, the extensive use of templates by Boost.MultiIndex puts this compiler +under severe stress, so that several internal limitations may be reached. +The following measures can help alleviate these problems: +
/Zm (Specify Memory Allocation Limit)
+ to increase the amount of memory available for compilation. Usual values for
+ this option range from 300 to 800./ZI (Program Database for
+ Edit and Continue) to a less demanding type of debugging information
+ (/Zi, /Z7 or Zd.)C1055: compiler limit : out of keys, try
+ disabling the option /Gm (Enable Minimal Rebuild.) In these
+ cases, it is also beneficial to split the project into smaller
+ subprojects.+Boost.MultiIndex works for this configuration. The same limitations apply as +in MSVC++ 6.0 with its original Dinkumware standard library. +
+ +
+Problems have been reported when compiling the library with the /Gm
+option (Enable Minimal Rebuild.) Seemingly, this is due to an
+internal defect of the compiler (see for instance
+
+this mention of a similar issue in the Boost Users mailing list.)
+If /Gm is turned off, Boost.MultiIndex compiles and runs
+without further problems.
+
Revised May 7th 2004
+ +Copyright © 2003-2004 Joaquín M López Muñoz. +Use, modification, and distribution are subject to the Boost Software +License, Version 1.0. (See accompanying file +LICENSE_1_0.txt or copy at +www.boost.org/LICENSE_1_0.txt) +
+ + + diff --git a/doc/examples.html b/doc/examples.html new file mode 100644 index 0000000..87e581b --- /dev/null +++ b/doc/examples.html @@ -0,0 +1,319 @@ + + + + + +
Boost.MultiIndex Examplesmulti_index_containers
+ with ctor_args_list+See source code. +
+ +
+Basic program showing the multi-indexing capabilities of Boost.MultiIndex
+with an admittedly boring set of employee records.
+
+See source code. +
+ +
+Usually keys assigned to an index are based on a member variable of the
+element, but key extractors can be defined which take their value from
+a member function. This has some similarity with the concept of
+calculated keys supported by some relational database engines.
+The example shows how to use the predefined const_mem_fun
+key extractor to deal with this situation.
+
+Keys based on member functions usually will not be actual references,
+but rather the temporary values resulting from the invocation of the
+member function used. This implies that modify_key cannot be
+applied to this type of extractors, which is a perfectly logical
+constraint anyway.
+
multi_index_containers
+with ctor_args_list+See source code. +
+ +
+We show a practical example of usage of multi_index_container::ctor_arg_list,
+whose definition and purpose are explained in the
+Advanced topics section. The
+program groups a sorted collection of numbers based on identification through
+modulo arithmetics, by which x and y are equivalent
+if (x%n)==(y%n), for some fixed n.
+
+See source code. +
+ +
+This example shows how to construct a bidirectional map with
+multi_index_container. By a bidirectional map we mean
+a container of elements of std::pair<const FromType,const ToType>
+such that no two elements exists with the same first
+or second value (std::map only
+guarantees uniqueness of the first member). Fast lookup is provided
+for both keys. The program features a tiny Spanish-English
+dictionary with online query of words in both languages.
+
+See source code. +
+ +
+The combination of a sequenced index with an index of type ordered_non_unique
+yields a list-like structure with fast lookup capabilities. The
+example performs some operations on a given text, like word counting and
+selective deletion of some words.
+
+See source code. +
+ +
+This program illustrates some advanced techniques that can be applied
+for complex data structures using multi_index_container.
+Consider a car_model class for storing information
+about automobiles. On a fist approach, car_model can
+be defined as:
+
+ ++struct car_model +{ + std::string model; + std:string manufacturer; + int price; +}; +
+This definition has a design flaw that any reader acquainted with
+relational databases can easily spot: The manufacturer
+member is duplicated among all cars having the same manufacturer.
+This is a waste of space and poses difficulties when, for instance,
+the name of a manufacturer has to be changed. Following the usual
+principles in relational database design, the appropriate design
+involves having the manufactures stored in a separate
+multi_index_container and store pointers to these in
+car_model:
+
+ ++struct car_manufacturer +{ + std::string name; +}; + +struct car_model +{ + std::string model; + car_manufacturer* manufacturer; + int price; +}; +
+Although predefined Boost.MultiIndex key extractors can handle many +situations involving pointers (see +advanced features +of Boost.MultiIndex key extractors in the Advanced topics section), this case +is complex enough that a suitable key extractor has to be defined. The following +utility cascades two key extractors: +
+ ++ ++template<class KeyExtractor1,class KeyExtractor2> +struct key_from_key +{ +public: + typedef typename KeyExtractor1::result_type result_type; + + key_from_key( + const KeyExtractor1& key1_=KeyExtractor1(), + const KeyExtractor2& key2_=KeyExtractor2()): + key1(key1_),key2(key2_) + {} + + template<typename Arg> + result_type operator()(Arg& arg)const + { + return key1(key2(arg)); + } + +private: + KeyExtractor1 key1; + KeyExtractor2 key2; +}; +
+so that access from a car_model to the name field
+of its associated car_manufacturer can be accomplished with
+
+ ++key_from_key< + member<car_manufacturer,const std::string,&car_manufacturer::name>, + member<car_model,const car_manufacturer *,car_model::manufacturer> +> +
+The program asks the user for a car manufacturer and a range of prices +and returns the car models satisfying these requirements. This is a complex +search that cannot be performed on a single operation. Broadly sketched, +one procedure for executing the selection is: +
equal_range,
+ multi_index_container sorted
+ by price,
+ lower_bound and
+ upper_bound;
+lower_bound and upper_bound,
+ multi_index_container sorted
+ by manufacturer,
+ equal_range.
+multi_index_container.
+In order to avoid object copying, appropriate view types
+are defined with multi_index_containers having as elements
+pointers to car_models instead of actual objects.
+These views have to be supplemented with appropriate
+dereferencing key extractors.
+
+
++See source code. +
+ +
+Boost.MultiIndex
+composite_key construct provides a flexible tool for
+creating indices with non-trivial sorting criteria.
+The program features a rudimentary simulation of a file system
+along with an interactive Unix-like shell. A file entry is represented by
+the following structure:
+
+ ++struct file_entry +{ + std::string name; + unsigned size; + bool is_dir; // true if the entry is a directory + const file_entry* dir; // directory this entry belongs in +}; +
+Entries are kept in a multi_index_container maintaining two indices
+with composite keys:
+
ls. The shell simulation only has three
+commands:
+cd [.|..|<directory>]ls [-s] (-s orders the output by size)mkdir <directory>
+The reader is challenged to add more functionality to the program (for
+instance, implementation of the cp command and handling of
+absolute paths.)
+
Revised May 7th 2004
+ +Copyright © 2003-2004 Joaquín M López Muñoz. +Use, modification, and distribution are subject to the Boost Software +License, Version 1.0. (See accompanying file +LICENSE_1_0.txt or copy at +www.boost.org/LICENSE_1_0.txt) +
+ + + diff --git a/doc/future_work.html b/doc/future_work.html new file mode 100644 index 0000000..dc709e3 --- /dev/null +++ b/doc/future_work.html @@ -0,0 +1,273 @@ + + + + + +
Boost.MultiIndex Future work
+A number of new functionalities are considered for inclusion into
+future releases of Boost.MultiIndex. Some of them depend on the
+potential for extensibility of the library, which has been a guiding
+principle driving the current internal design of multi_index_container.
+
+Several STL implementations feature hashed sets as a natural
+counterpart to std::set and std::multiset.
+multi_index_container can also benefit from the inclusion of hashed
+indices. As the exact details of the interfaces of hashed sets differ among
+library vendors, a good starting point seems Matt Austern's paper
+A
+Proposal to Add Hash Tables to the Standard Library (revision 4), which
+has been submitted for acceptance into the next revision of the
+C++ standard.
+
+Ordered indices are implemented using red-black trees; these trees
+can be augmented with additional information to obtain a type
+of data structure called
+order-statistics
+trees, allowing for logarithmic search of the n-th element. It
+has been proposed that order-statistics trees be used to devise a new type of
+ranked indices that support operator[] while retaining
+the functionality of ordered indices.
+
+Notifying indices can be implemented as decorators over +preexistent index types, with the added functionality that internal +events of the index (insertion, erasing, modifying of elements) are +signalled to an external entity --for instance, by means of the +Boost.Signals +library. This functionality can have applications for: +
+The following is a sketch of a possible realization of notifying +indices: +
+ ++ ++struct insert_log +{ + void operator()(int x) + { + std::clog<<"insert: "<<x<<std::endl; + } +}; + +int main() +{ + typedef multi_index_container< + int, + indexed_by< + notifying<ordered_unique<identity<int> > >, // notifying index + ordered_non_unique<identity<int> > + > + > indexed_t; + + indexed_t t; + + // on_insert is the signal associated to insertions + t.on_insert.connect(insert_log()); + + t.insert(0); + t.insert(1); + + return 0; +} + +// output: +// insert: 0 +// insert: 1 +
+The notifying indices functionality described above exploits a powerful +design pattern based on index adaptors, decorators over preexistent +indices which add some functionality or somehow change the semantics of +the underlying index. This pattern can be used for the implementation +of constraints, adaptors that restrict the elements accepted by an +index according to some validation predicate. The following is a possible +realization of how constraints syntax may look like: +
+ ++ ++struct is_even +{ + bool operator()(int x)const{return x%2==0;} +}; + +typedef multi_index_container< + int, + indexed_by< + constrained<ordered_unique<identity<int> >,is_even> + > +> indexed_t; +
+The mechanisms by which Boost.MultiIndex orchestrates the
+operations of the indices held by a multi_index_container are
+simple enough to make them worth documenting so that the (bold)
+user can write implementations for her own indices.
+
+Example 4 in the examples section
+features a bidirectional map, implemented as an
+multi_index_container with two unique ordered indices. This particular
+structure is deemed important enough as to provide it as a separate
+class template, relying internally in multi_index_container. As
+feedback is collected from the users of Boost.MultiIndex, other singular
+instantiations of multi_index_container might be encapsulated
+to form a component library of ready to use containers.
+
+multi_index_container is rich enough to provide the basis
+for implementation of indexed maps, i.e. maps which
+can be looked upon several different keys. The motivation for having
+such a container is mainly aesthetic convenience, since it
+would not provide any additional feature to similar constructs
+based directly on multi_index_container.
+
+The main challenge in writing an indexed map lies in the design of a
+reasonable interface that resembles that of std::map as
+much as possible. There seem to be fundamental difficulties in extending
+the syntax of a std::map to multiple keys. For one example,
+consider the situation:
+
+ ++indexed_map<int,string,double> m; +// keys are int and string, double is the mapped to value + +... + +cout<<m[0]<<endl; // OK +cout<<m["zero"]<<endl; // OK +m[1]=1.0; // !! +
+In the last sentence of the example, the user has no way of
+providing the string key mapping to the same value
+as m[1]. This and similar problems have to be devoted
+a careful study when designing the interface of a potential
+indexed map.
+
+Once Robert Ramey's
+serialization library gets accepted into Boost, support for
+archiving/retrieving multi_index_containers should be added.
+
+Andrei Alexandrescu introduced a technique for simulating move
+constructors called Mojo (see his article in C/C++ User Journal
+
+"Generic<Programming>: Move Constructors".) Move semantics
+alleviates the computational load involved in the creation and copying
+of temporary objects, specially for heavy classes as
+multi_index_containers are. David Abrahams and Gary Powell provide
+an alternative implementation of move semantics in their paper
+
+"Clarification of Initialization of Class Objects by rvalues" for
+the C++ Evolution Working Group.
+
+Adding move semantics to multi_index_container is particularly
+beneficial when the container is used as an internal building block in other
+libraries (vg. relational database frameworks), enabling the efficient
+development of functions returning multi_index_containers. Without support
+for move semantics, this scheme is impractical and less elegant syntaxes
+should be resorted to.
+
Revised May 7th 2004
+ +Copyright © 2003-2004 Joaquín M López Muñoz. +Use, modification, and distribution are subject to the Boost Software +License, Version 1.0. (See accompanying file +LICENSE_1_0.txt or copy at +www.boost.org/LICENSE_1_0.txt) +
+ + + diff --git a/doc/index.html b/doc/index.html new file mode 100644 index 0000000..5147aa6 --- /dev/null +++ b/doc/index.html @@ -0,0 +1,74 @@ + + + + + +
Boost Multi-index Containers Library
+The Boost Multi-index Containers Library provides a class template named
+multi_index_container which enables the construction of containers
+maintaining one or more indices with different sorting and access semantics.
+Indices provide interfaces similar to those of STL containers, making using them
+familiar. The concept of multi-indexing over the same collection of elements is
+borrowed from relational database terminology and allows for the specification of
+complex data structures in the spirit of multiply indexed relational tables where
+simple sets and maps are not enough.
+
+Boost.MultiIndex features additional functionalities, like subobject searching,
+range querying and in-place updating of elements, which make it a convenient replacement
+for std::set and set::multiset even when no multi-indexing
+capabilities are needed.
+
Revised May 7th 2004
+ +Copyright © 2003-2004 Joaquín M López Muñoz. +Use, modification, and distribution are subject to the Boost Software +License, Version 1.0. (See accompanying file +LICENSE_1_0.txt or copy at +www.boost.org/LICENSE_1_0.txt) +
+ + + diff --git a/doc/lopez.jpg b/doc/lopez.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ac37b4a94eb4303cfab9af0394509252dcd46bca GIT binary patch literal 15167 zcmex=rio14tUg}%Ewg&&pYw!El zbybuHXW!@FxxQ`s&PUFjzx48Ehpx7bX!vW#+&^jg_7w5|m(Rbhl$e&hack7|TgN@J zeP&pdg;&Y0x3!(|e$}y^jrYErNeVCDdtWqs)fb(G)2@fyx^a1nLxDhj#Wu0s3>Eh) z?;KpL&2o6|@Av<_5*4^y9CgLRUdufT8L& iGx#5_EcSL=`=HVAQ!M}D-t29ApPf#AX}dJ! ygy=FVMUE@7luI~S9iE2r9=+a}mHiz$UUOm4suXXc%|36KQn aQ%8PMLz055joZdaHM4U5~q{Y83c(Q<4M6rWe^8?=ZBxFhA68J)4;4e2e{} zp 2<)sZmeoK}ocd8mIo?W+m=ffU`z4vVRpIZM~bvi=o z@yi_(?557~Km0vn;)<&=ZrffxzMt{-?^3H7@ev8X+=Cyk=R6`S#-?`6ra >`k;oXSJ=#nQwPu3AaOb5Az8rmMm9u#z*_4wX^xIeH5r(x%23`e$Jq5?&z(H z7@T_-KD{M;Xp*2}UlGf_^VVP6mv8+ycXz$pbJqnG|FRb*-ww@@c24;5QhVLm<=2i@ zv#XhEt9()0G56ZL{Inz49|Kccy;ghe-`cVN|IPnz1-Br&CdPUO3>HqFzAUQX7P0`C zL?S?P%x}R00+7xP0~3q}$+4(`<@mrPn6PhPfSAY&=CUv_Fvx*bN}}?aKZE(4U=q}y zfau}^^BEy#s6*Vt1@2mbB$z-ZF@FUy89W&D)6y6i8FJFnKpi5m5fG7uGiSj?K)ozR zhA2??39O5e!4#}g7a;;R^9NYAfPvvZR>1rMB#%| 5 s>^&l<-1E`C*fPsO5i@}p2mm!fMogtMWk3oaMn8A`k6YO7z zI%JX&i38FLG6P8n)K5m?f;mt}g4lVbIXMgr;9fCXQhsS(O0j=ZRx-k}pyU!m1_p2s zlp!R)Kp`hTFCC;0gnd%eN|5 RXKN3x^sR`ei0}rp@Az1G2h7@ zE&=kaUw&RH$oP`{0{_yI;#63|0LgLXq^6Z%i1H-mmz3n^Vu*7WWu|AKD+lL5L6Bh# zjEs;x1{&~zBwR+YEDuPQ2R2*;8vICLU|?)uV3@$bz`*^IL4tvCbohi}bok`ix6$E~ z`J=-pqr)eo!zZJ|C!@nBqr)eo!zZJ|C&O&`1kyuL1oa3QLP7m8Q2&Xa!I2?_A)g_M zA(cUaA%G!+A)ldyA)lcb%qn1DU=SvtLV>}YL65-zWFW)_Hn0usU;#!(hW`(RJTgj3 z3as??^NRHnK@-e+$@#hZ6^RA ZxN)4{^3rViZPPR-@x3}Z6u?HKaTaj3xo0geVl3G-(kXoEsz@xzO)W`OsL0L9E4HezRR?RZ$}6@43G1sXfR&VF+p0(S1}K!|=jUW+mM9qM zS?C$*8XM~ T(8_%FTW^V z-_X+1Qs2Nx-^fU}C?!p|xH7LKu|hYmSXmvaFEawJ4JAA>Bf!C-ZpX!?0Jh2{wK%yb zv!En1KTjbsDZjMDR=u<|GsP;+$kHq|$-+X{(kL}q*U&JJ@HxN+6u-W{$cAw#*yw|T5XoP5TwD;bAQv|~E*pJtjDTVX 11_4|prD{I zY6(f9JQ`f1!9`LCkfeAtb&UoWNg+Uz;?dMK8eAlW07;5RQ`cy4krV W2kr}aYzR_sn!k~># zNs|sK8()0bv?y6bkbxPj2{gwKv4c@ik;%|8P^hqx`9tEwg`ZGY!=GdR`!q7K?9`6# zHL6St*Ua)<`s9+QJ44;%hQ<7r3Z8i%EgF&;MC}S@I((5|B4)&VdB>K0VLVghi#8}F zU0$s^?b7n4+H4WKLb?QUpDI@tZ|UN?a7|oK|Lw1wkmys~9Zdc2LY`dZyu4+OX_Ck9 zwh3!~TxM!sxrKj+z_eJ8mzt>_N@Z`IqA!I^{$jkNBHAv#^xa~wgP-Dd7nVxR=eRD> z*mq4Kddub5q%~H3PmXp@&eif;mYRB~pooz@BU|`VTSn4}Gua+`MXMiQdKAXEFlJA% zo5uCu4eJ&$OXgmWwfZX9XX>FeZ|M#@`DI3h%FA~wSsv9ncSe% Ud_S$YQa!N_ff2NBX;6|1(USG;7C~2fp(EFNEl xtk!~ )@U@+TPfDoA=~@`mMcrvJZqR$i^?DCe(Z zhkJH3H-yNwrR-{XA{}8ixnTXbx3|2H@0c+08oO0kpH;SG>Yfz=xtCNv8I}ca5nLiD z+N<$xcJ_aU-YvFE(hh97(_S=h)1M|TZL7Ik6=ZoPPdz*D%cKJgZi_$9Iby_oCE_qc z@ovFaNf{a}oTk6LO}9>U49@tVaN~kilP^!PsL;hUhlOQ-leKOKLMIt^0t|{&O Mb)h9@_cbJ#_z;+YLz$xq=xlmdwczFFh$}$5*!Otkahdv$#ato|qU<&P_XO zu;9+5{53m{yXva1jpCkoQqgNc=R=PFmySJKchB2*Pu&`=>c-z{{wLQOU*9onkMi!$ zp8iWL{w<2(QIbr;8eio(9gT~o6dsfH+SaB#ZAbsMdbvj#y-M*)VyoQtF3tMP;ImQf zuFB?&k~uqK9$7kk;TG0!?wvn5 DT7b!1fc;nId zGnAcad$R6_wJ%Q0?Xd6YJjv4ZJj$?fZ?etASKVJH7@aoW=lo~!sSM8fpB#D`zVyeg zcKD&(_u_|q-}6khRens?(;xr!3s zo39*F*!xtGRqxP~gL9_7 @0Q8VlF)hLfo(au=sWO~?#n= )wV1tw&pDAIsW*Eb*xCm%zK{zvxW;&+z2<%kZ4${|u%J{-w3bh#qd%EwL+n zlb*0RGNfwh^_vSgTkd}q@(EXde0*wm;nAu~+b4dqQIN^0*tG2O!ab`C3vawzb~w;G zs!Trf<4T5=N?R^Xiq*byCP(o96?t37N84K;)eFuwOsy|$TFvWU$bSCFjXS(=4)iUv z{rI}2@ao?UMbeqq^aQn)V`d3RWZu)N{?hm4z?qgOi2>SMe4ai@O}OE!dCz4%TX)>U zu%+3Tv_DCFPv*UvxH(;>#)N5I37f{9H$6)^qGU6aui80hY;@r;%Jisx|9f@3Wf;qy z2Aidq99F2@669R^_EJC-kJ=);CN0Oc+ELyLa~KqY<2KxIxLfJj!rv^KY5GIrhQ*Dt z?}j#VH<+51Z@Kz-@dg$y{zu~fGB#zh@k`2m<-1oT+_u8*R^?>wZlR@-Q!2YX($cb$ zlK5ZRCbX34WWVDI33~QbsQA&ntS!k>j~}KvMFg%~bN1|<2d4_3Zhhm|=6>?POwonf z-!}Z})cH4Sru+HculWHNzIH!*vP#pw;I%K$x#~&v|F0&`GDz7NP{q}K?$8v5238&R z3>J0e>kBTp7cQG5)qFMK$)TvX*U~@j=ss3 tlO&ceQJo#?eJG=-7U_lj%HWBwuJ;)&-<&wyG7#T-^Iaq{;fQdQPyiU zgVFtnc4k1khvTIG3{%uh`Iq(-SgH#t#;#G0u(;vx{k_qLKZ^UOub;f+3hsY`50xhU z=J{yB#bKTK*fd;fQOVRpt5!QEn6yfGXGYq2Y+aqSCbE}3{+!|Qhwt`ka#j48%5Ask z@i}=`hxJ}g+m3zpG&(Hdy1>}}$&O~Du&K6--{osgh~Qk_8*p;I{B&WS*#T0#snPwD zrlf7#GV9Jci^Fqg)UK_V=KRA)Zs*+2od4I%Wx^UbekCuM7iuN9pg%hBQre%*jXtsO z(r5ckT6*F$|Av!oSC{Z_3)C{rziAg%a$RD> dmI $z9c*!Mm1wx-ZOpWW4k>XZprZKVDCrUbtXM XY@IpB%IoJURbIAzK6}xQ|Nl(@bbHGq literal 0 HcmV?d00001 diff --git a/doc/multi_index_cont_example.png b/doc/multi_index_cont_example.png new file mode 100644 index 0000000000000000000000000000000000000000..120cfddac53af234463e20c34cd51a49d8a0b42b GIT binary patch literal 87417 zcmeAS@N?(olHy`uVBq!ia0y~yV2WU1U^L)hVqjpL?6YD!0|NtRfk$L90|U1(2s1Lw znj^u$z`&C3= k04(LhALGChK6PahM)f#7#dzOFq9fFFuY1& zV6d9Oz#yJKDgLM%17pa0PZ!6Kid#v4{{Oc>yn&5@@kq;=oyE`jS_ S`t|w2 z!Ivkgdhgk@=R(N8KR<;%_Emm >t@Md|8xo!U z{rO$??%VfoUF`0v>gtPU7P >3jDWs~(O3(Sh$L42~cI>b)nOYIUB;c@MN*nte%VM^fzkhvw{r^bg{`&ty zD?c6S6h5NiTz0ZsT>qaiF9TBt=h@YV^`|ni2ynM__4Md)8l@(*FsK e#ycNSb zbe35LL`z8S-&gzZ oneZWp9SgD@j(q!i`ewvU ziJ1%RSlG_||1S`FhU4oByA+1qVm?lnpY7jY&&b3f)vl(dW_)^aLr?tv{|~mzekorj zpVabqef<7Lj+^ZoQ5)K9SMe)8{P+2~ev0mc4tK-e85S%Y3KRIJPMv!3lAg8l;e0m@ zYlpK_zn;(Mxc%_m(VB1X-}vyvO JH*6@ktG%nY_S}d0j?b@N&b;(z+x{I7cKH?jcQt-~wcY=b6O+KUkE`_sj#YXx zdVEa$@Z_v7Yv=s`l6f|DLciF bboL4^xj_Hn@1Q_pBL!nPf_}Q zUY &%+JP23g_S=)UA`K= zo_F3p)>(`HJ!t(j_jrW2R0Bg&Q;7AfS+fcj`tG-AsFH|`oOy697srpXPZli`zduo$ zP%~{Rqe^h)ztY-tcB2T@B??CkWA+-Dt82*Ibll`5e~ <XD@O&r(OM Sr>Cm`2GBMxtp2U#6y$T^IZ7z z;r;9IgFjeI ~O?blkyHR|S*Z&4-q5u2p*(Yg#S*ZEq{&f8l zY78s_TXf#Of4_b5&;H2h1=CD?)~wMvFl$bN=i#$QTf?R$>1H;F6>lj1^XoJF<|QBb zdhc#bJX*gYRAib710##C!GUM`|Eea>?Cfmr&3*iCalU;G(>0CH;rYy5>+TjdbT`*N zoR#}FSX`p&$dhX&e;ZT7*EpO$R( Yk2;>GOmuFUw(FPnDAhYtM PfH~Wng_EStO0vdex z_t(FF{@h$qU*JW(o?ltS3WMZhiW7bvJ@hN}T+PHME)_COOJ_ Lmh{ex3xV}U$@clPjbVRmIq!!F}y~LwzU8M$I7Ab zMM}P2i#6zcl2EGonxFswvi~#VRn`)>oN8295VO_nvSo#ge{ILjWsaX8a{9LZ|6hOe zPNlB_s3= u_PMf#_&um9)Y-#2UbgGu{q zANzT^q=h*h+-v<^QR#EK9@8$jZ--o6de0o$QvEyb&$k#;W>cQ8>+h-_?qy(fiIh2X z=*{ef+~<$ho+$kB=3{ZBrR1EC%v#?iI(rUFyY0I5eEq~Ha!)`-j@qg(MmzQ2u$o IOAI^9+)%<=b>_@}A-{hVd`8%y@dxBOz3T~qo`OEr&~LqRR8bm{;9 ze}4XdeVzZ A$lki`AHovqG!2;_ajmxE17=N899(-C)P*UNiil*G1$Bb96 zcdq<+z--mi)8!$BLJka$wJTPv@DP2>HO2Jic{wMsn`c ->@#5rzjdE=D=WhP~AtvJp1LHsXLbZ+gI7FdE(b|b7A%A zpY<8nL^a5|u3|BCU ;L`{eInDSsW)e8v)ZH&FHXm&rOo_0`@fOld%=mUT{4yxQ(9T4 zWKRj1vf_nG1H&S}-6ETpB&H|luYQ*`_r{0+@Bf>xzt7pt@t>j0v0%G5|2x|!FJ5)* z&v%?x&A`;r>Bf3yef<7YQeAenKmI)Z9G=kk>)+ezB9?QJCJCaC9whlIPiJ5e;J*8; z;n}(woSXVvm+oEn`s(TH2e>ZWIb~wVdnF<`By7Rly$p;df1WomGIew&?qF_Ukos51 zA>hzqVPazP=EVyR4vqu6+8+J;`@8zvo0&G1MlG+OKM#+J+EwxK(TWusCR5MPw`ULi zSpPq6FW0M`W+o;gVq%BH 1Stc&APg3!-fq94md2h^6Ba6#=avZmJSTO4=t`-yVk~{RL3CT@ZzUH?$)DEPfvgN zrdwQpQOHeB&K*2=x8+J3ZQr?5a^~uF>-x^r{{3aDS6otB`tXhUhBEn@i~O6uU%1wz zz}#B)|R7pP$APA5S>4{xrj~OaD#SDrA@i9DE{vUq8&rz#_2X*!0PhtABiWxYP9S zfn(>t%kST@!$NQ~tH);XjN+*G_O+GT2l^u}H!NYz-Sz16YWM#0@7re|W}RE@JS)Lr z-VKLYhXn*4{QvQjd)Cz%#W@bTpoY}fUfDd;7~T!)TmlXYCO!M`@UWSgnS*>6$H)4A zznIVNG?< v7S|t{2mAFy+ga7#+l^~gazrTy$ z(fHeIH?>n)_d%!gg6|I5h6c-A3V#Y%{&cwF5TxnA&{$LP`kL;REz;}W?fY~s@5Ln+ zSC`opcatyV?3+Hv^zn25+jdQ1aT^Q`t2!F09@Wp7S-x*)Q;x^k_W#RMrZGR+E1U HIHifNR5!|{m%Cf#IqWnEA@_+edoO9!Lnsq6@@IntY-YL7gUnHG;9An z+tL&^)^E9<7c@Scf4zXKm)T6`z>)UU8~6Vljz4P49>(FVa6SM0r((x*ZA+ci_{v;d zHf*fFyI&sMBGPoqGdb!xgVFQjE;ogppVUoCuCBY+(!Z`gy^XE?lkkNfuRgIaC|O bi%sH^XxwB3tygJ|6lFTU$)5ZkNjec|Lgxg;pT8LV^L^Wu+~h0 zQ^)&f#m>U1OF8t`v^;qD?9aEq;sIT=yMO;aKVLxisBf*X)M*Fq&jnLVYWD1zzrRj- z*^-A39xU0gWaH*?hG|O~7+Jaw&zU3B^!3^M`}^+-pYpO!Q<+-IF!#jaqbnbaNzVvl zoKn Le>mM(-^KpAvbhT}Z=XG{^1~k;)e)l|4veR z`tyempFMiACjWJ2#(Tw;e& z+`TQqZN2V{4M!e+e{bK?(( LzBdWCS6Y!snZ8I;wN!1PWUCD&=3%$ z86 JEkQl%q~8A^4tA#w!Oi}Ik#nQn8959u#mTMb+rG7 z g7lc~AD1HN(ANVdYS62L{EUm&=S# z7y4~Y<_m8+S|72ySnhVOT} llT z%Xa6TV?=wFjsruW$*dEVCD-3;8s8`~+IVVH@rLCs>0Dggb$>o&-a9pOe|^)mhx_Wj zx_!IF8qn6b{`!tecVB1G{jS%~eEFhxSK<6b21b`anL}+$Xa1A5J(rct+wU9~H*bCX zzJ*5>U!CIqvQ)Bh-a_fJHAj06Tfghe+RdlbUocs!oq^G%_u`TN|08qO*v+;+r1mOe zf6c$Hj5{{J1inqR|Dr9g{H|>N=g047m#<^aYU#G|>R^?s4vmd0ea^@g%P!y$BCY?_ zcIW@&M>PN2*C)B `P~_e|B)y#n-aJ(&E!!zphsdpWi5+%W!*nO}xJh Y2^|_O^D{{Qma$MB`y_ zv#Bv?N>2}u^1X9{stKmwkIy&fH~v?5Lh(fBwmqUu*NW?slh{Nha%7Y=a`mjUS6MJ9 zG&mIQNIuSYiv5<@Sr%XWV?WegD~>R&X6G*b9ol`p?#Bng8$WeUu1ZNxXD^Mp8F6-N zj^pQt+|$%smRH>P#Zuk6xwxpHu<-Zp_85!ui!Qehx!k^U^jdQ#r}y!xHVgs|S61jA zaQ*qTIQ&cRSA*;tF^^)AGyje=M1DHM6S;`*BFD3T>Jg78$3`=-2xzSEn``A-8E{p6 zdy**szf LW=O0LavCHm9oJ(0++WYb|C!&P|tD@iA2dIJ??kC#Q($c0#Z>jsw zRTF%uJTIARSA9~tn8=@>vZqhg$i>MqIx?>MA)wH(A~Je|Qs~VS3=z}z#cvbw{cvNm z`Tze7W!)@w?(5ax-`)BB>1Xk*om`*@I{o+e_52rA%lB(=@|&D#W{j##J?Qz(o>_SF z@5kqNr|kUk^QT=sQ)SPtY(oa7j#I@4Cj8y#;FcVD`+NTV%8H%aJN^~Txw?1O@5@ng zQ!;Lz`dusizW?nX`*N;7_cXaznc3I G3d`THj+Uut;y;ojWeugll5nSEqoVadqScVOWCUs(fc=YZUh z@#FZz4eShzEw&T0GBTb#eR_75DR-Sjb4v?Lk$m>AFE3wTTbs;~|M&2fxPX9yZ*Ok8 z_sc!p6dDyJb>lRv)S>g|_oto~`{TD|<3>&%o;l|Eaw(mM&d;}3J;1PzL8J8FpUO3T zj8@E>ZYk>Ou3f*LfA!BphYlqrB?%n&nQJAwKl#t!zojK5Y3JwteQ=Oj;rpqn+TXr? zn=oOfS*}#tj49KmG1+G1 ;bQCZcbNH zQi_SWaQ6O>?UD>E7c%r@J~1dXaD<3%+qUh8sDz|sqNuusPEtmO$ExVq*w~NSA3lFR zthF!es@9W6QJ;jQB&Su$PEJk*o{>>ei#jDFBm|PxBomof7#LkD&M}?m(%dpRyCZ(F z%bzH%NBw>FMYqY=11kS Hk(-w6+b0)se@^see!V0~#pL`2 ztU+^RCd{nxSS+i@YPI9pO-YOCjAq-J0{=Yx9PVfr*CMj!ApeuS|GzxtwU<}+QFY?F zDmG)HLGr=nCJx7*NEr0|{qySL;?KV&CeAs|@II+wTVHVvduU)!#ydtMhxErBn-p$0 zy$N9pVOQAg-Z20D I7FZV4v7Uyy4G1L2crmr6g8*VM~nRA)-|G(Pb|76ok*DZHmlDx+`=|EmW61%+n zXU5wV-HrS7!uBR5Ejkjxm?J0rQX<;gnuA%PL13pq#Pf&t6InRs)%;UDe7aL@#}jjP z<0YZodhrRW63v&^ub=iu<6`~m*ZQS$I-E)0f6v#CxN$JbkxliZ;lI=rwHNGt_4W0e zHawD^^Y?FiuV{DEO?`VKr|nYB1zjp78y}pvuNT| FKF2 z*z#8WZtamn9K5m$kqg#+d9MHK!T0I!?^o{FF~Rj-&5s>_j%K^8I26Op^7GcL6I$RP zI$+1U;d;~hy~|&nJ9 atqdw#B9Vqk31@MyG+w>f?5(3U;>%bL<+`hNcUy<$h=`(z{I{cF}c z&VEuld28E|`?K%8W3OBAc$viizr|Ax*8b)!n%};J)4C%1-Tw3Q8*j~D=4`%Uo91k_ z{|Ak>{rLF0JYCN<;g8{_4fl#S{r=Bwa=OOD?dVi*Im>x5H 7FMpZsX~zw9G+!@AosAj2X+GMFut9+#SEh z;JvZ2(X2iHj`8%(3+FAJV9DDt<=5u#>G6B4e!SRtZE^U4AIXoN)Wpp=&hzfm_reda z?5aBFxdcs)yB7Aih{1tDv8np;vEJ%$Zw@YMnrP^BxcTM#`TD=V8x|I?j@xnQ><@hx zURyEAn>XS@ru?n^_U3I%UCPH=|2{_vrK3xEHca``-?_3=c8Wl`jrC{wH_z|u&tq0y zs^*i%B3`?H|Nj}Mn^L`c=g$^4a{c%JeE!qL>JJ}P+dF-qR$y#swb_el^TWdz9Nfgj z8ZUe}e@H3KXTjE82WrYb$(NkwN@02 -p_1 zM_4BZ)!Ei4Y)%l=xV`t^Ic7b+hQ0H(g)V6QKhAsMV)~g4ReJAFTPJfGR$JaY|KQ%M z{qOImKGSsxG5;iVB5cnJope#*|8?JZ)=fRlz}RAE#T+?7N88@DQy?x|Ls|5e+-Kj-hC{Ats8H(j}xuD;K3(}8M1za+O9k8_{**4lY@ zh$@BNxpMt_z@Z}?J}YJJCmjF1BjVszo}_ fQLZ!Ys^eK`h(-h#Lmt)y*fL z{@<6?!R4%$_a(mG-EQ*}3w~pBe*PuN2TmPX^N}SrefOQ)=C^sbIzGQ*Qz`YOT{7FT zDmYYb#er+*{(V^J>~NfcMPSjJu#k``Q>NHdebLzT>phQ;_WInTZ#Ft=&HJB_b@}Yv z59fG|g+HIazyECWCjZ Vzv?b-A7_YzKfT`1t#xh>yx+D49q&(A-{PN`Eg z-ZJ^fxq} %09Q A{r`0y&70J?rDt!Qn_TPr z^}T)lmaoZwYHEI|`Plq_ICsaCGmC$ht1fw3SM&RkyugWb2lrJy)nas9`1`xS>E#Se z7YcPPIhq|p4*NvCSeI^C_>l3=tQU*!R oRI(yi^&-oa@Wj#^a`}a1U9?SQKmvg^o qD;?`}yS@NmLi$P;a$m2Qn-7|eI>}cYSy7P0A_QUQCd=p}~vb-yJQYd`oqJY|(#m4^+oX&Re-eSm>{lP`COLsx8 zn#^>b-ctX02V~|RG!Z-h;!ORATk;8s&1)w9&`5dm#7c*Gm4fWN+TY(FTR${ZxU<;U zp}k>Su#qt{i@+j vP1@Clxg|@;{Gt zd^g{usd+dwNs9X>UwdgoFXOg#9eXtX{C>)Pc)GsB-~INrNk9H}yL!xcqmj~L-S$Pp zW|>y%? tYYP|Yo3UHjIR5*Lp?G*zF|?JSeVcez|S{M%03Gi_`yq%P(hSL}OZ!zS~{VN(0- z>Ys~3PggDbvFxbyED5jEUiS6B-n=;YSbN% z|E6}{n^V%h_V@em`YG=xOW8?mTU^2J%jm$sn;~-ORF#_Fy7g?=Y^L`aH?S}M=>D+t z@bZeE6}&yAj>~r^x+n@8Uw&FVz45GPC2M3IW8I6HXCn?XowOEUjo)7*D)8k0@8|L> z15cbeTI(3(@&21~!esH)-!r9J85m787746-@cobL{xrQuwmbQax%Suo*3;1V@cOy_ znw=9kSN?0?a&5ye$$F7PM{8r5&EMa2FyNYLX{mp@ -7p9{ZDdYu{=q+$X&^b_n~ zS{Iyuld^RKL$6=y_p5hmFI%r>&UQR?=!nRlsq$;91nR$6&5}|77 u1oirb53df-`5o7dH?^v z+j<}7CWsUn{VA^FmzMqe{d;EGt}kaSFL;`4(@%P^Fn!0b9UVtzy*~c0?ys(hq~^_A zj(Z>>(;{(fDpRwgsr=vnudkPG)co_@?@`wE+P~lbTj!|n`gL} UFZ z%in)}J)f=fG}k2W#@H7}&fJ)9U-u}l-8k=2&FP;XZJFQP65i-_Vab`af9vZ%o?}yP z7CpuEKk+Zu%$uJTdKL#+_%HkW>FMkB^Xap81GufFt#=51na>=tx3PUm1KXxeoAy=wa|#If@P7XOJ2nT5q)V<}*`9y@M#RmA zyr)lCZnA3LW8bF0%Aw$*x2ODlTt>!=1dp( OL|BgW_gw@7dP+ItWAzV z;!G?8N?gy+&;S4B<>iA9)Dkqgbc`)`dRUjvojCRD_s{A3^X@CTZG5io$7g2tawqq` zH#g6oJ@MdY ajFcI3nrR_$k# z%+J^=l!CHsuf~z9a}u4b{J2g$fBN+Aucz9Zye2I&IG~*J_}tbhXF_;9M3`7ET)20< zr>x&>LswHlW8v-FW*`6EWj}C^N$%~QnmxQz&mLGMerXQlvHJl$EDa1&ca^N3Fgh?8 z_OcxeU}s=7k!p3819hJr!NR@I4k_|8FnuW9sw2SUc*Xv4zaYzO*PJ?q4o4PVF =c{`KG_wteD z+-u(dR`Kk6oFKuroyD d=&CvESH1zIwS((JVS |gBi3k;dHjDJcT6UXyH&a-FFI_zG%W{r-H&bFMJO**Ezw@ec5u&}esTbJpW zn}^5BKCODcVui+uZU2SU{TQ6N^v)eW&h8`ZQ1tE1&DmzTvurAjF06L=xIO>Akd2^% zwYBt$d)KdrySk=+e|PspP+3`-LwQ$sx44+tJiFSc;9y~2eS=RnHZ~VncJAD{+-K&Z zB}-UJK#O`B)EF)+1^oH_{XL6pa#9jgiBEd^@)avyyuZKy;-QqoZM?R&wjT@{f4}?p z_xBE-l;mXQV}=*F3np5Zzhh8dziJiN2{8eI1MlS;7?c9UvobUHR(*YScDAD-e@<3b z)%$z42@81Gjxz*nT`)Y5V)a0ekz>KdXJ;m`GcdX=u$(+$LPPeiM~7OuA3l7z!{pfU z TrX4<_;mpjy=%*Lc-aeP?-q#N7pklGCbzF*&MiWLt?eXhSCP_ z)AQ}?8&o#*HiTZgcyVIRaR%kKiuEsFz7$MWON;drU| F#Tar zXjl+f@%fo=LOJ`4`{G-kyvWpWR-Q2N +SD* z_U}t5W!R* htGy_Y°PMPcf+X>PkO7l`nPG6*^E^ak*Z1YKo?%rRC?@n-y7KF7jm$a=!aPywGFz!I=~I5|R%E+9*wx7SL2HczB>? zvqEZ8Qc`m2-#=fYQ*S@ncTDKQrr3y&?O_v?a{ZbGe0V&9Ji<8=H9a z(7r_Rf%uC#s!EFm_Ufr
eyIINModqW1j%{{1r|4A&blEnDL{|DSU=SKI%3$(fUWNOV{V zJp4HQebJtn9VwBLlJ&{b|Nee>dwbUT`h>fxZlTNm^9fy8d@;?g{ya+*`_Ya|%ac;3 z{QH00ecFL-d*|=3+q`*mBKQ6Oli%64t-qH1>$|--?`JESWA^*&Hf~s$F~8)onR3yJ zLwuV}9zWeS#rb9fD7Ag4G*who{IiZn)O>qomGShS%vmD;VwYz&hSr{${P=@G%$MHE zxm}VMcwfJhO?>7Oc~| E*0G4WqpiJT@obMvjs<~{%ay{xI(?jv4!;RR2bT-uu3Ec 3XqU$EV);|KI4tN7;)esfru-^M}0C%H8RARKlj b%L6WgOD+JBs0`NwTGG@hJg?ZDu; zSm4I``j3xT 40NZ|Nd}J*!U!|q3ZGX!|e{A_Vr9^ z-y$je _4zaB&;Kp|?eqM` z!atd()u#O7-*R85>erE6=DG3yatFQU**je9zh75yIO%&~O;3Q=uj|PdiY3amGLp}} z(|L1YuMvOqpZQM}`3}_nWuJJ%I w|d_{KX+4S?HRUgw_9~hu`|z|JC~Vq zMoaZ5$8NTu&+1u~r_cOZwX$)B28-0)WBTW`bal5Ey}iD;eeZi4=QEe@R 8irA`E`uHi);*TzmJ-=cV>shk*~_HY(Mun9531OxRA$z!Ex{MRjazPtN25L zrG6W5a~N&h+|2jr@8{!@r^UM+@7&pRI&2Z=zl6lrca8u4$AA4)y5ooWg`MsHS$9}I z(3?EZ@ONdP+;YY*Gw!YDxzWFCTP1_3OWoaL|Mv^32mkE+e0cLMxlGZ269UrY QYgao}xI+q-@L|9@6j)_xtU{rUffS?hnEWlo9C%Utnc$4=qNthMj=CjI!{9~$>? z+dQ%Dy?3=86ZIlIcepW^1$^9JuVZ9Xe%AK^Us&yLwi{tW7617Th1&HMc`sXQ ^YqX?pJZ%tU@Y$)KwJPL%gBSC;{rmH49PORIRR$jX{3qtj z rtA@6RB9?{K8EpR3wsorR ze-6h_H?Kc-KdR;M`(5PDojVUKpSYo@$f+-Zd70UQyII%sjT;t!Fc;q3&T{GJ-JG01 zjE?eR=iIIDNeDA^-xqgU(Di59wq3WjMo$o1bI3Sj;rFNa>(BKsSSD|<^H1ehAqoEr zi)K$OT+6p&lHJnYr^}9=umAVQd0uA1a|Wwtmw%PYi=8?Al&68A>DkjAJ9ad)^E*vT zU$|wfgk+vp }?%oqxM`t^#m)F}CbueyaivRm^ zSN{eL6~j%d9s1vdK7HQQvQyIjxPF@0w*B=_!q!#?#;vM)$YoHV8fW|aSkvBU#vJQ^ zsZ6oOoSQbTWL28+_kmEehW?V8H1_vie||sXo!umKXDeGy(DDBbe0%mC`*ZKj{0IBj z$M2W3`tkmFd7Sx$n!h*y=hqo3Rh{}@|5qqK_y6Zltlcdt%=bbyx!(VGymeMf{oJ40 z?|l=SnI)p{=$!G{U-y^&ep5k6=&cu5!xNtU{{8LkbJ^Rhhm;$ev}e>AHuxX;!?)&3 z;&GYIX`v2hVoo ^BHK zdd#lG@m-!d*;x1sN9GC+iNae}2X0iTQTcz+ %XDKNT+uqqr zOHcSaeWKtEhgPW{|LgxOH+K+BOBKD>p`q|tT6nV6rB=~9^7sC;W U7=e&`TS#Y`j z>4up9il>fOOMPdMj)|PtRU^k-ra7T`>y(RZHyV0bI!?{*657Fb iNkHhosa-Uj}H*?d3)|of$ zY+gV5YMt|dyYKHL@0&MnG+jD%^XAQxIm&+X_9wj%{QC0q^k4HNQ>-5!nc405(K2R^ z%(8U{|J3ZsO4H+>wtjEf=X0~pT0hf`6`nNXt&|A+s%O^f9Gn~m&3svDJFEXM+%oOv zmz~{q_5Xw<=FW)>c_}_~Mr=&w&sU}D? hj*SVIwzJ_n%*1ckf!p7O4+fr^h~dUF>eRoxyT8 zwVC DXD4qwpB10Jd&S#Kya@`}b`&e!j7?IQ@I> z8K16sHt84FT7PHS6RW=U>R(3llvQ1uY@Hr2J0H!%GhN=ke&6o$mtSv}AGoor Cs-X?mbyVP$PqrI %JtD{D zeFV?k!23rkITbQuD_&jE+@d<`fSsi}yR@5#k>H#hrYg}#RSAFoGJStjAGb#*C7bn~ zXrq2Q!*8w#X~!Er4nlWMvihzyH2k&mCgaSQISW3YzWMO4up3*#N{?SD!pb)^{5)PI zraE#uhFz%P?buuU)yZbEZ%$86!do4O`o9eFs>e92wzqKWa?R}MIP{(U`#zhph; OXXm5WgudQyLc9gTneoLkr2LosnhKG|ga&sE5jd)X#vaqu2 z=hmJcf2GHbOf?4^nGz4WoDnxlyv20VXMy#(nKLwI>hDQPT)HiZbN3>yo1a@Jgqrbe z(0+LGbSt~+k(rf_KM%kA7wz?o+fnf||E?$O3JnntVyhGWEPQh4|A$~k$qDBsx%;Ro zKbvN-gX8FbiGTl7f0X|IW*=eB^fINqBw11YNpkGJFY<4sHZA_pwNzJF{qWi!5>tP6 zTTTf%(dXngBl+Lo|L$%g|Neh&=d`h077+KJUuwq_cSRc+(9Vn23A}+J?Em)}p2&;& z@%-p%cgBrHv!@yTk#6`aU2k7|<<92EmHEqkVn6TCzc0a-k^0orRy3{7?zOf4z4tdY z-#k6t@I5ba5`zQ7!u)Q_;%_obUNT1g%}eocwSV&@xupJod*hdrBC8rsOJ3Y%JdLm8 z>i@cbH sD1bU&o8a{c}2E_-hHd0FxNK|A3O;RUmp91 zk Pb)b3_~ z_An;nRNW3%L+KYAO1B$4*qhJrSxS&C$35wxz1HjROTE`WdhEEpK6Wpg&+ML-KAz+Q zwbR5tr5?SpKAPdKnNr4|Kgut{bnmDySUAJ^!tWLC%MBOF&1DmC&|wZeQ}8b8|No<> z^V` Bi*;V`^}DbKc0A7F1B{A|9rc<`-|%jzw%W|Qi`2?tN!mF zSKZy~tRw#X{c-cbzv2&TGfJ2k7)=s(3ao0F{CM|1+3O!;dp7KT+i|jW!AI4!XYZE% z+iU$zdX`iJpYo312TojBuxzPNk*0- kpHm}OfNKFZ5Eo=J0ibGDRa@r3T#+6N4C zPA@Edp)Pmm3iIN#N6%y*zj!um*EjZaZ_*rI9eCX3)WMW6tH7lEZh4KkWMIYZ%P+4t zyYDi8C-}iGcaeZX1DmTz(+z(4dS0I=dy6J~Ja4}ykV9ot(&u#j`CL}N<^{x_ICSRI z_xJH<9vgpjQEd7B`nbNL;KKFs`voOi&&1e>tG0f5XW#6zj~_fHm~ivy=@kmci{G9Q zcdllWIi6B}<(pr;%}f1lQIk1s!uZ^I9
;c#J3HeMXa?77@=imIK z)l;th_s7Gpt;_%4-#&|n=d$|wQ+g+k*qmc6IrCxt{R4dR!us!14He%?m(RFygWcu^ z15?I@w_Bgz+&pvfk_U?$nVC~&s!B`q+rMAbTU@Zxzy6Q#+V@+-Bj&Ysn$)}A{r%u~ zFL#EY;^YaRALq}kd^u;%9C^DMp6~r`dF%J( Sed1XwT`s|PcA_@} zqlt(Ao*(}ov)_NoEbo&eVd>z_UD&sKU#s5dzkk1QZeZH8bS+=6ubiA7+oGh4kB-_; ztG{6V-r?54o6|qux9`5*A@S?a&(FKouHLzGXMI-YzrRNcj-Q>EXdtV?DB#fi{lcXG z^7cjypRek-Sua2LxWqQ6(|YxmGuNBhSsp(U% Fk;Fokcfq zD!grN(423b&Jdreu6@M6M>lQLqmF|?ODblrX{>dAIP ZYQOk zpJ%&b(S&B%8{5*qekeY=_!&R<>+km;Bz?Poe|xan-kBHJS1#iFRI7Apn*9Q4fs323 z*sCpDzax9sS!?q>6(5T}u!uM?IPU&to_9w;NNARMzFhN-?~E^RE!KSS=-Dr3mi_+( zWS*rZr*Zvhn)EQjzAi%X?4gFYX*_FUf1l-#JNLl(Wbv*1_%DscitE<>-T(jpMZGGu zQ@^*oyv58SkW}Ip6C+cSwtDK9gbt^Kf6T`eCK`+Gum9_0)-GGauJ|#KLu$&;f5OW+ zRQQY it?Vvy_Xgi3<>4OR9=2$i_OgZ7L)7TSM|K~&I(L<(l7G!f<-nbEA zY2ol%z PjAn^?_8r~;n=`jXLRp4 zzr17mv;)tixHomPc{*}|2LF1xyR|hmBt&=v+x~A3_hU7EYG3Qwf9mOjgmQxqAGUm` z|NZUn)b8;4_O%nmX7cv%NLpql?3rg(w@pWU3v+LLLwH08$Bp*cH!Mq^J~GvwzNU}g zvv4Cr>>_m?B_7Ysj_)2Gu&^k6vSh-B3vZ>%7d1a}J?b*wmesVQ;UiZ_+3#nvj)@0N zwXgmC^>y~lnVQOm(Uaoe-Md@e)WoztZV%Tt&eyN!9N>v={{7|SWk(@MDB3qQ&Y5$^ zfw%au=!Xvl^}o61=2-9eykTN%W5)^ugP!`j|D0!-9az=*=Wi Xe?~-z4q@X zQ3=K~I%od>YkZed`}vnHw>I|##xo8F3Z_q-Tv_pd;;uHSfX8>OzdsRu()h|>#`fvE zr@N9*>shi!n(~GQJWETkssFZUUgNogd)s+?zEu4D`S0)F?|*I<^Of-_3MwvOQgd52 z_jZ}2lypaDr{kQt^JZ9PAM808FoB6hz=X@&+k5x!-RuR+nASb`Z=d1a*tjFII_*m9 z^n$`4M!o_5^E)N?lzo$*wOQY;DsP1XZ`>!INvfIG{+*t#zh}>$W<@SWCJw7Jvhwow z5x<1yyxCv(PpvMG(d1Y!Z%O^W TIJzsKFCKYToaeZgUaH}n6hIlup+Y0T~~0(L0Bj736juC2zR z59jYM{e0pso7)!_R&(LY{Dqy-w_eHA)X4nzm>pwseS245x0FpFhk!$Xy|snKiq)(6 zh0I;mTPH97IBl8ML@nKW8*O}j!**AFUbbn^TXnxjYdOC0T33F&u|Vn=6UTys7H4>K zF1PPGI$_o8!~%xdi-Zid>}&p (iC~?68&h_Z|QC{{2+(mi77%A3d67Rru@H z+0|^(1&k~g6y~ms*qiN{n`oTr%cK8(zx=)bbzeFboQhz((8#*})~wc`ON!Q|r*61> z^s!@5K7a3y #ec^Wsx){=M_uU;p2(qUinl`2B3@4&Vw*fo*lU z-p? so<4l= z;J=TLmw%ZPa^i%H^5F-2br=*H*h)o=8m514I`sWqv;O>j60=_Y|J`2q|GU>R@f+e# zyt@)-eS3a?zpl;w0$ry+Kc`P@o#`6m^yl>T_4oJHrb{R>C^WPk3svsY;;M4nrK6*> zyl-yjH*cHDFD4Vto<4r~@aePqdZ&(@tbBd%ao43Zwz4u7rQ{70Cw{!ps2snqCQ%{? zD{?ZhT)3d;!TC=A$>Zm@H&k7IwKV(YjT@{ij<1d9 z*;eZ5X@*6`s^}{7zEKaTtylcZ9n`=ewb!-e1ZYdu-amO@y7v%hQZd7XtKEiyW5GoY z@Jd~`*~W_#M0gAsI243V1#)w9+ibG0`*UMsGW*SU2l999*;5k`Ah7Jmm6gF8SA~a$ zs@{8beSQ4?`v3DLIehu_>5%g8hlktm?k>Nqlv4Nq-`V5G+bebK)+I19sj8|zTD!0K z`MK-s<25;F-nbEAvnhOCjH2n2i%!jxCl~+x^z_G86Em}*7YTnlCo|UY>8LJb5op+? z9Tq6TvB+uNiB3joM-{ncpV=>Uu8p|C9rc6p+eQm-Y0iUsVog(9Z{6%LYiga~bVMX; z<{XxbdZ{cA@4aidQ~By{uA%FRH|O@vo!fGEZtedWEz?pRSFN&|>({Bi{%V%0kWQtF z3}5%6ik&fWmAmHaoVLF@{j}=Eiz!Aki+1+te<-kMacRANN?vruo{w|y_$}Xj`)$qr ze6!j9$KIDDy-~ZFBW5JjS+YC!c%gyh0-^4WyuZIz^-lPB$oSyJFK6F7>_6|3Z{pj0 z=K1ISO3oMAjrZTpTdZ|N`Lc dMT5@j~0uiDo-93 zR9sn?ds~9zdTIC3q>jsZ6Hisx)b;UPU9Z6 ^ny<#79-57_mKcFJr? zkVw5V@mlZvkkz3x9K| 0d0)X->PDQl9>7etr6-7w7lC{pXwTIcsZ{+3fz~%?UEcE$8}u{u$Ghc(88& z`m0$Q%QE-bFy2Yu94T|W`Cx-)qOkMot5G^)GXJ_?o=j=VoO1f9)8j=p#nX4)T{mH$ z&KLG$8eJ~?@8$`Vm`J5Yw&|{#n KufbJ5$xq|Ni61K8f6tZXo@d}Aw&r@arPzGNKXYR*B&@mq+NFgl`{3s5uUD@6 zmDjz;Yf{U^bslV*O*xIfDx_H&*S!w#n&5d^M6SMxCx!QL!RDJX{qA>|Wo%R;N_;P` zyRLn9PSnpMGrg7?&Gp-96VUy#Y 4e!)Sr>=uF+ix#qeo(aY$RlCK8%m{OnI=+) z9|rI(-1lQ&{MxXSd~F9B+vh!>dfA2RMd=b|*=NCgPnL%;+{oMBz36~Ru-`v 9}|$l!4L2%D|Y*?H~hl1H+<>25V#CUF&Y%xid$l_rvd-9=d#uTkR{&4(S$^l`V7L z;AEBQuweOe_esaLW?y%bP (M?zQ(L>)pkXg( zQ&(fJGsocz6F!*o9y@kSpl$71-KXzb+V@YLD!TSCivq*@)DmU`4yS|XQaB2wk0r~q zCvdU7@V&q>>(^Olg^YK$>PPr_oiCZhi#Gj;IB3Xb5-lWjfA_?o(5;GZWIMXqej2Sh zv{mdK$G??acV%BErG+M@1!*1rnQkQ5X!v;U8 OY5mqz+P Mz>5DzyT#|**Q+@{o@tz}(B3eCE3TQ*)^rkk!(F+cZV8Tto>LPT@7%rn@=eGm zhwyOm-b H;H`S$ZQ|35MZi%svH&}@C* zZqK(S{;Gb)Gk^ yufkh){2wY9A>QhXn33Tz3+3gp3ZH3&I}99-5V`0 zoIA&NWB1i7S7dV4dzu0r*g@NTO&>O~a)+&pseE%| 8#h*8?)>aGrWcQzMU-wVwo=uv| z>LVBYw>j?kcJHwI>}~IVx7KW8+Y*& fB$~|^r;~Aj%@q+r!Lj?ZE|0|oP_!6 zn ?%yxoMLEYFnNE&6wZHbi32*!{oqT~>Ah2cH?WhfYpbfBoV`&h2fv zTjm;YxiQLuh6&RTwY0D#e4A}ms+D5 A`t{0*apZEX$WE*s{ zZ))$+FYm7EeLH`@L*nAEuaDceFXCl?=lykx+?{#HzW>%g`Z{N(q@;e`k4bt9ncwiZ z+wGa9f9Pj(iShG&e`;n-P4DEmEU(08{wN`B)87MMX7gY3b=v&ao_WLl; v)i^YmQbDL?r+)nlah*V%=}eUVRfG 9Xo2RB z!$-DEd)Pi}hDKfSjTtk;@74yKI`#Ga{r! ;*5|NlGsu0gtgKFi Af`{p+*Qzv7FZ5*41^30*MV z!&Rc;^ZEA@eyR1EpH)Ju{nFf~?XN$tow37f)~=Hg?|%N7K9w^)Y|p2U)eH8BvTqPM zkbBp*Qk35;(ogM^`-=a6e>^;+^6=2w2%V*e4<9-3?fdyC$x>@R%WS@%uix)C5KcGZ z7EZq6zAW|9s{W%YZ}%4$3tT#S_Cx%0@%#C4b~bU3fBrw;;Q7V)*|XS5$t{cC96xnN zq~!HSCdZG}O-gS3am9~hId^ uzDh@p$p}_aX20 zU#R)9X ahEphrjzTZRuiTVB*+2>(uGfzkh#!uWq2A ztkKvv@ALHfRTJ4)=$|^n<8$*M+rRbu{w;_NJ$Lem!B_R={d;=b_nZw^6!ft#{`c25 z^6VY&GbenHJh*&4KjU%uYx}=zgEl8AJqu#aljDvnm1DcqckOZ7kLf?B9`5zO8tl^D z+Rc5r@=g!W&!Ai9WQyYISt9BlXY(;^p7S?+-E^f#3$(i$J7ypMFyFvj`J6@C&(G2A zo;~d|KP=MNR$p&xxm0g|<#_`K>#Q9!X7bAIt=CfH{3@kC|I+0CAF=1oo>^1&{ir&l z e~VDGpo4fop$Q0`}I~Ycc**ge9@h%Cy#u2e|mcKtyl5=a&9Mkb ye!_nGrP^e ztUhVO)4;v@dS_cowA7TjPxohsH@5wE&r|;M|9|`R^Ap2QerGq=-d6mxv2+&W;vfCL zzrULyZOky+>;C@ccP>9a#`e2*JvE=U?bz${@wygEcK-YCTz290xo_=_b^GP*DjvLL z{G#lY@&EU9T@Cx+l8xQ6Gj{CcbmPi=@V`Fc;C@lv|VBO|L^45e>3OKmX7@J`=;@B-qQNJyMLS5esvACjLO^{?Q-YatJs9i!Z(yZ z?5K%;{POqonm;`rf#*-0`&f6-X2I1n9g=((w#MrJ_;FQ!Pl0XyRMz#=XI4};R>fbt zI-yY4+<{@?Z0?&J!ZI>C?k|!U&V)Q#`{I+A*T4JU-)CLVGwkj%+_dT6|Bua#HMTc> zYL|2VZ|Nw%+rK(o&b7_Ue}3oxzGUmVu!G|M7cTvKf4o0JMdiknDI2#a&zK>8*Z$vI z`x}b(_47hp;wOA~f7^WP>+L_Aof}umq)50Wp85IR|E<1UlHU1${5lP+67`GD-ZC`& zTlZ X?o!huZ&(MKkp}LX3|M}qMez~`|`7()#9bxFR-#=$-jb*}BD`D~P z%=zEh NXt{XGuP5AtTly@>Vsf8$1 ZCe}>UabQ@Oe(3ac{mq*;Sy@>L?Z5l&_IG)^HpQ6#3wRIB z-=23bV8Xx8&v*^E?*@hM%T7JU;T;k0dc^kWo1GuZR{#6|Z|#n1`Q 6%iH|YGzT*Ucf>cp2HexF_=FOaHh5PAPfz|X3L`}fQ9 z<=a?1d}n?7&wnMper9Bvjg72=!>v$pr9F4l`tt-$UwrzQyu!kM)`Lmc<2R|8&Q#QF z=zN(OWwhZaYsr(}mYd&6yx23_l= ;%^D zeV4&n_4abx*Mjv|3%SkjR`y)`^ !Z=cFJF3uYXVV1>>vBAO;MrR&9I ztkLmXC0CuF_xs$LuKW!mmyT@R#;DY`pT*60&yUFGd#ZnX3%uO1dVjsBS-x{_hmr5D z$`{)9; 6V*C9JJ{L^9_cU>a%87(O zuf@fKMA>^RwiLK6dEo`FH;P^b;KaS)V!Bq)K*9 zY|5Y4)@k_f+~;g1A&&Kb|7!0q n+9kbh?i#?BDT5hix>l~La zufSC0s9+@3@nEguJAe80nVPk~Ka1ZicPQq|T7AN<{(Q5}kB`a*aSbX;$^U=uzU%N? z{mCsUC&k0^B1|qkOSWHSWa3a2b~-nCcimsBiL>l$|8uTcZr!&g<-pE1;oq<3o#x@m zILd= z^e^`PEg#{$Z{P1Hm)Gyt=xcw;Y8CA4^Fg0oy)yIN>-x6Z`1iIIzgTk_H8y?zar34` z;CuVZKku9$-M8=T*FWgoFp=^1CetlT3&Q6aW_ffSl0MU=)Z|{bcgNRfvdXuDEM_cJ zikZ`N$?5;a<7|;)dv+Z@;gIl9uINfZ@kSwIPmYkP-#=G#C1ig7D$4wh!Evj&&gr8? zZ%+pEN@hOUcR*iknzc~Qba`9Hd$ZftaBHkvxA22-^u&*oXZ}>te?412-q1-@@YbXx zrVMB2u187P@%xevO|;mk7cDHRdSNp&hk{P?=55=y<=@|TcW1Hs69q4uhW^QO`zN2- zx_Cj7__83+j_HiIZv`f_#@sdEzS`#R_4oE?&YY<~;CS-Xp-rz(NNOv~@|Bs1r9IpK z|DR!_&+qj*XV^pdU)^*LZQ4>?wBh>Kvnx;ZBqk pr^TJc*xN}s7(+b3p@%%iAj`s?TZ`1hFInEUg5 z`}#&k)}4zuq@;At)JsZUJ>oiZ#!S{9KXvXlm92^72r;O?IqSs)20y)X`|B4*HM~+> z$QbwN#1d8Iug}lRt8EZTc`kUv!Q}}P@A~}rxhr+sk8m5TY2b2*nlWQW;rUODya7Vu zsS4$9HPSZx|M}fN*iEWm&&E*o%z1q#yRRbarc2f&DV;dIATdYm#I5j_atXJN$I8vrYg_(p&YCqnD`r?MGX}Mj{eQf@z1_K; zkFmP#(4j*-%)AW?i+(=)s~^8#-mZ9Nd-vuw#c2s{YZoxQ@7>+MW2c4CX)Ae~%85Z2 zRdr6hpBIoMK2Q6=@!(5VUk_e>zA$p@@BaC}KYqUcUEV%2(Y8@Pe*edU; +kQ&@2~m!^R@YfMZfk%I+*s)Ys%YjrM%aw=F^|O?*6Q- zKeTSC-DX{GSM{yv^19~tb~THNGZ-HK_&i;o%grxI$!W9r`agev`-gh#>+|zZDExl# zu m9w{HbUcm&)&b@_;@zzqB1Q?K6Nspe40zh7PO?~>>OuY`8_TWTq3bw7Xc zZcsR_xArSnuei8)sOh%$maA8#w||qhJ9hf? 2y6^rvgrv*5IIyGy^nyPSUhYHx1TF13d3jC}V_hZZ(AxA&i! zXZ-%|@9#2qV&2``xBdN{kDqvN?9BfDJ$}DrWJI#?q(g@m->|4O%e{5z)Uj93Uh;-K zc=?w3On&tCw+RVpy*+)V1}13 {ak3kMs=+SVpS+0{Q}TKD@q zC>GUn^78WX^XD5dO7!)(y1FvU>8;T@^I!5`H|NLyKYj{JtloUf%OvK}m8mI>l0MF! zW_x$J2Zj|ry;gg9c9&hvzg^#NM3$9p>sckotZOQto~=7wf;E!UI+(d5FzJv}TO8*l zp+)=a{_>S 5m@@YJdG{?d|22So~ey zHqfwG@WJz|7ehYxpJho~xM$0cZU0`be(ry-`ooQ>(%bjf{TG}c%cWE0!&8!4vR3rT zlFG`8#KR^&uBN)`=jPN`yp*`$ Ae|+x$t*r}y{w|NixhDOG&SlLc?r#BVA5uW JD5q%)Z|Hma@ZrCopT$eJ8@;`? zL+FwdGh0YVkXntl@HK~Jzrxhi%(neMu<613_^jMirl$WZY~AhzI#+04-oL;8;c?Kp zKwiEt-o4{n!~FTvr-p^oCQM+k{40MtXZEU?oJxD)U;kXsY*X3xO?A`%&a0<8G}+!P zJ92OLvJ*e1bIy1$v%!~v?N~ieaVd}d|3A(*Bu{)!`ypbO^m^msjQ{`N|JRSG<*-um zcURWg%d`4#56iWQ#*a#MI1hg9pE~vT$HVW1E=7nM3w_cyEIid=9<`8J;#1KF%i4q! z5z#Y#wH-5f@Rcp?ioqj(y%? &2=#hq+Ju;@hT6*5(_)JO?nr!v|@4vIN zB~H&4Iey~cM-8pUkFU%1+_M)p{n;PCUqEk>#L4xXGZmg6zpzLx#fh6y?T_ih{rUA< z`ro&I>6*XQwEo66_wRpZ)^Bh&|K}LCeR7zv(ZX+ag=d8)Rn )uLgG|%0 zGbg{M{A&5ld-nf7gBR Kp{c^?XeGmW3vrXoe zcCr22KIb 3{t{gP=FQY(iI!ADS_S+6o&UGb%3J zKjX^h9m{4uv~NDu6xqb6_&;&EfI*V=t7#hflUB*qzez4-6Wqut!pNZ@)?|AwKYoAh z&o8XH!cP2?)s43DPV(V6qNF5~US?EO_%|=(@6^z92M!)9tuarTd_3T6i-Dt TnAP|1|9#8-j=|xwYt>ZNo{(2DRW$oLA@T43{`r4C zc>Xwl=78bW-lMmKHmUY>nJP+4zdrwde^j>B`uLqQ=grS~o1m$p^W*pR`TIBMu };2 z{jDqWz^v!*=kK3l;@)Wa`Fel6=fg}()kw2%Vfzz)FX{9Yb2-L0tJ=cCLhM{5&zZ@d znI9MY*3Fp4*_eCI-+J5KZoib2qzP+urmR` g~@50#@21XO5-z_Z+8@`|4TB@ro ze0hI#x!vkn%-x#vQiErH`6|KjHull8hkl%==WNS(bm{D8`}#jVdwS>i^nBcIzuDM0 z@$IKSe}3n8&N}eD{tGu_UfQxQ>GQWjj?@_#)&KnT^~TTU^YiWO>%TS4U96kAS5{1n z?Mm{VMy31b=I(v{@c4l<3bQ6B{rGrye}25;-@Ssf?=diCY*ABL)b-%epPP3+W*>E9 zGZWkQxLVQsLEsf*W9HlIj`PpmQnsZj=akw?os_?SZ+~9T^1QxgCeIAXZJYP~V&ARU zBW9{7u))|czv{=L$?mg0+nYT9lbU2!|9MNi^Q+hU|Hs^kd1iIZZCTqgF*Un?ahHsO z?Dzd|;oF#G{Qvpc+2wa^uJp^MO`XR2?fX8N8`btUd^5fuDY~pGeOn>dPwUvf3u`$U znKDd-CtdJMe)8zon>SzoUyT+scAm#t{I6MD>0i{&XUBVP>ZhNdG<|Z?^91#+bH6=0 z{9MM*HBCuO?0;g?ynmlJPEnA*YOE+=Q}NmE-FgLn?sG?_?@P|q-e>nce9E8R5+!MF zV{U`=IE(6q%NNJH`!C V^1^6oG*0Gg_Z+TYUDtdVho1KW6jis#;w~y|for_OorY zFELhhVCYSAx@7HrAnn!L+w++xOGY%@oHX^}{rqY1JfdyWE _XWM7}d*vLf z4E{M=s{ej|Ra;-{bi|S+OVZCJI@mUUuon*g*v@_}$SLG>OZ|U0o1gz$;{{Hy-0I__ zuYKx>^{xwj{J;Ob{?4|~-f7RBh`lGzAHN=R|J(cb`+xPd3EMRJY +m&!>7%x)$ zIRE-Ors7$Dj;$>^9d`FpNV0>iA?J!6{r>Bo{c~5-@(nfKyrJO#ug+=A^>_Ccd%OQV zeNJ|N{Qg5hdd3DP8nctvJh;64{LiC1TT_4Dx2yfPKlioB^MudW@0*;9otl-s`}NB& zumA16_@tSWfhnUTp{?Y=sb42A&AWPQ(q@(Uk^bM?XH+<4{d}`ZCdfFkXU&1R?fvUI z7s+HEU$>G~M|yv}#rN-LqYGF+bx-6}mDk!|dvTr4kAAP}_<#TY@Aq-N@JN=~JSg+b zvNem!o~qsQmAmk%y)%>Z_jdhyj` @8)hmHK7ps`PAS !(=bgVly8RiJ_Wbxg{o!?eH@_p3KIHGOpFcJ2|F`*#Hu;-2 zZ2Gn9=X;9{Z+~xpzqr;ZMX-UvX+7ud+qY-VXgJxRt*zZXcW&+FWxk79MP&*K3Ro;% zjSP*q`mAVw;;@QAIrHMr{c^SGsejL&`7^uo=kxygI&Nw{vu^FL`@>Sy_`;g|^&ETu zUX|92C+qLm|6e;j>HncaY#aHS{%zRw_u;d~;(DXa=Td(B_$vSN>;wDye>t~y9=v%= zbjCWj%R)vB9134%36vO2+iI$>|9-N%|GK!nR#sMA)0wt$r+qo^dD`D8xc>h+X4O#F zplqiE&+osl=ZoDqctqgf?CW_evsVkt>&V;HJbCtrN$Tj~)0?wz%T=pKcZgiLQM%gf z2m9}X%HoUu{g^1s=l5-bYJN(7D$_I71idEz_J4nVettcD{UN18EpvHe-A-?-_&2Fz z#)pfu1oW5$9A20{>=agSxO>RGUoJBvqem>T;K0eF8 B+^*XBz%Y z_nY(l$)hiuxhsGE30;u i) ;M0|8*=&A+1cA)Ps?v`H_(=T z{YLZiwRI8KZ{M=tS$^y7>~fo&8o4|5GbH9|=_rZ3ko)!G;Nlq%T6S-L|NhRd(^2>5 zbxRjs ~Wmm2WpK*;DuR*xhr#pMIVm##YuZ zXBRXnfLW{h|G&M9cD%ZJ`g%i5LS7F?&%WZ (A?RysK81yr0 zD&qK#QB74@lB&{JdR;%__qAL1f?Q)IHJB_-WoL90dl^kX6Du}Z Z?;S7(oz#cL#7=!di3e9dts?!z~7b0%Nr|0BUwXYnQ!l^`Ln0% zRM-1^dxXUVZR(z!?VoQyQU7nvuO~CtHuG-Cs{Qw-bywS}X?@RDPha1Vr?Fo5?}vZP z2I}1%T&J~9RsXK!= oNPG**^ox8vOAH(N`v)W!gcJE)Bx^&TFrHlHq zfBWmYUTH9JDCkW7x@gg&Z{NQ0%iG!1{`!(pEOO|^-qiW4w+kOuxO0Vje_2 Q=)M{vi~%Tp5D67y^}9( z3UZ&lxB!y<8(o)8m@r|}rcXaVKX>oe;P~ D!sIt%{A?45amwK(!>i&Pa`gi_@2m9^!?Psa7x4k}T!ExT013GcBQJdf2 zc&9&qe~+Jp66hR!$r&F%e(db+y}Q5O-eBv@nKOIa_*fW(d#ClWrOZf?XwcTb-}*;5 zDf!2FjyGlh{)eB^+xO%jcU1H#{R8q(q;Flk&UbT)1=j>d2Zn|HePN-Yj3=Gj`JO&` z($mJbM^<8 8-DX3i*jzwfrP&gcKn{jU~J-;w+F-~S&U-yddI z)6-k SA_2a*gc#b$0gz N^lL-a)BXDM?cd+}`CN6WtXW=~+wS!L|2{i? zmp9zB`F=?7uTAyx%ErbU_U&D|_8iAPF|jG(H*cJ|XRv8f5woGeX2!#bM<<0Y+cj-_ z{@ui+q)AhzSd?V_zrVlUJ(znUgF=Iw`PWJHOhWAH?#`L3m(Ja}yPx}%>=qaQ1&jx$ zxX rtS4TJ$vWB(>lCNgX3Jx#{Yk_zt5cAJ+Y l1q-khn^w(j)N=|J_Q^iEelO zJ?wsb{Oj%-Z1}{iA^Q6J64Nifv+ipvs4& <)3T%+=Li>X<{Pwt729zHa@yw$4c-GU7(HZ1OD-t=qz;>)#H7#J8$qJ)Ef z>TxBM3r1M#%-Z?oz`Mf_3l;A*%EjD?Iq-&So~?S0&Lgpd|9PIUa+mho+}T>%zir;K zEj=d6!oo8*+D8cstpc?LO@uG~agtC-NK1V7=*gc?KVRQAf3G)h@1GY37k|&U-&6Hd zYLk^n#8nP1ZVgTC7gDb}yt}wNIhY %E(?;#Nol_|U;>ZDDEY+s{g) h`sZ zx7KgypR`IyUH$p``S$<+{^sutFgV$f!QcFTCgZbv*Y)G`Z|_KceCzBbqoAdxN4dN{ z-QQpPzrSjZA+zZ_b(yuCo$EOnnL0kq{d&;TuE VymyIwpesp%`VI$!~ zSB)Q@YdNxwIgp9}a_|z~GX{nRj@uMAZrISEKOv=Q#>emP@7F(A!>RbP%u{2UG`Hl$ znJz2T&A1JdSd=yi`dBpAUPy6jU`Ud=yT_W#?cf0>&@o2BeNBM|2SAD0_@RabD>DxR zsKbLrup}W(q^F6I4V*ME ?nPG?R`bQ==RN h^Rr4{y7-md1x-fHuY+on&Q8Yt9coOb5GdWX=^sX2!~vhVKh_V)2P!{5XEV~5kT zTU)c!&(Bl6_ifiMD=#OuqBudh1*=zkds@x3uea0J*RRu!-(R=4@G+Yz-?8}?jSF_| znsvyBL!e>H=1fD4o<~2fv2WP)#k7XiDaoVKGxElXKG8C M{rBTFMA(`ek0u>lcKM}5@3H09ck;~l#@)}`esF7)@6sUM>E0V|zs=hkb^UsM zv9(NJg29RajiQ}06;^XMt+<%6;Nz7zrHLn=e)|62`-GJYpQ6p|vj;YqO7Ki@yyLZ0 zsMjrd -fJ_*u3#)E!-Ki`z~MVo3h`RWw+hd^ ws8O }(c`D}`j+GNhugdn}?lTW7D$o=m(T7Fq`{&{sF&JPtf$0llM zq;1}LGso%D%Mzy@5jsLgAA2hAT=aIWh5G#Y-{T&i_)+2ap!3 {*SRvCq36!pZl^#2)(;A52eX8HxRL}N9a#*2hR^U->rFeT$JQ&h z@n%m`f C?9Bbh7a`7Pf+aiXA_ z;5_f>wbP~st=w`mXU&^3>!V`wUP2;WIro%JX8T@?_ v7CzzA =?O?qP7`{KR{HD3AO-&3~W z{JZbfYg-c5h;X&m?f?Hnq0(mG{r59{((LBnZa(-$a`~cDyPi*0_xoC9dyd 3Y*I zFSj`T^pXmPglCn7%qf$)@c+LX`KKg&O}VoDxjVzLcM_?I3LQ)vI+kn@ V?W1~&g_bEzwI~Ejcrydn?=ssBpDY`{eYM8 z@`SYi;u^`So=hFbA2-^1={=vlY-ikhp`iBo(+f8ovYCH=^;Ir)x3B*SEY@7lcJ(
%sXc{yM%3iYqi~c_PiS1^*tW@Oi%d!=UZMA z{P&a1^LhV7gpKMAuk%fvmYh~%BgZ<++n{{oy6kzgm1oEI9c1^~AXS@I$$j9a>}&@P zmOutp{wI8I4(J|oIC#WkgOT#?4NTfb8`!ybu-`k$R=#P+%ndsp-?#sNUL`q8XxHO) zuUD;Fl&IK}dplzCJ?7K0-~RYn zDJxDVJ{9wfyZ-gU@?hCZx7+5wU;ld6dF|>u!m;hYE&8SeY0v%?%OxGoalY8tY(m*Z zp}sFSCr?P!iTU^-)$2)WB-3&YF0}>b&l+Psy10d~|9-EVs4@M)0lgS8`;x-XHjDKO zEB{EY*N~Ty>fbw+?biNfnR*qALLFV%eJ_jrXZH%4ID`NCW}m&McoMC7n7>}Uo6xGX zF86l$7wan(2jdOOxaO_){+b%eu=Tz55u2vD4VTv6cG$}*u<>l*8it5_%&%h-EZIx$ z{10qkX|VNA_+Rk$*46`;vP?`SFfK{t)LGt;IsIH1bGJuAqyfia7KH|lxog 7!C_X$6}R4vTTA(#Z}?a)vV60>o5h~) zD>V;4GO>!zpEe=rR@CQv$&MDAveyQA>2REgbe&-Je9N_a8>b2cd372lIW7%3XSuXx z(YJf&EEimhVn6rg9{-YgtjRo5H9zw@iurCiapX_xHB9FD@KAhiRJMeK;t^JVImV3L zWg=Wo5*2>@36Cq^ zPjzUxj=!nPe-#pEFS}e&3vs-hco8Ig~SHI|Z4}nmwCYI{!e6$Est0{?sh!Jv~i# zvHuAdcX#I3xk}orH*GS~)zz&i?UiScUU$HSH8S4Sl0hwS!PNtP!m@{06dEKnuJFG} zow!`^#%^W*#e4SH%r%|Fu8{ru1jB)Ml9Ia`-oD+Mef`qSl}{KGt}P0*QnWVZ%V`1~ zq TWiH5y?##}pY I<-ulwzp_7D;&YAuD>UZud{wM#Uw0^_p^Mb2pNKE+A;}hWA;P?0M FY z*Y3~1DfO*MKT>+nuFK-WtnK{kY hKkt-pk|D^X5&Cz1{x$(%*0FBVrcp6npOZ zzQUQ| (n`&zI*xT)|{{O^GZvO$_XHOpd`2G9&_3Qorofb)lPUF0qct%I3zW)EO zj}Jw2)MWz|8GIEz7?}!nxw%jOumAt=-ygP{{H&Lcw3rqyV&@R#?3~!i2_AWy84wj! z_59r2ix)4h4qF=(9?rh%^7W9PUw`vwO>p#0NlIf=l}Qt06Earx;GXg4yhoH8%dHa} zN|7@p{t1d6DUhD&Af4`T-Sm&Th}D%7Ee`t|-|tCEQ_&S}k~zho=y|5)LP%#v)FUIs z8(tio` ZHS^O-+I#HyD$%+9ynCd^zX6CF}QZh0;H=S*{+zx6iFa?io z8fa^0-`i8!)zvk@S-|a}h6L*tHU`F)d7RsGZ>uRQU%q@fI5N^w%4%_f$OT5w&~S0d z>1n!RVq)9#@0*#L9$nQqb7toGkKFbD|FQQM8`S>zQ+oYk@&AC|>t7U0WPCSn(%Y2s z@6XfQ=akd`{r!F3!NYLVNuM)5_v`=ND*GVvM?=nJw?rXNl!38f?f;L(zyCdc@G*kz zjWQQc&kEZzw=4fFZgH?@d^&a}AUq^OKx&H48R>Glh8r9??t5zfmYtsGJV8+VOSh)v z#`0f{RXcZB#P6xun|hrwXYpbli#9O_hK%#A+SmX8`+NLEgRad*UdI_nPaR^~QuugV zY{%)^!d+tRiV|r|y`Mgpr8mx1V)jwbHqUG2Nh>NUytA)5|M0Wiia$)-8+v=c9zNdx z+ANQ4sj$vs3k^n&El=OxF3-N6-?Ef<%R#v}&N@92?u8C7=ls0AJ%9D}b
?s($f(YvIt&*|}_|Mfacg?27p9KXM|`v1elGgff4aQlQ@Uw7Zc(5T_4u`;s_ z6X#B`7iJYDk7x8bx$s7Ow4da}FhBl4@|7Q_l>aENyK&(3bbU)p%gP-)Cob1uVB$C} za`f}_^V4;sw^e`73l9%p!^YSh?XpcJIYR!p3X5T|h=ZxY?2}wcNooZh-?){7zO^>k z@Bjbr*VoyN7g*RPu2aqJYVt7NnCj%Fq%PfYuEpNaPo7O}#(ewwhnpr&$PQf0)~-{j z=y0Zld!?tiztgYp;-?j_GcdN?Q|IC2WSkTj7}(A)FPFQfAHKaU(Z!{ut*vd_wr{t# zX1hD5BQnMJ_xJO&vwy$4Yn{+tVp0Oi70jSq;q&9^>FMF?;}|z9Z78-tN&NTs)gIt` zIN!eh+nbxt#}=j)e0Y03zpiZC{g!hktlvVn*Zlh3*(|-X`fS6c@2(oHMfJu;YMX2S zpKd9BX=yC{_^1DVogI<;428A^zW)FJf6o8^=YMfUF?GLT_^`o#g}v^_@5^^9sBi5{ zPfbm-`t)w|VuADKMZSA}KbzaN!eHX_qniv2&sP2VCNFG!%YnIM&l7v+#wiN7zVbPk zetu{7`|!a=!|w+g43(Ik{!dIeF-;`xK;b6aj}N|ehi6TCbcCJff~xd;`#L7cwBs|3 z7`xoMIk`W66q?Lo5fO3i{$BY7i@pfo_SO1uU{1-?U-4>cZ!$%1>zwG1-@nSI_y41P zB|IDqOdJ!ZoS$c#os+Yt ^q{)w0WfB&ic-tT_K;+_2g<_gLG?A|Zt{HmGWYw`U~ z&F8v(JyxIX=WxFMd%4}zs3~LZ;?y@a_D57Y%CGXPJ$qv>uX(1$riUkQ4b%30waKh( z+=aKF&Zz&d_gLuBv9)C%PxDV_VXb>`E?nTizxVSGE{(p=!m>+0&VJe2U(JGx`5Iby zgfGj8_1$;5Kbwg~{+~gJVALO80f&xVPA)DkadG!9T?&eh-o0hZlu3; 8;(T<3iHU-_~EVAZhB2Me{o+8oqq$ zpV(HPxWDq|436uc@0{r|oFjCm{{MrIcil8y*_KF$oahnhI$y}%=KpT)@ hn6WDKrR}F%~~K+|K{_(W7;7d#m2wGCdL7mBQfHR-bw+??4Hg&e!gpQ)ax_#5iMW z=f?}n?d4Ya`NYJ0P&xbU`FA%_W&1K!vpcDb2Hnd#UT^&KxB31b|3gX7@6{{bu9WfV zF~0woXQJ7IBu5qfb^GhBo|H_sGb;T1-+hVY{QWhy>dTo@YD5IBzdy5e{95a8zd_ha zXTs 4OkDST&t*7<>e7o9PdTOkzX12DR-&f( @a{QEP%?xmFV(Y4u1py71uyyxfUPS=m$SMZSONsGVH zfm8G6 (j@kAF#(&QK(Z01j_jK#b=?$q17fe{Y=4!M5{TUm!7JS?H z|Kt4j54?|Nn`3ye^(RHK1|br(ehRhWSnAJzVMY|KDBl$z~~&e}DTbeUMFJ!>jHe z$Ir9nMKYSEeL7ui{J2=aApiWt0HtLrby{j4e;hu}c&6#VlXt)0iCf>uKJ)+I(LX5< z)uu37M9ip-uTA~yzT?lMq~zCo3&o9ZZ~pUdZN=Y%k&KFIJkAZr v0t8Lxz z|IZxea7nrPZ=Y5#P`H!5#^z4XcWvfzW)FJ #c9iu&~^%5?W}QT3_?KEGA0OHsZ#Od-^lJC;kj_>+z2L|M|n3`fsy7c_^maw9V9< z*VsL?^{H#+OI!BY=9AS7iVLn3aTPt%+g2eV`T53=3th1Z4K*>_pWVH4vqwiKBa&O9 z%5J;d#s+UmF}Ah?r?(r;w5&9!{rLa?cH!fJZ3kz}2>Q4ASj>)NJ|~VJxbms&Rf?OK zn2{4Gg%~fKK7IPUdG{8%cHg>n%fs~b<>~96U+sz8YFdADcXZ}^$A^a|-Trk;Cnsm> zExj0?{~o4qf4{t(U$yI_sfUDQnuc_7!nThU6>{#a`{&wCoyck{Zusd#-cLSjwI|p8 z6Z!>px7p?2|E6IQp`akJ;%{Z9U{u!Qv>)^T&+YEqp>pEO>+61zykb3xo@#dcc88_S zzqT&XVQpoD=d0EkPcG}<-!RMU?Nf2Sx_#1GTzlTV^J4Ee;^w+nyy dCs#+?Q<+ zNSQuiXSdD@?&@s*ylj=y>MbVSGj8~%R;pdur}X&$|Inr)n;w>1>+H|XJ1DQ2(sO*v z-O5ACDl8?^>!(k@)VTP+U44~=*qOtpqza#F8gE;`#`X06p7Y(a?lf9{ST^g@{qpw~ zyuEp=w2e0{j8`g%j(Bo%clm;cr}FQw wC$Id8BCbU$;iZEE36m0>&v~p)md3tzP`RodTkB<`ClwZ{{8>^|MT&eHb4LS z|Mzs~;K`knU!Q+{T_$Huaed)rDa-!Hi#Sv|{`1K3uV3^!IdP|={@I1g`(wF{y*b!5 zE^jh0TDIXdqx5-=s+lwQzqzw+%YT8@O^eR_ah-3LmvCr>;W@1p`~UyyUEwAmz5B@P z=NU~0F6>a$J}EEsP5$