From 79a634460e12fa3f4bb32648c46a3e63a79c5771 Mon Sep 17 00:00:00 2001 From: fpollicelli Date: Sun, 14 May 2023 21:05:50 +0200 Subject: [PATCH 1/8] return to wizard when tool by closing the tool --- view/verify_pdf_timestamp.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/view/verify_pdf_timestamp.py b/view/verify_pdf_timestamp.py index d464673..e2cc52f 100644 --- a/view/verify_pdf_timestamp.py +++ b/view/verify_pdf_timestamp.py @@ -322,3 +322,7 @@ def __back_to_wizard(self): self.deleteLater() self.wizard.reload_case_info() self.wizard.show() + + def closeEvent(self, event): + event.ignore() + self.__back_to_wizard() From eb2e0090845a730b7c87328ba7a5ca3c420d79bc Mon Sep 17 00:00:00 2001 From: fpollicelli Date: Sun, 14 May 2023 23:22:59 +0200 Subject: [PATCH 2/8] disabled pec form --- view/post_acquisition/post.py | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/view/post_acquisition/post.py b/view/post_acquisition/post.py index 64a1c00..16e0031 100644 --- a/view/post_acquisition/post.py +++ b/view/post_acquisition/post.py @@ -35,8 +35,8 @@ def __init__(self, parent: None): def execute(self, folder, case_info, type): self.calculate_acquisition_file_hash(folder) self.generate_pdf_report(folder, case_info, type) - self.generate_timestamp_report(folder) - self.send_report_from_pec(folder, case_info, type) + self.generate_timestamp_report(folder, case_info, type) + def calculate_acquisition_file_hash(self, folder): @@ -66,7 +66,7 @@ def generate_pdf_report(self, folder, case_info,type): report.generate_pdf(type, self.parent().get_time()) self.parent().upadate_progress_bar() - def generate_timestamp_report(self, folder): + def generate_timestamp_report(self, folder, case_info, type): self.parent().set_message_on_the_statusbar(tasks.TIMESTAMP) options = TimestampController().options if options['enabled']: @@ -79,11 +79,14 @@ def generate_timestamp_report(self, folder): timestamp.finished.connect(timestamp.deleteLater) timestamp.finished.connect(self.thread_timestamp.quit) - self.thread_timestamp.finished.connect(self.__thread_timestamp_is_finished) + self.thread_timestamp.finished.connect(lambda:self.__thread_timestamp_is_finished(folder, case_info, type)) self.thread_timestamp.start() - def __thread_timestamp_is_finished(self): + def __thread_timestamp_is_finished(self,folder, case_info, type): + options = PecController().options + if options['enabled']: + self.send_report_from_pec(folder, case_info, type) self.parent().upadate_progress_bar() self.is_finished_timestamp = True self.__async_task_are_finished() @@ -92,15 +95,14 @@ def send_report_from_pec(self, folder, case_info, type): self.parent().set_message_on_the_statusbar(tasks.PEC) - options = PecController().options - if options['enabled']: - self.pec = PecView(self) - self.pec.sentpec.connect(lambda status: self.__is_pec_sent(status)) - self.pec.downloadedeml.connect(lambda status: self.__is_eml_downloaded(status)) - view_form=True - self.pec.init(case_info, type, folder, view_form) - if view_form is False: - self.pec.send() + self.pec = PecView(self) + self.pec.sentpec.connect(lambda status: self.__is_pec_sent(status)) + self.pec.downloadedeml.connect(lambda status: self.__is_eml_downloaded(status)) + view_form = False + self.pec.init(case_info, type, folder, view_form) + if view_form is False: + self.pec.send() + def __is_pec_sent(self, status): if status == Status.SUCCESS: From cea3ea99c506dea4307308ec48d33cf672852fd7 Mon Sep 17 00:00:00 2001 From: Fabio Zito Date: Sun, 14 May 2023 23:44:15 +0200 Subject: [PATCH 3/8] modify close Event --- view/instagram.py | 1 - view/mail.py | 11 ++++++++--- view/verify_pec.py | 4 ++++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/view/instagram.py b/view/instagram.py index 31770cf..f3f5353 100644 --- a/view/instagram.py +++ b/view/instagram.py @@ -507,6 +507,5 @@ def __back_to_wizard(self): self.wizard.show() def closeEvent(self, event): - print("CLOSE") event.ignore() self.__back_to_wizard() diff --git a/view/mail.py b/view/mail.py index 45a6778..5bf2254 100644 --- a/view/mail.py +++ b/view/mail.py @@ -702,6 +702,11 @@ def __configuration(self): self.configuration_view.exec_() def __back_to_wizard(self): - self.deleteLater() - self.wizard.reload_case_info() - self.wizard.show() + if self.is_acquisition_running is False: + self.deleteLater() + self.wizard.reload_case_info() + self.wizard.show() + + def closeEvent(self, event): + event.ignore() + self.__back_to_wizard() diff --git a/view/verify_pec.py b/view/verify_pec.py index 00db520..6841e44 100644 --- a/view/verify_pec.py +++ b/view/verify_pec.py @@ -172,3 +172,7 @@ def __back_to_wizard(self): self.deleteLater() self.wizard.reload_case_info() self.wizard.show() + + def closeEvent(self, event): + event.ignore() + self.__back_to_wizard() From d90f27e89646de70ff2870189a4fe92794c4bd31 Mon Sep 17 00:00:00 2001 From: fpollicelli Date: Mon, 15 May 2023 01:15:27 +0200 Subject: [PATCH 4/8] added error messages on pec config --- view/configurations/tabs/pec/pec.py | 47 +++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/view/configurations/tabs/pec/pec.py b/view/configurations/tabs/pec/pec.py index ab61b1b..1f939ee 100644 --- a/view/configurations/tabs/pec/pec.py +++ b/view/configurations/tabs/pec/pec.py @@ -5,10 +5,16 @@ # Copyright (c) 2023 FIT-Project # SPDX-License-Identifier: GPL-3.0-only # ----- -###### +###### +import imaplib +import smtplib from PyQt5 import QtCore, QtWidgets +from PyQt5.QtWidgets import QMessageBox + +from common.constants import error from controller.configurations.tabs.pec.pec import Pec as PecController +from view.error import Error as ErrorView from common.constants.view.pec import pec __is_tab__ = True @@ -143,11 +149,11 @@ def initUI(self): self.smtp_port.setSizePolicy(sizePolicy) self.smtp_port.setObjectName("smtp_port") self.horizontal_layout_SMTP.addWidget(self.smtp_port) - + def retranslateUi(self): self.setWindowTitle(pec.WINDOW_TITLE) - self.enabled_checkbox.setText(pec.ENABLE) + self.enabled_checkbox.setText(pec.ENABLE) self.group_box_credential.setTitle(pec.CREDENTIAL_CONFIGURATION) self.label_pec_email.setText(pec.LABEL_EMAIL) self.label_password.setText(pec.LABEL_PASSWORD) @@ -157,7 +163,7 @@ def retranslateUi(self): self.label_imap_port.setText(pec.LABEL_IMAP_PORT) self.label_smtp_server.setText(pec.LABEL_SMPT_SERVER) self.label_smtp_port.setText(pec.LABEL_SMPT_PORT) - + def __is_enabled_pec(self): self.group_box_credential.setEnabled(self.enabled_checkbox.isChecked()) self.group_box_retries.setEnabled(self.enabled_checkbox.isChecked()) @@ -190,9 +196,38 @@ def __get_current_values(self): self.options[keyword] = value + def __check_server(self): + try: + server = imaplib.IMAP4_SSL(self.imap_server.text(), int(self.imap_port.text())) + server.login(self.pec_email.text(), self.password.text()) + server.logout() + except Exception as e: + print(e) + raise Exception(e) + try: + server = smtplib.SMTP_SSL(self.smtp_server.text(), int(self.smtp_port.text())) + server.login(self.pec_email.text(), self.password.text()) + server.quit() + except Exception as e: + print(e) + raise Exception(e) + def accept(self) -> None: - self.__get_current_values() - self.controller.options = self.options + try: + self.__check_server() + except Exception as e: + error_dlg = ErrorView(QMessageBox.Critical, + pec.LOGIN_FAILED, + error.LOGIN_ERROR, + str(e) + ) + error_dlg.exec_() + + + else: + + self.__get_current_values() + self.controller.options = self.options def reject(self) -> None: pass \ No newline at end of file From ce8060f4676952f878e1ae6b4baba1740e2d85e8 Mon Sep 17 00:00:00 2001 From: Fabio Zito Date: Mon, 15 May 2023 01:59:19 +0200 Subject: [PATCH 5/8] fix bug hide acquisition tools on social page --- view/web/web.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/view/web/web.py b/view/web/web.py index de5b3af..a6f31e6 100644 --- a/view/web/web.py +++ b/view/web/web.py @@ -79,7 +79,7 @@ def __init__(self, *args, **kwargs): self.case_info = None self.__tasks = [] - self.setWindowFlag(QtCore.Qt.WindowMinMaxButtonsHint, False) + self.setWindowFlag(QtCore.Qt.WindowMinMaxButtonsHint, True) self.setObjectName('FITWeb') def init(self, case_info, wizard, options=None): @@ -509,16 +509,16 @@ def add_new_tab(self, qurl=None, label="Blank"): self.browser.loadFinished.connect(lambda _, i=i, browser=self.browser: self.__page_on_loaded(i, browser)) + + if i == 0: self.showMaximized() + def __page_on_loaded(self, tab_index, browser): self.tabs.setTabText(tab_index, browser.page().title()) - self.current_page_load_is_finished = True - self.navtb.enable_screenshot_buttons() - def tab_open_doubleclick(self, i): if i == -1 and self.isEnabled(): # No tab under the click self.add_new_tab() @@ -553,11 +553,13 @@ def navigate_to_url(self): # Does not receive the Url self.tabs.currentWidget().setUrl(q) - def load_progress(self, prog): - pass + def load_progress(self, progress): + if progress == 100: + self.current_page_load_is_finished = True + self.navtb.enable_screenshot_buttons() - def __update_urlbar(self, q, browser=None): + def __update_urlbar(self, q, browser=None): self.current_page_load_is_finished = False self.navtb.enable_screenshot_buttons() From 9f494e294a49bf6a00bd3511ba454a37a93be097 Mon Sep 17 00:00:00 2001 From: Fabio Zito Date: Mon, 15 May 2023 10:21:02 +0200 Subject: [PATCH 6/8] removed back to wizard menu --- view/instagram.py | 5 ----- view/mail.py | 6 ------ view/verify_pdf_timestamp.py | 6 ------ view/verify_pec.py | 6 ------ view/web/web.py | 5 ----- 5 files changed, 28 deletions(-) diff --git a/view/instagram.py b/view/instagram.py index f3f5353..2e3f0b9 100644 --- a/view/instagram.py +++ b/view/instagram.py @@ -121,11 +121,6 @@ def init(self, case_info, wizard, options=None): self.case_action.triggered.connect(self.__case) self.menuBar().addAction(self.case_action) - # BACK TO WIZARD - back_action = QtWidgets.QAction("Back to wizard", self) - back_action.setStatusTip("Go back to the main menu") - back_action.triggered.connect(self.__back_to_wizard) - self.menuBar().addAction(back_action) self.configuration_general = self.configuration_view.get_tab_from_name("configuration_general") diff --git a/view/mail.py b/view/mail.py index 5bf2254..2c28678 100644 --- a/view/mail.py +++ b/view/mail.py @@ -367,12 +367,6 @@ def init(self, case_info, wizard, options=None): self.case_action.triggered.connect(self.__case) self.menuBar().addAction(self.case_action) - # BACK ACTION - back_action = QtWidgets.QAction("Back to wizard", self) - back_action.setStatusTip("Go back to the main menu") - back_action.triggered.connect(self.__back_to_wizard) - self.menuBar().addAction(back_action) - self.configuration_general = self.configuration_view.get_tab_from_name("configuration_general") diff --git a/view/verify_pdf_timestamp.py b/view/verify_pdf_timestamp.py index e2cc52f..ad8e34a 100644 --- a/view/verify_pdf_timestamp.py +++ b/view/verify_pdf_timestamp.py @@ -77,12 +77,6 @@ def init(self, case_info, wizard, options=None): self.case_action.triggered.connect(self.case) self.menuBar().addAction(self.case_action) - # BACK ACTION - back_action = QtWidgets.QAction("Back to wizard", self) - back_action.setStatusTip("Go back to the main menu") - back_action.triggered.connect(self.__back_to_wizard) - self.menuBar().addAction(back_action) - # set font font = QtGui.QFont() font.setPointSize(10) diff --git a/view/verify_pec.py b/view/verify_pec.py index 6841e44..12e0f45 100644 --- a/view/verify_pec.py +++ b/view/verify_pec.py @@ -64,12 +64,6 @@ def init(self, case_info, wizard, options=None): self.case_action.triggered.connect(self.__case) self.menuBar().addAction(self.case_action) - # BACK ACTION - back_action = QtWidgets.QAction("Back to wizard", self) - back_action.setStatusTip("Go back to the main menu") - back_action.triggered.connect(self.__back_to_wizard) - self.menuBar().addAction(back_action) - self.eml_group_box = QtWidgets.QGroupBox(self.centralwidget) self.eml_group_box.setEnabled(True) self.eml_group_box.setGeometry(QtCore.QRect(50, 20, 500, 180)) diff --git a/view/web/web.py b/view/web/web.py index a6f31e6..a715983 100644 --- a/view/web/web.py +++ b/view/web/web.py @@ -150,11 +150,6 @@ def init(self, case_info, wizard, options=None): case_action.triggered.connect(self.case) self.menuBar().addAction(case_action) - # BACK ACTION - back_action = QtWidgets.QAction("Back to wizard", self) - back_action.setStatusTip("Go back to the main menu") - back_action.triggered.connect(self.__back_to_wizard) - self.menuBar().addAction(back_action) self.configuration_general = self.configuration_view.get_tab_from_name("configuration_general") From c5c96687623bf81b2073d03a19ef0fc48d2b1ce5 Mon Sep 17 00:00:00 2001 From: fpollicelli Date: Mon, 15 May 2023 11:35:46 +0200 Subject: [PATCH 7/8] added server verification in pec config --- common/constants/view/pec/pec.py | 4 ++ view/configurations/tabs/pec/pec.py | 79 +++++++++++++++++++++++------ 2 files changed, 67 insertions(+), 16 deletions(-) diff --git a/common/constants/view/pec/pec.py b/common/constants/view/pec/pec.py index 001e97f..7dd41dd 100644 --- a/common/constants/view/pec/pec.py +++ b/common/constants/view/pec/pec.py @@ -27,5 +27,9 @@ DOWNLOAD_EML_SUCCESS="EML file has been successfully downloaded." RETRIES_NUMBER="Retries EML download" SERVER_CONFIGURATION="Server configuration" +VERIFY_IMAP="Verify IMAP server" +VERIFY_SMTP="Verify SMTP server" + + diff --git a/view/configurations/tabs/pec/pec.py b/view/configurations/tabs/pec/pec.py index 1f939ee..43282c6 100644 --- a/view/configurations/tabs/pec/pec.py +++ b/view/configurations/tabs/pec/pec.py @@ -10,7 +10,8 @@ import smtplib from PyQt5 import QtCore, QtWidgets -from PyQt5.QtWidgets import QMessageBox +from PyQt5.QtGui import QPixmap +from PyQt5.QtWidgets import QMessageBox, QLabel, QSizePolicy from common.constants import error from controller.configurations.tabs.pec.pec import Pec as PecController @@ -88,7 +89,7 @@ def initUI(self): self.group_box_server.setObjectName("group_box_server") self.form_layout_widget_IMAP = QtWidgets.QWidget(self.group_box_server) - self.form_layout_widget_IMAP.setGeometry(QtCore.QRect(10, 20, 511, 24)) + self.form_layout_widget_IMAP.setGeometry(QtCore.QRect(10, 20, 600, 24)) self.form_layout_widget_IMAP.setObjectName("form_layout_widget_server_IMAP") self.horizontal_layout_IMAP = QtWidgets.QHBoxLayout(self.form_layout_widget_IMAP) self.horizontal_layout_IMAP.setContentsMargins(0, 0, 0, 0) @@ -116,8 +117,23 @@ def initUI(self): self.horizontal_layout_IMAP.addWidget(self.imap_port) + self.verification_imap_button = QtWidgets.QPushButton(self.form_layout_widget_IMAP) + self.verification_imap_button.clicked.connect(self.__verify_imap) + self.verification_imap_button.setObjectName("verification_imap_button") + self.verification_imap_button.setEnabled(True) + self.horizontal_layout_IMAP.addWidget(self.verification_imap_button) + + self.info_imap_img = QLabel(self) + self.info_imap_img.setEnabled(True) + self.info_imap_img.setPixmap(QPixmap("assets/images/red-mark.png").scaled(20, 20)) + self.info_imap_img.setScaledContents(True) + self.info_imap_img.setGeometry(QtCore.QRect(630, 192, 20, 20)) + self.info_imap_img.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) + self.info_imap_img.setVisible(False) + + self.form_layout_widget_SMTP = QtWidgets.QWidget(self.group_box_server) - self.form_layout_widget_SMTP.setGeometry(QtCore.QRect(10, 50, 511, 24)) + self.form_layout_widget_SMTP.setGeometry(QtCore.QRect(10, 50, 600, 24)) self.form_layout_widget_SMTP.setObjectName("form_layout_widget_SMTP") self.horizontal_layout_SMTP = QtWidgets.QHBoxLayout(self.form_layout_widget_SMTP) @@ -150,6 +166,21 @@ def initUI(self): self.smtp_port.setObjectName("smtp_port") self.horizontal_layout_SMTP.addWidget(self.smtp_port) + self.verification_smtp_button = QtWidgets.QPushButton(self.form_layout_widget_SMTP) + self.verification_smtp_button.clicked.connect(self.__verify_smtp) + self.verification_smtp_button.setObjectName("verification_smtp_button") + self.verification_smtp_button.setEnabled(True) + self.horizontal_layout_SMTP.addWidget(self.verification_smtp_button) + + self.info_smtp_img = QLabel(self) + self.info_smtp_img.setEnabled(True) + self.info_smtp_img.setPixmap(QPixmap("assets/images/red-mark.png").scaled(20, 20)) + self.info_smtp_img.setScaledContents(True) + self.info_smtp_img.setGeometry(QtCore.QRect(630, 222, 20, 20)) + self.info_smtp_img.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) + self.info_smtp_img.setVisible(False) + + def retranslateUi(self): self.setWindowTitle(pec.WINDOW_TITLE) @@ -163,6 +194,8 @@ def retranslateUi(self): self.label_imap_port.setText(pec.LABEL_IMAP_PORT) self.label_smtp_server.setText(pec.LABEL_SMPT_SERVER) self.label_smtp_port.setText(pec.LABEL_SMPT_PORT) + self.verification_imap_button.setText(pec.VERIFY_IMAP) + self.verification_smtp_button.setText(pec.VERIFY_SMTP) def __is_enabled_pec(self): self.group_box_credential.setEnabled(self.enabled_checkbox.isChecked()) @@ -196,26 +229,41 @@ def __get_current_values(self): self.options[keyword] = value - def __check_server(self): + def __verify_imap(self): try: + self.info_imap_img.setVisible(False) server = imaplib.IMAP4_SSL(self.imap_server.text(), int(self.imap_port.text())) server.login(self.pec_email.text(), self.password.text()) server.logout() + self.info_imap_img.setPixmap(QPixmap("assets/images/green-mark.png").scaled(20, 20)) + self.info_imap_img.setVisible(True) + except Exception as e: - print(e) - raise Exception(e) + self.info_imap_img.setPixmap(QPixmap("assets/images/red-mark.png").scaled(20, 20)) + self.info_imap_img.setVisible(True) + error_dlg = ErrorView(QMessageBox.Critical, + pec.LOGIN_FAILED, + error.LOGIN_ERROR, + str(e) + ) + error_dlg.exec_() + + + def __verify_smtp(self): try: + self.info_smtp_img.setVisible(False) server = smtplib.SMTP_SSL(self.smtp_server.text(), int(self.smtp_port.text())) server.login(self.pec_email.text(), self.password.text()) server.quit() - except Exception as e: - print(e) - raise Exception(e) + self.info_smtp_img.setPixmap(QPixmap("assets/images/green-mark.png").scaled(20, 20)) + self.info_smtp_img.setVisible(True) + - def accept(self) -> None: - try: - self.__check_server() except Exception as e: + + self.info_smtp_img.setPixmap(QPixmap("assets/images/red-mark.png").scaled(20, 20)) + self.info_smtp_img.setVisible(True) + error_dlg = ErrorView(QMessageBox.Critical, pec.LOGIN_FAILED, error.LOGIN_ERROR, @@ -223,11 +271,10 @@ def accept(self) -> None: ) error_dlg.exec_() + def accept(self) -> None: - else: - - self.__get_current_values() - self.controller.options = self.options + self.__get_current_values() + self.controller.options = self.options def reject(self) -> None: pass \ No newline at end of file From c4cd57518e350e9da4070c3409de6060fb6cb070 Mon Sep 17 00:00:00 2001 From: fpollicelli Date: Mon, 15 May 2023 11:37:46 +0200 Subject: [PATCH 8/8] added server verification in pec config --- assets/images/green-mark.png | Bin 0 -> 809 bytes assets/images/red-mark.png | Bin 0 -> 1276 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 assets/images/green-mark.png create mode 100644 assets/images/red-mark.png diff --git a/assets/images/green-mark.png b/assets/images/green-mark.png new file mode 100644 index 0000000000000000000000000000000000000000..546b535d117645f277ea8cb596cedb43d11ce06b GIT binary patch literal 809 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc3?z4jzqJQa3dtTpz6=aiY77hwEes65fI>pL`1Rl}kyGUoZm$ zt7dQxi`(*t-~S5te_HW;&5yTH94)^-zmMnI@-gMrzf8uk*O$D$<}n4nxMn7`s)X71 z*+EGjkH_o8T^@)!++8YYb&KU<)Muc1j7i?^F0Or>SA+vO>?NMQuI$fQ`8ieORn$)= z0EHfSx;TbNT+W?%Gw84ZkL%K$bMwTQcyqZHrm73vx+HpP)&Kv?PMu@ozt()b*zMEa za5jb~Mn0#v>0X{t&Tv%bVO5>Lk9pcMu0J^z&zRM zRdP`(kYX@0Ff!IPFx53Q4Kc8^GB&d^G}AUPure_4YN`Z<7eYgBeoAIqC2kGY_Yb}X oYS4h&P?DLOT3nKtTY#y@*brjLYmb}9fqED`UHx3vIVCg!0FmZ1YybcN literal 0 HcmV?d00001 diff --git a/assets/images/red-mark.png b/assets/images/red-mark.png new file mode 100644 index 0000000000000000000000000000000000000000..ac6c122f8643cd51998b84fc97dd0803a33a1587 GIT binary patch literal 1276 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc3?z4jzqJQa3dtTpz6=aistgPb%?u1b{{!il z3=E|P3=FRl7#OT(FffScPl`Y4#=yY1A;2fZ6{zQTL&FadksmTL-xwHvNK5|^7XIDZ z`kja8hoImOA))WQyuaJqzcVm=XJY!!%KDv=@rRVucV_0FmX<$6MZa@!d}m|(&dvRu zlk-n^H%Nq&6QqoV1*D#h?T5NLNERpp^#)hT9I80%`|J0d42v0x{rb z0vQk~h?x-eKm`zcAq=1(L=8kSkOayC-4EeHGy>TWWk4yQF1R_!Y9MC9r6B6zc0p7E zxqN)UsDZff|NsB#YIAvkan@H7q*LDKkl|zUOFpeUGB|*N1M_x4s3)7Jh$XcROE3I?*mhib+7PZDo8O&^e4r z-tI2_UzwVJ0y&%o9+AZi4BWyX%*Zfnjs#GUy~NYkmHjy@Kc|Ykiu%a}pq?^M7sn8Z z%gG4|DM@J)Crz6;b@Jq?)2AgRrY5H+Bs_T#5)cv;78n{F92yuFe&xZVXNd`qu3Wiv z?c&p?%uI2%vbnX)etK+ath&z1$-;4db#`%#!N$ehwcd_wVy?N`+0xP0af)$@)$H!- z>AB)!Y?`XF;j{PInU}}e@t@ykC#^4=ugR8~Dj&ap-#)wl4GsdLA~K6)PAM!tbXr=B z?}?iWQ|F3|xH!>Dw#d*0tcHBG2?El`wa+ZqI<2t$*zxn)0y6wU-X2ecA3h77%*^?T zi$hhlndNUVONFarlfv7Ym6-x>UrI9VQF!~wq5F(+BU9u}2PI2)hLnk0it^&@CPW8B zgzzl!@+zLXRC39c(o?5?|I*T`Y+beL_phw1(kV+E?yXs!pJ5^K!Ph_y8gLs*GILXlOA>Pn aF!dN4LM(ahaq~D(4}+(xpUXO@geCw8D7YX1 literal 0 HcmV?d00001