Re: [HACKERS] [Fwd: Index Advisor]
Hi All,
Please find attached the latest version of the patch attached. It
is based on REL8_2_STABLE.
It includes a few bug fixes and an improvement to the size
estimation function. It also includes a work-around to circumvent the
problem we were facing earlier in xact.c; it now fakes itself to be a
PL/xxx module by surrounding the BIST()/RARCST() calls inside an
SPI_connect()/SPI_finish() block.
Please note that the sample_*.txt files in the contrib module,
which show a few different sample runs, may be a little out of date.
Best regards,
--
gurjeet[.singh]@EnterpriseDB.com
singh.gurjeet@{ gmail | hotmail | yahoo }.com
Attachments:
I have looked over this patch, and it completes part of this TODO item:
o Add SET PERFORMANCE_TIPS option to suggest INDEX, VACUUM, VACUUM
ANALYZE, and CLUSTER
Here is the foundation of it:
For an incoming EXPLAIN command, the planner generates the plan and, if
the Index Adviser is enabled, then the query is sent to the Index
Adviser for any suggestions it can make. The Adviser derives a set of
potentially useful indexes (index candidates) for this query by
analyzing the query predicates. These indexes are inserted into the
system catalog as virtual indexes; that is, they are not created on
disk.
Then, the query is again sent to the planner, and this time the planner
makes it's decisions taking the just-created vitual indexes into account
too. All index candidates used in the final plan represent the
recommendation for the query and are inserted into the advise_index
table by the Adviser.
The gain of this recommendation is estimated by comparing the execution
cost difference of this plan to the plan generated before virtual
indexes were created.
It involves a patch to the backend, and a /contrib module to access it.
I think we have to decide if we want this, and whether it should be in
/contrib or fully integrated into the backend. I am thinking the API
needs to be simpified, perhaps by removing the system table and having
the recommendations just logged to the server logs.
---------------------------------------------------------------------------
Gurjeet Singh wrote:
Hi All,
Please find attached the latest version of the patch attached. It
is based on REL8_2_STABLE.It includes a few bug fixes and an improvement to the size
estimation function. It also includes a work-around to circumvent the
problem we were facing earlier in xact.c; it now fakes itself to be a
PL/xxx module by surrounding the BIST()/RARCST() calls inside an
SPI_connect()/SPI_finish() block.Please note that the sample_*.txt files in the contrib module,
which show a few different sample runs, may be a little out of date.Best regards,
--
gurjeet[.singh]@EnterpriseDB.com
singh.gurjeet@{ gmail | hotmail | yahoo }.com
[ Attachment, skipping... ]
---------------------------(end of broadcast)---------------------------
TIP 5: don't forget to increase your free space map settings
--
Bruce Momjian bruce@momjian.us
EnterpriseDB http://www.enterprisedb.com
+ If your life is a hard drive, Christ can be your backup. +
One problem with only putting this information in the system logs
is that when we provide database services to a member of our
community we do not actually give them an account of the DB server
or log server. This means that this very useful information would
need to be passed through an intermediary or another tool developed
to allow access to this information. I think that having this available
from a table would be very nice. My two cents.
Ken
Show quoted text
On Sat, Jan 06, 2007 at 04:08:24PM -0500, Bruce Momjian wrote:
I have looked over this patch, and it completes part of this TODO item:
o Add SET PERFORMANCE_TIPS option to suggest INDEX, VACUUM, VACUUM
ANALYZE, and CLUSTERHere is the foundation of it:
For an incoming EXPLAIN command, the planner generates the plan and, if
the Index Adviser is enabled, then the query is sent to the Index
Adviser for any suggestions it can make. The Adviser derives a set of
potentially useful indexes (index candidates) for this query by
analyzing the query predicates. These indexes are inserted into the
system catalog as virtual indexes; that is, they are not created on
disk.Then, the query is again sent to the planner, and this time the planner
makes it's decisions taking the just-created vitual indexes into account
too. All index candidates used in the final plan represent the
recommendation for the query and are inserted into the advise_index
table by the Adviser.The gain of this recommendation is estimated by comparing the execution
cost difference of this plan to the plan generated before virtual
indexes were created.It involves a patch to the backend, and a /contrib module to access it.
I think we have to decide if we want this, and whether it should be in
/contrib or fully integrated into the backend. I am thinking the API
needs to be simpified, perhaps by removing the system table and having
the recommendations just logged to the server logs.---------------------------------------------------------------------------
Gurjeet Singh wrote:
Hi All,
Please find attached the latest version of the patch attached. It
is based on REL8_2_STABLE.It includes a few bug fixes and an improvement to the size
estimation function. It also includes a work-around to circumvent the
problem we were facing earlier in xact.c; it now fakes itself to be a
PL/xxx module by surrounding the BIST()/RARCST() calls inside an
SPI_connect()/SPI_finish() block.Please note that the sample_*.txt files in the contrib module,
which show a few different sample runs, may be a little out of date.Best regards,
--
gurjeet[.singh]@EnterpriseDB.com
singh.gurjeet@{ gmail | hotmail | yahoo }.com[ Attachment, skipping... ]
---------------------------(end of broadcast)---------------------------
TIP 5: don't forget to increase your free space map settings--
Bruce Momjian bruce@momjian.us
EnterpriseDB http://www.enterprisedb.com+ If your life is a hard drive, Christ can be your backup. +
---------------------------(end of broadcast)---------------------------
TIP 9: In versions below 8.0, the planner will ignore your desire to
choose an index scan if your joining column's datatypes do not
match
Kenneth Marshall wrote:
One problem with only putting this information in the system logs
is that when we provide database services to a member of our
community we do not actually give them an account of the DB server
or log server. This means that this very useful information would
need to be passed through an intermediary or another tool developed
to allow access to this information. I think that having this available
from a table would be very nice. My two cents.
Well, you can still run EXPLAIN manually and see the suggestions. I am
not sure even how a system table is going to work in a shared
environment for this usage. Perhaps we need to allow a table name to be
passed using the EXPLAIN, or now that I think of it, EXPLAIN output is
actually is just a single-column text table, and perhaps we would just
need to give people a way of saving that off.
The really nifty use seemed to be setting the GUC to ON and running and
application, and capturing all the suggestions. Perhaps we need to be
able to pass a single-text-column table as the GUC value and use that
for capturing the output suggestions. But again, if you are doing it
for an application and setting it for all logins, don't you probably
have access to the server logs.
Anyway, this is a new direction for us, but I think a useful one, and I
find the implementation used here creative.
---------------------------------------------------------------------------
Ken
On Sat, Jan 06, 2007 at 04:08:24PM -0500, Bruce Momjian wrote:
I have looked over this patch, and it completes part of this TODO item:
o Add SET PERFORMANCE_TIPS option to suggest INDEX, VACUUM, VACUUM
ANALYZE, and CLUSTERHere is the foundation of it:
For an incoming EXPLAIN command, the planner generates the plan and, if
the Index Adviser is enabled, then the query is sent to the Index
Adviser for any suggestions it can make. The Adviser derives a set of
potentially useful indexes (index candidates) for this query by
analyzing the query predicates. These indexes are inserted into the
system catalog as virtual indexes; that is, they are not created on
disk.Then, the query is again sent to the planner, and this time the planner
makes it's decisions taking the just-created vitual indexes into account
too. All index candidates used in the final plan represent the
recommendation for the query and are inserted into the advise_index
table by the Adviser.The gain of this recommendation is estimated by comparing the execution
cost difference of this plan to the plan generated before virtual
indexes were created.It involves a patch to the backend, and a /contrib module to access it.
I think we have to decide if we want this, and whether it should be in
/contrib or fully integrated into the backend. I am thinking the API
needs to be simpified, perhaps by removing the system table and having
the recommendations just logged to the server logs.---------------------------------------------------------------------------
Gurjeet Singh wrote:
Hi All,
Please find attached the latest version of the patch attached. It
is based on REL8_2_STABLE.It includes a few bug fixes and an improvement to the size
estimation function. It also includes a work-around to circumvent the
problem we were facing earlier in xact.c; it now fakes itself to be a
PL/xxx module by surrounding the BIST()/RARCST() calls inside an
SPI_connect()/SPI_finish() block.Please note that the sample_*.txt files in the contrib module,
which show a few different sample runs, may be a little out of date.Best regards,
--
gurjeet[.singh]@EnterpriseDB.com
singh.gurjeet@{ gmail | hotmail | yahoo }.com[ Attachment, skipping... ]
---------------------------(end of broadcast)---------------------------
TIP 5: don't forget to increase your free space map settings--
Bruce Momjian bruce@momjian.us
EnterpriseDB http://www.enterprisedb.com+ If your life is a hard drive, Christ can be your backup. +
---------------------------(end of broadcast)---------------------------
TIP 9: In versions below 8.0, the planner will ignore your desire to
choose an index scan if your joining column's datatypes do not
match
--
Bruce Momjian bruce@momjian.us
EnterpriseDB http://www.enterprisedb.com
+ If your life is a hard drive, Christ can be your backup. +
On Sat, 2007-01-06 at 16:08 -0500, Bruce Momjian wrote:
I have looked over this patch, and it completes part of this TODO item:
o Add SET PERFORMANCE_TIPS option to suggest INDEX, VACUUM, VACUUM
ANALYZE, and CLUSTER
It involves a patch to the backend, and a /contrib module to access it.
I think we have to decide if we want this, and whether it should be in
/contrib or fully integrated into the backend. I am thinking the API
needs to be simpified, perhaps by removing the system table and having
the recommendations just logged to the server logs.
The patch to the backend is in the form of a plugin API, which does
nothing when there is no plugin. IMHO there is a significant amount of
code there and it is too early to try to get all of that into the
backend, especially when more tested things like Tsearch2 haven't.
Plugins are cool because we can update them without needing to bounce a
production server, which means the code can evolve faster than it would
do if it was directly in the backend. (You do need to reconnect to allow
local_preload_libraries to be re-read). Tuning out the wierd
recommendations will take some time/effort - I don't know there are any,
but then my gut tells me there very likely are some.
The output isn't a system table, its a user space table. The reason for
having an output table is that we can use multiple invocations of the
adviser to build up a set of new indexes for a complete workload.
Reading things back out of the log would make that more difficult, since
we really want this to be automated by pgAdmin et al.
--
Simon Riggs
EnterpriseDB http://www.enterprisedb.com
On 1/7/07, Bruce Momjian <bruce@momjian.us> wrote:
I have looked over this patch,
Thanks
I think we have to decide if we want this, and whether it should be in
/contrib or fully integrated into the backend.
Well, as already said, the plugin architecture gives others a way to develop
and deploy their own index advisers, or even something else that does nifty
things with the generated plan!
I am thinking the API
needs to be simpified, perhaps by removing the system table and having
the recommendations just logged to the server logs.
The advise_index table not required to be a system table anymore, as
required by the original patch. It can be any table/view on which the
executing user has INSERT permissions. The Adviser internally builds an
'INSERT INTO advise_index ...' statement and executes it through SPI. So, it
actually behaves as if the user is doing and INSERT. As a side effect, if
the EXPLAIN is done in a transaction, which is later rolled back, the
recommendations inserted in the advise_index will also be lost!
contrib/pg_advise_index/sample_error_messages.txt also shows an interesting
usage, where advise_index is actually a VIEW with a RULE that redirects
INSERTs into another advise_index_data table.
Best regards,
--
gurjeet[.singh]@EnterpriseDB.com
singh.gurjeet@{ gmail | hotmail | yahoo }.com
On 1/7/07, Gurjeet Singh <singh.gurjeet@gmail.com> wrote:
contrib/pg_advise_index/sample_error_messages.txt also shows an
interesting usage, where advise_index is actually a VIEW with a RULE that
redirects INSERTs into another advise_index_data table.
Also, the DDL for the advise_index table can be found in
advise_index.create.sql script in the contrib module.
Regards,
--
gurjeet[.singh]@EnterpriseDB.com
singh.gurjeet@{ gmail | hotmail | yahoo }.com
Simon Riggs wrote:
On Sat, 2007-01-06 at 16:08 -0500, Bruce Momjian wrote:
I have looked over this patch, and it completes part of this TODO item:
o Add SET PERFORMANCE_TIPS option to suggest INDEX, VACUUM, VACUUM
ANALYZE, and CLUSTERIt involves a patch to the backend, and a /contrib module to access it.
I think we have to decide if we want this, and whether it should be in
/contrib or fully integrated into the backend. I am thinking the API
needs to be simpified, perhaps by removing the system table and having
the recommendations just logged to the server logs.The patch to the backend is in the form of a plugin API, which does
nothing when there is no plugin. IMHO there is a significant amount of
code there and it is too early to try to get all of that into the
backend, especially when more tested things like Tsearch2 haven't.
Plugins are cool because we can update them without needing to bounce a
production server, which means the code can evolve faster than it would
do if it was directly in the backend. (You do need to reconnect to allow
local_preload_libraries to be re-read). Tuning out the wierd
recommendations will take some time/effort - I don't know there are any,
but then my gut tells me there very likely are some.The output isn't a system table, its a user space table. The reason for
having an output table is that we can use multiple invocations of the
adviser to build up a set of new indexes for a complete workload.
Reading things back out of the log would make that more difficult, since
we really want this to be automated by pgAdmin et al.
The complex part of this is that the feature requires patches to the
backend, and has a /contrib component. If it could be just in /contrib,
I agree we would just keep it there until there is a clear direction,
but having it in both places seems difficult. I don't think we can
maintain a patch to the backend code in /contrib, so it would have to
ship with our backend code. That's why I was asking about getting it
integrated fully.
--
Bruce Momjian bruce@momjian.us
EnterpriseDB http://www.enterprisedb.com
+ If your life is a hard drive, Christ can be your backup. +
On Mon, 2007-01-08 at 11:28 -0500, Bruce Momjian wrote:
Simon Riggs wrote:
On Sat, 2007-01-06 at 16:08 -0500, Bruce Momjian wrote:
I have looked over this patch, and it completes part of this TODO item:
o Add SET PERFORMANCE_TIPS option to suggest INDEX, VACUUM, VACUUM
ANALYZE, and CLUSTERIt involves a patch to the backend, and a /contrib module to access it.
I think we have to decide if we want this, and whether it should be in
/contrib or fully integrated into the backend. I am thinking the API
needs to be simpified, perhaps by removing the system table and having
the recommendations just logged to the server logs.The patch to the backend is in the form of a plugin API, which does
nothing when there is no plugin. IMHO there is a significant amount of
code there and it is too early to try to get all of that into the
backend, especially when more tested things like Tsearch2 haven't.
Plugins are cool because we can update them without needing to bounce a
production server, which means the code can evolve faster than it would
do if it was directly in the backend. (You do need to reconnect to allow
local_preload_libraries to be re-read). Tuning out the wierd
recommendations will take some time/effort - I don't know there are any,
but then my gut tells me there very likely are some.The output isn't a system table, its a user space table. The reason for
having an output table is that we can use multiple invocations of the
adviser to build up a set of new indexes for a complete workload.
Reading things back out of the log would make that more difficult, since
we really want this to be automated by pgAdmin et al.The complex part of this is that the feature requires patches to the
backend, and has a /contrib component. If it could be just in /contrib,
I agree we would just keep it there until there is a clear direction,
but having it in both places seems difficult. I don't think we can
maintain a patch to the backend code in /contrib, so it would have to
ship with our backend code. That's why I was asking about getting it
integrated fully.
The plugin approach is exactly what happened with the debugger. The
backend has an appropriate plugin API and the debugger is a plugin.
The patch to the backend shouldn't be in contrib, definitely.
I would say its up to the installer to offer the opportunity to load the
adviser plugin, or not. I like plugins because they encourage faster
paced development, diversity and choice. e.g. Multiple java language
plugins give users choice. We could include an adviser plugin with the
main distribution, as happens with PL/pgSQL...
--
Simon Riggs
EnterpriseDB http://www.enterprisedb.com
"Simon Riggs" <simon@2ndquadrant.com> writes:
On Mon, 2007-01-08 at 11:28 -0500, Bruce Momjian wrote:
The complex part of this is that the feature requires patches to the
backend, and has a /contrib component.
The plugin approach is exactly what happened with the debugger. The
backend has an appropriate plugin API and the debugger is a plugin.
The patch to the backend shouldn't be in contrib, definitely.
I would say its up to the installer to offer the opportunity to load the
adviser plugin, or not. I like plugins because they encourage faster
paced development, diversity and choice.
I would suggest that if we want to encourage faster development, we
should do the same thing we did with the plpgsql debugger support:
put the plugin hooks into the backend and keep the actual plugin(s)
as separate pgfoundry projects. That way the index advisor can have
a release every few weeks if it needs it .... and it will, for awhile.
Stuff in contrib is necessarily tied to the backend release cycle.
(This is not a statement that I approve of the specific plugin hooks
proposed --- I don't particularly. But if we can come up with something
a bit cleaner, that's how I'd approach it.)
regards, tom lane
On Mon, 2007-01-08 at 12:16 -0500, Tom Lane wrote:
"Simon Riggs" <simon@2ndquadrant.com> writes:
On Mon, 2007-01-08 at 11:28 -0500, Bruce Momjian wrote:
The complex part of this is that the feature requires patches to the
backend, and has a /contrib component.The plugin approach is exactly what happened with the debugger. The
backend has an appropriate plugin API and the debugger is a plugin.The patch to the backend shouldn't be in contrib, definitely.
I would say its up to the installer to offer the opportunity to load the
adviser plugin, or not. I like plugins because they encourage faster
paced development, diversity and choice.I would suggest that if we want to encourage faster development, we
should do the same thing we did with the plpgsql debugger support:
put the plugin hooks into the backend and keep the actual plugin(s)
as separate pgfoundry projects. That way the index advisor can have
a release every few weeks if it needs it .... and it will, for awhile.
Stuff in contrib is necessarily tied to the backend release cycle.(This is not a statement that I approve of the specific plugin hooks
proposed --- I don't particularly. But if we can come up with something
a bit cleaner, that's how I'd approach it.)
Sounds good to me.
--
Simon Riggs
EnterpriseDB http://www.enterprisedb.com
On 1/8/07, Tom Lane <tgl@sss.pgh.pa.us> wrote:
(This is not a statement that I approve of the specific plugin hooks
proposed --- I don't particularly. But if we can come up with something
a bit cleaner, that's how I'd approach it.)
I have another idea for making the hooks a bit more cleaner; I will try that
and run it through you guys later today.
Best regards,
--
gurjeet[.singh]@EnterpriseDB.com
singh.gurjeet@{ gmail | hotmail | yahoo }.com
On 1/9/07, Gurjeet Singh <singh.gurjeet@gmail.com> wrote:
I have another idea for making the hooks a bit more cleaner; I will try
that and run it through you guys later today.
Please find attached the latest version of the patch. It applies cleanly on
REL8_2_STABLE.
The following restrictions are applied before generating an index candidate
(this is not mentioned in the README):
.) It should be a base relation; We do not generate advisory for a view or
Set Returning Function or something else.
.) It should not be a system table; like pg_class etc.
.) It should not be a temporary table. (May be we can allow these; opinions
please!!)
.) We do not recommend indexes on system columns; like oid, ctid etc.
.) The relation should have at least two pages.
.) The relation should have at least two tuples.
The last two restrictions put the onus on the user to keep the table
ANALYZEd or VACUUMed.
I have moved the calls to index_adviser() from two other places to the
end of planner(). IMO, that is the best place to place a call to the
Adviser; instead of duplicating code in every caller of planner().
index_adviser() makes sure that it doesn't get called recursively.
This change however costs us the loss of ability to append suggested
plan to the existing plan, if being called by the EXPLAIN command. Instead,
it now uses the newly written function explain_getPlanString() in
explain.cto get the string representation of the plan, and then emits
it as elog(
LOG,...).
The only kludge left now is the code enclosed in '#if GLOBAL_CAND_LIST'
in plancat.c. We need to decide whether we need the 'if' part or the 'else'
part! I already see a strong objection to the 'else' option, since it is
very close to the core of the optimizer! Opinions needed.
After adding the CREATE TABLE advise_index(...) script to
src/test/regress/sql/create_table.sql and enabling the GUC in the conf
file, 'make installcheck' runs fine, with a few acceptable diffs. Moreover,
post the 'make' run, we can see there are a few advises for the tables
involved in the test run. Four of them are ob serial columns of
hash-index-testing tables, so they don't make much point; but the rest three
of them are on big tables, and one of them is a multi-column-index
suggestion.
Now that there's just one call to the Index Adviser (from planner()) we can
now move forward in making it a plugin.
Best regards,
--
gurjeet[.singh]@EnterpriseDB.com
singh.gurjeet@{ gmail | hotmail | yahoo }.com
Attachments:
pg_index_adviser-REL8_2_STABLE-v23.patch.gzapplication/x-gzip; name=pg_index_adviser-REL8_2_STABLE-v23.patch.gzDownload
����E pg_index_adviser-REL8_2_STABLE-v23.patch �:ko7��S����(`)�d�y8q�N��M��:Z`�0�Jb=3��3r�����A�C�l'��A�h$�����*W_�Ef�����y���P?����??�p���@p����S�V�������Z�O�b�^����6�����j`�JWa��M%������|.��[|��������T|P�8<8x,?���<��x<�o�>�*�]������� �,��h�<�.��{����}����j�V���������?���Y����_�O��g1�yp�����U�\1��������8;�<}u�A��\�o��b��8cx���^\�$�.5���n���`����n�lNo�\���+�����7�I0��`������Vplc����,>:>8������t4}����p�,�V<� '�iL}9ku����d2��u�m��������������03Y�r�{�����7 e�w/~� �t���6��D�s�����������W�0~�������%`F
����^����a�|��%~}~vr��l���on6��137)��4�����&{7�`����o�����!4��#1}p�}�m?8�n������Y*���fa����-qBhm��t�7��m�hS�W������\,U
Fh'�p��Q��q���Y��=��/�|
Y�U�)KU�B
�a��6 ���a-Z��$ ���R���*��t(��A���U�@��`�6��Oxc������Fc��YU�\\ #����J]������$W(��;Q��� -|D` P�J����\�X(�bw_9��
9A���1V� _�p!(Q�x
�A�X;����z��#�d
���\)@)���*���`��# CC�����Z��y�L��gGK]T�(x�� fm��0^"�J6�&�
����]
�1"g�R�5�(��
$�6���KW�L�p)���-���Q�a���\�A� �\�+�+3%,guF�2��a���h���MU B�T��vrm�"����>eC�D�Y�|\#jk`U�H4U0).$ �h����[����J�����*R
���$�-�V
�.u!����Z�l���f#��dj�(V(�98�R��]C��R["i�RB� ����6����h ������n�;��
r*
�������1��!.�u���e���zq���r#������V��ca�e�;���1�p��u��&�4�!���t�� �B���qBM��*�<�oA���Z��-; �
��#n�RV6�Pc�#tt��J��R;G�T���Wo?��_�: �Cj�+t����
��������3�����3����.[�5]���6�T���w�$�n���OP�!tTp��/��"RX\P���s��n(���e@X�=X�7H�!�O���C�����2svNW �!f���|L� �[��
�c|���K��j�G�=U!�4<��j���P
6�K��8��������� z���'��2V_�K����|\�4���X;��E��@L?x�(�<i�\�k����=9�<=zp���<:��O��>�
�n��'Y o)��\�J2�q}��(
�,��v�c; E�Z��w��)�n�w��x_(�T��h}�r[��]�j1@_�3�R�)���H�nIi�LB�������E��cN��$C�e��D&[GP��+YxV�R�D)Ys���DL�[�<���H�+9����oN��B����*O��Xl�l;��%�C�kB0A�L���� v�����r���
�V���q������3���V�a������k,M�133��6�����b�8��������w=[n���f�x�(+�W��!�A�J����
�X��@�P�E������&y�&�g5 �\��<����`'�^�5�v��������s���/���m�?�e����cOg�`"��H����w�~| ��j�bG\Y���
��+��`�g�}��-2�d����m������B.@q���3�����d�U�������
��M��-�b��L���`�\gZbG�D�E����Q��n�e[zr�mw1=���g�(wj{F���
!�_�gt�3�2����xW��c���cjdB&�o������3V�^F�o�|��kN��g�U�od���`�q�],E
f�ve���9�&�g������2],Qq3GT2\e��2h�R���>�R��������*���s R:�5$���T�M��0/�?�� 7S+t
v��J1UW�P]Y��oI����h'�U�#1] �uZ�!��R6-����AU ^Y�<
��VV�n�������a���=�A��>.�q2�+ ����J/��fF�?d�������
��%z�T ��m�D�������Nn���� �v6u-?�����x%"X�o�P����~�tsc$�J��K�j�����S:K ���������-a`��R7����e�+�s�a-�T��6�5�I_�+*����za�����4��R 8TL������q�C�\^��R�Y����t<�
��2o#h�����0_��i��m�{ �'N� T��Q&P�1�n��$�ap�K��7N�_�V�F�Q�����g
,�V�6�����e|��x]����>��k;PG7�����M��q �g����<5rwW���7���������ebUa4�A�alw>}*��B:�}�#I@�� C�=�7� �\%����1%�f�u�l��!0��M1m�V��h��?O��� ��p�.�9��LFE��a;����vY���FqF�����cs���5����`$o�q��X�@��s�3���Y�������('���� ��n?o�H�C�8�����j������ ����
��l���C�
�'��fK��?����0D���a~z*7�i1,�&L=�"wC�,T���6�(b`�
n&�M�
.��N��b��0����M+T�r]c�'���Q����<|��fh��ykQg)�<�������� pB��%gt!���$������2����T�VO�Qd��3�y�&rS�E4Re�J��'����a�3��u��#{"S7[�A���hU�Z�HN�@���]z�U
�$��-�}������2�!b%��m{T�yr��H5k��!yE�Z# ����*�~�/��BpbV�K=3*��@TgW1�*�T��u�th���kXbE��������tx�E�Em�d�$P����D��];�Ipf��s��sW��7�x�BYUe*�$>�:���
�S�(b���{�'�!YE�hl��������������D��%8���Za����T<`�109�L�M�����L�
���d�����*PT�FQ;��f�
w��p�6�i�9�#S�{ wr�O�D�;�������x�V��:#��M�"L�g�>oG<��I"���t��l���nvQ����0��|f@<$TA������v�t���������S�d�^u��l����`���`���
��bg�D��>Vn�����=N��k[V����V�3�pG����$��J�����������L:�MLP�Ki�i�a+UOe��o�,+>�
��m]��6�v3eI0|�b�*Yti��"���4{���%�e��>�p��c��n\K��h�I�������0���R
H�9��u��&
��Y��c|��/)j�l�"���qq"11*�4�l/�GV�P�A���g%������(�v�I ��[��Rj��W h�'j�^z��e)�lk�f�����zQ���y+!#��n��������ZgP:�Ix���u��M$�ZZm�WY���K6���O!�����<'��N,�yo���ot���I�n��k�3�&�:V� :���O�K�
a����� y�������O7/��p�z�����A����8|�����o����n^������
��������8��{��
���Vj�82,|K3�Z�E�(h6���'�R�*���wL�!�E2�KH�j�R�rN���'�CZ�w_��l<8 a>����-���.}v^�~K�`ky�D����H����?K]M2!�
Uh{�M�����[���_�M�������&���������]�������&�>A��4�#� ���n��.�_���
8^��|�O�i�����d���;<OU�#����=gJu��o�(�{b �]5' nK���FAf5])34�}��R��,�u"�C��!�q������Q���t��&A`glb�*�O�Y ����:������P*�����1$`�T��:"+�L&C$��*�����J� ���
,�Y �M���%����OET..�������7����>�1�f$�N ��T�4�������"��4\����������I�^�]���%�#�Xd��-�O���k�)to �� ���kU�V�j"k��XU����$������F�= ��P�E������r47� Kc�������8��Gx�������CU�����#���J�*�[�z�����^����l���O��qc4�0Q�� Ed@e\��^8+����=zJ����4Nm�W*w�����n"eH�.���?l��V���'<���8�.�dP��(�m�3�����K!�����r�[S���'p)(\nib�S+��y�����k��F���8����ND)��j,��9���p�,��vv����Lt n�nR�B�1�����*�ZX<�r���J"6�(,e�HL��Ds"j�|��o!�T7�9����z�2���|��L���*S���/�����?7md����F6���R�p�B���qr�G�l��.���d���~�c?%'��6ssX����o�����/��N�i�E{ �*���o�t��&}�]2��
��B��E�/&��R�I�N��z<FA���Z��a>rs��I_�To.�%n�L�3|~|1+� ���A�PZ~)z��g�Jk�l��Mg��������PW�a���i)���[U��-�\�.��nG�rd]�*���Z�W�y
��Y���3�p�@����+G?�r
�� �=f�K�j��s
X%�U��'��o^��!5��4E�K?xG-��5��(�!.,���EeZ����F���M�"��tfd�by
�ng����s!e��Ho����bp�$�`�
k�tf�1���[����B��-xg�f��,�Vd��R\ ,!�{gQ���F$R���R4v��=���I�K��a.�4�� v�N��%Tng)b��P��y�L���!f���M2t%��VA��.��\��1N�
�Lf8�,��T�������}s*� ?�>�H8�����!�T��i�-
&��>�"����F����Fd"�N�qjH�/���4YG��
)�8J����5�3<@j�M��,�O���Z��t[�en��i9���$�uV2������ ���Eh������Z+,�Q�b]�!�[�w4 ��SVeZ���S�V#5]e�1O3s�P6�.$d�����B�������Nh��,��r����~�ZK�oS���:���%���;������{�i����LF ���2Y���EM�,)�<A\gW�0���/^� f����I�����������hrdI�f�������IX�Q�C'����l����}���=��. ��<����_�p��'s~A���6c�����&������v�9�?qDK��� vExow��C�K������?��_��j�����2@@��\O�!��p��A�
��%GB0ns�;��"i�QQK�+��1���: �JWyp
^MoX1�g2�� ������tk�w1��e�S��Ir�J��ozg=�/����h�qM�K�\���0�K�D�)�=a/�:���~vy��r�m�d�,W+���z�Y�~�NP�
�+�d��dJG E�GzP#�J��q[7k=P��Umxp1I�&���P m��"��F�������2'{Ok6�[��l2�o���*�,P�F
���O�k� ��ZJ�r�l�g$Z��G��(��j�w����yB�l����������Y���`w�?��{�H Y�@�Oh�~���o���(>���x�NQ�I�R�H4����P]D��p� $,M_
���$���U:H
��hN������?�z3Ro~2�d,�����V�#��gg�iDZ��R��S0��r$�YPiZYB}��W�)t����%��
1c`���I�*Wu{"y� ���E
M��w��������W�E�L���}T:d�����=62����[v]y�k H������/��8�@�a�Uy=yZZ��u3!��0���t��O���("��CvvH��?
����/��
;���0����[�����C �"*��q�� ] ���^��`����bJ����"<�P�l����eD��P�����FE>��H3t�n�8�d^�.Iu��-,�1�8,�m������@Y�9�����9�]����9+�0rlX�9I��r.Q*�e|��3h���Iv���� ����;���|?37#G�_���-���)-�AA�({q����D�E���P��>����V[�Z1����l ��-�����O����[<Q�t`���I���=_':�3Zg��en�����,��W3ejU��N���~��sTAL���3Y����g���d��@$�(�����t�Hg|����r��(a�F�2-�FhL�pA��� _f2��jD�!���\@��r.���7�c��3"i��������Q\��y�6�{�H�� �C>���$�<�������'H�d
i:F����hV-�S�t�P������B��'| ��]��r|�x��@�Ac&� L���T�V ~�qy�V��/i&-*c/sQ&(��~������R��"'�������</�=*��
����,�����,��������6u�������%9��e�`������d9\-0h�,�OC�pS�0�fEe�"��
�b�;�V��cN�;l�5_����:P���G��?�op�?1~z�E�e��,;�j8Uz�����0����&��E[�!�@?+�8������,�x����k�{������]��5N�i��`S�?r��B���m����/���SF#����EK�����|t�K�-D+�
��/�PuQz���v#4��n� ]1,G��3��8� &�ag{���.}P���k���u���h0~bOl��_������wjxz2��� M�'$w��A ����Jj�C���
�,��W$����M�`��y��������&5d"xc9-`�d�����M�n :��"���<�=������|Q8�O�~_����[$X^�L3�&:/�\yv���Y��E%���{�+��O��mT�D ��� ����������U��
y��/g'��{�!�5�����3�����������-x|u6���3�������X��D���Q����w1@)�1�3���QO�P���%o{.n�U6�)i�x� i�x�����6lR��U�]��D�1�T��`�pA��yC�W]���s)��B���4gx�����n� j%<����[U��P��� *UDQ}�e�u��f��[���[S<�����B�A=t�;Y�SY�}�\d9�������T����!)6������&l���m��Zr&��1�> ���y��F�o�j0��Z�7�/N�z}�5
���=������M
�)"�N����/���d�Y������
p���XoD�z-���C��#�T�DO�E+-��%
�]�$�_���^��i�-����q"#�\��.p}�<M��..�z�YxXY��CS�!
-z#�?�"i�'�����}L��q�|��7�-��
��S��1��ul����*�j����c��}5����@Sn�Y�H�zQx�z�:�BzR&����5�)�#���')e5:9;��a#��y������X�8�[|�,Y�v)�Y;u�ZN*��R^���������4n5]e+��v�H�3�v���N��:�2F5d4.+������s
x{����5� 4=�}oA�����~�,� ���^;F\�[��h���+����t^����+��emD���2A���}�j5������Ge��D~�:e����xe�G�>��Q�(%���-�?�a
��nb-"J��)P_�I�[� ������CK9T��� w��������?�TW���ZX�?��� �I��C������A�[��� ��SU�Ovv?�4dV���7z������}��b�+���W��Z
�O��^�q<""J�@���x���� |>_�A���!�Q�JWKur���rQW��.�B���.���z9����Q�+��^!�Hv3��h=��h��T-����Iftg��T��x��D�G�h�oV�L��2��\Se����5�Ao�+��&q�z�9/ ���C7�5��<b08:|���G]o~b��b��#y�m�"������ �tAM�JcHX_q���1���
���
D����L�+�>�7��pO���.�����a��� �P�|�f����d`�Z���?@6->l#�7/�7��_<�:�����ai-�*_V�������A�R~�Su+��=�r�ohl����������Q�W���U���v(�[o|�q�R`�t]� ��D�8�
���e9jX�����"���m����;AL���7�f�&�'M(v��6��1��������NeFJ�D(��bc1 ����4���,�+��5p�}��l�:G�.p&]�.�9����������6��s,
Pvg���t�w��zI���;`��o��x*�����O���@��8�b���Q �pY:~�y��G�A�U)B������u���%]����qO���1��'r*__\�>oN���t��J~��R�V���`@���>�I
�#. '�L��l4k]����s��(�Rk!)�=�`hR��9I�����RP5I�;lj����*D���8�!�,�C}���Jv]����eR���s���!����1�m�Q��vK������0s4q�>�+��M����#[���I�i��.EM���R���9����-@����KG��������v�������Tg8K��1j>���V�� ��)��n�
(?����0N�����G����x}�+lb��c=� ���m��al���C<��S2f1)��*�SO�h=�c�J�R����U������C��L�>y�h�N�zd�
�@��<�;�k)qG�j����2TP���&��nf,-�L2���m�x��RA2��- l2�B"/QF�nc4��iy3ED}�l� `���2�$���L;���N��;�Av�C��<
�M��x�����W�+D�O��aP� ����4����� ���w���Lw|�m������n�6��o�z�"�6C��-�s�\�k��N��K��==)bb�)�+��s�|�����R�P�q������������M8:uH� p��a�j-:���:�N�������8�|�Q@�B������IaK�%����C���t���9.4zRJ�5��0B�E�M� *�j��������;�dh��Yl�d����a���
v����S)L��3�� ���`m��kt,? �dK�Zlu�����7��1���0���{{����N�@��.��M;���c"����
|d}X\�?�t�k:��'t�L�GL�� ��N"�2K�'#^O^�7%��1m�tkb|-?~y��4���
A�=����@��������"T�b���g����J�����^`G���*���B�"@��j�h�������H�#Cu$�&��4`fC&�������Z���"������?��Uv7j�K/WfsW���q�%�^c��2��aG���BC��y��
�5���T�jT�xx���������7�����^}���(8�~1��������}E�U�;�-:%o����]Z-A�XF'��y��=���������bsQ����������p��'�������D~I�c��)q�V��G��k���
�%��zW�&��>t"�~�2���(���V���kzl�J�
/����c%7�oq�F;�}8���uS(0�({(5��u��\P4�+F4s�x�L�L�
�<��3Uk�*;y�l�,W�F���k-C#���������&�'v?��`�<��������� ������V�b�a�;>�e0p��l�o������D�E7/������ ��8)�������Ws����a�������#������y��b�!I�pHz�!%y�����`�����I�F��`�k�%*����Q�E5��3��l���I*/:j�����:�=O �U��TT�q��}�B�M�GO��sr��-�X�I��E86��eC��K��V����x��MJ���i��o1��0��/R��YX���*�s�\ ����u�������!�"-�{�wt� \�H�A��y��!j'<%�H
��"��-m��4�G4~�~������L6pM��g���V���2I�� 9�
�����~,���O�7jp�z�5Vrj�������R2(�L>e������a��26sm�������X0�g���m�Q���cz=��o����"����x"�LrfX�x�@�l�K,[>e��$*2\�y7�p���� 2-�h��e��2���P;]�{qHZ�o����M��C7N����g'/���[S��������G��� ���Yll;�,s#�[1�~��>#����^ph��f�LG��n����r�FBY��5#�(����r;'~��%�����������@����w��������fd]ZV7��lf�^����o6���.�g����v�<"��g"�42����| A-H�����j���c��}�����P����m��^5�����[�h(|�� {+���������������-o�t�x<�j�F���*[��mS��d���e��M���r�c���P@�b�L
)Yq!����g4�~��)�h3���V��(��� ����}�S����;L���gS���L��X��"�f(�x��\�1�#����(�F6�:[�
�R���B�E������rZ�l���(i���'����2�����IHO:t�C7��K�� �[���:�4�$0���h�)o�c�6t��� @��A��b�N�'�a�� ��
���(��� �q7
��-�$ ���'�0���K�Z�X�I � <��Jp�0�Hpa�� ����]���
�#���-���
��U�v�}���R+I��,KaQ�#7 �Hz�W@�
b�
B��0]
3Y
�S0��������>F:��},h����U�_�����b�]82�z)r]c�5������W�/�rP�}v�Bt^k�=g���t�����`���K���A�<��z}��F����U�WN��$�������������U��CC�����N����Tx���i���
���K�����C���:4.��2�J�Y����S���G=�uDl��H�Teo�dk�/u�?��O�d�'