From c06c03e7456e91320fe3e42f9825e6335022aacc Mon Sep 17 00:00:00 2001 From: Bakka Uday Kiran Date: Thu, 23 Feb 2023 14:51:28 +0530 Subject: [PATCH] [M108 Migration][Native Control] JsPopup Migration & Bring up This patch brings up popup functionality for JavaScript APIs like window.alert(), window.prompt() etc. Reference: https://review.tizen.org/gerrit/c/278533 https://review.tizen.org/gerrit/c/271926 Change-Id: I9f50d76b8f5d8b309eb1749f6cb18a3e2ffccc4c Signed-off-by: Bakka Uday Kiran --- .../javascript_dialog_manager_efl.cc | 2 +- tizen_src/ewk/efl_integration/BUILD.gn | 11 +- .../browser/javascript_dialog_manager_efl.cc | 175 +++++++++------------ .../browser/javascript_dialog_manager_efl.h | 58 +++---- tizen_src/ewk/efl_integration/eweb_view.cc | 24 +++ tizen_src/ewk/efl_integration/eweb_view.h | 8 + tizen_src/ewk/efl_integration/public/ewk_view.cc | 7 +- .../efl_integration/resource/JavaScriptPopup.edc | 2 +- .../resource/images/popup_btn_cancel.png | Bin 0 -> 1184 bytes .../resource/images/popup_btn_ok.png | Bin 0 -> 1392 bytes 10 files changed, 143 insertions(+), 144 deletions(-) create mode 100644 tizen_src/ewk/efl_integration/resource/images/popup_btn_cancel.png create mode 100644 tizen_src/ewk/efl_integration/resource/images/popup_btn_ok.png diff --git a/tizen_src/chromium_impl/components/js_dialogs_efl/javascript_dialog_manager_efl.cc b/tizen_src/chromium_impl/components/js_dialogs_efl/javascript_dialog_manager_efl.cc index 1554d90..9f0fab3 100644 --- a/tizen_src/chromium_impl/components/js_dialogs_efl/javascript_dialog_manager_efl.cc +++ b/tizen_src/chromium_impl/components/js_dialogs_efl/javascript_dialog_manager_efl.cc @@ -62,7 +62,7 @@ void JavaScriptDialogManagerEfl::RunBeforeUnloadDialog( open_dialogs_[web_contents] = new JavaScriptModalDialogEfl( web_contents, JavaScriptModalDialogEfl::NAVIGATION, base::UTF8ToUTF16( - std::string(dgettext("WebKit", "IDS_WEBVIEW_BEFOREUNLOAD_MESSAGE"))), + std::string(dgettext("WebKit", "IDS_WEBVIEW_POP_LEAVE_THIS_PAGE_Q"))), std::u16string(), std::move(callback)); } diff --git a/tizen_src/ewk/efl_integration/BUILD.gn b/tizen_src/ewk/efl_integration/BUILD.gn index 3e32f33..2624586 100755 --- a/tizen_src/ewk/efl_integration/BUILD.gn +++ b/tizen_src/ewk/efl_integration/BUILD.gn @@ -644,6 +644,7 @@ shared_library("chromium-ewk") { } deps += [ "resource:edje_resources_ewk" ] deps += [ ":broken_image" ] + deps += [ ":popup_btns" ] } executable("efl_webprocess") { @@ -663,4 +664,12 @@ copy("launch_exec_script") { copy("broken_image") { sources = [ "./resource/images/broken_image.png" ] outputs = [ "$root_out_dir/images/{{source_file_part}}" ] -} \ No newline at end of file +} + +copy("popup_btns") { + sources = [ + "./resource/images/popup_btn_cancel.png", + "./resource/images/popup_btn_ok.png", + ] + outputs = [ "$root_out_dir/images/{{source_file_part}}" ] +} diff --git a/tizen_src/ewk/efl_integration/browser/javascript_dialog_manager_efl.cc b/tizen_src/ewk/efl_integration/browser/javascript_dialog_manager_efl.cc index b11690a..3a5b308 100644 --- a/tizen_src/ewk/efl_integration/browser/javascript_dialog_manager_efl.cc +++ b/tizen_src/ewk/efl_integration/browser/javascript_dialog_manager_efl.cc @@ -11,70 +11,7 @@ using content::BrowserThread; using web_contents_utils::WebViewFromWebContents; -JavaScriptModalCallbacksData::JavaScriptModalCallbacksData( - content::JavaScriptDialogType javascript_dialog_type, - void* user_data) - : alert_callback_(NULL), - user_data_(user_data), - javascript_dialog_type_(javascript_dialog_type) {} - -bool JavaScriptModalCallbacksData::Run(Evas_Object* obj, - const char* message_text, - const char* default_text) { - switch (javascript_dialog_type_) { - case content::JAVASCRIPT_DIALOG_TYPE_ALERT: { - if (alert_callback_) - return alert_callback_(obj, message_text, user_data_); - break; - } - case content::JAVASCRIPT_DIALOG_TYPE_CONFIRM: { - if (confirm_callback_) - return confirm_callback_(obj, message_text, user_data_); - break; - } - case content::JAVASCRIPT_DIALOG_TYPE_PROMPT: { - if (prompt_callback_) - return prompt_callback_(obj, message_text, default_text, user_data_); - break; - } - } - return false; -} - -JavaScriptModalCallbacksData* -JavaScriptModalCallbacksData::CreateWithAlertDialogData( - Ewk_View_JavaScript_Alert_Callback callback, - void* user_data) { - JavaScriptModalCallbacksData* callback_data = - new JavaScriptModalCallbacksData(content::JAVASCRIPT_DIALOG_TYPE_ALERT, - user_data); - callback_data->alert_callback_ = callback; - return callback_data; -} - -JavaScriptModalCallbacksData* -JavaScriptModalCallbacksData::CreateWithConfirmDialogData( - Ewk_View_JavaScript_Confirm_Callback callback, - void* user_data) { - JavaScriptModalCallbacksData* callback_data = - new JavaScriptModalCallbacksData(content::JAVASCRIPT_DIALOG_TYPE_CONFIRM, - user_data); - callback_data->confirm_callback_ = callback; - return callback_data; -} - -JavaScriptModalCallbacksData* -JavaScriptModalCallbacksData::CreateWithPromptDialogData( - Ewk_View_JavaScript_Prompt_Callback callback, - void* user_data) { - JavaScriptModalCallbacksData* callback_data = - new JavaScriptModalCallbacksData(content::JAVASCRIPT_DIALOG_TYPE_PROMPT, - user_data); - callback_data->prompt_callback_ = callback; - return callback_data; -} - -JavaScriptDialogManagerEfl::JavaScriptDialogManagerEfl() {} +JavaScriptDialogManagerEfl::JavaScriptDialogManagerEfl() : dialog_(nullptr) {} JavaScriptDialogManagerEfl::~JavaScriptDialogManagerEfl() {} @@ -93,34 +30,45 @@ void JavaScriptDialogManagerEfl::RunJavaScriptDialog( wv->SmartCallback().call(0); JavaScriptModalDialogEfl::Type type = JavaScriptModalDialogEfl::ALERT; - if (dialog_type == content::JAVASCRIPT_DIALOG_TYPE_ALERT) { - type = JavaScriptModalDialogEfl::ALERT; - if (alert_callback_data_) { - if (!(alert_callback_data_->Run(wv->evas_object(), - base::UTF16ToUTF8(message_text).c_str(), - NULL))) - ExecuteDialogClosedCallBack(false, std::string()); - } - } - if (dialog_type == content::JAVASCRIPT_DIALOG_TYPE_CONFIRM) { - type = JavaScriptModalDialogEfl::CONFIRM; - if (confirm_callback_data_) { - if (!(confirm_callback_data_->Run(wv->evas_object(), - base::UTF16ToUTF8(message_text).c_str(), - NULL))) - ExecuteDialogClosedCallBack(false, std::string()); - } - } - if (dialog_type == content::JAVASCRIPT_DIALOG_TYPE_PROMPT) { - type = JavaScriptModalDialogEfl::PROMPT; - if (prompt_callback_data_) { - if (!(prompt_callback_data_->Run( - wv->evas_object(), base::UTF16ToUTF8(message_text).c_str(), - base::UTF16ToUTF8(default_prompt_text).c_str()))) - ExecuteDialogClosedCallBack(false, std::string()); - } + switch (dialog_type) { + case content::JAVASCRIPT_DIALOG_TYPE_ALERT: + type = JavaScriptModalDialogEfl::ALERT; + if (alert_callback_data_.callback) { + if (!alert_callback_data_.callback( + wv->evas_object(), base::UTF16ToUTF8(message_text).c_str(), + alert_callback_data_.user_data)) { + ExecuteDialogClosedCallBack(false, std::string()); + } + return; + } + break; + case content::JAVASCRIPT_DIALOG_TYPE_CONFIRM: + type = JavaScriptModalDialogEfl::CONFIRM; + if (confirm_callback_data_.callback) { + if (!confirm_callback_data_.callback( + wv->evas_object(), base::UTF16ToUTF8(message_text).c_str(), + confirm_callback_data_.user_data)) { + ExecuteDialogClosedCallBack(false, std::string()); + } + return; + } + break; + case content::JAVASCRIPT_DIALOG_TYPE_PROMPT: + type = JavaScriptModalDialogEfl::PROMPT; + if (prompt_callback_data_.callback) { + if (!prompt_callback_data_.callback( + wv->evas_object(), base::UTF16ToUTF8(message_text).c_str(), + base::UTF16ToUTF8(default_prompt_text).c_str(), + prompt_callback_data_.user_data)) { + ExecuteDialogClosedCallBack(false, std::string()); + } + return; + } + break; + default: + break; } - + // If "*_callback_data_" doen't exist, create default popup dialog_.reset(JavaScriptModalDialogEfl::CreateDialogAndShow( web_contents, type, message_text, default_prompt_text, std::move(dialog_closed_callback_))); @@ -129,34 +77,33 @@ void JavaScriptDialogManagerEfl::RunJavaScriptDialog( void JavaScriptDialogManagerEfl::SetAlertCallback( Ewk_View_JavaScript_Alert_Callback callback, void* user_data) { - alert_callback_data_.reset( - JavaScriptModalCallbacksData::CreateWithAlertDialogData(callback, - user_data)); + alert_callback_data_.callback = callback; + alert_callback_data_.user_data = user_data; } void JavaScriptDialogManagerEfl::SetConfirmCallback( Ewk_View_JavaScript_Confirm_Callback callback, void* user_data) { - confirm_callback_data_.reset( - JavaScriptModalCallbacksData::CreateWithConfirmDialogData(callback, - user_data)); + confirm_callback_data_.callback = callback; + confirm_callback_data_.user_data = user_data; } void JavaScriptDialogManagerEfl::SetPromptCallback( Ewk_View_JavaScript_Prompt_Callback callback, void* user_data) { - prompt_callback_data_.reset( - JavaScriptModalCallbacksData::CreateWithPromptDialogData(callback, - user_data)); + prompt_callback_data_.callback = callback; + prompt_callback_data_.user_data = user_data; } void JavaScriptDialogManagerEfl::ExecuteDialogClosedCallBack( bool result, const std::string prompt_data) { - std::move(dialog_closed_callback_) - .Run(result, base::UTF8ToUTF16(prompt_data)); - if (dialog_) { + // If default dialog was created, callback is handled in dtor of dialog. + if (dialog_) dialog_.reset(nullptr); + else { + std::move(dialog_closed_callback_) + .Run(result, base::UTF8ToUTF16(prompt_data)); } } @@ -176,6 +123,16 @@ void JavaScriptDialogManagerEfl::RunBeforeUnloadDialog( EWebView* wv = WebViewFromWebContents(web_contents); wv->SmartCallback().call(0); + // TODO(karan.kumar): remove message argument from the callback + // http://suprem.sec.samsung.net/jira/browse/RWASP-204 + if (before_unload_confirm_panel_callback_.callback && + !before_unload_confirm_panel_callback_.callback( + wv->evas_object(), nullptr, + before_unload_confirm_panel_callback_.user_data)) { + std::move(dialog_closed_callback_).Run(false, std::u16string()); + return; + } + dialog_.reset(JavaScriptModalDialogEfl::CreateDialogAndShow( web_contents, JavaScriptModalDialogEfl::NAVIGATION, base::UTF8ToUTF16( @@ -194,3 +151,15 @@ bool JavaScriptDialogManagerEfl::HandleJavaScriptDialog( void JavaScriptDialogManagerEfl::CancelDialogs( content::WebContents* web_contents, bool reset_state) {} + +void JavaScriptDialogManagerEfl::SetBeforeUnloadConfirmPanelCallback( + Ewk_View_Before_Unload_Confirm_Panel_Callback callback, + void* user_data) { + before_unload_confirm_panel_callback_.callback = callback; + before_unload_confirm_panel_callback_.user_data = user_data; +} + +void JavaScriptDialogManagerEfl::ReplyBeforeUnloadConfirmPanel( + Eina_Bool result) { + std::move(dialog_closed_callback_).Run(result, std::u16string()); +} diff --git a/tizen_src/ewk/efl_integration/browser/javascript_dialog_manager_efl.h b/tizen_src/ewk/efl_integration/browser/javascript_dialog_manager_efl.h index 12a8314..9524650 100644 --- a/tizen_src/ewk/efl_integration/browser/javascript_dialog_manager_efl.h +++ b/tizen_src/ewk/efl_integration/browser/javascript_dialog_manager_efl.h @@ -2,13 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef JAVASCRIPT_DIALOG_MANAGER_EFL_H_ -#define JAVASCRIPT_DIALOG_MANAGER_EFL_H_ +#ifndef EWK_EFL_INTEGRATION_BROWSER_JAVASCRIPT_DIALOG_MANAGER_EFL_H_ +#define EWK_EFL_INTEGRATION_BROWSER_JAVASCRIPT_DIALOG_MANAGER_EFL_H_ #include #include "content/public/browser/javascript_dialog_manager.h" #include "eweb_view.h" #include "public/ewk_view_internal.h" +#include "public/ewk_view_product.h" #include "url/gurl.h" namespace content { @@ -16,39 +17,10 @@ class WebContents; } class JavaScriptModalDialogEfl; -class JavaScriptModalCallbacksData { - public: - bool Run(Evas_Object* obj, - const char* content_text, - const char* default_text); - static JavaScriptModalCallbacksData* CreateWithAlertDialogData( - Ewk_View_JavaScript_Alert_Callback callback, - void* user_data); - static JavaScriptModalCallbacksData* CreateWithConfirmDialogData( - Ewk_View_JavaScript_Confirm_Callback callback, - void* user_data); - static JavaScriptModalCallbacksData* CreateWithPromptDialogData( - Ewk_View_JavaScript_Prompt_Callback callback, - void* user_data); - ~JavaScriptModalCallbacksData() {} - - private: - JavaScriptModalCallbacksData( - content::JavaScriptDialogType javascript_dialog_type, - void* user_data); - union { - Ewk_View_JavaScript_Alert_Callback alert_callback_; - Ewk_View_JavaScript_Confirm_Callback confirm_callback_; - Ewk_View_JavaScript_Prompt_Callback prompt_callback_; - }; - void* user_data_; - content::JavaScriptDialogType javascript_dialog_type_; -}; - class JavaScriptDialogManagerEfl : public content::JavaScriptDialogManager { public: JavaScriptDialogManagerEfl(); - virtual ~JavaScriptDialogManagerEfl(); + ~JavaScriptDialogManagerEfl() override; JavaScriptDialogManagerEfl(const JavaScriptDialogManagerEfl&) = delete; JavaScriptDialogManagerEfl& operator=(const JavaScriptDialogManagerEfl&) = @@ -80,13 +52,27 @@ class JavaScriptDialogManagerEfl : public content::JavaScriptDialogManager { void* user_data); void ExecuteDialogClosedCallBack(bool result, const std::string prompt_data); void SetPopupSize(int width, int height); + void SetBeforeUnloadConfirmPanelCallback( + Ewk_View_Before_Unload_Confirm_Panel_Callback callback, + void* user_data); + void ReplyBeforeUnloadConfirmPanel(Eina_Bool result); private: + template + struct CallbackData { + CallbackData() : callback(nullptr), user_data(nullptr) {} + + CallbackType callback; + void* user_data; + }; + std::unique_ptr dialog_; - std::unique_ptr alert_callback_data_; - std::unique_ptr confirm_callback_data_; - std::unique_ptr prompt_callback_data_; + CallbackData alert_callback_data_; + CallbackData confirm_callback_data_; + CallbackData prompt_callback_data_; + CallbackData + before_unload_confirm_panel_callback_; DialogClosedCallback dialog_closed_callback_; }; -#endif /* JAVASCRIPT_DIALOG_MANAGER_EFL_H_ */ +#endif // EWK_EFL_INTEGRATION_BROWSER_JAVASCRIPT_DIALOG_MANAGER_EFL_H_ diff --git a/tizen_src/ewk/efl_integration/eweb_view.cc b/tizen_src/ewk/efl_integration/eweb_view.cc index b57d167..cfac19e 100644 --- a/tizen_src/ewk/efl_integration/eweb_view.cc +++ b/tizen_src/ewk/efl_integration/eweb_view.cc @@ -139,6 +139,15 @@ void GetEinaRectFromGfxRect(const gfx::Rect& gfx_rect, eina_rect->h = gfx_rect.height(); } +#if BUILDFLAG(IS_TIZEN) +static Eina_Bool RotateWindowCb(void* data, int type, void* event) { + auto wv = static_cast(data); + wv->SetOrientation( + ecore_evas_rotation_get(ecore_evas_ecore_evas_get(wv->GetEvas()))); + return ECORE_CALLBACK_PASS_ON; +} +#endif + static content::WebContents* NullCreateWebContents(void*) { return NULL; } @@ -333,6 +342,10 @@ EWebView::EWebView(Ewk_Context* context, Evas_Object* object) OnViewFocusIn, this); evas_object_event_callback_add(evas_object_, EVAS_CALLBACK_FOCUS_OUT, OnViewFocusOut, this); +#if BUILDFLAG(IS_TIZEN) + window_rotate_handler_ = ecore_event_handler_add( + ECORE_WL2_EVENT_WINDOW_ROTATE, RotateWindowCb, this); +#endif } } @@ -2892,6 +2905,17 @@ void EWebView::SetSessionTimeout(uint64_t timeout) { rwhva()->host()->SetLongPollingGlobalTimeout(timeout); } +void EWebView::SetBeforeUnloadConfirmPanelCallback( + Ewk_View_Before_Unload_Confirm_Panel_Callback callback, + void* user_data) { + GetJavaScriptDialogManagerEfl()->SetBeforeUnloadConfirmPanelCallback( + callback, user_data); +} + +void EWebView::ReplyBeforeUnloadConfirmPanel(Eina_Bool result) { + GetJavaScriptDialogManagerEfl()->ReplyBeforeUnloadConfirmPanel(result); +} + void EWebView::SetExceededIndexedDatabaseQuotaCallback( Ewk_View_Exceeded_Indexed_Database_Quota_Callback callback, void* user_data) { diff --git a/tizen_src/ewk/efl_integration/eweb_view.h b/tizen_src/ewk/efl_integration/eweb_view.h index 42f4698..3df69fb 100644 --- a/tizen_src/ewk/efl_integration/eweb_view.h +++ b/tizen_src/ewk/efl_integration/eweb_view.h @@ -640,6 +640,10 @@ class EWebView { Ewk_View_Request_Manifest_Callback callback, void* user_data); + void SetBeforeUnloadConfirmPanelCallback( + Ewk_View_Before_Unload_Confirm_Panel_Callback callback, + void* user_data); + void ReplyBeforeUnloadConfirmPanel(Eina_Bool result); void SyncAcceptLanguages(const std::string& accept_languages); void OnOverscrolled(const gfx::Vector2dF& accumulated_overscroll, @@ -844,6 +848,10 @@ class EWebView { content::QuotaPermissionContext::PermissionCallback> quota_permission_request_map_; +#if BUILDFLAG(IS_TIZEN) + Ecore_Event_Handler* window_rotate_handler_ = nullptr; +#endif + bool is_initialized_; std::unique_ptr<_Ewk_Back_Forward_List> back_forward_list_; diff --git a/tizen_src/ewk/efl_integration/public/ewk_view.cc b/tizen_src/ewk/efl_integration/public/ewk_view.cc index 82cb5e5..e2c3269 100644 --- a/tizen_src/ewk/efl_integration/public/ewk_view.cc +++ b/tizen_src/ewk/efl_integration/public/ewk_view.cc @@ -564,12 +564,15 @@ void ewk_view_javascript_prompt_reply(Evas_Object* view, const char* result) void ewk_view_before_unload_confirm_panel_callback_set(Evas_Object* ewkView, Ewk_View_Before_Unload_Confirm_Panel_Callback callback, void* userData) { - LOG_EWK_API_MOCKUP(); + EWK_VIEW_IMPL_GET_OR_RETURN(ewkView, impl); + EINA_SAFETY_ON_NULL_RETURN(callback); + impl->SetBeforeUnloadConfirmPanelCallback(callback, userData); } void ewk_view_before_unload_confirm_panel_reply(Evas_Object* ewkView, Eina_Bool result) { - LOG_EWK_API_MOCKUP(); + EWK_VIEW_IMPL_GET_OR_RETURN(ewkView, impl); + impl->ReplyBeforeUnloadConfirmPanel(result); } Eina_Bool ewk_view_web_application_capable_get(Evas_Object* ewkView, Ewk_Web_App_Capable_Get_Callback callback, void* userData) diff --git a/tizen_src/ewk/efl_integration/resource/JavaScriptPopup.edc b/tizen_src/ewk/efl_integration/resource/JavaScriptPopup.edc index efb3d8d..25292f1 100644 --- a/tizen_src/ewk/efl_integration/resource/JavaScriptPopup.edc +++ b/tizen_src/ewk/efl_integration/resource/JavaScriptPopup.edc @@ -30,7 +30,7 @@ collections { scale : 1; description { state: "default" 0.0; - min: 0 70; + min: 0 30; align: 0.5 0.5; fixed: 1 0; rel1 { diff --git a/tizen_src/ewk/efl_integration/resource/images/popup_btn_cancel.png b/tizen_src/ewk/efl_integration/resource/images/popup_btn_cancel.png new file mode 100644 index 0000000000000000000000000000000000000000..5f346cb1623ffc78d757ca3d0e4528043ca5e42a GIT binary patch literal 1184 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC$r9IylHmNblJdl&R0hYC{G?O` z&)mfH)S%SFl*+=BsWuD@%qp275hW46K32*3xq68pHF_1f1wh>l3^w)^1&PVosU-?Y zsp*+{wo31J?^jaDOtDo8H}y5}EpSfF$n>ZxN)4{^3rViZPPR-@vbR&PsjvbXkegbP zs8ErclUHn2VXFi-*9yo63F|8hm3bwJ6}oxF$}kgLQj3#|G7CyF^YauyCMG83 zmzLNn0bL65LT&-v*t}wBFaZNhzap_f-%!s00+w{G(#^lGsVin%-qt%z{teX!qLRg(AC7!$;r*t#LUvz z$<)%)%)kPs*Cju>G&eP`1g19ysMpZa)X?0>&;qE}6sulPV#qB3+U$~Alv$RV;#QQO zs{r=2RVHq?7~yscL~jZfw?O@2j8m^Z&@uX;s6~oum=G}ifSB-v3*^9)erg^ty%zx! zHjl2}Yz78KAx{^_kcwMxW?tkyWWeJRe9CIg5t%fmO&)4Vaw1J4oi!p!le@LT(@)w@ zO}g(byJMU8Im?Q^-~u@o1qMbA2L`5yB;A=_r&x4@vez#Q&DUOdW^2l+`2vS;#d!sr zUyWO}b(-4R3YC_eE55hBP7|!kiP_EHH~EUxthmFBVXkcJbIMDY|D1o7y=j{QPUmrh$$_!6eKbLh* G2~7Z}D~yo< literal 0 HcmV?d00001 diff --git a/tizen_src/ewk/efl_integration/resource/images/popup_btn_ok.png b/tizen_src/ewk/efl_integration/resource/images/popup_btn_ok.png new file mode 100644 index 0000000000000000000000000000000000000000..f20f62e7f8872c282aa2bb8135b3393de9dff42f GIT binary patch literal 1392 zcmbVMZA=?=7(aoHm&u?Sw6bZ=gJp@*-b=49cT(WEYgr@ZrEMH8e&BjN=%rk*-W|47 zRE8#2Hg)oWWeI}Gf*NCR(?pCirpdBpya;A7OSX)ez@~F!#QK6{!+3?3`GM?%m%ID_ z|IauP*+$`S^xk*p=%%G(N-k&>K;vw^M`&-0Z4kR23!EozIqp5!Fa$fk6RF)^Z{0id!v7Gb#%uY!KQT?pHu z9@WLdNXSx?NJ+ zr^GM>uB)gaJG2p0i@OP=C7B1!M#R7&78JDLMifT~oTvaX1VvyJgAuC%MM$%iL{Kn& zL7F!?&_;R~XWEx`vO_^tjgT-LjYf@8lTnh}VU!>U7{Oo+GiVwHr7NtmF+*4>%UED| zg_DJdDo9~4Ws&tuovIzuBHc(qjJVyKhQmslD2*~W#ztV&h`^$l%4=O)Q9b;Wt1L)sT(KnRcyim^Bd z6vs_w+<~KLt%ETW6y~&=EDVKPv5bwau!zZILl84X*lZMvI&h-4*6F}4gsIj{5EjIi z!MehV%7!^U<5$r9rm@6*u_P_?tSZSqN$SXSKvPgsB_$|DK-z0IqM)1Qgm6ldD$qv0 z3@-~W@d2kSiQqcJq_9N_qpW*XZ5V1@X1lADu`AD0dAh}}M|uZ~aw9?&_$2XCLa>wFa}!}))X_kMCsSu3^`RQAZz zr}l1NJ@8Q1W#Ij9UpbtZXj|UZ;(kinb)xJK6UOWg{Wbpj*N3|My}^scXwJy7g?ArJ zhDMXFtc0CDGc%l^XHf5n+jNxxoRkt@0rr_oxxv5tqxs;@H?AD%zVOj_sOJXWe15EZ z>P{YVs`>b84qKX>$f_Uyz5Hs!v-9mezaDyL@fl(A&Q7pl-1~?6_N0c#kZNwP|r;n;w|WU0S;JTJg=)KhWi9U`A_Od;bN2{Oh;? literal 0 HcmV?d00001 -- 2.7.4