From 72d579b6048c3b80bdcf26c1d7ec862315284bc2 Mon Sep 17 00:00:00 2001 From: Grigoriy Geveyler <1117339+2xG@users.noreply.github.com> Date: Thu, 7 Dec 2023 20:17:28 -0500 Subject: [PATCH 1/3] =?UTF-8?q?=D0=92=D1=8B=D0=BD=D0=BE=D1=81=D0=B8=D0=BC?= =?UTF-8?q?=20=D1=82=D0=B5=D1=81=D1=82=20=D0=B2=20=D0=BE=D1=82=D0=B4=D0=B5?= =?UTF-8?q?=D0=BB=D1=8C=D0=BD=D1=8B=D0=B9=20=D1=84=D0=B0=D0=B9=D0=BB.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- task-1.rb | 1 - test.rb | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 test.rb diff --git a/task-1.rb b/task-1.rb index 778672d..4b4846f 100644 --- a/task-1.rb +++ b/task-1.rb @@ -3,7 +3,6 @@ require 'json' require 'pry' require 'date' -require 'minitest/autorun' class User attr_reader :attributes, :sessions diff --git a/test.rb b/test.rb new file mode 100644 index 0000000..67e3b96 --- /dev/null +++ b/test.rb @@ -0,0 +1,34 @@ +require 'minitest/autorun' +require './task-1' + +class TestMe < Minitest::Test + def setup + File.write('result.json', '') + File.write('data.txt', + 'user,0,Leida,Cira,0 +session,0,0,Safari 29,87,2016-10-23 +session,0,1,Firefox 12,118,2017-02-27 +session,0,2,Internet Explorer 28,31,2017-03-28 +session,0,3,Internet Explorer 28,109,2016-09-15 +session,0,4,Safari 39,104,2017-09-27 +session,0,5,Internet Explorer 35,6,2016-09-01 +user,1,Palmer,Katrina,65 +session,1,0,Safari 17,12,2016-10-21 +session,1,1,Firefox 32,3,2016-12-20 +session,1,2,Chrome 6,59,2016-11-11 +session,1,3,Internet Explorer 10,28,2017-04-29 +session,1,4,Chrome 13,116,2016-12-28 +user,2,Gregory,Santos,86 +session,2,0,Chrome 35,6,2018-09-21 +session,2,1,Safari 49,85,2017-05-22 +session,2,2,Firefox 47,17,2018-02-02 +session,2,3,Chrome 20,84,2016-11-25 +') + end + + def test_result + work + expected_result = '{"totalUsers":3,"uniqueBrowsersCount":14,"totalSessions":15,"allBrowsers":"CHROME 13,CHROME 20,CHROME 35,CHROME 6,FIREFOX 12,FIREFOX 32,FIREFOX 47,INTERNET EXPLORER 10,INTERNET EXPLORER 28,INTERNET EXPLORER 35,SAFARI 17,SAFARI 29,SAFARI 39,SAFARI 49","usersStats":{"Leida Cira":{"sessionsCount":6,"totalTime":"455 min.","longestSession":"118 min.","browsers":"FIREFOX 12, INTERNET EXPLORER 28, INTERNET EXPLORER 28, INTERNET EXPLORER 35, SAFARI 29, SAFARI 39","usedIE":true,"alwaysUsedChrome":false,"dates":["2017-09-27","2017-03-28","2017-02-27","2016-10-23","2016-09-15","2016-09-01"]},"Palmer Katrina":{"sessionsCount":5,"totalTime":"218 min.","longestSession":"116 min.","browsers":"CHROME 13, CHROME 6, FIREFOX 32, INTERNET EXPLORER 10, SAFARI 17","usedIE":true,"alwaysUsedChrome":false,"dates":["2017-04-29","2016-12-28","2016-12-20","2016-11-11","2016-10-21"]},"Gregory Santos":{"sessionsCount":4,"totalTime":"192 min.","longestSession":"85 min.","browsers":"CHROME 20, CHROME 35, FIREFOX 47, SAFARI 49","usedIE":false,"alwaysUsedChrome":false,"dates":["2018-09-21","2018-02-02","2017-05-22","2016-11-25"]}}}' + "\n" + assert_equal expected_result, File.read('result.json') + end +end From c34987ec35130153467b66f08941ed244085c48d Mon Sep 17 00:00:00 2001 From: Grigoriy Geveyler <1117339+2xg@users.noreply.github.com> Date: Thu, 7 Dec 2023 20:19:34 -0500 Subject: [PATCH 2/3] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D1=8F?= =?UTF-8?q?=D0=B5=D0=BC=20=D0=B1=D0=B5=D0=BD=D1=87=D0=BC=D0=B0=D1=80=D0=BA?= =?UTF-8?q?=20=D0=B8=20case=20study.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- case-study.md | 62 +++++++++++++++++++++++++++++++++++++++ execution time graph.png | Bin 0 -> 32494 bytes task-1.rb | 41 +++++++------------------- 3 files changed, 72 insertions(+), 31 deletions(-) create mode 100644 case-study.md create mode 100644 execution time graph.png diff --git a/case-study.md b/case-study.md new file mode 100644 index 0000000..006a4c1 --- /dev/null +++ b/case-study.md @@ -0,0 +1,62 @@ +# Case-study оптимизации + +## Актуальная проблема +В нашем проекте возникла серьёзная проблема. + +Необходимо было обработать файл с данными, чуть больше ста мегабайт. + +У нас уже была программа на `ruby`, которая умела делать нужную обработку. + +Она успешно работала на файлах размером пару мегабайт, но для большого файла она работала слишком долго, и не было понятно, закончит ли она вообще работу за какое-то разумное время. + +Я решил исправить эту проблему, оптимизировав эту программу. + +График зависимости времени работы программы от объёма входных данных выглядел так: + +![График зависимости времени работы программы](execution%20time%20graph.png "График зависимости времени работы программы") + +Судя по графику, программа работала с асимптотикой `O(n^2)`, что неудивительно, ведь в ней был вложенный цикл. + +## Формирование метрики +Для того, чтобы понимать, дают ли мои изменения положительный эффект на быстродействие программы я придумал использовать такую метрику: время работы программы на полном объёме данных. + +## Гарантия корректности работы оптимизированной программы +Программа поставлялась с тестом. Выполнение этого теста в фидбек-лупе позволяет не допустить изменения логики программы при оптимизации. + +## Feedback-Loop +Для того, чтобы иметь возможность быстро проверять гипотезы я выстроил эффективный `feedback-loop`, который позволил мне получать обратную связь по эффективности сделанных изменений за *время, которое у вас получилось* + +Вот как я построил `feedback_loop`: *как вы построили feedback_loop* + +## Вникаем в детали системы, чтобы найти главные точки роста +Для того, чтобы найти "точки роста" для оптимизации я воспользовался *инструментами, которыми вы воспользовались* + +Вот какие проблемы удалось найти и решить + +### Ваша находка №1 +- какой отчёт показал главную точку роста +- как вы решили её оптимизировать +- как изменилась метрика +- как изменился отчёт профилировщика - исправленная проблема перестала быть главной точкой роста? + +### Ваша находка №2 +- какой отчёт показал главную точку роста +- как вы решили её оптимизировать +- как изменилась метрика +- как изменился отчёт профилировщика - исправленная проблема перестала быть главной точкой роста? + +### Ваша находка №X +- какой отчёт показал главную точку роста +- как вы решили её оптимизировать +- как изменилась метрика +- как изменился отчёт профилировщика - исправленная проблема перестала быть главной точкой роста? + +## Результаты +В результате проделанной оптимизации наконец удалось обработать файл с данными. +Удалось улучшить метрику системы с *того, что у вас было в начале, до того, что получилось в конце* и уложиться в заданный бюджет. + +*Какими ещё результами можете поделиться* + +## Защита от регрессии производительности +Для защиты от потери достигнутого прогресса при дальнейших изменениях программы *о performance-тестах, которые вы написали* + diff --git a/execution time graph.png b/execution time graph.png new file mode 100644 index 0000000000000000000000000000000000000000..b80786544801797a9e9abb140fcfae74392e521e GIT binary patch literal 32494 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 literal 0 HcmV?d00001 diff --git a/task-1.rb b/task-1.rb index 4b4846f..bf9ff83 100644 --- a/task-1.rb +++ b/task-1.rb @@ -3,6 +3,9 @@ require 'json' require 'pry' require 'date' +require 'benchmark' + +include Benchmark class User attr_reader :attributes, :sessions @@ -42,8 +45,8 @@ def collect_stats_from_users(report, users_objects, &block) end end -def work - file_lines = File.read('data.txt').split("\n") +def work(filename = 'data.txt') + file_lines = File.read(filename).split("\n") users = [] sessions = [] @@ -142,34 +145,10 @@ def work File.write('result.json', "#{report.to_json}\n") end -class TestMe < Minitest::Test - def setup - File.write('result.json', '') - File.write('data.txt', -'user,0,Leida,Cira,0 -session,0,0,Safari 29,87,2016-10-23 -session,0,1,Firefox 12,118,2017-02-27 -session,0,2,Internet Explorer 28,31,2017-03-28 -session,0,3,Internet Explorer 28,109,2016-09-15 -session,0,4,Safari 39,104,2017-09-27 -session,0,5,Internet Explorer 35,6,2016-09-01 -user,1,Palmer,Katrina,65 -session,1,0,Safari 17,12,2016-10-21 -session,1,1,Firefox 32,3,2016-12-20 -session,1,2,Chrome 6,59,2016-11-11 -session,1,3,Internet Explorer 10,28,2017-04-29 -session,1,4,Chrome 13,116,2016-12-28 -user,2,Gregory,Santos,86 -session,2,0,Chrome 35,6,2018-09-21 -session,2,1,Safari 49,85,2017-05-22 -session,2,2,Firefox 47,17,2018-02-02 -session,2,3,Chrome 20,84,2016-11-25 -') - end - - def test_result - work - expected_result = '{"totalUsers":3,"uniqueBrowsersCount":14,"totalSessions":15,"allBrowsers":"CHROME 13,CHROME 20,CHROME 35,CHROME 6,FIREFOX 12,FIREFOX 32,FIREFOX 47,INTERNET EXPLORER 10,INTERNET EXPLORER 28,INTERNET EXPLORER 35,SAFARI 17,SAFARI 29,SAFARI 39,SAFARI 49","usersStats":{"Leida Cira":{"sessionsCount":6,"totalTime":"455 min.","longestSession":"118 min.","browsers":"FIREFOX 12, INTERNET EXPLORER 28, INTERNET EXPLORER 28, INTERNET EXPLORER 35, SAFARI 29, SAFARI 39","usedIE":true,"alwaysUsedChrome":false,"dates":["2017-09-27","2017-03-28","2017-02-27","2016-10-23","2016-09-15","2016-09-01"]},"Palmer Katrina":{"sessionsCount":5,"totalTime":"218 min.","longestSession":"116 min.","browsers":"CHROME 13, CHROME 6, FIREFOX 32, INTERNET EXPLORER 10, SAFARI 17","usedIE":true,"alwaysUsedChrome":false,"dates":["2017-04-29","2016-12-28","2016-12-20","2016-11-11","2016-10-21"]},"Gregory Santos":{"sessionsCount":4,"totalTime":"192 min.","longestSession":"85 min.","browsers":"CHROME 20, CHROME 35, FIREFOX 47, SAFARI 49","usedIE":false,"alwaysUsedChrome":false,"dates":["2018-09-21","2018-02-02","2017-05-22","2016-11-25"]}}}' + "\n" - assert_equal expected_result, File.read('result.json') +Benchmark.bm do |x| + [10, 50, 100, 500, 1_000, 5_000, 10_000, 20_000, 30_000, 40_000, 50_000].each do |n| + filename = "data_large#{n}.txt" + `head -n #{n} data_large.txt > data_large#{n}.txt` unless File.exist?(filename) + x.report("n=#{n}") { work(filename) } end end From 9d8dea2c06f7260d257f8aa1f180590e73b84eda Mon Sep 17 00:00:00 2001 From: Grigoriy Geveyler <1117339+2xG@users.noreply.github.com> Date: Fri, 8 Dec 2023 23:53:51 -0500 Subject: [PATCH 3/3] =?UTF-8?q?=D0=98=D1=82=D0=B5=D1=80=D0=B0=D1=86=D0=B8?= =?UTF-8?q?=D1=8F=201:=20*=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B0=20=D0=B8=D0=BD=D1=84=D0=BE=D1=80=D0=BC=D0=B0=D1=86?= =?UTF-8?q?=D0=B8=D1=8F=20=D0=B2=20`case-study`=20=D0=B8=20=D0=B3=D1=80?= =?UTF-8?q?=D0=B0=D1=84=D0=B8=D0=BA=D0=B8.=20*=20=D0=91=D0=B5=D0=BD=D1=87?= =?UTF-8?q?=D0=BC=D0=B0=D1=80=D0=BA=20=D0=B2=D1=8B=D0=BD=D0=B5=D1=81=D0=B5?= =?UTF-8?q?=D0=BD=20=D0=B2=20=D0=BE=D1=82=D0=B4=D0=B5=D0=BB=D1=8C=D0=BD?= =?UTF-8?q?=D1=8B=D0=B9=20=D1=84=D0=B0=D0=B9=D0=BB.=20*=20=D0=A2=D0=B5?= =?UTF-8?q?=D1=81=D1=82=20=D0=B2=D1=8B=D0=BD=D0=B5=D1=81=D0=B5=D0=BD=20?= =?UTF-8?q?=D0=B2=20=D0=BE=D1=82=D0=B4=D0=B5=D0=BB=D1=8C=D0=BD=D1=8B=D0=B9?= =?UTF-8?q?=20=D1=84=D0=B0=D0=B9=D0=BB.=20*=20=D0=A1=D0=BE=D0=B7=D0=B4?= =?UTF-8?q?=D0=B0=D0=BD=20=D1=81=D0=BF=D0=B5=D0=BA=20=D0=B4=D0=BB=D1=8F=20?= =?UTF-8?q?=D0=B7=D0=B0=D0=BA=D1=80=D0=B5=D0=BF=D0=BB=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F=20=D1=80=D0=B5=D0=B7=D1=83=D0=BB=D1=8C=D1=82=D0=B0=D1=82?= =?UTF-8?q?=D0=B0.=20*=20=D0=98=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B0?= =?UTF-8?q?=20=D0=BE=D1=81=D0=BD=D0=BE=D0=B2=D0=BD=D0=B0=D1=8F=20=D0=BF?= =?UTF-8?q?=D1=80=D0=BE=D0=B3=D1=80=D0=B0=D0=BC=D0=BC=D0=B0=20=D0=B4=D0=BB?= =?UTF-8?q?=D1=8F=20=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE=D1=81?= =?UTF-8?q?=D1=82=D0=B8=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D1=8B=20=D1=81=20?= =?UTF-8?q?=D1=80=D0=B0=D0=B7=D0=BD=D1=8B=D0=BC=D0=B8=20=D1=84=D0=B0=D0=B9?= =?UTF-8?q?=D0=BB=D0=B0=D0=BC=D0=B8.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- case-study.md | 57 +++++++++++++++--- ...ime graph - after 1st iteration - zoom.png | Bin 0 -> 51464 bytes ...ution time graph - after 1st iteration.png | Bin 0 -> 44553 bytes execution time graph.png | Bin 32494 -> 33162 bytes task-1.rb | 33 ++++++---- task-1_benchmark.rb | 10 +++ task-1_spec.rb | 17 ++++++ test.rb => task-1_test.rb | 0 8 files changed, 99 insertions(+), 18 deletions(-) create mode 100644 execution time graph - after 1st iteration - zoom.png create mode 100644 execution time graph - after 1st iteration.png create mode 100644 task-1_benchmark.rb create mode 100644 task-1_spec.rb rename test.rb => task-1_test.rb (100%) diff --git a/case-study.md b/case-study.md index 006a4c1..daad772 100644 --- a/case-study.md +++ b/case-study.md @@ -11,11 +11,27 @@ Я решил исправить эту проблему, оптимизировав эту программу. +Для начала я запустил небольшой бенчмарк, чтобы понять, какая асимптотика у программы. Для каждого измерения взял первые `n` строк из файла с полными данными. Результаты бенчмарка выглядели так: + +``` + user system total real +line_count = 10 0.001417 0.000258 0.001675 ( 0.011769) +line_count = 50 0.001417 0.000258 0.001675 ( 0.011346) +line_count = 100 0.002608 0.000000 0.002608 ( 0.013075) +line_count = 500 0.002582 0.009544 0.012126 ( 0.022563) +line_count = 1000 0.009544 0.010132 0.019676 ( 0.030331) +line_count = 5000 0.218717 0.020935 0.239652 ( 0.253703) +line_count = 10000 0.979160 0.000000 0.979160 ( 1.010272) +line_count = 20000 4.887525 0.017847 4.905372 ( 4.930110) +line_count = 30000 13.817134 0.099889 13.917023 ( 13.935027) +line_count = 40000 29.488743 0.109932 29.598675 ( 29.619598) +line_count = 50000 50.501303 0.109971 50.611274 ( 50.648952) +``` График зависимости времени работы программы от объёма входных данных выглядел так: ![График зависимости времени работы программы](execution%20time%20graph.png "График зависимости времени работы программы") -Судя по графику, программа работала с асимптотикой `O(n^2)`, что неудивительно, ведь в ней был вложенный цикл. +Судя по графику, программа работала с асимптотикой `O(n^2)`. ## Формирование метрики Для того, чтобы понимать, дают ли мои изменения положительный эффект на быстродействие программы я придумал использовать такую метрику: время работы программы на полном объёме данных. @@ -26,18 +42,45 @@ ## Feedback-Loop Для того, чтобы иметь возможность быстро проверять гипотезы я выстроил эффективный `feedback-loop`, который позволил мне получать обратную связь по эффективности сделанных изменений за *время, которое у вас получилось* -Вот как я построил `feedback_loop`: *как вы построили feedback_loop* +Вот как я построил `feedback_loop`: +1. Запуск профилировщик `rbspy` на малом объёме данных. +2. Анализ отчёта профилировщика и выявление главной точки роста. +3. Оптимизация главной точки роста. +4. Запуск теста идущего в комплекте с программой. +5. Запуск бенчмарка на малых объёмах данных и проверка попадания в бюджет. +6. Закрепление изменений в системе контроля версий. +7. Обновление бюджета в бенчмарке. ## Вникаем в детали системы, чтобы найти главные точки роста Для того, чтобы найти "точки роста" для оптимизации я воспользовался *инструментами, которыми вы воспользовались* Вот какие проблемы удалось найти и решить -### Ваша находка №1 -- какой отчёт показал главную точку роста -- как вы решили её оптимизировать -- как изменилась метрика -- как изменился отчёт профилировщика - исправленная проблема перестала быть главной точкой роста? +### Итерация №1 +- Использовался отчёт профилировщика `rbspy` при запуске на файле с 10000 строк. Отчёт показал, что больше всего времени программа тратит на выборку сессий по пользователю из массива сессий. +- Было принято решение вынести эту строку из цикла и вместо этого выполнить `Array#group_by`. +- Время выполнения программы на файле с 10000 строками уменьшилось с 1.010272 до 0.283054 секунды. +- Также уменьшилось время выполнения программы на файлах большего размера. + ``` + user system total real + line_count = 11 0.001461 0.000487 0.001948 ( 0.012805) + line_count = 51 0.002695 0.000898 0.003593 ( 0.009555) + line_count = 100 0.003591 0.001197 0.004788 ( 0.010995) + line_count = 501 0.006650 0.000000 0.008918 ( 0.019601) + line_count = 1000 0.012564 0.000000 0.015094 ( 0.029157) + line_count = 5000 0.050438 0.019783 0.073774 ( 0.103414) + line_count = 10000 0.160801 0.000000 0.170127 ( 0.283054) + line_count = 20001 0.400933 0.048675 0.455922 ( 0.547208) + line_count = 30000 0.637398 0.019211 0.666364 ( 0.770074) + line_count = 40000 0.978085 0.010174 1.003803 ( 1.200759) + line_count = 50000 1.290851 0.019795 1.325995 ( 1.518988) + ``` +- График зависимости времени работы программы от объёма входных данных стал выглядеть так (синие точки): + + ![График зависимости времени работы программы](execution%20time%20graph%20-%20after%201st%20iteration.png "График зависимости времени работы программы") + ![График зависимости времени работы программы](execution%20time%20graph%20-%20after%201st%20iteration%20-%20zoom.png "График зависимости времени работы программы") + Судя по изменившейся форме графика можно сделать вывод, что асимптотика стала линейной в данном диапазоне обрабатываемых строкб возможно на более крупном масштабе мы увидим ещё одну степенную асимптоту. +- Отчёт профилировщика изменился значительно: исправленная проблема перестала быть главной точкой роста, время подключения библиотек стало основным. ### Ваша находка №2 - какой отчёт показал главную точку роста diff --git a/execution time graph - after 1st iteration - zoom.png b/execution time graph - after 1st iteration - zoom.png new file mode 100644 index 0000000000000000000000000000000000000000..c7b1f652c981e2724eca707060bccf5665fd915d GIT binary patch literal 51464 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 literal 0 HcmV?d00001 diff --git a/execution time graph - after 1st iteration.png b/execution time graph - after 1st iteration.png new file mode 100644 index 0000000000000000000000000000000000000000..c639f42ccb2a8aa5671ce59f993e157ccf52c5b0 GIT binary patch literal 44553 zcmeFac~q0v)<51}TfMD}kTF1H%(YagBA_53 z5TFzpWRx+404X9wWRgJ;2t;O?g3NRH?k8vkB@ger*6*L+TJKt3yKejBJm>7Q&pvy9 z_Gjeh zKcAWZsPW?`pJWDZUA+7`{QocPPwC-5`GmI=`QN8>yCf6%m;ZJ;aluK)&diB$+0pb9 z6-QH3TfBvx)1`C&grB7S_w;{$JbUfZ$kGhqtS&pzZ$arb^MZ9Tp{Xijt|rR8zaxA= zYcRTYQk3wB+CE}S)gWg&T-|cj8^4+KNSv&L&23ZY{v^+#yu4-e-5*Wwipuzpg9u|KET7|Dh0uzF;fG2Mi7l{z(rpe);IKEhFFIMD4?qw?~83+mn)$ z54jmABqiFux?_9ip@94Y|mQQF>>AKc2~D_!>o-*;1ad8!v1yhf6V4p)4QrFHTFu|q`tQ~;m1h>CBB`tHpb`3K%^gD@Qv=B5*xkFThHo8qCfOj2XSoL+xO)v^|v`+JrD2XIe z5w*44JX)3ZlNx6@8MCU_E`)NqA4H?CT^V0iWDj}9>7*X~v!d?u{@@!wf@J=PM#LKq zf6=w84JPQx(_slO8uP=1J^sR2+p5+Mf}Yfi&_|z<9Lm2wVU*k_5b>DleoOYatA(S} zy24tL&@3)#neEw8k*SIW8yBw;z$`n+2p`kXD$YEZXWbnbxJT+&k;KRA{|{$rD`leQKjNOkzjILY*AO=MfK-^AHAi2%BKa5t^) zXO(m3&ee5$6^=g>vz;1z!Fri#Y~(I6zn_dYIJ{Nm@*=nI36tXD=;a3k|A; zBNbg8r)RuI-I@4O-|eG!;)P;Ib!4A5`rqBBvKyBU7r31LDY>VOJc9MepTUO$&#E30 z<&|86KUIn*_S_x57LU0ln~@bI$Sj-{DVLLR9mguLFI-j*PJGGI6mmg?G+D39Kll)) ze+T&s&dcCK`X_Ltbz)Es~q3>^PbOscgQ@VaBQ8k^kw)Bs(fU$mo%>RD>yn* z5~1sB`rhnPiJEAiNedOU_fA)pD`aPHHaC`|$_t?k=Z(W_yf7T0%JY;F91sayF*v;L z!Pty9>t;+Fk~C@+LxjY6H8lUbhfggyZXGLBLTb6pXI>jUY2ko2!=@_UnXbu4e%-Oi zm3_r>UFE+ZqsweqFcjR5_P+ai`F`00Ezuh+z_>5su_39ve9~eMnn1+ywZnQKkfMA( zQPkIlQs!A-=mj?vkO>>e_+WOXJzsxIJ?RgWrQVl@r55|)AN;n#a)T)5O;xESEsG49 zfw~Um;2qzTm({PU-;Yevix+BAD=gcoa=2D^wB7Kj0@-MIzAPI<)6s2+j;hRWuxZa_ zW~x$a_(|2ZN|8e17!+Y|!r`Y32__nvL&cs0b@gbPa0dppVwSZu2BM4SI!F7K*^?Gb zG-+$YaHPAk@=Fx-UA`VcvHGb~LX$aKR)Hq!Z_He-spRrSs|8MPM_aHI-nm4grf$;` zb%XbYwrCsLOKOI@pr6W%W-vJ-^Gw>m(B66wuhl70<5!!gQt2HoLSIg7JY#5RIGOLb zP2gyizkpo&YlRoTk9h_?6aagFB2Wyx1H?8OnJlxtwH`l1i zRQ9cp3%QOq0qF_w3lDoP)=gUUq7C`5>fC@tfbfuRnrh&AUX+avd78RB9SL6ROxFeb z1Lwsp!2vj=8lU-*hY|Ph@LaNgWdzAsTwFx();Tp8H1pQamLFgL+U7?QMT{R!GAoI_ zkoy2Gij)H(9|r}z&V9+h8j|9~Z8m(;)NF}tWX@9)dNbpJijDlvlu+b)-xXi~v6~oM zm0IL{wW(*;-C-PkMam&?x%cPlHpJO%^dQ{I_{BG!lNJKI(U)%0M4UKBhC6gCZ&~tw z(Dn-_9v=DFmpUMAP3L3yHCXb|jZtM3;Aq}N)UlVW8QRehhsk`Uoq7?1tl!VwQ#Jm` zM^~Z9Y$Z4Z2rC2$jr z!?MA%x@NwHBwJQl#YT%VZ9+VGI~$F_-Sl6TGp$^IUDkRSS5Q#!+M##P(X00b)mOpUIr?yNLoumVA1>shW0azW#Cg!AelJMR z=#gJ`Zs3Nix);>aiFq*({>KJqa`GsChA#$;OkRaug35vq`i{CqQpQ6CvPBXzX1aPd z5P_XEoXfmv{Dz9xVG_FWL($R%B3lo%)7|=Kw;Uq6>55CN+9k()UhJnM!Z{pV&E{9n z7)vJ>Bx;(ZN4l<|KU!zgH`Z-yn&*dib9U}W-qh*#v71?&cED)=B8vN1oXAb#)j1kRM88#eG zd%EFs$7Nc|C}RbAA~4lNb0_romzwWpbzO}acX2z3q#{tRkE5yjVIy6K6^Cw5ChdlU zI^O@;a?H;v&d$zt-Or@1zWiPeVD3Nr&+bFKY1^~s&h7dbED^(FCvMW)8J&syjpy*S zyO$yywA9Wah`W5-x z_A)(r$Ip0g0^kV8JN2pUhn_)_$M9lL_fXWGR$8OgI$G8;#->(C3D*D1`V#nz7w)!yh~a84gHPE*aM+yy zrwR4BmUCdrmx}VhrRTNez6#>b;<$^|3g+=DZGY|M$?OXe5&iG3mb4F{+^N7Qoi^qf z8~VcNMo&g{voDc`(lz->H~Mp!e!*LOkF0>b=S|2TI>3ztmt9^Gn)3lxH(sGgXTChM z)HmCZ6oJQfY%rjli{{dSHW1{GbnsQt2376PXO>Z>lk*Ho6DJc?sK25l0}n;R# zcfl&ne}ikq$v;@h0X+Ja`k{@B?Qlr#)h@v%PZj!gm!NHT07iIMhhM`4`Z^kAV5?2% z+#PC0!MviaxKReX)x}{k!+k49e!Hw42Zx5*Pm4zNm{r}sD+KF&59wFj|Nin%ZV6)R z!Js!3++J%>2Uz(@$cy4yvG%8wQ(e<81a}MUVLsh?6kuS0W#trih-#{PF~439aeX|y zV3%b`3UsHvl|b&d8Uc1!JvQm&2kYqT4{0inJ?U9?9XIM1h^|==6>h}Qc`=Ta>BZk# z+FPl@)yL7XLw1gfm5m6*p;N$(gF#ugfRZFdQ6bLCUT}k?gQ5`9?jy*2b+3&jMDQw z7hK51Wp}H-wIg^f#m?fV zvT_Yt3N4=a)(k%{4ZF>}mM0-WGSV}9vUh>G>@_|8{6;CwBkfUah0axi=yoiEdAkjW z@x0GFL4xFmm^R1Zu4^mX{FIvFdTg}k+O@3%>31G_uT7>T?Nf=2U}U9~=d}Ax_)gTv zd2T}NPIHomCaA>d8%XP{3-UMK#RwPbKJuGzaLcjd$me3FNFr_Bov*3u6CqDNt2^zT zJ^Of~AEHmmg|+pDBV-V|V1G}G4F zaYmfV*Z(Jb1M}O%2mq|WFecQTkB(wqhIn&@6kmtNgX%qd^P#DBb&OpF>os9o*&Wmt ziJBT|*4ur1cP}bZR_B^4c`>+a&&7+n#vhdEdDMMAP&dAYh|p7UV^y;Af{O)x0Wf!J zf@hGBxbPYi7j3XA>F9gT_u_WJry$HPAhJe%E{`S`4+)xvNekCCrf|IHCkSreW$6wd zb7~yzx=lH3X}{ZO(Rb2f4)x))H{YG=cV2@i->PitfATX;o zVL$!sntfg?>`*}~+#?!5g$TH}#u?C(Se0ff4N`7ndWyoOxWD5Ay;(cndBN64S19_& z`s$tdRNT?WyroXNbP@WIA&OXU``MBJ2m(p3M4IZ>uxJO`s@0vT((nkQH@Pg~g$e-B7r~jXDktN6&6rKj~J7|SE5O)R9&i3u(boAz=_ENya%PSgM--x-@VHn zt}z7xu|3c47Wvy&n1(%==`sisvH^R-eKDZS9nlQPLZ54ckODI4tI+Q?YHyq*-xx96 zWk5P2&yIR=%v<@`D#&`R;wzWMLUwCDgQgyshx%Me>^^^Y@Y4@wA>IQ93H;xtLqAy3 ztLJ&-FGtG;07yc6u7vgcZuv=aPyOU2Qe7Cw3FSUZ@AkK|R1I|b97RN%vz1k*hbvqh zLOwF}l&iIcbo~jLhJ8tSF1A zi!J5hu{{ldho0M!ZD4TUr#{yjkZmV@^EAC=+R7|v^ZJp)i}L7E-+&`W^2@>uF4QCb zD0em59I4#)rHjL$J7t3n>UrMjGY@HPF$t}}Y2-%YdTP~qZK5Vm=J_?e8Ic3D4~R2d z_0791c3*`=jqrTV25;}uhU}f^O-`V|{mt8WG3m@Gzz(R6PHs6z(Dw3s`JAchW(cK_ zOiExV9C7Y)ck<)G9>v)8~~aNst*0B zjB#<8cja7^+;_(Urk9IY-$AkZxFys9Bb4=-*U~)s%*!VyEtX*^W)Xt_TMWpbRb1;V zyS2S=;$#7(R13dVQuy4Y^*mT+xkDq`sjjA?kctDIBxdombF2KE%|Xf#Lb@lLKTxUM z#5?dkn!&!_^}N#%+ur3@V+USlgjhpdFPh2Td`nsXQp`&)NLE8;1lUAe?a{vk$C2karNjw*jreGn-m@X0-VQRQI1bFk`^W~0d4V@~_+=e%JKA3ie2sVl z+$8i>WvqBcQN&2sk(!9`=sGkTBPDo|{L6KHrxMDpHpJ`WDo2%VzM;6WYk7XziT^-9 zX-PTC;%#KAt9eWdnC&ImfinO$aGfhS2YKoqWz`t3i*QqCo5!n6q0M4HY*J?X3j=%2 z`ku3nh^NTieug-KFExu1WcCa{e1(2U5A{Be9cg3yxwYnW1nGvcgc@XSQLK2`zLp~U|gIsTURr$s&&&U*o^zaiVN8$>wD`f zZc_m9rs?}ZtcOgXN1Lz;>RaQ~YAc+bd8T#(3_zm}UE47U%XOxLsxA&S7(~Mwrhq($ zjN7ICJ2#3eLrt12>5$i~-gaL*y$8>^tsHO|f%Taao?JsdJ)1bLZil-emcc$3?( zy)H?tUOu=dizfQxRj@z7Mttt;_AQ58`?0)K6fnnfoc;8#vGi=H@+Tlyi|m|>uN$CK z>xRDpj>j5-jEKzQC1!9H?7G%-f7W}4S@!TW!Qp&|hq7CaJc#ZWmn1U48aoz=s+boq zUH||?e{{JN`0w4fqILZDFh#=)&H%Op)E#ZD_P_SFf5Tx@+9%~?4ri($!PS1_7j)rW zOA(8IL>EZi#|(~uz}{zf|3JvHZ%Zgt6aD84=1R&x~x$&h&eU%$ zDgfFNtm*>h&<$>~UE)MSiv3l2?hdvTDIC8K41Jq7M3vjn>|?erZL~t{=Hv+0s9c?{@3F$Ti(i0M9eil~y+Wfd*IAdv z_Ekq3Y83eCV5j>a{~H^9Y_p&8(kdi(%>h+05^P=UngE=oIN}CE@&k3-?K{s^-F^oB zbj{Y6cl=NNt9x#6yCL(DZ#3dIpL>Jgc-C}8)W22b&A#(MZ(d)Oe-^arD69}yq}uQ$ zx)=<=RfkNzK)LrDZl~oSuZ>qH&Qk8>dJ^q0 zhZtooZ3qbv)bI}G5a0Wp#@fT>)~!8};NK#lIWnsca3P}KNxUJ!+_bjH!D3>f){H8@ zu=~XW!1Q2rZOkE2uA@65;lBLP3>XA*fCjMsK;+*XJ8R2LV604aTjBhlyT~fBRw}JbeWTUUQcna7wZ)btAv3g4EGDa-bHl z{stfJ%To>kjYk0aS0tzU)9J;<$LEUdu6!vF{+QV>Ahc|L>qib9daX%$9;;D%yuH{j z+vzmqvO$iSnB>ng`_47>?6kg!#sC^Ac=@o^ur>|5)RhEFbGbb?}Eu2v} zek&zC-38Lutl6<{O9OgTghy~gW8*y!Lt|rOUlH@>bVJ)`_YSr&=ZZ!>Yk7o^7b*w1 zO-_0q0?Iix9dy}Jws}|o;W7Gba;Wx+>>&#)ALxN zL7KeD;F~r4|7}xMMGz5%>KeJkkcfGagw~9DcZW%iS>AWjEM6E;td!J>v1&iND;_ez ziH|A{Ha*|z{)N5}Cxf)wi>n&XV#O|GFW5m@ijLgElbHM#(WSH(PK6gAq< zz^(miUob=f2l<8~?=Sj#x_G%>EY9pK{h{r{afBk|u0G`#RO*X%bOdsq4_&xz@iBft zcL>=N6NJ|w zILIp(=x6&*if{q&^o|c+x+Y<5zlcrNSnjRG9#No2MAm0CLIKp1rwIS?ZB4)$g{~|e zGo~AijC8k?jFuEF9s8o(RL4L4qnM(nIQT8W{#xy?oe};kQ%>#=@70_N9DFUmxwfbd04;jfVDkR`eofwcu*lg8FE^yc42jSR5lTz zN92+Nsv}51J2_qZ>dwE#R*Qah71ppY-~!^-_Dwj(7zF^ZM?naSWgS+3RdKf68I7h_ zhl_iDB3P&yx+MTj8w!tB#gnVkW}e+I@9s-?Srpd`&K}CP90+%@KLy28tJb%=j%wOp zJVUFBpEMP?2+q$}XamP*6FPrQEzy%6{I)sE+1f2(AHdG4t9N>JEt^^?v9J1Brkp7x zP8CTk@IcQa$7sEp89jb|&>UHL0U_ddxQl{lb0{(&{dG>yJG&>#&#-dZW+1!^!cXoZ z#vo~3F*}NswWAAh?u1){JE|-K3UrO2gn@_Xbr{FL*%xY#R;lFbI%BiiBQ-IRvhr#Y z!o3$=hELW02DlE_^?luEp%bj{&@iPJtg}3&I}jd?`g8&kq--`X-4U3m;tpsIcg0{? zLNsR$0B&((?r>{(^Z>vN+;_weKl$oMa##6KmPle}TSkLS5#Uzbm*_AEoO^5gqsQm| z!@(c9>yV3SElCeHW%yYg>kX@YAiN%Jw_ENuZCYp_AIhkR-~g7j_W*+T1jslV?JKZ&&v=gW-C=SNN+@D15oK+o*!j|PNy3-@LD z_9E34plfrvx|F6O_Xe5XPq~Zivh2juXq;`!3tb>NBLH1EWOun5!$%R6f$+qv&2(CJ z#6M7`P*&wLz%=8j0flf#TbPMAf3}soI+R}Q>-2FW4<}1O36{LMi=)A(s1KJXvcaxI z8hIR7NcacJ$_{3;+w9=>Ec0)sG;P{apUsbAC(cVZLuqHcu>?^3%PIJJ8GvEA9**QtG*{5JnTs^P2LF59wlXdS>y7n{1 z)SNk3HpfMA7Tl@>Ukm>HQ^IP{b=6g>yno_(Q=0AAe&W*zlBXYEym>1~nCm3YN;fOb z+ruO{)OjqY9(R?Kw#rlR`3Z=&$E*1vEb+(F_4ONMMqr<%omZt(S2-bjhQodH8YyLb zhIeEY7Qzl|);fKLl+1Ej;xDxZ%TJYIiBr{b^>K!vZd_-4Uxwg0e;T%4Ec6WzYIwnwsp9KIWrC$BG# z&BlE-TF2pZA84DX&beQbZYdg+>s3U;Tfb+3_znNv~K6cipFwk7RZ5#2I~Z z-%!RaFGB)c3f|E6B1aj*@AY`T-uv+*n`TU@@@gKW)JV@R(41KY z>Ou{NGsaziUWaQ8HB)Z%lfsY4Z&iuz7>_tMX3KrF_1xm7f$bQRAX9)C4yr zbd^>1fC&q7*K40%5c@W9W1bhQ94RU6(!0Pq-4liu2|TQ!G-WG=hL6^ zlTPqOk4DH@X23z=W`k5xt5!-vu}a|)oWvS8)!BEl@0NKC*c9jOxI02GAn(ZS$+-IP zg)m9{$~EmLS@0L8wNL>UhbD!0wUEOR)29*s6L;yVn%P3BN8+tm@}s;>kqD6(OhM5LOM{Guo9Z?%AkctCjkeFtBpN$mts>d0Jj3W&e!48 z?;(^jF1%uGbC!OVJcP%A1y3=p1-pEIyAZCwhPC$Ixbm9zjm4=L0y3K=Vh#mFqI3uF zo45~cX6rdI1uplSm-`0J2>yJ<)YbuE2EPNWSKW|j!xwf-KI13t4>KITm}jTPiM#QB zT)5S-PZc{_2d(HGBw2+iBhS0hmPnkyecC7bnwmwyL-kQo3KgMejZY zhAKvboWL*#?x)l$aSmBjbawgPvE-B#KOxw4kI9@;5-t z`Z2-wmG*#fX@sn8$vI+Bk_H>I(rZHoA}B(_2f%4R!sFaYUrd9jD^Aa*aVVT0%Q zPapxlSNjWabr70|`Y7UCbDxYPOs41#G8xZ9(4qlxmAM{+12CDIVPrDZA*@r~(J(l= zWbRePZQ;%DrId?6COup)D*7M-7jZv4suhgI#cVk10~GW6xcF823jWszH8Lu8&_N+O zL{^@yu_a)*Ju>$VlGU~!MS=fn{jaS2cz)w zj<)vp8QI%5^$f!m5M2jO#Jf3VLFcEJvr&;>%a}b-X$|n-BlY-2Q*_axmWzPR#F=8!>MOlOU*|6tNra9 zk*;L{(|%3zY|z$h5p!nOiGlEE|9!s@ zDDm;Y>*V8=gLMR@oge+(87w4hDiB8kxL~+K6dE(Ex=*#t0f$%j091Yvd%Bxm zFaZ6!Zfn(I23SS?(SI5xf?p%RvAsZqQ6)HzkKR8&T>aUX0uhRZW1obp7EXo$HG$)m z@41Cgv{(S`djV0(t^)YmkGt;xlL)v1NV~0)fpp8UogHz(cE4ZSYAJng)p~sqyd0uc z4Yz#?KFY_gy=^;*B%H8En9J;$?CtZ11-4AtZv?Wj(kR+t`=`}TFYRd&G`*ji8~Uhs;PCu07@ zp72ZA_@p`lT>#p$zDFiPGj z#Yg3v+M^a6nnZsUkj3Q3w?Q(>hLdDKS!R)OwdXmA%ccp;(}6y4mn$M&O;^!{-h(+) zRW%QVb7|^ngXutI0kb58^gUbGX?c94pUrrjt&&ruJ~AxRUh*QPK?VnRIrn}4GP|$C z9jfLqqqMLU0E7E3vRcMEx4_m^%3|Zeu5lmqkY?jt+E5*9jMbd zR1=X*MHHlS0k8u&m)ynSY)aoU3gQ?kPM)+FKo!Ta`W)LR{qO%wE75aeE2LX46-=sc z@QbW@78Zb?C}Ge0LL<;X14XG_T;7K5%Yg%R#i+}(Dy6w!EQVQ>P|{tyeZT=i-SON^ zx5pT`0r7(>D`^JqqIR@}${N6|p#@^1$^wLyT+eMP*2#Wq5L`&7PSSS-0CfMB+VF9raeYWE#M)F>iX`7 zY6rKtB~z=w<0Ou^!gcLpylL!lKai>8Kv}wJTi)btxR1CRpbHL3eFZ6SQ$skNsFI6v zBuak;8oCG0HST&3%mNoA^a4d~17cav*`{j2edTfr0O~)1TQWMj4($hfN1j8ci(YX^ z_tvm7ice{s1^12Xw6~f1<`o~80_>tfc=R-fyvzOBbH3A(dZd+*x=GUDe)K~Gx!`82 z_5|@_uzd)%vZ<$$xU_3(r}TH2L;sj+ybOH}kbbCZ3iXW-9Lq875(CW~lO$>eoYBH4 z*Tr4|$_MnF`M5`bPlPh?#7uZ<>ZQUckb2oqe+WF*K5YWm9|S1_Uf;eFGDDPl8pw$I zl`CTZ#ifNcLbh#Bk%ZJ;d1Cabz&v0@Y}@bq6W8HyDZ5+m24te16EssBWNhG3sC$YA zstELDcu((r2f_f~6}ldEg&GkxntG0?FH7JW5Y8KrW_h?y>6JEw9`KU##2EEJm*0R< z_a*Pt=D~-cQSYf?@9r%6F9eH~4E-=9jyiq7;He;lN|v@Ako?x4lbJ8L-T5n-Sa&mZ z$Sd4{msIhFaNV`P{cuG$$Y{l@_#vD&Ghfx~ZiA1Y?bAm95%5;6NOE$JCpU7B zw{CB{AAJy6G_YBBab1Pe>zA?0l=8mh)QT3F>|?kFAc-IpRY`7pu{lmT(&!q*J4cn4 zuR`q;ykHMza4R>d0)4fc)S~Cz&2;+1nOQukz6Y3ukAO@HeaxY^2d9tj8nf(O5gS*n zVcT-fI7`I5HZ>eb1PE&~Sb2%-vhM?(lpzDUJ$IwOKCTFg|MsZ!PHo}3W``t)=~S>h zUQ4p+Q-84mXaF@r2&=Fi>kD>|;4!y1f9SjPzDC4ke%>u%2IS*i66*+b9B85Po-6t; zNZqrIcW(Q9m7F{RfI#me4rTQ$FSk{1YLCUqn8S&?C6J-!;ye!;A@v;SpWMWHefT+G z0qt-;!47q}LPQ&nD2IvfvoE+=fN!uls{-tW&F}^wn2K_J!=QHQ?Ew(#c%J~HE+GLf zbVN$Y%DoU(tS_a1VUA@HGV~qil0ZsW;w86)QIOK6y1k#jeaZi-^Epl-r>EF`r5nsZ zcOZ0wLC9tP*I(ZOyVcH_!TV~UNwt+~pv@7=JPkB!!1`WBGBQI$C)JmcSw|=z;wt$H zsES1DH~GjkbsLDs)t3={3sP1^`2~-bA_Nl7JB$$80YZ&ccmVcdeW_>*CNED9rItLz z5VEl@v-WNY9KvbYURkc9fA##X&t|eo;|cIiGR!W!C3qlmEQwX+s%`(|wYj!f2N?4F z{1Ye%M^^Bwa>#$V%;~GPSSS|-9JzJOxP7dtX;K~e#TD$?gWT3Eg*jH}PS*Dr6NXa> z(Q<_Y?5T>n?;&pLwl6_hK*;?&h#ZUO+#t~bw7`Z~Rj5Q*_p~ILAWgdWkCKiq-3x|( z0`z=W+LCiyWuvVCBw%q7ULjzIfo#VuraJSm3NfoAtw?`t#&ED#ms!m04!Qm?QOc59 z*aM?@unE84t>6~koc$ILp$Zr&m8sK88VDtkJs(!V8wg#PQC=EbqnKr`<-6Iu<6&aH zp3;Itn?y~8s0jT$!$bKU8L6sw<2Rgqb5S> zJa`m@MB-0dIZRP*?v1v|(VD1kKrAi+AFx&y8{MrEkgu#y&cAtXCO^~=8*Ci%E9&&` zVe!p5TG@T&fzHIi0<%tpJ;zNzy;Y3)z99^t2*DkvI5dI_6;HTC`p`0P%$Uybp)FFB zy&Iq*{p3{$$blBa<%1jnY%?LtBtpt)^z+yf%ZoG#oIZ#6w}VTB8>bY$r8!lzSy^{ak;N5$=ySqn;pI5Vzz)Z?`+qz~4Z7UNRi36cr&W=XDi~##<0y znj09RTFsa*w+7*i=yYh-PNL6*9A1G6 z2M6o3IjFoz*IR7rLl|Q6o~!+o6?qXNfj+ab8~s?q;x)HCI|Rn$y0@`aJ(x!5IRm(- z9VRk*0NQT=bC3%Xp+W%349xOc3BkdolV z=p3q)f`V6MH24b0x+$=IF|OB|CCKyX*ki-5av*9UiOHcY%(qrC-z`MnYvi0BJ{vBU z0X-hH$LY!2I|#DVtLY2Lw+sR3R5A-^*4wK&Si*^5_QM_xRD zHb)B7<4CR=Vy*X5`(VE->0?dj$(^-93Hp)<2o%%L>}mtWs=}I0kR&DEN1`{f|+n7A1c3Y9~KPA#TY<`rQMobwB63 z4C_IG(@{VIcord`GX4wx3M%ZbkU>96B)9N&B<_6-N)>O%H7rNicTuL>|}4~ufcOef3=)iRio7otS19B-tGS(D;j6s;@wwKX#-^r%QR4Cf z>p`%lD*t`>NKFiO?8%Pc<^FIfhDjU+~}^BV>&Ut7Si;y&HS-0!xx%*a`N&DAoB#DE6~viPDx3@`}_OD*9{D* zE|h~h2_{75Oz{j(&SUls@7IHMk)zoRpzZBZa5VY*DpL-boAz&}B55jrvR#1`)>pZJ zlarN$N+-??PPSKc_F6$fk#AUWJ*-Lof%09wnQ^}smcQ_V)$Rlik#x<1>mo>3czEm- ze@OT@C$ctvR6A0q?8}%}VK;)cXraj9+7MPfl5Pc$loNsZH}zcmGH`5ny$x`LI0Ykn zs_^a>L+3&Fr{QLR)GJiRA@>NR36XDTAvnZJtF^afN*okP>O#NE^0+AniP&roA98qL zehay+fa8Mn*Wy4tpsSO7@AFpyCGunlKVcITWMC6$Zw%fRVgTs@>XLn-%jXAQbKBg; zuq7@RAx8nc)q0uBZ*!kqo^D_?6;1vGH^y@P{3`!!zKUPv+It_0Thh!-iZV+cjp2{zG&dWatV^IqI5A zOocrBhnw-i52D%t9dwrMCjqqrNv=l^0O-s~u0u7|IzZbd2U{|2#8aeqPp#mkG4uJe<&)3+L zl9~B8%wxhKB$VmZtPpKQDU`Ik$qPzTb#4~{K*N|-k^X6nO*H`A=#pBy;I)<(2)M=0rmShrxEaTajmDH6(gt)?%O;lz^Rvsf0zA#H>3Y)pNZH2gmh?I zGfEudWX8lUc~V|CPnrFl6%*j{{YAG4PurM!aK3>5OnjFXTVD;`=8wzK-dy$F-2W!s z5a`|L(sP>e%wsY8n{ZAmRUJH;I;cGTz4=l>udB3&lr#j6=C?Y? zQK9lcjh~b|!vyPxD*k7c9TA_~4)n$aA$dU#@#^8Wcd58{UdC$U3f;8XgImduUSS%~ zYewH&mAG5?X~nDVkWHqHb-x-shcwf1O4{@8yRRP)Ol|S?uOiq zHa-bDcOYGWKB~`YBwU?o1K%IXd_nyzVAIe@a0j>H1*!$)@zTJn#I#ba|nj50$h^7p++MRFPw!n|p9o~(e0A%)v$OwF` zBT#nhW!jM>$Vp!$eX{Nk9t*a#y>9AQrbG6}VS;B(ZVB}NaFpi*QLIaop&S`Rz$j$fxXN<@_WSnUroiutq@@krp8W zTqdJHcu)sXeUYBGj{DHdHF=YDbgc<9F8rGFxr@!_-8xzi%;z}`OQ34(?FT;B)@(f* ze%|rIuY;{`klmgMnT*`tZ(JOOssoM+#xg6%$U{U>%PL ziUJjLY$Dsn*zQnde?hLFPpSG+L?6A%AXsL3QU_c3+lYmZ&b+8BXrPp|D+02uW3G)K znG0c^p2~X6r0LH*-(*|z`}AfrO}FK0hSAdFYV1fei^^EuDgb7AS!ziDnFiWeW-Ozu zmo{E(J#tUh^!ACWz!!v$zP#e;Tan9DrWt*FG(8krBH5`fi@+@my$-ltID6E?t0U#8 zHlu|j=NXR1zCLAvrn*L*d4)=_Z5crY;AFFJKq(QyX84{AdF!tS^NK4smGF~f zD~I)&O|=sWpwj}U-aCW!9^PNa)7*0^95L&_h;$UQElgK4&IZ7|y-Ci90L4@ZMuyOP z{Vf8%j;rz&cH(KrN%GKyr7e6p(~v(hVxrbXAjaddEc5~Jaz;p9=Q*i@buQb03*m?t z$q(J^oopdyb0@bgm6@kIk9JIIO+r!B+YH7!Q-=IsNv<`cN$wJULX!GG&A1yfTt>-F zg_j|dhE!g?&Bv^Boi>L14iTtPF&@L`na<`-&#Rzg-}v$gqI|85Ti?STjm?cnOSJw+*x?eD|=PZE1I4!HshV9q%3K*@T0X#|o~to}3^h)In(&S$wUm>%K56;a?4EMu?0i zHjO|Fj-|n)e}i)C{kYgf2W$w(rXDu?YO_8<#ptxq7`0j*%EDi={$Tt z3N#Do)9rl*4V=2y6r_g(Tv`Z(w%&UWH_)o8XpF1v-ZRdYR~IipIj(K(?E%(oXX!x9 zf%lN?I#wj^dpt9!%obW$6+pf3^Z3k%7@}VrP&Ly{=>d}|(4!vZ#hEVChsh&RWCn06 zhU#A)2Gc$s`W%YuPSFYwFZnI>_)$dVGhXlZ3oT_CJiETY8KiJ^sGgBZ9KPHvZ=Hbk znzWb~MN0U&uK2)qC_A!;I-Gj(W6Pw}Sjc%mVC;-d^cva<+_HteY)Np{!HLhE% zJ3#Rxi2Xz|yI`36kjNCLU_eD~XjX_v>`F2`lHlbv3 zGNlwbxNjl4k6n0bU*SWoFH;L9j*=JrY7LQ3t;W0tWbqxS^x<3^#vi{@ z`aK(3kFvf4Y=>K-^ zKgJ)B+_oiD5|3C2@q#xVasYW_K*YKMF3=jiQnuMflUA_EU0PMKdEX;^cAJ>-0Db86 ziHYE6_Q0o_wvmAll+PhZq#-sIsrG|Yz&R54|0g{^?kz1CoEth{EZZW^PgJX~auV_@ z@8~f*zHqzkk=3~|B}uqyI3)_mH&!7N2EDP?HeKHX#D`Y$wKG{VI{1zj40P?f03}qm z07>L4x8;c#0X{qXMKW?u-c75e;xy6l-)}!3T~(6z{Shd9&(rW~5U2J%14{~J)C>p; z9Jic5tVJt;qOFoO&CmXL-+4)J+g9Zv_L40yN+~aPuwK`{oXt!alprU%`CwgoPR)xJ zAO!F=--iIW=v~M3O|F+;QhzCKd(%&6Jicr01gA{1CSZo?ERH2SFv38t>&==kF|1Of zEv=8A=Xgc6jnDrFLA~IxKn?o9QQXXJY<}|5r9lpjoa=ipUzX1@4{V#NI7=SPb1>u= zP=bp#uuUer6{F;GcxeZsz+7i7#pi?gBJ(Oj$eGD!^OL*1XBeIH?G??_d?>O?om3ix zvTUkpAg(Laz|8@UDQ(weA73sTHPaTbrXi{e=jHLyNozul{}bfg6=x? zRkPb)AHHha)Iqe%N{NG>4QnLT+dEO#)_$(G7Edc0)t||bD~eof6;6S!a`17dzqCV( z{v{Tke53Q4b&BdXfA>r>Y3_*FV zY)w?Km+aJ8=@mleyX??5sAHrDP!mGWH(z`6s4aKqPTSASdq=*_)t{lnNAkBX=1$p~ zjY!N?XJJ?qC)ybFt$F!`{;Mv*$#MlZndyXDVrDsRZs5?&YZbBf`{sT5!X1-07fSqf z@ZCFR2$bdJYG>hmV$n!;YQoPfR>`oiWTDr-WIeNZv#MuuP%#eiz_e#u6)njZgRv(?YoL+Iw zyh&u{B>YpM*+g-{HN9fiB*eX^G=#-A2zF@JS7X@N9d?xKkGO4ZL>etujI@@HCXGm3 z^GFbwd%8_-@w#2R9SmG+8`I|%RD+K%r`=x8c|FFy9n;GnZ`3{!f*mQgV@NvsH!uyB z9c4tx0Y)1Tm8(+hls?ENSD!QYcX zfCT3x#tM*7HQpKX2jB7QBOXdOi1kLA0m6jz{mmwV@{NQ1FqdhA;4_BV&(d1*nBvUB z<`=2V?!KOg+h4=ZrodiSJWgYIQ=C~N;gO6Xrj5O1yhiyB_-~!?-{=P`8HT}O`T9mi zJ+^M9u~ZQoX^9HiulsT5M`{)uoa7eScI_D{#V$&eXjnEmXD}3uicKY3TP} zTC}nm56Z51A<*uQKT3TFN2iw04$qWecA8~$jOWdJ((v%E)<27 zA-qPp5czQPa9WM5rZ0IMRHG2hXv6>}jQAy+I=tTCbKo`Puu=vTsi4G@KWmv6vNoQK9ulwCOv^ zDE_4?QcvQdxsr7066<=NS@#nx?Ns!C*{?&pW^{J4*`w*p^6rn5`QwiYda0C;R?TAg znI^Ls0U91Yv9qWdz^og?V!eFnwZ6=;F|3l;mZzhi&0%5_l??6=|7$MlTbglC|BKOY z=Ayo%#q|(EJ%T$45sLxAOxJO&_WtQTm_5%r+>|_n`-i%LqG?S`{r5`0SY^HGpM0$P zShY$+&-0=01$!W|fI?ZWohz$l3^NWWj>3@?c3RjiacbFz4XD_Yr#&3c=W<#!J8{50 zGT=M8+jgy<-_PA#2=cd?aZoqPlyMyhq@7_fOFM~ImLG>%2S+|x+A-qJw50yXU{W2X zwoU|v@y)p#)wt!`kV~2UZyK*d4ow+x_gM7jfdnQWF#1qt0V9h3fN;ryaN7 zj!|A7mnYiYwi{k7l4eJLO&q;#C;e>B?4M1AX*=5lBHNX<6vNo*(kqhKZ8Ed1tSU}J z!}i5*ZH&SOuaUl`KHbyCG7}GwhNLcn6G(d?$6*ayNQnm%&WOozkdo*>2KNkxvqk6F zU-UjC7ljnI)$^$xnmFAZeO;Q&HdULeh7xQ?5{KT*@v#wgN2utbzi}}e? zNnu{trMZQFFH+CW#k^6PEcsG*swS)FCWRJLLcB;N5|Sr`?c6CLw37KJ*jBp->5Z># z;JbW*MjcBb3pT7{OH=a+-Svzqqo{@B9;KZEDeibCGscmbXm@l`|C5E$POTnkQ_U82vKgzx2-l-4ZJbeOLA%oElE&71q3@*(7hC z*9J5~Tj*!k%O8nl1l5I!P^F^;A`o8j^pJwmvSt135s!&;^JGiTA*t_qz2{lDm*_Xk zCgeA{Z`k|QLjI6rCN3NBE`LYq{K2oSAW>mXJs?DXni9d|&PY9HV;3@{q*ls|du3F* z{7lY9E==ioZWC^n{Uu?hO|5;l*_y#4DS4_xXolfS(`0$ecgK!09ugN5N_l#d>zWOB zEr%A-3j0&8HkZBl+-RXEZ7A7)5H)nbsiXp6%}1`saho zQJIeB<9UzOj>?Ki# zN_R?pTX1CDlJBR*3UMRtaNMrux>qqzEp<2&y0^ZlaGtI0-!m~RNT@S1qu_<2I=yCI z5h^@)h{n$l@8RzanHsP=b`k?`(R9n0*^Zq%WP;rtoI_#~gEv_k9Oc)_Jv?RgvOuuyP3Q>c37R`-LALQr((X?HeM74=F0~N1H=b`{@VO zW~M_`m*@VXaI@_bXWHWdJTnrkh&&1VSPI4`cY|~{sH||j2mk*0a*0QSgK+Milx>Vq zmn<5$(FMet=Ro`O@vtu2WC4(#&jIn~QRj9czXZ}yw90|R3;mZ|b1dmzZRx*Z9(^=%I94TDhW zU@V6Q8@Vj}{@v#cnQjLY@w~w-`Qi__)E|m?yZBgyyul^UveIa@K~qr?iI_Pi_!R!x zFx(fLXYM=`dnF}~LscWGq3oDFoaE%>_<$NHx+u2Nz@zC>yf(D{m=Y2S|E!hloM!hZ z6%u%G0Dmej#yi2eORy-~;nAWsV}0TlFQwMac{NS-{LZ7HhCMC0|B`|ADRwqj^-az> zg^VRZ(={P;AiV*Yq`aXn;^3+rtF~LZ4|6_kU`QSw(==_a(iL0er9{s;90Mtuo|`3S z*3T$^0?AasAXpf_&5x&w|1%w*jvz~pp1%dW&g5y9dDRBhH(>q-iOr8mgvY&4c$0-? zf}$Xn;f@UM*aeZi)znW=*;Rqq>!v=nt+G<`_C^qMmxvWQ8M~Uu-W5HEIPUTyCC0-U zSTtx)R-@YDuY{%%cdg|2>P=l=Y1sz7erKv}oQUx_FY@gry)Zt?7@b^kdw_Ukh;@-o z*a+ituy(D)L%L4sqhK{+W3{;#(QecXqiG3;@U{qFr)r1K(1#K<((Hv5-Z`eMx?XFN z04%as8nrv5F!cbB9fXks1z&2M2paZ76)gJcBxlhv_V#uD`zQ0itEI2da->_EzomJ0?8g3z#4tApt~B@T4U?EeKpXIdNY6&HUX&{oRjZ@xHB1O zH_L$NKj)+mOzxOvGZy#@K;crC5P!A*a?XJh0#?di5Z*n~_+}e?f9Y7M-)&sshXt0= znf37Lx)h>sye*|EEQ2QUJm3)8b-8Zxrvb+_VbwDs?<#ho7W)r8_IDh_cnlY-31`du z3K)hN8T>aI#%l@tmJ>aN!7UvX>TR%!l2(Xqs3e+*SuR%LX@hC{fm=f!^{)FJ(=$nUFgZ;)OzR29)UlsrI1_n88#|H)#Oz z3F||Ma1l#2!@l?#ja0M33vSXs=~thy7`YHyXlS`-2wA4L95+TKY6;c|&qq){l{ja! zY=q)&aAd%vQ|zp_6t=<389kYe+6AGcEMu$QGQqSILhSLV1LXmBT@NYtbrYGNuU&Cw zL0ucb)jxlKxUc_DeP8SC?Dk zU3HgV9ryR8L;yM%uX6<%B;~1_sU}Z=`f1*HZ#753BDJJr(LC%<1SUWJ+`FBD1Bc{O zcB{9T%`y)~_VP{9#?ink#U5X^vmI8!^yisva0<9L>uILbfBxFq1Y2Lhr~a67;Yf() zkGWgPlA-*}6u5v<_m}~brrg%Tnz`5V3+2!U&wDnAAdRzSKOIC{#o zSwzWHQML3^=Bh+`*%ceXN1NxOT6S#iKCP{)nPsn}zb*ua!}3aVwdM356lFnZ!w{@~ zBe{)9Kf#p8=(r};h?XTZ3O7MmI(F$($UFnG*o--E#0E0yxM%Q(DvGVaxLWXODx{2b zORRr$BIp^s8kMOFm9kh6k*q)?lOc8%@=QNK*;Kin{h}?2+b9^e6}1$n27EV$%c7M0 z9Sd9*yBYzp<)G#I9iRmI?}ncCWfI(RhP=g)b3l_(q;eApmn2MPs(3)0VcgYg)}m@` zE<~1h*dkHq=^Zg`XHoktMLOoXd-j)Ju*+6O&28y=66dW(C_cr*Z}1wG&}FHed`t-3_nyN|_#$+xeDPP5P3D!|LJ)YVlsQR7^s4KB28jhw?_*r{-~m zu?IoS_d1Kn@$Xyp20EAq)f^cxnxZGSqaTsfM~W?$6Yp&=pX|%XEXCo!M)3X;m4_DB znw}6YK70X(p>|)VoBFqHP*f^Gq<`cALq*ohV=>)obSVj2^%N}*11m3pWFuDK?FZ+X zhThIM)gcL*3F7C&ELXTrhK@~~VAeyyx47BdwsQDBq3_FP_)jJAh=Q0r7u{MZe{f2} z`xxD)T{1o<%gfHbV1h3G)Y$t$Y#(iFcd=UK*m*-U{2O+4%GQSwxn1)8*$I1-Yt1tl zDyE&;_x39^?j_X2#~wB>um=BqRh)Cw&->UM%)jI&UNc#=6I)6_mQ?Yg#6mG`tNN{6 z3+h7^Ro{~f@LiMIsl`>J-KD*|eTUVDk1<}i8@JIx?O6=Jb}4s^cT8r6lPh1Zr51#)7>TVl>zsJZTxrcYiHigka8TAvq$v`y1Z zFuA78++u?hm1>9F*Hbsorjgx zLfv^n$rm%%xoM-t`)Jmv9;<;#)xc?C%8ORU3B4h1+SMUctzu$rRtylVs1&u}} zOrP% z$<*W#Fe3J+Ex9*@5!P@?B?UFr(D8b;&>RBFLReXR0H=P+?e#pfOgsDx_LI$Zf0B|% z30J!v)>FdNgl~-GU!c5vVO)>!XrtQ_l=K~RdhjShaq~-r5+_ZRu?ZN)8pj`OBq}n5 z`+Ll>fF!Iv3F|@Q>rTedKd#JZfK>zVwM`I|22-azx05{0N$fvpFA_9)g$0(xV>kFm zMUYvhuxg-wrf;cmg`8rY>a~nmB8O|D$Id&5eA^7X$fuJ#J8<|>v1+H*LtnTNqplOo z(KDM>M|H#XLhqoW0|xz!6Kit;Tbx~i=SHr>n_XK0I(&TD`7iWA*CJRRnu4rEx`Ox$ zRMBZujm6Doil&6S2QOMkWnK8|DM#=%4b`-nG-dz2o;#05Q^mPR`20E}E2TsVD*)-J z3y8VJbU$t15!-VkR3Z3!2N^KYIcT{P!<-k2N?kbQxAvl(7SOW7f4AlZ++Lx+Zpo-R z7`|)lcX?s+uqnRN%b?$;v}vmAp484Utzl>P=o4am(}Ox)hTP?ZfydsFs?QE#0BLrl zIH>zt{B|p}@VtT0X7pNtp8T9?9OB7KC(#Wt*x!1v^?h!iqXDH*U`bW%q@m*X<4!x~ zOXJ!>j2EB%EW;K+!7)w%TJ#A7T^9PRhq!4%%6cearj=VMv!W^P*oj)M8$3gGDFlPp zMgqNOF2@&bOoGyQP;U? z6GyCnoMXR~&060)@Wq?O!FE%~2SYKzf6C7a?duN}_3pj@&#cXRV7$p0Mnc!03Ms<< zDVFSE4o?`ouk0I!h|_`0i1fjRGEMt0TT%UtC+PL+TI=0gW#=UEczB$ucKjX)BT#^1 z)GOe5XjO@7mdGTSoIEeOLk-q6r7U36c_2frxE>x?6LO|)2_N0ET3GIkU4m=6qYQnm zR@4A>vG^C=Q_3V16tLiqMJqPKI^p-~HS$Coy^c1FU4H@8V9#T>M z>^r-W>Py5Howx70Pat1*Y`147e|_JCaUekCM<2#R%N$yQoH#Y zrbwBcNlfJSA?H)3m8G)BRl5h!c#W;HEym`wd3ISml3Uv%qt%m?oaL(1l+d%Kyvb)D zkquu{cp;AW;@!e#d?*bskeV1L0UVYnN>g6UvN;g$nlyUXNBV-fd(5$JMxs0)nii)# z3B^Sb(W{=Cic*=%33_8H$%ezxI(_Sig^asTC_lJXbI~(;rd$~n5uSiwtEts@+4m%U zpBFiCPo!jX>AgnH4plWIc$2$HN#sBhV~eQ@H^}Bdc-?OAK`vMK+m9>$pdS5wU<&cq zhGi|scDYa~CBADhS85GIDC&VW%8Vk~-|h2QsM&QXsY*sDt$`T|Lr%BQnbk;aP8IyC;qM5jK{0(?q~*jWT8#n#kEcfZFjE3 zFT5o1{v(}DS84}1-LRz;$}T)Qb`O!|?h_tMof%Ff&J} z)i`;QTO*vdMf5_k5#z=W>T5uav~UFVAsY~>7ILC>8ilvxZFPxf4M+?8l9u~IC_E(} z=1xfrcnkgr%Es>+M0=@(YAi{7TZ!$~EJC2dIIf;s3Xh`WvA{vkc7#YVUHP~Sa@TD} zhzDz>Mhr^2pqF4t0`L)EsV87(GxP+!hs@YyQ}h-cgpJRPO+vIxZw_M?hz+X8S3?*~ z??;W0F$Pg#Ef583g64%XOocZ@Au2Q%JM@I3JN!|mVG0hKGg9(q)Yl8sL2Y?1FPrNJrnnmxsPxY!7MjR`P01f}X&SfTqQif=v6|>JGOL%QM z5slKM8Po>}Rp|7^{Yo1{_3K=b(uW>8)D%J*{7JZ2j$xJhCMg#i9TNe=n2pHOS4p+g zi3}-$40gnPOI%-v>%m%`Ka$0QPvc-it-jNN%OmE}WX8ye7-h$!6|(3EVq!xR;f&A{ zyQep5gQUMsJMmm%X`<}9$&(Z@$*CqGHl?kQqF=7OWQk2U)(tM9v{_4dS*lcVcCF?Z zWwcOI-4Y-1Doj#suT1UM-ock&p3{R9&3y02<)z4w! z(Md3VqdvVYUE(_BQ#s@A_!z6g@}cFNK4qgB&L;TmM%wZ}XZhOuH{%1ErSp=lU^M2d z;@F^EIAn`BxdAJf9nO^si=FVA*yvu%<0RX_d`}zdHmYUU0U%Qh7K`(z0BZrN`|r@R zTQ%`dL933#7qUnmf5_?1!?V9<`wvWI`zhR3X?sHx@Dev8RpgpU73jI{nk#c_oi-`@FQ+S8?wWr^jvV6X2V_rC<`N6u+iz2@I? zx~b`U!!sZ5v@^}c)*ZlB)faCK7D&)%&wc|*oA+g{e{yBJ7Rlsi=TtJ4BX9IGMA+yj z-rcE`#yrg8@zAviKL|8j{3}xU&iJQR1DDy zxmEA~OfM+AV_SUx+6!>k`TWuG$(XSime1&iX0tixiblt;b8p!cdVS>nb~M-9%d2sr z8|h(|75hMy0{NF&=+AZEl7uI(vL>-9WAd+MpUu zC4igpTVHk6dE%1e?+DEjQ9hPpfE8F@A2^E4xVotJpm8OybADMnxBxY8WBP%NWBhl) z5l?M*c6ct0FX8gJA${k>GxBdBt1&|gM$rmeutGj4T4a!qoZTJP+9lMjQk4ba|84FE+~juAi-`rgjAlP9-5N7T=e?!tOwEi z!?7|T1(6=U67?Y53NpsM#Hd&zI<7gR_;x{ti`F^;@?YMC*3&{{=FJrY+%AgJA4wZmr zwlN(WN;SXeE{rL01>g{~G$0cF5>Ftk)j>COTp}-tq=q0VTY}fU#BNI%n2XNjXQdbc znk=`uHw$ehvN~NPW?(bk53n%P?Amz)78jn)&(8GAY%*(8{4@$f z*UZ9W;%^G*x~8Jb-rL=;Mf?^upFixiai+BNX-NV<8dy=KpK8xGAGO?ilX>N5UVuD8w)o2Axj?k)6MMNcFlI~k>(KCZES1qNYN&dS;wrCWImL&a~M zN!*e;vFS_+ujv=1Rd-E7)c&0QL#j2WZVFI7)e1Zn8lx5rZ<>p$1!Ax2#>I=4vLdTH(6^xZeef&J-tW)HrQ1sanPWVK6~RAeB);z=1IVBB0D6gfT!!-gUw#Iezc`_j~{7ufH~jv-e(m?X}l> z*0a{ReAv`z&8M3_{ph2Q)*SlzKSw|MXxRbyXU!-7g#WWQR&5mi^$(w;Mn8R&QN6hb z{^MV6Kbrjb(MMTPt3*y8!+)>z{@KRoqmMo-M*jInxmWTD_@7_;8e03Bd!6+4cRK6( zkSv zj|<{@PfX$>N~g!UDk_#0O+^*QcciVhTJ9G9+xAMWfB4h>RaUfhCH(g))eBjfd#r5= zS3ahEvrAt2Q0AWfcGerOUW$HFF=X<$z1sP#!JmJNelqul7_Wa0;8tF}Wb|d)>S}qb zy|Ko}cj#U}?&?j?+_M2*8vQQzzYN=dy0l&Um+FNac$>BL#K;A zxnWh**VY^FsimzhgK4==eETLN=5OnOub))B@o;k81us?o|HTx~uN6|1tE#F5M-oEU zC~5|dbPG-W_7G`h4^mRT*H67Uw`!2n$Ce@!G^DvW`MhQxcjb(us$#k002G3xqJDg!yPhr-}O`G76+ zF+Eve#inbSF_#`jUWyh&@MTzFb2>+65@OL3cxo>3;;U--|N0`dRDv$PD)<%DtN-*YFldzQ` zxH0*y?CE^*CW~{j`ncLEt-1hrai><%gE9_%qelC-QIo=z7C96ejTW(KU+=}OrrJG! z)z{aXHk4o8xK=-JtN*^6>-!cR{Y@Bxz}`PJ7RMxx#d%#aOi$&0WH|GRM~{yAxA=LS z6ijbztSP!8A4AV_DG%-2H-P(2wSJL}+8fee|Ln%Mae<$PvrEiPKf|oZ?>|4)UY`1g z*FWp}aUEq5I%D*WtC}xwi+{>3W(0rMXPZQ8?C(iQU1p=(+EJOQS^Y`?=?Q;83{)6 z&%5^c=eKv$f=>41oecYYw??RLJ$Tg{t7B!8waA{{f8wH`l$Szx>p0k|bcJDSMDsH7 z!BWiMf9RS^?yq+@c%`=ZcPDQ8lv5`>+xN1zcAbjfV98pu9oCs|{yx8Ki)Yo{eP1i< z26)4;PS{mijrAG!4C2%nn}2?2V7LaO@@3&rG>+6$*0^; zvkqw~dH)ssEW4<@l+ev!?0<;iV<~!_+5w--@7MS3&e8G48oa+UCl>{AXJjUYcUo^G z4)^46bKT#j^*vobd|~y-TW<$G?lCgNqMPBx?JT=*P4}NQ=TQZ(oD6)ieM&M~r9o(; zlGYPw1+ne+e<7C@V^hVI(M9*wnhkc06uL;vDm6BO3r=QI|8QY3Q|RZ+nZ6g{wvu_j z8lm!{!0Ct`;kn5^v_F68te`o)r`3W}JCV2vt~Qx99ELTN#o{Ve9;-WO-$ff@`&eZx zE>^4D*vJQK{3atb+gWen8a3!B37Lq)wKQ8?K>OQmgeOYnc`3``I+sz?pFMbq?4cEm zf)D)MU&J<{soAwBWS}kV3umn;$ycowePW%uf1dOg zGi$e^Omg*csSGARFoaY!atmW|;JhpqeDM#Zo?_;K9XM6xkX;U`XwqN4o$y4Rq)ea@ zIrLIvKeU(px5QHnLbQuNYrY1&rslfCR%weIrwxBJs(Yp4xytHwy! z%!jY>E&A%vbsyv6u2pxGB+4m6o4Y(Ck6_Mw8P<{Ddx?h=Sw?ksb_$b^7K5jx7w8+D zqT1wiI1a#kl=78_*5d-`86ykA8CO?_?Bqz7gugBuP>o2qo z4$!?*D06Tp;bh$A6lc)A$|D0(uxKY!E-SW-DDRc3H}*5L)(%ZTVT}{4$7=n!DgS}1 zw*o6sR+;Cbr2-Z`yGE-H@nM(VHO*P8a9VW)-ly2fB9ybD9igpogl7>3Qn@M`w#@j%1;?9aSZYL6$`*)c7?Kslfm%8Z`Z zW{s~J>#X!90+<#`sLycDPN_LzbuxqeKk$U2qGzf=vo9V~Y8-u5_ADFFvWDfj79IF! zq6xv#1eBQ`cJk=krV?g|ue%YYU}01EB!5XPbib%EhI25?p7%pg(2vpY6w~0mycgP} zUTN`to5-#x#)xeWyG|_cTN2WQraE^as=}In5k-jV2(tD?j2RP1Gb=;w``$#*6+H@KPCqsq6sF(wwQ5BvNw z!O(cx;6=mzX^(2hsdrOjGHlaV-o`We}-2 z^)8B3KOTqs5%u@L$QGeE2pqg&QI6m!5p||7eEONO8FCEU=?|(?SR?pSb(gj34x#fi-sTByvRfrG2bre+(?lT(mv>X(?Qb&J5T}1xX7GVf@vH92!O<1|3*cTxJ$lQs!aP&$NmcjldCyhKC`2o? zEnn^ozEORl$eGD@L!G8|e!!W>DVn23ZY9Q+$T-Bfza2+Ud3r`hZQtk7nECRdQMrHW zjULKAc@q;8K$zy?vhUnKA#;Oj5En_a>;8(4gzbpZ6f&0@Af;v&sp8$O&68_hs93@| zLJmM5;>0XA_#VX!{;!)u*lm1^pzj@0e@1yGG{AMmI4?G+rKYhiF*0p--y3d8Z$Qc? zvnb&15>-3Ncy7|Y-S_PAJk|9x2Xb~i%YV%RjThd0Vzj8I#hM( zHG=(O78rB>4ohzvG}+hMsVh3pv`7IplNs)Ws!paqzqwco=Cs*q4nq`f|L3fWxVovL zo;7UsIE6k|cPo7kcXTwI1t`Ps+t`2}CC2%E%eS4wJ`1n>J&QmZhFgsX=5Ga*VW=9%oDB$ zwn+idMU$t&>nL%AQGL_a*VnaiKZ(96`wug z>koC1TUsp^fa?X_eynOYeiGCrA7W{g<$aC?hm1%Nn$m^?^FQzeUHsH!pK^(D3nGBz z0IWM6uh;X}jj{+ug;u<~yW&1v?aHu-jT+w`>wk)b5t9p=TwgK9Z&eBr`Akl@l^eI@ z%)G#5i;EhChhr*QJ<5C(p`@dEjCuw^To#o00xjFmi>d6DTHtpt7AGC|EY`))WecSR z>wfz50YS;yiJ
_?aUmq~$-g#~{Hrz>c@pR&{KNUT-4$vz}KU_qzQ==AI>Rb&i{ zP7(Mk`{)J#lvJlCg;W-enw>rB^)28P2qxspU^frq|*6UOP^lb+VSw019K^lU55<i(mj#jG&kZ_FQWK|pAh%e zQ>h`Nls3%sBN~MMM)p~G{q)y(Iz*@6sm3^JEjH2{lDCYsCvHM?F;#TnurHIkToS7^ z3V`Oq+ILyfNevlISO-G4PF+Z_C(}X&l*;iLphu`WwiDJL*R)A}$$s8syEwoTH+S>xA zR^5agYR&229`P+!p`5BGN1E6Tkq}}|&L{{3nY-i{DZ-!G(+v2Ted!taP4fw+_a5*A zCmb&f@&bTH*8F@|kWJL_uhtJX#|KV=6NmDO1T2_$Y>^3Vv;g&JKIn$C(|n+B$k@8} z+}>KQ@2rj+}B`k7|F8IJ-iqKh^VbTcC=K>}B_Nb&S7Nb~hh9t{CGrhP+L*MW6tb<&|2}$D(h66xXZ=C=X>~R<6cf)pz`w z48y!qEr$UuLVd;ukg{eAj?lqXs}AL=SZC2x$m4t~d0QUMMIGg^tGi>!>Gr|bpMn1- zQ2|T=Md^-i=j0Nn(u~!ev9Y^*ivm)#Q8x7Z=yc))#M#*t1m8e;;EQM;hmNmL2m`A+ z6jc*(YrCuLAz26dearF0kq&%oPECn%G|IkiVr2vPSH(QBE}Z>5JjB^`4g_2{wD1VT z1`&Lg8`_V|>;k*o>QA-mc8XW>Z8y$A6AM?@a;is_v3f}?PK8;+unH|A>=UON`S|z* zTckJ@hejytX&0Ku{py&WB{hQE-_0dZ4Zd;YUAM{k77|$CDVh|%Y4$Fy_~Rj{=3pTL zU9bejv%XHmu_iX4kOc}E)*C-%P~}yW%@V0nC~M&k+UwyOlWMst3Qb3cRQ18Hhitq&Huv?U+-#<90(Li+^eXs^-Lv-jxc>!tIk8v^9JMPzoU6gk4~RtrV!3B zYuBSckscy$0?YM!o7A^K8RTNcm?wL0N0P$kaddfYwV-!`eW?de0&StI16+eNX^`W% z<@lw#Uk!>V;0X#j2z&z0$g^_6(Q%YbDgE1uJ`S3p(r^wA?0i0B;j%ogN@=lhPwzmT zV(CX#^dvtQh^MBm7!=GA9w<`1&@#W!ZWpQ8nKnKGT-n=MWM(mH39LGWPk0JRE&8v zLkchf?pBCbW&zCwlQPN524LUk7#m&xLo)h7lB;U?Eg$?HGESF~y8z|%h|@f3Le~fq z*_OA;jW45Yl_AMW3R;=a&X7xyC;n%6Kh%ZAE`6P7s_p+4u}KAB0d7{K8>MOF_^~@X z&j^lcs~R|s*R>aSJR4arO|LB&M{x?wbyQ=gF8_spsy)#Vx!z@U=K*QE-RMZ8Fb+pV zLI{*|BnRgxGi37PuI%KhiKb}5Q7;=5$%G_(j6zHoi}8wtYygU$zs*P^PUrV1SPY_X z`&0X-)FiNNlaT&IQ;VmzP4T0BNs`BRKVUxVD{vTb-b6T(5ftwh zCwYfpHQ7D8L;G`r83_KvNWUg_Zuq{_ss+!`uKpht!)Whch`d zdyM9u80Rk^&Tj4t>GXIhjINtwS@ z@Q+j5#LSMI zQ`?l6Z7Tbwzp~j;B+onhw;Ve|KlQdkdya83Z(SeoVKxQ%uTA#tw}Y#`ykeG;viO1Y z;Pxz2NOO6-%#2o2on?wF97TOABn&^WRj$Q?(Z&ww+2s~qmX>Bb%k5eK3`VlD!Pzjm zyFpzEWOqB-?|Ye76QV#Dd6N&}YHfP(57j=?S$5jO{Y*^pc-IjHd=k5DW>;=S zdecw+U6C&C~Vr|&oyQ{H2fT`y?K0XKxE&l3jy6vyRi@R)T~lP_u;0@auNq^f*9X^d%u7EaXJpggRVIqM z!vGC$3G`v!ENXf{R_zOy*~feetP$e;s@uxy3EuSXu8PU8WahS0)!mNn+ZzQ`hEah2 z@2O4ZWb4bCp~{MwhC=gn$a8=lB1exNk(H=bJ>8?}rbdti*+N5>WxcnQ;{ic)`w*$8=&iAOhyJ}R^ zGn~5(?~FBD_{h7U?0uB6cDtSU%`~`uX?NOwaoleQzRXVu=#^1_T24{R^H?Lt*4EZk zSMVRP1EW0O3=p=&yw?3aJ7tn`bm2Om?EC~4O77tE^d9NGyaV**snjyioG z`cte;uti+(+WqI%bCr=4$;+4V0qvK8WfHB51!~-`i}eHKOZNDN4Etc;${018Js!9x z>MYS&VL5Ao9Ov(dS6M=iGdL4n5Ykghjyt=@%O!T;ckI;jrmq}b1xNgV>Nm+w|0SBolxQ#r|Aa-0+vs!%?;D3YRIWj`Vn{Jj(Lr*tUWQFtdHG(hL4r{UW#U<1TOi!O;>p9hsv`?)c_1$)xYNNPd&B~^RNb) zOjvuyazgeXm&p@O#XA|UYAAkHe_6_#n{_^lUtGo85SJ7YkIeSiA0g}Rd>auIEiycP% zoyWD$M*;$Vd-4BnejA_c7GPJ+vrnM5xZ*}Q4i*pzIp0D z9~$6<3s!&Vuyt)2d1SPvaJq^OlnFdmboE2ifsEh_AepQ!95x})4kg78HGRJ=C!uPC zUt9Hr(X`forki{Ny7*T7*3xGqA)7w?j5)qs28Y3mT_4pEZZkL>(;w zqr1>vc7H9Swt#&O1ip+a#%Fv(t>r>2&9%%a1UgA-(y z<1!v^7;gT4oFaG1h{--54YbcCyr1I3zuWH{yPTP3zsIh;pik(# z`ON7^ETB^ChK$SDsFP@ddh8Sz?>;p2G;KF!EoeS!;1{$Ny^p)jl38V=h1WQ2? z=#QHju0tgtQ057XseC^H4vQv+lL_z(md$k&rX zBC-Nq?%E%7c`XRE?^QTkD=iAka6?<5(0Lpn?(s?Yq6~V^ji~lIWz>BxY>bZ5`%<3f zN@8d^Xe*;GP@ZwFNC6~DEKLZ~^t_6VDzAY2%Mxm!)2`A1P8JbzxMBAA*Gc3OieKg) zAbT(2zis$6OI7*YcRO&E15@ruY6DH8YiCHFno|{(079*!)}s#ST`~Y@ZS_7ZnDf_< z%{uDxQCAq*xLyvkL7w(bu2n%j0hyCsV@BEkl2m^|&QhZm>LQ#Tle`nPfSb10twVIq z2cbm2U$&7@KG2fy3R#B|?zD%p0`=Q$=|Du9a4=vG@jbS4rNmCz)E%Cp(^NEms=QbN9$TEByC=6 zhjwT#m3dC~-vAxX8|x)?U+wqDvY;SqiGelPTD}uZE9_lhpvPlpD7spDeS}7|47Osx z`tW075w62dTc`cJZe==yfDvK4Y-y8(()=LSDdn4osgbeb}Tyct#e(!K|y% zU9YZm5@oRES6c?7Sirv&;~&Zma1^M@XipssZ-Jop>Z%$!27By|MtdFHLuE^ewJ%O( z84nby?!ZyV#BUvX|3;C|n)Qq}KK~+&#>*8Czj+csTLwjNb2!%AJ-pY{gL7s5Yf`Xh zV;#LFemzyW3gul9YZ*d0mRvZyw~HKsunS}*x%{%dq}mS5swA8PR6nG)ZmArHA!z5*~NV#br2DnRy)wNv{2T+>rIwoq-db)x7`>Z{<*XZ+r?2qtGDdNQsMGUCK!>w##V9)YZ5fFnX3a#V4WmiVpq=zqYS)`Xc%4TS^8 z4`%Wpa|$PD6P%d*bTQ98^dDF4CH0B|e++3fJfJ54ZOVtU7%@BI1IO;{z?mDxXZeH} zGXnvjm(l$V$&H5oVr}t2m#R82?vX;nC3;=_-;xZ{@TibM_80AONR5KB!=>sti6JyR zFf=!c+&{t~yT#@CJoznvrjIgOx1{kBt8gofMxmA%`{l@vW`HTr2%4?~H$_yXBslsh ziWZHy^;ch7l_>6BEl)e$B|6ph;F19Mfd`8c9RbjS6#qVlUrwMXQb@Qx@R7i07~v!a zd>@Clwrzy2-zLltZnmvWj0>vIC=KtZ^F>=4x$%DYF{-NioV#<$J?`dI%y6al=AjKg$xIbrQ2W3dofqGh`f+so6sHqp`Bfir{?gXbl4HW0?Uy5}ked(yu(5@I%#!+OWL zOFw`FPBV9u5s>mJieR38!5~)mUoJLtITCxOZGwSK`yER;j| z{*JO2+oSA+LvwTUV2kgi zCD0qbidM6K>|GIk%VcxNCNDL0T@|Xb)7+%rcL56`?MH!O?~maZY(s9C!zfcO2yfB$ z`$g1JQ@OJ>=ZwKjn6qV`d@*-727VC))G^@HhT5l(BF_6maBWejO-@=v5qk$FakG3 zT07SQ?)1KY&2vj;t1=Cyp}NfkPHw-dI)`!EoXK7TexkuV$8WA4ymli4m`(>8jzOhf zRfm4KG?GD42W<%3$9@JK#soM5P>cSqwG7uHA$XL9lUEAtG|MS^;DF0ct@w<~IKOds zSFb9BMH9oF0i$s9py;x9^L*5x_qlrA6V%PrEB92E7y|x!%%`q39q=b@bfph#1fP1& zO>ZAYt`)SC*u8}?VIT+oM`^KK8FI0p%-_I23lfcR#+u!!tt^)yrmYsLID9uUy!z^G zu*WtLXliTA$|>KYF7t(J|IiBls&IBix$@;(U!p2mTVtb1RR?%{5K97UYNIr?k(I1L zQe%M~{dsLx` z>ITpt{?V+;A9;Wbsk(g1v08suTyB!6GAwUpeqJ=4O@bfmPHv`Fv$qobRhc z>FMch&USX3l5dZ<4?7)k-$?8@KQ;!nTyv9#qT&cW1TDN;?ou9^ zuGbj|tiV@gVV@BRD;C#!a&nxC-wxM6B_{o}d51LCk=l*9n0Ql26yOZ!r$1?*J~kB}=lNINK<*sDRC>#l9!ApSlN&Jw z|L(`ZB@uqVVb{*JFN5e>JgNGh;}dxC|7 zgO7h|A<~E^b{ve{ym1c01*%q;XWm4PxoIbl-*r_qs^niniJmhr=Wzp+ODeOe;`D@scNE8IoKUW{{;H0MJot&K?c*HL4bs|y8z!BxlXACYA2F3CN`Z0|MxcFB z?EgG&EfUJj%xh80i17R7P3??v%x~+NNYLDt`_E zVa?K}D60n`-?)RkC`=LEh>LPXnb;HirXsE;py2L~=e~F7y%POIMpDbqxb|^FG{ggL zuhlyeJgsN70MJ_#go42iQ2xm9P6!lHu43n|(5;R1uiqLk@>fnfgAt7b?< zarq&|KZ1Ni9M37j#>W4i8dA8oxKq@o z%{ zyIDPWxt*i!dKLuj=r<8>5({7=(5KR~<5AXafz&5;9rLk-&5fGc;lP8}-QTXW6J_DR zfO#kf3!hjv4h=_q=%r`GD{dxV_c#%dBnGWmSE(g=;KE1ze`Q2FDyyS2YBM z@XFNeR+RPp0i!qS_hpB}=zgzC0%)JXTaVgMW%XnA&#sFi9Sap$dP-V@tP%rl*Q7%q z4jORCI4pN8(-s~Da*aC5qj}Q007x_f_6$KiwZ2Nqt^w{6Qgi!1H6HWDHa+Kx1EHQG zAl9#j3{60Qd~(c2Wp)9J;oR<;3QgkJX+SGtz4pIoRi-8aPp77064)_Ij}3P_hv8ZY zsLq$9ai89s0sF2YBpa)hvS%TL;?Yw;f(W)E%dEt>2Pi%1*}ur{$%vV2Iyo3%iVcpG)%^oJT2e-R-vqZkt2^Cc6)~;DNe~H!1bWQT zZZ65n`7E}6@?{u=UwQ93A?Xh3uuhL_jBK3jCZ9<6s40uk2pQ@C3j{g*;AGggY%8k+ zvI|d(R+}Df0ho5W|20(X96%T@XJwCJbU8xQfK`V;)36+BzQ?O^R#3M;#!HdtEfEXb zAmBW4WmM|XFZP^qE{G+1d~K}Bzi^-UFQAAB+}9QoUya#lbcDfO2owq#XLI{idm$$= zGg(j{{HnpGHXv5m;zfnQg&X0D1)9Q4oU+I=Tb2&AF!SiiCfcJn5fTZId*Xt>;#U_4 z@}Uda2mj`_#?;dXV@mW#nG}S6;=McMD6o+Cluj;nw+$_`7!7GBw;>Y=<4&HycAP=3 zJi?J#LWk_KQz6UUq|q}1*F_oUv6m9K#Dny~T$4H4i0qm#w}7&MpK78zdUJ*jQ)7A{ z4~iH89K=u|&c5SJl*U_&yu=6mEO2}81@Y>f)M9l-wN1Aii!NkR)I=t)<0BM1x-6fd z%6D=D!?pb)M1G3$v;z$eRnc%+4LB6wJYFmD6zjukQvQhEVxA`B?TmawC}xo4>^6CY zOT24$OL-nk`ysyUYpko$x3@z=#9x_#7mPSg@<_MLPqK1Q}Hk&Xnq@)U& z=WzY4Ch4m}_9fDjdA8a6L*7V<73tC_b z0OdtS6h8g;RVJ9@@$3imb0P(p6yOFZj~VpCULmcaXomRlifF+yDL+AG^4&WjSMo8` zP;d7*t+8`IpS(h@Os-Z+Kv>%P@bY9c^?vr^rEp4I!Zxp}jSC9W~k>7h|nB;R7&YpnZ@ zyLa!l&(x=W8eyLwAb8Gg-VM%n8(z%uy3|*&NCZTr7Ym7a5z4B+Dj8_Xbb{_w4vdGu zpT`SNQBlSIIm73P=m3VX2Si|GzX9_?3(0TGD8#TM2}$xG`PthXVBalF8)0l3ShneHVI+}Gr& zIR@)bi-cRrt4Pxn@0XA{f>x<>Mg2&w!T?7{qIHkcOdw0Y45+L4Ok+ux($M=F97`8+ zvf2!*DG(~#mNq;ME%K0?e%hr+N>#&gx~ea$?4NDQx_G1uA#`3}Lyd}05dH`!7jGx} zVFhG_mh@QN(3}JLuz`LG^%FbxJqq=AY?N%@)X*PwIaQ8(8^kwj3|UinCL0RGmUenw zUEh>J>Wj!s5YT&5vIID3Lizo3x9dAM#?Z5J_i%Qinf?_7xnJ6#HS|YK4j8R- z6l6QwR|F#I%O!GtvX?XF*Vid&r)MUZD4i<UpPq*3wb-7S_v-dcs{w5 zGKvrw-Zy5&Z*KDvJI}nX)`LucxFi6aDJ_)c{RYb$u2h*g2AQ~-wCj>qw>R}Uk(i;p zymQBp11q!d@2bas2%5T%Ax>;1Gh%i|sQiqw{GZ%7P@*Ctb2rf+o$iYF^X3+M7x*I? z%J(ICxZMK)F%9546+NgwI~>twKt$QK_LBgKyS=X7xDm)`w(1*3#G9w$@=dr_&*Eqdf8wGH$t#vK^ z*9|IEt0(hIw;aIjz{L^vD2MqMzbe~yaiI-o=vSfMe-izL*J_}JqeH>=kUt?1p4Cif zo(UZVCVH`~z*mR1W&Ke{*tZj5rupp-9`31>zU@CFP<7S?j3lY(j}4-(jG*;5Y?T(y&|wugChw9!WC@z$iz;tRGsZ zaAM_CdKFjRHJHp~Aq`X@|0O>4I1YNO0+tVCnlwoBL8D}8IJ{>77Z;;JqW`HgyQWhH zjjW*Y>kP?ZyIOVwHA-dwb15`F*KT;D|GwJRQC8E-3o|VxPbF{Zhbo`3q~L0%5b}O2 z-jm%^2IbQFDv7*j%}fK$`)5KkAr;Oh59PhNg^7}~D+d%sK6@Qw=TpA*D`NpEe z8vQsxM#1Y9JT(yX?w-j5%*t2V-UP`*zxc$!dWubPGVZ`bXT)Z+2o_lQy+ciM6%;tXYj$G25EUks&vQ0HL)Nu;6=@}nqH3k1gYNv zb#XF|^_%!c&?}fp;6ZiKdqIZN53uO5v?e2|(L8+xK_rpf*3!1wp<(EzF9c^`!t8UDP!aPk*8sT|>xDFLqK1A-wNSifvD()Xu7567CLPwqY` zG!vrnc8pkmCvIyfpOd8*^6!~E&76+RuXxf4R-EpUhxe6&3_vV+U*qR@LdZis7hMmz<`AT1TmmcGw5i9>?goOaNN-aAP}bBVJ#b(?n}Cqgr!=T31<8Nf=I z%PQT9=#qi<$$ZGDg$Uo-#ZiY-c52Z zrDf!q5s-$Yow~@m(hR~<5#7H|CD@0lOf-wmX@Iy9n0hHz(LIG_v|kIuh1+t5ZqLA* zOV!%Iv5-BjmvsPQryzd?K zili{6jLNnWX<^`}KLF%sr55ij5#szk!~mAKA<4#1=HLe#o&bInvmrY3Nxy-1`65hqjat9YR5bp zKLAZr(^dL=3KXn}aT%NI)Y=)SF0T0jmFs6+;)Lgnvq zSG}2UDlB^6U)kyANza)=pibBgH){xbzmQh0*32}Co39lqI-Km$v4U@MV0eYo5e_&& zz;tyB4^8cVy!1gxe^!Opguz(#;sL?&?kv@4$mv(7&x> zX1-Rjz-nGySV32syjDX7sqi3!OF=3<|E>s}`6k7p=dvqoF#)8C-wgm#i7h960p~ua z^asm&9cdlz0+ZSaS})Oyqk;z<^7c5S&s0>pFMZ~P1zmK0swhUY8&m@>&2ETOyJ4L?1v7iNq zeO>L6evLnO1dh)POyEQBCRe1kOMAP(;hA-$E7CnWreJeBMlzGL9+grG+NGs~Po-b# zSda=3-6wmpd@>5#f!Giar5(Bs!$r3+Lrs7Si2iELo<$koKfxEja&~v$$k;?82UO&i zk%jw|pKtba5?!4KC6_!7UG)iXF=b~?VW+BdzYUp+MT*CCB=;5}jI)OG|B783Udl4x zS#S!Vgm2?RdN1;cUBhcxW2IW+h}@OjiO#pf)sf_v(n7RF7wl|P8~q0Ymu+$4g3C$w zblYON8%P01I`}tC^}cC7$=U5jfUhmgfvQX94{Y~>lU4Z*4tPLhA{w4R*!%}6)(LgQC4!E>wnBRy+ZC;0Cg>hac+B^n1q{|MF zsF!i9%aUK`;m{>-=qT|dA8-LaST%FMI2T{c`OUGJKAE!ZTgjWLww6JkKilx*SKbN8 z{Xj8Fv_>&$gN^j{s`bo~_U5f5Q;UFDV%zmO7_ zjEi!XMYB-m+@&~cm7%LSw5m#1As(L6Xej19@;Qi6XXhxLkSBkb={J*!`ltV*TmzuAQVeh3T&o zOU!x^o*05tEm1;X!|Hk;uN0~yxeF*nzo@3hG-2U=p$kzzH*0H%1H!HVp(t zU{Zq6|6*OxpXpGArlKyM_R`5X#Z=3i$^eR~j`cV>)^i4gS|VlJe)=5^D3N*tg(UpP z4`|J2U*~H%csb_o3^tvfg<9U%&dgIH1$T$Q`>$0}^r5&Bn7F~^%sj!3SF^Ci;#IGH zxAinPl9#Sh$Qso0zlb^h=NSEM4XJskv^4uxptX4%=rGcn@gzxeUo*SuqokJp)-RqIbiS&;pD4B-r)l%8Sev4yZF zXFdcqcO_ov`I((_reiXfi-SP5e0@Z&>v(I9U&UMDp?P3nvA=NP&ClA8NfJmzV?;)& zDzpbxl2W`Pm*fS0q+l3oU1mb{#kXm={&m9hScJ*!cFeaH_76bd2IgQeCp$rKqjxU2 zU;G!wy4Tqa>2~8~?!%tiy|9cu&O*ejKrQXyokMfc`y#){<42=c;0wiI9c)J!)ug{B zMY}Ox)7`}o!^w{#M4ho=fy-RrsnEt z{M)Uk$9pZ226+R17z)p=A7@VTEz6z~=M(Fn3lCW?mhU=f&-wqwcu&zM(uVCi3kF3a zcAm}}eL~IYPDOpv;Q55%u5vR9g0;_$|CJF!M?f+Q5AKUc&v35xK&rd%kxxx(%g-J7 zG0R(2;=6HOE|74!=M#?#;^nL^jcj@D++r4dWo12xh^zz)w;zf^*_O);G0|wT7+nhN+aIEXvBllKOarihpk})P zlLCN(%%VMD0vs(5YYC#P`XffEX8nUo^#HkzdV6VKyoFv&2>ozoRjA=Zo{4%|bIqi;K)WlT9K8!85VUDU%@s@*SySxBioe!UAe zHh3~+t=WNdMY)B$#dh3e`!0wRNi2k+Uh}oom0z-X%cELY?hT^dxri%zqi|fw>QRl^ zBwM(a6&x$Nz^{Ru7Mh(;|1dQmlpDE%q^XxE@m|w@aQA@t$^}KvZ*a61zab8ni-J27 z6ig1d1eCw)5BCz;1?*~zb#(LNj0nO6Dg%J{B`#{+A=SJMw;PwOfXkl-_I=cgl?T=j zKAm(HEFVF%rYh14I1ESe*eOv7)kFj#1W^*yX29#KFa3MQWnZ$akl$S&vNc^ML;bln zP)85J*C=GeZlCRx!%?hnc_Fs(9@##xyPBH@b-UmAOPq#!l1#-<#`9VQZmW=xRHV`^ z^`(~_kYr5)@H{wfHEj4UKn}ma4Zd22XfU{AwRB1b_uy(WxYnykuOESDg4~CA4Y&TL zO#L#Ym+xxM)79)YVVd0x^0M#B?qVO*O=$9OYf(o#q7dpK0M~berfEu&;x2oNrvB?zujmDolY8o zlms8IT5R?*>Ew&Ba~HNk7MAVPq~*oANf$xSC! z?%cRupWUJrBhc(98n*MyJJ;mMw*iO?%5Pd>ZRcA?#oOF8);!s|a?bY#Z>%lDiaO08 z5c{~(j3o7ffDTM+OMzxc*c3g*TvIe1XTZ9qWZ!G*q;n+ljWHg*ANiy)_3Uf~@+|w8jb=TRs zTjQYpV_*#@aV_8Ck#5>IJxAVA^d5V0;l|}?rFq#EUX_f3ON|$|57*0Ktf6kxM>+8L zyT)x$mL+)=Bz^>^YR3kjDKL7-SqP4UWaWX=!W5e1xJMGi=%T=KDrxeZTMa{ykDR>G z95b)Uw;h+r!A!3yx)9?S_ge^YD_30r4bt8dDIpm0@2W95j}w&6xp*m(UNt0bCa%I2 zeZS2=|I1eJ;}ml8i?B$+9Dqv|xJr@; zQtTklE7V`kUXGO&(CdFv^j2h9ql;YRG1H^!;rz)KxCtIX)N#)}!!PZl;>Q&y`0Y(gWykUKmUN*D@Sj!rZJCqc+r{@uW$WM84 zGRotQsxoP>n9RSzDm*fi=9mc=fE~KO&9PSlz9u0|t_hXoNQq<2$MHsh5OD5|GPlx_`Np!~4#>9}C|tMAQQ65f|Ov=hucf zl94ZB7!ftcu2dH8pM++9UXsa)HjW2P2j9W^g3A-ui$*0Q&-@D~o{Sexw~n*M2jt91 zea}@2&x}Pm=<)k+sq0E6$PU8pi7tJ=i3BqT;=6|p;{G;8D#?4KYP^L2-#8EqW4Hne zM%>xpKP~nb7$35z`8+Z`ovL>9V(EpXDXy=kKm0YTI7}`oYP;nUp>Oyv zcUcQumO`(Phs9?JwVaDL%wAqv?9NbK76f0q zF{h-fkZQvr18cdbG>|gqOV1D%R{xEB^ocmMu{f%LM(B21RVW~TOOgc9_;MY1K${%< z0={7?jk~P^uF%G%pV!^B3qFxh_XZ$78P$BG40cfT(SYnK%VEB!#TZ5Js^ag?&0u;Ma|O5p$b@ zfLp|)Wjo(ecT}FMsk&+iy*-9S6P2?B$YpfO$C5o8B>iI+uB9iXkfx@JG-$Z<7INbD zP%MY9O+K=1v*yX?w*jv9-?usd;WOyaU)#IGk4P`G$JLlGsp4TWeDQOY0&B94N`LgI zgwo>3za9;cgOX};(%sq$;XUs-(iM^>(tii}zhskWtWWbY`dU?}T77;`u;=Zd=Qnjg z6W**9b13xM0~Z~8s|$Zs`hJW83^=;1XB5);BPl>?@ngmu5a%X-X>in{Xx1{-ttWA z{8ff+xnuJii4*=i_#P_sKk(il2#<0oqQ3Obs;tMc3debza=#E>DCzB>I$u~5>R8`) z>#TnR!^O4x0Nv_GUW;kn#XcGi*U*=;L-!M-FNH}5uWmRp<@(|qRfC$WxOfxVGk>fN zZ*6k_<2v6@yEKZaVS}Ex(pHa_>?!N}j1uw4%0$?mRoBmDN#Fs0Jtjx`htF>$YDZ+b z>`S)1VY^W-KRA^D{RR<+g4m33*ATjWoxhS0e)@Hy;LncTwf63!O>0;Ltg=|W?2?%s z4QE;2wd^O0q^^}kqe4>%Yz}474&vmBMr|(~iWW=+->g}w5QQJKwhEne(J_5oS)pxJ z>>_UU+1Eza9!uHO%DWzYKi;}b@#0;a27G8Y^)8fkZ_eGM+7}n^a;I1N1=px-_=0PT zp8HW%%JimB8gz*4tRa(s^E2uNlCLG>k<(g!h+=u{_b=)gu@!4x8Xy?{|BDajY#+$n8BUE#KIXmL;-Hn?9>Mpl$=R^w^Q$ty$OE)N=Z|MN^iU z+0LQ+vqF2Wp_`YV_S`=G#`!C*%=?#Y9rq8w#~9Z{d~W=4Ta zZz1U_w0be^mniO+EQM*_WDGUNJ|_z zvYC@|mwki6sKC`7Et^7q@)V|Jjb!i3gIiOx+Dy!8zT`6u$v3(LW&RP0}UTfH@B@QWj{yv%aZzfGk|u1EctDz&aXemCR(vcpGj zoqxarEOLPP;CV!v+_T7F>%v{Ykll3azl-ip;JTj2$I8|$&_BOSZ?)w+#@n4!7ygS# zJ69oDRIz;$FfPRVq@!0aILEBJa?`tct71=q?i{&QxD&X<>V^+^Chyr}P$$@IGIV>% zHsB@^Sa}W_fzG?T%M^6IIbyp=;s3wifoI?%-!6=@u4eT1cp@*jpF`v&V9)_-*t8dL z$p`AN1xAGq9CI}ggPl47U2KQ6@EyxaRP?bH*kKOnOEDp1y1+RDo$D;qbbs43-emE9 U@#otvGX@~=boFyt=akR{05G^1p#T5? literal 32494 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 diff --git a/task-1.rb b/task-1.rb index bf9ff83..869795a 100644 --- a/task-1.rb +++ b/task-1.rb @@ -3,9 +3,6 @@ require 'json' require 'pry' require 'date' -require 'benchmark' - -include Benchmark class User attr_reader :attributes, :sessions @@ -98,10 +95,10 @@ def work(filename = 'data.txt') # Статистика по пользователям users_objects = [] + user_sessions = sessions.group_by { |session| session['user_id'] } users.each do |user| attributes = user - user_sessions = sessions.select { |session| session['user_id'] == user['id'] } - user_object = User.new(attributes: attributes, sessions: user_sessions) + user_object = User.new(attributes: attributes, sessions: user_sessions[user['id']]) users_objects = users_objects + [user_object] end @@ -109,7 +106,7 @@ def work(filename = 'data.txt') # Собираем количество сессий по пользователям collect_stats_from_users(report, users_objects) do |user| - { 'sessionsCount' => user.sessions.count } + { 'sessionsCount' => user.sessions&.count.to_i } end # Собираем количество времени по пользователям @@ -145,10 +142,24 @@ def work(filename = 'data.txt') File.write('result.json', "#{report.to_json}\n") end -Benchmark.bm do |x| - [10, 50, 100, 500, 1_000, 5_000, 10_000, 20_000, 30_000, 40_000, 50_000].each do |n| - filename = "data_large#{n}.txt" - `head -n #{n} data_large.txt > data_large#{n}.txt` unless File.exist?(filename) - x.report("n=#{n}") { work(filename) } +# Метод для запуска работы с разным количеством строк файла `data_large.txt` +# @param [Integer] n количество строк +# @return [void] +def work_with_line_count(n) + filename = "data_large#{n}.txt" + `head -n #{n} data_large.txt > data_large#{n}.txt` unless File.exist?(filename) + work(filename) +ensure + File.delete(filename) if File.exist?(filename) +end + +if ENV.key? 'LINE_COUNT' + line_count = ENV['LINE_COUNT'].to_i + work_with_line_count(line_count) +else + if ENV.key? 'FILE_NAME' + work ENV['FILE_NAME'] + else + work end end diff --git a/task-1_benchmark.rb b/task-1_benchmark.rb new file mode 100644 index 0000000..533d438 --- /dev/null +++ b/task-1_benchmark.rb @@ -0,0 +1,10 @@ +require 'benchmark' +require './task-1' + +include Benchmark + +Benchmark.bm do |x| + [11, 51, 100, 501, 1_000, 5_000, 10_000, 20_001, 30_000, 40_000, 50_000].each do |line_count| + x.report("line_count = #{line_count}") { work_with_line_count(line_count) } + end +end diff --git a/task-1_spec.rb b/task-1_spec.rb new file mode 100644 index 0000000..6f5a56e --- /dev/null +++ b/task-1_spec.rb @@ -0,0 +1,17 @@ +require 'rspec-benchmark' +require './task-1' + +RSpec.configure do |config| + config.include RSpec::Benchmark::Matchers +end + +describe 'Performance' do + describe '#work' do + let(:line_count) { 20_001 } + let(:expected_time) { 4 } + + it 'works under or equal expected time' do + expect { work_with_line_count(line_count) }.to perform_under(expected_time).sec.warmup(2).times.sample(4).times + end + end +end diff --git a/test.rb b/task-1_test.rb similarity index 100% rename from test.rb rename to task-1_test.rb