Improving RLS planning
Currently, we don't produce very good plans when row-level security
is enabled. An example is that, given
create table t1 (pk1 int primary key, label text);
create table t2 (pk2 int primary key, fk int references t1);
then for
select * from t1, t2 where pk1 = fk and pk2 = 42;
you would ordinarily get a cheap plan like
Nested Loop
-> Index Scan using t2_pkey on t2
Index Cond: (pk2 = 42)
-> Index Scan using t1_pkey on t1
Index Cond: (pk1 = t2.fk)
But stick an RLS policy on t1, and that degrades to a seqscan, eg
Nested Loop
Join Filter: (t1.pk1 = t2.fk)
-> Index Scan using t2_pkey on t2
Index Cond: (pk2 = 42)
-> Seq Scan on t1
Filter: (label = 'public'::text)
The reason for this is that we implement RLS by turning the reference
to t1 into a sub-SELECT, and the planner's recursive invocation of
subquery_planner produces only a seqscan path for t1, there not being
any reason visible in the subquery for it to do differently.
I have been thinking about improving this by allowing subquery_planner
to generate parameterized paths; but the more I think about that the
less satisfied I am with it. It will be quite expensive and probably
will still fail to find desirable plans in many cases. (I've not given
up on parameterized subquery paths altogether --- I just feel it'd be a
brute-force and not very effective way of dealing with RLS.)
The alternative I'm now thinking about pursuing is to get rid of the
conversion of RLS quals to subqueries. Instead, we can label individual
qual clauses with security precedence markings. Concretely, suppose we
add an "int security_level" field to struct RestrictInfo. The semantics
of this would be that a qual with a lower security_level value must be
evaluated before a qual with a higher security_level value, unless the
latter qual is leakproof. (It would likely also behoove us to add a
"leakproof" bool field to struct RestrictInfo, to avoid duplicate
leakproof-ness checks on quals. But that's just an optimization.)
In the initial implementation, quals coming from a RangeTblEntry's
securityQuals field would have security_level 0, quals coming from
anywhere else would have security_level 1; except that if we know
there are no security quals anywhere (ie not Query->hasRowSecurity),
we could give all quals security_level 0. (I think this exception
may be worth making because there's no need to test leakproofness
for a qual with security level 0; it could never be a candidate
for security delay anyway.)
Having done that much, I think all we need in order to get rid of
RLS subqueries, and just stick RLS quals into their relation's
baserestrictinfo list, are two rules:
1. When selecting potential indexquals, a RestrictInfo can be considered
for indexqual use only if it is leakproof or has security_level <= the
minimum among the table's baserestrictinfo clauses.
2. In order_qual_clauses, sort first by security_level and second by cost.
This would already be enough of a win to be worth doing. I think though
that this mechanism can be extended to also allow getting rid of the
restriction that security-barrier views can't be flattened. The idea
would be to make sure that quals coming from above the SB view are given
higher security_level values than quals within the SB view. We'd need
some extra mechanism to make that possible --- perhaps an additional kind
of node within jointree nests to show where there had been a
security-barrier boundary, and then some smarts in distribute_qual_to_rels
to prevent pushing upper quals down past a lower qual of strictly lesser
security level. But that can come later. (We do not need such smarts
to fix the RLS problem, because in the initial version, quals with lower
security level than another qual could only exist at the baserel level.)
In short, I'm proposing to throw away the entire existing implementation
for planning of RLS and SB views, and start over.
There are some corner cases I've not entirely worked out, in particular
what security_level to assign to quals generated from EquivalenceClasses.
A safe but not optimal answer would be to assign them the maximum
security_level of any source clause of the EC. Maybe it's not worth
working harder than that, because most equality operators are leakproof
anyway, so that it wouldn't matter what level we assigned them.
Before I start implementing this, can anyone see a fatal flaw in the
design?
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 26 October 2016 at 10:58, Tom Lane <tgl@sss.pgh.pa.us> wrote:
The alternative I'm now thinking about pursuing is to get rid of the
conversion of RLS quals to subqueries. Instead, we can label individual
qual clauses with security precedence markings. Concretely, suppose we
add an "int security_level" field to struct RestrictInfo. The semantics
of this would be that a qual with a lower security_level value must be
evaluated before a qual with a higher security_level value, unless the
latter qual is leakproof. (It would likely also behoove us to add a
"leakproof" bool field to struct RestrictInfo, to avoid duplicate
leakproof-ness checks on quals. But that's just an optimization.)
I wonder if there will be a need for more security_levels in the
future, otherwise perhaps a more generic field can be added, like "int
evaulation_flags".
In [1]/messages/by-id/CAKJS1f9fPdLKM6=SUZAGwucH3otbsPk6k0YT8-A1HgjFapL-zQ@mail.gmail.com -- David Rowley http://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Training & Services, there's still things to work out with it, but I mentioned that
I'd like to improve equivalence classes to handle more than just
simple equality, which seems to require "optional" RestrictInfos. It
would be nice if we could store all this in one field as a set of
bits.
[1]: /messages/by-id/CAKJS1f9fPdLKM6=SUZAGwucH3otbsPk6k0YT8-A1HgjFapL-zQ@mail.gmail.com -- David Rowley http://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Training & Services
--
David Rowley http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Tue, Oct 25, 2016 at 5:58 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
The alternative I'm now thinking about pursuing is to get rid of the
conversion of RLS quals to subqueries. Instead, we can label individual
qual clauses with security precedence markings. Concretely, suppose we
add an "int security_level" field to struct RestrictInfo. The semantics
of this would be that a qual with a lower security_level value must be
evaluated before a qual with a higher security_level value, unless the
latter qual is leakproof. (It would likely also behoove us to add a
"leakproof" bool field to struct RestrictInfo, to avoid duplicate
leakproof-ness checks on quals. But that's just an optimization.)In the initial implementation, quals coming from a RangeTblEntry's
securityQuals field would have security_level 0, quals coming from
anywhere else would have security_level 1; except that if we know
there are no security quals anywhere (ie not Query->hasRowSecurity),
we could give all quals security_level 0. (I think this exception
may be worth making because there's no need to test leakproofness
for a qual with security level 0; it could never be a candidate
for security delay anyway.)Having done that much, I think all we need in order to get rid of
RLS subqueries, and just stick RLS quals into their relation's
baserestrictinfo list, are two rules:1. When selecting potential indexquals, a RestrictInfo can be considered
for indexqual use only if it is leakproof or has security_level <= the
minimum among the table's baserestrictinfo clauses.2. In order_qual_clauses, sort first by security_level and second by cost.
This might work for RLS policies, if they can only reference a single
table, but I can't see how it's going to work for security barrier
views. For example, consider CREATE VIEW v WITH (security_barrier) AS
SELECT * FROM x, y WHERE x.a = y.a followed by SELECT * FROM v WHERE
leak(somefield). somefield is necessarily coming from either x or y,
and you can't let it be passed to leak() except for rows where the
join qual has been satisfied.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Robert Haas <robertmhaas@gmail.com> writes:
This might work for RLS policies, if they can only reference a single
table, but I can't see how it's going to work for security barrier
views. For example, consider CREATE VIEW v WITH (security_barrier) AS
SELECT * FROM x, y WHERE x.a = y.a followed by SELECT * FROM v WHERE
leak(somefield). somefield is necessarily coming from either x or y,
and you can't let it be passed to leak() except for rows where the
join qual has been satisfied.
Right, so quals from above the SB view would have to not be allowed to
drop below the join level (but they could fall *to* the join level,
where they'd be applied after the join's own quals). I mentioned that
in the part of the message you cut. I don't have a detailed design yet
but it seems possible, and I expect it to be a lot simpler than the Rube
Goldberg design we've got for SB views now.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Wed, Oct 26, 2016 at 1:20 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Robert Haas <robertmhaas@gmail.com> writes:
This might work for RLS policies, if they can only reference a single
table, but I can't see how it's going to work for security barrier
views. For example, consider CREATE VIEW v WITH (security_barrier) AS
SELECT * FROM x, y WHERE x.a = y.a followed by SELECT * FROM v WHERE
leak(somefield). somefield is necessarily coming from either x or y,
and you can't let it be passed to leak() except for rows where the
join qual has been satisfied.Right, so quals from above the SB view would have to not be allowed to
drop below the join level (but they could fall *to* the join level,
where they'd be applied after the join's own quals). I mentioned that
in the part of the message you cut. I don't have a detailed design yet
but it seems possible, and I expect it to be a lot simpler than the Rube
Goldberg design we've got for SB views now.
OK; it wasn't clear to me that you had considered that case. I'm not
convinced that what you end up with is going to be simpler than what
we have now, but if it is, great. One of the reasons I did the
initial security_barrier stuff this way was to avoid inventing a lot
of new stuff. Subqueries already acted as optimization fences and
that was what we needed for this, so it made sense to me to build on
top of that. Now, if we do build stuff specifically for this purpose,
it can probably be smarter than what we have today, and that is fine.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Robert Haas <robertmhaas@gmail.com> writes:
On Wed, Oct 26, 2016 at 1:20 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Right, so quals from above the SB view would have to not be allowed to
drop below the join level (but they could fall *to* the join level,
where they'd be applied after the join's own quals). I mentioned that
in the part of the message you cut. I don't have a detailed design yet
but it seems possible, and I expect it to be a lot simpler than the Rube
Goldberg design we've got for SB views now.
OK; it wasn't clear to me that you had considered that case. I'm not
convinced that what you end up with is going to be simpler than what
we have now, but if it is, great.
Well, we already have mechanisms for controlling how far down the join
tree upper quals can fall; outer joins in particular require that. So
I'm thinking that it shouldn't take a lot of additional code for
distribute_qual_to_rels to handle this too. Admittedly, the amount of
boilerplate elsewhere, if it turns out we need a new jointree nodetype
to control this, is not negligible. But I'm thinking it'll be a lot more
straightforward. There's weird warts for security quals all over the
planner right now, and there are still some things about them that I think
work only by accident.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 25 October 2016 at 22:58, Tom Lane <tgl@sss.pgh.pa.us> wrote:
The alternative I'm now thinking about pursuing is to get rid of the
conversion of RLS quals to subqueries. Instead, we can label individual
qual clauses with security precedence markings. Concretely, suppose we
add an "int security_level" field to struct RestrictInfo. The semantics
of this would be that a qual with a lower security_level value must be
evaluated before a qual with a higher security_level value, unless the
latter qual is leakproof. (It would likely also behoove us to add a
"leakproof" bool field to struct RestrictInfo, to avoid duplicate
leakproof-ness checks on quals. But that's just an optimization.)
+1 for this approach. It looks like it could potentially be much
simpler. There's some ugly code in the inheritance planner (and
probably one or two other places) that it might be possible to chop
out, which would probably also speed up planning times.
In the initial implementation, quals coming from a RangeTblEntry's
securityQuals field would have security_level 0, quals coming from
anywhere else would have security_level 1; except that if we know
there are no security quals anywhere (ie not Query->hasRowSecurity),
we could give all quals security_level 0. (I think this exception
may be worth making because there's no need to test leakproofness
for a qual with security level 0; it could never be a candidate
for security delay anyway.)
Note that the securityQuals list represents nested levels of security
barrier (e.g., nested SB views), so you'd have to actually assign
security_level 0 to the first security qual, security_level 1 to the
second security qual, and so on. Then the quals coming from anywhere
else would have to have a security_level one greater than the maximum
of all the other security levels.
Having done that much, I think all we need in order to get rid of
RLS subqueries, and just stick RLS quals into their relation's
baserestrictinfo list, are two rules:1. When selecting potential indexquals, a RestrictInfo can be considered
for indexqual use only if it is leakproof or has security_level <= the
minimum among the table's baserestrictinfo clauses.2. In order_qual_clauses, sort first by security_level and second by cost.
I think that ordering might be sub-optimal if you had a mix of
leakproof quals and security quals and the cost of some security quals
were significantly higher than the cost of some other quals. Perhaps
all leakproof quals should be assigned security_level 0, to allow them
to be checked earlier if they have a lower cost (whether or not they
are security quals), and only leaky quals would have a security_level
greater than zero. Rule 1 would then not need to check whether the
qual was leakproof, and you probably wouldn't need the separate
"leakproof" bool field on RestrictInfo.
Regards,
Dean
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Dean Rasheed <dean.a.rasheed@gmail.com> writes:
On 25 October 2016 at 22:58, Tom Lane <tgl@sss.pgh.pa.us> wrote:
The alternative I'm now thinking about pursuing is to get rid of the
conversion of RLS quals to subqueries. Instead, we can label individual
qual clauses with security precedence markings.
+1 for this approach. It looks like it could potentially be much
simpler. There's some ugly code in the inheritance planner (and
probably one or two other places) that it might be possible to chop
out, which would probably also speed up planning times.
Here's a draft patch for this. I've only addressed the RLS use-case
so far, so this doesn't get into managing the order of application of
join quals, only restriction quals.
2. In order_qual_clauses, sort first by security_level and second by cost.
I think that ordering might be sub-optimal if you had a mix of
leakproof quals and security quals and the cost of some security quals
were significantly higher than the cost of some other quals. Perhaps
all leakproof quals should be assigned security_level 0, to allow them
to be checked earlier if they have a lower cost (whether or not they
are security quals), and only leaky quals would have a security_level
greater than zero. Rule 1 would then not need to check whether the
qual was leakproof, and you probably wouldn't need the separate
"leakproof" bool field on RestrictInfo.
Hm, but it would also force leakproof quals to be evaluated in front
of potentially-cheaper leaky quals, whether or not that's semantically
necessary.
I experimented with ignoring security_level altogether for leakproof
quals, but I couldn't make it work properly, because that didn't lead to
a comparison rule that satisfies transitivity. For instance, consider
three quals:
A: cost 1, security_level 1, leaky
B: cost 2, security_level 1, leakproof
C: cost 3, security_level 0, leakproof
A should sort before B, since same security_level and lower cost;
B should sort before C, since lower cost and leakproof;
but A must sort after C, since higher security_level and leaky.
So what I ended up doing was using your idea of forcing the security
level to 0 for leakproof quals, but only if they have cost below a
threshold (which I set at 10X cpu_operator_cost, which should take in
most built-in functions). That at least limits the possible damage
from forcing early evaluation of a leakproof qual. There may be
some better way to do it, though, so I didn't go so far as to remove
the separate leakproof flag.
Some other notes:
* This creates a requirement on scan-planning code (and someday on
join-planning code) to be sure it doesn't create violations of the qual
ordering rule. Currently only indxpath.c and tidpath.c have to worry
about that AFAICS. FDWs would need to worry about it too, except that
we don't currently allow RLS to be enabled on foreign tables. I'm a
little concerned about whether FDWs could create security holes by
not accounting for this, but it's moot for now. Custom scan providers
will need to pay attention as well.
* prepsecurity.c is now dead code and should be removed, but I did not
include that in this patch, since it would just bloat the patch.
* Accounting for the removal of prepsecurity.c, this is actually a net
savings of about 300 lines of code. So I feel pretty good about that.
It also gets rid of some really messy kluges, particularly the behavior
of generating new subquery RTEs as late as halfway through
grouping_planner. I find it astonishing that that worked at all.
* Since the planner is now depending on Query.hasRowSecurity to be set
whenever there are any securityQuals, I put in an Assert about that,
and promptly found three places in prepjointree.c and the rewriter where
we'd been failing to set it. I have not looked to see if these represent
live bugs in existing releases, but they might. Or am I misunderstanding
what the flag is supposed to mean?
* Aside from plan changes, there's one actual behavioral change in the
regression test results, but I think it's okay because it's a question
of whether to put a non-RLS qual before or after a leaky qual. That's
not something we are promising anything about.
* There's one test query in updatable_views.sql where the plan collapses
to a dummy (Result with constant false qual) because the planner is now
able to see that the qual conditions are mutually contradictory. Maybe
that query needs adjustment; I'm not sure what it's intending to test
exactly.
regards, tom lane
PS: I've been slacking on the commitfest because I wanted to push this
to a reasonably finished state before I set it aside to do CF work.
I'm not expecting it to be reviewed in this fest.
Attachments:
new-rls-planning-implementation-1.patch.gzapplication/x-gzip; name=new-rls-planning-implementation-1.patch.gzDownload
���Xnew-rls-planning-implementation-1.patch �\ms7��,�
XW�&e�i�n��Rd�Vw������'�p�
g���d&�����������J����"4�~y��hxM����E�
�M����N'��$�h�����HB�����gQ2���I��8{��>���T�����������fx��v�:�^��Q��6y��e2M[a��\�_��i��:��W���|�����>Sj�����>\�_���~�^�m�E����(Mt�������a���������$�I�^/7��up���t����a�E�j�{{�}y�����[��8(�e:�&��~����2=�zOfE�m����l?�?~�@�����`
�����)P��6
�uZS!n��������i�S ��������o��w�o�518�JsM��-3� &�C�H�M��rK��Z"�� �;7t���I��8�OV�~L]�f�,�>=>;:��&������h���*^�5EA��8H���|�v$3�(JG����-�� X�>��W�Je�tsy-��>w,��<�G9sm������Lw��Kt�fA�Gi������E��x�O��������JF1��D�����+�s��d��OOn�l�����{s;4�{\P/��t�$�_/�GD�"�~���G���>}u�����jM"��g:�{��SZM��E��l��T-1u����k����>���=����+�����a�[��w-`�N>�<��
����4���P��/�;��NB}A61����xyv����Nu;{u8�8} �T�rc�,�m����n�,��t����m���u�~���~:�Bu�F�-��9�-�(���/��������`;��k��q�Z���c�S#�X��#H���cs��^gs����2����������
�o6����h���FN�^��v7�F`���ui*N, ����pXYO��{����QI���y ��K�qr�9=��}qv|��f [,U (i����.������2����Qi�����s�����B�������N��D����Y�L�G��(=�Fad�W��.�������^����!��*P�uU�U�H��-i�p���z���7!o) }��:�(`�c
2�W@H|����n����|m,x;�T:1$�S��.��j����X`x���ej4�$&��{�� T���4��/�<�A(�Bc@@W��h�8�����iSw���2�&��V�70�^�A���O�ID:d��n� �$(�������E�XIF��JAx���l��F�IU�0��Jt�� �(^)8N�j��
a �&�uE�)ZT����J�� ���u���B��y�[%9�J�G�* ��@o�����=Q����G��'`�FDk��b�7W��oVxl(&)���8���usz F�Q&�I�9P�b0�g�d�wQx�}W�$��D��s���� x�++����6I��Q���L�mZ�j��C�&�$�p��^Q\q!�T$��Xf��7zV�Af����35����v��s^A�\1hA��r�� ���C4�m0`�Oc��i��z�c-w��!V2������X���cQC�9�%l�B"��.bK��#��^������p3�f!.+�B���� �� �l`lgs�*�m�e�m���d�H�,����
������3oh��C��h�!q���@��" ��M��Z�>�43�d��5M�V) ���>��*��qaJ�[]����E`��T�k5�Qw�����~i�:H&g����:�'�X��^��c��+lQ�}�'��0v4�P�b��J�\��0���t�������i`\�����`����:����|�H��<�!��(�jF��0�e8�X[��u��EBcC�/9�����i���Y����#t�m��h�� 9EG��~!�e�i��$(���V_�oZ��dn�����5PL
x$��L���.u�.|�.���li�6�Nc�4�+���e:r�g�wI������t&��;p�4&��4�g-b�F`x�_����8�#yE�� ���^2�����g���D%@@qW$�6�O�����V���/�0`(�V���E�P-Z!�S��� ���/���Em����@�@�1��Z��ZC�9�G�O���)����Y3���V /@i�1f(.�B`���p�����]� �Db��v�
65�*:=���E���$Q��#RDuG�6���A�k��w+�CS<���LJ�j����K
��H;�j�pw=D��������5Y+�A-��N�;��HH��Ks��)��B|19�Q����6!� kX�iF�K��e�:��k���� ]yB��i�Yd�$>���,H�4g�B]z�EJ4�R<��T�f���yl��?�!Z��L��!6����%8�����-�#��v����`��1�\���Md .!��jsM��jx�P�������G�S4u��!�1�;��W5N#P�<7Q�R���e�=u��0dI�v>�I�EC�d�b�K� @��_;;N�����X83f������m��.�{J���la���O�!V� �X���r|�f{���JUm�=3\8a�y�KO�)[b��3���
6l��,3!��|��������p��W���t���'-���Y�K7����8�lU����!�$q������
���9��z��#����$�����0�B?�6p�|�����T#�S5u�8�,� �X��CX.�g��m�R��RH��SJ8M!� ��;�VgR��������d��U
�c���E)8&,���1��������h�����B����o���7�}�b:���7��0>J]Z���`��t�=�%��;D}���-N�Y ��a2w��2,� #�B�`bd�}Dr�%lIO�8|��8H�L
^b�9G:L�b��#9��TX
`�z�*��H��X��{�
��}�����m�7����\�|M�_�m�g���p��g��^8��G�S��MJ��E�}� R��+g�G�Z����� z�����q��������� �������i��yOnn��Icyud[0��\Ww��_��?{��w��zC5�BC�hZ$�� 3�m<�5q�>�Xm���)�[�FX�.� ����S�����^t��}#�Kr\=����-�-Icf�qy��Og�%����\�p��q��;;dH#>���������/Mq�;�����A�sv�i.|��|@��A�����R]b��W��]R��/2�����P1{�����������}�=8P�|��<����$%'��d���L1�����
:Hl��c�G��0�Xj���6�����I���7/x#{�e�t
A7�0��nN?�kr�%��u�=qz�]����q39�����G����0_�v�_n_ ��4���zm&��:�������k�}���#�*�x ���p��6�E����8/��X��'ig���F�0��j�����z'k%�Y1)5��=���J�5z0c:��<Cc(x�[��m;Yg5����.�y�E���y
B��j�7����oD"�
T�o�I_��m�����@�GGR����6��W� ��d�J��g���� �U����C���y���J�y������g�������D[��q(�CP4)�#�Z2���s�l��`�QRh���Y��?�TX�I*�!dZ��w[��iF�)2�_��Z>)��F������# E�T4�7b,�ia4^��[P�����
~��,9����N��UU��� ��7��Xv���7����tt����2N��eX~]�hORK���B�+��8��H[�ZP��X��f���l�t�����g��zI�
m����oy�|e�����.�,R��$4q�����%�B%��_�1
3����6;��� R��1�&S�a�1����i�vc��
��yJM�zn���E��suj"t8^sOwMXN��2 �H��������j������O�(]J���eE�D�d��
�����>�t�n����+��m��<+�Z�j@1���/��'Ly{�q�Nn��K:���V�?� ����T���>%{u
��tc�k;�s��#:k���d�|IT�����T�"���&���Xuu��r:�����F��:�v@0�din��<0������w�<��*����H�����"J��o�i
���5d��r[����H`C��.a����������m�Zg�vZ�,��~d�g�����,$�(~�.�u��c���v6�������~5P������s�\�nu}+�[>IDA_9E���E���-�������:l�J�l�vt���&����#�ld�m���G0�n���>h��]^�S�WWt����������f�F{Y��H���B
�2��������*�f��M:�?���������vM��r�Dw�B{�C�/���
'�ww�.��i<)���IWlr��~������`-@������kuP9u?�x�d ee����s�(�j4�9�jbo�AGYZkN�����fr�R�4h{4�J��D���� ���#J�FQL�N)q\��o���� �Y�;���6u{���'c�F���z�������q`C���Z�����`�]����{�f)_�n�k���:F=o�O9En������gi}"�m9�t=�_���x��&�h���?���)��mq P����*gU�'�A?N�����Y_�Uo>d���6}(`�������3��������R�e���v];f-���-���W��^����4.���/�j�����\�Z�#?88><��O���rF��V��8B��zYU���Y�'Y@��E�|�3����g�:rv=%�\��W��@����/�������@}���f�.>�������4��.�qd+)�/��a�~�2���a���JA��:B.�� ���k�R�L�k�*q�����������#EL�b�j�\�PF%n
� F. ��F�^�u���\0� HAUPW����(/�����4�� ����\��$XU�������Ge�(�$C�H��������(���]����(_����C.+*X��+��\�L�Y����*��%�()'�������6 u|���I�+��b����d(15%�Z�����2k���!B]���_d
�o?��������_����������v��i�mA$[�S��*��e�J�jD���6'I�MV��&�|����z����T��dgO�Y�v�g3�~�MU_���X^��\o �:o�Z�dF��)n��������k��`��Sgl]�1����:s�?�����-�\ A[������4@���``��jvd�pz�=�I�y��#h�j���t������n��g%&:�S
������v����K����>����^����|���H�������V�������w�.����jZf�)g\�f>�8J��-g����LYK�r["�`E��4��fBg����-tt�6eo��-�&��t(�r=W@Y]s
��EG�^X�����������#�{~���B��-�9�G�����G������K}j��Z�S���+���;����cy�&q��@ t�P��sp�������l�?oG�)���P��1�t��b!C��0��8��/g�|���f��H5��@�8�Ka���U*�M�8��������=9��;`�%�(��AR)u���<d�r��^�~�$�j��lX����2q,�BR*��&����
��n���gl|vZ���t�Y���x_?q��J">KiJ9�r�8� ��,���~�������d>�r5
����3�
���\�'�J���d��#s]�hkq�1��00<M��t�����5�N�)y�pD��ALE�B�����^��H��1 �X^�;T��XZ9��&MRs-u�� `0/H��]��z:��V[4(��H���2����������>/��V�LS���$�WWB�^�Lm��=bJ�p�#!HNbS�y���>r^��a�P��h��^�Yz8,cJ����������3[��f���1��_��S�d��(jm���dB�����F��$�S������sh��2Q"�
�w
�����m���eSe���ic�{�����z<��"