From 056921b1e8d64702535f03e238bc2e451ddca646 Mon Sep 17 00:00:00 2001 From: Friendika Date: Sun, 25 Sep 2011 01:56:03 -0700 Subject: [PATCH] addon repository relocated --- README | 1 - calc.tgz | Bin 0 -> 1958 bytes calc/calc.php | 363 +++++ convert.tgz | Bin 0 -> 5324 bytes convert/UnitConvertor.php | 283 ++++ convert/convert.php | 228 +++ facebook.tgz | Bin 0 -> 9982 bytes facebook/README | 39 + facebook/facebook.css | 13 + facebook/facebook.php | 1059 ++++++++++++ fortunate.tgz | Bin 0 -> 663 bytes fortunate/fortunate.css | 7 + fortunate/fortunate.php | 27 + impressum.tgz | Bin 0 -> 1797 bytes impressum/README | 27 + impressum/admin.tpl | 6 + impressum/impressum.php | 76 + js_upload.tgz | Bin 0 -> 113799 bytes js_upload/file-uploader/client/demo.htm | 38 + js_upload/file-uploader/client/do-nothing.htm | 1 + .../file-uploader/client/fileuploader.css | 31 + .../file-uploader/client/fileuploader.js | 1247 +++++++++++++++ js_upload/file-uploader/client/loading.gif | Bin 0 -> 1688 bytes js_upload/file-uploader/gpl-2.0.txt | 339 ++++ js_upload/file-uploader/license.txt | 24 + js_upload/file-uploader/readme.md | 152 ++ .../server/OctetStreamReader.java | 125 ++ .../server/coldfusion/coldfusion.cfc | 1 + .../file-uploader/server/coldfusion/demo.cfm | 1 + .../server/coldfusion/readme.txt | 9 + js_upload/file-uploader/server/perl.cgi | 62 + js_upload/file-uploader/server/php.php | 162 ++ js_upload/file-uploader/server/readme.txt | 18 + .../file-uploader/server/uploads/.gitignore | 2 + .../file-uploader/tests/action-acceptance.php | 46 + .../tests/action-handler-queue-test.php | 31 + .../tests/action-handler-test.php | 31 + .../tests/action-slow-response.php | 2 + .../tests/browser-bugs/safari-bug1.htm | 9 + .../tests/browser-bugs/safari-bug2.htm | 19 + .../application-javascript.php | 1 + .../iframe-content-tests/application-json.php | 1 + .../tests/iframe-content-tests/header-404.php | 2 + .../tests/iframe-content-tests/somepage.php | 1 + .../iframe-content-tests/text-html-large.php | 6 + .../tests/iframe-content-tests/text-html.php | 7 + .../iframe-content-tests/text-javascript.php | 1 + .../tests/iframe-content-tests/text-plain.php | 2 + .../file-uploader/tests/jquery-1.4.2.min.js | 154 ++ .../jquery-ui/jquery-ui-1.8.4.custom.min.js | 200 +++ .../ui-bg_diagonals-thick_18_b81900_40x40.png | Bin 0 -> 260 bytes .../ui-bg_diagonals-thick_20_666666_40x40.png | Bin 0 -> 251 bytes .../images/ui-bg_flat_10_000000_40x100.png | Bin 0 -> 178 bytes .../images/ui-bg_glass_100_f6f6f6_1x400.png | Bin 0 -> 104 bytes .../images/ui-bg_glass_100_fdf5ce_1x400.png | Bin 0 -> 125 bytes .../images/ui-bg_glass_65_ffffff_1x400.png | Bin 0 -> 105 bytes .../ui-bg_gloss-wave_35_f6a828_500x100.png | Bin 0 -> 4427 bytes .../ui-bg_highlight-soft_100_eeeeee_1x100.png | Bin 0 -> 90 bytes .../ui-bg_highlight-soft_75_ffe45c_1x100.png | Bin 0 -> 129 bytes .../images/ui-icons_222222_256x240.png | Bin 0 -> 4369 bytes .../images/ui-icons_228ef1_256x240.png | Bin 0 -> 4369 bytes .../images/ui-icons_ef8c08_256x240.png | Bin 0 -> 4369 bytes .../images/ui-icons_ffd27a_256x240.png | Bin 0 -> 4369 bytes .../images/ui-icons_ffffff_256x240.png | Bin 0 -> 4369 bytes .../ui-lightness/jquery-ui-1.8.4.custom.css | 334 ++++ .../file-uploader/tests/qunit/package.json | 21 + .../file-uploader/tests/qunit/qunit/qunit.css | 119 ++ .../file-uploader/tests/qunit/qunit/qunit.js | 1069 +++++++++++++ .../file-uploader/tests/qunit/test/index.html | 17 + .../file-uploader/tests/qunit/test/same.js | 1423 +++++++++++++++++ .../file-uploader/tests/qunit/test/test.js | 171 ++ .../1imagelonglonglonglonglonglongname.gif | Bin 0 -> 1688 bytes .../tests/sample-files/2larger.txt | 1 + .../tests/sample-files/3empty.txt | 0 .../tests/sample-files/4text.txt | 1 + .../tests/sample-files/5text.txt | 1 + .../tests/sample-files/6text.txt | 1 + .../tests/sample-files/7small.txt | 1 + .../tests/sample-files/8text.txt | 1 + .../tests/separate-file-list.htm | 24 + .../file-uploader/tests/test-acceptance.htm | 106 ++ .../file-uploader/tests/test-drop-zone.htm | 48 + .../tests/test-handler-queue.htm | 81 + .../tests/test-upload-handlers.htm | 382 +++++ js_upload/js_upload.php | 339 ++++ ldapauth.tgz | Bin 0 -> 1517 bytes ldapauth/README | 17 + ldapauth/ldapauth.php | 130 ++ oembed.tgz | Bin 0 -> 1949 bytes oembed/oembed.js | 6 + oembed/oembed.php | 89 ++ oembed/oembed.png | Bin 0 -> 417 bytes oembed/settings.tpl | 7 + piwik.tgz | Bin 0 -> 2845 bytes piwik/README | 43 + piwik/admin.tpl | 4 + piwik/piwik.css | 8 + piwik/piwik.php | 95 ++ poormancron.tgz | Bin 0 -> 950 bytes poormancron/poormancron.php | 64 + randplace.tgz | Bin 0 -> 2071 bytes randplace/randplace.css | 14 + randplace/randplace.php | 180 +++ statusnet.tgz | Bin 0 -> 14846 bytes statusnet/README | 75 + statusnet/admin.tpl | 16 + statusnet/signinwithstatusnet.png | Bin 0 -> 5808 bytes statusnet/statusnet.css | 74 + statusnet/statusnet.php | 480 ++++++ tictac.tgz | Bin 0 -> 5041 bytes tictac/tictac.php | 665 ++++++++ twitter.tgz | Bin 0 -> 8940 bytes twitter/README | 77 + twitter/admin.tpl | 3 + twitter/lighter.png | Bin 0 -> 2490 bytes twitter/twitter.css | 41 + twitter/twitter.php | 285 ++++ widgets.tgz | Bin 0 -> 3292 bytes widgets/settings.tpl | 19 + widgets/widget_friends.php | 32 + widgets/widget_like.php | 22 + widgets/widgets.js | 64 + widgets/widgets.php | 170 ++ wppost.tgz | Bin 1924 -> 1930 bytes 124 files changed, 11673 insertions(+), 1 deletion(-) delete mode 100644 README create mode 100644 calc.tgz create mode 100644 calc/calc.php create mode 100644 convert.tgz create mode 100644 convert/UnitConvertor.php create mode 100644 convert/convert.php create mode 100644 facebook.tgz create mode 100644 facebook/README create mode 100644 facebook/facebook.css create mode 100644 facebook/facebook.php create mode 100644 fortunate.tgz create mode 100644 fortunate/fortunate.css create mode 100644 fortunate/fortunate.php create mode 100644 impressum.tgz create mode 100644 impressum/README create mode 100644 impressum/admin.tpl create mode 100644 impressum/impressum.php create mode 100644 js_upload.tgz create mode 100644 js_upload/file-uploader/client/demo.htm create mode 100644 js_upload/file-uploader/client/do-nothing.htm create mode 100644 js_upload/file-uploader/client/fileuploader.css create mode 100644 js_upload/file-uploader/client/fileuploader.js create mode 100644 js_upload/file-uploader/client/loading.gif create mode 100644 js_upload/file-uploader/gpl-2.0.txt create mode 100644 js_upload/file-uploader/license.txt create mode 100644 js_upload/file-uploader/readme.md create mode 100644 js_upload/file-uploader/server/OctetStreamReader.java create mode 100644 js_upload/file-uploader/server/coldfusion/coldfusion.cfc create mode 100644 js_upload/file-uploader/server/coldfusion/demo.cfm create mode 100644 js_upload/file-uploader/server/coldfusion/readme.txt create mode 100644 js_upload/file-uploader/server/perl.cgi create mode 100644 js_upload/file-uploader/server/php.php create mode 100644 js_upload/file-uploader/server/readme.txt create mode 100644 js_upload/file-uploader/server/uploads/.gitignore create mode 100644 js_upload/file-uploader/tests/action-acceptance.php create mode 100644 js_upload/file-uploader/tests/action-handler-queue-test.php create mode 100644 js_upload/file-uploader/tests/action-handler-test.php create mode 100644 js_upload/file-uploader/tests/action-slow-response.php create mode 100644 js_upload/file-uploader/tests/browser-bugs/safari-bug1.htm create mode 100644 js_upload/file-uploader/tests/browser-bugs/safari-bug2.htm create mode 100644 js_upload/file-uploader/tests/iframe-content-tests/application-javascript.php create mode 100644 js_upload/file-uploader/tests/iframe-content-tests/application-json.php create mode 100644 js_upload/file-uploader/tests/iframe-content-tests/header-404.php create mode 100644 js_upload/file-uploader/tests/iframe-content-tests/somepage.php create mode 100644 js_upload/file-uploader/tests/iframe-content-tests/text-html-large.php create mode 100644 js_upload/file-uploader/tests/iframe-content-tests/text-html.php create mode 100644 js_upload/file-uploader/tests/iframe-content-tests/text-javascript.php create mode 100644 js_upload/file-uploader/tests/iframe-content-tests/text-plain.php create mode 100644 js_upload/file-uploader/tests/jquery-1.4.2.min.js create mode 100644 js_upload/file-uploader/tests/jquery-ui/jquery-ui-1.8.4.custom.min.js create mode 100644 js_upload/file-uploader/tests/jquery-ui/ui-lightness/images/ui-bg_diagonals-thick_18_b81900_40x40.png create mode 100644 js_upload/file-uploader/tests/jquery-ui/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png create mode 100644 js_upload/file-uploader/tests/jquery-ui/ui-lightness/images/ui-bg_flat_10_000000_40x100.png create mode 100644 js_upload/file-uploader/tests/jquery-ui/ui-lightness/images/ui-bg_glass_100_f6f6f6_1x400.png create mode 100644 js_upload/file-uploader/tests/jquery-ui/ui-lightness/images/ui-bg_glass_100_fdf5ce_1x400.png create mode 100644 js_upload/file-uploader/tests/jquery-ui/ui-lightness/images/ui-bg_glass_65_ffffff_1x400.png create mode 100644 js_upload/file-uploader/tests/jquery-ui/ui-lightness/images/ui-bg_gloss-wave_35_f6a828_500x100.png create mode 100644 js_upload/file-uploader/tests/jquery-ui/ui-lightness/images/ui-bg_highlight-soft_100_eeeeee_1x100.png create mode 100644 js_upload/file-uploader/tests/jquery-ui/ui-lightness/images/ui-bg_highlight-soft_75_ffe45c_1x100.png create mode 100644 js_upload/file-uploader/tests/jquery-ui/ui-lightness/images/ui-icons_222222_256x240.png create mode 100644 js_upload/file-uploader/tests/jquery-ui/ui-lightness/images/ui-icons_228ef1_256x240.png create mode 100644 js_upload/file-uploader/tests/jquery-ui/ui-lightness/images/ui-icons_ef8c08_256x240.png create mode 100644 js_upload/file-uploader/tests/jquery-ui/ui-lightness/images/ui-icons_ffd27a_256x240.png create mode 100644 js_upload/file-uploader/tests/jquery-ui/ui-lightness/images/ui-icons_ffffff_256x240.png create mode 100644 js_upload/file-uploader/tests/jquery-ui/ui-lightness/jquery-ui-1.8.4.custom.css create mode 100644 js_upload/file-uploader/tests/qunit/package.json create mode 100644 js_upload/file-uploader/tests/qunit/qunit/qunit.css create mode 100644 js_upload/file-uploader/tests/qunit/qunit/qunit.js create mode 100644 js_upload/file-uploader/tests/qunit/test/index.html create mode 100644 js_upload/file-uploader/tests/qunit/test/same.js create mode 100644 js_upload/file-uploader/tests/qunit/test/test.js create mode 100644 js_upload/file-uploader/tests/sample-files/1imagelonglonglonglonglonglongname.gif create mode 100644 js_upload/file-uploader/tests/sample-files/2larger.txt create mode 100644 js_upload/file-uploader/tests/sample-files/3empty.txt create mode 100644 js_upload/file-uploader/tests/sample-files/4text.txt create mode 100644 js_upload/file-uploader/tests/sample-files/5text.txt create mode 100644 js_upload/file-uploader/tests/sample-files/6text.txt create mode 100644 js_upload/file-uploader/tests/sample-files/7small.txt create mode 100644 js_upload/file-uploader/tests/sample-files/8text.txt create mode 100644 js_upload/file-uploader/tests/separate-file-list.htm create mode 100644 js_upload/file-uploader/tests/test-acceptance.htm create mode 100644 js_upload/file-uploader/tests/test-drop-zone.htm create mode 100644 js_upload/file-uploader/tests/test-handler-queue.htm create mode 100644 js_upload/file-uploader/tests/test-upload-handlers.htm create mode 100644 js_upload/js_upload.php create mode 100644 ldapauth.tgz create mode 100644 ldapauth/README create mode 100644 ldapauth/ldapauth.php create mode 100644 oembed.tgz create mode 100644 oembed/oembed.js create mode 100644 oembed/oembed.php create mode 100644 oembed/oembed.png create mode 100644 oembed/settings.tpl create mode 100644 piwik.tgz create mode 100644 piwik/README create mode 100644 piwik/admin.tpl create mode 100644 piwik/piwik.css create mode 100644 piwik/piwik.php create mode 100644 poormancron.tgz create mode 100644 poormancron/poormancron.php create mode 100644 randplace.tgz create mode 100644 randplace/randplace.css create mode 100644 randplace/randplace.php create mode 100644 statusnet.tgz create mode 100644 statusnet/README create mode 100644 statusnet/admin.tpl create mode 100644 statusnet/signinwithstatusnet.png create mode 100644 statusnet/statusnet.css create mode 100644 statusnet/statusnet.php create mode 100644 tictac.tgz create mode 100644 tictac/tictac.php create mode 100644 twitter.tgz create mode 100644 twitter/README create mode 100644 twitter/admin.tpl create mode 100644 twitter/lighter.png create mode 100644 twitter/twitter.css create mode 100644 twitter/twitter.php create mode 100644 widgets.tgz create mode 100644 widgets/settings.tpl create mode 100644 widgets/widget_friends.php create mode 100644 widgets/widget_like.php create mode 100644 widgets/widgets.js create mode 100644 widgets/widgets.php diff --git a/README b/README deleted file mode 100644 index d8abf2a0..00000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -Repository for Friendika addon modules diff --git a/calc.tgz b/calc.tgz new file mode 100644 index 0000000000000000000000000000000000000000..f5d6870da96417394ff4a9ffac24d863e93dbc36 GIT binary patch literal 1958 zcmV;X2U++ZiwFRb>wZoE1MOOCZ`(K)&DR+4e_*u1*hy>4mJ=sUWew6MGuy>BEm~vt z!(gVMCE6w`iz+2K$t>o-?C5&6d;R{fe>Ut7`h(tH4<3dmd+78#`y~+tA?66}EwDYKd`Z0x zUV9n(0$IP)Ft`?23umf-fW0J)5x<0 z1rh=KiF&YguG>CB|7|w*IhoNQB>dByvCr)m_We%_;zh0JsD&Med3qtzMYA-LjXQeT zZ2Vm%iM%3BwJ`w&0>>2MPB9Zr5oh&3kN>*S^(xF+3dHV*I52$`mduHTKt zvl)j6au3P23Q@)Sh>Bu?fya**d;fFJ0c=b3OS$_WXR|`1TIL$ z37WZVf?c%4oZ^W~f@TA5kwXLD#rI=!7s7fpEpGLqML)YU;ydOOF4P>~`y?^_A5KGp zLY7*|DF%^n6*soMBM=N+rw%YU%#L6y!|sfP*DevaukPPCZ7ngOiRhqCcZuDIBp&5` zd^SQ}VL+}k*;;Vy(s5|~D&`%!i53%hE#p9@Q`9ajUU11CR1$@gAacPt0_#E;X!0=+ z$S*F#Vcy13vym4`cn_?l1;k5A9sL+hLXPc{uR+qf1BX-UtzN$c^E7wfWsWc6j{6-r zo>Fgh{E9AVP;?oN1?rF;I2;pij}GdQd{|Jgow)Ikmubst5}&hWh;d6FXHU4lS7i1?^#xTy z+eGCbt#6V&gN#8b5f;tgauQTUJt&H5Y?CeV=^~fg0XY~fepe?sSL$6!(`QLOi_iu! zr3M*QAv@c^mL*IZC_4|MET>i*ShH+r1MBg_SXX(`2EHU&*}$gPV%r$12(5xOpZdRJ zesF-UIcNMpE5|29GnZjptv%SHFRea&OPp5yEL9}H3sa8^K9-np{ca2s4{^ux@r?Z5 znuiN_POuXftPbzim)30Nh2TN^5c_^wRbs%di)) z5kCh$wv%TuXUg~jd3Zt6Y81zs57Cv`^IMkmf?k0C_* zNDE=dVWJ){T$dVfI6&zPOuA$mYG|1}EvVy&s$)!?lEqe;N94c=?tk(of&VhT_VW+% zRYT0P;dTE!(sCuU{!!}DBnm_3Wj}zCMHD?3Yx9{wfMSQJKCv^olsV~5kF4wDlT9@p!K3PET)^ZK&at-TqEvUC)YvXHY zD`%xT`slkHkR|cf`gc}WjkEe{5IUQOYuV20vYppw^XP`d=|x?#7Z2Fz!q?1N+T$v1 zg}hQ$e)Jvxi}3ZwXs@m+y$2j@v_$oue%*eO22@y(q(SR=9JW5J;%j%?%33*Qt*afi z>aNX6z9hF0>suu))#D%k-Ts0(5jCXDLs5vyA1|_?RR7$Rg^|_SiSGV13fAJfNo{+O z#daWX&Fnb_uWFRl4QiVOlO33rndOF4F}q5aA7AzAsRK>bqg~XNYp)4&yI@yTc=In$ zQmd|Q&t?U4@R+kEe|PW@*Gkr~9Ta_gy~W_eq+WgX8d_;ZA`@EsD$4w6!z){F3<}2&w-T3;# z)L&WX(sjje-Uz~;Sg^dcbJY<9@3)*Z;g$nm{)l>MRjP|VK#rM~SM8)^B?~U;49K=4 zFgZ)BS6$&!oZ{@u9A{rH#<4c6C|T^5{x~<~B#gL+4q5u2FLwR^ZWI(06ciK`6ciK` s6ciK`6ciK`6ciK`6ciK`6ciK`6ciK`6ciK`6uuSz18glcj{r~r0R3~iKL7v# literal 0 HcmV?d00001 diff --git a/calc/calc.php b/calc/calc.php new file mode 100644 index 00000000..8c079dc7 --- /dev/null +++ b/calc/calc.php @@ -0,0 +1,363 @@ + + */ + + +function calc_install() { + register_hook('app_menu', 'addon/calc/calc.php', 'calc_app_menu'); +} + +function calc_uninstall() { + unregister_hook('app_menu', 'addon/calc/calc.php', 'calc_app_menu'); + +} + +function calc_app_menu($a,&$b) { + $b['app_menu'] .= ''; +} + + +function calc_module() {} + + + + +function calc_init($a) { + +$x = <<< EOT + + + +EOT; +$a->page['htmlhead'] .= $x; +} + +function calc_content($app) { + +$o = ''; + +$o .= <<< EOT + +

Calculator

+

+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + +
+ +EOT; +return $o; + +} diff --git a/convert.tgz b/convert.tgz new file mode 100644 index 0000000000000000000000000000000000000000..b6e3e2a538ccaaba3a6b2e4c2d67a59d7f93eff3 GIT binary patch literal 5324 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 e_&h$3&*Ss>JU)-l | +// | Co-authored by : CVH, Chris Hansel | +// +----------------------------------------------------------------------+ +// +// $Id: UnitConvertor.php,v 1.00 2002/02/20 11:40:00 stasokhvat Exp $ + +/** +* UnitConvertor is able to convert between different units and currencies. +* +* @author Stanislav Okhvat +* @version $Id: UnitConvertor.php,v 1.00 2002/03/01 17:00:00 stasokhvat Exp $ +* @package UnitConvertor +* @access public +* @history 01.03.2002 Implemented the code for regular and offset-based +* conversions +* +* 13.12.2004 +* By Chris Hansel (CVH): changed getConvSpecs in order to have it look up +* intermediary conversions (also see comments in check_key). +* +* Intermediary conversions are useful when no conversion ratio is specified +* between two units when we calculate between the two. For example, we want +* to convert between Fahrenheit and Kelvin, and we have only +* specified how to convert Centigrade<->Fahrenheit and +* Centigrade<->Kelvin. While a direct (Fahrenheit->Kelvin) or +* reverse (Kelvin->Fahrenheit) lookups fail, looking for an intermediary +* unit linking the two (Centigrade) helps us do the conversion. +* +* 13.12.2004 +* Chris Hansel (CVH): $to_array argument of addConversion method can now +* contain units as 'unit1/unit2/unit3', when all units stand for the same +* thing. See examples in unitconv.php +*/ +class UnitConvertor +{ + /** + * Stores conversion ratios. + * + * @var array + * @access private + */ + var $conversion_table = array(); + + /** + * Decimal point character (default is "." - American - set in constructor). + * + * @var string + * @access private + */ + var $decimal_point; + + /** + * Thousands separator (default is "," - American - set in constructor). + * + * @var string + * @access private + */ + var $thousand_separator; + + /** + * For future use + * + * @var array + * @access private + */ + var $bases = array(); + + /** + * Constructor. Initializes the UnitConvertor object with the most important + * properties. + * + * @param string decimal point character + * @param string thousand separator character + * @return void + * @access public + */ + function UnitConvertor($dec_point = '.', $thousand_sep = ',') + { + $this->decimal_point = $dec_point; + $this->thousand_separator = $thousand_sep; + + } // end func UnitConvertor + + /** + * Adds a conversion ratio to the conversion table. + * + * @param string the name of unit from which to convert + * @param array array( + * "pound"=>array("ratio"=>'', "offset"=>'') + * ) + * "pound" - name of unit to set conversion ration to + * "ratio" - 'double' conversion ratio which, when + * multiplied by the number of $from_unit units produces + * the result + * "offset" - an offset from 0 which will be added to + * the result when converting (needed for temperature + * conversions and defaults to 0). + * @return boolean true if successful, false otherwise + * @access public + */ + function addConversion($from_unit, $to_array) + { + if (!isset($this->conversion_table[$from_unit])) { + while(list($key, $val) = each($to_array)) + { + if (strstr($key, '/')) + { + $to_units = explode('/', $key); + foreach ($to_units as $to_unit) + { + $this->bases[$from_unit][] = $to_unit; + + if (!is_array($val)) + { + $this->conversion_table[$from_unit."_".$to_unit] = array("ratio"=>$val, "offset"=>0); + } + else + { + $this->conversion_table[$from_unit."_".$to_unit] = + array( + "ratio"=>$val['ratio'], + "offset"=>(isset($val['offset']) ? $val['offset'] : 0) + ); + } + } + } + else + { + $this->bases[$from_unit][] = $key; + + if (!is_array($val)) + { + $this->conversion_table[$from_unit."_".$key] = array("ratio"=>$val, "offset"=>0); + } + else + { + $this->conversion_table[$from_unit."_".$key] = + array( + "ratio"=>$val['ratio'], + "offset"=>(isset($val['offset']) ? $val['offset'] : 0) + ); + } + } + } + return true; + } + return false; + + } // end func addConversion + + /** + * Converts from one unit to another using specified precision. + * + * @param double value to convert + * @param string name of the source unit from which to convert + * @param string name of the target unit to which we are converting + * @param integer double precision of the end result + * @return void + * @access public + */ + function convert($value, $from_unit, $to_unit, $precision) + { + if ($this->getConvSpecs($from_unit, $to_unit, $value, $converted )) + { + return number_format($converted , (int)$precision, $this->decimal_point, $this->thousand_separator); + } else { + return false; + } + } // end func + + /** + * CVH : changed this Function getConvSpecs in order to have it look up + * intermediary Conversions from the + * "base" unit being that one that has the highest hierarchical order in one + * "logical" Conversion_Array + * when taking $conv->addConversion('km', + * array('meter'=>1000, 'dmeter'=>10000, 'centimeter'=>100000, + * 'millimeter'=>1000000, 'mile'=>0.62137, 'naut.mile'=>0.53996, + * 'inch(es)/zoll'=>39370, 'ft/foot/feet'=>3280.8, 'yd/yard'=>1093.6)); + * "km" would be the logical base unit for all units of dinstance, thus, + * if the function fails to find a direct or reverse conversion in the table + * it is only logical to suspect that if there is a chance + * converting the value it only is via the "base" unit, and so + * there is not even a need for a recursive search keeping the perfomance + * acceptable and the ressource small... + * + * CVH check_key checks for a key in the Conversiontable and returns a value + */ + function check_key( $key) { + if ( array_key_exists ($key,$this->conversion_table)) { + if (! empty($this->conversion_table[$key])) { + return $this->conversion_table[$key]; + } + } + return false; + } + + /** + * Key function. Finds the conversion ratio and offset from one unit to another. + * + * @param string name of the source unit from which to convert + * @param string name of the target unit to which we are converting + * @param double conversion ratio found. Returned by reference. + * @param double offset which needs to be added (or subtracted, if negative) + * to the result to convert correctly. + * For temperature or some scientific conversions, + * i.e. Fahrenheit -> Celcius + * @return boolean true if ratio and offset are found for the supplied + * units, false otherwise + * @access private + */ + function getConvSpecs($from_unit, $to_unit, $value, &$converted) + { + $key = $from_unit."_".$to_unit; + $revkey = $to_unit."_".$from_unit; + $found = false; + if ($ct_arr = $this->check_key($key)) { + // Conversion Specs found directly + $ratio = (double)$ct_arr['ratio']; + $offset = $ct_arr['offset']; + $converted = (double)(($value * $ratio)+ $offset); + + return true; + } // not found in direct order, try reverse order + elseif ($ct_arr = $this->check_key($revkey)) { + $ratio = (double)(1/$ct_arr['ratio']); + $offset = -$ct_arr['offset']; + $converted = (double)(($value + $offset) * $ratio); + + return true; + } // not found test for intermediary conversion + else { + // return ratio = 1 if keyparts match + if ($key == $revkey) { + $ratio = 1; + $offset = 0; + $converted = $value; + return true; + } + // otherwise search intermediary + reset($this->conversion_table); + while (list($convk, $i1_value) = each($this->conversion_table)) { + // split the key into parts + $keyparts = preg_split("/_/",$convk); + // return ratio = 1 if keyparts match + + // Now test if either part matches the from or to unit + if ($keyparts[1] == $to_unit && ($i2_value = $this->check_key($keyparts[0]."_".$from_unit))) { + // an intermediary $keyparts[0] was found + // now let us put things together intermediary 1 and 2 + $converted = (double)(((($value - $i2_value['offset']) / $i2_value['ratio']) * $i1_value['ratio'])+ $i1_value['offset']); + + $found = true; + + } elseif ($keyparts[1] == $from_unit && ($i2_value = $this->check_key($keyparts[0]."_".$to_unit))) { + // an intermediary $keyparts[0] was found + // now let us put things together intermediary 2 and 1 + $converted = (double)(((($value - $i1_value['offset']) / $i1_value['ratio']) + $i2_value['offset']) * $i2_value['ratio']); + + $found = true; + } + } + return $found; + } + + } // end func getConvSpecs + +} // end class UnitConvertor +?> \ No newline at end of file diff --git a/convert/convert.php b/convert/convert.php new file mode 100644 index 00000000..7a4c90a5 --- /dev/null +++ b/convert/convert.php @@ -0,0 +1,228 @@ + + */ + +function convert_install() { + register_hook('app_menu', 'addon/convert/convert.php', 'convert_app_menu'); +} + +function convert_uninstall() { + unregister_hook('app_menu', 'addon/convert/convert.php', 'convert_app_menu'); +} + +function convert_app_menu($a,&$b) { + $b['app_menu'] .= ''; +} + + +function convert_module() {} + + + + + + + +function convert_content($app) { + +include("UnitConvertor.php"); + + class TP_Converter extends UnitConvertor { + function TP_Converter($lang = "en") + { + if ($lang != 'en' ) { + $dec_point = '.'; $thousand_sep = "'"; + } else { + $dec_point = '.'; $thousand_sep = ","; + } + + $this->UnitConvertor($dec_point , $thousand_sep ); + + } // end func UnitConvertor + + function find_base_unit($from,$to) { + while (list($skey,$sval) = each($this->bases)) { + if ($skey == $from || $to == $skey || in_array($to,$sval) || in_array($from,$sval)) { + return $skey; + } + } + return false; + } + + function getTable($value, $from_unit, $to_unit, $precision) { + + if ($base_unit = $this->find_base_unit($from_unit,$to_unit)) { + + // A baseunit was found now lets convert from -> $base_unit + + $cell ['value'] = $this->convert($value, $from_unit, $base_unit, $precision)." ".$base_unit; + $cell ['class'] = ($base_unit == $from_unit || $base_unit == $to_unit) ? "framedred": ""; + $cells[] = $cell; + // We now have the base unit and value now lets produce the table; + while (list($key,$val) = each($this->bases[$base_unit])) { + $cell ['value'] = $this->convert($value, $from_unit, $val, $precision)." ".$val; + $cell ['class'] = ($val == $from_unit || $val == $to_unit) ? "framedred": ""; + $cells[] = $cell; + } + + $cc = count($cells); + $string = ""; + $string .= ""; + $i=0; + foreach ($cells as $cell) { + if ($i==0) { + $string .= ""; + $i++; + } else { + $string .= ""; + } + } + $string .= "
$value $from_unit".$cell['value']."
".$cell['value']."
"; + return $string; + } + + } +} + + +$conv = new TP_Converter('en'); + + +$conversions = array( + 'Temperature'=>array('base' =>'Celsius', + 'conv'=>array( + 'Fahrenheit'=>array('ratio'=>1.8, 'offset'=>32), + 'Kelvin'=>array('ratio'=>1, 'offset'=>273), + 'Reaumur'=>0.8 + ) + ), + 'Weight' => array('base' =>'kg', + 'conv'=>array( + 'g'=>1000, + 'mg'=>1000000, + 't'=>0.001, + 'grain'=>15432, + 'oz'=>35.274, + 'lb'=>2.2046, + 'cwt(UK)' => 0.019684, + 'cwt(US)' => 0.022046, + 'ton (US)' => 0.0011023, + 'ton (UK)' => 0.0009842 + ) + ), + 'Distance' => array('base' =>'km', + 'conv'=>array( + 'm'=>1000, + 'dm'=>10000, + 'cm'=>100000, + 'mm'=>1000000, + 'mile'=>0.62137, + 'naut.mile'=>0.53996, + 'inch(es)'=>39370, + 'ft'=>3280.8, + 'yd'=>1093.6, + 'furlong'=>4.970969537898672, + 'fathom'=>546.8066491688539 + ) + ), + 'Area' => array('base' =>'km 2', + 'conv'=>array( + 'ha'=>100, + 'acre'=>247.105, + 'm 2'=>pow(1000,2), + 'dm 2'=>pow(10000,2), + 'cm 2'=>pow(100000,2), + 'mm 2'=>pow(1000000,2), + 'mile 2'=>pow(0.62137,2), + 'naut.miles 2'=>pow(0.53996,2), + 'in 2'=>pow(39370,2), + 'ft 2'=>pow(3280.8,2), + 'yd 2'=>pow(1093.6,2), + ) + ), + 'Volume' => array('base' =>'m 3', + 'conv'=>array( + 'in 3'=>61023.6, + 'ft 3'=>35.315, + 'cm 3'=>pow(10,6), + 'dm 3'=>1000, + 'litre'=>1000, + 'hl'=>10, + 'yd 3'=>1.30795, + 'gal(US)'=>264.172, + 'gal(UK)'=>219.969, + 'pint' => 2113.376, + 'quart' => 1056.688, + 'cup' => 4266.753, + 'fl oz' => 33814.02, + 'tablespoon' => 67628.04, + 'teaspoon' => 202884.1, + 'pt (UK)'=>1000/0.56826, + 'barrel petroleum'=>1000/158.99, + 'Register Tons'=>2.832, + 'Ocean Tons'=>1.1327 + ) + ), + 'Speed' =>array('base' =>'kmph', + 'conv'=>array( + 'mps'=>0.0001726031, + 'milesph'=>0.62137, + 'knots'=>0.53996, + 'mach STP'=>0.0008380431, + 'c (warp)'=>9.265669e-10 + ) + ) +); + + +while (list($key,$val) = each($conversions)) { + $conv->addConversion($val['base'], $val['conv']); + $list[$key][] = $val['base']; + while (list($ukey,$uval) = each($val['conv'])) { + $list[$key][] = $ukey; + } +} + + $o .= '

Unit Conversions

'; + + + if (isset($_POST['from_unit']) && isset($_POST['value'])) { + $_POST['value'] = $_POST['value'] + 0; + + + $o .= ($conv->getTable($_POST['value'], $_POST['from_unit'], $_POST['to_unit'], 5))."

"; + } else { + $o .= "

Select:

"; + } + + if(isset($_POST['value'])) + $value = $_POST['value']; + else + $value = ''; + + $o .= '
'; + $o .= ''; + $o .= ''; + + $o .= '
'; + + return $o; +} diff --git a/facebook.tgz b/facebook.tgz new file mode 100644 index 0000000000000000000000000000000000000000..05c7c735fb916966b35732f13b059f6ea80ec9c3 GIT binary patch literal 9982 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 I-2k8f0DmEIApigX literal 0 HcmV?d00001 diff --git a/facebook/README b/facebook/README new file mode 100644 index 00000000..325f18dd --- /dev/null +++ b/facebook/README @@ -0,0 +1,39 @@ +Installing the Friendika/Facebook connector + +1. register an API key for your site from developer.facebook.com + a. We'd be very happy if you include "Friendika" in the application name + to increase name recognition. The Friendika icons are also present + in the images directory and may be uploaded as a Facebook app icon. + Use images/friendika-16.jpg for the Icon and images/friendika-128.jpg for the Logo. + b. The url should be your site URL with a trailing slash. + You may use http://portal.friendika.com/privacy as the privacy policy + URL unless your site has different requirements, and + http://portal.friendika.com as the Terms of Service URL unless + you have different requirements. (Friendika is a software application + and does not require Terms of Service, though your installation of it might). + c. Set the following values in your .htconfig.php file + $a->config['facebook']['appid'] = 'xxxxxxxxxxx'; + $a->config['facebook']['appsecret'] = 'xxxxxxxxxxxxxxx'; + Replace with the settings Facebook gives you. + d. Navigate to Set Web->Site URL & Domain -> Website Settings. Set Site URL + to yoursubdomain.yourdomain.com. Set Site Domain to your yourdomain.com. +2. Enable the facebook plugin by including it in .htconfig.php - e.g. + $a->config['system']['addon'] = 'plugin1,plugin2,facebook'; +3. Visit the Facebook Settings section of the "Settings->Plugin Settings" page. + and click 'Install Facebook Connector'. +4. This will ask you to login to Facebook and grant permission to the + plugin to do its stuff. Allow it to do so. +5. You're done. To turn it off visit the Plugin Settings page again and + 'Remove Facebook posting'. + +Vidoes and embeds will not be posted if there is no other content. Links +and images will be converted to a format suitable for the Facebook API and +long posts truncated - with a link to view the full post. + +Facebook contacts will not be able to view private photos, as they are not able to +authenticate to your site to establish identity. We will address this +in a future release. + +Info: please make sure that you understand all aspects due to Friendika's +default licence which is: Creative Commons Attribution 3.0 (further info: +http://creativecommons.org/licenses/by/3.0/ ) diff --git a/facebook/facebook.css b/facebook/facebook.css new file mode 100644 index 00000000..0c164331 --- /dev/null +++ b/facebook/facebook.css @@ -0,0 +1,13 @@ + +#facebook-enable-wrapper { + margin-top: 20px; +} + +#facebook-disable-wrapper { + margin-top: 20px; +} + +#facebook-post-default-form input { + margin-top: 20px; + margin-right: 20px; +} \ No newline at end of file diff --git a/facebook/facebook.php b/facebook/facebook.php new file mode 100644 index 00000000..7ffdaffa --- /dev/null +++ b/facebook/facebook.php @@ -0,0 +1,1059 @@ + + */ + +/** + * Installing the Friendika/Facebook connector + * + * 1. register an API key for your site from developer.facebook.com + * a. We'd be very happy if you include "Friendika" in the application name + * to increase name recognition. The Friendika icons are also present + * in the images directory and may be uploaded as a Facebook app icon. + * Use images/friendika-16.jpg for the Icon and images/friendika-128.jpg for the Logo. + * b. The url should be your site URL with a trailing slash. + * You may use http://portal.friendika.com/privacy as the privacy policy + * URL unless your site has different requirements, and + * http://portal.friendika.com as the Terms of Service URL unless + * you have different requirements. (Friendika is a software application + * and does not require Terms of Service, though your installation of it might). + * c. Set the following values in your .htconfig.php file + * $a->config['facebook']['appid'] = 'xxxxxxxxxxx'; + * $a->config['facebook']['appsecret'] = 'xxxxxxxxxxxxxxx'; + * Replace with the settings Facebook gives you. + * d. Navigate to Set Web->Site URL & Domain -> Website Settings. Set + * Site URL to yoursubdomain.yourdomain.com. Set Site Domain to your + * yourdomain.com. + * 2. Enable the facebook plugin by including it in .htconfig.php - e.g. + * $a->config['system']['addon'] = 'plugin1,plugin2,facebook'; + * 3. Visit the Facebook Settings section of the "Settings->Plugin Settings" page. + * and click 'Install Facebook Connector'. + * 4. This will ask you to login to Facebook and grant permission to the + * plugin to do its stuff. Allow it to do so. + * 5. You're done. To turn it off visit the Plugin Settings page again and + * 'Remove Facebook posting'. + * + * Vidoes and embeds will not be posted if there is no other content. Links + * and images will be converted to a format suitable for the Facebook API and + * long posts truncated - with a link to view the full post. + * + * Facebook contacts will not be able to view private photos, as they are not able to + * authenticate to your site to establish identity. We will address this + * in a future release. + */ + +define('FACEBOOK_MAXPOSTLEN', 420); + + +function facebook_install() { + register_hook('post_local_end', 'addon/facebook/facebook.php', 'facebook_post_hook'); + register_hook('jot_networks', 'addon/facebook/facebook.php', 'facebook_jot_nets'); + register_hook('plugin_settings', 'addon/facebook/facebook.php', 'facebook_plugin_settings'); + register_hook('cron', 'addon/facebook/facebook.php', 'facebook_cron'); + register_hook('queue_predeliver', 'addon/facebook/facebook.php', 'fb_queue_hook'); +} + + +function facebook_uninstall() { + unregister_hook('post_local_end', 'addon/facebook/facebook.php', 'facebook_post_hook'); + unregister_hook('jot_networks', 'addon/facebook/facebook.php', 'facebook_jot_nets'); + unregister_hook('plugin_settings', 'addon/facebook/facebook.php', 'facebook_plugin_settings'); + unregister_hook('cron', 'addon/facebook/facebook.php', 'facebook_cron'); + unregister_hook('queue_predeliver', 'addon/facebook/facebook.php', 'fb_queue_hook'); +} + + +/* declare the facebook_module function so that /facebook url requests will land here */ + +function facebook_module() {} + + + +/* If a->argv[1] is a nickname, this is a callback from Facebook oauth requests. */ + +function facebook_init(&$a) { + + if($a->argc != 2) + return; + $nick = $a->argv[1]; + if(strlen($nick)) + $r = q("SELECT `uid` FROM `user` WHERE `nickname` = '%s' LIMIT 1", + dbesc($nick) + ); + if(! count($r)) + return; + + $uid = $r[0]['uid']; + $auth_code = (($_GET['code']) ? $_GET['code'] : ''); + $error = (($_GET['error_description']) ? $_GET['error_description'] : ''); + + + if($error) + logger('facebook_init: Error: ' . $error); + + if($auth_code && $uid) { + + $appid = get_config('facebook','appid'); + $appsecret = get_config('facebook', 'appsecret'); + + $x = fetch_url('https://graph.facebook.com/oauth/access_token?client_id=' + . $appid . '&client_secret=' . $appsecret . '&redirect_uri=' + . urlencode($a->get_baseurl() . '/facebook/' . $nick) + . '&code=' . $auth_code); + + logger('facebook_init: returned access token: ' . $x, LOGGER_DATA); + + if(strpos($x,'access_token=') !== false) { + $token = str_replace('access_token=', '', $x); + if(strpos($token,'&') !== false) + $token = substr($token,0,strpos($token,'&')); + set_pconfig($uid,'facebook','access_token',$token); + set_pconfig($uid,'facebook','post','1'); + if(get_pconfig($uid,'facebook','no_linking') === false) + set_pconfig($uid,'facebook','no_linking',1); + fb_get_self($uid); + fb_get_friends($uid); + fb_consume_all($uid); + + } + + } + +} + + +function fb_get_self($uid) { + $access_token = get_pconfig($uid,'facebook','access_token'); + if(! $access_token) + return; + $s = fetch_url('https://graph.facebook.com/me/?access_token=' . $access_token); + if($s) { + $j = json_decode($s); + set_pconfig($uid,'facebook','self_id',(string) $j->id); + } +} + + + +function fb_get_friends($uid) { + + $r = q("SELECT `id` FROM `user` WHERE `uid` = %d AND `account_expired` = 0 LIMIT 1", + intval($uid) + ); + if(! count($r)) + return; + + $access_token = get_pconfig($uid,'facebook','access_token'); + + $no_linking = get_pconfig($uid,'facebook','no_linking'); + if($no_linking) + return; + + if(! $access_token) + return; + $s = fetch_url('https://graph.facebook.com/me/friends?access_token=' . $access_token); + if($s) { + logger('facebook: fb_get_friends: ' . $s, LOGGER_DATA); + $j = json_decode($s); + logger('facebook: fb_get_friends: json: ' . print_r($j,true), LOGGER_DATA); + if(! $j->data) + return; + foreach($j->data as $person) { + $s = fetch_url('https://graph.facebook.com/' . $person->id . '?access_token=' . $access_token); + if($s) { + $jp = json_decode($s); + logger('fb_get_friends: info: ' . print_r($jp,true), LOGGER_DATA); + + // always use numeric link for consistency + + $jp->link = 'http://facebook.com/profile.php?id=' . $person->id; + + // check if we already have a contact + + $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `url` = '%s' LIMIT 1", + intval($uid), + dbesc($jp->link) + ); + + if(count($r)) { + + // check that we have all the photos, this has been known to fail on occasion + + if((! $r[0]['photo']) || (! $r[0]['thumb']) || (! $r[0]['micro'])) { + require_once("Photo.php"); + + $photos = import_profile_photo('https://graph.facebook.com/' . $jp->id . '/picture', $uid, $r[0]['id']); + + $r = q("UPDATE `contact` SET `photo` = '%s', + `thumb` = '%s', + `micro` = '%s', + `name-date` = '%s', + `uri-date` = '%s', + `avatar-date` = '%s' + WHERE `id` = %d LIMIT 1 + ", + dbesc($photos[0]), + dbesc($photos[1]), + dbesc($photos[2]), + dbesc(datetime_convert()), + dbesc(datetime_convert()), + dbesc(datetime_convert()), + intval($r[0]['id']) + ); + } + continue; + } + else { + + // create contact record + $r = q("INSERT INTO `contact` ( `uid`, `created`, `url`, `addr`, `alias`, `notify`, `poll`, + `name`, `nick`, `photo`, `network`, `rel`, `priority`, + `writable`, `blocked`, `readonly`, `pending` ) + VALUES ( %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d, 0, 0, 0 ) ", + intval($uid), + dbesc(datetime_convert()), + dbesc($jp->link), + dbesc(''), + dbesc(''), + dbesc($jp->id), + dbesc('facebook ' . $jp->id), + dbesc($jp->name), + dbesc(($jp->nickname) ? $jp->nickname : strtolower($jp->first_name)), + dbesc('https://graph.facebook.com/' . $jp->id . '/picture'), + dbesc(NETWORK_FACEBOOK), + intval(CONTACT_IS_FRIEND), + intval(1), + intval(1) + ); + } + + $r = q("SELECT * FROM `contact` WHERE `url` = '%s' AND `uid` = %d LIMIT 1", + dbesc($jp->link), + intval($uid) + ); + + if(! count($r)) { + continue; + } + + $contact = $r[0]; + $contact_id = $r[0]['id']; + + require_once("Photo.php"); + + $photos = import_profile_photo($r[0]['photo'],$uid,$contact_id); + + $r = q("UPDATE `contact` SET `photo` = '%s', + `thumb` = '%s', + `micro` = '%s', + `name-date` = '%s', + `uri-date` = '%s', + `avatar-date` = '%s' + WHERE `id` = %d LIMIT 1 + ", + dbesc($photos[0]), + dbesc($photos[1]), + dbesc($photos[2]), + dbesc(datetime_convert()), + dbesc(datetime_convert()), + dbesc(datetime_convert()), + intval($contact_id) + ); + + } + } + } +} + +// This is the POST method to the facebook settings page +// Content is posted to Facebook in the function facebook_post_hook() + +function facebook_post(&$a) { + + $uid = local_user(); + if($uid){ + + $value = ((x($_POST,'post_by_default')) ? intval($_POST['post_by_default']) : 0); + set_pconfig($uid,'facebook','post_by_default', $value); + + $no_linking = get_pconfig($uid,'facebook','no_linking'); + + $no_wall = ((x($_POST,'facebook_no_wall')) ? intval($_POST['facebook_no_wall']) : 0); + set_pconfig($uid,'facebook','no_wall',$no_wall); + + $private_wall = ((x($_POST,'facebook_private_wall')) ? intval($_POST['facebook_private_wall']) : 0); + set_pconfig($uid,'facebook','private_wall',$private_wall); + + + $linkvalue = ((x($_POST,'facebook_linking')) ? intval($_POST['facebook_linking']) : 0); + set_pconfig($uid,'facebook','no_linking', (($linkvalue) ? 0 : 1)); + + // FB linkage was allowed but has just been turned off - remove all FB contacts and posts + + if((! intval($no_linking)) && (! intval($linkvalue))) { + $r = q("SELECT `id` FROM `contact` WHERE `uid` = %d AND `network` = '%s' ", + intval($uid), + dbesc(NETWORK_FACEBOOK) + ); + if(count($r)) { + require_once('include/Contact.php'); + foreach($r as $rr) + contact_remove($rr['id']); + } + } + elseif(intval($no_linking) && intval($linkvalue)) { + // FB linkage is now allowed - import stuff. + fb_get_self($uid); + fb_get_friends($uid); + fb_consume_all($uid); + } + + info( t('Settings updated.') . EOL); + } + + return; +} + +// Facebook settings form + +function facebook_content(&$a) { + + if(! local_user()) { + notice( t('Permission denied.') . EOL); + return ''; + } + + if($a->argc > 1 && $a->argv[1] === 'remove') { + del_pconfig(local_user(),'facebook','post'); + info( t('Facebook disabled') . EOL); + } + + if($a->argc > 1 && $a->argv[1] === 'friends') { + fb_get_friends(local_user()); + info( t('Updating contacts') . EOL); + } + + + $fb_installed = get_pconfig(local_user(),'facebook','post'); + + $appid = get_config('facebook','appid'); + + if(! $appid) { + notice( t('Facebook API key is missing.') . EOL); + return ''; + } + + $a->page['htmlhead'] .= '' . "\r\n"; + + $o .= '

' . t('Facebook Connect') . '

'; + + if(! $fb_installed) { + $o .= '
'; + } + + if($fb_installed) { + $o .= ''; + + $o .= ''; + + $o .= '
'; + $o .= '
'; + $post_by_default = get_pconfig(local_user(),'facebook','post_by_default'); + $checked = (($post_by_default) ? ' checked="checked" ' : ''); + $o .= '' . ' ' . t('Post to Facebook by default') . EOL; + + $no_linking = get_pconfig(local_user(),'facebook','no_linking'); + $checked = (($no_linking) ? '' : ' checked="checked" '); + $o .= '' . ' ' . t('Link all your Facebook friends and conversations on this website') . EOL ; + + $o .= '

' . t('Facebook conversations consist of your profile wall and your friend stream.'); + $o .= ' ' . t('On this website, your Facebook friend stream is only visible to you.'); + $o .= ' ' . t('The following settings determine the privacy of your Facebook profile wall on this website.') . '

'; + + $private_wall = get_pconfig(local_user(),'facebook','private_wall'); + $checked = (($private_wall) ? ' checked="checked" ' : ''); + $o .= '' . ' ' . t('On this website your Facebook profile wall conversations will only be visible to you') . EOL ; + + + $no_wall = get_pconfig(local_user(),'facebook','no_wall'); + $checked = (($no_wall) ? ' checked="checked" ' : ''); + $o .= '' . ' ' . t('Do not import your Facebook profile wall conversations') . EOL ; + + $o .= '

' . t('If you choose to link conversations and leave both of these boxes unchecked, your Facebook profile wall will be merged with your profile wall on this website and your privacy settings on this website will be used to determine who may see the conversations.') . '

'; + + $o .= '
'; + } + + return $o; +} + + + +function facebook_cron($a,$b) { + + $last = get_config('facebook','last_poll'); + + $poll_interval = intval(get_config('facebook','poll_interval')); + if(! $poll_interval) + $poll_interval = 3600; + + if($last) { + $next = $last + $poll_interval; + if($next > time()) + return; + } + + logger('facebook_cron'); + + + // Find the FB users on this site and randomize in case one of them + // uses an obscene amount of memory. It may kill this queue run + // but hopefully we'll get a few others through on each run. + + $r = q("SELECT * FROM `pconfig` WHERE `cat` = 'facebook' AND `k` = 'post' AND `v` = '1' ORDER BY RAND() "); + if(count($r)) { + foreach($r as $rr) { + if(get_pconfig($rr['uid'],'facebook','no_linking')) + continue; + // check for new friends once a day + $last_friend_check = get_pconfig($rr['uid'],'facebook','friend_check'); + if($last_friend_check) + $next_friend_check = $last_friend_check + 86400; + if($next_friend_check <= time()) { + fb_get_friends($rr['uid']); + set_pconfig($rr['uid'],'facebook','friend_check',time()); + } + fb_consume_all($rr['uid']); + } + } + + set_config('facebook','last_poll', time()); + +} + + + +function facebook_plugin_settings(&$a,&$b) { + + $b .= '
'; + $b .= '

' . t('Facebook') . '

'; + $b .= '' . t('Facebook Connector Settings') . '
'; + $b .= '
'; + +} + +function facebook_jot_nets(&$a,&$b) { + if(! local_user()) + return; + + $fb_post = get_pconfig(local_user(),'facebook','post'); + if(intval($fb_post) == 1) { + $fb_defpost = get_pconfig(local_user(),'facebook','post_by_default'); + $selected = ((intval($fb_defpost) == 1) ? ' checked="checked" ' : ''); + $b .= '
' + . t('Post to Facebook') . '
'; + } +} + + +function facebook_post_hook(&$a,&$b) { + + /** + * Post to Facebook stream + */ + + require_once('include/group.php'); + + logger('Facebook post'); + + $reply = false; + $likes = false; + + if((local_user()) && (local_user() == $b['uid'])) { + + // Facebook is not considered a private network + if($b['prvnets'] && $b['private']) + return; + + $linking = ((get_pconfig(local_user(),'facebook','no_linking')) ? 0 : 1); + + if(($b['parent']) && ($linking)) { + $r = q("SELECT * FROM `item` WHERE `id` = %d AND `uid` = %d LIMIT 1", + intval($b['parent']), + intval(local_user()) + ); + if(count($r) && substr($r[0]['uri'],0,4) === 'fb::') + $reply = substr($r[0]['uri'],4); + elseif(count($r) && substr($r[0]['extid'],0,4) === 'fb::') + $reply = substr($r[0]['extid'],4); + else + return; + logger('facebook reply id=' . $reply); + } + + if($b['private'] && $reply === false) { + $allow_people = expand_acl($b['allow_cid']); + $allow_groups = expand_groups(expand_acl($b['allow_gid'])); + $deny_people = expand_acl($b['deny_cid']); + $deny_groups = expand_groups(expand_acl($b['deny_gid'])); + + $recipients = array_unique(array_merge($allow_people,$allow_groups)); + $deny = array_unique(array_merge($deny_people,$deny_groups)); + + $allow_str = dbesc(implode(', ',$recipients)); + if($allow_str) { + $r = q("SELECT `notify` FROM `contact` WHERE `id` IN ( $allow_str ) AND `network` = 'face'"); + $allow_arr = array(); + if(count($r)) + foreach($r as $rr) + $allow_arr[] = $rr['notify']; + } + + $deny_str = dbesc(implode(', ',$deny)); + if($deny_str) { + $r = q("SELECT `notify` FROM `contact` WHERE `id` IN ( $deny_str ) AND `network` = 'face'"); + $deny_arr = array(); + if(count($r)) + foreach($r as $rr) + $deny_arr[] = $rr['notify']; + } + + if(count($deny_arr) && (! count($allow_arr))) { + + // One or more FB folks were denied access but nobody on FB was specifically allowed access. + // This might cause the post to be open to public on Facebook, but only to selected members + // on another network. Since this could potentially leak a post to somebody who was denied, + // we will skip posting it to Facebook with a slightly vague but relevant message that will + // hopefully lead somebody to this code comment for a better explanation of what went wrong. + + notice( t('Post to Facebook cancelled because of multi-network access permission conflict.') . EOL); + return; + } + + + // if it's a private message but no Facebook members are allowed or denied, skip Facebook post + + if((! count($allow_arr)) && (! count($deny_arr))) + return; + } + + if($b['verb'] == ACTIVITY_LIKE) + $likes = true; + + + $appid = get_config('facebook', 'appid' ); + $secret = get_config('facebook', 'appsecret' ); + + if($appid && $secret) { + + logger('facebook: have appid+secret'); + + $fb_post = intval(get_pconfig(local_user(),'facebook','post')); + $fb_enable = (($fb_post && x($_POST,'facebook_enable')) ? intval($_POST['facebook_enable']) : 0); + $fb_token = get_pconfig(local_user(),'facebook','access_token'); + + // if API is used, default to the chosen settings + if($_POST['api_source'] && intval(get_pconfig(local_user(),'facebook','post_by_default'))) + $fb_enable = 1; + + + + + logger('facebook: $fb_post: ' . $fb_post . ' $fb_enable: ' . $fb_enable . ' $fb_token: ' . $fb_token,LOGGER_DEBUG); + + // post to facebook if it's a public post and we've ticked the 'post to Facebook' box, + // or it's a private message with facebook participants + // or it's a reply or likes action to an existing facebook post + + if($fb_post && $fb_token && ($fb_enable || $b['private'] || $reply)) { + logger('facebook: able to post'); + require_once('library/facebook.php'); + require_once('include/bbcode.php'); + + $msg = $b['body']; + + logger('Facebook post: original msg=' . $msg, LOGGER_DATA); + + // make links readable before we strip the code + + // unless it's a dislike - just send the text as a comment + + if($b['verb'] == ACTIVITY_DISLIKE) + $msg = trim(strip_tags(bbcode($msg))); + + $search_str = $a->get_baseurl() . '/search'; + + if(preg_match("/\[url=(.*?)\](.*?)\[\/url\]/is",$msg,$matches)) { + + // don't use hashtags for message link + + if(strpos($matches[2],$search_str) === false) { + $link = $matches[1]; + if(substr($matches[2],0,5) != '[img]') + $linkname = $matches[2]; + } + } + + $msg = preg_replace("/\[url=(.*?)\](.*?)\[\/url\]/is",'$2 $1',$msg); + + if(preg_match("/\[img\](.*?)\[\/img\]/is",$msg,$matches)) + $image = $matches[1]; + + $msg = preg_replace("/\[img\](.*?)\[\/img\]/is", t('Image: ') . '$1', $msg); + + if((strpos($link,z_root()) !== false) && (! $image)) + $image = $a->get_baseurl() . '/images/friendika-64.jpg'; + + $msg = trim(strip_tags(bbcode($msg))); + $msg = html_entity_decode($msg,ENT_QUOTES,'UTF-8'); + + // add any attachments as text urls + + $arr = explode(',',$b['attach']); + + if(count($arr)) { + $msg .= "\n"; + foreach($arr as $r) { + $matches = false; + $cnt = preg_match('|\[attach\]href=\"(.*?)\" size=\"(.*?)\" type=\"(.*?)\" title=\"(.*?)\"\[\/attach\]|',$r,$matches); + if($cnt) { + $msg .= $matches[1]; + } + } + } + + if (strlen($msg) > FACEBOOK_MAXPOSTLEN) { + $shortlink = ""; + require_once('library/slinky.php'); + + $display_url = $a->get_baseurl() . '/display/' . $a->user['nickname'] . '/' . $b['id']; + $slinky = new Slinky( $display_url ); + // setup a cascade of shortening services + // try to get a short link from these services + // in the order ur1.ca, trim, id.gd, tinyurl + $slinky->set_cascade( array( new Slinky_UR1ca(), new Slinky_Trim(), new Slinky_IsGd(), new Slinky_TinyURL() ) ); + $shortlink = $slinky->short(); + // the new message will be shortened such that "... $shortlink" + // will fit into the character limit + $msg = substr($msg, 0, FACEBOOK_MAXPOSTLEN - strlen($shortlink) - 4); + $msg .= '... ' . $shortlink; + } + if(! strlen($msg)) + return; + + logger('Facebook post: msg=' . $msg, LOGGER_DATA); + + if($likes) { + $postvars = array('access_token' => $fb_token); + } + else { + $postvars = array( + 'access_token' => $fb_token, + 'message' => $msg + ); + if(isset($image)) + $postvars['picture'] = $image; + if(isset($link)) + $postvars['link'] = $link; + if(isset($linkname)) + $postvars['name'] = $linkname; + } + + if(($b['private']) && (! $b['parent'])) { + $postvars['privacy'] = '{"value": "CUSTOM", "friends": "SOME_FRIENDS"'; + if(count($allow_arr)) + $postvars['privacy'] .= ',"allow": "' . implode(',',$allow_arr) . '"'; + if(count($deny_arr)) + $postvars['privacy'] .= ',"deny": "' . implode(',',$deny_arr) . '"'; + $postvars['privacy'] .= '}'; + + } + + if($reply) { + $url = 'https://graph.facebook.com/' . $reply . '/' . (($likes) ? 'likes' : 'comments'); + } + else { + $url = 'https://graph.facebook.com/me/feed'; + if($b['plink']) + $postvars['actions'] = '{"name": "' . t('View on Friendika') . '", "link": "' . $b['plink'] . '"}'; + } + + logger('facebook: post to ' . $url); + logger('facebook: postvars: ' . print_r($postvars,true)); + + // "test_mode" prevents anything from actually being posted. + // Otherwise, let's do it. + + if(! get_config('facebook','test_mode')) { + $x = post_url($url, $postvars); + + $retj = json_decode($x); + if($retj->id) { + q("UPDATE `item` SET `extid` = '%s' WHERE `id` = %d LIMIT 1", + dbesc('fb::' . $retj->id), + intval($b['id']) + ); + } + else { + if(! $likes) { + $s = serialize(array('url' => $url, 'item' => $b['id'], 'post' => $postvars)); + q("INSERT INTO `queue` ( `network`, `cid`, `created`, `last`, `content`) + VALUES ( '%s', %d, '%s', '%s', '%s') ", + dbesc(NETWORK_FACEBOOK), + intval($a->contact), + dbesc(datetime_convert()), + dbesc(datetime_convert()), + dbesc($s) + ); + + notice( t('Facebook post failed. Queued for retry.') . EOL); + } + } + + logger('Facebook post returns: ' . $x, LOGGER_DEBUG); + } + } + } + } +} + + +function fb_queue_hook(&$a,&$b) { + + $qi = q("SELECT * FROM `queue` WHERE `network` = '%s'", + dbesc(NETWORK_FACEBOOK) + ); + if(! count($qi)) + return; + + require_once('include/queue_fn.php'); + + foreach($qi as $x) { + if($x['network'] !== NETWORK_FACEBOOK) + continue; + + logger('facebook_queue: run'); + + $r = q("SELECT `user`.* FROM `user` LEFT JOIN `contact` on `contact`.`uid` = `user`.`uid` + WHERE `contact`.`self` = 1 AND `contact`.`id` = %d LIMIT 1", + intval($x['cid']) + ); + if(! count($r)) + continue; + + $user = $r[0]; + + $appid = get_config('facebook', 'appid' ); + $secret = get_config('facebook', 'appsecret' ); + + if($appid && $secret) { + $fb_post = intval(get_pconfig($user['uid'],'facebook','post')); + $fb_token = get_pconfig($user['uid'],'facebook','access_token'); + + if($fb_post && $fb_token) { + logger('facebook_queue: able to post'); + require_once('library/facebook.php'); + + $z = unserialize($x['content']); + $item = $z['item']; + $j = post_url($z['url'],$z['post']); + + $retj = json_decode($j); + if($retj->id) { + q("UPDATE `item` SET `extid` = '%s' WHERE `id` = %d LIMIT 1", + dbesc('fb::' . $retj->id), + intval($item) + ); + logger('facebook_queue: success: ' . $j); + remove_queue_item($x['id']); + } + else { + logger('facebook_queue: failed: ' . $j); + update_queue_time($x['id']); + } + } + } + } +} + +function fb_consume_all($uid) { + + require_once('include/items.php'); + + $access_token = get_pconfig($uid,'facebook','access_token'); + if(! $access_token) + return; + + if(! get_pconfig($uid,'facebook','no_wall')) { + $private_wall = intval(get_pconfig($uid,'facebook','private_wall')); + $s = fetch_url('https://graph.facebook.com/me/feed?access_token=' . $access_token); + if($s) { + $j = json_decode($s); + logger('fb_consume_stream: wall: ' . print_r($j,true), LOGGER_DATA); + fb_consume_stream($uid,$j,($private_wall) ? false : true); + } + } + $s = fetch_url('https://graph.facebook.com/me/home?access_token=' . $access_token); + if($s) { + $j = json_decode($s); + logger('fb_consume_stream: feed: ' . print_r($j,true), LOGGER_DATA); + fb_consume_stream($uid,$j,false); + } + +} + +function fb_consume_stream($uid,$j,$wall = false) { + + $a = get_app(); + + + $user = q("SELECT `nickname`, `blockwall` FROM `user` WHERE `uid` = %d AND `account_expired` = 0 LIMIT 1", + intval($uid) + ); + if(! count($user)) + return; + + $my_local_url = $a->get_baseurl() . '/profile/' . $user[0]['nickname']; + + $no_linking = get_pconfig($uid,'facebook','no_linking'); + if($no_linking) + return; + + $self = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1", + intval($uid) + ); + + + $self_id = get_pconfig($uid,'facebook','self_id'); + if(! count($j->data) || (! strlen($self_id))) + return; + + foreach($j->data as $entry) { + logger('fb_consume: entry: ' . print_r($entry,true), LOGGER_DATA); + $datarray = array(); + + $r = q("SELECT * FROM `item` WHERE ( `uri` = '%s' OR `extid` = '%s') AND `uid` = %d LIMIT 1", + dbesc('fb::' . $entry->id), + dbesc('fb::' . $entry->id), + intval($uid) + ); + if(count($r)) { + $post_exists = true; + $orig_post = $r[0]; + $top_item = $r[0]['id']; + } + else { + $post_exists = false; + $orig_post = null; + } + + if(! $orig_post) { + $datarray['gravity'] = 0; + $datarray['uid'] = $uid; + $datarray['wall'] = (($wall) ? 1 : 0); + $datarray['uri'] = $datarray['parent-uri'] = 'fb::' . $entry->id; + $from = $entry->from; + if($from->id == $self_id) + $datarray['contact-id'] = $self[0]['id']; + else { + $r = q("SELECT * FROM `contact` WHERE `notify` = '%s' AND `uid` = %d AND `blocked` = 0 AND `readonly` = 0 LIMIT 1", + dbesc($from->id), + intval($uid) + ); + if(count($r)) + $datarray['contact-id'] = $r[0]['id']; + } + + // don't store post if we don't have a contact + + if(! x($datarray,'contact-id')) { + logger('no contact: post ignored'); + continue; + } + + $datarray['verb'] = ACTIVITY_POST; + if($wall) { + $datarray['owner-name'] = $self[0]['name']; + $datarray['owner-link'] = $self[0]['url']; + $datarray['owner-avatar'] = $self[0]['thumb']; + } + if(isset($entry->application) && isset($entry->application->name) && strlen($entry->application->name)) + $datarray['app'] = strip_tags($entry->application->name); + else + $datarray['app'] = 'facebook'; + $datarray['author-name'] = $from->name; + $datarray['author-link'] = 'http://facebook.com/profile.php?id=' . $from->id; + $datarray['author-avatar'] = 'https://graph.facebook.com/' . $from->id . '/picture'; + $datarray['plink'] = $datarray['author-link'] . '&v=wall&story_fbid=' . substr($entry->id,strpos($entry->id,'_') + 1); + + $datarray['body'] = $entry->message; + if($entry->picture) + $datarray['body'] .= "\n\n" . '[img]' . $entry->picture . '[/img]'; + if($entry->link) + $datarray['body'] .= "\n" . linkify($entry->link); + if($entry->name) + $datarray['body'] .= "\n" . $entry->name; + if($entry->caption) + $datarray['body'] .= "\n" . $entry->caption; + if($entry->description) + $datarray['body'] .= "\n" . $entry->description; + $datarray['created'] = datetime_convert('UTC','UTC',$entry->created_time); + $datarray['edited'] = datetime_convert('UTC','UTC',$entry->updated_time); + + // If the entry has a privacy policy, we cannot assume who can or cannot see it, + // as the identities are from a foreign system. Mark it as private to the owner. + + if($entry->privacy && $entry->privacy->value !== 'EVERYONE') { + $datarray['private'] = 1; + $datarray['allow_cid'] = '<' . $uid . '>'; + } + + $top_item = item_store($datarray); + $r = q("SELECT * FROM `item` WHERE `id` = %d AND `uid` = %d LIMIT 1", + intval($top_item), + intval($uid) + ); + if(count($r)) { + $orig_post = $r[0]; + logger('fb: new top level item posted'); + } + } + + if(isset($entry->likes) && isset($entry->likes->data)) + $likers = $entry->likes->data; + else + $likers = null; + + if(isset($entry->comments) && isset($entry->comments->data)) + $comments = $entry->comments->data; + else + $comments = null; + + if(is_array($likers)) { + foreach($likers as $likes) { + + if(! $orig_post) + continue; + + // If we posted the like locally, it will be found with our url, not the FB url. + + $second_url = (($likes->id == $self_id) ? $self[0]['url'] : 'http://facebook.com/profile.php?id=' . $likes->id); + + $r = q("SELECT * FROM `item` WHERE `parent-uri` = '%s' AND `uid` = %d AND `verb` = '%s' + AND ( `author-link` = '%s' OR `author-link` = '%s' ) LIMIT 1", + dbesc($orig_post['uri']), + intval($uid), + dbesc(ACTIVITY_LIKE), + dbesc('http://facebook.com/profile.php?id=' . $likes->id), + dbesc($second_url) + ); + + if(count($r)) + continue; + + $likedata = array(); + $likedata['parent'] = $top_item; + $likedata['verb'] = ACTIVITY_LIKE; + $likedata['gravity'] = 3; + $likedata['uid'] = $uid; + $likedata['wall'] = (($wall) ? 1 : 0); + $likedata['uri'] = item_new_uri($a->get_baseurl(), $uid); + $likedata['parent-uri'] = $orig_post['uri']; + if($likes->id == $self_id) + $likedata['contact-id'] = $self[0]['id']; + else { + $r = q("SELECT * FROM `contact` WHERE `notify` = '%s' AND `uid` = %d AND `blocked` = 0 AND `readonly` = 0 LIMIT 1", + dbesc($likes->id), + intval($uid) + ); + if(count($r)) + $likedata['contact-id'] = $r[0]['id']; + } + if(! x($likedata,'contact-id')) + $likedata['contact-id'] = $orig_post['contact-id']; + + $likedata['app'] = 'facebook'; + $likedata['verb'] = ACTIVITY_LIKE; + $likedata['author-name'] = $likes->name; + $likedata['author-link'] = 'http://facebook.com/profile.php?id=' . $likes->id; + $likedata['author-avatar'] = 'https://graph.facebook.com/' . $likes->id . '/picture'; + + $author = '[url=' . $likedata['author-link'] . ']' . $likedata['author-name'] . '[/url]'; + $objauthor = '[url=' . $orig_post['author-link'] . ']' . $orig_post['author-name'] . '[/url]'; + $post_type = t('status'); + $plink = '[url=' . $orig_post['plink'] . ']' . $post_type . '[/url]'; + $likedata['object-type'] = ACTIVITY_OBJ_NOTE; + + $likedata['body'] = sprintf( t('%1$s likes %2$s\'s %3$s'), $author, $objauthor, $plink); + $likedata['object'] = '' . ACTIVITY_OBJ_NOTE . '1' . + '' . $orig_post['uri'] . '' . xmlify('') . '' . $orig_post['title'] . '' . $orig_post['body'] . ''; + + $item = item_store($likedata); + } + } + if(is_array($comments)) { + foreach($comments as $cmnt) { + + if(! $orig_post) + continue; + + $r = q("SELECT * FROM `item` WHERE `uid` = %d AND ( `uri` = '%s' OR `extid` = '%s' ) LIMIT 1", + intval($uid), + dbesc('fb::' . $cmnt->id), + dbesc('fb::' . $cmnt->id) + ); + if(count($r)) + continue; + + $cmntdata = array(); + $cmntdata['parent'] = $top_item; + $cmntdata['verb'] = ACTIVITY_POST; + $cmntdata['gravity'] = 6; + $cmntdata['uid'] = $uid; + $cmntdata['wall'] = (($wall) ? 1 : 0); + $cmntdata['uri'] = 'fb::' . $cmnt->id; + $cmntdata['parent-uri'] = $orig_post['uri']; + if($cmnt->from->id == $self_id) { + $cmntdata['contact-id'] = $self[0]['id']; + } + else { + $r = q("SELECT * FROM `contact` WHERE `notify` = '%s' AND `uid` = %d LIMIT 1", + dbesc($cmnt->from->id), + intval($uid) + ); + if(count($r)) { + $cmntdata['contact-id'] = $r[0]['id']; + if($r[0]['blocked'] || $r[0]['readonly']) + continue; + } + } + if(! x($cmntdata,'contact-id')) + $cmntdata['contact-id'] = $orig_post['contact-id']; + + $cmntdata['app'] = 'facebook'; + $cmntdata['created'] = datetime_convert('UTC','UTC',$cmnt->created_time); + $cmntdata['edited'] = datetime_convert('UTC','UTC',$cmnt->created_time); + $cmntdata['verb'] = ACTIVITY_POST; + $cmntdata['author-name'] = $cmnt->from->name; + $cmntdata['author-link'] = 'http://facebook.com/profile.php?id=' . $cmnt->from->id; + $cmntdata['author-avatar'] = 'https://graph.facebook.com/' . $cmnt->from->id . '/picture'; + $cmntdata['body'] = $cmnt->message; + $item = item_store($cmntdata); + } + } + } +} + diff --git a/fortunate.tgz b/fortunate.tgz new file mode 100644 index 0000000000000000000000000000000000000000..5c9ce167fd291b3f51ab790aa8b48a6da19ec693 GIT binary patch literal 663 zcmV;I0%-joiwFSg>wZoE1MQVfPuoBchJB5H#mJ3tK;SRpI0|tPQq>zh_EM^7W3OWi zd)M7vBcSSk?`{I7r9{01ICP$qGa1jkyYK9};6inbDC%3UMxaTO*oxwD5=CPxh$qox z9B$$dSYbE`lSz0Qo(5JBMoAJ{5Wk+JCpxK!0I(X8tt)X;u^oBsI-Z2n>GUl$y&*;K zfB)oVQtq{fF?cc=@AN;6lV|?NaTr?=>{Z1M{&WAm-gfw54;muY6+2P9ok0}0w`YB* zriGe87zDouS6nIH^r;!IxtPHR6k;+U|t*SVi!9|_}0YO;K8`#bZ zg^cs-iULufN($R60eAuQhKf6A$(l;fRQf`N+*Ap@!2G`GRB5h@%j%lK<>T(dyi}^4 z`F`(*m+{7L1uv?a`i)Lr=(l~_wu_EsMi=yxyR4XYv#v*n<}wp>T}eg7veXJku2Hh2 zEO(E=C3()7zhm}I!c)nDs;qPm_1*Pi$BzBcvt#@3`cm7?|Dz!}J{Yb{V|y?pCkxZ; zt6Qq3E-A^~Z{Vfi&g+U@gP?WlNOf0JSyHMTP(>=rlj1-_^NOU7-Vg`;g$X)W;)*$EMxuliHp-W#sQcjb!yq+0 z-&nn!C$lBztZTG*D%0qIe(y+~h6iT&Qd723OY=NB)SEOIuC`0fs~gB_B4z6I;+%~N x-COIM`#NLcZnpKkPac9G2!bF8f*=TjAP9mW2!bF8f*{C#`2}&i5~Khq008DgO}GF6 literal 0 HcmV?d00001 diff --git a/fortunate/fortunate.css b/fortunate/fortunate.css new file mode 100644 index 00000000..61813b7d --- /dev/null +++ b/fortunate/fortunate.css @@ -0,0 +1,7 @@ +.fortunate { + margin-top: 25px; + margin-left: 100px; + margin-bottom: 25px; + color: #000088; + font-size: 14px; +} \ No newline at end of file diff --git a/fortunate/fortunate.php b/fortunate/fortunate.php new file mode 100644 index 00000000..5a6302e5 --- /dev/null +++ b/fortunate/fortunate.php @@ -0,0 +1,27 @@ + + */ + + +function fortunate_install() { + register_hook('page_end', 'addon/fortunate/fortunate.php', 'fortunate_fetch'); +} + +function fortunate_uninstall() { + unregister_hook('page_end', 'addon/fortunate/fortunate.php', 'fortunate_fetch'); +} + + +function fortunate_fetch($a,&$b) { + + $a->page['htmlhead'] .= '' . "\r\n"; + + $s = fetch_url('http://fortunemod.com/cookie.php?numlines=2&equal=1&rand=' . mt_rand()); + $b .= '
' . $s . '
'; +} + diff --git a/impressum.tgz b/impressum.tgz new file mode 100644 index 0000000000000000000000000000000000000000..901114e578e4386d554f97444657a56fdd92d26c GIT binary patch literal 1797 zcmV+g2m1IQiwFSg>wZoE1MOJrZyGre=QDrB975eCqL2rWDkZeJORB5XHqkY@FI9!i zt^q5{dT;Gb8ddqtU&kaL@Fo~lB58Y83`sVy=3tUzGTwv z?Yw&R>N#Y3Mq;`B^RHGiO@8Pe%D}x|XO;bXd;1+_|DFBb&K~|l`**wDUIn&)s1z&c ze{TQ&8?<({y|q<^E%-!c^Z?#FM^Hn@R0JtYB;)Y`oJHA$#UMG5Fob}|k^~Z1Jm%?) zC>Av(rxeJDXA%-Jq2Ra2DWh@7E=WTG{!LS%!FF2P>i1D5r#wA?b3S53z%ip2$T8*P zG4!WWCgPyo4vWFol+S1uvu~}K$^yEbqSpbVz4} zMc~(kld&$~5QI#JDNQ00P~Us&H9eomhSx-{*DIJ>iYerCTq%`V8YA=E-t&j>>!kUj zKFW6=LF*8_{&a8PwWROm9_}?-Ucaq|tpxlkrYTA>p>l}+J!TWX(2r7_h8& ztCyKomMveLaHZFEn;DLLLChr;>-aT8&TfowxM&uCrIdQwYk&n{WAM=$5siIw(1z3J z(pjg5IW8@ToF$;tPhgtT@nOwt&97*AwSgN`_8`t2if({Lcy*UTnk6OPrPAqR-ImJw zL^9|jBabJ>H9j**;nWye$ztaYz-yUZad4DEdw$i4R`pRBDqY@MXe3aB$=xS=yjTn9 zOLbv9>b}Z2GakC^Tt*3Mck9OY6hOP^n*C8*nq>vtEuEEDqQvKze2OTgLm$MHhC*eg z5e4J+SxUp-%n8mSN)S-xGa^C#kUE3)r5tGQ>bLO=E=kJB2=6$;T=OioK%m_h-tiPT zu1a%0fe}&zqr>B{O^bh>936i=(TjkOO{P>Lwv1}?^WLn8{U+)TNjSs5O7GymsFOU( zx!~pd-~9UU?DX?_5wIHY22inNB7B*$nVtV)r@!Jn`qF${E5h1sz&w_%#dTbZ@Ok8$ z19s6)LC%BOnMD{E59d&947?3uCKfSVketJ?fpFE?%=7}1SQq*+eVGV)4_>FV=A0Go zSZOuXbQgR*w>d!5M#lBLMr}=dacyS6iq8iXmZ+30o(Ra25ED$O92rhdKR{zeaxQzY zcHSnusPo)|C0atAc4$+Sq_Gq}ge;A*H1&r=JvqcpYHf|tl1Ws9+--5WtsRC~&!=4Y zb=d@xrsUesLxxuu*=WY32ZsZF2=lAaEO8jCDF(CHnGqIZadUmjR}9_~WM|{W4RYJh z?<3&M-M2e7ObWh*eXWO-c62@iOCtU1ZQL!rwSjSz62A2u1^>xh%GIc`V^{z+o>~I6 zt_!!5?rLy*olD>i?Vta3@AWfK(HEHH^b~vC(f{vuI(v)nKfV3kP5=KKl(#~zxyN1} z-nq8AT3y|q=eN|f+^tfR{&q6c{du*zwg<03Uj4-XKELEn;L|afNF9&AuODQaV&1=6> z9WIs5@xOvnk3p_VJ+<1p4`5#Ol>t$Dt{;(5Ke@4i1Od-tIoAr@hpw>HrtYEX5~b8O zR3!qMK8n!4V&xlmNNdZu5-!P&Z^}YqatruQ_Qu0SRq|lt5i)^w$u$i@L~JsZ(RI<6 zhYv=@E29e{A{+D@nPIP?Ur7Q!yW`BRk}ja|!e)_u%u_ebd9gdY*7bu0bS^tm9S{ko zRJT|2dR!x>t<}pX4nt=Br+l%|2@uzu;lV=AnZ;h9g$PrH>aSfU6!|}|r+@e!cjW)= z?*8_|`+ujmyUG90Lf^lm=LaTd4OyIIQn`T1pmjZZXx|lXZje_6Ze+i?sor~`dq#M~ zdK-!!vC<^vM=Ugfe_>%iWS4;Tix7u3(>vA%eGLHeI-&WX4$6l$RbUJSc5gLI&{2jX nb;r;i^xFtF__c$|hBmaJ4Q*&c8`{u@ep>n$vaqYb04M+eImU*z literal 0 HcmV?d00001 diff --git a/impressum/README b/impressum/README new file mode 100644 index 00000000..8e4255bd --- /dev/null +++ b/impressum/README @@ -0,0 +1,27 @@ +Impressum Plugin for Friendika + +Author: Tobias Diekershoff + tobias.diekershoff@gmx.net + +License: 3-clause BSD license (same as Friendika) + +About + This plugin adds an Impressum block to the /friendika page with informations + about the page operator/owner and how to contact you in case of any questions. + + In the notes and postal fields you can use HTML tags for formatting. + +Configuration: + For configuration you can set the following variables in the .htconfig file + * $a->config['impressum']['owner'] this is the Name of the Operator + * $a->config['impressum']['ownerprofile'] this is an optional Friendika account + where the above owner name will link to + * $a->config['impressum']['email'] a contact email address (optional) + will be displayed slightly obfuscated + as name(at)example(dot)com + * $a->config['impressum']['postal'] should contain a postal address where + you can be reached at (optional) + * $a->config['impressum']['notes'] additional informations that should + be displayed in the Impressum block + + diff --git a/impressum/admin.tpl b/impressum/admin.tpl new file mode 100644 index 00000000..cfba8df7 --- /dev/null +++ b/impressum/admin.tpl @@ -0,0 +1,6 @@ +{{ inc field_input.tpl with $field=$owner }}{{ endinc }} +{{ inc field_input.tpl with $field=$ownerprofile }}{{ endinc }} +{{ inc field_input.tpl with $field=$postal }}{{ endinc }} +{{ inc field_input.tpl with $field=$notes }}{{ endinc }} +{{ inc field_input.tpl with $field=$email }}{{ endinc }} +
diff --git a/impressum/impressum.php b/impressum/impressum.php new file mode 100644 index 00000000..b760c7e0 --- /dev/null +++ b/impressum/impressum.php @@ -0,0 +1,76 @@ + + * License: 3-clause BSD license + */ + +function impressum_install() { + register_hook('about_hook', 'addon/impressum/impressum.php', 'impressum_show'); + logger("installed impressum plugin"); +} + +function impressum_uninstall() { + unregister_hook('about_hook', 'addon/impressum/impressum.php', 'impressum_show'); + logger("uninstalled impressum plugin"); +} +function obfuscate_email ($s) { + $s = str_replace('@','(at)',$s); + $s = str_replace('.','(dot)',$s); + return $s; +} +function impressum_show($a,&$b) { + $b .= '

'.t('Impressum').'

'; + $owner = get_config('impressum', 'owner'); + $owner_profile = get_config('impressum','ownerprofile'); + $postal = get_config('impressum', 'postal'); + $notes = get_config('impressum', 'notes'); + $email = obfuscate_email( get_config('impressum','email') ); + if (strlen($owner)) { + if (strlen($owner_profile)) { + $tmp = ''.$owner.''; + } else { + $tmp = $owner; + } + if (strlen($email)) { + $b .= '

'.t('Site Owner').': '. $tmp .'
'.t('Email Address').': '.$email.'

'; + } else { + $b .= '

'.t('Site Owner').': '. $tmp .'

'; + } + if (strlen($postal)) { + $b .= '

'.t('Postal Address').'
'. $postal .'

'; + } + if (strlen($notes)) { + $b .= '

'.$notes.'

'; + } + } else { + $b .= '

'.t('The impressum addon needs to be configured!
Please add at least the owner variable to your config file. For other variables please refer to the README file of the addon.').'

'; + } +} + +function impressum_plugin_admin_post (&$a) { + $owner = ((x($_POST, 'owner')) ? notags(trim($_POST['owner'])) : ''); + $ownerprofile = ((x($_POST, 'ownerprofile')) ? notags(trim($_POST['ownerprofile'])) : ''); + $postal = ((x($_POST, 'postal')) ? (trim($_POST['postal'])) : ''); + $notes = ((x($_POST, 'notes')) ? (trim($_POST['notes'])) : ''); + $email = ((x($_POST, 'email')) ? notags(trim($_POST['email'])) : ''); + set_config('impressum','owner',$owner); + set_config('impressum','ownerprofile',$ownerprofile); + set_config('impressum','postal',$postal); + set_config('impressum','email',$email); + set_config('impressum','notes',$notes); + info( t('Settings updated.'). EOL ); +} +function impressum_plugin_admin (&$a, &$o) { + $t = file_get_contents( dirname(__file__). "/admin.tpl" ); + $o = replace_macros($t, array( + '$submit' => t('Submit'), + '$owner' => array('owner', t('Site Owner'), get_config('impressum','owner'), ''), + '$ownerprofile' => array('ownerprofile', t('Site Owners Profile'), get_config('impressum','ownerprofile'), ''), + '$postal' => array('postal', t('Postal Address'), get_config('impressum','postal'), ''), + '$notes' => array('notes', t('Notes'), get_config('impressum','notes'), ''), + '$email' => array('email', t('Email Address'), get_config('impressum','email'), ''), + )); +} diff --git a/js_upload.tgz b/js_upload.tgz new file mode 100644 index 0000000000000000000000000000000000000000..bfbbab6ea59abd9c0478cf9fd4de1dc9b182b877 GIT binary patch literal 113799 zcmV(oK=HpHiwFSg>wZoE1MEC|bKAC)`B(ZBFwbL>2}Mb^Y`2o-T$4CyI&PB2Zl`xX zkA4sdNt7vqAxJ-J`@7#RKvLAxk0#DcD`aAkz+$n$J^=z4icS*xoVwL#-z?Q2?e1pQdN^`p#y3cdOQDY(J~jH+LI5&&c+-BWaux5z~l}XCvzL zz3AKv7Qlu5?Vb7$Km70%G(BM&=KRl}>~Ii%)i#j9J3Ea9{D+*z))fD@8;!;@Qv0e@ zEJ*)y{_nj6ZkNl|=g-UJIr%_GtVw=3BEL&XU=e1%VZw>LF!p!=W%QgL$yX8%c+9Kb zi1rytQh1yEE|?&HP(K+F{mU0U$7Ca_KUgFrnz~)X_n(q@z@sL4J%~I(UQ@xy-XM;{ zX0_UjJQld#8MS%Hf{_=vBBTzpdDO3l5$}0Et2$V%<3P22z*fz=ftU+)ev)*)mvk2T zg-{ELC0P0^cN3q@AyUz2k z9*;)4MRe-AJg6>ELDPU@3`i2ueTPFrR*jVk@I!w z8j1-jhG6SdQ`-JsRXrh9z%QUI9qN(j!#Ku44<*h=C-Yq(G;3Mwm%%Zl<9zO+q^Z=9~fW9Mp(CB|gKMku(RiTFrn?WUbS5 zU_N$-kUOu&Ec^sz=ivF-eOpRv&4AyQ7r#X;PNEzXw0(MBlS`R`GGEe z`C`8XiOyjFq6A1sU>cgle3;j2Wm05C&jUNgbaG(bm3v$x(vsBQMCz_{|5epp~gm=qp$$h~Z5fVRdQJadaM1QG{L)Ab%cH*Zb?PM(J!VBG7# zJx2wND&SCW3upoE;CNcuJNTNC%eqOwN#ZDBDCaylO1dKtbR<(Y!*eYh)&OQYQqf8! zv~Ot2d5=)XUu$a#sC>^0n5&r*AXi2(eDNn5(UCAz)lvzRllt9cR4O$~3-wS&QX=bO zRz)|J0kRaP6wUqd$O;u@Tc&XJBc6mE2zmJhB7|<)@}<-FTzkm9z|bva2_QK4zxn;vfwJijL%CEOW*?R1X>AtixC9;5C&l$`DYAz(ZMf7UZ|s+=AEp$7tV=F z^RP~`@BwsUm1Sh6jD8T6GdL#%qAdTzTS4#TWCH9kSlla~M1+Q6>O#j+7ZpTsaINqg z4;Xp#@mB(KcK~v)uqs5OdQ2{;7fU0KAQ#~1`2~iLG6*DPm0|NhzPG2mbSpJE5dZ}C%T6`SM?p4eL;>3(Y59}u3 z!ubmDs^|3$U0lKR5T?gERF&&K2nbO=c*Py^oYZTZjr2zb{xdPmLevYfMKcIn|p}}Zabq4qrf-4~|jVbUG#I-+w$Q8^6Ln#6F`aVzr!8Aa!z~L?< zKmZxUBcH^yFK{R;`&j)%PdPRe9OlF#1k#wCg-U16aUeE9Z*s%=eL}yXNBmLA=KFH_&J`9OI;%-&h8=Ouz)e@VKqGOm% zA}ggr?gf2S3~>ccEvFC@n2H~MeE06)bLY*$tKZ+rIa-N115W1AjD=?~L?ebn3OYAu zI25QHh_qU3sjQ=HO-=5{{9J@Qn=!(iSwAh6+T)IeG#+5NEY4gwz!X5nxdkvOqX?G0 z7&(4Zbzor+Sl~`{AY;><1rB8KrIB^Znkzynvn3Pm5Vl!>SvI>%NADdQh#(OtgEER+s><#{*AP_H+7?Ea1NZcB+GR3*S3HreRuo zFA9_ntV`lE{1YfF?P3BwSbYBojU!A?V|W>XB@C}RG4H5XLlFyh3vrsQ@id|5_*}5G zTsE8Kq>#BY%N{Ta9XGhv&N_$A6ou9_uZzL&ylG~-NS5V}r=n>&M#ZWa^}Dzd@d>)G z=AES!c4AzV1Wxb{D&fZhqd2M0s&?KT9G~c4zQ_fp)4av$`l?%n`Zxrsnd}@LeE#F$ z^NIHQL>q3kKzfhpc zt#{tOKRh^6zTH%xALeQITdaF6LlbOyp(cYH#AoTvdLH;iWc5SUxjbK?|CZpXevakm zM2|s>bF=;+L7YLAp&9GPQi)uQNO_eE(e0QQ#TX~WlpET`v05rOIb<;ctJfMoZ13*W zra+LA*3@8hFjNEElsK^=5if1in%~aY(2OnNLM)vT4Gj&Nj5$I?V54V&r`9Z|?e{$7 zvq)Ntsu%k(?$81go7tBM6E(9mnPQfTk_E3*F4UM%bu=VJ^i%Tk;092OXIof`L|OlW zbt@O7eEcVqpIl~Q{tDxMV;z`SFs|z`8$p*Ec_UR+@QWbovGR#2*CoUW{P)qNB6OvG zTBso|yx18Svf}hm;OASS_w}Y~@_9R*K+M97?g4W)4KpJJGj0*VThn7zu$!MHm`Jro zPi>&y-bb@$;^&04M1|h%ef2;_00na-n9(XkQ_;`lJmz}7xULm=Jm2$8v`yOk`1$1n zPru(>;HQjq>V)2@C{eQwO64K#qFfc?k3}(ys?;X6X~r%gFcbAOs1yW(qWEeNeK5V7 zX>fl=`(=ba27M?6F^8EyjgVhJ#TZY44h$ZPGv9m8j9J-J_8q;i7ZndcQ+58G+B&#+# z>l(wd%XktjU)Pv`gMnG-1z?2Myr827plECW6*{j4^`=8afMWt_#?O5?>BY~~ORBf- zE5&H2L5;yO1TZn0TD`FdutN-Z;=82Fr znNH21k@jg$t0>GO3M}WR1kHIa$wlg+iwJm^cbY?0W*`fnp)X+g)RzLExfU8z!J=~r zosk(TpcEudG@Wsk}uh2p{d-`w1-?XLL$6zLKC zA29hLrcrC$bEo+7{oh!)J;nd+`u5Ih|MycQx&NCemKxg6$H$+lb-PA@x#Rc8N@ol(Hu{(p1I|L^R8Nm%Ls6Qq0VKQMZw z`TxB12>r*sxfR?ARgvrEcTWQD(*Mo+jQ%&a>MQ+!ilp?vT$*nIn|=|F=)e{J+$G$!O*I%b0;@?{LE`9;y4@#IMrdPLI%k!AC5l_i_Abx>Nt_ThscF zA;C)jpCG;0M}!i|&hJgiDt(9aSpR>og}*f2J^!yy$N$@n?UnvNMY_}fuNMCP(dqBZ z|L+?B+@b%Q_4-WwzqQi;r%4Z)|7WxRd`p+kE-7B2A-7m*8+6a%qcDkCL;@CH@aRnJ zTX@jG2W;{A&Ac%>JznxlJp{uVM)YBJZ5R8+#Cj=c!bi! z9n2ze1^}c`M1Z)57dIU!k_7Iyo5G;bUJN`{FDJ_D4`SS-7qSRXUN9HhaQp;M2$Bod zRU6VQ^7i->$)4GWdVcg1QXJ%UB;3h9i{`+-40G(s4+~$R;=z zAf2v&p@~EcJs(L@I0<vo|K~|kdjDf0e8xhs4K=lr zUzQuD@dQ9iJ>nS<$X;@UO6~s6>*41Ac?Ut|Y5mJV1h!rsQ!cHm*h3yE3#l_;owTTv z78vS&v6Kn`Q>Q)C(vv)9Ih3a|v7vh$$eJY=Z)L+R;JLUIMijiF3}gbRuCAI`fPbI-nBF4s z&{n!0p3hf}{CM_i0>3;*prjUgWQexYg}bfD&5P6XFZtlR84PD zf6c?ING_sn*6KBj{K5wT`OJjZm)FN9)F-~@umIOe@NPx5M)T|YV_dFz_vtXZ7M^To zaKfH#5HEgDi_>=Bt5rHdAZ+~0XCRz~T0-UxMMmfhmADG@h7Y+q;~QNC+qIg!vc<^nq5R3Z zFt78=07ld>uf3kJ=GdP2jMvne*Ku@pE$r+9z4Y=tcn1b?-#0X$^QLApY)Ct^M$Cmfr8RqS6-rjH2pjOws?%E=9UOF}%(o5qyiTtL_v8cET zoTgkDvM>%k#^qowz2W%QY&v$|=UwU_oKxTE+Bh@0xlzCAYz$xJC8R$e|9W_HqiJTV zYeT3AMIRvi+}J3-*|_j`&R!2Z-!;1Cn9e_uOv|-;7PE%twY<%^O|v_KVZhRhJGeZ@LGBK&aJG#G@C9EJ8mR>@LrY?q=q2Pi*X-+0oE%J z11|zWSu*juL}aE>7>obO;nZCpd2Po=VKMMrwxvnz0{D({ zZ2;4}bN1GYmwGshs3H_N>VU$ZX)s?a*2cOmdB=8J)wKoM z1*4{Tbq2gT+e95%Kyc%OG%}PodIB3nUYoQfJ( z%_Fm!*dmnp&ngwrs@q}PfzHIZ^))tad8?O*jh;nqCy7v?k5y4C078(Us9hdr)C7A` zD*%e_BD7}=PlD5&3LvmR(lu|(QoI1V)oaW9#qowgJB-+II&veP2*&W_ymoUlTLL!j zoM~oH_9bF?Ke2l})ulp7O^sH2sCq-C0Kr?1QD#7Xo>456166=U_NvRZqEwz0UW*}*)jIceS3R`4U>47A zGwtjatYes3M^&Ur8Pi@E6hsqxuRYgZ(ifVoH9>St#g z1)cgLbxNULqo4q^U~wq14rxSdr%g|1 z(#dn0&PYlZ6iHW-E4q{%J2Cm+_dWm+l&EB9A73OA#Pj05?*-{na!w?iOJI&U^NbBJ z6oBhCJIXZl<4ix14|Qz#?~>k%9hln%-AbraZ(_VEJS*GygO^pi=EXZezI_ zO&Uc)oX7-33E<}#f5PGpB+hqQWP%8SvS@>|H!=euIT)DNJ;P%p35>a{uRH_}^uZO+ zzdd^bJ;US8V9?(J#Uo8%g$moz3bn))d0Ae?9sc=5KRH3d8w|5 zZBDSlEWlzws579$Wli*jawrM;RkLOp&vh$5i043@nOYMVa^%#|C=2#FmdkM-ooPP* zU>-)fn4^0YznBnZ4!Zx<#U|LkIiu4@pwVIt>V+mH;QUaec`b@L;UHW(!F`-bRa?QA zHY40QIFDKc=r8XI53m7A%BnbH6)6|x|2&3g{4J257uj7y8}I4WysVzoIPJN#Q*j8F z-m3+`S%>u6U3^lDH%eZFtnP}pczrB3@N4EE-idcgjy_C2oX;Nn=acE(^!;r3G?;vN zI(vLvefX0PMJKaia6A%!$BNm~I|VN8_jdI69w>re{xsF?97xuGPoIl>!DFV(jta3g>sPn0<-Y zD2iW*W67UC02W_t3qIY|>07^MXzIuWVaeb9c9eNp1c{gy;N(yEH7 zSd+5BaB7dFppcl8BK-uU+)sA;*uERW&p?<4 zz#V#iIysvGI{+F%1ru(FuE)t9f6~lJ{?fFEdsIPRVcs?G9%#g%0m;cmGX`x60GEM| zX9V|9ZMUV?Mu9ibo5^bO;X=E-yB$7;Zh@;#aEdcA$!9^VKv0C1PXGlP_JMlAIzzGK zQ}lY#Q6SRofmL2Q<}D*<_Mm5QNwW9n7+<^%qnpK=k4B!yaPL};OAwLmWRcB|&A76Y=%11P>IP8S=!=wO^E zE$2X$M+29)5^v%h_2-XFjBI}7E!JdiV#04Jdme5ksMpO_v^Hkww{FMY5$lqv-TdTm zTTncQ$)lWPcpkL3wi4-mS>J6GJrw+e%PE&LM=#{_qh?@FkL8sB(h+P`8IF zS=8{~=q+c!7^5~29<}#`M$qO7f2P0_V3XG3cXiXX*qt$uwr(^_u(b&h4RCl6baTMY zV8_`yJveuZh*dTBkt_nn^(awd0}5$00kaYQ1zW9jOILMlRUt=4V;L%Z_}aRZ?##6_ z0i+n!82vzJRrOGdM4pMXDb@rpa;>0b>>P-91gCzdFuG}g$-3R1QMaJdKXHX^zwzvV zRNv)_3Kdoqve0#cQj*B?WGu`G)}Ru|3WT0DlVX6uc^5Rg7G49TaG8Q2v&mQOS2uo zd;ordm0AVyc&btu&aG;@d;Y_^cvh@)*z7hN1szwuRkWVK=)Uqz;|HpRCUoua+u;p+ zj!C>_9m)tL$MvYajpFPZ=C9O78Y}2^aQy0IJWYqt=QNzA zkApGxo_#-?45ueEd=iYYznR+~RQXUvl?bpEnB|jTh;?9#%)%~0gvMaN{~^I=?B1Yq zL#}))s65@&8-i63_*#ns#*J|Iy&v_jp8_7!I?U6W0<* z*&Q6)R}}BFH1%E~{h+?AZOonBN+g)W6QgjER@S&{iHxfb&&wXnn_9?`%n<0+b=f-F zd0O9g%sjlYOcq$`x@(^7pkQy8VFtDUH{I~t6p#e{xH|Tcp67AON@y}k(c|2+Tr$<8 zo}2-Ea4KE?vIgIBP??;lXXDiN*0;YW8Au;9hpZVtKhNSE#%J%oOaKw$2G8&o70cLp zjtZIGg4EgZE7;RL$}mIf;Gjz&gvEfiK_C4({REL1>I4``VEb|6pj5tVQ+4$Zy`Ksv z2)sOB#7m4U!HRuUj=}6mi2yUB;!kp2c_uTXIOluL?HoN2w~I776CkPYKkdx}@pH%6 z0mwfIcEZrcGx(5_eUpN*0XEH@rPE|E=(X(_^zWrIp<3EIrGiB6n}Ehekpix_P1c&# z`y|8_0C1c?^gHqYoc@PH2h(rWPpIj&s90e%w0MEeKXO6`STzT0|Grsd!BNMf{s>iZwOu6Fnf1;M2GFATytuyB zBaDyAkCAB&V!UY&j6?@M5>R14oJ5K&OV1N}T2Sx=3r;<>7j&hEx(?!3psr|$_^$|u zUWK{>IY{_&Vhd+%PS_`*9znh`S2YPo^H{^MDcGo7m5U}y^hv=(&3(FK8lN2YRmbln znnMRHlou`rZM5+Gs=;FIl_qZ_?zTu;{eRJ$Z!NsS>-vCjs~zUq=3 zR$aQ(nso6I9^}$g8veyc6^B0b9;S;8h^|k-Rf~1zL9xwbk>1hK5q)od^z?j-F7l`6 zBmJ-V>$i_a>d_JPBOlF+Yf!AqERA!p!?qFT?8L>5nlHAWqVU^q<3~>wej@jrzj{Ur z)*}ijCdK`u(Niz(F*8pOXmgKY5zB*5m1jfuejfvrndVz?xeQu>z0T+y;QQYeKyom_ zEJ_{a%MHtYBerP!NBu*i(qoYST4rGu`rE8rfQtJ$i~0wfAyAuE1i)wnpwmoXiOnvy zd^|40Zw^5PP|F1Z{clD2JN2JNyY=ufrFeKFO5v^XFkHHEE4Q+s~p#`>0A!VEJ7tv#nLo_sC$;_7m))*Q5); zj9Lovm-`|DfS#K6lC>?tq5bdgZ`3+1B09OyM7gz(s8REE!MdQwMBv;8F!(3v^*SPl z0%-3C%m?&BBwscaJpD0NZzIEkTVCZURQM>mT9$=oOXA#d`S%U0zb!f>eP3w1y6m&atcLS0YSmO)e z-O@X|x%XoBezxYm!U-Fcm(AR5(JCzR91M~7)HmpjrWY4$Rzar(s!;{Ai&*h0*0OhK z8N_ggE0UF^T%k$0CMf`F%o?qshCi-^c1{3M#ii7W?0T}I%ouA$8MV2roqgHR$JH-y z6A*tJsep@7f!E$U6z@(QE$?wfiA-e%7Bn%4I-rOgsNOdl`QQO5dy$8-<2hUjkG`)5 zCG?Ms)+0Z4vA+Hkk^A>0TzOzW-0R?^2bX*z&=dH185C-;i_inyyyY9{1N1N;V(6l{ zgF;}_AhNjxF1Q55I~jSA2UkDhl_zdD8Ja2{{QsnGfN0T$niORUs-#CZmvrN?!t#Uk z*zZnyhWLj98|Jgp$u`=1PeFIkLq(=J?+?IKzf)TkJ!D|prOZ{?fyviBv<5Q1sVPsl z%Vz2Ot{-F`a;KA)L&Q<`XOwIJmiEQ?vx-#AmY16RFr&0Enk6R#+B~YHl|+T1n7fu2 zFs~{(N>;^%_M!yiZjU+ z2Lw`}J5&>dBo)o#9;buot}FvU_sC9>Z(9XMGUAkL%*KnI5TXCDhjJ~)FoGMi=<~%I z3=6=PCM%!`ve-03OqsKWhTDZfkye~{C*RRcS5zqcjNb%fpTHMGlxJWDO8gmP2pumX z&od$WJChf{Nd`ONB~bJb_S|ad^*u33DT9v_BcXYFb-8RW%<(Si+B6SpLiMn>Aj;i@ zkt25|s33MuK_s)_i_qv%kRUjK=R48!y?z|Lv#@0>FevcHZFZY=x=PTohlws;e(wcC zk1Bd`JKt2Wn$%BiaKd;3G1s^WkfuT4HWF^aN^1Pb+NG2_{v_av+5QZ*%MmB05oI1y zEqVyF3U=Uci+t|4nb1qW4HjfmW<3qAbin^>IM><9 z^`18tLreMn7=M7u@k59cHLEJ*yUp&pBXO^Z*jp&23^*a|&e>3MhMo>4;g+wzxGcS| zJPk3K5!K*u7fOyM)Ae*a8(oPxW{YlyBk@nXD52ySF3@7FHs!n`Rd6I!B1b+Sj;Q#9 z;-iH~b_*-!lNDQr6`EOK*(t2sn~3bXDCb*1G~YKQrJE?KMfW` zX^LW}FB8^XXvNHZWDh)XMwm8l{&(ACO&+sN>(J@9wNopx{#SMiI0lLT|DO#T4BYKv zso3n9-?3>;*z5u*0`A2EMlYIeTbvj10*1zeFs3SR(PGBCj;*>jYuT|`p4Z;3ZEz5U5J``V z;04N1&6dZRTuqjgm-JA`d|X8R1*XpP#4^CANip^er|{4MwbWOw;%`BU}?6vP1v&m63_Ppo|9S4Z;c+^IiCGNz75Wf^6 zSKN@vsYqKS;ilSQeWHnE_7&`Q!lzG9&MdB=Q?7N^QFNs}GS@m`O{V{0fQu|8RH5tyTrNytNQP%E(q z8@cKUMHdiBfYZ7LGgCz}P9r`@m*VyCEXtaoXUaiOJ`vk935yFm2~v=NKjSJ`Pfg4a zDmKB_z#f0gQE9x?NhCbafYL2nKDd|bChpz#vJ=zoed1Y-+w4QDqu;Gdiu zpnJWe(>#UT&8GP83kHFi`|jyCD>@M;iU5=1+p>b-*3KWFFfaXKeQ9ER^T<7>F+ zS={0*SRD4v$s`|iDd_n+dO*@-RS*~lU7*{JuaI{5ihKoh zMc!3iF~bx2+OtLOQSHpy(?9VLxXtNn9TWRz=lb54UVK+zwOEJXC`%%dbVi)ql+eDalJ?0Z#x*A3V?$3&e@A@a4chmY z#`Qze6A=jWR1%XAXU}J%cg8(5Z&Svw3BJ*iPI2M8J0H<2Oxd}LUu^8L3#@J<8&Dg* z;?$##T?!@#dSZoj=R@k|XCi5BVKxp?%U5MbQ>R*h`9&Q}c7N$${&&Lz&7<*YbZ662 zV4*dqC|k!g8cqah?en8hA%k2s@jQ$#0eKIb443w^I@8HR4Wk3b5B1R$c7|(5AZgs? zxD5wr_ymtkwac1hD#JMMBGnwqp~+~Mim@MGf}t4t;bT02m^wKk&S8rtnQ`)AdN^5A12o=@e8)pzK(m$(0YF)f}Ka|0{IIQrXS6;uF&sm=fE{G7glyh_xoh zaWXzeTw)qe8mH2nD=ukgQ%YP3_)pq27JaOiy+VNzhD&o2*<8?Jg~Fa2C+1fK=2jLR zi8fjk%=CDEQcUlb;ja)iD=J@=qAYB&zC0rvhmNT2&c?jW$`c z?zxoNxM8@p$b#rW113tf$DdMvR*eN0dZbD{lo-Hj+@HObEUnvW8Dj8`;`~^u-=9DS zM|^Y01sbuVxdct7)dG~oC95(kD5pK)tue1GF$Op2DU91OgYA_$_QIZ+fAEWQuhpXy1@CZRl`3#d5DZ}?+y@%x) zV>vGDQsz~48eg85MsL4Fo&8pplS>X(G3H2l%NT{*v8bvQ%e~u%k1hR%#}ggTbgg)mp#gZ)GxfiB{b=ar}Rn>({uBZ1V+6z%tV#=!tttVu1)_A zVLn5@d?r3?^s#{>1XbPS86%=z$}fTBzu0>Z05^)OaoomWIE7+50Rnr%+-ZHQJL&G+ zB(LR;9dN-mU~)d})oE4kB&|-;75gMGgp!aDzEnt|r9mKsl7tTk1QQYnq!AKAZy|-y zs{s?pf8Lv!-Pt1PZ1~9U`+re_Z+CX)O?&g^&6`(hb>D?Ud1Z*>s<1DM(UZ0p`IJAuOU!H&zufKa@vfO*X!`$&-CX70wk& z1#}HtS_H36%0MmB2oj>^f%Xl|w+AeE{>)7eG^@Xa=`zTF0rWoOF{;Trm+@>$l0dJK zwyH@!w6gg`7r%?Kqncq*6!cN)Fz4woXN1BTkCJp|s#WF}$tJgA&a}W2S=4S*YYta3 zGYT^3`SewG`AWk3syL$}j=d2%ZF7A`eYkm}Dmu+AY?X{YSa+F8@BK1SgFmdZOWOSh zS)RZMU*AKkrLuB@>d-c;2C{#LEcZc{`zUTkz*zi54+TItjU?SHGPccvyNfES8Izx3 zuB9?=hf*2BW0?88Ey8hUqAnK9^_Rg!%deD%#@Qr0TRy1X<|3)MFTo;Pmdoi02xQ{5 zUin^K70z@}X;neNL&UFT%g5@QB#>z=#4|rWqOb5c)wPo7NUK*x!?-zH%`O;B0tC9Z-XUVJ0hK$5y2^*vE@TjveD9HfYj-z6k+mwM}|)9sP5% zlp|#UEI}(28%R{dvyS~eSpt7unY@-|6+#%gb@=be5{xA+#N3ks(Uokj%A`_XQP=b9 z*x!>SL}aM2RP5s|q%=z^8$4k+Ly&wVt?SuEdX{t$BhyCpq++ zZG#j`u+P?3MV;-~-MqmONSH|3@maNfrT+2oLkvtqSaQUciM9==kaMb_tci%m3~|Qd zZoU0zg8Sp)h0RiJ^k_o;MS=Du*>hoQ6%#^okmjOggj`}mNM_JaHld$vgTB@vM^B#s z9TObDF-?HY^028xJZfoyTPwEA;Go8zfzyszuVm=hl96RrRJ9jmpV{28m4rh|*Q#tL zs%Bc$))MYekt)QQl`t=h;aE6gzI4XAte5UsXCx%re4$O$;#tfp3T2<8n-sRGN5-hT zfH6F_M+7e-3O_DHV6Qd`RRtXBMI7=ai?cVK!D*(OMn#l;Xo@NNFf{a&;W{;&mq93S zR<#=b9-}4?E9gm?yA<3kx)3zFJ&cKB&NgdaxzNuE zb9CV9rRLOU_qUY&QarcV@W+chuJ(D@sMq;UlRjR`u;d4%1Esnj!%Pt-{& z6@6HDAk1|tea__cHDxVVP{C#hFCLF!vK`(~(F>Zrc@gJ<$<1!7pI}B#?p9JOKNqWk z*930ngN_95qMRpH91Mv^bKLyMcpBt@i-L34aT4y{fE%Ie;B?4nlf1YgkG9oenn)w* z3UP5ZGmq?) zRgHQ|mYsH=>|{a~4;jhD_Gaw_I8GYJEC;d?>N1urkzU(JQPU*1@V3|kYwmmA2;+D3 z5KK>fc2u!hurO^8P3_H+4YQFTj-y+wM?N50i`&zHoI+znnmZ zkXkUArsIO{NRH66OaTN{3DeOZyS|?r49BRHTjSa%*32a>FXCpYDnHW){W2)U^ZIHT zI#|u{sNM4aO7?k&5i?iIXE*~w5EPj;C)ibaLc9P@v~$BA6hK)bx(#$rHo!Xy{g-Hg z1apX3rnmS6ulj~cK%D>%Po!fl*MOw>bmpx*Nxgai5++eP$7JLr$t0`XlF8{$T@d})>L;3WBs^nSpl`y2%(N*3{owZ-oSf)($D2;Q+a!7)Pezj} z)v3#<)ZC7=EXGdo0papyfHaUPiVfwV7l8pKW7bfMS(GCd5uztWKjn0>9)6P4Sy!pU z;eJ8DYuFS>`{x*_)973)(A$KPfvFaI?6j4k?XGW)X8MuzH9HSXrfzV8I#9xvv9U-f z;5DChAR%CspUWAwmq&d8`*JqU+$rihTWLXTMz-}Z)27;RYQ5*IHc*$%NMg| zv?g>4&#Q`$>X&WE8Pe@e{-xCmA(k15q0n(0@_;sgES{EU5T~)P7tA5lZT~ z*Jjh%u_y7Q>et|L$+8JSHI)EdLm7Yzlr=u1EUa9DAT5LM{z1m zCHdvHfhg_@INq_Ln#!ix$Q&FTu5ZbmYS5RZj?U_odi`6_H3 zL!20Kpt_}vZV`BF681{Meo742B#vYfY&+!ehcRHO>|UaKk%Y@qO2o7D0ml(`c=|L{ zpnrizOD1wk93LfX79?v1n1ZcDJ1)^9sl=FNiJzL`fq+LEbp?Ur6R_eY@rrNS#_t$T2it~j_kato?LG<2RFf46`x5{vJPDl+k3a1 zZd0>@>M}puW<{OvS&&N$WQ9Nm=3bq);+Vt(DJ2apQ3jQQJT@q>0>f&K?-qk|hNFZ0 zvbwD1dIoz@rcfpfrCRPu^_qn?aYww=(<9+wGn;Y5NW-)8*d|gI(+E4;%iou<*Wf4kl}HC4}9wB z0Ux-%)7JM^dRqOxJ*SX=romGMKadB=-3z)GBt@FrcB&Fs-?M%_Bv*RKYp)zwUz(bj7R-L(HJ?Y-a z00GIAa3FiZWIM-FYC&{0Ae2t^%BeQts}HM9DP=3vN^`EIMeIacTtc%6-B=E-&jBrN zU$%%!1qw94RkJ&tLkfmLvuao!pb<-imMhEUXj&Zx=OM+Ixsd3)G7MLj7@`B8$ODXV z8X)CjV~{06=EW!wKwt&5IY73Fh*<~yAPhX|4z?B8ms1Jz!=Kwgz?>E?SYqN!1lw4y z-$vTNsE7d}d6T-CkTN=xOI1tABTg1x45_TK(P4FwW6Bow%ERVogtUk;iNh2{$>(&` zRv@s6ApCOX@r6*%p5E%FN+m#OksRFwigVN)Xi=r&OCg5zQ`yKSFK6k1yG!Apv;!By zc=$~by1t3v6=P>p7>_U+fFv^5@CPoy!NGO~UL2dyVnQ(?S(fE2U0*;WWlQzf13U%o z0ZfEIM~bGfvrSgn#F96Y0m@>>*APBCu!ihVK$fBdgt^QN4(V%vvSrP!JX^JW5$G9q zbpeELFrq0+5EoFbFWKTk!qN1c6rb-j=|GCCUeaRnhpdX0mK4`PPE#FZR%;4s#pR@z zY$Vj=_6Eos9>DRRv(^6P>d_pj6#7T%3k+h<0BDY@38mDOS%?uLk`qgEy|`+QEQ6eyuI(0+ABsU1 z7|AI}VNz8(vaskqHZwkogKA2ln~j>L+l>lKhLD(+7P8%-Y#{|}$Xxoo(0s@^q350#eR=kjmQp5&LchsF~%aDrvzGj2z9$ z0&ebDe-d-3OSsr9CgqT@%j96-a4DV>P5>}K&%cpm9dSk3LNqsL5D)mkf8i0IQr9SX zE1=*rV+@tnWa3#;u?!5Zc+iN-C?SADNr8X!KKaH9Oe7j9z-yH>Ryg~m_^ptC?zjhm zkulpS$YbuF^Inq?P^_Mt{T`$HI2Udd;EYueHHK&h>vfI!O_n3C_QOHDLbq;JzI}s>N(8fVaVBbJbAOOJRI;h(`%$oWz5;Dg?8hHLq~>F8NsUY`eRe4G256x!^`gl^@Sbi%U9%F0l+ zT_(fSoNUNuQFqTiItSRE-G=XEAD|nn zmBnO85&jm+z)ngq+~1ie$90}ac2=6!7KY$a9qSjd#RwS)b@zwzZ7^pLuK|;ySTYSh zFbPUQa##+6Shx#PyLyA6Y6?UFx)tRjRi&(nH&&!o@6kf;umA!Qw)>K!o{aq$Q=&L1 zv@fTsev+ZPm!VlVdgBrr!T1DsGwefalxa}mBp<%6UYVYwxFn}if!MX?K#}h<_J06h zYzIktTa;2wqK!GAUZC8k43ce{V;nnM=M<16*szS_A(sgemWkILg0}H=L>b|Wmp3OE zhm~t=c$G43GpQ+}nG+}~Q;^d0V8E2{W@QqY5`N{TSa1;M3Sa3=B0=!3s_;w=K~VoQ zO!Lk=H}~?xGjsJf@7$(W9-f`2aUKyzdmynaIczId|b`cE3c`7D&(gZcwV`gwyBU8^=-YfQbk;G9Q2az2^2qwIjPBwS62GP z%1h{99d$mI8zNT~hPY2?dVCSNjLE~U^x9gE@vXo6uI zz<*Jtq6I*NO1BTrYQQ#Wb4E63?mJ{R^ucFxc%#fu&f@s8b8^uvWqZ;+SrmKLjwp$s zxzJ?%@{d76ZJdmUb>_km%c-eoX(R*p$7KBbz#tWZoNn?*=rbZJISs&(F-K6&!Lmo8 z{W-hv+tv%2=v}9IjRsS|8WL`4f%ys9 zT0$6h&?sRiMTa>_0j@^OYf-WZLbM;cv{65s9dm}wDJ}@RNi;`#VuR07X^lrZBP0)t1Eo#1KH*(~mQw#~-mr@=9k2RAArcr?WrOe(@5D=p@D zCqzAxB7f;oBnFQWNBvn4zogpy)V+C*;uauHHxG^`rI^F99E?u0>W{#K&#(GpFg0m> z^-qIWvH4`~a*WrF;V@)fJtSG0)3GcWZXP=_!t01-n@!NCI6xy_;FqcRg$cI#NioRj zkZiTC!W#=JA1r@J;ThY)n6=Fx^fPgYgY&eLV+@PJw!0n}FM2z|m))RAjlr)&Q5AS$ z^OQJ5h5z^g;;c|%^H8toR>4YbFBwC{KE16Y5Nqx^Wql6_QDyoZAkQ*6KhYfE;m5i` zu!HLeoFb|K#LPl%u8M3?b|LmHIp+w2;WN=2UBU&@!4Mfi&=-WRZFbySrBu9A6f_Lb zg9E*MOerBeK9PKB@o14&tdm7rxEuq;p*rB)0jMn{9a0lhCR!+uIU9-E2=wNIU5lnX zuSK18JDcnXN|CaJ7p|zAWZ#4x%DHFKVF zjHx3!1R8IvMaD~w~> z3gd`@w-=EtGHi(u(t&g*Wea7dvB+iqHnKZlj50cAZr>DHdt^DX1vn$im7GFakRsE| z?e=AhtjT85CX0#;Hj)JMg8*UAop}Q}DhVEJN9S=lylEHV+T5=?A^Y4}C?91hNiv`@ zawdt4fUr5rk15VhagjNzJ=d^ycMe)PpZ1)C;WMvsc*6#()vPUMS_+vR>Z1T+h>aI( z2v&Fn9b9PSXeK}P3Z1I0VqmEUu^A^ks5LrxK+KZG;8{M+wa?N_@HY*QUp>8|#66nj z>aOtM7#X%>WKpnAm`6d$#fk4UF6mLNb0OBKAC*x>5t11gK}@vGlXDhpX5?3iP~a%P zEV8cXCRZ39yLjITLFtsMQDIgwq)Ktq8g?r_A5fntM9urlk**~Og2taCOD6yTJ3B1>ti*Fm@k z4>iOKFT4?Wp?|0=7`7{yWX_XO_A{y&EL>2i{ojW9>GYOqQfyP zQMFE1adUp_05cI6NN3yu!NWT-kLXtylxyXfLXEOV*^_j#ac!r2dY`wokb4z5&9cDE=hc9Gg*!LW*uPN=?quqe)OJ zNmwC-d=y7X8_`rU*~`N4B?%`ZIA4tRTNaRDn9Dz9$P&rSNnjKrn7p10Ffj3+{$6=3 z&gpAEbxzEb>bQNPCMykbW1}`g2nl`4}?6G-zRG(u|hnpEy181B4Xfhap zKb&$oE`u|2tS^vJ;>_%l8&^g$GTKl^(SNILzaR-@Lx?l=*$gl){m>w&g!(k@M@}fl zoSX)dAU}=tk-wzB0dVxm>>S5TL&S^%7G{xT)$~9O(5h9!cnV^26Co2-YS`l4B@Mcy zxx0iaAU2CxtssPyQ;JMwtq6uAjxHBjm%-L3#=Q0iimYQr?3fiZs~9b+MX}x79S(BE zaN7rAiA6-p&;Tid(Yw!SP-77xjvX3wlbIOO$^tSKvXSS2sYxxA)cDkBV9~)a731-_ zqBMHMT=O1P(PcBC2I#|CFQ%vgJ@8Qh*%`RfT5N+_K%?3Sl_JzxhT=B+;8c@lC4eFTl*4|vT0q`bb%@M{Z5p@#7F%2<>U;KNmdUcnaw;Tjff#Yc*H93)j&26h=vRTX z4F>TD3w};QQ4LEbdT9(6yC|xy4W=|sy;cjZV;NFA_5_QQBi%)?w(DjmaEKrj2d{p- z2j{36jsU1@P@vtAQPqe9i&_YbKRnTz5-;q*IB!?l4vU@Da7?>02Sw9l#ZIgRW zncE9C2OV=so-{i#QLUI_rO(J#^jus|RMN#tCYNGf-be!nD&TjwLe{yK!&th<5vV56 z4kbe%%_)ONWAd#ZUMej|#nz9sMLU!-WTleo${ZH2cMh#)4t3O4nL~sAW|Se4mnoW2 zi;137)ZU6pp1J;6JH+-~?mnV%u^L+n2_OlPc$LR-&>6?0VjJ1LtVoB?U6LBj3ktkhEXPec|Gu`VJ7$p;{=)0@RD#i zsRWyjHF`0FamC~%W|RaKnwH26&p}xmv<@G7?Z?QnbN6>1-Rs6?HJ$bOcyQJP$|7u0 zSqZw)L^H^)7@FMlwxpp=maQ((Y$Qx36~G5LCrZPHkO!w=i4bKfrv$Yoyfn~6wiMgI zc+ioeR&a6_JJj=ppiYr^D6ocD@`3WqP_k4x^He*`gk|kAxHIInFe&9p8Ny=IBay&{5qP8zaD2hu)T%vUTsw= z5fTFIiUC~EX_=)v!unP=D0eN_;z0@TPCM+k`E^#bq>b79&b>bv7*NJ#wdHFGJBXf zC2l>-qHG<)E<3hq8YEq)*hW4?yovEdb3nxI`$%7?;L~yCA`14%jFvTi04Il4Yu?F# zCP<)yqg{j53tq#EM z4O(QZbR{FBvpw%N**wT90vqB)A`@?X9{bKto-26oAgmtiUBbo+*$)~?uM-BBA>mFe zv*00t@vxH4y^Ujxph|DCXXwk0P|Fy4u8%X;MUM25vx1GwbS-jgC+u^MQA`WS5lvS7 zLZ9i~5bZ`yX4Q;<$?oU*Uhfj(@OLR081fPt4k>;-@%rW1Pz`i1Q(l$Kc%|YSvJuoF zPX$7g2D6fKWT?ub(<*S46zWwVdaE+vIO?KE1GffpTy(py?J{MD85_A7()i_59h9^9 zd5bMVKf40qwM|Z4XhRf*Hgg1yLZ{S>fUHAGJhqwPbYw)1Zg$k`JU{Acrlln#q8`XZ z`N)W@1pMDdy26lP9T%(t6Ubj|ELqf2DDBm&k&?z3Q^f!$rFuL6h-%X6fG0FxI2IT{ zBT|zih}hmhU`S&!GTiDXxK$KlTVrHv8&S^BDMs^zD6=5T@faJCe6P|^2^Ku&=Y}d3 zow|_(TxFL=rgV6~xsOH$stlVF!OhH|{-*p_-@`MMw!26CBTdLH5^TIVV|QO4`jaU)9@#0FyM z-vqcCHw6$j-VY6m#}}nBpwDG)rv=eRgsw!q&Wkb!sO%g-x(IuJbca-ihA) zo7`81abG@9_DdO1m-HB9H?X9UN?siRx?WV{-i$a5N>N~z2Eckh(>4G`N%>$fD#InW zspIF^7;qnfINKSs-%&#~pi^}70%wJ>qD=-Sz6l5)8DOfmTqezm3OU&Q%Ye#BNH827 z09(mma6lHwn*kB-`5p%mYRS8MX|=RqdX3{Be3Prqb$H~KmJ@lOp;PwrxpU@E#}Zy8nWCHkGVG_I(@i-|e9>f;yh$Uau_dJ9GcT=(k)l@W*Og`O}Z@I~Qj_`v)( zLkhE9HXq%l%OJb$=+}ldUQ}jxRai!F`BmAxhxvDsm3(`3O8n|POvfNbNFvI zlmR)iP=mkZ%*jK$1EU}_?HaK*ia!P`Y$|k33`0L=~M_A|g#f0FO}_{Hmr9wdOatK}}o zyAV|#vgNI+l@LG@*n;a+@DqLHJi_EBrCPAL2g~JP&Zp_O~Ub zg+n1!JkSX1MCF_y@nl1+nc9cw3?Rz0sJ<1Zye4KzRaU^fM&hQD0Lu-sOlAgTMjbbs z0P3tUVPIA=eu5VPUPA7`R+9Gn(fhBZX&YBpX;EOdcoQ-jK}Xjs4pl4 z4L!KKOtQ|rjj@BMDrAWj;*r64)I2I@0&pG^GidEJTJ=fr8sTqC5oQz=82xcHEbyDB zjeeW|{7NOD2UTHU#7QY=3E1-eZMbx(P!hux!}bb|$dSWvChrH-uK|MPa6n*td98|l zywO;!&5xb)TgAzmvh}+eZ1>67L2z+(djzESNwP8r}d>VX(AUcGX+=NDT0jmA&7*yJEQi62dbOGfY>4ba50u2;1 zk>No7Gck#BB+WUKw70b6EizA-79B0#qx5`9=+aQ02Hk~8#4jFcj(TZ6_6b8&0VA;{ zvss7P)N^D$VV#f(YcFI*b&Mz8hT97(6Zfp7zbdFs!CI)H$u(w~Wa-Fg5ws+yTaMYF zQ*Aw}5V)txBq16-F|krYCMaL!;wsQrMv5aCkzm9Y;k})*9v;CceYVw2LuCteO@T?Q z?QN)BG?z!5`teB6Kh4P)kdR1xE~L$+DbxpqNU|6wgq}P6d59HOjXGM63{+NE-9pf2 z&px7r9r{*^LsVv^95*$s0_~OcC3#wGeFuG?+mXsBL*%=|84}^_hDmClku{2y1UXva zKQR3jJ*Q=|6jW3Y?~`3T`Tsb3CJvhtzhY)Vzx4(>jS`|svYY3 zSfB+R#|{wIbA7Bs83C4aeXPOUAw+=CAi2E6QH$Ek;>V1d2cvp>IeM%wKrJgf=K9TB1Q5=Y z3I;jo!@1rht>rjIn5VaXx*V}*BWI|VmVU~6B$OWeM}?dhdr^%|PHi#CMx9tm+6INvpLm&}Q9zAYS^yEJLT3Wak4QfeN zDnoIvh?kYhu$Yc<;X&QT)@)|O!0!)+wXAi!q%jXV=)Y97z~QlX6;YH+3ynd8BXMlE zf?F^WcY|Li^0zp{Z8?aK7-tP=Ymn;0GXkv z>~hwWUiRk0U28b0k_|Tz6_&DzZgk<{l0!nE&^5>w8(U40gtZ!zpe97BUV{|fJCGM3j*eBmyNTpyeEno(Y{;&^W=?^f z&fyKBm=HmNmNoh?WFi{jE520Lh-+E2@KuCiXG(RH;DMMdLrZmx21iClf)J`ZNTBKY zKC+7NX2gINql^n-X{Am1KKeMCE=K0JuUmfH(sH@5S|1!DON}he`R!&?(BhPAx6Leu zZUkJw&TpUJ2R6CumA*sAOrs8nZBY?GLmHkvUcq%KR2$| zAS9Whk$EVT$;gf7vW{`cWfch}mZPv6puz=}VAAb@;#kBf)Knx9h#>4#0KM#0Knklv z%!t~&6fW5lAlRa*itL}(G0k749vGLieFogd>t!v4?&AqI*hP^1v>S)hZac%fmKLA+ zOxb_|*gTX`!UwcdgdwK_MuOM|r}T^}I%qs`hzW$qw@18iV$U4pD4ZKz0678U5QQAg z!5~3#oIzxGZSg++oDBMfMkE91Y$c#`<1(_>>Y||;!jMfMkh{t)S=g#V943S3T3v9F zO~z$FMe7U(v{KQPJUK})5w{>UqlS#IpkXkC1!LZ5)32gB15Ghm8TzW|b{58j%fwem zsR~q*l!td%(eetq#p&&2*@7_+KD4QU0Zsf6^Z8rIp*QB2+ra7)0Fgs7Ojum&8vys% zYRoUNgS29@T21iqF7t-7_Za=thOp~`jtV`Y6u0WxJ#s8H2h(14rDE%;48b^AbqiTt zq*^*eZKZfyn>BupR=0_YUMm#8>Tm0B1Jy3TNdjBNe{1Hj`oUIibbe2NuL}QED&`^_ zgdl5!(Ksl*kpD2t2x>7gaX6$fnnWYYI?Y| zzWbQRWD8@EYcJv|K$2kyL8T%(sE2>a>T_*Nl}fRv)Al7z zcmR)uXAZmB7Xp-PiIi$wBZ1)uQ>=0Mol+LM{jzZGCAzS^RP3W;O`Af$EKGwut1K^s zpzZLaI=-O9g~iETz~-F*Gce?*3J;{h#HLc2)JmhAs=}5Eg%`l39#cUgIoCi=rjKDI zzz_gL!X9{jzsNWcrZ;^Gd(54aNUKQ2N_KVVm%4XYLC>Qcqsk;@b z7ClNvi!dydT#v#QHbg)GHy#^pH^|W}kXLZX$-l_sC{_;g$fW>s#5*@tP&5&zQnB_9 z%5BM`;6jb@GE31zcfikF`UW9`U(s#(>C|VEe7^^NP~87}uzrYFn)62BX1O zAW%ETu=QA}y)nN)T>bGgM?s}ym1)4`;>}|_0RH>l1XRMdd`o)!s50>6yGnm(? z>iV{)0?bu2DuKpq+M;Md9j-dTv7p>``A?-1=kXu=*qu6_*aJH7#)K6`VrUx@Sa=*&5H%@P8D-w1 zkh;)l94sG4Es=zef+I6TUBc1(QUQ(xTy;51@SZ^id}noo5Vu4fDU!E<9Uh_XcN~@XFk(27<$bMq(GkzKG6g;vmCc6a{8Yg7OCWN=XAWfFp zrUK$AQ~XxDdm-9thw6=ZJLB0Bw!a49Tt@H76?PR2hkbI|K_ekk)D4N~M_*HQygR4R z$Tk+yY$Dhw=rp_B_i{lbz!wP#ZW+{XzL-o$2oyD8nNUa7vZji!I3uEpyr}udF8F-( z9Odc^6?1{qo}D{OI*7;u!X-dl;C0>Q1qCjE(#ICfVi1{Xf*F^BXIiHbmnA;na&$|e zYRIyw#%mTEQ1bFvyi$R9gS}HbOcz9i0Fy5f0;kR2<8R|bkr!?WKrMp9&dad@Je&G^ z{iGZ-aD%=XW_(Tx!4M$CYP5&fI$(l}B(X!HXaYM3TZ|wzG~}2OkRwJ^@6p*ENv}$! zY$vQ<2C@;tVCA8MZE)K3_+oGY2K9FxM@1XB4XJepf=)n1sWq%1>ePo1w`S902$%wQ zYS)NTYSSdp)CPuIOHED$`W4iAqJmBD*DWn zsZ5Ov`i;GqnpQnb>4TSI%31VfH3QBHv2W~+>u>d#H|V_%bA0HH+jAG31ynJ-0~+M! zGdaQ~1&$@hK2plBbjb>?ZB%X4nDTYprcSTTiK9Irx2{3D5MTy_ir>g4%v;x}k0sNq z<#zT#O`vKJb);4*S!LbVwQwQFVQ@M|?*cJw1-c1Is`!_-nF-ed{yFG@LcH@@YXq1@ zG~UHS%~p-39t^EEsWRocC|CakU)4~Jnyl98GTbp%>yMlFkklJS94(tofda_7<8ut9 zKJYmPr4)23jUxw}iY>FxHaxW^T;8ccqg6VFW&>T+5nL1WSz$?D9EG@r#SH^AY5guc z9k4NU-o9WnS!GPqm)>Su#>Yso*zH}VlJK&@<9tFQrbYPWUxpxNgeh~%+&Zi$8KY}7 zLZ`7eV4B+rGfbOf&9Ut&Hc7aTwMMPWC}#PI`@2;=T_&8=C?UBW8WCX50?ew%SdK`% z3dRy(+0QQQq& zWPHx3c{s~y)Uzd>S;7*Kb<9$5%0cg+4@JM@o`af(fgWi_P(ftpLAuGv%ppRFs#5g} zM2D|NVJSxY+X=ZVCbPzfY85lns`lL+6vO4QKtI0SG>$ znJ=MU6fj%0vgq6%b(>N4NE`cxit`DE+2&C*udfA;qNtdLbZ|#U$igULqWYC0j@o>7 zH9sWFn|p@vC`^}7%&@Pw$WSlmQ4!igbpaFe4#~;_bu%=G8XkeN7lFJ`9vc#sA{Sy* zNh%9m*wY0e>p=&M`t2=ftGpbROCnFXmW(eJluZ!kBe7C$Gv6LlKxX2jEM@&v9EGw9LLLp-Aj67{E-7W-rO1=Q~T$YcRl#aro zRCVQ0S@?j!#_871Yp13Z(XRb~w6fM2(>yz9;@LrqjG5X)gyVvJI!=!ywtbC|>!Bi^ z{3Dv8<7$o2ta0WyLD=<3dNrDC=OsWTY!npwVxb6kxo3TZLm*SHk6FnPEQ9?i^;pTh z=r)6YFomV0GQvNgksj?z)Or+UPDzS>&1Pgy(-POj4O>?btc;#wvk8HcR!s?Ml@G=k zSbu0<@*VEjs4Y1Se9(^MAi^1K`6v7J?%`29d6Y0+-g^kXWOnYijbXbU~pZi z%?*Y_lPR>m`4|E?`+W~Biwqt7`teFCc;NfEjF6I;FbqzUN#^0%= zq=4x!!j_XEwzwcwu5#xRVq1AN~;jpYH#B>Hvv(&K~=?h$kNB?kRq=?T%V+z-qIiDI2@ zHR4hIDZPxb_Xt)m%x3g_c{Q9pykaNDeC{mY5NYLtd!qH(aX^o(%u@axS5iobG z(;SDpB8Nv*hsjzT`(w9rL$?p+kg!@HkyR6?hjuVP^XzOu#wa0nmvM1&VgVTFU&I;g zk7?+`LP)fef7=2jJqynJQu@iXQaB57Tg13Ay4*&8wYArQ&Zl&jnw>$?7&-*NTfAUfDaSmlDC5+MG7`5L8k)S% zfY}x@#Y*0MgDC*-jd6RFh&bVU4EiS%Wp|!@jOommmSjft1P|who+Q~bRRS1A4>jm> zy{K-0X782Q=!Bt{Rv6{^iNpf5EhZ-e`$zN3 z5~H{lOm*hx6ASfhw$#$naY{LW?wt~qG&ogf=CYQxj*Lwa&RzZO)Pk9`3T+rszL)pR z0xdQ3RFf*2X4tT%Y9IV~xv2G(OJ-wNGA@$z?nG*r2=-Q%U{v)pb4C9L*vfurlzql| zyfU(N**^f2lIf$h8}{ikgz2h|1IK)xNCtq-y)k29j$#P(4ytoyf_lwdNU5pK9?;wnZEi@R zaL5ClJMw@$MZ_N_M{b336YRyq6$r>kT>%!cYPHp@n%5k~ilemRD6crmDxO{#l}Nr! zLOLoG3Pss%H2F^3Ls}4Jt%1i@jM&J7H`0I67t)7QyVOTkJIkcDhUhzZI%4nW*MCkq z0j~J*pQ7cIKkCz*4vKA|QgBTR-fWY0XXiS372G|F4x)ryRBY{_V}w;OR}@+6)2&=J z2^!f;%pxijNwU+QxwP2AGCz=ER{fnJQ()t{I>nX{u$>{G17b?pqb6GoevsDJxV%ZY z+Gx@n-loQc(b2@s&kl*Gg3^ zZoz}e5kL!u?znw<^A#SOTFr*bWAO%_IUK|$(I7ijE3q7L2*fhZSjH+?;FeweH7&e5 z=yt%AqHOL)*wljeDy`0Rv%raD3>9le2}j*;d8HA-md!4Ls~Xa3!fknG%vzmeIbC=9 z=puuep=*jS0U?1BD(yeua1b%Mt)GrX9NFg}_07Rq@-I8GBKjfre#GE=MfvJb49u*b?!C z6r>dp)E9?(oTlfN$iy{SV10u}0FAJ#UXx_`!9d|R;E!z~3G7!?)=ct3p<8N?q7k?0 z^b6*!*Kr?74>f+uFZtWz)JJAQxS%vuH8>9Tdpm+jx}&Z*u71(u>xjl&ulJj*T%cKt zB_n--ep%q#Ao`v?buEaFm^ux%1=X-v0=r>B_+*-6e&KKn%dP5ZE0HTk3JHX^PAtqzo_fv#>bF#s%hckAJNs68f@cPF|m6P>6 zBKLELuiPVYhSUw>2-B4aIetTuEW~;7a~vXL>O&(QK5;SYkw&%#g>Y1pCd4GX5L5hO z0T&|psptcS6`Tj#F+%tlvH8cHZAt%Jq5`p$qBB6|8igcR0ozwvfRct<1+1@RqXPY1 zHt#y@T=Z@THZR2^h#py&N%UQWWM+Ol4Th%9Z=b66Rpr142K^&E)CAYBzqDbf07iEm zU{esJ&w8-~XkV#A!wC*jbBbaRuk3^HslAXcxPjI9!KLYp8Ql{)r+3fn?ChQpnm(g* zMt2y~$uAt9F?|C0Cp>dTxGUThnh@&j?&_L3K?;q#hWGIs0@1uAO~`3|sZ4P=ldqAl zkeWUtJZsjh52H;V;%`oj%%sm(%IbO{&`nUpHx&>86?%QXOi~JDO2C9n-Ehp}wLPta zgYdN#l*@b)`I(s|RdQsBVg_GRM~5_;E|UEK?f866Q`2Z}Q6eR@0$3q$V4pUy4}{qI znxN)DCSR6$_MTR54tX33yjy!ERh2@d9ZgM%j4lOQ$IwtBB5^woiAu($Oi9|T7Y%>4 z6#!R#RS7mIv1?0~9k+N*{m#Y7E&#gk?%X}CklqUVRc435QHIrHsLG>QiJUg-^a8R; zkf%lmBvQt!NZu$*V2?^pmsp@mr?Jl%%Cl)S`$s2?8LL54@Cu65q4%W?2~0vZP*a0| z25N;Hs8?VHBidBEA!tS*p`}O3qe1^}r2o&){MD!b@NY0tBpmr>Bd>$ws-3B$0sZgn z4tF}}e`n`^=>LcFo722#<-)ZmuUagDC~~fE4jg{q523nqkxI~jr1Tkn?Iu1*V_diw z3Kd495*7M&PM-lU;Bg~`en2BBLOY@olO2MLD_W(HJ1A&EG-*X>KPG{D13$Gy3WnRe z+dJEHnS6VH$uFUfoXcVO+&SE_pBqejdk1CQ5WP8e*8wJ3(2$x75Gi=`x>Ta_=S5^R zJ^|4U%s>Q`xFWkvSv%Mpt>X5fpwq=+aU_hx^L8~=&t%}r|D(ZT^mF;futBQ3Wr)$Id zIP1qPD4K4`DKdmgtVA>=snuOFPa5)ZhQRX3PxDbnO3K-JPBP+5bO`U)}w`$=CD& zY{~!y;-*XBdQc^2gM6mkA^Zz;(@#!IS(Sz*D5Z71Y=es#a(W`8p zPC^TG?r4Fo@fRS?vBy8jcG|vnI=*%ZUmdk}kH1!HYaR#?j)@N&fge`Lf3lF(Ge>8` z99@na&F(DS^|N$|^}yzAZ#|vxv{qUOTbCkfi3EFMm!9xa7Y{gJInFU7t>blYc7-q} zB_pQ?arbO>_lCF5k-t?Y4+*W52K{0zE1~$q>Z=W>Vdjev{KT^_B@n2<$gymJy4@i) z_wU{(W0x#orE1$;*m}Qy-P_%x^0ldEpfGzK<{cv zsNIdBODJpQbuj2XVWm^)Qo4IZ$Pjll+@gV9aVPoH*-NU>db)aR)j};eM#nckJ!F8C zu~eir-Ku2BTR(Xlh_q%~m0YAX-&*YzYZ&Lxh?tQTl>+q=Js6>OBhaxO0_dE%)*Ww- z)YhuQ7$$eRaJaW8)vKo8PkA)8SNq>52=ebhubO@TP;$L${{28PdR23d-wzySSN48D z4E9ocGVjH}36z`Ou*KlM;3vx?TD236`mm+E!So;;%UOV3Rm|~%^=AWbe(|mbuIoL? zC9j5B><9p{geR;*5q;Q^{bmT%LGjurlTQ)wHVV|Mw8ndSTO&Q)%5-H0dF$&*!0Sw9 zmNI+i*RU5Q+qs!1ty8;O;NR)^?~I*<1O0+l&1}IZ(y&?diL`CD_Yh*p&XU)JaPm4o zo0T>hLq)tzBy?Vv;(FG|r=+qW4V7AVo&*xWZ2-6p0JjmqZ4_`@*=R$+9?dn8ODbhx zU$7dE&9$)7d}_D>TOiq1W5TQjawj$stw!5+98x^eBYDXzUjswnE zq%ckp2Q+eOP$RPZl9^G7@J>K8=*1}=JZo#-(Uwq{WCJgk3z3cvEx!poqPFg2f9z0V zHEEyFlX6kZfU>m|!>)YLJ&ApYUBMY~tPtLn8m&tj#s}0u0;y%(ja1PuA2js?A8*nQ zHLevuxLyIYarG=Wlr3khN%)`YSxY=iT9X}$f52VjV8_*0WdFVTN?G#{uE(&wk(RZ< zW4QMN?zac<7RIW#R;@~UJx-%ZqbQ-eZibu_LyD9Iy%ab$a{Fc}Gbc;_X={@u@h+~T z!*;V4bp0fDJVgz**0w;VEiAXSMx@p@1W!2NcAO5|b({k#_2OeILz3#1U=tvgph==w zkRFbUdWj%92p(ERfS|tPENknzWR)bxb=J#(*g!>cRW6h_^>}s!q#Z)-{!=*6fBIxA zhoX#x?s8|!vI@bffw&Ficz9tw~D#d3mtVxe%hC+(3smY$$6$(XtO+G&0 z=4Jd+dhfL^U2M;k)=+(9JrR%v!N$};D|1s_1kJBj*>X;4HieI|IK;HJrj8E!*SZ?8 zSG@#bM(vsDzv%vYEy`Xtr1bK#B%vBQQ?FFrGUkPZbO!|RwAv`^X5mw%F>Ud=`{Edbeaw=6l4Pgm9(!- zgWC|&S_tD#I*R@+6t;XwW(C_v=!cGj3^2jHJJz41W6UPSHc>cr_Ccn#mPk4s9%!PL zr{hDf-=q;T0$4?cYI9=u;N1Z!Z470}8K!I$VJiBJ!X{`8WW)x=b!Z-+`l2u#3`gLc zP71JbU}MxS!B{{@kCKG;fu!d-YzpDdjlvMj-%v?Qkt%a=fHTn=f`XL9wu98UL?(=t z%9OEr3&=rSFK6=70z)e%q%{;3q`-m&Yf6ObCAB`V7zGy*QhXCa8p$N|QUO9JNQn%n zeaDBe>4Zc`czy%9t=XGIM#~0=3X(?S|Iw!4pYZINp^{&*)@f-d4r|m}xg?G7ApVHd z6AmezA*CzStB4=thCx1}XvHG5O`HHXHC3Y`g=*qbUp=uTPj?d+akD(2wR=)A7wPHf zkd`f$W-7BJu+Pi4mL+B=BF0$@)`-6rv?8q8vS0$nRQ&6gjJFJq&I#W-(;$MNx~9z z4vs@pku|?m>{CGBj$o!WE68qBl&yVZMl-aE)6fJr%jGhd1JSRF)CxG?>b?Pj_R(s2 zFQd+O+gK2<@=exl6o+AzC0HKDwg~{MRwc9m1kWN}B>$QpYG3A=byyIq{E0(0CxzaC z(Y+Ek%04|y7d_r<5&BDZh#EIz@MG*)*a;VY785H_P0|gU)~N6);Knm*%0t+2X43=y zn}U43P;7OTG4ebtqo4qpA-&^<5sJCuJTMy}3{KG!w(u20W4#!L|ajJ3ECqvf{sdT zFXiGU$vv2a(6Nz85~kAi*Ak36~cTiJL)V7KUh=_`cbP)js0Rd@J zq9Pz&en^uN>AjcGLKH*<1f+L@(mO~ekVpq9q4yAahX5f2Qa|4B?{DUtcjnICo&Dp? z+?{jx>^|o?&;IPqk7wu%lIsWjUOwn~k$Wd0c_ zG;x{-dZ<;H?aR0qf5})_R%ZP6`RnnB?vea1v_GeR%p^|J<03 z{CYpNTVPzA?aI&{FUDGQ`ERo9lbFX3Qr{sT=G&Ax-_6(?VH>in-g^6eFB81!6aD;& zXGz-$$cy8|*u35k!DVi7-yZwg&4=gVhVQ|%jTrY;Y!?lZ+$)*rt$cNm_64)Qm3AWd zaZ}W@!7-bzKM92>vBtLGY@}per41fWBZxrk}xBx zE6)2`Jc-Mw*5nF9ChZ;0_qX~UD1RE3TTzJq%WP9vXXS4Ab1t{BHt+&R|4Z}ZalqoM znd*+C+LRo$i=zC-n49|LrF4zzxQeSKDSML?r)<@~{h^#)X4jrSQl^1CunLW-uj6RQ!S;^b(_>>V#UUHSV{(#X^FuDIu4KUu4r(s7!%-{98TWB0geCsA`~ zCtl+x8;o%)J>b-D|JT%aiwb@}zR7^6$x=sZWC7;;CT$3cuPxnnblX!vbV%9>nRZzn znhSVShudHF2DT2XWTNN{yQRa%vt!wrX;3%w)~Wt_$b=TXje))2S+(Ua*j4+9V##dY zm^Pgs#!n4|hHY5PIg=k2+~fVYN&~s71YP``+rrc)n0p|T`?7-&AdbbwX|rucs^9(N zRZ@iAvs;Z@ZZ~@>@6k&5B=eVwfL4^#3UXH7a^2cXW4gcuXnT;fo^85(#g^v98l7y~ z9~*t77WUq#X=FWJd${%cIkU2SZ3`OzvEoa4y@Y?(c9uQtTCs@q%s2F36PaJ50g0bH z4kV=AGZJs+CCg@fxwZ|ysIa~!SZ9S{*znNBLnkh$Mxgndv5-lMSoe- zlH2>Pv)z&ie(`6bweA(=6;I!C7(qAB{%%@OQ@T*QoJbXZbii*(&ui|IgXrDadVpGr z>>!uQU1KMY0A~E02SW^oV z&XI(&r4LLKOn71(u)?tc7 z4)3gwTpRv1DVZn!dc7y^vq%7k%v5+ON&bEHxZX&u;#b0J?+mBU{9nJkx#zcW!P?Ht z%~Sm9_%M1Y%*WzAngV4DX10B~7#AaFe2&bLYfGW>oXPD`)nnOM^0zTXV@DK9+&nc7 zM2V1Se^&fzy`SNeTD)cNCZbI8E(J+~JV0b;KqTcJxIrfuhgMR*@X#S&?hvVIi<9fe zRB>-rBRqrz34VZxbyRZ9c$;nTPViac{Yn!)k<0PYPwX|YI%chbLw}Nm-*NXfj687> z`u*s!36xhQ1JW^9AZ%3SC>EDea7q8quO{)N*En{Oo13anS{&XDXx#cP#BA?c9sNtg ze;~Dj7TjuW$R(Iv%&M7NG1iYwp8J*0+Q)~PHXNzWBCB?_!C?2sHoPI zAA4Sw690os3E2B$Th^7Om{^E=W(n3%YD{Rts{N~Hd0RvqI$;EVAs}u|_e_l+Tz?1ByMw^>Dm_)?LzpH&gE?mZDmK1ipY!ZV!bDbo`|O8{$)9^Q3JErN+Sb6)|G z{E5*|tV*4u1A~jjDpKPPZioQ$enO_59QlgcS+;fF46Lq_tW*a&l+_1PL)UIW)f*nG z$^LAL*RFf4Ns?ONp7Iv?YPEq|aq=Q?3zeY4M^pTreqB(fHT8by3fMc;zO;|;s=un& z@0iUWAup5vN42ER@-4^IJmdM@{+eg0R%OYyI~j{_wj1f+L*<0oGA0xDR_`rU(WXRH zSY!;ccb?=Ma6t^6{R4}gl{0b~z1%r8RR8Qb-9f6~`p@OAuFg_iU6i2DGScb3E~bme zot5X`+Kn^lq-YLzsO6(xppo~WT(wMuAbvUSMepFW3=CE^?{rglI2RLGSovK9EdR+2&4 zM!&6dZQysKT7e4w zAGedaqsl+}d-*F%lr`Ib0pHC0Y;vW9A@jQt|ZwwOih+yit3H#+txR&AEd2w;YBJCLxMccA9`#J8p+l>d8 zFg;P(D=KB8ZkZB|@`LWA^%31W3VM}Z+Mm6nwL@g9XnXL z;FESXZvBrm-=}C0$eAitm^D z_CmMf^;PM9x$kFXQr{)%4cafRjptqOZVhzid7HD*0mg=L;Nr!Rv|xh05#V(VH{>EzXEHB+-H5D*BJF#UmGP<z4rIbHUU*R;0W78e88BJLWBcKQH~N`*Qu0w2ux{e6By` z6O$^c6c-ly?8j;BCA*+<)=%;@PkxM_J=9NEUT`I4e(k=!H%=eMa)XX*+?@ffoY3z$%eYmq zan;gx@`(ZLy^;OUn}WH57W+w2gW8cF2Xo=7PAM7pN=-`re$CcLJOaW#$eKAne;IcE zl8X^E#U4AHYf+TE?1ulI6wM|A{kMbjTMjpOlkI&Hr3h zniQR(Pj^aj`Kn$|*TBm@`Q)W2XQ{bi)wIdCH&U9@DhM{5YH6aDGfD|rE@{U9y~u*@ zOW5+Puj-HF${2&}UoWkDG^V+ahKK)e=Rn4i+bOk2-!UwiQS-M>zv@6^$dRgZQ^@u= z#^%>Y*UFk-Z>wsyT#W6uv{%cRE#UseIfu(!dY)rz!P6x>6$rkx`ti{B)eq35%(YRE z?f+@W7tK$4|FGN*Nv0!-x2Y<5$G)m8o7M`?+4aJY{uV3dB)ymj(*r$w>gw>m_4LX6 zxshD|{mW@6k6XK^*|#G;t|zLrB~{J`sdBPkE)Jtb`S!-q6gO5(aJ{~nJN#g(+0^@%EOkAQ@8yQj zKW$zPEr%hmcK}4{&;3bRa?BiG$GTeOpG+n`BYUIe zP(GyBC!w)-Hfuu0WA#?RY+K2^p1z+K8@H;3LH4l3vE7H)OZ~+k^Y9W ztwiQyz`^gO7x2**?2}|MXRt4Q*B*Ok7~Ya8HK%OGL*N$&({xVncPo!w)iR_(tjp_q zhPU6fzqSF-ZT3%Vx;KU1%C>0%J5BEzi9fG#syj3bFQ!9Wa~?JjiiHz6L|z)z{7&h6 z@R~2(rEbG1xxCgs-1&zFZ=!qfU!3Tae|K}V9%Jzw$ZdF4^Ku*XMT?7f_Jj}ka~6{t z2N%F8>1uB{6J}OHGt?27rzwpL-P+7wzQ-XvC$9bHUg5HU1pm`tiG}#rH|SN~REZx5 zNu2-3_UO$8)Bnm(&xThs3o&!iPJS`lqv9u;oz9B(HI{su!{2(!^de?Fwj3I1f_^n4; z^;|l9PG05v5nk$YevFl!WR{wfyR^&8*7n?M{+)J*3?+2doFbOBD-7YWPmDyXKup7S zg+0|jXf9~LQyV~*WA zy6mB-hW%S07;KwvQrN;%)}RqBB`oq^{mRGsmCcOFz~K5xj;hgF+4leVj9`e9pncJ4 zl3P`qYL(;mOD_8*XMCIAHDWa%k;JQYim-O_q*q$oCWCYYa5drr;CEpc32&hrBm|Qu zfOGB=T)ZvtLdwoa@#f5`*G+3zh1=Utb^y6G{08<8G(#Ve3I8NMrE^CG&Q)nK%W1#R zaOf5@xmoacnCHdj(Q6OUaQB7={i>@64Pm;WOv@wJ2wd!Dy_7j8Z~GW&(3{LQ0mr~> z^^5~?^)y3Y!lX$>szhe{)h$S~E>|s&T5<`9i>LSR?^)$hNj*Km@g%mXJcA&C`(>|= zPplp{@zK{u^!vN10=4pPGboBTbB4%SW=ME72d|nT#0}aX#_Z7tstkF>- zc9y)&R^6Xy37B?;znA?%p~ew;oZ|K`Uw)L&U@DLh1lWZvtVBaVf>dnTIq~@h z0#2pAFLt&|&8C3j0g@Mnshwxwz{x1<(_^mdHzq6wQba#$Q?4x`6a^9?0ODed-0`OU z!2Ka0?4X>LdkY7a@ag-F1|%d`5{8f={ynGu*yHJI@VZSPB4ltAdOcrE!7;8V1+xAV zu1_5$oXLxo@>QYlk|%q0Lzc76D}yyMWcQJ}2Z8HQ!Qeb^cXT`mLi$C<2iQ!rVzQ_w z7UMasKB@JMNT`2zI&=XWRSRg|y$2<%QH-+WOFWR}%8M^4AmD$%X20dB=!3DF@S|+Z zCWtM7Fc#_DIE>zpk`z#sz1 z`y3m8##TM4vZ%4^;MIQ#LRn9`LP<_Ah^wWA*Xl1K*-qDS_%&ln2s>2ES-?xek{5P5vHsURQ4-*jwUpp>jR)V=*ANi z1Iwu#RwmJK0^=PX62lK#0&fxQ0L8{;Tb3PhVi{}*FR&wwC)AO-Px^jRQ z&K&|Osar2N?JNuqII_1p@SJspS82zK&3Mm6j_Lz}1pvxs+x;IFFm#;}-e{sE6G<69 zh`#B6SOkO0t%s|l6;=*0n)8CBmDOn!p-(gM0Cw~Xs@1eV$e|;D);=p1s}3Y6P%2@& zJw_?_57@K3##*6>9gIu1!qK|9Sbzn=i@1GdRrkN_dd z2*}PIdepr!pksHi>RMHV;Qx~lkNG2%*-3cc< zX9qG|N@9lvCcvPR&uaGthG$Qsg)!j0Kh8;Nn-z*+i;WZz1|z7?^FZz8@%fX?*Z~J~+a^lg8`HKgIM!O{ zLv5rGkmOhtFHk&Uvc@r`jg35u)L0sAZw0LA*%lT=;VbsRu@7Mm6Z zqT1T59H_arI;<7|e>U96J|fqzTO%4V%W)Tr%rfF^kPF&$Qqx$(13yifR|20vujN3j zeRi2e<){b14ov$OH7Ld$5HN@B1=QibS78bkK*RQaFibP8J#ZF9j*l>^ls}b8Mh&BU zdffG)t=p$hT{%vHl>NW26BqjziR0a@n6~4={UTz%qHY#pc>L#eIv&- zaww6K7Q9cP)h!oRYTn8L(MNPMd9eD7?tR6mb3)EsVd5gprTk z_v3FaOq*Jq4s7Z+ALmu=2bthTVIfC)tBuUT(=*s2=N6^ewYZR7ko!Rh(x_;GM8deo z8S$VnkEkru(%Q3|p%H5}XA?*?0Tm_?vN_C0C7p=#>8o-Rx9ykliC7ErKNiG-iu@)= zTrW8e@ytDFo7s8u9^7v#fho|lCn=5@9n^gfrcm#SnI|{fb0Y}Efv`qkLfXY8l#*~C z%vOqXr5x61dU$4?869~*7}!MaG;Mrw1qM@U^`(au8=7`YaR9X6NIi#N+tII09X5i? z*_N2npX0y#&Pd}B@+7hjXw>F7UDc|ve8vZ(H1yV1xitSGSKni%c;FEV=Gh*T@Ccv) zIA1 zuL=|90NBYgOw;n{kH9`I4nYOQqq6|0PL}6T9R8TRv1e;U`VF2nK%%lxExl@Zlruhex&dCq|hH9-KF0=Nk?PyKBrm!4&MYwvu%_#MPwf z)yp+z1hh4Hds{o51`gifk7$KEcI2>>vF4Eb7Aip0LRrGTkrH_Z20$a;&yoy%+NX*z zFR6dG^pAGGRi0~krXt}%>S$3T&L9F)stX_=7QDU2#~cL4P9Y-zey8F^+#%aIjA9L@ z2bm2y4Fkef_tlZy#5EMrC?kYi&zhD%Usf~|mg#)Keg8Q7 zLe1C?T`|cJVJ|@4LNN-qVk5vZs+(eSf#b>;5_WWusB^8RFiKU10<&j;W?LXYVoZ6hQ(P~+auUQ6LHS^X5i81!Z>b_ z%?S=>#~rw69*1)arY!T}(d%=xz?tLTyhhT_u6GsKbFQz_8RD}W9ljo++q4#>_Vv_+ zFtgTKDzdJKAnrgAXY=|UP=fyMzxL^<#E*@Bl`T6mspjXXu(=TUxko|kUjEcnRER$% z4#S&K1|mPl{VOYjWY1GOa_&_vR&VSdXZFT|!9*~0*qk~8xxw{)5ebU6myE10zob9SHpF1s0u4GNqK>`SonNj!y!z_U7oNJt-|4@>8 zrhcLw$#PT=h^TaIWP~5%rb8gdrB&{vcB~luFuUj*@(cygFr`p-_3_MRb?4dZv%R=^ zA!V6^qg@(G0LfL&!Ct$}Vxi$Q0f_M>=ZnlE{INUZ2f@T}U!HAjqc+S2d5@Y5CMVp( za8^6FU>f+>+mPwCzeU)~m9R_p)5$!9;|URT^XiyB{Pia$$iW`AuX#J;B|LI_5R8%5iY)6JbFN6#!zOrBg|!p>3O1H z%SKZ;6^768KQ0p#0k4s2p$N?PR75M81*6mux4<#C*%PC7*A42u9S3dNI#otAto#GA z3C1aog3*J~!)Zs8Ft-e!<%NnkvytO9u|=h`tbMvgkNE(|4P6C7`>Ls_?)-kFJ zlh76)qwRf&5@@>dfG`b!9Ij(|z)l!Oxc~Vsav)3_u%ob*Fq1irICi6?R2G=7;JHtC z8>QhNvX665HfW8gdu^vNK)JPK83D-N$^Isg5^Q<6b|_B}u7!twHDN2(lYhS#84t zeA;Y(&~^Za0YLrBCcuJX%<+j^BWZuTZJ4}npf4>-Pua@aQtM3R&5}mg9addv>^-#q>#+rx1TYg{D~%W6&I_?@ra^^ zp!*J?A3YhOEu&+4x-h7z1IERa%`>-^dn~Q(k^18lkLGnl#v45m$*g3ZkdPJDOr2)C zgKmT={G3M{@8-O_h#QWhkPm2g@9aZi*5@1e5GhiouA3 z09s^G9#>|;2f3ju%D6?zyQ4rY1u%gPopaX^6YK`S9itdAA^I791Z1qD=W!|^5N!~b z_(7r7rk)ztB3=|*_zh{1Wc%~a-C%^unH$ z;*ExvNrjxF=H(N1Zw8XucH_u14TEtcwRX&QZ5+^lK_tBbI#*FkinBirJnk34YXPW4 z8BQ7AwR!6mCN%Z@3z8ce5WMXM-236y;=W%i9P=gYH*+xd=O#XQ>syTbg6GJNIoyvN zH8Hcn8iMHHaL) zC4da%K=<691_H)?-}%SmLRh$5WI-lQp9Tj89rQ=S!w{5X%^F`p1#W{Jg?(q1;g>b_ zu2hhcM8JTfpvBnnm?aOw6IaU|{2N~~P^ENs+}8-l!sw*MvKC%$qX1W-vO&~Lv5>t~ zEG3Xo*w)~S_QG{4SD7C!=4_h7kGj<0O~k&W$oWbFxmm64{9wZX8;kI$y5}t~Pr)6` zfTlT)Hygl?9o{U=irW>)5b}rplgiQ6hSql9hUkmor|zL(P)wBzXlKt$xDbvA1y?lS1sTV z%lKILn<-tU)Igi{eQ$2G-_ma&d1K+8VCC5^y0EozJ4?A?ILl)c8w9~FN8|*%ebPDM zF!Ccgc}g{$eRs5>f}INL$Weki;LTS1|1jV@>r>Z6h)35CM$GwqZKD7fY%fyE-L~1x zobQ)S=s6Oj;Kf;y3wFV7(XC)irl3~q9!PNS{D>nq_#7d+Kz_4YU8VD%;qW{hxD^TI z_77ePH)^D;e;zM-D;A6J9LEC!m-{$?!N(vNhCQ9~YW(ybl*^BpHmE{4dfA*7dFw8m7nvf7?R5iHL6#QBH34M7K_xNJFblpi?Q zAY!e%N7>2*q&HrLfI{$RYGM{bsI_^_KO!^yJa>~SwH+>sPQ`FJ&8=57LRx||k80Ir z771v47GbYzSsPGdks^PX9Y5sFops*x1sL)avQ|3leh;JIxC9hy^&A0V4S(z-xF!=%+u4 zC;2)Yat_&d5O0lDJ*FO>{M4t&YR-5qykW2Du4{YQ+awYd zKn78vKmU@c57t>Y`k@8YRG#B?A`;QIO|`~oe9jnb@NuZi6Z!rabfp7WQlQpJ8!C8&@m3FIp5%SOO~biR%_yO+REfhigk;3w5 zlGu3p`scF#`j>Jd%35;M0mqQ+xB7UyB~X^tw?< zj%>3Dg8I@^g5(7n#1?M8R5h{6=pvgcc-y^X)m4nYEE9MLFqs4#3I*}4Mw+=1q;wZ* zk+G^A$Ok1aZP1D``=;BhvUHaR^ubXxj19L{vl>Iq<#ShfUF0`4L*A<1?0$1=(T4r| zgBGtC>>I5yW5%ntujIL_tVFLp)m|wyydCgdy+3^73a97v(AiHx!x{v;4s0!}jqdEw9A-1DX@6bEdZM z>nM7ak4`qe{$jwDBBcB#+c|s2p{MABiMZ1V*Mr-uE@GGWeAA*8Diu6S!xdjKyQhc$ zG0AqXPka-5{<39=kfmK(8b{^G)e&%q}cICc5u2?Qidq~ zBlVvJV*O$2(bDyTf&inoQ-pD-On5sp?ZS+piSO94>hFec=YzirobMaGu~vy0epS7F zZv(Du`ypf^VQh;iDDZFpVB*zfRtpUhoIq|3{$c%k9rS z&g3Q?m{C{3gnztTYV|kHq-RZmh8Y187G?WtbT8qoHBb&)036?tx`f`Y5F+~J<*gsjxo;-P)2hO(GN7fIPamiZ4hq*s zjW;*Ea~R>MHhb1K`*?q9l@HcbxHR_wh`*WOY_4j@xTkrGlC^(VfyLtY{JYPy+x%;# z${Ks@qH%Lw-huPh0wdL^GtqLaBx2~W^o#%wLsUk??y$H@A(XyHp(bQtmL z<(GZ4j5Ed}jZ=3}LRs0nSH~+TlH60j-+1Jr61M=@iFF$R*r)5bQc< zCYsD0#xjz1f=naa587(B*YPm{U4O)996B`D;JEz_9JGcuT2CQ8XjE}nGiOGhsHk!S#X;f+}TBPK6$_K6j0Rbw&4&Nox_a4 z27jnMSQ_P77AyT}yW#sR@O#|Hj`c4mf48y1m2sl~z2U(;EJhWVRkMp2V#K*l21`1e z(aG%^4q0cOA;bH8E2xJp%5iM$-`cL|TpYIVS<$NdZ@P{7UpB2$=N)OEt@L{m70)VA zM3R;HTcQ_dVu6|DeLa;I&R(AHm~&(9ZQ~tqGp{wn{{3ot>}P#du+25I4_1MLj6))S z5>%~Jqe2X$RFapn6P0CDOock#*d&tghb+|8^xGi2qrrzm;Y}gm_Ty7- z6~`Y*%SS<&C7NHaV6{PKdFnNxtYSx(y+93Yd5it=A_dk@wM3M22Wecd=tcdbmnvqx zrNBEFrX17ZApK5?O?m%)TG#$-nWpoxLg%*zi0&GeC;`T_0W$mMn=RLJr8KdvBeL9UoyYY&_PB-e#2aUkE@p$EQt3n?^N?mEIryJ=Alv*8O1kN2 zQDG_NqhhI9xayyg_|1@xpy%nlArDq6Vz&-2I1%b>4~2*NpE{MlUl%xOuW|7z`=$S8 zv!ih3oQ$GTPU7yanp#Ot_<>SY2{sOb&7V!xW`Ydv(u79v*da;tSH&mM=CoQ>;6srP z&3bwKAFfz4M^e=66JN3tcz-)BkOCTIg`~4?mH_9`JP2I)5Od@IWG|nRQW0sF~-QEP^);u zsOCrIAB{OS$&8LEuMcyglLcKtiW*ip=>lG-sQi-L(E(SJ*7(ugeERMmAA2M1l`F=T zNXk!DI={Wkbj$io-Ie4hjf3Nk1c`cB={K)1dZDXF612(~^~q7U zSd#>Cq0+~4&8$z>i^>fCd&5QT@58q^8#vc=Gko*TUr4@mmm%rz;YdBR^Uq!%sH~^b zNxl_($D2cj|GHgM`d{Wr@v*{^YVT}ZE%@I5@yH<(be*Il2)hTrCWtL{IqS^O^*+Ig~qf&=K$^A;o9(#;YtP{V8NXUdE?IUJdoZTRd|1?UK zqi|tjKD&+;?UpD*FU$QpidwuQ?cRm{v_ZQ~lbW5v@{2Jqzy?|QLb2GD=XcC~8Pma| zGtL{@-P0Pv`ISxC36DN=e4@m1ABA+Ax73hZrJql%n#Wl8n%bSy-LVvVKgl{5q0_{8 z$%cJ6xm&9C!_$J4y+NJq4@_!o6PoDP1L^4ZW7m!3idU~$SbUdF0$Kg}+fc2^Ywox$ z#q%NLy}6o25Y8r{GH*_I8BQOzQP^TkBH3T> zSWSZ^%-E`|bKF+(bL?llu)me*s}X~ZFAZM=rDuiHueoQ9hecgUTh*@#N)g$y_x4lP z8D~VkX!H+sggv{#flc^#ar*b8dtDIg=Lq(@D8--1jnSS2pS}lnI zv9%X%mx+?WLVY}(7Q#*+y!SE1A1l^xy?TD|dTV5wGmMb&L96rh+F2tZ$xA5lh`s7j zgglP7b6UmBC8htdB9Q#AisZyHYRd4~U{#X4Dx!Ey8)>V)Xk?!Jcxgmir3< z4GxA1K!?hSHBCJK^T0MjjP+Y?tKUnm@XSgL#6`6A@;vL^OexM{Db;5E1>`;`@2~sB z|3i^K9lfi2$-4VEYN6LlrI=Asch33U$Fz*X@8)=y*TgGL6s#gE`~$eZlOxJAaH~uh zhq$F}*tMx=X9KPx9E$2&{82@Ow}}1wZfN{X3LDIunmunhsc9|WWd3R4=!bw#sw$Q^ zn$(beAz{rY>Gow|{`iGR5u%HA5IgiIx9Xt{70t7w7td7HeDxTZ)mF|)TxPNKbkO);(L$6knh6@@JRL?(n)I3qOpw zu4arwPeBfc)2;0+*2u-U*yC6~kPecV)PM6qgY9yJFem}R9FI-SG8MKK zSsiw*dNS>A3g}t7AcCg280;`7KG)oaM(^4!#`LY#INXfsrN3d3wB9zs&-BMam7dyx zVjX5LNqg$|;p5iqdia+J`ot}UN@5bLM4QF0pxB|WW;Lm-w}>8F7GdHNM?>SY4xP91 zNmCYEtCXEP%zTSghb7CQf4^0J&n<=z9V`kf36g5Cw2q9w#>7FN5G(Mmn8(FlUJq#p zW+-8R9onA8; z_bxgOjksUvx)V~?mHBS|x;p@PuC2+T&#wbblWVlSC$=8U!>n(JC>9aDcP6`{D@L-c!sGl zv{9eAKE<4HqlwjEu?-AroI>q;HrksmaQ&3F8S4^RE*jB#$;*-}sV$Mn@cy0tR^6+< zTWNRhWb9f1AeoH6|X4_V!jXN5N-EuPp) z13c$rrj0Y}(MtZAew(XRQlf~Zzh%RV?ucLyGKO-ZKOM4Lt|mkNga+)vT8`$bAaefg z<{T7a>=+*iT)R036C-qg0R(oxB$vcQ_BN7K13Z3Fb97@As-5v@(F6GAUM6$!G9BL# z5*>hx#>1PbK|sQQ2(>1HqG0a?@bMeT#5Ch@^Q?U*+EeBMqh|KSaVvd#KntEk%ry~AWTH>mV%0CD1+1D!QuM>!}N$VnT?IiMz@LwxX6qNFVr z5M-Ul{veRBTtrr+< z0<`cTk3ffS!vsM*#-1WiP{EK#xc+P|XCUYgA*ivUqAfk%Cd?DyoQt2B4YofS|+W%32*V$(|cdOsN7NFIJ2n zBPF`Sh3oszq410*Tx+&qtA8(@QY(&j`)1a|1RUtZ_roIfSMwJauccx*b)1Jx!H72- zk|{_{2#$guM*KKAOr3g*q5iL)R^iIL6C%K$Ylws6<{ElZ5$_g=VXk{2^nhbT|ptD0Zwob zrR|KI8S>|UWvxvTPMt@b5E0~2JS48$cLG6;0$f#|y$8N@CfgL-P2oAk0|*@mD!Nf= zl4G43*Il21q52(SsCH=o^>7RpP2GNQ4h^FNq`;5DE)WA&WK6k~pw*sU%D)Wuupf2*OVpWg*D-E&?Jf#G>`>&oxEDk_jH@!$ovLQnhup&D6%nR!p*75X5Db9=-@;R4`zLD~`0fKa(7wEG?!o^D zGCmHOnr?dquyRf+GWP6}y`6 zahqMF+;-E>))coBPQ85$8hc`iT)mui0Bj;lcF7G=dNxRI$x4xy^G>0aRqB?8|23P9R@%xXI_z6-uREDu~(DZ6H2??HW~mV_a9rutRAL(>dgikJxMTcn`ZX0lZ~Lw>nscN?!q(Cg6L;%aS z!9pLC6ky-O^#+WyfNBeLaTxYrZ47OjRZ|0G^U&}GGgCvuqv`+|9-5k&-!?gXf!doS z!;|CVL(pS@-%X6D8&l$Te%t8zv;Ok**p{tO(MMv#lM}PkliSqP1~M|bZFF{2UDr=W zCNG{)*Ch$qd9`mn{Fxn{R#SasbOxpzReLv(t&`)UYF|GYo0u7$o>kYaCv1wo4P<;LHHAS}i%9RdQvaRT}d-VE3BJ>ewye6+w0u`~@n+ z&c$`)({jCJ(5f_u`b?pEw&2&4oJ+AOU8BydRia=D{2j6hQ|9v}zLxzagq zU$(tQs~nI-Bne=fR_%y^OLloB&}F+!5j>aYDW(Y35ZUxJ>TRQH?}3p@sbWn@upiHM>}M=%KptooidZmF!(lLd@C}V4FE> zFEs@cA$#aeK~l1exa)PtZt^9sFvL@kFr;gRw(iA4w(e!qfnBASCXz1ytY&S8MJ{&q zv2%5C52NCtcd|owjp86kjBA)=Rd12Y#=wi(>l0IEbI?fblKmXYK=RHKh!)xmR?nd_ zCxKOfg_S+;z(|W}!3;nPKoygx#9rOO_A@Y)*}im7Rnh zz)@zfI;`4+K7p3E)9BDV`)0IsbS>DnCcx;s)k&_^m=elJ7h9%N0Abro(OH$|NKln| zPN12{kvu7q5_7U}EG0e$$#-iphU57V1o@aE2OJLGmQ~J6U2K=p=;Br-5%Ho7<5n1E z*i~?R`KT^|W?*#b5Ti?=`>b+!&X!=Nc)rCwDMn@vd@v(12ZBh`oD^zCLMMVqn{5XI zHlR&GGZe?(X78cZVZBBZGO@IVRW8#i1HtV=yG+w7yR}j$gfpP6JZ}N}xRkWBz z%18{9)CJy(w+%VQ)j7?_)t0X#HyX^NPWzcYY>u)@%~>o`E|mph@|&F8B~^gqTC%`^ zAtiOi0w|C?L&CLvxsJB&^P%L9^rHmuj|3^Uw=k!N8|Q5i1Yk&!0he%&G)&#mSMcCE zAd0|d^u#iK;H`73js_~AGMKP~NR`1Go6t)%#0w@^B4*-rB7t?YxP&67N+5%}1p8ue zeb9F5!SOVdGQeVTtSf~o&4C^>K>@5V4N|nES3({!DkjM) z;mZ|}DXZR{?9N4i62=OYT$Wreazdp6AvS?Z1Me6E1n`O_)!Q5iw;TQ?cnB`1W9cO^ zIS5pqI>&Kn-osZAiqH*=(2)|^@jpFJt3OI;0&%~6bFc$2eqY_%_6{)I9@2FLedww{JR4PB8uw8 zQ1-Aj2bO^1%5}D`)G9^GNk|G~Z<0&v!MfC3I;YVtsaxvOnOwn85YBWKXvL}7GTN#k zlk@4XLR%*oTqhLJ#ZF@|tr;xRZ}3t^_YXt0=egUSH^BY!EJ&3@`NXUzC{V3T_rw7s z5w~lGP+Cl(H6TJ4O~BUfeC^CcsC$+)P>0kidX}n`aO$DzP<6L3x*KD35LRoix&)fC zq))Rc25ttWGmM`pQFGwv%ii9A&y9akk#capeRJDF9EiLbAey(KuCXxD7T17lz*!(U zZKzt+7kx<9P+&O2c$5Y|5sWg6oJ_3)eE*zq00n{Ec&J=27J;9USmqoiC9>c!M7?v(hwv<#C<5^?!oZFqKvlY|6jQo~%vR+nW9 zQrdIz1*SPEc_vIV5?QxqMJe>R5<@9bM@RU$z2aWM(%4_{>OpIJd`ClsQ> zy;MK0zHK%Y6AWOxDhCnyhS5cSuIKmr+js#Oys6es` z(`$^HKEn8v*`Tg2-_QjvZNRw)7BI!p1~>qKlvUP?Yy>7BV!#!6kLt7{7}Co_fFG2G zh+PYG%5--l!sz6L076x(6_9(E2nk%d2pSRrJ4V3~r|qE4cTmB|1r%Vrfu}iEZG`6Z zdJ&h3(@`@4_T@0%`nV18%kk{2vjw=lMrZ|eLrsPIQ{7&Gqw6B=s)f(oFvfMIPlA3W zgd~xMX9cr*IZKPGq_VKhRbLXay@M@k3iNtWUsRL8&TQ~lNb$3L>59gP4KeLK@o4>;o&rJohFr z^HpxIz+7ox1>)gOnC9^`bLlWX+EcKyV5m~yMZ1Q`ufY_~No~tC2(h&SbHYjkhr1Bt zwd>uea2Y@%KvcbRwhqt$m=^G1JFHh=k04%<1IKTyhr2VtyyM_(b_AwiJk4M(?JE1J zfpvIvQq`6}Loq_r;PgTNj?dLj`nrH!`5H&3Ru;Z)02VH4nf=qkRnV_PYoA7TEFHp* zn7IVF+7q}t<|CM^vH75J^u&O3K@Mmjtn%EGc0W8UN(b0!H6wxPaGWoj?$;J8c&{s9 z7#Lcw9C~0IJv6Z5e5a=8z=43^bSaTMwY0K~@hul(jHrbV1i~jtAhJ9g7Vy~o@)+b5 zZx{VcQq}X=(?c+fdh5{q7F&VgmYH`c!!4&SNSh1YQ>_4^>XJ3Op1{)i1Sz*y0)+H) zi_oV>#4mxtZ--+Jzbi9-=Zgiuz?B;=b&eKb}V>-W)$>DqN=;obw$nvIuC#wk8p=}&Fd#&U`2ReyCjFO>{ z)8nV*>XAmv)w>pAxyhN_$|2V==sAk#PmX8jQLJG(&(Qze6I%O{)`QQ!G_&YhSDS2= zJ*2Gl0Ch#B!OpFENJV3ZNa6sJT*}LKE(fME9ca@+8WA(X=(yyB2COXqfB`#(ZwJF} z>ch~`vw*?G)bQleE*32$S+gnSidF@pLN{w0mt^L+aFhncjjvhFBndPCzel^FoqbikO5(Mqv3m$O{I7}*(4LypJkTlDp7OQ3E6{Q+hPCO(+QhLY z9*I$$#XD5T5=kY+!7}xap*V)}F{!|qlz$9vCc?y1e0F>+TMF)5mzGbrxxnk=V(WE^ z<$HQPFe%oBOD}c-cIeUyK`^Nh7~ThgxDXl2Zaw09$kSE6`&suKWzUY66W zi@zF*z9%7y{O}(|(I*);sdDw}smP3(vGMuJWhyh(xx_Bg;C=x=+RqbSa!>OM1S3t} zv_N85a9fImOR7pqX;H-$5*?*pchK^2Ep6njTowEtJm(PiAm%wC~{lJoEQ0*Ps`~9vk5)yP0SQdsu7l(L4RwKALc&31pz%;aV_#%aC2HJazb$uYNatE9ZiWay8iPAFLWnM13&Oj!QS%%8o%0OLDt( z2g{@opjB#)b43?NJwPcwpsT=1)s=@kAWus?RW2M5>P)gbR082TZ3!KF_>+g>N8@zj ze@;!-`Lir-NsP6h{7MV5>*x`gp7{n+c$&)(7m32N*sd`G5-i)1t2ckoG!=dfiVJ0g z$_qb+2`=S~R%oRqrbZ;I95-MKSiwDtB~(^T_D~vipA2$w4!Dx-1Qjz&Kw<+NOW3GA zWm*-_kP9CZ4{MnzkPl_EmhOi*25ldST{G}2h+U>AG(4tK>N6RoN2(Dnb=`xhX&vhy$u z1|K4cCRe0LQRHe#@lG#@?p}2FOwZu4+k*xckHKPSEC6F>xl7Itq1)ZJyD!k)x3}+Y z3}%5*tz}BqgH~jlCA(BCThYUIQu0FyWlM_UpGC=u?NU)u!b&+Ql`BptIpwI5RKikK zT&(2(9_O5U&bjw?_W)QdA9E!xrtdwE?|kPw-}%mWz6TsH0OHM{o@Y&DzU-3iJszde zZDHuOqRn6<7)N~DBj2N!!GJ7;`ORb;2IG1jEmrg5*E#vIJNCt8a=AykA^F4Wk36U( zbx8R#@3EHvZY~jw+?F5hieE6Iu^0B_xh+($?|9?L_;GPECS`T~#L`kZYy~3^5Wxq5 zyfAR);q%`cFx$}N9qej(NxmF;UYmXn-H~V=|9lah1CWFE^7MN%=zC+j62P*N+qx|Z zODkC87F|DYOTCFy5HLO(z@HRGjvifD{9N&DeSF`&-!TlUr3&3P%PmNy_fpOuQse4f@JEtR6Db|=U&{$0NcK^P9S%7wWzy&I> zI{eoODqd&#l4-WcjnOBeV#A%8ehcmDf>y+=t1E}nby3E?qsE{OprM;nT&7p?B})tT z8}Slvn}Fe9^`bacBFk$J+#wvu$0hS8Zo0_1w5v95>_sw44yD}&EELH(8X8auYjM8K z(wrcS()tJ4veZ`shfX4o(&Qc4y^6%q)v7bF@m4X{adh;LX((2J3{U=+hQd#i0_ zP!ks}-=j-HA%zP~X2ou;%t{c}U|JCEm3eQdE1Kc)Uz5U;WGQih8{&;DB5w&LV>4%B zWc-5qAf@1~qjYj}?bNge6B$DrIG7~H1CZHWRZ&`9PD8?=u z%$>-fn+s3;%Wl|9od_0r5F&dfNJMEsA-2pg6p`R83H+ zDHP}gTWU5Ey~Ej6_AaLpUyktlNKCZ&y{i8ZMg|IZv9u#^!P8xOjSbC~zF2aEgReil zX0P*OkVfvPw^GNN^mAn z(q5A<*45CO>TJRL$Si@(Z5UM9ltgs4t^U?7ophTsG&?WVo9djBZ}rh<^sIRv!FNS5 z4dUghtL$9h;M4|2DNu&C1@Z)nS~2k_G%Ze}XR}vxJuY8bWk*1(Fdm+Y}1c2;x5yCcZh)q(JMXKgEAuf4vCdlv}O$^)yi)hDiFeHz`Uo~K9 zxg}DQu};YcAWFJ`#wK92$p}qlLNKJ-tn8dtU0ZaTFv7~#id&@yG8)I_p3yY!POKKR z;ZEUhXCO8AJ0o72Hoh zI}p9f%TKW{tKbc3rOUZQ|9D-8_nNGpPE@k*2}m=WRf^Qe$~MO8CHAnb;_{Vyo>>U^ zQ}-&}mQ4F<8sK8YiD-aoj<#V7gloaLLl)~#T-D-8iq@{C&kL<%_GpE1vA?NQ!@jdb*Pf=?3+wtHS3iuRYEW#9CG&%IF3>z)lWpYXV$S3C zYkuO}CvncuKW!};S^-JMnkGVg;jUSykWmMzIi(6}I@;O5o|S*q#TA*l1)REXCHAXw zabKOt3pWtvbsngpSgZt|My1mc)fn6CE7vZ}Eo4M-7k&6H$T|RFI(6B#|VzYTQC5BTX$Wq8J#f zy_7PS_FiE3mt_Cby3;vDDKS-LIl9(ab=55`kT{Tlya}aWC@JedEBnGqYH0x`2TUlH za|WdIF93nGlwpW#T?x1#>ALlM%1Dy>A^zz{A)+I_{vxf4Y3*$v})AAUBOm9 zC9mxlnx&?xXhBzKUC=vQt5<5P@i{$PAY4cl@*a&ycsB96o~T~#G!}~}d)-HFR$BDM z9l9o}88S#Smf%y^`7`dZbcX(nTPe0JgK}Ni6CvYHpIAOAD*Tc@EdKHqj*DfkdQKl1zr&%iU}`E|XXpgVkA+&_Tw*1I zR=N-Lz=rZ6C{}Hn2K#5N8sNEvF7*`GE(K>|rH!5G!dt;L)9Iq|j^t&4SGt#9oil#x)Km z!*;RQtt1PS7P&ei?-}*yY7&IA3#$Gc6LJ53M&Z-}pY7K7)jCwDC|K*=W7^-VUJ?th z9Lwow@RDeFMWJCSMgv;brlG;x2g%>RpH(`Qw$6I>{k2~rV>$tD-8-iJE#qp@rj&u) z{hm6GJsMX22zMynp0ZF@$)yf(+EMJS8=}~(QuZo3i=&!8OYxs+myx)!R43mw9WVn; zR}6gWzk%(#eKAy{v!c;pgG}SH>MK{*6mRw>MgeFwT0&J8-&WE-$?<2kXk2c23uJ!5o?knV|4yJwNgWK;AOg1=^2?qPwuMwY}OdlFNn(Nb;KI|1q{BqgPTGgeCKCKIgAz<2boSWNe_6mLwYjb2J9~b#jknP< zey%3y@urW4{2{FH@MS;hSzm>GgZCb-o>yXZ!afK(SF_1Bo?$>}rzG!PE`Y-m&*qmD_LT2vKNFTUIK{LFxdEPyigcGIgBx zePb(mrkYZNZcbY%hosaxnn+fOYw2%iRTDv}GD?tFmffzBe6uU9>h>OywpY5imr1jm zRFYb48N{eqx`lwwI2c@;M4{jI8m+y|skS+p;ViGzef!!9W^=a`zHM>#>HII4pxs~D z`YdEV<83L6NO6Cdx(vlyvS;7gC9<~xQ@)M)XWwmky`bMl>#fXBac!MWa7r^MMaG8N zn<<`=*=15DllNh5X)#i6W^WwUg&7_fM7yO@6Xa$3yJ3Aff5&Oz0jyyjz+&JW zvO#R*n{MlNmvj+z=jl$TvzkA1dJ(FhDKHB3%Tw)Igv=C;n^XO&fxoIlMtsaso+0_A z>e5mzFP$xFYb$%)pG1wk($aQDF*8X?7RQ_in5!9MP2z};F7Z{MII{Nqep@C}nK{v7 zC>iGxq&sD!wK~rt$i=HbHciVw{Ak$UR;?F!{lkBzi~4h}1knaA1qHv=QCw;^mRNN# zjZtL4#7tp|>N@dJ>Xa86`OBLxUctL|dH*Rq5zQ*G)4whB#+R^JA}_|algG+VeDG*a z132+91~?}m<{-nun7E}G5L4UcXoQ=o-KM?{WlWRPQiY>=OqG&Vl`5-&;qfxR9#gHM ztCi+%&Z^}!I3Fzl6%&9|ob9ILOgJT{Bkg5jF-KbXeSwUsu_-X)=c!nGrIJep^-%+1 zVvbLdQ%FuuX;@>9tk|hEO@36mz=s}OROoK z8yqU0)k-Bd6GPIVW+p_B2qX(fd!5)^JmFZ-+MoMN6CIOh?kPie^Z+|b86zdcI~}&N z#%CU(>}%3H(L%>#(y~DMQI47GFdH0!GdArNh>8ic^JZVs8otCAZQE2|DY#W;w4`% zDm`G?Ew|$oLFy(Hwp}Q@&bL4|6u43CmFOBR1HOg<91Eb+Mq|MVNc3FxWJ`Phc!nU9 zWV6K-3@Y&ea*E;dHE?fx>}rH6A!@Qzq8k=H5p74R=yj{jR>{nQ78{=Gr8;&g=_nyi z;4-NjpNQiOYq1|I*Q8iEZA?F8ia;`~zFxM`Jk}Df<#sdhN%lD#!!ifmBhtXc3K*3* zu35b);Ih7~n!n3UiH3*Ky>JsLsuz`PPnIdoiu8Fy#+3L@4%DLt@ummr@i1qE7N|#s z4AEvq^F1K>4yOUF5~40FJJSQ3U!kYDGj7}z2;Itx_r1p`F-4Q zM8RdhogLDr+Y7?X2tHvw4+38qL*@&s5dJ!F?}|`ilmZBTa#%I~)ZImqb7K4x@-81Hb<)uUpR@7>gqv9RD)wciG!%r7d^HFsw?xR!G_M{3)J ztz(zxO>+JE)^=Ik&_JUynu}W{6q64uPukh|W8MtsLT~eg#=Y3xQ1gpb+3TPk;F^mq zcX-DQ<1}+d@;Q-n&L4Ca{Zi@Pq7*6Si7$j1DWu(406@7`#2?c2#~S-sTFEj&FehSb~vH0Y~wA zk#t!_M9*d+tij11V7%fuCStz)dH`dnVZxFT<|)ZH`vFLiit47IX(q~JWT(PhEb;xm z*eXEc5r5skUtI7qLRF=QRFJz&{T__WtT%)m)qV%fg!a2IU*56b!9E!#D&uArCW?ko zc9j7hfHi@K09uO!4yoh)CVHwB2Q^wG9I{-!*I?&yV zWDg>$Kv~(tiU#iOsdPo{21wPXTQZAL``9rVhuFhRM1x`rljfDXjU@B6=gKJ@Gxyj^ z{#d7UtPu0y)x~fJHk}%XH~>Ud+P>RGn!{N$2aUOxtZ4!8EKz~3f{WdfOz;8B7Ua-#cm2>vPT6bpgaxlO zYLV#l9bW{>6x}9fbj#m1XFeyU-YV4a>}u9h2z$X!F|p|@)-L_+&E=XV6HF5ZND#n* z-I@hY`8H6}?FP;;O)t&!{ZP!ZUpjls+#>6@%(&^d8e1w!b$OAS7{;|J33PoC8buP) z-U~ioU;LbRM0?G9MxB#MZ&z;x{;-$_lIRhs-74Rn!Ko6X1)5m3iNe6VY)~$;IXRjz z*4-eilVB_J3(8eYX9JXM>};`3K1LXPgO(?GKH;qO8sy(m!@}B=XLos6ka4sm#2|d3QIKciCqojiU@KSy&Z<3on4UP+ z+BW}bwEx632L!!eI|R)9*aR2=(J1k2Ji7#=E9GRNo`fa&@D z;+=0PwyQER(I zp;u%C?UKtvyq+H@8GY5w2+r9|3os%5K9k``%DJ{Vv-CsKo_3m$7rPsDkIPY8y!0D! z;nb9I7rZCqAz8t`@}>Lt7p2{o;QQ@l)Z4Z#2FIpi2vRG)zHEu>%hkj=);xQncz)fi;OT;Y|~Nh?6KUP{FDDBWuvgKfwP=AdI2b*i1rGBiCH9Yr(1 z6DJ%aAX3o^-6(>#wD^WtY@4`pM2tqRd{&tLwNqDi+lrA=SEYCCg3^Fv&pg3wJnjy! z&l>(kztd@?0#Qln#Q>+0*(>F`w7PBzk7xGKC!-coOVeD*q=be#3(gzE$)M?t^Jk6s z^;`nC4Dn*}Jp+3Ger?rF3PB=!7z!4q4J?Wa>9(obiVQ zlH?|sYs&kGI5Ke}sHmpaN(MC5RcfIko}`s;7!weE1U9*#uVEQ5a;i?mOo*N?;IHb) zA@3WNhCH@pm*a1;7%=gRrFr6^%8<8eU*w6-+-T#u6qhph;*90fhf4l)a=7XsCj%k0 z_0t}v4(XtlcH)C95%R`NMMPGL61(CGJ|)dia*AWMw27+}J7#Hmt62(Z^H^!`LDyO~ zj1;9OUJ4#7woJmQv=Xe9v)0_dPY$^37MazsihX9Z%XjyQX5qDLRcYPL6F%qGkT(V$ zzGN49I@)}pEA~XerwtrvpPA3=$W#YMLE#Gugy|%_m%%WZTUrYA>;u$vE{XA4b4?pW zT?SA-AlAarmR53U=&{jlSprr=zsNCIN~I(}X*88>1Qx@oDVKb+t@jeG%NtAM z#~GcPx@v0U2JyW%fm&6XGrfiwAQ@p9HRMoM*%~ob0M)}6B?Pwet(2hP_QELVgeGt2 zzSPsUP;girvYse@$Ij=sOM)Q$iaFf2{Y@JfAiGs!O1o9DkkPTesbRynqT5&ysG|7y zYGM|+BlLtot`O69Yzio{!UO>uST6Is) z-R7z*74@w-#Dpz(JB}#N5!qnZmSVW5%Lh~&^r~)T78ftfX4kKKlfzPHRX0-!VdD7{bqR^j{rL&OPvwj zGA>k0R9nGndlXJZ(=ntQP^4N;T+xS|&lvW;&q5s>B- z>=f?VT73xv?VVl5;Ci|wp^k$FfC+cQw5$DN?(EBbD3hj7O5Eyeem0dBA9ZZ2fY^gc zmQZ(K&G-(?7@Os-m~wxhMc&t^Lx$8Si(_g1p1vQKRSs;!BQvpm9Lu>tQ9J21V-%!s zNp5*++ZAkjXf%!Sa22c<)-s(%llq8C3mOlz8lO@57*+N%YCDD{kv#TS!}KK0 zWuuU1o&8;m_k%`$J8wc~I~kn~_c^km-cD}6LmTdMXv2pXn%K(eIAhVQml|@ZS>AHv z)BZL{x(f}d2av}xsUK*TwW4OUq=}yrC@Ixc%z9b&((K6Q53xjoN__6nX*o&Va|UE0 zLs>O9gg143Eay@pFL}06t!Af`kL?$;Y?qr2c{i7^V^T*2H+g@S<{H(OO|7==#wrMi z)bI$V7uzi>eJmzG5!^xhDtB-CY=$Ur+lmb{9C_PPPs9_MxK|)ws?|7YM6(*>4#WI3 zZvo4vd^FkzJ+Tevl#M@0TWg~s{Ric>HR_1n#AEF0U&=Xs23+{ho^T$tTPTk$`I*)q z3$K|oz1obO!DKpClXyFgq$URrc9NG{N+_k4mZFrQ&l2-3gU4GMqmEF!%9|onP1TWV z+C4ZasxkWITS%9FI$hqD124apg#w*Efl3;{RmP25M~~i;Mo_ovx0S@{rWkrCYpJa~ z4Gz{G;~>9XPrMR2Y?*AgSH*mfV-b2-4(QlZ95!;r*S3Ofj+)&Sf5GuX)_h~ZbEUd^!9E-Z|`R5?OlUqcK24bBeR>Ww|6aum~&?m#wXIAY3h2wa`!A9A$rUdx_cm|mCE)1=I zW4~bw5Z0h};^_AYX~HTh7;=i}kcB8q0Lh%Gz122aDoC>Ph=`1Hu`e~A45BYcVGpnW zjJq=q~z|Cgt({?`{@q;4sjLx%DbW!pJgA5Lh(RL6v)Yn_{uiC4m*>Xp#LG z#H#BhMaOQV&93Vd-v*eWwEk&Vxi89%rr97g;v)7&CaT!4yXpe6Su(cFhTiaE%ea+u z6JFdFTzdpH1~W2%CN#w`3w=~N(6~u*4fCY|s=Q;;ntLV_)QGb5S6VclO$yJt6MdLX(R;!@`zDh)WE*F zYL6=W_(QkuYgz;egwVC@`zL{pNGWWoJ&Xg6&9ri(`M18gq!!SZ>4?o#<-yAAgmf(@dfRanqiK*;04;^Cpwr~mKNE|xHM}v` z@RBz4oVwi9O$p@1WxS}$zT9rZTg%SafBEl>7H0)OUwO~atnTV)xBCY zOXEtI64m3P@AiZ4cXCJ%9>M;@dFX*V94CIyZjg!M$`57ExFBkt?GK8VBx8oO@TA<* zqlUC;aKNYHU?7tyxCVo)QyhB+mM$P+GYh?I!?m#Gjy(QKuQt8Auu0IL`7*ahI}2p;V89d8ptXe1H`{<8U4)^mrclBWSyQQA}+h_Xe<`!sKFfv9cS* ze+M0rZMEEj^RLf$j2$0Dfe9(*lJRs~nhfH`F`nsE(LB9$^r&8dFFZJjGAgagYASg6 z=t9WDr>IE$GV&w%o|pFQD@!w@lo&Uvn^@g+u5zOYW9#Dwk<3Nx1IdaDTGIHGX7hQ? z#9R+XN&6A?fI&r!O84*Qk3L;HxwM+6>oi4UxN%Z}^>(aJL`^jOn)tlP0Nr^s>=E`m zc|Df4p;Iaew@FjV;f~OYktsa>tAfHdRK_>3SV8Enxc$D9Kh~^j6k9T!#$$6CiBY#H zf*Mt7GQjjC>ig)T55mH2Zx<+QsOhEXcB@%67S7S5K9;-?wDmt54MvstSzX(>aPImV zo^Yr#Do1?`Jc?m_E_xkz(x)uX0sNEr6FHOw2At>HkV!Ai#&bqi8h+Z)aN2cxW3SW5KaIv?E=G5m)@y~P#q26C z=>%s3W`S8}nhSEzY#UEPUWH2KO$Xy%!pPn%TdH=P#h;h|~Gp7~j4gF3)1392v+x@R{-8mE-vx+o&YHI}Y>26QA-mhNF3 zo0jkqm*irbNC=Z~t>>kB1Pm;IT$+Rei1=@%kpV%4xGl9V9^5a~t=Rvw6L3tvB^0Un<9L>lww^ z7ho?jO$@9eyKG1apjE4J@-I%qtVH`>Ik4tkd0L1`*O{axmd9Ku=AJ;DG_hxg-j0)k zNdSqCB>>kDH`kK7&~K-)xtn6q;B~#cC5`nCI69IUoAeK`0$s-B#8XX4fbD7~4~ZE- zM}!g2kd-&jotFtMVY${pN^i#T>o8k)7dF~H1`7c}*dL?zleFdPB{2UeF9=&Ch-);u zoYJ)udq3avgtS$&922FgNvrKqZM||gqcZAcTAG0c%LMT#_@<|Xw*@U1Z9U`gDq^qV z?HXhq&zVwt)u5QgMrP#%t6nI!35y~& zG38IS%X;WZ88sWT_}r{iKwT49*3bTM(_%yLd-;gwkd_x22`(bE&PG=r3` zK4D7uE#Bk&dUbvF1l5$CYSxi0FT%xKP2oqV;_)4D{1uQxc&|yU7aSlQT|u+Ok=PmMVn2HHWMxiUP{7f-OIr< zuU^t~7tP8@Ql?Z9Ux=={4V??AOS*b`=*G5w7?G#F zDN81k^tIT~N{-R=v&#Ke*Wt#_wXw3cqnvm(buP$3>Ia5`k|Cen)DwHG?VWq||%Q&oz^PQFy%a%l_Qs%>xc@sMR= zXroqY!rMj@U0cLEWKH2)nkcSFR!$eSR+#% z%5q&ke+(MYYioBCaCR|ROdSm#A9KQ(^N7<`TRT#% zQtm*Z3qdZGV&-E7qiLqZ#phdJc@M6(#wB?}z9b{#su(iT@X}32gK0KWn67!%EGi?p|4lbVl=3^N81Pq{)7~6BXUeG0BqUd(wG@QiTNl_PYLCjF7IG!+MKi zp0I+ltgeswugRz^?z_uUcULB*L|zLKU)Bd8CBkF!N~R)U%EP?JVouJscW~p-I12Vy z7F#Oa3voUMUNDJtg-9Bj?D}ZE5xcLDCNixWqr-3;6oY~4GG?w&a~DfzQfCM;i)Ymu zDg&%O^8%ALUW^`z2Pmf`)1sgqTNJeCwJ2!gDI>+A0Kk(;S{XP#S0rG|K7y2lT1Nyk z)<_HlJ_`RjU3(`a6xq`h8xTAEiu6sAR-+=g0k8MHl6`;K)UGdAEdrw?7_m;inQ~Jp z7o|Bul{_PE3l~Jo!&~Gb=S34S9#n}EkOkfv*+9fpj+DA3M_=X%+Ai6boH5Q;-B@|a zv#}(PDrO(XHCudXCBjoCZ>;DwUAzEFdg&)Y*yrfd+>E)?O2*tlrWxOp$+?w(NF!?9 zS*dJ#mg%2Rk2FVXda`k=HT_e31ADr8ww1{2Op$f!E(a8)(^Sk668>;pO6u`dEVJ5`Ct#}H+#&L2EJg0%3`lHAR$E`-5ZLce}>hbC_ z9*3&8!o0Y|L&eVGE%%Pga9azNii2e3_&ZTgSc*Fn-x2zoN`(ub?)$^r z!c0+gIq@;^N+0>o5Jd1r^}0ewmnul^Q7}N>mIv0`$8-8FoWpyb7a0&zfq@4dHqiFL z^M-k6@l57Oq1%j}<{o`wM6XSTezd6l_t8O}Y{L{*aiT}W?K#q9m4>#N$wl>j;CI8xM)k^@)O9GmF z*@+u)sjeX8V(w)SiltT8I`5C zx}!uCOn1sJ&+o3civ@#;7vOZDS9fVtb*I38=!|{T8x_pLBNq+}VcofBgYN`G58Aln z_9tG=s)SFp6UfiY1>@_U1x~*o?0D@plpI3x$8fd^(cP#}rt0|5j@KL%w#$xD4`rq+ zKH#?QJm);))RvZyTP0v&Zp4LZOJ={paD%3%9#6F2hFKRgS4xi9?>I&I*=aPK!ik6! z*#K)wX@aC(MNnK_l*Zi&uE8x>f)g5o1$QU7y9AfUCAdRy3+}FsySux)YeNrz&1Uwq zdYfCP?&ek9^Qn@okZf6Y0aV2h?R+_m!Ms%BrgPAG6#U?@mP0WY0_T~_-|3wW7%c7F zXh@+HlOOnirmc^j%uZ0W)YTtqF?4ZIgrI?nl9OMC-S!G+5N|*qWoa;jtl;r)>C?|I z{D`p)ER-rFYk?@oSD@j^wcl4~Ed1_hy#3+y^l(hr{Dy3)cdPP~9lOw$m_AE%D_VsA z4z72I2^;E~kLo@3PPrqHr@#di!D)eA!_bVJ`P*|T67R7z(M8wg2JW8;BVY9POdVo4 zVFZ83lq=ZkwxKL#jLSw(n$U&0cP!UBV}|^~BDC|2<{=bsTjI>f+eV|6IBLlBU%iAg z#v;kkF=Uq&1>#GMn>ivS?Kztw#>GCarUsM|`I&@ri2Nt)IZ~Wy_a1<=tmxA*j~o+x z=MzhviYU$Z@T1vgOdAY5(H~uQ}?216Qd$& z`fWXpt2wncL!F&`x8qI7OlA{l2I?;&K&PI=<}1S7MXWH6@$~1#P8wguFs0@+l6XE% zRN(jylV#Mzs~|rsDw3(QBE5Y8s!ZZ|9Q(C_vqrfBaLJUe?{-poxZPsaEA{i_*=Mr= zF9bopYo;dpFqPrMtMfamOk(FEB}ck_h#tCTAa62KRRfqv_oU`XrWK)BSH&f{fnSaw zUuIjYuqi{^0Op%}Wdwq*L|RT&QZDP2*Hp@2%`}nxyfi9jA0re~5WMF0rY#W7noF1n z?=XC)CtHs+GcGDyi7)^+!KU;8bFFd_Gi2SWK^pS=4dZIyb2;r+l(0}V4>_W-6hZNs zTdtPHXAX4jx>28YHzMle{-|6+G{heEAoB5t3@WsPnZl%#VdH)Drrqeb-N6w8&t0e^ z_raJP3pjct()p#p1Y5!+q=5P?4GVJ*RDShzBdr;!bUJArC0I9al8x5SEL0Q(>eEYa zKbCG_e ziQ)Z40Th^>*-`#kJsC6vsQm?rQG6e(=S0Nn!0;cKqRUVv?nX46#qX6WGCGR$cUtPk=G-|#%AW9hct5PS#LlpMH_+db6=nC0 z-Q^DUdzTx~1M&BFHcavd;&jcd+5Nui53>~!z>~oLli+XBy^x!N$Sp$tM5IYO&!7`f zG-J-)WbwODi9%#z3LzC=K4R#G_^y!#)1JL!PJxdckk5{U;I>9kgx~QCq_8kah0FRq zhAoqS3Ia%`Ux3K;gZ@F9X!)Z|qb72$^S=7k#bW+Qz{&GFf9;)yD`cwLtmN-cdD|{g zX5o#RSj&O+S#ROq)2{xC5)yN$wyd|;8?E88@bmPf;dCOxOyOclrJ>aEc8!NQp~gV3 z!Cm4?WmtaGst=ehh*|%hLUH~A@YqT0c(;~8JcZN{6)qU!it8S#jNpz95_&YY0Q+C;AiR`7^a-;|P>1VL26dX^#5>6BQ_fml8lFVYotfwH*C{pa=hVtRkW zK{LeM>%b9S9xDNn6FRl#U4dpFlth~d!B~K#Lj)gQA(yc_S3HL+{2tchBMkek%lCPs z?Q3`Ggdi2~^9H6<%)Ubn&)rfAJ6VZT>RxLCnUIY|UY&^3=tO+Z`F}MJF>1Mw2bNdL z?BspK)(e#J$(-i;EniV8(jQnfIVpQ3*M`{?TGXWHK1(tgjCA>5)=&>}wN8>tp365a zUfl6_{73`X%*eU6;kt@G;WxIOz)n@s3%OKdc(3Tl{l;x|Yj^zv-Sv)0tb>B2i|Xv3 zC(l-Bq|9uq|4h=JQJ=^7(bI;u)_mA=?}&_=znWxB>5e4O(krrZGQ$-4mzn&Tvv8H@FgV;V>S2EM!+Q$q(n03_7z=b>3rt;JDab$?bUIaOP@I> zecSF5P!ssD{9}FkZVL|UcIYV?<{wuOqig7dqeZS-h}$&A(3d>EyCz%)5@f>PatJ-d zY-#P4%e)C%c6^1TTp4-FS*#G9wvaWp2S($GScvuLDDpGV<5>6|$TE3c$DZA?Msw!1 zQQZ6kjnhpmEpOjx=oE|v3r*4T+_Q3^?*CZX<0|FArA9~?uNIUha=}iTe)%wPgTv(Z zgjDr}Wz|eA8|I?o-O4Dmwf)ZipnDgpB!$1pq-&sXF@ooWPo)EIj=aU|-F)sPU*izN z8h9eF*XmuTft@v~|2QDxi}}R><8oiKd_L6G@@-^g;I5m?A33K%qV`T5dQafx85&n1Yc7jOU<{RH9tifDA$oV)TQnAd5UaReH}m`jDMVhz1B!0eRHfe44fQKDGxQpX$E` zzE`{_Dg5#X3e`D`)S>dM z;JIgw&YPxpFc`DrbYu|2=cotM_io{$XApR{gGu`0k4o|W{xRzz;!@ycTEW|7`+N5D zk-$R6Bl*h~o6o@;(Dd8~0L}`=1U-&UC*4xKJlR76fu8#re)|?^qYCUj`Hn$IkUKg` z(knCu_fJCJ3Icl1et+qu2LGx8KzJ%Q-;OE3 z!@%n((4#$p74S`8_xaUcVD7c>_VRgu4dk2u#It(oImm3E;eDy_egwGzE4-Igb-rc; z>sqJWcbjAsQeG*Vb%#JV+oFKq+nEaAecs=v6+UG(gD*rcgB2X_zJmVHw!zf$06LI|pvs}5p$*T?(vLqmz`|i5!3sk2Ln|1Gcw-Rs z5dgO%*uVaK0z5xkEQOZ%J$tCCf-5r*fmU~CuNzM#qt6Py*B=)G3qY(+H5Ovp+uV^W(f0b3{lAG=%7Ew=O7%@`-xiN`+e>x#p{_$_LA=j;sW61(K*zK z0<5^*U*x>`n4;f)6}S29*S9a3&`e6rYM3aT7&f8sOT-3yADYf#8Tg>qg=-Wyd@-Bu zXWvDY6S~N^MHqgA5zm`L+Kik-^bh_38VgwyF#zEc49J~^A<~gZ2m-Hp002|`dg;)A zZvs$cLUioGaGaN*+fK;w3#k1D_i}{n#ajQ_`(htrTM z4WXCmQ-$|YbKuUfe)H3SHOO@@W#b);m<^s<)%QKdeO}0=7y7*|YQO5fGYm!qxLO#V zCs6oYR@_Q*;|pEy0>J)m`kwlyyMU*g!EDcMhvQ?7P6*pCq3qWg`}c9YhWooaqPH&zEX z6|P*1fs6L{VP7`~uY>INLUtgVR+<=DgOD@hw`}k7Q{cYA8zB17;05PNg=aI5E;a)&=vgD4F*KhdzV4;x^K*wQ=CGU2bmyb zSCGLQ(jnmH>ZH&DgKpzy{H@9Fv=RTUY!^5u|S#Fx#% z8`(*S2(}rb-d@k5h3d6l`jZ>62T`!Iv)kT28Mc**Soh#bnS9w{v?!ZZd%Z`=4U6~@ z06cUvLeWTtLLrn92#IiR_6QU<(+XU~jeaacBC;d|D7?h5tNtBDFAll(696P)-UdkD!8-Zgw(asyAUl&BO%Q}jW+Nhbww z0Zuwi>y;Y)sa=>egXM3)60=iCa*6`!8bmPpQ18NlT(s$c@!Qui*G@G1HK{q&fh&wa z<+96c6i?B^5Q3LqEWdd#(RD#F6m}lQ-ml&S`X6#BKaj$}9iDjT%TAsfYN!I zKznG1@UbBr z?q5-WW;0@tvF~kVFEz7*DPo9#tJ(!e_N5`EZpwl;co>V})83FPG)deO({Eua7K6MLIhGi?SD`P(xsDsL`iC`qAa8l=9Y2yOc|&@)Q!A}tw` z2vvhE0vaNtuS1^~20B9u)kX=8@EJx`n#c2lg+KERf7nls+1-`X&x9`RTer7_z(+|SW zwaYw(SsRyHwC|lPQYfFZ^5~iV)vEH_Z%?sCw|mUlxrZNKsNWhqQHieGX~RveW3lIT zK^erAwzyg?i9oNzmSEr#7p6Ak0;jGt^Wiq815+}Xbt4(G>877vxp9<6U(c<3#@5w=Sa`-j;i z!7)3e>k%OjhaE@RL{%r@nviL;o>&L3KbLca5M1*Ibg}7%qU_cikvvEBxjIk1it@DM zfLHrFIQZTmpoGvTr?aG=3hIIFwvSxFG|rqW0+rDbGEMD4#gEBIw8}~ zEswR&}6eYiXsx6co%euOMEE2&*VEeFD!&;{>rY(9(!zEunv<0@jv9{(2y9>6=~J^IH81< zj0iH_Qa!&aBGkyZ?`@1$|NW$mnkb=={iL(qKWvbwVZ6PG@smAY>d%%b3nr@$*>;DG zBPxdc=qi+nFY2V?=!ENr2(*E8k{4ynLME85pILhz^L_Vc=2Q^YVz#Is(Mz_QanS8Bz2jTcsx z#EA+>x9#=#6l6}GB~#G!6p}Mn0{b?(>rP|;c@_hQ5ze_q=-~tB<(t3uBb-TV!BhNe z9sAwLY!^ws%KbZ=h*cGD#@(waA_P?iO+m4G>Pkb;M0&j33G+E(=w3)4-Nj(tzQ6EI zJ*VfjLY3jHX<)%sI;xz>>W+>IZe+fUG1KZx*mJzkW!=L}phg2n+vEwt^jTe{|GCe? z_+j0NvMKMYF1(g8&JU8eU$GBLFI{6zb4-7j!9=DciDD>G65al|q(eg8%}nXd+(E7X ziGom2F=BA#64hY@1)*fM6j{Hpc1NsU6OeJSnK36EEm3SXW^h+W6Kp z|BVIIkUhJp8{<`Qg_r*+S9L8`teXklD<2#hY9K3Rfijj7E6 z-*&4(XL=CmDrg!#rp{UP_quS;Uu2d@k;=M|x@61AEiE&#RUQtw&h zP@4P0cPxW&OlMWi6%BMk<=nrlffmEB zSBlw`-6q$(V)_Cxk`jF#qbnlIsHcnievqqOK~%l40cYUIwLtDuCqwI;3s7y7kzzTk zTDOF<$MV=N*uRZI!h9BlWl8r9I>M7X&|kv?QjHx{Npc1>iyJd|D#VnQ-P(C&b&?~~ z9*49VElDsBs2^2a3NtEO`V`hJp&Ak#SY6N~48c95&}oHYQN2!1u?Bs#T+ zF^YV97!L#&2G{)-P*$ksDB&FNzi=zveO?-n}&D!VlQOW7qBI6>7M`_KiSFc0Q_+ee#@vHU4ij`c0wI2s3EFwov zhX!S+kEC2w#Ks@1vG_KA0U~>5zM1r$JTan)mgBZOn90^KWmN4y9;D(lbvBISZEbq| z1vL%!$Hg9;<}?=RYs=DO2KHL)IciOb@*c)-N&<(2(|?Kc9shkFvRhwnJ?!FWA+I7f zw-<1|`7&8dXsT8K`qunV-!|&JTho?4%v2jv-SFi|eyqOlD&m5bIPX{n(^e9^ow>!` zX&1F#ec1eSQO`PHy;vsw-=fp7a4>#I^Uq+eX|%j7ZAW=$9PCGbQ}|KQh4a@rei&*r zc+25Y@i|dvWw&PLlvUOre%H(Y&?k2sXa8IT4jVeAd&x2KBLe!2t}9mVT7=K;JJ<^} zYDtOE)>n-aJ{TVHCACyM_}xaHiM{Vj*ByPFGR$GcYpf*ROl8GC_A~Z#2^)m;r5TaP`@83v2yFZIPn>?#NFW)#4ao3*GF9WpjSm3THcUWmVGTO$PrMK-1P4o4_UwK4=)$~ zOGzCM!F*E1X@wPX=_-0y9DvUDY{t1oesuRTMK*7Rw^%JQ;G%>g4|Di>LRLKxYIp3% zHSuxE+PfJCk!sC1>+-jdS~1=p63(Wgh)6QYZ=Jms+jc{v(+Swh#+V0;=9S(Q?^}2w zj|d;iYa&W=hZ&!G2g>X7rViMRrz=`an$AlWp`^rm3umGyD*OS(Uo3brDHyyfiHCmq z-#r;RWq4Oae|r55-k~)#NwmudtBL2Ak?+09){O!zC<{p&)_w#K67ne z^{h85?KK$Z)`3WP+HH6u?S0%^>PsI%Mg%H9mG+nG2QYItp*hIltO$8?d9JpTPMdRK za{CYby;Njxxk$A>yZly}cJ4K37C@rQWx_^bv%IWa{X-gECs*w5mnEjlgi^`Zws=;P z11LCfqzUgP@`543vH08cbUugRa+!ICk88nT9U8;u*~1Xde0v{+wrJi zUGEULf_JdHO7r}JZ7s!v09R|Y6h&uN;UDJi5;8-#0UIv z3@69^{rZtnXLUUe=24E=qE;NBOmfl)t)ZNY((W3p@WBRy?z-bFn zqTQ%+tm{GfN&EYu%Gp37b1!ii#z6HIu3o=*b*TyzYp0!Gr(FdjX}U(eKf7pZk7#T8 z)lMZa0_c*Tu(_~qR1JgO!~19Dreu*N{Bs&o z6fX(eJyRlodyn?$S*@a&kWG2)g*f+;7$MA1cXw4L<>)+Q)p4*>C9$!;a48B3)^m8g z=yV-#8az}SDQXiP&cAEap5fbZN^BWXVOh}GJ@?x%})9$Isl zcmM(XU!ocnL5t#@62yw9vp{w43lZjpWby(!Rl!^-=-QocpHa4w{^T;hZvW+^EFC%rN9~&khNkkek>pBgky`VLS%JR=aT)!?lM7$k?=t~^WN`~G@2Yr+A<@ChBY@o!! z#n+P;URNKZiAu|$Dhz!x5Wkk5wr}!#MDIMMR#yI)w04?#jVy~*L~-S=w(hyR#B7&r?w&8K@c55D6q*^v&!7DcGb) zOWu^xnT&4Q#X@syHEN1z=~uvx!D(%Uxfza!!xv=9wyjUSlCKQlybQWmT`c}%IMc( z`6u)yM(eX0;C)0`D7DRI7ibsfQtrTN8pWlr1}^KIQ9zWTWI>D!f@0p}K_z|+*e-cz z(zBqUd&M1fJ@2ceADV%&WLwwiwZQrSflr;<%~w`IF*fsBV+c#>IF?Z!X#g>4$0Bi@ zes#0Cxk&{a>YhdZb!TOfd7=fhFS%0%``aB`h+eM2`;jQ467Vi2{$Jfb<>VLgMAsXC zHS_ECm?HgPdj~dLdxn>Aqo;#Bt148nPf2e`Vz%{2Ce}Bm9#jY9px$i-4nu>m3!^L&xJ6^HD zpfnZ_&}whfXH?+#D5pb@ZyS)z$)50!4txCfzul7LQ2(03fx;ou1UEZ3^@C9 zK7+YC7FObN{{7eA4e05Z#v9UjnQ1mdnC|a$hkl1e07OB3FANj+UA`sa_(^}X?1zsb zkvNE8?}-bL%JZ{7TGe;NNdD80Ij<$R-+PKL&n-ddRj*_`f(E-M9%X$_cLc&!Xm>xu zHPGpPa{i6y^W-}bCi>oW%k`wjTvW~_IABin$0b0Ro$6)cxOpU=tMH2MYez!x55x`` zRtsoDJo#2Me_g*&PhRuKx zAQ8$DMGhJG%K2)WCztTsz4OzX+xDovDw*F7=&6^dIA-Ziie%B`D1T5$b`kP2pzrj4 z$K(3~e3OK1k$~EruXUW_d3W2ck)8;aSC#r4L)H5x9Nky+2Hx? z*MUp$M7H;FQBLeF$oH8CvX}jCd#C_Bsd^ipd?VO=%FG52*hAI<&zYcOa9j54pyIQ_ z`$s4Faf?s-6n|gscd@Hm)I|1->Na!R8^)KK4<6+kagf$sjKeKCb5|zmZD<@P z@zmU1`y>f*P@pK#IL71q`Qh?TMgns3kk7_DyAmL`;^ zOKiq&j2+7qf9CKUQ%4ijdqR_ow%dU0t%{Jd3Aay?Y<3rubT?PnLQfs@+UvvTus1d+ z3n}?lW?WwTN^7;?DynpAOZ;|-obkaCZI7_bS-TkaFB&T}$B^EpQW2Bw2nkeAE*;c} zrT}!Kl|~N5z>}g~2&fur5lWm3w-?|>lcRJXP@xU6v-7)qx?c8uw+`%y7=)JO)3xFSF+7h*hVW0)a~b25 zx^;0CG}zx}&6%bC+@y)bmueDQGLeqSQ&8N#VAdOPh%L zyxQ@H=IoPL8#RIESoL9)&xm+@GO;-0oc@(Q1)MmjV(_Scs$UIs{*4qg{`c*>3_6ex zN$)YAuXG#O;^0E#cPsYI>OyPro9lJdH5bKNa$IzcaEvw%EgV`NQc~P?py`pR`4+}@ z5unQel!=tjxvN7coZ%b7*>e}*s}m*9ZQ4ihpE%)@5|dQNPerJe=nY06Y+FgS#B z3hX}fCx9c75bphyl{yx+kWAFEdY`s~Q7E#QaICCF z^e4fEwZO#?gM&~=2%Rk@I+=GjT&ocbp!^O>Cy=a@ z;EZd~u>-|?BQh|tiZ<*Bgv`8hN8L`xjrmG6Dzq=7wxdMe=h9`+@#vWh^f{Z?($qyB z&!wx&>YxV|!_g`o1o)`TQcJw7C6wF4oW?iE?Y|xthx5MuWp<{>=tZ-*J~iEKSRQyb z3V3r1AzEf_sQg=7b}OMVZo2F8FG!0SR@G4qg8t@O&hpiS>Ama{eVn)_6dIg9dPgu8 zA$|9=WR{BWE$tW~H|;hdO!?g73uxTqAuM25;KZQZ^lX$^5_e#FZIkz(K|#sk$#i-T z?_=U8dGsNhL=C8r!6v%L00Gtu&x@rAWPak_zhUhPxC;8(TtyVjUDn{imz~hX7uzUq zw3%*68iXAD30|&>{SGuD6PUJF8!T&k{IE&0fH3y@Vged-vAvOay8bTuzqx0Vsnk-h zy0d^shb3h=s!xix_Z{Od#zWX^t#v&C)#txrwKN0#BJ)!%qo`4L z9L&?>hi1asp8wLRj#u+5tQcQvp=UNq>1#W8_z#1u#xDwE-Yi%3rR;{DKEap zFEC(}sKgU>+jd1#$l}D{#j^!`k9c0m&rRtl#j92-_}_9|(itfH?CxPdIsO=rgCc&mQC>?&^TcqV@OLMvi zRJh~HsU#D?rSjMSOmR+{@0hIdw5HTMY(`(%O9IMuh(-~a)ktoe9;JW1+Ub=bdW|=6 z!7tLl=j)m)Uh6TI(E2(AC-Fl4)aH%b0Vjalpw)14XYCS!l4xHYpZ z^WgTm4YY7`$7xxFeN>gSpr3Ik)CS^hdRu!dDL+Ft)>Ck8PF~M#66}zb4n4v)c=>5z zUJhMVQ&aATz-JBXDb2q8buSGkDK?z9gS7v$w-}bRk?I#w(_5C zjdQha=0tVS_~c>5T^uDVB}9+b@|sFQRt2|#h&YXyUMlp1X0wm@9%BE?f2aF97D zx|LdXHnH^7Yq6Ov$i+z@2$zS{@CwHF%*8QwsvijhCbv~1r3fpCrw?}^`tU!AaHCBu ztM8Gk`B^ug@uDR{HUGRLlssYvWx947jpw2rSKC|8@xy+N|;;g}4$*0GAqb)QJ=Ms1efB2QZY(&N1^_&j( z+bxaKR~)sF?%+JpiKD19ow@KBLbLcw7VqW7D&xsclR)1~cVmO&Hq%zq1ks}F;u9pM zZ5x^k{Oi12ykq783KC=XO3HaxrdP*4KBXS%uU+D+T2WiigWXf+Z2U1uy69udyVoYJb&n@KJ-x9IQGw(9nvTZ z2si@Gs}mkrGIHNw+n_|;d2KcL5HK|jROj3-QGt(pU*=FYoGzQe+?PSS>UrBbhVNs? z;;bCzs6S^hl`+|*D?Ez`h_s5*MZ5^okLO82>qEFUc;JJmTSkVn`Qocu_2y%YP)$N1 z*4@EIpycZx_85B2JREotiaiU4rLeE2blzFVloD8K>e1q|!5Mpm`dP ztB=Kk{CyJQb0rizoc*D?jezXtUjyAix@8p^yn7k$zkA1gI|rX3;M*$qr_R^Z8b~&8 z%kP;Lh(@v%J;noM@Om%ceRd@as;H_r(|}No|Dx;ia^W_mZwufS658-sR@(N;&x>!i4fY+#3NzZvd2AWX6u5 zUDf4JgMx6sa>Poi{OY^v(K>rve)3C6;j6F=bPw{&V|7YfQuSeDU?x8~fBTSDKvwcL zumSIBa(43jBk8waL~vCa2Q00-T=x0(>>8E>oIla>U*ZXy+~*(pzm)V*KhfAi;|97CveOBZ}Og7rh_JlJENTA8V+8LxavD5W1B8*z7_L~ z)3j3*8D)Xl2(0yjsxFqF%6|%lgXpRH9R}9_>F83Ke*r^I!sDGuf8s$jcK6qHe6<1d zf)kmAhuD7!&+csLp!Ji0CahR3Lv>6$c?<#y=4A63C8%a>JPkX>q8Xi-Y(jOrP5F9n z%Y_P+LUqMHv+9eS6|7zg+_41{c`+`OQmSk`*%d9BHZ|14RFT-G)dY;vW7;I6PUZ&< z9RCFc(!U*j!D&}Uu-YA6iYemYR5B9M8wfV9`O3-_oG<6k)M0}1TZLQHdZq!wDibbZ zV=C9etet*kSP``KMapukBJS;a`SSU4;XMZUbplwlb@<2SJ#>;Da{?H%tL07iVI-+` zs@=(O7TVu%}Yw0A=uv2z4HXp`xJE&5pkY_r*7ZDeLc`Nug; z-+~qCYH7&dkMGb`Sa_JB0RO$c0r|~t`FZa0E#Z3Vx%_l`eSpwfH>24H3sZ+Y!)#@b z_WM79eu71wOe%1Zlj&Q}%6wFV)o&gqL-=-ikL?${A|wch(1`lfF$#B;t_@w&E~dYf z3a?T-=WcF(Cf1pI!~{PWh7K7mj^7TxH+nNOa@c$kSz?boSs*e_NtU`}ZM#=D`7gis z6ML*0oOz~~#Xy)=O2)s4;mRp%@=lC^hk{F6*)M@XL>^Z=gj(J$agtT^`P^U+*mp#F zMoqw7ZForBP_fA#ocp1C9+VjJt{Pz;1z{xgFUcc37O&X0-A(o++?d)KQlZF@%ur0~ zWK9Q2`-{BXAFPg-G>Amm!F1`MTa1+AiK=1d%PT|B?k91c$cf&&{1an=6dwKd0FA6? zwIFFcg10|6KZvdG4HGq%vxh4wp|J6u2pmk?wc3d5J5H8J;N03#zk@cTQJrx^9hJkx zrf3POa4dbVN>k|*?7!!C5pD1DPtgWPNZe}wzUiyk>#Mg;3^X0NbFp z{~UoWW@j`j2CbKxZXd5!tf6ZczAyU35z_4MtoB=Z`imJM1l2hsP#h*z+`ZnT zhe@NP*3E6NfeLNM@3&tbY<{95hSNM;I$D{J{Zf>teEzgUGVP2hyq{L%kNkMRQln^2 zOfG$3gk>hPfU-#TG}s}9jF=HNG{So*g09l|Gt>3XS~E%2dMLTT3QKrH$mkemrm3cQ zt=3?J7l7GI-Inw_ll{xC88njNZ|$k4KYU0>-WbJB&gIPhJ#$op8ST_W!sNcg!B|c0 z4v4N<-0|cbA`8k`}u{ob>oOpj< zy0gVrD8(VNO4unFCmmG$DH|Ke6((ePEuLrgJV3x&V;xXuSqgH18hn$RVZdQkDc9&H zq_xr*J=D^l(J9>d2n8&4IgQ= z;ZM}v+5YLMQhx(AM+iGMuH2loqZ*GRE@o~j!V?C9t6Ba%(5=fany_$WYZShu3+>AM zIv=pYAO9^Ss)9?4>~lkUA07_Rz&}gvmTxN)&PPPN0(r_9=YmD)7;!TBT}&Nj6x^xvJ!w?lIeeC%uy%vLHg7p}2p7&qjDIzy zXZ3ULg}1OQ!KquYK#mA+DS$MebHAua^wX)@-M=l^u2yQt;h)Q(7iskaxWQ%=?qqak zao=L9#)BypQ^9@=i9oJBE0MqX-^0S>Stx(_GNNv|)@A!GfAtF?D?g2E|C2FW_Gi<4 z7jTMk>RP%%h7&&Ug(I_!7};t01j~X%LzWAr60YlF>VY^`%oxkL3Y)%67|Aj<1C}}8 zWJt~h>_~{+FQW};hXn~9p`j{kq<=caAl9GOE|h`Yvn*XI;^+#aIqc0Nc_*Gs1b5PV z;l^$Qsw)jxwe=ipo?0||%`bW(AHEwyr(2H(93o5@HFlXwMkkoNgCZtk=O3?@Rb{X% ziUa_Sa&iG3rcTes7un;pxc(V+TaxfQmh)NB$b`q4D3{1On0od;-1GI~PcfqUSvX@p z)xr_5J3j=N-N|Ms906)G28wb;iSM6dOVM(JM~tk0e54>Rx3{;*Ftp3=j>n6n8t{L0-4`*&qI{~?p zp9;oasx;4YnVXgO*yUz4v8-YGI^=*`@RT~x_VK$^YNcN~bIT(6KQVePrkHpdYhvm% zqe!*e(~vNnV3;De7xfguTAcU3@cIApjf53nE~(HQnK92ACUebl@kQgLZj4&{j9 zSK(CVK<`ryJ;S>B5EZvS(b|Fti$I`av1F?1tB6J??O!QnhUaz5((~53>a80e*ikE& z^32(!OeY(HtKak)Y7T!bRGjlNDHl$Mi$COSV-t~;?bwd5%7iBMx)iUPfj`}0hqH+swQdy zpHSBCzp`>M$3r*E_j?5xffnb6{5q+iubTU|lO(jQu&jSSqT?ynEPH}d#T!2Bu1U6` zI`c$|6zgDyW)1k#8}Dwv>MluUhdP&EO06lfvhp9sitHrWtioF6$$HKR_+!etHG{tR72S?3x4Ojt$Bchl4 z=zL(4)N^OP@s}&P>Y;Q@6ij}OlB(*728rm{9T8M@Fg$9_c+nQi7v<;xvA@96AUtVs zK<>KkLn;08AaQv~(LkOaix#x+1bFlU`#ur5p*t}bUmh<)2y#1q6t7$NHQ{>t|E95t zezPO!!(Cb_W_BV920c$H$z2FwYitGDc&m%VFu9;9EbBvA?of)_7THj{$I(ueKIR&x zSS6PjXbG2nUK8TB+{AR=-kbh|5C`N)4FbC{L^DLXeDe$g;kD>L_#Z;31m_J9qj?ET zdu^+B11N7SH&+eC4Q=oSEum8Xs6e!K+`%w#HYAh6?i-($@Qwee(I@k7A{uF78I+5V z*hf4Yqyj>Wf398HH0-NfNU z7C&rllIRC#HE-N)yXVk&{pL^te**CH09&+?%Rf)hv=gj;De z1nJX>%aviSDCV4z;7)BCnfL1vhlL86vdj z-wn1en&-rM$X|A?M`%va3nuVUKiPq;bElAHh!11!;N8?MM z`6oDCXq*>hJkIm*Zcr~?4jlTIR?WKj)AD4I)oHQb;6&69gOS!>x>ed9*6?(WusuS1TtIT9{Y*SO<`tc6lT z$$;{%Vp5<;wA@}QFH5ZgKIk-}hyG-I}nOU*|gkJ%~v zW%<*(%|AW$U%&S>(Z^6d{-CTdHQZmkFNUH5)*^1|4S>gTtt7$9Fzm@aGdMHWpwa` zL(!)?mS=DaXruQg-g8Qr^yBUa( z8j|I`{fO@>-dG#=L`C}zL~;2OHl{^>?U2!YsY|Q$6JKhSEGC7u|ER&nES6(h@kxr+ zCpD41kH)ZE3Z!CSF0Z*(q^L+)G`9*$otGu(2R@uyV5A6+uFvrD=>q{?{jUo)$2JCi zR=#-P{4dA@M`q5E`|J21Sv4p_OvHOch&Fq7*z#-`2^><*JWlqqlGb8{L#|09son!g zrD1IaDS8E3OJysNuR8Ue0rNR{!U33Kla`1Jw&yj{Vsy9fBZ>Dtxe+79^7QpoL)?iC zV=zPPPz~9Z;uDX?B|n{ETgTb%y1Brn4?Xt~JLfH+>uZr2G?l5~c9Sq?=aC^fGjA-j zMO{xzkL|$F2E?;Ued+zk+Elhpd6M8@?DfGAh58*Dv99j##abWxi_CT=f|U3|swn$k zVpl^laFV3V@4gusC`p)@^6|8rH*IBYL7QwPb@Cy{$l;-`3NR6pau$WOBd8Ac0TL;v za%AW(LkQ@(78SM|=~I8f$+$$+{mgLF4uJ$mp6?b3T}@V;>4{nlEd;REZ5ThhYQu{wh{V$=HdeoCtqW93190g*l)>4*TagCCdOOg>y+9HP8%fRpM@UHLI6u_WCoOCV7k_S%l25%VCc z?pg>fj0%`L-E3S8^&t114P>RN&Wy+p6NhZz7q_4pMzI1dm8H2-Xo>|*FbB1)sq?n% zT?*&oj%VVLSJJrX$g7D(KZG9}(;_W(2^1fqt%g!ar3|S*w)Z~hu>!pofa?1dS5XHO z{t8B97TBPg{3Z}+Oe~A0C@VHucoIji{oTY*L?aK`tYX1^iPUCA{##l7?zc;1Li#v4 zXV1|nf|H%8Y;eF$Ik4TJxIohA9?w`-4*AY($;=!^rg!~Vvj&Bbvy@o1W|&yI-u6U8 z>kTc*rqZu} z*h(t%W3{~YpyTL}#3m=R9cHD$ySJ8FZHv-=pt)jB zpRHT{q2NyoDM}{1C{R z{x{kVbo_n71=SFKy@4oh%uGIIR;F;bzP4+P5P>iA1I}8WXYXq+d#RZ6@%s&cDvc_4 z;^I{i4i&IU7G_A$4-56+dLl=ob8aGjX8Syc6h+8B@=vTfU=bKhGhSF%8>Kee$%u|q zWmz07tw@&ww*KBT?$H4+j%uZ83Ej+! zHq75G#%Q30#x4@76ZiXp6r`jl!8Zs+VKG3}_=`V>SyK0u;aWU@0JI!Jl`?H27&SGk zms)BPD5@Dm*VvM%?Se767AK=cc$HMy+Y+Z))igrMSbkt~+@2 zGT}{>z|rV*2-DcK;UeIe;YS*bk~q-`Muc61i?rH1N}5V?9wZ=r*G(Q8;C3ztJL=$B&*At91_VYmu; z(@UOM4B>Eq!6^jjUGE=yDrh%PA1I6$)KOH;R)nu2d~X-PUjDchE|bo)jln?OYOKFI z-1|oBByULWmJWO6iw|rfKqPkAB^Ael(gGykO{En`oLR7r<4@7W4)#HAGC~n zV4ZMOv0w@8T&o-7v-CG~5@r$i|_(V`Y0QajJ`YYLkY;aN+1y*Fw%!2Rp z7dY#S-T2T3Wi4{sU(cap*-})=LzB=_)-#?1faV-=S)sSI5N)q=4iHe-#ZEj>Wn9a9 zX&Hu_{iq2!T&q^6Q&*C8C^QN{6Z7^hKN%&}Enrqu0ptkoc=)2-mAgNi9|y~DY^o=x z4i?Uf>!wBm-mq2T0<;5}A+F9rh$^KGIL`@E^4oye^_PPP zLsxky4y?DPB8|~g3~A6L**y@Lzy~*`1tBaWbt6B>Y%u^H=THFy2W?jjwkXEY-(UQh z5IcJYtU^CiQ)klFoFR_&iSU?McK61GO__C63BKaYy}qJ?4o2uxaX48bEB=DvgX)om zi|WM&NB>Q&IZKbix3}y9@>ogPhrx}9)>7rUynHDp7DV6s!U<87p)>c z&Pdp7QrZTTUxar+kHQKen+a}& zf!6?W4Hj^pwNXmy)u|y$nP`<g+rt+)m+6(jg*w?wjw*gjhJG#!~} zLfg<_VDd-H)X8z;p(n?Nk>6u>C2#&sRvsyBs_A#W6MEQjQXL&7AKV<@aA}??%0|Sr zWv1C0l8W;n(${brQ8ckl9JnzYcNR3Z?4dwQ@GKx6Fv)E*$a9RS&jJY?EhzVyZ3Aqn z8ZbEauuLU#iD0|v`7cER^&(tfG{|`;9zuD7v)e4R)C2;-@GuPs zTKT;f3N9e!?k^P0&6Gu?B!X0mQM@-aX5>@Lvq1|Vfi|%m0@5hNoM^5~yQ&s9i)-G~ zn2tfpI*uDbX?Fw=L}zU21-6PPFb_f`=DmM;M=BP4Am4Yg4-gimKS_nnQe|S3@OePp zbPFJO8uNJD0pHK+12_14+JncjJdWm(OQJ~|?Uj_yurdZ{P>5TQnaeJF!bqFKjpHJk zEuGaR^Xt2j=EqkSSTA2%EH_COz{q(>8DJ!=6lT#S`Q5#Bk@=48t4UMGa@4^UGZFQ2 zj~%)s=X%%NM+_#5me$T@4PC%$Z?%E)!QpNGhFss}im*}6!|K-K3X>p6XMH}X$|v!A z=GwAD5q2F8uGFRxEX~?!2N@x&t*_^6-4IlwRrI%Yk_#2nu@1V3e3iv`5JlAa!~;d= zs#j&J3zIt@m2tz#-*leYLrDvNx4+;f`D_r5i5(d@NvU7husLM2!e9l%9cASzVzN{& zp+OSQ@mF^!>lCojZkuMD<-sReKJ6ssBL_uFk)hcIubG&DAR}F?p55jt`2%~A$eu~; zoOq((>at-AJyI>&3*7syk_sH5Dy-2*!$H3XIKt>zfq~iM*KmjIQg(e<_V~S6%A?t} zt2LVr=eM4Lm^K2U(N*EKL?jkNgJFtU;-um>iOyYN#|J|Jx6KLN3dU_lFiLYBr=sc2 zW7uPa%k|VLv-U0<%1NI^SX!+5`nH-yEDC;GQgJ8x@PF z2rCe+BN)CuuRY?-=veRU-{DF54y+poSmCjy{?s_=jd(2?R@!s^=&UhER7+rh1|qEr zHX>?v4v2(uVPg~h3Dw%dy`g(U^Zoai2pE&_ukt9^H-62#ZH3b4ypHu-8zx(NSRZOe zLqW4`lxf$5?42{6oI_SSde+*Wq&f_YW)md-7*AsZxry|rC>-S-c;HpVL^k-(vMCj8 zdC_N58xybf8|)-BzruXS*-GW5CVOM_n^uS{{8zWED~Owt)##&w|Wfw7cM_Ky$XK61DPatbF8LsVK20`esW*p#ASDNE8oP znmlgS^5N!GH7bX?g{1m@>UG=+F5gY;5$%7TKjXmSYD9s-@YLnW4N9u$M{M$~Svp7j z`Hx2F-wqBJv{{raPHPdNuhBOTr!^R{%BN+DGFo@^xfIx|OC$7Dkcqh`Hb&H?y$GsN z#@)+iQfsPX`1xVLXIND2%{RNv#9Bi=Lg$L3q~PUTmFk2tu*e(Ed#-9)@HvDo1v}9PduqSUjJ>%A8pP=U z!oixqMQjf5c3cK|EwPZH02u!U(lBF!&L4K`1MC_pb>|M98hXhkPSK zpxabXF23N+ZsMnUb>)2{8Z6nCN*a*CO-#}Oi__YOM;GHU$)Mis09_r+T+n`$is7A| z4)E2~o$l#eLjKiPwYD&DUs8t6QECm$4T>W=0g5hD6%xDtb&JD_AFR>WroGND3<-<3Gc-rX#$0YoahaLq+o9s{)>2@-jNo~x>( z6;yO;nF%Pky*2R^v3zH90$tF#BhQf<@5LyZ8cRX&mvE;aIPfo{A_YhKvtp5}()Rhj zWyzC)Smow_pm}Z6mX9@++*w5Cz9zj{7=R$=Il?^6E{6t}3XPjDgU!dfd9u@-*N9{Q zbgHYNa1o8|)mgGQ%p2&4aLSJ8(vChY>tnORUq*2n=QbQNz7C6}L7GRYK5KPMr`%ZOgoIkcuh(8x^=6 zk=Y171;?rX-ZPS1L)1-Zmy^eoGOr}333LIt&KX`u>R^~`yDh4) ztD!nSYbyvJD~^`*aI?;9LbZOh4TqJfnb$^YvDC~RIF`l;Y!45g$`a_&w1FBmnk^N^ z1h)e`fC%G3lK|<|K^%=Vwvp4uC@BOUjy99s`?~gu%zyB@HoNyGrd&ZKi;{?a^^3HKz{ zQ(1#cp0yNs37;yQvE_@5Oxpl&$7p9ZZCg~Unk3m*CJZGmH~rnk)M>n)Gj4=ILhI$@tZu6CgC_dy zjG1B?gM1>vDqRo(RRHpfPv+0Jdyy17l9>FfQ~_AnIWP3e!1H^mc>NY`!t_h__B`)6*YY*jrr7}uV|)h2+s zS6S9H45S?45Tq+Hi%7ZXzf(>tRqbo7OeN@J&da6tb+U%r2pT3&WmPV%GOVr^YeZ!w zA#LQxn2-Wgfsi8yP4e21lfpb-UJ@CbzjLSO+kLBI7c4v6URMt&E;tetBR)u*lOk~p zE*&mb+KQz(twjJ!>WuGp(221Hl_llY6K-Q|=Y~L=AoicIytF|DpTpY!$8t=B&uzxjGx zPG<+{i@hJNzRy3Guf0FJzTeBUJs)PjpSe2i9>>spufZ;*-=BKl-*(@jb~;^7_t?LW zY(3AXyI%`*KIME@zx}-*fplL}=o`77&zZhI(`tO(>$gp{+8u9Zzdy6IIlXV4y^o!_ zzxT7h_r33jYWtVJ&(qVDYCUhOy>Fkt%eTIlzuzltKTp_tADem~AFDrkzLmbmN@{rf z`e;ABuev&$TmP++5GVehSN1=z?0;U_|GcvQ?_OCYJp5Zf(=3zFj}>^b0m8F9$dyPS z_?1z}S8J0pm&v3rS&AI)*uT7BJGv~nj0dhtp69M^$9UlBw6AHEuNTGczYhWY%IMNF zJoKNL&zBEA=ZAmHSc(`1DKw4tYOF^hDaGDR+{H=}6m|Horvlc4tKoHh2^T5T)ja!I zjDNjy#!cH*)2MCh|1)+~%Hx$)7&J2$?3g`F5fHFSkH&gxr%IDoZs_J_(vsWThecpg zoz^d7^DJ=!Aas>HQdj3FKz{CBuVO0A|OU`P1NaGV|TTR4H&nullnmXVeUq< z3SGk9T)cd5ARWO`k!lr%JlS)felc!rgDAQ~29z@&m9`J>AU$W$V!Shx#!%K!l(cT1 zyqxSIvPxD_dH!OdHZ+1Mhar@4(vEGc4!-5Dm!|1Zqg4c;vIAhtooz)t_x;Q&K+=Ene79e={_s+jcIVvk%zk$$rVnl&9 z%()=+u~M4n0IQQDW{RMoicqoyfuE!kfG4?hpB3l-ZVYMJWsY3FF3nM-)bR&jQPP%t zq0vhdax#^5(ItHZGx{Ibk;R;r%x342(yVB6dox;O;3~-yomCNvP+ep_HHOi!s!X#F zX=`?B0(1avV2$3NO5P{*=QnqQV{ZI6sHjmWMe$q)Hl{y|gCB#C!id&6hPfUUe?inZ zaqg{|8v!=w!BIjcX=>~7KF+Kwu7;7if!QYH%Y5EB6-sibS!%v)oqi;Fs`9a1H4;S} zV{Y>o`DxKmKO-Hnu6(W{%_Ao#sT_S;T-z$z9#vKYAG%gjxKJVtdi$KlL1#)4ZJ=k# zC3FY~XV@!gw4Mzrh$+!{oRS?a13oS>IfL33_4=UMCGloc)g3gCwRM4GkXn8zg9UCgHE2?36mvWjINdHpv)L&FojA|K*i4? zibj~m921+QS=e8?HLagu^QbcoF{2wm54zatC7j+OEGU73Vewea!9mSWUt?n-JWe&5 zb%A1PpyMqsYYwJI=29wA8KJUXB9@d`IA3U8A}A}*q%&wX^{exa0Hd8I%3Z=GpNwj@ zLS+qVP&sED*3v6jPuWBWnvgLU(@Vkh6Y1M=2BkXU;YZ%(Jwhge{)U7SO>0$CcO3`{ zwV`|OMU1DFyaV5{7k#@-4foL7t-hrR1cRP{%&|$40Fxi~w^F#ffB_^JZrt9()(vnv zPfX6+&jd-M7d%{&cNy>IDkU#JO1CkH(c2V{B0? zaGf%#foxaH#Or4HZq55`7x8I(@)UJ}K8!~p(IOrMl$xCha zNa}@xq^6qMd78;klNrx(;fV#CO>7?Xpk95Ed?5Id_`(?}vE9r88ygkk3@Gr1k=z!i95O@fkl=vi^#pk$7e_8?;npR5rAp1&!UtDbOY*Zae4&c03$UexYGQK7hlM283g0J5yR8N9Ibusx;mPE0k>w5+abDs6H{ zW7ct?*fC=QUZnWizb(qr7%_0DdQ;=as^_s03#CTJ-s%69h}CXkpWxePBOpXkIuF6v zN`zs;(peO~QuG}J!qC?kCW=o0MVMC8XQ#kO$XR9K_@>d!{Luj!=ZQQVI_7Qf z5*A>O>36vqVq}e2r;}K8MM~tnT132yuJOAnt@2|~)W_%p$5cHIX(Z=q~X zcD4}IturdyDbq^O#8XJq6Li{z{Xt_?h_*P&+ut9C%Z7bo>Hi1`C4d5g`!gJgpxUoQ z`WHc0pKyR(R(aD(w!=Bzfox~6Tu2`;asWSfwBY)II5Wt(Px329L7t2;c6TC9E^9;A z^L8h=a5hfII!mR8WShYds@z&oP)6*&+8^>c`|kpdc|TO(K3I2{5DA($K70`<-xac`c*#40x!54R#20OL0 zPVS(VL5wQ?>sc!$YkoN9?^ng!r&zE;BclZ6!lG1ByQ#vz` zKyR8QQ!ZyY7HrVpGmrRFbt264!to8;j~(`f2e$H)g)p(do9elye|e_D5ZLgaPYKU> ztgEhYP9{^|u|<)YSuVl6R8E46JsB3>xO(Mm z-nqRc?Zj@EJ|#Veb(Tbyd>rGdp&N4zf1X*%yH9J--=&by-i)NBpVXEg*gjX7yjNatasB3o-kqzP#z=v*;#EC&=KUP9|_UP7)z#4Q=dV>pC~V_5vGY0 zjI1{3xc?GLlKLDIjjJ$JTTGJ_4n$l4eYt1WYf138sLgya=N6gl+1oi*QO}rbm_#WZEl?4#l+GYU!jW2D<`>VPE4xK5Lf zjOpr$d@veGdY3wK$i!!U{kaZ1ebNNI7DNtFW|*aCx$-lB8rE29q-H_1`pQwp8b?3u7aLm5oV`ErJRiM$uSj_Rdrm z#N(H( z2o8et3}~YaG?4VSeGaL9EfiDHbfrO54oEiv3pD6~pfMaN7gkj4N8?6OB0GKQRgTVB z7SGRX-y1Sy`7RFTVX$()AvxtEY1MG|(Ng9rc&083qC8)@O)~|V^o)sI5T}j~7dU`L zg9&9Yd#uo=dhz%$q41F}sM}seP?{rc!5~$bZM13*6dea4Mf>xS;ruw!@btPEDJ#{l z;xw6tC(8@-NKjP?bmGgB$mO#H3{iz>GLzP!iHwFGeaGLS>u9u7IX1gsQ^V>mPzYIj zhRB#|Q5cr5D;F3+sZF`YV~66k97zIFN)|=T43GdRAieUog_(&6k@tXhB?`%SMQuv1 z=F_vEX3c8JMe+M;MJ$=u3$@lYm_B$ z8>+1e+ehabOmviK45$)j;xY1i7o?+P0u<^oXyW*a+nk=E#EUs;fkkUlDGan?{+=eV zkRE<>rVHYZ+(6uOUDS=EX2>%1J{pZJi0}{J^a7h zMZdbGzctx(*1!kN28<&P54?Ik$*&(pbI~3(UDfc1m-VcYen*?;ZcGj?V(z7KVD3Nv zF=KgH*8x@gJEJcOVngN;3>iYqIty2w67s14ryp=b!Hb0$j70e@B&xWwbas-hUe z=iLLXHL=~7BiUwh1xVA(3A)*3OhDzYPiC{=#BT1UM6$GcB!`@ejI||2_N01KeiC8aDKT#Vp0muh%?YM!vP{`Q;H?_*p9}BSiM-PF^XKQc? zrukF<61VgWm5Q^fCBYLzg^ z?T2QZuXD2-r}<>M7Y`PqR{S(BW|PBwj3Zw^Z7nK9YS|q>BOD`bb4Ha~$Q(mFfN+Fi zrA{&w!pY7vheWBT5$DiZk>8cN%3|uoBv{QW3Z7+}fj;vL<4Oq2sd2-Wg`i7Po{IdK zrG`pJk2B0DCGWj18rkugT8tzl8QdhdWrWS3xiar;YEE*{EL{{`017^}#<_}v?aPqI z3!h=Q0V2V%FXD2oph~8p&Ya0RfG~?20>-dFI0VO11<96dRj-Ki9yQqDYtmCIfj@Wv zH~6HE6G*X%1{vt-)g63$f4=%u_hObCEwB{ZGL3kz9O=}WU}4S5E7T7fSJ z{H9ibF}EvVuq*PsgqF33d}+P(=Nl?NeN(AT!hJtAs~Q)9gouvh;?24icNv`D>yD7r zMwc!aGS32qhKZw&LZ|G6t#ExHpF2X%oa;fCF|;k=ULVTVWbB#EUBxr%U`E(QlU)|w z8{CAbJDv8cy^r1;4rRSv1Mh1%myVNJ#*FxM5E715ee?D~?^L(TM6YjZefUmq@iz2U z7jOcZhdR6^27D8eR#mJEl38bWkIp;*GXk_bv*t#a(GaK<;XpV>Z)X=bX)Y#NAoNWD z6-@>npUc!zbt?}+J(t5`cWlb7s-3OTwmjL7*6CETcubSfV?;1nK-%`B@_k>ZRS@3PNRNx{8e zf)vhh7|}mvYO{fICSX)$MW`diY9d;fe_>U7eA zDbJ8`r_};Lj359@ENFt@P#poZ{_k>C_Es`{{H1bXsH%b3b#jzZ z8}3n{$O`Kb6rq{IG~Us5W0+#3lbl!*omDCH11lDc$4kh!a2tv#au0n&t|<>{wDxto zxqm9%hl>dCpNH()=t^+9UnfW%5&UTsuIw@$dY5{cU9<5h#m=b_a$9hL6VgZTyBjnJ z+?{6X?*5(6ol(`HT@IdD)Ze=8*7p!zC{;h&bLOXgEB_B_R1bV*OE+zxinJqnSwAA)2+f=?e0Lx2ldwl_8AvuC z-O^gc!&JND2*n~guD_g~f`Vj(;Tor<_eQJVobBdE5I!cLM8m3u?_z0mtI@1nU{Q61 z$PI}r?cRZtqQv4JF9l7>U~tr>pa6C*4hc^m4VI4qWnc%yLhx>#;Q4k5Z5__X&3Fk4ub_F!YcP=RB!q7VC5W*>u)( z)mxv&VUd<(WKwmBk(4lS4va#8ZE6BcSC#-^bq=^#fs3-pI7!sti(wJyLm<`QdHpe= z%$qsfNeG4%4>6bLsT(QQ*PTg)%t*Sc*Pc~>TSV){X@}SBbV}U2W1+%sV1aLc>;uW^ z6tfYxkS7QLHW!jqlMtN?&|g{g<7&W%KJS>u zEjOcmU3G1FjD1yV^95ZrX!d1;{3LmS;Q+|sxrVOCKl1`Y8ja=poU|nX^0uG$KDJP= zb{?^1s)o0|RDEz@m3`0wZJ3Bn0htQNj9xcQg$TI%XK@*Zpvvd3|uds<^tO1QDG4XLrq~t(!TvT%d7XVR1poQT2>)E`p%ReME%)bn_CA5f*EdrMhB+S)IWswfWohyA=DqD{?4q)#yWpawu>b(~{bd|5{=7*WfjaOkIdN1I9^< zP?Opr_k>L7rPJ?O1%nfwYk<4%61eU@JL#(&jdrieMxD0&5rf+>4O;-C@&+iiFTD14 zOnyZTKx5rI@&O!F-?#zBA=Gys?vooDyBrk1N>x2s0YNB@$4Nm@|Up08y8R#&4zI#s%Rh7w2)9WRQo)D^su_-x2*= z5pyR(%b{mJGnTdxnTV0!;B4*QHrX_JH@h@%-E z3G@QkGtf$khhW7ZlbAcnGD1qcPF6r@USn7DELTMdXsL_47)#lIe@@vQN%B-@Tvt2* zy@aP1KkLK2;k?2jLbq67xBo8Ftj2N*AmYrv17%CObz&0aDGNt)B?99kISJvZ?qU`q zswR>tW00vn0+IzmOn9BT2I1YrlTrVofR5rl)kaa5^54_$&Gpf2+IDj0Oh-i(1*lPx znDjwRZRL=4U}hV#Bub7&xK~n(W)MbP9UgFSximImm%BuJ=jTglynFKba#0OZA&aX_ zhsbi#|(IGLkBh-j?ytU;C0mLQqwi}dghAIqfBCb97=ATU5rT#={T zj_hNRaLNZTFQzN>*JmVm#i8gmjNj|OlB7;3S5>qwBwZfIs+f?SXfV2f7ej&V3uW4D z0tO#0{d-Gl^iMf8uTT`wvzbW;V@-_*GVZo%c%UKIEVs$r!`zCt(!hz)EBVU-dcp#*Rq~u!R6h}#HNIl04$e=WoX24u6LDMuC+SR$gr@xvGEIz121z2(X z%pwFO>E$15QjN<4!}JL&+UTE|y-dc$j%a ztpj+dcJ&2ShEh?Af9FJ3E1}zT@GsFdua12`cQU6x(v~h&Uy{&;b7~-#8JO|HJ1s4h%;3Vrq>lT;o8rElF*-St0!-sc~IA#2q z=ap+GhVeXCc+7C1LJ$_Ws6%(+ zeVU^Y`9gEK^lkv!f}kPU7mY=|LyZIXQEPngRhu=Q_|LXUsPz0u&gRbYa2C68&rDFl zD%1$V6@*W@|K|cY9pqx0XkMy>T_W5qn}@>Dpka=pEQk6&;BtOP@*XNbTqp5lPKmYw zF&;2r5kX;K9R>$ckN!RdfwZ`HAe49HtLjp~SVP!5tzm%73x}GviK<1B1}m{FYk3@0 z3Go%RB01(C?Xe#KmMZ%qK$!2`6~4fUfUM_2)M^R8VdtyURu-10)yU?`Wm6XHzL!$10M zhKbH7Il>oA)ubk(jEsaFeE_5V+ZBf{^bCJtKWDBS#m+?! zaD{V_U-*I(G9p(Z3VoSk_tT^o5!07P{;ka4hB@|#4snlExHm{2hKIA5LWP}B_fBO< z9TRKi8!dfooGXol0PfB^lVm^4n0l4T-A;DBB|4@$uZD7o<6(6KGAJrc&VmC{8L`Lk z+2y8`SK!4F!;gad4HR4@MRP$;xUF`$uC!3V4;>r!r0sBaO{Gqy)zPp4p`AwCd^%Q3 zq?bieiJM#3SRK%c0F%M6fN{|>EyAUzJ}7R5@gR!zJH-W5C&~pv8?hSvV+Qqd zv3IqZHQttQ)^Kbg36fOYE)7)%7SV>FFK)HP3%I^IZ$1{?G`nQGj&2_ft_w(wMRxW_ z5Bh>kufsh#+12wfR9?PkK`NTJ-R_%sIU#1)n{Mew_>IP|ymtyRAxUlRz-b!uDTJ_q z9Bu>H!5C{93%PhXnue0^Ui+xE=)y;If!upav*Qx;#R>F-79ACvG3-*Gbx{U#i^P;| z=3YAv%@Gub{Iv{nm5_@Xi@z}3S@$?`x-^OMz~^-$QjHdvskgtfS)DTc?$hO2{g8tG zMgGE2`0S@?crj^M)#}yy<&WOqQXLDcR;4Up-7soGNUBRK;eE{1?GnOra^?<7BS_iE z>^{PLjgFZQV(B|*Cg~62oLNGwKSf8}3{T?g8+pc-+&!a&u6&WndMjh?w9no#RyBeC)4Iu7IC73ghPxI}gn7yyY8d)_^yBL2jOyBlm2ZzW@ zt$a_@L?4&fq}B3C3%xCa$qS~Oc&va%DJjmHM*V(l>1Hq^JhRP7qXjZ4H{5M!B@;A64ImE>L*V_W*|I39kLYkXmTh% zqa5C!(zq|T(*S*EIz7%6Fy^BTEg1fMG)GT&5&TIVzm>=&poS4_$lIU9+bBhStW_R@ zuGMkJY|(ByU@Pb06T@y}Q>|$*@Ri(n%SY`Y?Z(WXtFVSL142>$Msr7{1FIg3q@)MW z;SvX8KH8E}9m2%G3=Nr2Q-tgTYa%tGSP@7>d3(G@2ZGhyTQfK(TU~xosG3UtV9!XQ}s_5{VUyz)-yiaM8VvxF&%!j(H_h9mzb{%mf^en~mfTZPdDIIjbmo~2@oUnBkdd7uhL`(gvYev@ek4H!y-b<#JBY>4sAjwQ31KGIVq=kQMfKRpL~wgmzEs~m*svfA%H&WQ$IfzhYeuRM8SlTOaSIznMYs8#y!X_`Z|onvmY3h+ z!{&|tpI`QzMQHR|owcv2XBKeNc3)Cg&7Z^eYo?(DS@^Co5-Wcwocb>=Sf#}S2(4^U zJoIBiRXq`|D*H2$=u}oZl^hYN;H~{d6w8!Fn{`E!4Du&zcf%cn*~fyeLAB8(Vl;Ng zG=qFXv%A^B_QB9`TA5QOst9LSc8GvT0)z?KGq^#?v*_=bBiGUtbFySEs2_(d36!b_ zi?b)fS10y=YNvud78jSJdLIL);|6M=z|;~tdZ*7)CUa%AeqEU6y?{Aw*;o2wU#P+$ zFBZ6Q3yVW1UI{i=H@l%QaEz!Kt4Rt+{GS?X!dEaHWzjHgnc6>B%Gr^kc!GRIT{2$X z5-0g4h^@7f-ujP<+e#J(CT0Z#lFvsB8j!ySk=ci%ZM;o>;n!cRvw2urpzXpmv11%w zZ%_34kH~M~z2&Ptp&?*9ab1&q{{ach!v3w%eZl(Uw=tEq$(QFLgufQz7r&Jm=|2X( z(Pk+_EXbM8aB-cjB;BvE_RxkXa;Ws>yvG zMVDHXDNq$3*(IZk#j@&2Q$`+4v18Ui1t+~zsHYOYk+(knrxx@m#czw3L@e{KmRNCJ zc@|?64F%R89R(=nmdJUqt$Fc0a=cFHAq;?vAd0nND>_2&gaci>0vQ*|Gkx-I=-_sA z5+k9AFi#ZOmHxOLwki#c=zgU|DLYxZ1;x?i*siK3nslwa9wPG|gIo)|Nw z?N>E&Fw}ImkZ%2eez^dHuv1efs$IxCMMkK~cJ1m5ZNkLc#ALHcMoO7EF;ci``5l`o zBz-I}L|i)@!b37OA(QmI5Du@=p5Skts0j&CE~8qmb7&zU1SLUKcEAqZlNyymoJCTD z=-Qfofe8wwSz}7hrvv5+C$rO=qdC=ifkfe%5B_(0Z&bEGY5|A#(p_xv6t04@>GpwhAT$b`Yq3i6Mt9M#s|7h~ZFWlC_P}{d zK#$WJ$JYl!N6DU;&byrWzbLi1!>2Pv@FqM>!V|0SdSb?|7oy&(n!-av790e|8S>vx_PTH=@WJtLcxTdp%lz2 zS(`GK%BtJi;(y6&>tSZVcBg5P6#C<6Vo8c&!305XT-NA*Sj-YC*llS)HpCLZX%&p2 z^##GIbdYI9^7|)#r3<&k!9RXLAX~^VCHqUgH=i#+BV<0vkY4cr0*5tt$~g5~)*~PU z^*7kUf=x(nVjQ5GQE-!g7LSO?aMXxyC*JA@p(j3P1>uaFUuZxJJwL3Rkv1HqDJMs1 z)JRSq(+*xoRLUF11K|qBzmre#&+LSrce_XfDLYGLXJc*cFWlT%+tl;arQ?9Bh|W@w zkob_Wa~!KMFXjx(`}UG%kRj?Ex%tA{W^5;wRh^NkRVTN|F!ZA05g6T#Pp{qB%3rv4 zb#v|N=FKZ>S6|q?oZq(1e5E0`Ka5J*wKDQ+rlmL2?1t}RKt41?D7@fB5&M~tTFnt5 zR7BburLU=`xSr?a-*{&*V@2yymP0~NaT1EqyhmB<4nQO1{6x^ z`zuGz;>BDPBzTcB69nVkGK#|#-RWAN7CNB&(zz=eYqsZ1QDVMJ#{V3CP=l z|18>AVR=bk%J@mxzN;3t3i55ia7xn)585Y+7^=W;o9(dyxz>~?w{dJs7b7!8fTKs9 z1%G&xQKIu0v_dauiVillLphHOz41mfXnRG}15T;Fx{rD3q52V>O7CF4Bu9<0j7m+R zt!#P@rV9!>PN6D+f!$yhL8E|et^Gty9eF>8hIOn<#gtHfFbTyHV!wTT9T_c%th!kC zrgzs5qcFic0MvN832c0WGhkD&Nk-L%GX}<1tihr7x#zN7k1|$`POp3bnIEoc3(I2K zGX$oz$;Y|BKod&`ME6dNTh?C#APKw_Q17qlj+Ltl#XJi&wo48Q&Yq{hMQczD4+t?g9?bN*Z$&5*EZKSp#Od7|7Pfa z<)|J?$GGqN-{qy_CzcNGe;>y)=loZ@e&lzD!Pt9%K4#qiE-lq;{r~dumE#Bc|Htt> zlUsPGxjlHkv!5C3{~9{ZZjgrmhR0TN?j3iZeayQ5JF!%=*8j?K?co0Ju{?`(OW<4x zM!TGeYLeH!T7KEEs)1RMtX65lT=MFT)*PnsV+OB z5DKyQNt6?BuX|$(P{P?5(Ll7h>vTc*k5Ihrj6FL0pg7g_%53DYD^j94K@(F+aynqV z;KKGOs{-1}im`AA4Hz0oWoS7ojWEg8T%2=?c;}IqxXYKQpSI`X@MMBW`IT%|Fw`rE zbJ5r*B@CR`hOPdDVm-;veH2Ey6O}j)GZP6b+OorWOa?*Q@8G{4jc+t*f;`@%Kj9u5@x4%{l89#?2aQ54A~#YQI9oK&D=mT=n` z_?r49+h=KBqeWF4a!8V}uFb96#K5dAMKEx{0jL=ioRLvH)8bRub2%m)qmS&Gu{C@v zM>a+{>mEn2BW)h z<=py;@Y_@&>YOx zReM6kBujdG;p$7y3*OKh16^FFB_dgiQv}viaz4%WZO(Gp`P5|SIko4Wt8rzdMzlI} z2Nb{-nT+HYt90Ol6E-aHcoCvPMl3yEvG@Xmb+J)1oVN#(Cb5SppuzE7EOHL=gViq~ z0BS*ALhmo)9IMhq&smlPFPf?5(gqU4+m>vr7mPgC3-4pdSb}E!Yy{kH+kGkTsQsWuf4ES+fIdVc4pcofFSFn;yA4Tt{tN z+1Z$2?Uj|KvU5HNBP{viIcI6PR;yKND@&(<;Lp)L{m5n*d1YLN8F1C zlzdQmKUBTDF7~&Y%fXxgM|4oktNH6KE1IOloEX=>FarcGWoY?Y8WSg@WDMx&v{xtBAp21SI&j*pScXwjihm)jR?`K9%X zPQy8Q>iDzIo;Y=UW%;=iOV1u(T3KGcvYOqD2%vOvZDVu&>N(t2ZeCo!ar62)*jgH# zk~qw#))zI=eCxU!^~5EDc0YGd##g);wDy$A3x`u{5oxNIWC{erwndZ11>N)40Hb4> zPh4R0PT(VF_M@Uf^P>HdlhLrIR}Lp2MpdZ^QArP+$72Ib;MJAt0qvWMCGN9dV=|L))KC0IHbAPnkW86ESNvc8p?y{n=*qu+_$eRHg>4Y>NJ%1ODoA%tkP51M6yyi}yySXl40UEASrjndSfCjr-MB*MF!!X59a*oTw%5 z|CSHpKRuS`>4n8fI9_b}Lz-(|2b6-2RFSLd_k|bM>-7unc;vjcQ|!1AFp$mQJUima zprTmrqThvGtX_Zd;tBC~uq$uP+dl5~g~bke3ob^%BAP2KLf`H!_pT&Fw9gjzjs>lW zfqVCojM3b1mZ~SLTYl$hr?$8}Xqq+xm}glZ!>Vd;{i@hV>8*M#j8WlpB_=D^DAp^V)0o?>Vu%B=2@*M><71`E_9*rSJ~u&O3YeSFMI%-eFheQy|$^H9c=g z+FJTU*#cIp&Z|QcKC^)r-PCgyKU1F8f9w@ zo_1pJB84C`nJPC~c5u3`ET} zUS-<(CX89N{iw$c^f8MM;8BFSoU6~+pSr(m^c(fu;cZmvS7Qj?>V5n{pBeIB3wG+x z1eI$KVFI>)`>$H<_{jtNugCGsKmQa8uGM*fP;j&2znxe)W!rz9IJI;j|38k$ivRY+ zY55NZJ$nLK+arnp_QXTSe`8p*_-{|VN%7yfBN_kgiNjBb2yjnO1UTo+VR(1CS37e7 zmc}Jo8l2lld01YAg#vYI0)3A-R2((>#G4x`?umyC754<9Xhx{GC#+C$PdsR-xF_}- zD(;E&P;pO)P;rc4rnZL(6{k0$dU--C-filgo-mN;ParN;t~z1P;ruG6FUTK z4y{5Nr{geZAgMd|`1%HFF^Gjdqg^w2oca_OQhz*n@HoARIfBQj;`0QLldK}1<0nM$ zxF^0-g2&Cj|37#ruvzxsr%tWd_Mf#AD+l}k<9IHp33h}H2$~RW`0b&$3+HXLNc3`I z-`d&PskY(p-5sKT*T9WPAr8A3`UInBNNT)_$xvXSRbndQlUJ?kI4=!f_eah-iZ4|N zopYZ$_e#8l!l5kS)xP63opBIEtPNX+iZ|E=jaIJ=Pt3+QQbLuMN_h@qoOf8?NG+^D z3uIK|n2bx+VZxVn_^SFiRAN=9wBS))aVRr1NF0*|S1^gHU;U*`snd&H?oj;_q1{uE z)=xE;`-?Jq)>$%1LVGb3t$^=Z(=nhaq6l5Z&~H}<{2F6)rOghhfi`!r_p$RlH+8Px z_n6SBUHHEz zI-b|Yxbk((wWlcX`84u-;)zQ9Oh#?ow|jnwE|V4Od4d{8`SrQQm8C^84{svbV*+>Q zWv|(U!wCJ@a-;3mr0KUPB^;R}Jy8K+lv2Yf(F(^Pe8wr6G5SuTQ0PVuoMha7NZH?^ zVn1lPeNLo>M#95x^$7*Ya|#YvI&uj@osCf+mb++Pi&-Gt=TQOHM--{3I~_f6A=yu| zI3na~=atJhgty=rPAeU6jEDn40v4Ohga(MigVwt2Lrt520}W4uf%9n;&?HYa1ZJo2 zH^=UHH;*DZ2`{aVf}Jyrb4z)U_fYxO$Yb*G2#$FHnHqo`jEcRyz$VMU?r=A6ptq4n z#O6uTZgpgqV9^1G6p`{X=f%sD^@Bh5;JkoJI;hHZ;Sfpl!ZSpX9VV^ls<%@torz1( z*Q%C6YkD!Vv$%+;Za6P^krvquUviZv_)t;d7$c}TR`bJ-$qvnqlop`}D1t#I5}j1V z0lDP7u<0!EaU}z6#=VTsqOvPj8D-_<094!ZfWd=BZRi;_f?*KD4kt>SRuY&aAR>3% z=5rF|P-j#63ZId%A>Q4HJR13lpbUI@$@ls&S2l=w*cf3G8@gQM>9xBf=!ERU(7*g? zPGgTIYH(5oGQkTnbk?UCNBA>vv!(o`w<+|;#G6r^Qlf8DT4v0;&SyTHBRRLNj_{>6 zYvR#&FlH>;X|%2YggB9oV(&&f9d>{^$QOCZ|&;FTEYxZJgI(BInC9xc%cL@ zpM9=OpJqA0&#vR`7V|IBExV@+hf^G+PgG>D&7$@9dme38R#%?fcaQ@iE2shG0 zkdm|k&n9;sJgaM7SWvbJT@QqJU`}~^3jau@H)Y=@%07);9C*A4$thxoRC8I#q31dp zRKm`MrEs$o&4w8=$K553NDh6=(3}XqggxnwDzakx5o#)S zY3m)kXegfUx|EZyOE3l>H@mioj6QM6Pu64Q%e1cWTTa4UsX!63b_yqB-u=Va8ahi3SD}JOou8ayQFmc~zk^i$^Y|gdZVA7^IVnNvB{r=nB7HjzTXz+ID&YwoFbd zAv#G7$PXqr33*Ndq~Zo{>0B*~OpU>{@VrZ&cR7jdE3jEZ^^Ae}!!YvPcD3XvMGua3 zmwj?_gn0olCh-meBCVG(+WQU#Qgv@5G7KNXGJZmU#$E><3t%*W05N}Mq|+RTq%D+5 zu1&Ha3lpTLPbnN&0km9CMR$#fLt9U=`>+9@Qxv3wMkPQAIrgabfZ?{hIGTLeLr-bZ zmGs1eMkeEyNKF7lga|`>6hF%8LYW_FRY`lsglZ5Y-UeY1Lm!$B*_tH>EC%mV2wsWz zRpDeTn!7y=c614kgJw~_9P%P`HUsIz!7GQIvuRdjkRQUO=He}s0Dz39-_8N8BFiE# z@gc2r(FwPNfFnhRxA{|mvoiLSyC|2c<~F&G(F>{*(5#SHpf^SbcWGMgH~qdJ`GO5$ z%Z$-n>Wu1`q&QIm{mOrpP=N^=geqC(2}o@Yq}rb2N|cu|p8>AA9Q=xW8Zog9r{j5? z#9@G9bk`U32h`z@d^%ttTZyqic%|GDNUK#|WmMN9XQ;AE3#_b2O(QRKywxZV+BpX# zq2LI6cx}}429g-aVK*e&*kyu&zx;7dP7SVMFO5pXDQ5@fH1bAa-6_^en$x?9bs)=J zak&KegLN**MBA-6AqL`zGj8;~F8a8~e)3`)EbB9Dx*_ZR5!C1U=(>+{;kh_t#61h4 z916CIivWYFo?Z@`HoKPA8N0GiCFI>wip85 zX9s9JlwmJq6o#OQ(CjB7Ftuyw&OB)QkIh*;Y<$M+GPVCsCI(XwXVxXNfX(qO&Km zqwCRyBr<9WundEOErdod_QsJ*$L}i99r9M1yM| zLHNVAf5&f6$b*9;WjNf45@#@Oh2sHjwrI7{KGchwfq!8e@<8I=tqP`z&fpPEGZ7DA zd;muf+znfO&lL~?3dDeT`8AaY)n?KZq*V~o26B0Ljd)k(ToTr*QUn{}{Hv8q`;&@7 zL2cqffe~n-GX$;YnA%z*;s-^s$dLc0%hH=`H(uPJI1LxBUA?%D&Xersju9Bvuf9-r zF0OBE-dI2X62&{ff-hdXxPEE<0y$b@mrGT4+D{Ri1Z@)L(G8Jgnw?;LTd)bbUIJ+( z=gROIbhD;{2*f<7$CqKDyDMbh0Z5}T1zLE3Tx#qB04!bBsPY`-uQPo4G8?Ltb0okh z@M(|G#(>bX{k-esX((s}-lGMWfW7Ui4(Kpir01jy`l`UxffRU37i??2rk%~-Av3w7dl z5oN{8z$Sq!bRx_)EGvjeH!9>wO28Q6z&tZfUhh4RV(1$3b+Jr{-?{BJn*QLL37tG_ zBzYk3bC|4|rG-G?mF_4r7Kt%Pk}OdQjiqI#4nYp9%x_6Vn?#g}3OO`h$4FAai_oBx z8&8G_)C&$R#U2dv!{VDK)O&m{qE*Rhf_pGT*}Fp>DxD?qR6nBa(Mb?mPWD{HMBF2k z!-jN10rrK!k^L}nF&JkG#HDKPWtMgvMPz83%x#6(i`<0NAlre*+d{3%5{g|S@ zU0cw#y7e2!!KYZ-+ZC<2LTC&|g2UjLm8_%*V?KFgic`9jpowypW6BZ29<|7$8mAMC z@v%5Ylo)KD#wrIB$p9os+B;@0S5+FsOVvv&ow}e<2Bi*hr$x#~=0)p1GJa7`e+sd0O zR2+zIyanNLDIqE}6L1i1A_7#i8otQ9QN;3MrorJMc3^X+uOy9)Bekv5yO6g!9GArc z#l*754AvtVJm^rUGF`l)jCS0Mi&&8Kj9V0~Mt|H^tsntqNdj7=A$VFPDaR|+%Z*;; z1RPU*6V%htQ2|v|W4!CR1AImd9vCe!SnYtws6-m2kEq_oEmd;i4#od!aS9r(L6R7S z5fJN}#%Qt|q-moSZv>wr4kWNm(?u=V3r1|CUcWE*FKo`~vBBgW-`lZx zBDE4rc*V8YGu$`13T(Dsza#aJat;7CY6AB<+R_yzF!EVtFf>qJ7KUOv2a=;nN(g)n z8c(OyShbW>Iut58UQw*W-)RZavnNwGKb-li60t! zO3vO>h_CAMrr5K%4S7HmwImbDnHXSQaI6~PGat(UQWg$HR3b6;Ih@+D=tjzz6WT0T zHG;W5@gT~>8hc%Li~(+F{-KhygS#{<$~K{5S-VD{cxasRO9h1rg5#Yl%cVQI*~vQhxbtvWDEJvukUUD4?#=iT+jd=!>SG}aTLI-{S8Z0-CMjB^ziJVEkaDy5(0 z5^hle2ho)JaG1T;gfgJ8DNl0y&27jPS0fmfMP$tk848$zNDvX}K{{jc>0Apf15jF_ z5P)Jf@Lk`dt!~WvW!eV^urfe^s^DIZK(hQ4pFzrE&C6A*haAin1bM45heH!ACa(pp z1p{~Nqwl6v62%Hb+;dnMTLl!Bl|YspnXA?lN!(?T)qn(R%+7}yhfo*CNW;;rAhlgbz}iYTN!bNc|x zkolRAV#KvBYX>@{N*tmfikuQoZ3%6M)FR-fhxHYFx~MgK@zQveeCjHy!&5onWh`u> zHYQEEJ2V;lLUJ)K%Q`VrVTBmOLRW;IF#MA{Clx{TIrzGe%tF{s5%vCS(Il!jBYp~ zlN#)5a{of$e4!>Iu?Mx~{l2RU4)KU!l$T-R?;z4qw#$k18*!AQa$-FCa-r)!+%<$c z4sZ78qEKmi;*957wIZI{Sz9PtMss00faGwVO7Thnt%P?Hg%1AIBQp;QJNBptirTAHX~#6eL>s+F}I@=bO72&L6Pg8HPm zO~U9%ID)jop8kdewVyBnfT$5DrViVO%7-l5Ok%+V7v#U#1_u0K8`@}0I z5#$E1jnJ(Y88`1`xQU>FuxDI>rht`G%TVGMC1^85FKes_8S=)RW*0XIDWGW@L3I@; zjTroKY>1-(qm@Imgr^&1#S#EG4&t2`1}K^InX&YJ%$!71cY>!*p6>LsCQ{@mvW{S( zk19!dPfe5~EH8-Hs^OzdOcajSnH0yKmA2-su2AR!2hW%o)CNVNee=OqIC$W7<)Lg$ z_jNtL=|`-n@4GwdB43;nljGrbU~dWVn!35mcVwikFyw1XbzcwD5A<;VF2&;#aRlY@ue39TOp>EmFh$G#;!CF9q z`0<1+SEJ-;IeDinzOc~FSxk$5UFmWcWDFl1MXvIQr*_n*#w#u+Q zk*NxlO1v!f&qy93}iU%534zIB?)5{7Lwp#3;%6#+5ou%#f6f_jcFX#f$UV( zS?}<^PTCYSMwj;jxCdaM=1IFtnmm?Kw8JT1Kj%OY#SO=kg*yNL_O7fd6%XOL-TS*j1A=|<{k1Pm~olS+p;Gtwx zWcaZ`LZ@Zx*lX%7+ol2fqh&HtL*I2Vw?+~Pw#iz?b^+HX`gJ?w>U#x!p-?E?9(we1 zHO317cu2g8Y%uN9GEF5^B;gC%LwagfdaWOYL7M=#mm=GXpV!}}JO9ErO)V8-FEXtIPJlT4=2`t7dW}3gs##hrp!CG51T&LalDm)FF4=|~b_#`cw zViyHLi8&0bVkw6rLQ&W);-~eJ$89tnvj$t@a-%mh)%}@&lT{x8Q3?;LfSaF0b*9cU z_SP9@PhEB5H^_wK0FAIOTdv$KcYdQ~3<^A5FhYy*DX0by-5YC*6GdeD^L6PJi_M=n z_iDr?GN4Ihi`Q!6CjBFJ$Ya7#bdBk8@=-rP=R`fAI>776T1UHaC-GYZ@W&j11ki6` zNNG1RX=l}?M-m1msy@$$;_oh4aR!y`&6gg@O}pwtosL|vm+@2&yZKOFK$mu(E`v-N zbrlykEHf|$d3!JU3fx$2d|nypAO(El&=RT!bte=>e3NHv6Q0klnovv`9fyIU7dZDB z>vXGU#12hE`d$`5CtcjFWLGUF3+frW+*cKgtj&8V9xDEIPGNDa48u+!cwjJ5J{FCk zv-E5VQSrjxnfb6*cuE%)?X8goAQ6-zAH0gvI2KO3PqDT7{sbeBW7^2z~k)(q|< zGCq?P94Tx9z=*|aqM!75Ej(M;2Cp5+C2jB-bUTf`7-i$kF+1VhiFK=YNb&?mNM`3X z7kE$-7S`~BHsUTEmQsQoB!~=#WZT*ZC1_&cU4^$1uaMsHlpY#t(XJRy2c2~6k)n1q z)>8g#JeRLsI7f)44A6AC(ITHRk}9p*!kxq);&{h4fJVS?<=v-cd)g3U79X@h|s3bMz};G-}Pewc)XXl`@Fh&?Tz1?*ojrZ<>OhV z=zi}5;IAyzr<6b=E#-sU9odlrB*2C)DHz>G+$}xPC;iz+5}{7d94QnF#p6o+ytZEj zV;7jY8qKp8&FTr5))Xgu5Fa*cH6{%^sy1KL5?m)-Y++l6O8un`B*vpw`{^81XN_9( zq<#*5wda>{wb7u)na=FE`Xfzo?Wg@(;~Z>dr;#Hfi(BVa+)zK|`nO;tLxYRtXw}n$ zhmLKG>8Wb1NO|H)52ciGA7hNGb3;lTS38Knd$zzEmn<=F+c5_<0A1E!p_3ouc& z_@H(OQny$1dg)5)rgd>r)A?>O`x~h0PHX!#-fHtQ2IoP2AM+43YmI8XDZF*frclF) z!r3X)-Cdj><7u0YQ2c=3aghD;=JH`IjU{XYon( zQlQ$GDjqaUhvhCy1qp?h&g%0s%z@|Iqk&*T@QRdcFNr*PAi7p~c@no8wf#E&Lw_gH zqj!BQvqG!rpG_LdeDOS&QikQ7t{@5!27- zHC)}Sozi^qa;om{Uo>fH;R@VAqiJ2xVymC>ONsEjyqfFH16xl#&+%cketgkfkTL4{ zjHVDxvaGomVnWseM>@$sTtB3)_K)=K#idny86Q=_bV!#~4_?)wd8D6+)IqQ!JnEsy$8_DJBt}Rm7b(^(C$32&gA>94+8SD^~X0#+abKOoRZH-KM8_Gd`&BPRU1YH()_90UHI^{m`a6bV#|5$u?*U=16E7 z89TnmZIyGfzX4!jk9y!HU>>k_v?u-k6||Ouvs^`O`3bz14%4^VqVnk$ODQf9C*oE% z%UJ5IMMJx?d;&g^4pUGit0*!56dxux@j0BBu`yzD3!lh}8OMJWEvBG!7pO5mix-pI z`uxfONMQlI3GRdtO#+XbC}FF&2f-%GIt8e0oDb=lB#V#^3S4(jT%;vnM+wK8n1;0U zlQyPu?4ZB>?49V-h;fp19qXq;axY4VSXxA>08o}>Ayd9){^drS`N(w^w zSR~`hIhyS3wi|YLwGj@aA_$k8*$5{>j)!?{xQ&m;;O4od03xiU-b?3zO` z8a46#afrEqH*^M12x4;_IYz}>4k1oliqz7fX~vUy^jQOR(rA!VliOUznLQwbbU396 zO9#dFHgq|kx{GNh5nxv)Kyyv>VHv}R3}(IrJhJ(WZrikEd52ooy9eo*YeX^vt-x8o zFENp!;NB6GM!KE%;`v0KJ3gPqERgIv8X~*CkR;C|#k02ow*bYgfUWo*h^b^{T;{X9 zI~%6PfUB(S)=^;u-Z}tYA+S+Y32W!n(9eOKZy=Dy&_Y^`T2rcs70?2_OtIy>Z`9fM z7)^ZCzIw;?I8nTr5hutOCn-6f(MrpQdrAD5thI60=Yl3MTjUQ3YJ3!#WrDpT2~rR6 z3jOFDG8$p>&Jf5?_7$L{BixK$2(s6*(DqyWBq3Qy{PTcLPjEc9}J2) z|8}wNdc$cYANL*_Hqlk%1E;{9Jw9_aj^iDEuO!%fbge|T1@{93Ln;hs6W#sEY8kMP zqRoZZaT4B&y+Dz~DFKH_$)dEV5y=LArg?$6n^^H8$fLk}m8Dq%}p~Ewbr)P|}Pr9(jy3M*UyEg@4L+fq}t^7JAYaVECS__dc zY%l6=qPS+UkLKt+tRyTVbKrQ2`78Z3Oub7U)?~I_DsNyD zLcdX%96$%(D0@5uYc$L#cerxb;Mk*YSiu5%0o5X>R9hPyj*p!`)F#-Xmh(>|%@j)q z>VXB8^N?#WPov?Hh4{;ZZ944G4MDZ$Sjt3>Ub+}|ux?ZhPy_-C>Hlw0@|`X4{A zB_u%dWXuD^|D_qsCK(A>u;e7U74IqJnWp6?NO zVd_*`qQ%YyTx4u7CX}2lp==egh`^s=By!XJ@FAbTY134;z~8n?N~jLL?HfxFmq9qFr*%Ql4SacftX zJ%S+*%k+OeBD39nx!s z@x6^*9w>`!Tv)XR;b{7hlt$~-Y4|PP)9a02M!k(BrXMN)91ZygS>PLQu>M}Z2~+24 z(3OlAdPaXqN=pna`tS)>mndTF`m>1^*`SNqo>4$eRs?hjVx~dSnqe(@rPS0hT6z{g zO3(nvpoKhEIv!-h*1|P_FVUB!X+ULdxTR5+2N)D_|FBQ)rb>Yfnl34dgS_ExWYIZ{qbmAaYy}!dZoW zD+`rrZANxT|H?{V$PVNP$4WvKB^Pd$rgaFPvkmx{u?GIy2C)(QuIm%4VKSrxspWvfA)>m>$ycScoX*Gjv;!j0T(D=QWg_N_)@Su^ zU29(;8<;IguyK{q16*4*>TrG1(wH#q#YwX`)N854v@TZsSIhxB8@=oKJ5OwFnmFHu|YUuDM zdgiT!QCuwiwrybagH^dCM0nHVccq$mh7o^IeJgX&HSUgrVVv1ygQFKoG_m3^`V2VhBf-4(FPp;UEH`%1+h%mq$JHPQiZd46aW9d zN;^SR#qX!-Ee(Zbxc;85dWC2p?e>4ScX$0+f7YM%XZ=}!)}Qrf{aJt3pY><`S%21_ X^=JKAf7YM>=g+?Z5|4e(09XeAW*?2g literal 0 HcmV?d00001 diff --git a/js_upload/file-uploader/client/demo.htm b/js_upload/file-uploader/client/demo.htm new file mode 100644 index 00000000..2a0cd6d3 --- /dev/null +++ b/js_upload/file-uploader/client/demo.htm @@ -0,0 +1,38 @@ + + + + + + + + + + +

To upload a file, click on the button below. Drag-and-drop is supported in FF, Chrome.

+

Progress-bar is supported in FF3.6+, Chrome6+, Safari4+

+ +
+ +
+ + + + + \ No newline at end of file diff --git a/js_upload/file-uploader/client/do-nothing.htm b/js_upload/file-uploader/client/do-nothing.htm new file mode 100644 index 00000000..0da19059 --- /dev/null +++ b/js_upload/file-uploader/client/do-nothing.htm @@ -0,0 +1 @@ +{success:true} diff --git a/js_upload/file-uploader/client/fileuploader.css b/js_upload/file-uploader/client/fileuploader.css new file mode 100644 index 00000000..0e3f111a --- /dev/null +++ b/js_upload/file-uploader/client/fileuploader.css @@ -0,0 +1,31 @@ +.qq-uploader { position:relative; width: 100%;} + +.qq-upload-button { + display:block; /* or inline-block */ + width: 105px; padding: 7px 0; text-align:center; + background:#880000; border-bottom:1px solid #ddd;color:#fff; +} +.qq-upload-button-hover {background:#cc0000;} +.qq-upload-button-focus {outline:1px dotted black;} + +.qq-upload-drop-area { + position:absolute; top:0; left:0; width:100%; height:100%; min-height: 70px; z-index:2; + background:#FF9797; text-align:center; +} +.qq-upload-drop-area span { + display:block; position:absolute; top: 50%; width:100%; margin-top:-8px; font-size:16px; +} +.qq-upload-drop-area-active {background:#FF7171;} + +.qq-upload-list {margin:15px 35px; padding:0; list-style:disc;} +.qq-upload-list li { margin:0; padding:0; line-height:15px; font-size:12px;} +.qq-upload-file, .qq-upload-spinner, .qq-upload-size, .qq-upload-cancel, .qq-upload-failed-text { + margin-right: 7px; +} + +.qq-upload-file {} +.qq-upload-spinner {display:inline-block; background: url("loading.gif"); width:15px; height:15px; vertical-align:text-bottom;} +.qq-upload-size,.qq-upload-cancel {font-size:11px;} + +.qq-upload-failed-text {display:none;} +.qq-upload-fail .qq-upload-failed-text {display:inline;} \ No newline at end of file diff --git a/js_upload/file-uploader/client/fileuploader.js b/js_upload/file-uploader/client/fileuploader.js new file mode 100644 index 00000000..89c09ebf --- /dev/null +++ b/js_upload/file-uploader/client/fileuploader.js @@ -0,0 +1,1247 @@ +/** + * http://github.com/valums/file-uploader + * + * Multiple file upload component with progress-bar, drag-and-drop. + * © 2010 Andrew Valums ( andrew(at)valums.com ) + * + * Licensed under GNU GPL 2 or later, see license.txt. + */ + +// +// Helper functions +// + +var qq = qq || {}; + +/** + * Adds all missing properties from second obj to first obj + */ +qq.extend = function(first, second){ + for (var prop in second){ + first[prop] = second[prop]; + } +}; + +/** + * Searches for a given element in the array, returns -1 if it is not present. + * @param {Number} [from] The index at which to begin the search + */ +qq.indexOf = function(arr, elt, from){ + if (arr.indexOf) return arr.indexOf(elt, from); + + from = from || 0; + var len = arr.length; + + if (from < 0) from += len; + + for (; from < len; from++){ + if (from in arr && arr[from] === elt){ + return from; + } + } + return -1; +}; + +qq.getUniqueId = (function(){ + var id = 0; + return function(){ return id++; }; +})(); + +// +// Events + +qq.attach = function(element, type, fn){ + if (element.addEventListener){ + element.addEventListener(type, fn, false); + } else if (element.attachEvent){ + element.attachEvent('on' + type, fn); + } +}; +qq.detach = function(element, type, fn){ + if (element.removeEventListener){ + element.removeEventListener(type, fn, false); + } else if (element.attachEvent){ + element.detachEvent('on' + type, fn); + } +}; + +qq.preventDefault = function(e){ + if (e.preventDefault){ + e.preventDefault(); + } else{ + e.returnValue = false; + } +}; + +// +// Node manipulations + +/** + * Insert node a before node b. + */ +qq.insertBefore = function(a, b){ + b.parentNode.insertBefore(a, b); +}; +qq.remove = function(element){ + element.parentNode.removeChild(element); +}; + +qq.contains = function(parent, descendant){ + // compareposition returns false in this case + if (parent == descendant) return true; + + if (parent.contains){ + return parent.contains(descendant); + } else { + return !!(descendant.compareDocumentPosition(parent) & 8); + } +}; + +/** + * Creates and returns element from html string + * Uses innerHTML to create an element + */ +qq.toElement = (function(){ + var div = document.createElement('div'); + return function(html){ + div.innerHTML = html; + var element = div.firstChild; + div.removeChild(element); + return element; + }; +})(); + +// +// Node properties and attributes + +/** + * Sets styles for an element. + * Fixes opacity in IE6-8. + */ +qq.css = function(element, styles){ + if (styles.opacity != null){ + if (typeof element.style.opacity != 'string' && typeof(element.filters) != 'undefined'){ + styles.filter = 'alpha(opacity=' + Math.round(100 * styles.opacity) + ')'; + } + } + qq.extend(element.style, styles); +}; +qq.hasClass = function(element, name){ + var re = new RegExp('(^| )' + name + '( |$)'); + return re.test(element.className); +}; +qq.addClass = function(element, name){ + if (!qq.hasClass(element, name)){ + element.className += ' ' + name; + } +}; +qq.removeClass = function(element, name){ + var re = new RegExp('(^| )' + name + '( |$)'); + element.className = element.className.replace(re, ' ').replace(/^\s+|\s+$/g, ""); +}; +qq.setText = function(element, text){ + element.innerText = text; + element.textContent = text; +}; + +// +// Selecting elements + +qq.children = function(element){ + var children = [], + child = element.firstChild; + + while (child){ + if (child.nodeType == 1){ + children.push(child); + } + child = child.nextSibling; + } + + return children; +}; + +qq.getByClass = function(element, className){ + if (element.querySelectorAll){ + return element.querySelectorAll('.' + className); + } + + var result = []; + var candidates = element.getElementsByTagName("*"); + var len = candidates.length; + + for (var i = 0; i < len; i++){ + if (qq.hasClass(candidates[i], className)){ + result.push(candidates[i]); + } + } + return result; +}; + +/** + * obj2url() takes a json-object as argument and generates + * a querystring. pretty much like jQuery.param() + * + * how to use: + * + * `qq.obj2url({a:'b',c:'d'},'http://any.url/upload?otherParam=value');` + * + * will result in: + * + * `http://any.url/upload?otherParam=value&a=b&c=d` + * + * @param Object JSON-Object + * @param String current querystring-part + * @return String encoded querystring + */ +qq.obj2url = function(obj, temp, prefixDone){ + var uristrings = [], + prefix = '&', + add = function(nextObj, i){ + var nextTemp = temp + ? (/\[\]$/.test(temp)) // prevent double-encoding + ? temp + : temp+'['+i+']' + : i; + if ((nextTemp != 'undefined') && (i != 'undefined')) { + uristrings.push( + (typeof nextObj === 'object') + ? qq.obj2url(nextObj, nextTemp, true) + : (Object.prototype.toString.call(nextObj) === '[object Function]') + ? encodeURIComponent(nextTemp) + '=' + encodeURIComponent(nextObj()) + : encodeURIComponent(nextTemp) + '=' + encodeURIComponent(nextObj) + ); + } + }; + + if (!prefixDone && temp) { + prefix = (/\?/.test(temp)) ? (/\?$/.test(temp)) ? '' : '&' : '?'; + uristrings.push(temp); + uristrings.push(qq.obj2url(obj)); + } else if ((Object.prototype.toString.call(obj) === '[object Array]') && (typeof obj != 'undefined') ) { + // we wont use a for-in-loop on an array (performance) + for (var i = 0, len = obj.length; i < len; ++i){ + add(obj[i], i); + } + } else if ((typeof obj != 'undefined') && (obj !== null) && (typeof obj === "object")){ + // for anything else but a scalar, we will use for-in-loop + for (var i in obj){ + add(obj[i], i); + } + } else { + uristrings.push(encodeURIComponent(temp) + '=' + encodeURIComponent(obj)); + } + + return uristrings.join(prefix) + .replace(/^&/, '') + .replace(/%20/g, '+'); +}; + +// +// +// Uploader Classes +// +// + +var qq = qq || {}; + +/** + * Creates upload button, validates upload, but doesn't create file list or dd. + */ +qq.FileUploaderBasic = function(o){ + this._options = { + // set to true to see the server response + debug: false, + action: '/server/upload', + params: {}, + button: null, + multiple: true, + maxConnections: 3, + // validation + allowedExtensions: [], + sizeLimit: 0, + minSizeLimit: 0, + // events + // return false to cancel submit + onSubmit: function(id, fileName){}, + onProgress: function(id, fileName, loaded, total){}, + onComplete: function(id, fileName, responseJSON){}, + onCancel: function(id, fileName){}, + // messages + messages: { + typeError: "{file} has invalid extension. Only {extensions} are allowed.", + sizeError: "{file} is too large, maximum file size is {sizeLimit}.", + minSizeError: "{file} is too small, minimum file size is {minSizeLimit}.", + emptyError: "{file} is empty, please select files again without it.", + onLeave: "The files are being uploaded, if you leave now the upload will be cancelled." + }, + showMessage: function(message){ + alert(message); + } + }; + qq.extend(this._options, o); + + // number of files being uploaded + this._filesInProgress = 0; + this._handler = this._createUploadHandler(); + + if (this._options.button){ + this._button = this._createUploadButton(this._options.button); + } + + this._preventLeaveInProgress(); +}; + +qq.FileUploaderBasic.prototype = { + setParams: function(params){ + this._options.params = params; + }, + getInProgress: function(){ + return this._filesInProgress; + }, + _createUploadButton: function(element){ + var self = this; + + return new qq.UploadButton({ + element: element, + multiple: this._options.multiple && qq.UploadHandlerXhr.isSupported(), + onChange: function(input){ + self._onInputChange(input); + } + }); + }, + _createUploadHandler: function(){ + var self = this, + handlerClass; + + if(qq.UploadHandlerXhr.isSupported()){ + handlerClass = 'UploadHandlerXhr'; + } else { + handlerClass = 'UploadHandlerForm'; + } + + var handler = new qq[handlerClass]({ + debug: this._options.debug, + action: this._options.action, + maxConnections: this._options.maxConnections, + onProgress: function(id, fileName, loaded, total){ + self._onProgress(id, fileName, loaded, total); + self._options.onProgress(id, fileName, loaded, total); + }, + onComplete: function(id, fileName, result){ + self._onComplete(id, fileName, result); + self._options.onComplete(id, fileName, result); + }, + onCancel: function(id, fileName){ + self._onCancel(id, fileName); + self._options.onCancel(id, fileName); + } + }); + + return handler; + }, + _preventLeaveInProgress: function(){ + var self = this; + + qq.attach(window, 'beforeunload', function(e){ + if (!self._filesInProgress){return;} + + var e = e || window.event; + // for ie, ff + e.returnValue = self._options.messages.onLeave; + // for webkit + return self._options.messages.onLeave; + }); + }, + _onSubmit: function(id, fileName){ + this._filesInProgress++; + }, + _onProgress: function(id, fileName, loaded, total){ + }, + _onComplete: function(id, fileName, result){ + this._filesInProgress--; + if (result.error){ + this._options.showMessage(result.error); + } + }, + _onCancel: function(id, fileName){ + this._filesInProgress--; + }, + _onInputChange: function(input){ + if (this._handler instanceof qq.UploadHandlerXhr){ + this._uploadFileList(input.files); + } else { + if (this._validateFile(input)){ + this._uploadFile(input); + } + } + this._button.reset(); + }, + _uploadFileList: function(files){ + for (var i=0; i this._options.sizeLimit){ + this._error('sizeError', name); + return false; + + } else if (size && size < this._options.minSizeLimit){ + this._error('minSizeError', name); + return false; + } + + return true; + }, + _error: function(code, fileName){ + var message = this._options.messages[code]; + function r(name, replacement){ message = message.replace(name, replacement); } + + r('{file}', this._formatFileName(fileName)); + r('{extensions}', this._options.allowedExtensions.join(', ')); + r('{sizeLimit}', this._formatSize(this._options.sizeLimit)); + r('{minSizeLimit}', this._formatSize(this._options.minSizeLimit)); + + this._options.showMessage(message); + }, + _formatFileName: function(name){ + if (name.length > 33){ + name = name.slice(0, 19) + '...' + name.slice(-13); + } + return name; + }, + _isAllowedExtension: function(fileName){ + var ext = (-1 !== fileName.indexOf('.')) ? fileName.replace(/.*[.]/, '').toLowerCase() : ''; + var allowed = this._options.allowedExtensions; + + if (!allowed.length){return true;} + + for (var i=0; i 99); + + return Math.max(bytes, 0.1).toFixed(1) + ['kB', 'MB', 'GB', 'TB', 'PB', 'EB'][i]; + } +}; + + +/** + * Class that creates upload widget with drag-and-drop and file list + * @inherits qq.FileUploaderBasic + */ +qq.FileUploader = function(o){ + // call parent constructor + qq.FileUploaderBasic.apply(this, arguments); + + // additional options + qq.extend(this._options, { + element: null, + // if set, will be used instead of qq-upload-list in template + listElement: null, + + template: '
' + + '
Drop files here to upload
' + + '
Upload a file
' + + '
    ' + + '
    ', + + // template for one item in file list + fileTemplate: '
  • ' + + '' + + '' + + '' + + 'Cancel' + + 'Failed' + + '
  • ', + + classes: { + // used to get elements from templates + button: 'qq-upload-button', + drop: 'qq-upload-drop-area', + dropActive: 'qq-upload-drop-area-active', + list: 'qq-upload-list', + + file: 'qq-upload-file', + spinner: 'qq-upload-spinner', + size: 'qq-upload-size', + cancel: 'qq-upload-cancel', + + // added to list item when upload completes + // used in css to hide progress spinner + success: 'qq-upload-success', + fail: 'qq-upload-fail' + } + }); + // overwrite options with user supplied + qq.extend(this._options, o); + + this._element = this._options.element; + this._element.innerHTML = this._options.template; + this._listElement = this._options.listElement || this._find(this._element, 'list'); + + this._classes = this._options.classes; + + this._button = this._createUploadButton(this._find(this._element, 'button')); + + this._bindCancelEvent(); + this._setupDragDrop(); +}; + +// inherit from Basic Uploader +qq.extend(qq.FileUploader.prototype, qq.FileUploaderBasic.prototype); + +qq.extend(qq.FileUploader.prototype, { + /** + * Gets one of the elements listed in this._options.classes + **/ + _find: function(parent, type){ + var element = qq.getByClass(parent, this._options.classes[type])[0]; + if (!element){ + throw new Error('element not found ' + type); + } + + return element; + }, + _setupDragDrop: function(){ + var self = this, + dropArea = this._find(this._element, 'drop'); + + var dz = new qq.UploadDropZone({ + element: dropArea, + onEnter: function(e){ + qq.addClass(dropArea, self._classes.dropActive); + e.stopPropagation(); + }, + onLeave: function(e){ + e.stopPropagation(); + }, + onLeaveNotDescendants: function(e){ + qq.removeClass(dropArea, self._classes.dropActive); + }, + onDrop: function(e){ + dropArea.style.display = 'none'; + qq.removeClass(dropArea, self._classes.dropActive); + self._uploadFileList(e.dataTransfer.files); + } + }); + + dropArea.style.display = 'none'; + + qq.attach(document, 'dragenter', function(e){ + if (!dz._isValidFileDrag(e)) return; + + dropArea.style.display = 'block'; + }); + qq.attach(document, 'dragleave', function(e){ + if (!dz._isValidFileDrag(e)) return; + + var relatedTarget = document.elementFromPoint(e.clientX, e.clientY); + // only fire when leaving document out + if ( ! relatedTarget || relatedTarget.nodeName == "HTML"){ + dropArea.style.display = 'none'; + } + }); + }, + _onSubmit: function(id, fileName){ + qq.FileUploaderBasic.prototype._onSubmit.apply(this, arguments); + this._addToList(id, fileName); + }, + _onProgress: function(id, fileName, loaded, total){ + qq.FileUploaderBasic.prototype._onProgress.apply(this, arguments); + + var item = this._getItemByFileId(id); + var size = this._find(item, 'size'); + size.style.display = 'inline'; + + var text; + if (loaded != total){ + text = Math.round(loaded / total * 100) + '% from ' + this._formatSize(total); + } else { + text = this._formatSize(total); + } + + qq.setText(size, text); + }, + _onComplete: function(id, fileName, result){ + qq.FileUploaderBasic.prototype._onComplete.apply(this, arguments); + + // mark completed + var item = this._getItemByFileId(id); + qq.remove(this._find(item, 'cancel')); + qq.remove(this._find(item, 'spinner')); + + if (result.success){ + qq.addClass(item, this._classes.success); + } else { + qq.addClass(item, this._classes.fail); + } + }, + _addToList: function(id, fileName){ + var item = qq.toElement(this._options.fileTemplate); + item.qqFileId = id; + + var fileElement = this._find(item, 'file'); + qq.setText(fileElement, this._formatFileName(fileName)); + this._find(item, 'size').style.display = 'none'; + + this._listElement.appendChild(item); + }, + _getItemByFileId: function(id){ + var item = this._listElement.firstChild; + + // there can't be txt nodes in dynamically created list + // and we can use nextSibling + while (item){ + if (item.qqFileId == id) return item; + item = item.nextSibling; + } + }, + /** + * delegate click event for cancel link + **/ + _bindCancelEvent: function(){ + var self = this, + list = this._listElement; + + qq.attach(list, 'click', function(e){ + e = e || window.event; + var target = e.target || e.srcElement; + + if (qq.hasClass(target, self._classes.cancel)){ + qq.preventDefault(e); + + var item = target.parentNode; + self._handler.cancel(item.qqFileId); + qq.remove(item); + } + }); + } +}); + +qq.UploadDropZone = function(o){ + this._options = { + element: null, + onEnter: function(e){}, + onLeave: function(e){}, + // is not fired when leaving element by hovering descendants + onLeaveNotDescendants: function(e){}, + onDrop: function(e){} + }; + qq.extend(this._options, o); + + this._element = this._options.element; + + this._disableDropOutside(); + this._attachEvents(); +}; + +qq.UploadDropZone.prototype = { + _disableDropOutside: function(e){ + // run only once for all instances + if (!qq.UploadDropZone.dropOutsideDisabled ){ + + qq.attach(document, 'dragover', function(e){ + if (e.dataTransfer){ + e.dataTransfer.dropEffect = 'none'; + e.preventDefault(); + } + }); + + qq.UploadDropZone.dropOutsideDisabled = true; + } + }, + _attachEvents: function(){ + var self = this; + + qq.attach(self._element, 'dragover', function(e){ + if (!self._isValidFileDrag(e)) return; + + var effect = e.dataTransfer.effectAllowed; + if (effect == 'move' || effect == 'linkMove'){ + e.dataTransfer.dropEffect = 'move'; // for FF (only move allowed) + } else { + e.dataTransfer.dropEffect = 'copy'; // for Chrome + } + + e.stopPropagation(); + e.preventDefault(); + }); + + qq.attach(self._element, 'dragenter', function(e){ + if (!self._isValidFileDrag(e)) return; + + self._options.onEnter(e); + }); + + qq.attach(self._element, 'dragleave', function(e){ + if (!self._isValidFileDrag(e)) return; + + self._options.onLeave(e); + + var relatedTarget = document.elementFromPoint(e.clientX, e.clientY); + // do not fire when moving a mouse over a descendant + if (qq.contains(this, relatedTarget)) return; + + self._options.onLeaveNotDescendants(e); + }); + + qq.attach(self._element, 'drop', function(e){ + if (!self._isValidFileDrag(e)) return; + + e.preventDefault(); + self._options.onDrop(e); + }); + }, + _isValidFileDrag: function(e){ + var dt = e.dataTransfer, + // do not check dt.types.contains in webkit, because it crashes safari 4 + isWebkit = navigator.userAgent.indexOf("AppleWebKit") > -1; + + // dt.effectAllowed is none in Safari 5 + // dt.types.contains check is for firefox + return dt && dt.effectAllowed != 'none' && + (dt.files || (!isWebkit && dt.types.contains && dt.types.contains('Files'))); + + } +}; + +qq.UploadButton = function(o){ + this._options = { + element: null, + // if set to true adds multiple attribute to file input + multiple: false, + // name attribute of file input + name: 'file', + onChange: function(input){}, + hoverClass: 'qq-upload-button-hover', + focusClass: 'qq-upload-button-focus' + }; + + qq.extend(this._options, o); + + this._element = this._options.element; + + // make button suitable container for input + qq.css(this._element, { + position: 'relative', + overflow: 'hidden', + // Make sure browse button is in the right side + // in Internet Explorer + direction: 'ltr' + }); + + this._input = this._createInput(); +}; + +qq.UploadButton.prototype = { + /* returns file input element */ + getInput: function(){ + return this._input; + }, + /* cleans/recreates the file input */ + reset: function(){ + if (this._input.parentNode){ + qq.remove(this._input); + } + + qq.removeClass(this._element, this._options.focusClass); + this._input = this._createInput(); + }, + _createInput: function(){ + var input = document.createElement("input"); + + if (this._options.multiple){ + input.setAttribute("multiple", "multiple"); + } + + input.setAttribute("type", "file"); + input.setAttribute("name", this._options.name); + + qq.css(input, { + position: 'absolute', + // in Opera only 'browse' button + // is clickable and it is located at + // the right side of the input + right: 0, + top: 0, + fontFamily: 'Arial', + // 4 persons reported this, the max values that worked for them were 243, 236, 236, 118 + fontSize: '118px', + margin: 0, + padding: 0, + cursor: 'pointer', + opacity: 0 + }); + + this._element.appendChild(input); + + var self = this; + qq.attach(input, 'change', function(){ + self._options.onChange(input); + }); + + qq.attach(input, 'mouseover', function(){ + qq.addClass(self._element, self._options.hoverClass); + }); + qq.attach(input, 'mouseout', function(){ + qq.removeClass(self._element, self._options.hoverClass); + }); + qq.attach(input, 'focus', function(){ + qq.addClass(self._element, self._options.focusClass); + }); + qq.attach(input, 'blur', function(){ + qq.removeClass(self._element, self._options.focusClass); + }); + + // IE and Opera, unfortunately have 2 tab stops on file input + // which is unacceptable in our case, disable keyboard access + if (window.attachEvent){ + // it is IE or Opera + input.setAttribute('tabIndex', "-1"); + } + + return input; + } +}; + +/** + * Class for uploading files, uploading itself is handled by child classes + */ +qq.UploadHandlerAbstract = function(o){ + this._options = { + debug: false, + action: '/upload.php', + // maximum number of concurrent uploads + maxConnections: 999, + onProgress: function(id, fileName, loaded, total){}, + onComplete: function(id, fileName, response){}, + onCancel: function(id, fileName){} + }; + qq.extend(this._options, o); + + this._queue = []; + // params for files in queue + this._params = []; +}; +qq.UploadHandlerAbstract.prototype = { + log: function(str){ + if (this._options.debug && window.console) console.log('[uploader] ' + str); + }, + /** + * Adds file or file input to the queue + * @returns id + **/ + add: function(file){}, + /** + * Sends the file identified by id and additional query params to the server + */ + upload: function(id, params){ + var len = this._queue.push(id); + + var copy = {}; + qq.extend(copy, params); + this._params[id] = copy; + + // if too many active uploads, wait... + if (len <= this._options.maxConnections){ + this._upload(id, this._params[id]); + } + }, + /** + * Cancels file upload by id + */ + cancel: function(id){ + this._cancel(id); + this._dequeue(id); + }, + /** + * Cancells all uploads + */ + cancelAll: function(){ + for (var i=0; i= max){ + var nextId = this._queue[max-1]; + this._upload(nextId, this._params[nextId]); + } + } +}; + +/** + * Class for uploading files using form and iframe + * @inherits qq.UploadHandlerAbstract + */ +qq.UploadHandlerForm = function(o){ + qq.UploadHandlerAbstract.apply(this, arguments); + + this._inputs = {}; +}; +// @inherits qq.UploadHandlerAbstract +qq.extend(qq.UploadHandlerForm.prototype, qq.UploadHandlerAbstract.prototype); + +qq.extend(qq.UploadHandlerForm.prototype, { + add: function(fileInput){ + fileInput.setAttribute('name', 'qqfile'); + var id = 'qq-upload-handler-iframe' + qq.getUniqueId(); + + this._inputs[id] = fileInput; + + // remove file input from DOM + if (fileInput.parentNode){ + qq.remove(fileInput); + } + + return id; + }, + getName: function(id){ + // get input value and remove path to normalize + return this._inputs[id].value.replace(/.*(\/|\\)/, ""); + }, + _cancel: function(id){ + this._options.onCancel(id, this.getName(id)); + + delete this._inputs[id]; + + var iframe = document.getElementById(id); + if (iframe){ + // to cancel request set src to something else + // we use src="javascript:false;" because it doesn't + // trigger ie6 prompt on https + iframe.setAttribute('src', 'javascript:false;'); + + qq.remove(iframe); + } + }, + _upload: function(id, params){ + var input = this._inputs[id]; + + if (!input){ + throw new Error('file with passed id was not added, or already uploaded or cancelled'); + } + + var fileName = this.getName(id); + + var iframe = this._createIframe(id); + var form = this._createForm(iframe, params); + form.appendChild(input); + + var self = this; + this._attachLoadEvent(iframe, function(){ + self.log('iframe loaded'); + + var response = self._getIframeContentJSON(iframe); + + self._options.onComplete(id, fileName, response); + self._dequeue(id); + + delete self._inputs[id]; + // timeout added to fix busy state in FF3.6 + setTimeout(function(){ + qq.remove(iframe); + }, 1); + }); + + form.submit(); + qq.remove(form); + + return id; + }, + _attachLoadEvent: function(iframe, callback){ + qq.attach(iframe, 'load', function(){ + // when we remove iframe from dom + // the request stops, but in IE load + // event fires + if (!iframe.parentNode){ + return; + } + + // fixing Opera 10.53 + if (iframe.contentDocument && + iframe.contentDocument.body && + iframe.contentDocument.body.innerHTML == "false"){ + // In Opera event is fired second time + // when body.innerHTML changed from false + // to server response approx. after 1 sec + // when we upload file with iframe + return; + } + + callback(); + }); + }, + /** + * Returns json object received by iframe from server. + */ + _getIframeContentJSON: function(iframe){ + // iframe.contentWindow.document - for IE<7 + var doc = iframe.contentDocument ? iframe.contentDocument: iframe.contentWindow.document, + response; + + this.log("converting iframe's innerHTML to JSON"); + this.log("innerHTML = " + doc.body.innerHTML); + + try { + response = eval("(" + doc.body.innerHTML + ")"); + } catch(err){ + response = {}; + } + + return response; + }, + /** + * Creates iframe with unique name + */ + _createIframe: function(id){ + // We can't use following code as the name attribute + // won't be properly registered in IE6, and new window + // on form submit will open + // var iframe = document.createElement('iframe'); + // iframe.setAttribute('name', id); + + var iframe = qq.toElement('

    Back to project page