From b8475e3a57a0e74bed58c1d66f01070e9a0e577b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Mummert?= Date: Sun, 17 May 2026 17:31:28 +0200 Subject: [PATCH] Initial survey bundle import --- .gitignore | 1 + composer.json | 33 ++ config/services.yaml | 22 + contao/config/config.php | 21 + contao/dca/tl_member.php | 55 ++ contao/dca/tl_module.php | 32 ++ contao/dca/tl_settings.php | 30 ++ contao/dca/tl_survey.php | 212 ++++++++ contao/dca/tl_survey_answer.php | 60 +++ contao/dca/tl_survey_category.php | 70 +++ contao/dca/tl_survey_condition.php | 93 ++++ contao/dca/tl_survey_content.php | 241 +++++++++ contao/dca/tl_survey_editor.php | 75 +++ contao/dca/tl_survey_submission.php | 74 +++ contao/languages/de/modules.php | 10 + contao/languages/de/tl_member.php | 5 + contao/languages/de/tl_module.php | 6 + contao/languages/de/tl_settings.php | 6 + contao/languages/de/tl_survey.php | 23 + contao/languages/de/tl_survey_answer.php | 5 + contao/languages/de/tl_survey_category.php | 6 + contao/languages/de/tl_survey_condition.php | 6 + contao/languages/de/tl_survey_content.php | 32 ++ contao/languages/de/tl_survey_editor.php | 4 + contao/languages/de/tl_survey_submission.php | 7 + .../frontend/_survey_assets.html.twig | 410 +++++++++++++++ .../frontend/_survey_branding.html.twig | 3 + .../frontend/member_survey_edit.html.twig | 193 +++++++ .../frontend/member_survey_list.html.twig | 52 ++ .../templates/frontend/show_survey.html.twig | 84 +++ .../frontend/show_survey_results.html.twig | 162 ++++++ public/fonts/Blogger Sans-Medium.woff2 | Bin 0 -> 43008 bytes public/fonts/PTSansNarrow-Bold.woff2 | Bin 0 -> 124496 bytes public/fonts/PTSansNarrow-Regular.woff2 | Bin 0 -> 91440 bytes public/images/Logo_Landesverband.svg | 59 +++ public/images/kigu.svg | 67 +++ src/Contao/Manager/Plugin.php | 34 ++ .../MemberSurveyEditController.php | 273 ++++++++++ .../MemberSurveyListController.php | 80 +++ .../FrontendModule/ShowSurveyController.php | 126 +++++ .../ShowSurveyResultsController.php | 93 ++++ .../SurveyResultsExportController.php | 61 +++ src/DependencyInjection/SurveyExtension.php | 33 ++ src/EventListener/SurveyDcaListener.php | 477 ++++++++++++++++++ src/Form/Model/SurveyAnswerData.php | 10 + src/Form/Model/SurveyConditionData.php | 36 ++ src/Form/Model/SurveyEditorData.php | 36 ++ src/Form/Model/SurveyQuestionData.php | 86 ++++ src/Form/SurveyConditionEditorType.php | 48 ++ src/Form/SurveyEditorType.php | 44 ++ src/Form/SurveyQuestionAnswerType.php | 40 ++ src/Form/SurveyQuestionEditorType.php | 155 ++++++ src/Model/SurveyAnswerModel.php | 12 + src/Model/SurveyCategoryModel.php | 12 + src/Model/SurveyConditionModel.php | 12 + src/Model/SurveyContentModel.php | 12 + src/Model/SurveyEditorModel.php | 12 + src/Model/SurveyModel.php | 12 + src/Model/SurveySubmissionModel.php | 12 + src/QuestionType/ChoiceQuestionType.php | 79 +++ src/QuestionType/QuestionTypeInterface.php | 22 + src/QuestionType/QuestionTypeRegistry.php | 46 ++ src/QuestionType/RangeQuestionType.php | 56 ++ src/QuestionType/TextQuestionType.php | 48 ++ src/QuestionType/YesNoMaybeQuestionType.php | 61 +++ src/Repository/SurveyAnswerRepository.php | 104 ++++ src/Repository/SurveyConditionRepository.php | 93 ++++ src/Repository/SurveyEditorRepository.php | 177 +++++++ src/Repository/SurveyQuestionRepository.php | 163 ++++++ src/Repository/SurveyRepository.php | 346 +++++++++++++ src/Repository/SurveySubmissionRepository.php | 117 +++++ src/Resources/config/routes.yaml | 3 + .../views/pdf/survey_results.html.twig | 338 +++++++++++++ src/Security/SurveyEditorVoter.php | 36 ++ .../SurveyCategoryAssignmentService.php | 111 ++++ src/Service/SurveyEditorService.php | 107 ++++ src/Service/SurveyEngine.php | 38 ++ src/Service/SurveyFlowService.php | 134 +++++ src/Service/SurveyPermissionService.php | 29 ++ src/Service/SurveyResultsExportService.php | 242 +++++++++ src/Service/SurveyResultsPdfService.php | 409 +++++++++++++++ src/Service/SurveyResultsViewService.php | 395 +++++++++++++++ src/Service/SurveySubmissionService.php | 113 +++++ src/SurveyBundle.php | 15 + 84 files changed, 7157 insertions(+) create mode 100644 .gitignore create mode 100644 composer.json create mode 100644 config/services.yaml create mode 100644 contao/config/config.php create mode 100644 contao/dca/tl_member.php create mode 100644 contao/dca/tl_module.php create mode 100644 contao/dca/tl_settings.php create mode 100644 contao/dca/tl_survey.php create mode 100644 contao/dca/tl_survey_answer.php create mode 100644 contao/dca/tl_survey_category.php create mode 100644 contao/dca/tl_survey_condition.php create mode 100644 contao/dca/tl_survey_content.php create mode 100644 contao/dca/tl_survey_editor.php create mode 100644 contao/dca/tl_survey_submission.php create mode 100644 contao/languages/de/modules.php create mode 100644 contao/languages/de/tl_member.php create mode 100644 contao/languages/de/tl_module.php create mode 100644 contao/languages/de/tl_settings.php create mode 100644 contao/languages/de/tl_survey.php create mode 100644 contao/languages/de/tl_survey_answer.php create mode 100644 contao/languages/de/tl_survey_category.php create mode 100644 contao/languages/de/tl_survey_condition.php create mode 100644 contao/languages/de/tl_survey_content.php create mode 100644 contao/languages/de/tl_survey_editor.php create mode 100644 contao/languages/de/tl_survey_submission.php create mode 100644 contao/templates/frontend/_survey_assets.html.twig create mode 100644 contao/templates/frontend/_survey_branding.html.twig create mode 100644 contao/templates/frontend/member_survey_edit.html.twig create mode 100644 contao/templates/frontend/member_survey_list.html.twig create mode 100644 contao/templates/frontend/show_survey.html.twig create mode 100644 contao/templates/frontend/show_survey_results.html.twig create mode 100644 public/fonts/Blogger Sans-Medium.woff2 create mode 100644 public/fonts/PTSansNarrow-Bold.woff2 create mode 100644 public/fonts/PTSansNarrow-Regular.woff2 create mode 100644 public/images/Logo_Landesverband.svg create mode 100755 public/images/kigu.svg create mode 100644 src/Contao/Manager/Plugin.php create mode 100644 src/Controller/FrontendModule/MemberSurveyEditController.php create mode 100644 src/Controller/FrontendModule/MemberSurveyListController.php create mode 100644 src/Controller/FrontendModule/ShowSurveyController.php create mode 100644 src/Controller/FrontendModule/ShowSurveyResultsController.php create mode 100644 src/Controller/SurveyResultsExportController.php create mode 100644 src/DependencyInjection/SurveyExtension.php create mode 100644 src/EventListener/SurveyDcaListener.php create mode 100644 src/Form/Model/SurveyAnswerData.php create mode 100644 src/Form/Model/SurveyConditionData.php create mode 100644 src/Form/Model/SurveyEditorData.php create mode 100644 src/Form/Model/SurveyQuestionData.php create mode 100644 src/Form/SurveyConditionEditorType.php create mode 100644 src/Form/SurveyEditorType.php create mode 100644 src/Form/SurveyQuestionAnswerType.php create mode 100644 src/Form/SurveyQuestionEditorType.php create mode 100644 src/Model/SurveyAnswerModel.php create mode 100644 src/Model/SurveyCategoryModel.php create mode 100644 src/Model/SurveyConditionModel.php create mode 100644 src/Model/SurveyContentModel.php create mode 100644 src/Model/SurveyEditorModel.php create mode 100644 src/Model/SurveyModel.php create mode 100644 src/Model/SurveySubmissionModel.php create mode 100644 src/QuestionType/ChoiceQuestionType.php create mode 100644 src/QuestionType/QuestionTypeInterface.php create mode 100644 src/QuestionType/QuestionTypeRegistry.php create mode 100644 src/QuestionType/RangeQuestionType.php create mode 100644 src/QuestionType/TextQuestionType.php create mode 100644 src/QuestionType/YesNoMaybeQuestionType.php create mode 100644 src/Repository/SurveyAnswerRepository.php create mode 100644 src/Repository/SurveyConditionRepository.php create mode 100644 src/Repository/SurveyEditorRepository.php create mode 100644 src/Repository/SurveyQuestionRepository.php create mode 100644 src/Repository/SurveyRepository.php create mode 100644 src/Repository/SurveySubmissionRepository.php create mode 100644 src/Resources/config/routes.yaml create mode 100644 src/Resources/views/pdf/survey_results.html.twig create mode 100644 src/Security/SurveyEditorVoter.php create mode 100644 src/Service/SurveyCategoryAssignmentService.php create mode 100644 src/Service/SurveyEditorService.php create mode 100644 src/Service/SurveyEngine.php create mode 100644 src/Service/SurveyFlowService.php create mode 100644 src/Service/SurveyPermissionService.php create mode 100644 src/Service/SurveyResultsExportService.php create mode 100644 src/Service/SurveyResultsPdfService.php create mode 100644 src/Service/SurveyResultsViewService.php create mode 100644 src/Service/SurveySubmissionService.php create mode 100644 src/SurveyBundle.php diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..496ee2c --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.DS_Store \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..699c356 --- /dev/null +++ b/composer.json @@ -0,0 +1,33 @@ +{ + "name": "mummert/survey-bundle", + "description": "Modernes Survey-Bundle fuer Contao 5.7 mit Symfony-Frontend.", + "type": "contao-bundle", + "license": "proprietary", + "require": { + "php": "^8.3", + "contao/core-bundle": "^5.7", + "contao/manager-plugin": "^2.0", + "phpoffice/phpspreadsheet": "^5.7", + "symfony/form": "^7.3", + "symfony/http-client": "^7.3", + "symfony/mime": "^7.3", + "symfony/security-bundle": "^7.3", + "symfony/uid": "^7.3", + "twig/twig": "^3.0" + }, + "autoload": { + "psr-4": { + "Mummert\\SurveyBundle\\": "src/" + } + }, + "extra": { + "contao-manager-plugin": "Mummert\\SurveyBundle\\Contao\\Manager\\Plugin" + }, + "prefer-stable": true, + "config": { + "allow-plugins": { + "contao-components/installer": true, + "contao/manager-plugin": true + } + } +} \ No newline at end of file diff --git a/config/services.yaml b/config/services.yaml new file mode 100644 index 0000000..7086991 --- /dev/null +++ b/config/services.yaml @@ -0,0 +1,22 @@ +services: + _defaults: + autowire: true + autoconfigure: true + + _instanceof: + Mummert\SurveyBundle\QuestionType\QuestionTypeInterface: + tags: ['survey.question_type'] + + Mummert\SurveyBundle\: + resource: ../src/ + exclude: + - ../src/Contao/Manager/ + - ../src/DependencyInjection/ + - ../src/SurveyBundle.php + + Mummert\SurveyBundle\QuestionType\QuestionTypeRegistry: + arguments: + $questionTypes: !tagged_iterator survey.question_type + + Mummert\SurveyBundle\EventListener\SurveyDcaListener: + public: true \ No newline at end of file diff --git a/contao/config/config.php b/contao/config/config.php new file mode 100644 index 0000000..71e7883 --- /dev/null +++ b/contao/config/config.php @@ -0,0 +1,21 @@ + ['tl_survey', 'tl_survey_content', 'tl_survey_condition', 'tl_survey_editor', 'tl_survey_submission', 'tl_survey_answer'], +]; + +$GLOBALS['BE_MOD']['content']['survey_bundle_categories'] = [ + 'tables' => ['tl_survey_category'], +]; \ No newline at end of file diff --git a/contao/dca/tl_member.php b/contao/dca/tl_member.php new file mode 100644 index 0000000..e99f50f --- /dev/null +++ b/contao/dca/tl_member.php @@ -0,0 +1,55 @@ +addLegend('survey_legend', 'contact_legend', PaletteManipulator::POSITION_AFTER) + ->addField('surveyCategories', 'survey_legend', PaletteManipulator::POSITION_APPEND) + ->addField('assignedSurveys', 'survey_legend', PaletteManipulator::POSITION_APPEND) + ->applyToPalette((string) $paletteName, 'tl_member'); + } +} + +$GLOBALS['TL_DCA']['tl_member']['config']['onsubmit_callback'][] = [SurveyDcaListener::class, 'refreshMemberSurveyListMetadata']; + +$GLOBALS['TL_DCA']['tl_member']['fields']['surveyCategories'] = [ + 'label' => &$GLOBALS['TL_LANG']['tl_member']['surveyCategories'], + 'exclude' => true, + 'inputType' => 'select', + 'foreignKey' => 'tl_survey_category.title', + 'eval' => ['multiple' => true, 'chosen' => true, 'tl_class' => 'clr'], + 'relation' => [ + 'type' => 'hasMany', + 'load' => 'lazy', + 'table' => 'tl_survey_category', + 'field' => 'id', + ], + 'save_callback' => [ + [SurveyDcaListener::class, 'saveMemberSurveyCategories'], + ], + 'sql' => 'blob NULL', +]; + +$GLOBALS['TL_DCA']['tl_member']['fields']['assignedSurveys'] = [ + 'label' => &$GLOBALS['TL_LANG']['tl_member']['assignedSurveys'], + 'exclude' => true, + 'inputType' => 'select', + 'options_callback' => [SurveyDcaListener::class, 'getSurveyOptions'], + 'eval' => ['multiple' => true, 'chosen' => true, 'tl_class' => 'clr'], + 'load_callback' => [ + [SurveyDcaListener::class, 'loadMemberAssignedSurveys'], + ], + 'save_callback' => [ + [SurveyDcaListener::class, 'saveMemberAssignedSurveys'], + ], + 'sql' => 'blob NULL', +]; \ No newline at end of file diff --git a/contao/dca/tl_module.php b/contao/dca/tl_module.php new file mode 100644 index 0000000..07d82c5 --- /dev/null +++ b/contao/dca/tl_module.php @@ -0,0 +1,32 @@ + &$GLOBALS['TL_LANG']['tl_module']['surveyEditPage'], + 'exclude' => true, + 'inputType' => 'pageTree', + 'eval' => ['fieldType' => 'radio', 'mandatory' => true, 'tl_class' => 'w50'], + 'sql' => ['type' => 'integer', 'unsigned' => true, 'default' => 0], +]; + +$GLOBALS['TL_DCA']['tl_module']['fields']['surveyListPage'] = [ + 'label' => &$GLOBALS['TL_LANG']['tl_module']['surveyListPage'], + 'exclude' => true, + 'inputType' => 'pageTree', + 'eval' => ['fieldType' => 'radio', 'mandatory' => false, 'tl_class' => 'w50'], + 'sql' => ['type' => 'integer', 'unsigned' => true, 'default' => 0], +]; + +$GLOBALS['TL_DCA']['tl_module']['fields']['surveyReaderPage'] = [ + 'label' => &$GLOBALS['TL_LANG']['tl_module']['surveyReaderPage'], + 'exclude' => true, + 'inputType' => 'pageTree', + 'eval' => ['fieldType' => 'radio', 'mandatory' => false, 'tl_class' => 'w50'], + 'sql' => ['type' => 'integer', 'unsigned' => true, 'default' => 0], +]; \ No newline at end of file diff --git a/contao/dca/tl_settings.php b/contao/dca/tl_settings.php new file mode 100644 index 0000000..1cbc921 --- /dev/null +++ b/contao/dca/tl_settings.php @@ -0,0 +1,30 @@ +addLegend('survey_settings_legend', null, PaletteManipulator::POSITION_AFTER, true) + ->addField('surveyReaderPage', 'survey_settings_legend') + ->addField('surveyResultsPage', 'survey_settings_legend') + ->addField('surveyGotenbergUrl', 'survey_settings_legend') + ->applyToPalette('default', 'tl_settings'); + +$GLOBALS['TL_DCA']['tl_settings']['fields']['surveyReaderPage'] = [ + 'label' => &$GLOBALS['TL_LANG']['tl_settings']['surveyReaderPage'], + 'inputType' => 'pageTree', + 'eval' => ['fieldType' => 'radio', 'tl_class' => 'w50'], +]; + +$GLOBALS['TL_DCA']['tl_settings']['fields']['surveyResultsPage'] = [ + 'label' => &$GLOBALS['TL_LANG']['tl_settings']['surveyResultsPage'], + 'inputType' => 'pageTree', + 'eval' => ['fieldType' => 'radio', 'tl_class' => 'w50'], +]; + +$GLOBALS['TL_DCA']['tl_settings']['fields']['surveyGotenbergUrl'] = [ + 'label' => &$GLOBALS['TL_LANG']['tl_settings']['surveyGotenbergUrl'], + 'inputType' => 'text', + 'eval' => ['rgxp' => 'url', 'decodeEntities' => true, 'maxlength' => 255, 'tl_class' => 'w50 clr'], +]; \ No newline at end of file diff --git a/contao/dca/tl_survey.php b/contao/dca/tl_survey.php new file mode 100644 index 0000000..0a975c6 --- /dev/null +++ b/contao/dca/tl_survey.php @@ -0,0 +1,212 @@ + [ + 'dataContainer' => DC_Table::class, + 'ctable' => ['tl_survey_content', 'tl_survey_condition', 'tl_survey_editor', 'tl_survey_submission'], + 'enableVersioning' => true, + 'onload_callback' => [ + [SurveyDcaListener::class, 'refreshSurveyBackendStateIndex'], + ], + 'onsubmit_callback' => [ + [SurveyDcaListener::class, 'persistSurveyBackendState'], + ], + 'sql' => [ + 'keys' => [ + 'id' => 'primary', + 'alias' => 'unique', + 'published' => 'index', + ], + ], + ], + 'list' => [ + 'sorting' => [ + 'mode' => 1, + 'fields' => ['title'], + 'flag' => 1, + 'panelLayout' => 'filter;sort,search,limit', + ], + 'label' => [ + 'fields' => ['title', 'categorySummary', 'assignedMembersSummary'], + 'showColumns' => true, + ], + 'global_operations' => [ + 'all' => [ + 'href' => 'act=select', + 'class' => 'header_edit_all', + 'attributes' => 'onclick="Backend.getScrollOffset()" accesskey="e"', + ], + ], + 'operations' => [ + 'edit' => [ + 'href' => 'table=tl_survey_content', + 'icon' => 'children.svg', + ], + 'editheader' => [ + 'href' => 'act=edit', + 'icon' => 'header.svg', + ], + 'delete' => [ + 'href' => 'act=delete', + 'icon' => 'delete.svg', + 'attributes' => 'onclick="if(!confirm(\'Eintrag wirklich loeschen?\'))return false;Backend.getScrollOffset()"', + ], + 'show' => [ + 'href' => 'act=show', + 'icon' => 'show.svg', + ], + 'copyPublicLink' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey']['copyPublicLink'], + 'icon' => 'copy.svg', + 'button_callback' => [SurveyDcaListener::class, 'generateCopyPublicLinkButton'], + ], + 'showResults' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey']['showResults'], + 'icon' => 'show.svg', + 'button_callback' => [SurveyDcaListener::class, 'generateShowResultsButton'], + ], + ], + ], + 'palettes' => [ + 'default' => '{title_legend},title,alias,category,description;{assignment_legend},assignedMembers;{publishing_legend},published,isLocked;{meta_legend},createdAt,updatedAt', + ], + 'fields' => [ + 'id' => [ + 'sql' => 'int(10) unsigned NOT NULL auto_increment', + ], + 'tstamp' => [ + 'sql' => 'int(10) unsigned NOT NULL default 0', + ], + 'title' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey']['title'], + 'inputType' => 'text', + 'search' => true, + 'eval' => ['mandatory' => true, 'maxlength' => 255, 'tl_class' => 'w50'], + 'sql' => "varchar(255) NOT NULL default ''", + ], + 'alias' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey']['alias'], + 'inputType' => 'text', + 'eval' => ['maxlength' => 20, 'readonly' => true, 'alwaysSave' => true, 'tl_class' => 'w50'], + 'save_callback' => [[SurveyDcaListener::class, 'generateSurveyAlias']], + 'sql' => "varchar(20) NOT NULL default ''", + ], + 'description' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey']['description'], + 'inputType' => 'textarea', + 'eval' => ['rte' => 'tinyMCE', 'tl_class' => 'clr'], + 'sql' => 'text NULL', + ], + 'category' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey']['category'], + 'inputType' => 'select', + 'foreignKey' => 'tl_survey_category.title', + 'eval' => ['multiple' => true, 'chosen' => true, 'tl_class' => 'clr'], + 'relation' => ['type' => 'hasMany', 'load' => 'lazy', 'table' => 'tl_survey_category', 'field' => 'id'], + 'sql' => 'blob NULL', + ], + 'categoryFilter' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey']['categoryFilter'], + 'filter' => true, + 'inputType' => 'select', + 'options_callback' => [SurveyDcaListener::class, 'getCategoryOptions'], + 'eval' => ['includeBlankOption' => true, 'chosen' => true, 'findInSet' => true], + 'sql' => "varchar(255) NOT NULL default ''", + ], + 'categorySummary' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey']['categorySummary'], + 'sql' => 'text NULL', + ], + 'published' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey']['published'], + 'inputType' => 'checkbox', + 'eval' => ['tl_class' => 'w50 m12'], + 'sql' => "char(1) NOT NULL default ''", + ], + 'isLocked' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey']['isLocked'], + 'inputType' => 'checkbox', + 'eval' => ['tl_class' => 'w50 m12'], + 'sql' => "char(1) NOT NULL default ''", + ], + 'assignedMembers' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey']['assignedMembers'], + 'inputType' => 'select', + 'options_callback' => [Mummert\SurveyBundle\EventListener\SurveyDcaListener::class, 'getMemberOptions'], + 'eval' => ['multiple' => true, 'chosen' => true, 'tl_class' => 'clr'], + 'load_callback' => [[Mummert\SurveyBundle\EventListener\SurveyDcaListener::class, 'loadSurveyAssignedMembers']], + 'save_callback' => [[Mummert\SurveyBundle\EventListener\SurveyDcaListener::class, 'saveSurveyAssignedMembers']], + 'sql' => 'blob NULL', + ], + 'assignedMembersFilter' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey']['assignedMembersFilter'], + 'filter' => true, + 'inputType' => 'select', + 'options_callback' => [SurveyDcaListener::class, 'getMemberOptions'], + 'eval' => ['includeBlankOption' => true, 'chosen' => true, 'findInSet' => true], + 'sql' => 'text NULL', + ], + 'assignedMembersSummary' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey']['assignedMembersSummary'], + 'sql' => 'text NULL', + ], + 'createdBy' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey']['createdBy'], + 'inputType' => 'text', + 'eval' => ['readonly' => true, 'tl_class' => 'w50'], + 'sql' => 'int(10) unsigned NOT NULL default 0', + ], + 'updatedBy' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey']['updatedBy'], + 'inputType' => 'text', + 'eval' => ['readonly' => true, 'tl_class' => 'w50'], + 'sql' => 'int(10) unsigned NOT NULL default 0', + ], + 'createdAt' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey']['createdAt'], + 'inputType' => 'text', + 'eval' => ['rgxp' => 'datim', 'readonly' => true, 'tl_class' => 'w50'], + 'sql' => 'int(10) unsigned NOT NULL default 0', + ], + 'updatedAt' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey']['updatedAt'], + 'inputType' => 'text', + 'eval' => ['rgxp' => 'datim', 'readonly' => true, 'tl_class' => 'w50'], + 'sql' => 'int(10) unsigned NOT NULL default 0', + ], + ], +]; + +if ('cli' !== PHP_SAPI) { + $hasListMetadataColumns = false; + + try { + $columnNames = array_map( + static fn (string $columnName): string => strtolower($columnName), + System::getContainer()->get('database_connection')->fetchFirstColumn('SHOW COLUMNS FROM tl_survey'), + ); + $hasListMetadataColumns = !array_diff( + ['categoryfilter', 'categorysummary', 'assignedmembersfilter', 'assignedmemberssummary'], + $columnNames, + ); + } catch (\Throwable) { + $hasListMetadataColumns = false; + } + + if (!$hasListMetadataColumns) { + $GLOBALS['TL_DCA']['tl_survey']['list']['label']['fields'] = ['title', 'alias']; + + unset( + $GLOBALS['TL_DCA']['tl_survey']['fields']['categoryFilter'], + $GLOBALS['TL_DCA']['tl_survey']['fields']['categorySummary'], + $GLOBALS['TL_DCA']['tl_survey']['fields']['assignedMembersFilter'], + $GLOBALS['TL_DCA']['tl_survey']['fields']['assignedMembersSummary'], + ); + } +} \ No newline at end of file diff --git a/contao/dca/tl_survey_answer.php b/contao/dca/tl_survey_answer.php new file mode 100644 index 0000000..01bd1b9 --- /dev/null +++ b/contao/dca/tl_survey_answer.php @@ -0,0 +1,60 @@ + [ + 'dataContainer' => DC_Table::class, + 'ptable' => 'tl_survey_submission', + 'closed' => true, + 'notCreatable' => true, + 'notEditable' => true, + 'notCopyable' => true, + 'sql' => [ + 'keys' => [ + 'id' => 'primary', + 'pid' => 'index', + 'submission' => 'index', + 'question' => 'index', + ], + ], + ], + 'list' => [ + 'sorting' => [ + 'mode' => 4, + 'fields' => ['id'], + 'headerFields' => ['token', 'startedAt', 'completedAt'], + 'panelLayout' => 'sort,search,limit', + ], + 'label' => [ + 'fields' => ['question', 'questionType', 'value'], + 'showColumns' => true, + ], + 'operations' => [ + 'show' => [ + 'href' => 'act=show', + 'icon' => 'show.svg', + ], + ], + ], + 'fields' => [ + 'id' => ['sql' => 'int(10) unsigned NOT NULL auto_increment'], + 'tstamp' => ['sql' => 'int(10) unsigned NOT NULL default 0'], + 'pid' => ['sql' => 'int(10) unsigned NOT NULL default 0'], + 'submission' => ['sql' => 'int(10) unsigned NOT NULL default 0'], + 'question' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey_answer']['question'], + 'sql' => 'int(10) unsigned NOT NULL default 0', + ], + 'questionType' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey_answer']['questionType'], + 'sql' => "varchar(32) NOT NULL default ''", + ], + 'value' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey_answer']['value'], + 'sql' => 'text NULL', + ], + ], +]; \ No newline at end of file diff --git a/contao/dca/tl_survey_category.php b/contao/dca/tl_survey_category.php new file mode 100644 index 0000000..0445ab3 --- /dev/null +++ b/contao/dca/tl_survey_category.php @@ -0,0 +1,70 @@ + [ + 'dataContainer' => DC_Table::class, + 'enableVersioning' => true, + 'sql' => [ + 'keys' => [ + 'id' => 'primary', + 'alias' => 'index', + 'sorting' => 'index', + ], + ], + ], + 'list' => [ + 'sorting' => [ + 'mode' => 1, + 'fields' => ['sorting'], + 'panelLayout' => 'sort,search,limit', + ], + 'label' => [ + 'fields' => ['title', 'alias'], + 'showColumns' => true, + ], + 'operations' => [ + 'edit' => [ + 'href' => 'act=edit', + 'icon' => 'edit.svg', + ], + 'delete' => [ + 'href' => 'act=delete', + 'icon' => 'delete.svg', + 'attributes' => 'onclick="if(!confirm(\'Eintrag wirklich loeschen?\'))return false;Backend.getScrollOffset()"', + ], + 'show' => [ + 'href' => 'act=show', + 'icon' => 'show.svg', + ], + ], + ], + 'palettes' => [ + 'default' => '{title_legend},title,alias,sorting', + ], + 'fields' => [ + 'id' => ['sql' => 'int(10) unsigned NOT NULL auto_increment'], + 'tstamp' => ['sql' => 'int(10) unsigned NOT NULL default 0'], + 'title' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey_category']['title'], + 'inputType' => 'text', + 'eval' => ['mandatory' => true, 'maxlength' => 255, 'tl_class' => 'w50'], + 'sql' => "varchar(255) NOT NULL default ''", + ], + 'alias' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey_category']['alias'], + 'inputType' => 'text', + 'eval' => ['maxlength' => 128, 'tl_class' => 'w50'], + 'sql' => "varchar(128) NOT NULL default ''", + ], + 'sorting' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey_category']['sorting'], + 'inputType' => 'text', + 'eval' => ['rgxp' => 'natural', 'tl_class' => 'w50'], + 'sql' => 'int(10) unsigned NOT NULL default 0', + ], + ], +]; \ No newline at end of file diff --git a/contao/dca/tl_survey_condition.php b/contao/dca/tl_survey_condition.php new file mode 100644 index 0000000..cfc7fd0 --- /dev/null +++ b/contao/dca/tl_survey_condition.php @@ -0,0 +1,93 @@ + [ + 'dataContainer' => DC_Table::class, + 'ptable' => 'tl_survey', + 'enableVersioning' => true, + 'onsubmit_callback' => [ + [SurveyDcaListener::class, 'touchSurveyConditionParent'], + ], + 'ondelete_callback' => [ + [SurveyDcaListener::class, 'guardConditionDelete'], + [SurveyDcaListener::class, 'touchSurveyConditionParent'], + ], + 'sql' => [ + 'keys' => [ + 'id' => 'primary', + 'pid' => 'index', + 'sourceQuestion' => 'index', + 'targetQuestion' => 'index', + ], + ], + ], + 'list' => [ + 'sorting' => [ + 'mode' => 4, + 'fields' => ['id'], + 'headerFields' => ['title', 'alias', 'published', 'isLocked'], + 'panelLayout' => 'sort,search,limit', + ], + 'label' => [ + 'fields' => ['sourceQuestion', 'answerValue', 'targetQuestion'], + 'showColumns' => true, + ], + 'operations' => [ + 'edit' => [ + 'href' => 'act=edit', + 'icon' => 'edit.svg', + ], + 'copy' => [ + 'href' => 'act=copy', + 'icon' => 'copy.svg', + ], + 'delete' => [ + 'href' => 'act=delete', + 'icon' => 'delete.svg', + 'attributes' => 'onclick="if(!confirm(\'Eintrag wirklich loeschen?\'))return false;Backend.getScrollOffset()"', + ], + 'show' => [ + 'href' => 'act=show', + 'icon' => 'show.svg', + ], + ], + ], + 'palettes' => [ + 'default' => '{logic_legend},sourceQuestion,answerValue,targetQuestion', + ], + 'fields' => [ + 'id' => ['sql' => 'int(10) unsigned NOT NULL auto_increment'], + 'tstamp' => ['sql' => 'int(10) unsigned NOT NULL default 0'], + 'pid' => ['sql' => 'int(10) unsigned NOT NULL default 0'], + 'sourceQuestion' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey_condition']['sourceQuestion'], + 'inputType' => 'select', + 'options_callback' => [SurveyDcaListener::class, 'getQuestionOptions'], + 'eval' => ['mandatory' => true, 'includeBlankOption' => true, 'chosen' => true, 'tl_class' => 'w50'], + 'save_callback' => [$guardCallback], + 'sql' => 'int(10) unsigned NOT NULL default 0', + ], + 'answerValue' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey_condition']['answerValue'], + 'inputType' => 'text', + 'eval' => ['mandatory' => true, 'maxlength' => 255, 'tl_class' => 'w50'], + 'save_callback' => [$guardCallback], + 'sql' => "varchar(255) NOT NULL default ''", + ], + 'targetQuestion' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey_condition']['targetQuestion'], + 'inputType' => 'select', + 'options_callback' => [SurveyDcaListener::class, 'getQuestionOptions'], + 'eval' => ['mandatory' => true, 'includeBlankOption' => true, 'chosen' => true, 'tl_class' => 'clr'], + 'save_callback' => [$guardCallback], + 'sql' => 'int(10) unsigned NOT NULL default 0', + ], + ], +]; \ No newline at end of file diff --git a/contao/dca/tl_survey_content.php b/contao/dca/tl_survey_content.php new file mode 100644 index 0000000..7f07827 --- /dev/null +++ b/contao/dca/tl_survey_content.php @@ -0,0 +1,241 @@ + [ + 'dataContainer' => DC_Table::class, + 'ptable' => 'tl_survey', + 'enableVersioning' => true, + 'onsubmit_callback' => [ + [SurveyDcaListener::class, 'touchSurveyContentParent'], + ], + 'onpalette_callback' => [ + [SurveyDcaListener::class, 'resolveSurveyContentPalette'], + ], + 'ondelete_callback' => [ + [SurveyDcaListener::class, 'guardContentDelete'], + [SurveyDcaListener::class, 'touchSurveyContentParent'], + ], + 'sql' => [ + 'keys' => [ + 'id' => 'primary', + 'pid' => 'index', + 'sorting' => 'index', + 'published' => 'index', + ], + ], + ], + 'list' => [ + 'sorting' => [ + 'mode' => 4, + 'fields' => ['sorting'], + 'headerFields' => ['title', 'alias', 'published', 'isLocked'], + 'child_record_class' => 'survey-question-record', + 'panelLayout' => 'sort,search,limit', + ], + 'label' => [ + 'fields' => ['question', 'type'], + 'showColumns' => true, + ], + 'operations' => [ + 'edit' => [ + 'href' => 'act=edit', + 'icon' => 'edit.svg', + ], + 'copy' => [ + 'href' => 'act=copy', + 'icon' => 'copy.svg', + ], + 'delete' => [ + 'href' => 'act=delete', + 'icon' => 'delete.svg', + 'attributes' => 'onclick="if(!confirm(\'Eintrag wirklich loeschen?\'))return false;Backend.getScrollOffset()"', + ], + 'show' => [ + 'href' => 'act=show', + 'icon' => 'show.svg', + ], + ], + ], + 'palettes' => [ + 'default' => '{question_legend},type,question,description;{settings_legend},mandatory,published', + 'yes_no_maybe' => '{question_legend},type,question,description;{settings_legend},mandatory,published,allowMaybe,jumpOnYes,jumpOnNo', + 'text' => '{question_legend},type,question,description;{settings_legend},mandatory,published', + 'range' => '{question_legend},type,question,description;{settings_legend},mandatory,published,rangeMin,rangeMax,rangeStep', + 'choice' => '{question_legend},type,question,description;{settings_legend},mandatory,published,allowMultiple,answerOption1,answerOption2,answerOption3,answerOption4,answerOption5,answerOption6,answerOption7,answerOption8,answerOption9,answerOption10', + ], + 'fields' => [ + 'id' => ['sql' => 'int(10) unsigned NOT NULL auto_increment'], + 'tstamp' => ['sql' => 'int(10) unsigned NOT NULL default 0'], + 'pid' => ['sql' => 'int(10) unsigned NOT NULL default 0'], + 'sorting' => [ + 'sql' => 'int(10) unsigned NOT NULL default 0', + ], + 'type' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey_content']['type'], + 'inputType' => 'select', + 'options' => ['yes_no_maybe', 'text', 'range', 'choice'], + 'reference' => &$GLOBALS['TL_LANG']['tl_survey_content']['types'], + 'eval' => ['mandatory' => true, 'includeBlankOption' => true, 'submitOnChange' => true, 'chosen' => true, 'tl_class' => 'w50'], + 'save_callback' => [$guardCallback], + 'sql' => "varchar(32) NOT NULL default ''", + ], + 'question' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey_content']['question'], + 'inputType' => 'text', + 'eval' => ['mandatory' => true, 'maxlength' => 255, 'tl_class' => 'clr'], + 'save_callback' => [$guardCallback], + 'sql' => "varchar(255) NOT NULL default ''", + ], + 'description' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey_content']['description'], + 'inputType' => 'textarea', + 'eval' => ['tl_class' => 'clr'], + 'save_callback' => [$guardCallback], + 'sql' => 'text NULL', + ], + 'mandatory' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey_content']['mandatory'], + 'inputType' => 'checkbox', + 'default' => '1', + 'eval' => ['tl_class' => 'w50 m12'], + 'save_callback' => [$guardCallback], + 'sql' => "char(1) NOT NULL default ''", + ], + 'published' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey_content']['published'], + 'inputType' => 'checkbox', + 'default' => '1', + 'eval' => ['tl_class' => 'w50 m12'], + 'save_callback' => [$guardCallback], + 'sql' => "char(1) NOT NULL default ''", + ], + 'allowMaybe' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey_content']['allowMaybe'], + 'inputType' => 'checkbox', + 'eval' => ['tl_class' => 'w50 m12 clr'], + 'save_callback' => [$guardCallback], + 'sql' => "char(1) NOT NULL default ''", + ], + 'jumpOnYes' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey_content']['jumpOnYes'], + 'inputType' => 'select', + 'options_callback' => [SurveyDcaListener::class, 'getQuestionOptionsForContent'], + 'eval' => ['includeBlankOption' => true, 'chosen' => true, 'tl_class' => 'w50 clr'], + 'save_callback' => [$guardCallback], + 'sql' => 'int(10) unsigned NOT NULL default 0', + ], + 'jumpOnNo' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey_content']['jumpOnNo'], + 'inputType' => 'select', + 'options_callback' => [SurveyDcaListener::class, 'getQuestionOptionsForContent'], + 'eval' => ['includeBlankOption' => true, 'chosen' => true, 'tl_class' => 'w50'], + 'save_callback' => [$guardCallback], + 'sql' => 'int(10) unsigned NOT NULL default 0', + ], + 'allowMultiple' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey_content']['allowMultiple'], + 'inputType' => 'checkbox', + 'eval' => ['tl_class' => 'w50 m12 clr'], + 'save_callback' => [$guardCallback], + 'sql' => "char(1) NOT NULL default ''", + ], + 'answerOption1' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey_content']['answerOption1'], + 'inputType' => 'text', + 'eval' => ['maxlength' => 255, 'tl_class' => 'w50 clr'], + 'save_callback' => [$guardCallback], + 'sql' => "varchar(255) NOT NULL default ''", + ], + 'answerOption2' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey_content']['answerOption2'], + 'inputType' => 'text', + 'eval' => ['maxlength' => 255, 'tl_class' => 'w50'], + 'save_callback' => [$guardCallback], + 'sql' => "varchar(255) NOT NULL default ''", + ], + 'answerOption3' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey_content']['answerOption3'], + 'inputType' => 'text', + 'eval' => ['maxlength' => 255, 'tl_class' => 'w50 clr'], + 'save_callback' => [$guardCallback], + 'sql' => "varchar(255) NOT NULL default ''", + ], + 'answerOption4' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey_content']['answerOption4'], + 'inputType' => 'text', + 'eval' => ['maxlength' => 255, 'tl_class' => 'w50'], + 'save_callback' => [$guardCallback], + 'sql' => "varchar(255) NOT NULL default ''", + ], + 'answerOption5' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey_content']['answerOption5'], + 'inputType' => 'text', + 'eval' => ['maxlength' => 255, 'tl_class' => 'w50 clr'], + 'save_callback' => [$guardCallback], + 'sql' => "varchar(255) NOT NULL default ''", + ], + 'answerOption6' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey_content']['answerOption6'], + 'inputType' => 'text', + 'eval' => ['maxlength' => 255, 'tl_class' => 'w50'], + 'save_callback' => [$guardCallback], + 'sql' => "varchar(255) NOT NULL default ''", + ], + 'answerOption7' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey_content']['answerOption7'], + 'inputType' => 'text', + 'eval' => ['maxlength' => 255, 'tl_class' => 'w50 clr'], + 'save_callback' => [$guardCallback], + 'sql' => "varchar(255) NOT NULL default ''", + ], + 'answerOption8' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey_content']['answerOption8'], + 'inputType' => 'text', + 'eval' => ['maxlength' => 255, 'tl_class' => 'w50'], + 'save_callback' => [$guardCallback], + 'sql' => "varchar(255) NOT NULL default ''", + ], + 'answerOption9' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey_content']['answerOption9'], + 'inputType' => 'text', + 'eval' => ['maxlength' => 255, 'tl_class' => 'w50 clr'], + 'save_callback' => [$guardCallback], + 'sql' => "varchar(255) NOT NULL default ''", + ], + 'answerOption10' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey_content']['answerOption10'], + 'inputType' => 'text', + 'eval' => ['maxlength' => 255, 'tl_class' => 'w50'], + 'save_callback' => [$guardCallback], + 'sql' => "varchar(255) NOT NULL default ''", + ], + 'rangeMin' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey_content']['rangeMin'], + 'inputType' => 'text', + 'eval' => ['rgxp' => 'digit', 'tl_class' => 'w50'], + 'save_callback' => [$guardCallback], + 'sql' => 'int(10) NOT NULL default 0', + ], + 'rangeMax' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey_content']['rangeMax'], + 'inputType' => 'text', + 'eval' => ['rgxp' => 'digit', 'tl_class' => 'w50'], + 'save_callback' => [$guardCallback], + 'sql' => 'int(10) NOT NULL default 10', + ], + 'rangeStep' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey_content']['rangeStep'], + 'inputType' => 'text', + 'eval' => ['rgxp' => 'digit', 'tl_class' => 'w50'], + 'save_callback' => [$guardCallback], + 'sql' => 'int(10) unsigned NOT NULL default 1', + ], + ], +]; \ No newline at end of file diff --git a/contao/dca/tl_survey_editor.php b/contao/dca/tl_survey_editor.php new file mode 100644 index 0000000..65d4847 --- /dev/null +++ b/contao/dca/tl_survey_editor.php @@ -0,0 +1,75 @@ + [ + 'dataContainer' => DC_Table::class, + 'ptable' => 'tl_survey', + 'enableVersioning' => true, + 'ondelete_callback' => [ + [SurveyDcaListener::class, 'guardEditorDelete'], + ], + 'sql' => [ + 'keys' => [ + 'id' => 'primary', + 'pid' => 'index', + 'survey' => 'index', + 'member' => 'index', + ], + ], + ], + 'list' => [ + 'sorting' => [ + 'mode' => 4, + 'fields' => ['member'], + 'headerFields' => ['title', 'alias', 'isLocked'], + 'panelLayout' => 'sort,search,limit', + ], + 'label' => [ + 'fields' => ['member'], + 'showColumns' => true, + ], + 'operations' => [ + 'edit' => [ + 'href' => 'act=edit', + 'icon' => 'edit.svg', + ], + 'copy' => [ + 'href' => 'act=copy', + 'icon' => 'copy.svg', + ], + 'delete' => [ + 'href' => 'act=delete', + 'icon' => 'delete.svg', + 'attributes' => 'onclick="if(!confirm(\'Eintrag wirklich loeschen?\'))return false;Backend.getScrollOffset()"', + ], + 'show' => [ + 'href' => 'act=show', + 'icon' => 'show.svg', + ], + ], + ], + 'palettes' => [ + 'default' => '{editor_legend},member', + ], + 'fields' => [ + 'id' => ['sql' => 'int(10) unsigned NOT NULL auto_increment'], + 'tstamp' => ['sql' => 'int(10) unsigned NOT NULL default 0'], + 'pid' => ['sql' => 'int(10) unsigned NOT NULL default 0'], + 'survey' => ['sql' => 'int(10) unsigned NOT NULL default 0'], + 'member' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey_editor']['member'], + 'inputType' => 'select', + 'options_callback' => [SurveyDcaListener::class, 'getMemberOptions'], + 'eval' => ['mandatory' => true, 'includeBlankOption' => true, 'chosen' => true], + 'save_callback' => [$guardCallback], + 'sql' => 'int(10) unsigned NOT NULL default 0', + ], + ], +]; \ No newline at end of file diff --git a/contao/dca/tl_survey_submission.php b/contao/dca/tl_survey_submission.php new file mode 100644 index 0000000..28c857b --- /dev/null +++ b/contao/dca/tl_survey_submission.php @@ -0,0 +1,74 @@ + [ + 'dataContainer' => DC_Table::class, + 'ptable' => 'tl_survey', + 'ctable' => ['tl_survey_answer'], + 'closed' => true, + 'notCreatable' => true, + 'notEditable' => true, + 'notCopyable' => true, + 'sql' => [ + 'keys' => [ + 'id' => 'primary', + 'pid' => 'index', + 'survey' => 'index', + 'token' => 'index', + 'isFinished' => 'index', + ], + ], + ], + 'list' => [ + 'sorting' => [ + 'mode' => 4, + 'fields' => ['startedAt'], + 'headerFields' => ['title', 'alias'], + 'panelLayout' => 'sort,search,limit', + ], + 'label' => [ + 'fields' => ['token', 'startedAt', 'completedAt', 'isFinished'], + 'showColumns' => true, + ], + 'operations' => [ + 'edit' => [ + 'href' => 'table=tl_survey_answer', + 'icon' => 'children.svg', + ], + 'show' => [ + 'href' => 'act=show', + 'icon' => 'show.svg', + ], + ], + ], + 'fields' => [ + 'id' => ['sql' => 'int(10) unsigned NOT NULL auto_increment'], + 'tstamp' => ['sql' => 'int(10) unsigned NOT NULL default 0'], + 'pid' => ['sql' => 'int(10) unsigned NOT NULL default 0'], + 'survey' => ['sql' => 'int(10) unsigned NOT NULL default 0'], + 'token' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey_submission']['token'], + 'sql' => "varchar(26) NOT NULL default ''", + ], + 'startedAt' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey_submission']['startedAt'], + 'sql' => 'int(10) unsigned NOT NULL default 0', + ], + 'completedAt' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey_submission']['completedAt'], + 'sql' => 'int(10) unsigned NOT NULL default 0', + ], + 'currentQuestion' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey_submission']['currentQuestion'], + 'sql' => 'int(10) unsigned NOT NULL default 0', + ], + 'isFinished' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_survey_submission']['isFinished'], + 'sql' => "char(1) NOT NULL default ''", + ], + ], +]; \ No newline at end of file diff --git a/contao/languages/de/modules.php b/contao/languages/de/modules.php new file mode 100644 index 0000000..5a4f9ca --- /dev/null +++ b/contao/languages/de/modules.php @@ -0,0 +1,10 @@ + 'Ja-Nein-Frage', + 'text' => 'Offene Frage', + 'range' => 'Bewertungsfrage', + 'choice' => 'Single/Multiple-Choice', +]; +$GLOBALS['TL_LANG']['tl_survey_content']['question'] = ['Frage', 'Titel bzw. Wortlaut der Frage.']; +$GLOBALS['TL_LANG']['tl_survey_content']['description'] = ['Beschreibung', 'Optionale Zusatzbeschreibung zur Frage.']; +$GLOBALS['TL_LANG']['tl_survey_content']['question_legend'] = 'Frage'; +$GLOBALS['TL_LANG']['tl_survey_content']['settings_legend'] = 'Einstellungen'; +$GLOBALS['TL_LANG']['tl_survey_content']['mandatory'] = ['Pflichtfrage', 'Diese Frage muss beantwortet werden.']; +$GLOBALS['TL_LANG']['tl_survey_content']['published'] = ['Aktiv', 'Die Frage wird in der Umfrage angezeigt.']; +$GLOBALS['TL_LANG']['tl_survey_content']['allowMaybe'] = ['Vielleicht anbieten', 'Ergaenzt die Ja-Nein-Frage um die Antwortmoeglichkeit Vielleicht.']; +$GLOBALS['TL_LANG']['tl_survey_content']['jumpOnYes'] = ['Zur Frage springen bei Auswahl ja', 'Springt bei der Antwort Ja direkt zu dieser Frage.']; +$GLOBALS['TL_LANG']['tl_survey_content']['jumpOnNo'] = ['Zur Frage springen bei Auswahl nein', 'Springt bei der Antwort Nein direkt zu dieser Frage.']; +$GLOBALS['TL_LANG']['tl_survey_content']['allowMultiple'] = ['Multiple-Choice aktivieren', 'Erlaubt mehrere Antworten statt einer einzelnen Auswahl.']; +$GLOBALS['TL_LANG']['tl_survey_content']['answerOption1'] = ['Antwort 1', 'Erste moegliche Antwort.']; +$GLOBALS['TL_LANG']['tl_survey_content']['answerOption2'] = ['Antwort 2', 'Zweite moegliche Antwort.']; +$GLOBALS['TL_LANG']['tl_survey_content']['answerOption3'] = ['Antwort 3', 'Dritte moegliche Antwort.']; +$GLOBALS['TL_LANG']['tl_survey_content']['answerOption4'] = ['Antwort 4', 'Vierte moegliche Antwort.']; +$GLOBALS['TL_LANG']['tl_survey_content']['answerOption5'] = ['Antwort 5', 'Fuenfte moegliche Antwort.']; +$GLOBALS['TL_LANG']['tl_survey_content']['answerOption6'] = ['Antwort 6', 'Sechste moegliche Antwort.']; +$GLOBALS['TL_LANG']['tl_survey_content']['answerOption7'] = ['Antwort 7', 'Siebte moegliche Antwort.']; +$GLOBALS['TL_LANG']['tl_survey_content']['answerOption8'] = ['Antwort 8', 'Achte moegliche Antwort.']; +$GLOBALS['TL_LANG']['tl_survey_content']['answerOption9'] = ['Antwort 9', 'Neunte moegliche Antwort.']; +$GLOBALS['TL_LANG']['tl_survey_content']['answerOption10'] = ['Antwort 10', 'Zehnte moegliche Antwort.']; +$GLOBALS['TL_LANG']['tl_survey_content']['rangeMin'] = ['Kleinster Wert', 'Kleinster Wert des Schiebereglers.']; +$GLOBALS['TL_LANG']['tl_survey_content']['rangeMax'] = ['Groesster Wert', 'Groesster Wert des Schiebereglers.']; +$GLOBALS['TL_LANG']['tl_survey_content']['rangeStep'] = ['Schrittweite', 'Abstand zwischen den moeglichen Werten des Schiebereglers.']; \ No newline at end of file diff --git a/contao/languages/de/tl_survey_editor.php b/contao/languages/de/tl_survey_editor.php new file mode 100644 index 0000000..860b205 --- /dev/null +++ b/contao/languages/de/tl_survey_editor.php @@ -0,0 +1,4 @@ + + @font-face { + font-family: "PT Sans Narrow"; + src: url("{{ asset('bundles/survey/fonts/PTSansNarrow-Regular.woff2') }}") format("woff2"); + font-weight: 400; + font-style: normal; + font-display: swap; + } + + @font-face { + font-family: "PT Sans Narrow"; + src: url("{{ asset('bundles/survey/fonts/PTSansNarrow-Bold.woff2') }}") format("woff2"); + font-weight: 700; + font-style: normal; + font-display: swap; + } + + @font-face { + font-family: "Blogger Sans"; + src: url("{{ asset('bundles/survey/fonts/Blogger%20Sans-Medium.woff2') }}") format("woff2"); + font-weight: 500; + font-style: normal; + font-display: swap; + } + + :root { + --survey-blue: #0064ad; + --survey-orange: #ec7c32; + --survey-purple: #9d5276; + --survey-green: #00ae97; + --survey-rose: #fce4d6; + --survey-black: #222222; + --survey-gray-dark: #555e68; + --survey-gray-mid: #a2a8b4; + --survey-gray-soft: #e9e9eb; + --survey-surface: rgba(255, 255, 255, 0.92); + } + + .survey-brand-strip { + display: flex; + align-items: center; + gap: 1.5rem; + justify-content: center; + margin: 0 0 1.75rem; + padding: 1rem 1.25rem 0.5rem; + } + + .survey-brand-logo { + display: block; + object-fit: contain; + object-position: center; + } + + .survey-brand-logo.primary { + width: auto; + max-width: min(100%, 320px); + height: 75px; + } + + .survey-brand-logo.secondary { + width: auto; + max-width: min(100%, 420px); + height: 75px; + } + + .survey-shell { + color: var(--survey-black); + font-family: "PT Sans Narrow", sans-serif; + letter-spacing: 0.3px; + background: + radial-gradient(circle at top left, rgba(0, 100, 173, 0.22), transparent 30%), + radial-gradient(circle at bottom right, rgba(0, 174, 151, 0.12), transparent 34%), + linear-gradient(180deg, rgba(0, 100, 173, 0.12) 0%, rgba(255, 255, 255, 0.98) 52%, rgba(0, 100, 173, 0.08) 100%); + border: 1px solid rgba(162, 168, 180, 0.45); + border-radius: 2rem; + box-shadow: 0 28px 80px rgba(34, 34, 34, 0.08); + padding: 1.5rem; + } + + .survey-shell h2, + .survey-shell h3, + .survey-shell h4 { + font-family: "Blogger Sans", sans-serif; + font-weight: 500; + color: var(--survey-blue); + letter-spacing: 0.01em; + } + + .survey-shell, + .survey-shell * { + font-style: normal; + } + + .survey-grid { + display: grid; + gap: 1.5rem; + } + + .survey-grid-columns { + display: grid; + gap: 1.5rem; + } + + .survey-results-card { + overflow: hidden; + } + + .survey-results-layout { + display: grid; + gap: 1.25rem; + margin-top: 1.1rem; + align-items: start; + } + + .survey-results-layout.no-chart { + grid-template-columns: 1fr; + } + + .survey-chart-panel { + position: relative; + min-height: 320px; + } + + .survey-chart-panel::before { + content: ""; + position: absolute; + inset: 0; + border-radius: 1.5rem; + background: + radial-gradient(circle at top left, rgba(0, 100, 173, 0.18), transparent 42%), + radial-gradient(circle at bottom right, rgba(236, 124, 50, 0.18), transparent 42%), + linear-gradient(135deg, rgba(0, 100, 173, 0.12) 0%, rgba(255, 255, 255, 0.9) 52%, rgba(236, 124, 50, 0.12) 100%); + border: 1px solid rgba(162, 168, 180, 0.28); + } + + .survey-chart-frame { + position: relative; + z-index: 1; + min-height: 320px; + padding: 1rem; + } + + .survey-chart-panel.is-line .survey-chart-frame { + min-height: 360px; + padding: 1rem 1rem 0.75rem; + } + + .survey-chart-canvas { + width: 100%; + height: 100%; + } + + .survey-results-panel { + display: grid; + gap: 1rem; + } + + .survey-results-list { + display: grid; + gap: 0.9rem; + } + + .survey-results-row { + display: grid; + gap: 0.45rem; + padding: 0.9rem 1rem; + border-radius: 1.15rem; + background: rgba(255, 255, 255, 0.78); + border: 1px solid rgba(162, 168, 180, 0.24); + } + + .survey-results-responses { + max-height: 24rem; + overflow: auto; + padding-right: 0.25rem; + } + + .survey-response-card { + margin: 0; + font-style: normal; + background: rgba(255, 255, 255, 0.72); + } + + .survey-metric-grid { + display: grid; + gap: 0.85rem; + grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); + } + + .survey-metric-card { + display: grid; + gap: 0.35rem; + padding: 0.95rem 1rem; + border-radius: 1.2rem; + background: rgba(252, 228, 214, 0.38); + border: 1px solid rgba(236, 124, 50, 0.16); + } + + .survey-metric-card strong { + font-family: "Blogger Sans", sans-serif; + font-size: 1.35rem; + color: var(--survey-blue); + } + + .survey-metric-label { + font-size: 0.78rem; + text-transform: uppercase; + letter-spacing: 0.08em; + color: var(--survey-gray-dark); + font-weight: 700; + } + + .survey-card { + background: var(--survey-surface); + border: 1px solid rgba(162, 168, 180, 0.34); + border-radius: 1.5rem; + padding: 1.25rem; + box-shadow: 0 12px 32px rgba(34, 34, 34, 0.06); + } + + .survey-meta { + display: flex; + flex-wrap: wrap; + gap: 0.5rem; + align-items: center; + } + + .survey-badge { + display: inline-flex; + align-items: center; + padding: 0.25rem 0.65rem; + border-radius: 999px; + font-size: 0.75rem; + font-weight: 700; + letter-spacing: 0.06em; + text-transform: uppercase; + background: rgba(162, 168, 180, 0.16); + } + + .survey-badge.success { background: rgba(0, 174, 151, 0.16); color: var(--survey-green); } + .survey-badge.warning { background: rgba(236, 124, 50, 0.16); color: var(--survey-orange); } + .survey-badge.neutral { background: rgba(162, 168, 180, 0.16); color: var(--survey-gray-dark); } + + .survey-button-row { + display: flex; + flex-wrap: wrap; + gap: 0.75rem; + margin-top: 1rem; + } + + .survey-button { + display: inline-flex; + justify-content: center; + align-items: center; + gap: 0.5rem; + padding: 0.8rem 1rem; + border-radius: 999px; + border: 1px solid transparent; + text-decoration: none; + font-weight: 700; + cursor: pointer; + } + + .survey-button.primary { background: var(--survey-blue); color: #fff; } + .survey-button.secondary { background: rgba(255,255,255,0.86); color: var(--survey-blue); border-color: rgba(0,100,173,0.18); } + .survey-button.danger { background: rgba(157, 82, 118, 0.12); color: var(--survey-purple); border-color: rgba(157, 82, 118, 0.22); } + + .survey-form-grid { + display: grid; + gap: 1rem; + } + + .survey-label { + display: grid; + gap: 0.4rem; + font-weight: 600; + } + + .survey-label input, + .survey-label textarea, + .survey-label select { + width: 100%; + border-radius: 1rem; + border: 1px solid rgba(162,168,180,0.5); + padding: 0.8rem 0.9rem; + background: rgba(255,255,255,0.98); + color: var(--survey-black); + } + + .survey-inline-check { + display: inline-flex; + gap: 0.6rem; + align-items: center; + border: 1px solid rgba(162,168,180,0.35); + border-radius: 1rem; + padding: 0.8rem 1rem; + background: rgba(252,228,214,0.42); + } + + .survey-alert { + border-radius: 1.2rem; + padding: 1rem 1.1rem; + margin-bottom: 1rem; + background: rgba(255,255,255,0.78); + border: 1px solid rgba(162,168,180,0.35); + } + + .survey-alert.error { border-color: rgba(157, 82, 118, 0.28); color: var(--survey-purple); } + .survey-alert.warning { border-color: rgba(236, 124, 50, 0.28); color: var(--survey-orange); } + + .survey-kpis { + display: grid; + gap: 1rem; + grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); + } + + .survey-progress { + width: 100%; + height: 0.75rem; + border-radius: 999px; + overflow: hidden; + background: rgba(162,168,180,0.22); + } + + .survey-progress > span { + display: block; + height: 100%; + background: linear-gradient(90deg, var(--survey-blue) 0%, var(--survey-orange) 100%); + } + + .survey-progress-bar { + display: block; + height: 100%; + background: linear-gradient(90deg, var(--survey-blue) 0%, var(--survey-orange) 100%); + } + + .survey-range-output { + font-size: 2rem; + font-weight: 800; + color: var(--survey-green); + } + + @media (min-width: 960px) { + .survey-grid-columns { + grid-template-columns: 0.95fr 1.05fr; + } + + .survey-results-layout { + grid-template-columns: minmax(320px, 0.95fr) minmax(0, 1.05fr); + } + } + + @media (max-width: 767px) { + .survey-brand-strip { + padding: 0.75rem 0.75rem 0.25rem; + } + + .survey-brand-logo.secondary { + height: 75px; + max-width: 100%; + } + } + + \ No newline at end of file diff --git a/contao/templates/frontend/_survey_branding.html.twig b/contao/templates/frontend/_survey_branding.html.twig new file mode 100644 index 0000000..38669a0 --- /dev/null +++ b/contao/templates/frontend/_survey_branding.html.twig @@ -0,0 +1,3 @@ +
+ +
\ No newline at end of file diff --git a/contao/templates/frontend/member_survey_edit.html.twig b/contao/templates/frontend/member_survey_edit.html.twig new file mode 100644 index 0000000..349e4d4 --- /dev/null +++ b/contao/templates/frontend/member_survey_edit.html.twig @@ -0,0 +1,193 @@ +{% include '@Survey/frontend/_survey_assets.html.twig' %} +{% include '@Survey/frontend/_survey_branding.html.twig' %} + +
+ {% if headline.text %} +
+

{{ headline.text }}

+
+ {% endif %} + + {% if loginRequired %} +
Dieses Frontendmodul ist fuer eingeloggte Mitglieder gedacht. Nutzen Sie den normalen Contao-Mitgliederlogin auf einer geschuetzten Seite.
+ {% elseif createMode %} +
+

Neue Umfrage erstellen

+

Die Umfrage wird nach dem Anlegen automatisch dem eingeloggten Mitglied zugewiesen.

+ {{ form_start(surveyForm, {attr: {class: 'survey-form-grid'}}) }} + + + +
+ + {% if backUrl %}Zur Liste{% endif %} +
+ {{ form_end(surveyForm) }} +
+ {% else %} + {% set locked = survey.isLocked == '1' %} +
+ {% if backUrl %}Zur Liste{% endif %} + {% if publicUrl %}Oeffentliche Ansicht oeffnen{% endif %} +
+ +
+
Oeffentlicher Link
{% if publicUrl %}{{ publicUrl }}{% else %}Noch keine oeffentliche Seite hinterlegt.{% endif %}
+
Status
{{ survey.published ? 'veroeffentlicht' : 'entwurf' }}{% if locked %}gesperrt{% endif %}
+
Bearbeitende
{{ editors|length }} Mitglied(er)
+
+ + {% if locked %} +
Die Umfrage ist strukturell gesperrt, weil bereits Antworten vorliegen. Stammdaten koennen weiter gepflegt werden, der Ablauf und die Fragen jedoch nicht.
+ {% endif %} + +
+
+
+

Umfrage-Metadaten

+ {{ form_start(surveyForm, {attr: {class: 'survey-form-grid'}}) }} + + + +
+ {{ form_end(surveyForm) }} +
+ +
+

Bearbeitende Mitglieder

+
+ {% for editor in editors %} +
+ {{ [editor.firstname, editor.lastname]|join(' ')|trim ?: editor.email }}
+ {{ editor.email }} +
+ {% else %} +
Keine Editoren hinterlegt.
+ {% endfor %} +
+
+ +
+

Antworten und Ergebnisse

+
+ {% for submission in submissions %} +
+
+ {{ submission.answerCount }} Antworten + {{ submission.isFinished ? 'abgeschlossen' : 'offen' }} +
+
Begonnen: {{ submission.startedAt ? submission.startedAt|date('d.m.Y H:i') : 'unbekannt' }}
+
Beendet: {{ submission.completedAt ? submission.completedAt|date('d.m.Y H:i') : 'unbekannt' }}
+
Teilnahme-Code: {{ submission.token }}
+
+ {% else %} +
Es liegen noch keine Teilnahmen vor.
+ {% endfor %} +
+
+
+ +
+
+

Fragen bearbeiten

{% if activeQuestionId %}Bearbeitungsmodus{% endif %}
+ {% if not locked %} + {% set questionType = questionForm.type.vars.value ?: 'yes_no_maybe' %} + {{ form_start(questionForm, {attr: {class: 'survey-form-grid'}}) }} + + + + + + + + + + +
+ {{ form_end(questionForm) }} + {% endif %} + +
+ {% for question in questions %} +
+
+ {{ question.type }} + {% if question.mandatory %}Pflicht{% endif %} + {% if loop.first %}Start{% endif %} +
+

{{ question.question }}

+

{{ question.description ?: 'Keine Zusatzbeschreibung.' }}

+ {% if not locked %} +
+ Bearbeiten +
+ + + + +
+
+ {% endif %} +
+ {% else %} +
Noch keine Fragen angelegt.
+ {% endfor %} +
+
+ +
+

Sprungregeln

{% if activeConditionId %}Bearbeitungsmodus{% endif %}
+ {% if not locked %} + {{ form_start(conditionForm, {attr: {class: 'survey-form-grid'}}) }} + + + +
+ {{ form_end(conditionForm) }} + {% endif %} + +
+ {% for condition in conditions %} +
+
Wenn Antwort = {{ condition.answerValue }}
+
{{ condition.sourceQuestionLabel ?: ('Frage #' ~ condition.sourceQuestion) }}
+
weiter zu {{ condition.targetQuestionLabel ?: ('Frage #' ~ condition.targetQuestion) }}
+ {% if not locked %} +
+ Bearbeiten +
+ + + + +
+
+ {% endif %} +
+ {% else %} +
Noch keine Bedingungen definiert.
+ {% endfor %} +
+
+
+
+ {% endif %} +
\ No newline at end of file diff --git a/contao/templates/frontend/member_survey_list.html.twig b/contao/templates/frontend/member_survey_list.html.twig new file mode 100644 index 0000000..c1adc0e --- /dev/null +++ b/contao/templates/frontend/member_survey_list.html.twig @@ -0,0 +1,52 @@ +{% include '@Survey/frontend/_survey_assets.html.twig' %} +{% include '@Survey/frontend/_survey_branding.html.twig' %} + +
+ {% if headline.text %} +
+

{{ headline.text }}

+
+ {% endif %} + + {% if loginRequired %} +
Dieser Bereich verwendet den normalen Contao-Mitgliederlogin. Bitte binden Sie das Modul auf einer geschuetzten Seite oder mit einer separaten Login-Seite ein.
+ {% else %} +
+ {% if createUrl %} + Neue Umfrage anlegen + {% endif %} +
+ +
+ {% for survey in surveys %} +
+
+

{{ survey.title }}

+ {{ survey.published ? 'veroeffentlicht' : 'Entwurf' }} + {% if survey.isLocked %} + gesperrt + {% endif %} +
+

{{ survey.description ?: 'Keine Beschreibung hinterlegt.' }}

+
+ {{ survey.questionCount }} Fragen + {{ survey.answerCount }} Antworten +
+
+ {% if survey.editUrl %} + Bearbeiten + {% endif %} + {% if survey.publicUrl %} + Oeffentliche Ansicht + {% endif %} + {% if survey.resultsUrl %} + Ergebnisse anzeigen + {% endif %} +
+
+ {% else %} +
Dem eingeloggten Mitglied ist aktuell keine Umfrage zugewiesen.
+ {% endfor %} +
+ {% endif %} +
\ No newline at end of file diff --git a/contao/templates/frontend/show_survey.html.twig b/contao/templates/frontend/show_survey.html.twig new file mode 100644 index 0000000..b17e7b7 --- /dev/null +++ b/contao/templates/frontend/show_survey.html.twig @@ -0,0 +1,84 @@ +{% include '@Survey/frontend/_survey_assets.html.twig' %} +{% include '@Survey/frontend/_survey_branding.html.twig' %} + +
+ {% if headline.text %} +

{{ headline.text }}

+ {% endif %} + + {% if errorMessage %} +
{{ errorMessage }}
+ {% elseif survey %} +
+
+

{{ survey.title }}

+ {% if progress.total > 0 %}{{ progress.current }}/{{ progress.total }}{% endif %} +
+

{{ survey.description ?: 'Bitte beantworten Sie die folgenden Fragen. Jede Frage wird einzeln angezeigt.' }}

+ + {% if progress.total > 0 %} +
+ {% endif %} +
+ + {% if isComplete %} +
+

Vielen Dank fuers Ausfuellen.

+

Ihre Antworten wurden anonym gespeichert. Es wurde keine Teilnehmeridentitaet mit diesem Umfrage-Durchlauf verknuepft.

+ {% if answers %} +
+ {% for answer in answers %} +
+
{{ answer.questionType }}
+

{{ answer.question }}

+

{{ answer.value }}

+
+ {% endfor %} +
+ {% endif %} +
+ {% elseif question %} +
+
Frage {{ progress.current }}
+

{{ question.question }}

+ {% if question.description %}

{{ question.description }}

{% endif %} + + {{ form_start(surveyForm, {attr: {class: 'survey-form-grid'}}) }} + + {% if question.type == 'yes_no_maybe' %} +
+ {% for child in surveyForm.answer %} + + {% endfor %} +
+ {% elseif question.type == 'choice' %} +
+ {% for child in surveyForm.answer %} + + {% endfor %} +
+ {% elseif question.type == 'range' %} +
+
+
Aktueller Wert
+
{{ question.rangeMin }}
+
+ {{ form_widget(surveyForm.answer, {attr: {'data-survey-range': '1', 'data-survey-range-target': 'survey-range-output-' ~ question.id}}) }} +
{{ question.rangeMin }}{{ question.rangeMax }}
+
+ {% else %} + {{ form_widget(surveyForm.answer) }} + {% endif %} + + {{ form_errors(surveyForm.answer) }} +
+ {{ form_end(surveyForm) }} +
+ {% endif %} + {% endif %} +
\ No newline at end of file diff --git a/contao/templates/frontend/show_survey_results.html.twig b/contao/templates/frontend/show_survey_results.html.twig new file mode 100644 index 0000000..85886d8 --- /dev/null +++ b/contao/templates/frontend/show_survey_results.html.twig @@ -0,0 +1,162 @@ +{% include '@Survey/frontend/_survey_assets.html.twig' %} +{% include '@Survey/frontend/_survey_branding.html.twig' %} + +
+ {% if headline.text %} +
+

{{ headline.text }}

+
+ {% endif %} + + {% if errorMessage %} +
{{ errorMessage }}
+ {% elseif survey %} +
+
+

{{ survey.title }}

+ {{ completedSubmissionCount }} abgeschlossene Teilnahmen + {{ questionResults|length }} Fragen +
+ +

{{ survey.description ?: 'Keine Beschreibung hinterlegt.' }}

+ + {% if downloadUrl or pdfDownloadUrl %} +
+ {% if downloadUrl %} + Ergebnisse als Excel herunterladen + {% endif %} + {% if pdfDownloadUrl %} + Ergebnisse als PDF herunterladen + {% endif %} +
+ {% endif %} +
+ +
+ {% for question in questionResults %} +
+
+

{{ question.question }}

+ {{ question.totalAnswers }} Antworten + {{ question.responseRate }}% Ruecklauf +
+ + {% if question.description %} +

{{ question.description }}

+ {% endif %} + +
+ {% if question.chart %} +
+
+ +
+
+ {% endif %} + +
+ {% if question.type in ['yes_no_maybe', 'choice'] %} +
+ {% for option in question.options %} +
+
+ {{ option.label }} + {{ option.count }} + {{ option.percentage }}% +
+
+ +
+
+ {% endfor %} +
+ {% elseif question.type == 'range' %} +
+
+ Minimum + {{ question.minimum is not null ? question.minimum : '-' }} +
+
+ Maximum + {{ question.maximum is not null ? question.maximum : '-' }} +
+
+ Durchschnitt + {{ question.average is not null ? question.average : '-' }} +
+
+ +
+ {% for option in question.distribution %} +
+
+ {{ option.label }} + {{ option.count }} + {{ option.percentage }}% +
+
+ +
+
+ {% else %} +

Noch keine Bewertungen vorhanden.

+ {% endfor %} +
+ {% else %} + {% if question.responseSummary is defined and question.responseSummary %} +
+ {% for option in question.responseSummary %} +
+
+ {{ option.label }} + {{ option.count }} + {{ option.percentage }}% +
+
+ +
+
+ {% endfor %} +
+ {% endif %} + +
+ {% for response in question.responses %} +
{{ response|nl2br }}
+ {% else %} +

Noch keine Freitextantworten vorhanden.

+ {% endfor %} +
+ {% endif %} +
+
+
+ {% else %} +
Fuer diese Umfrage sind noch keine Fragen angelegt.
+ {% endfor %} +
+ {% endif %} +
+ + + \ No newline at end of file diff --git a/public/fonts/Blogger Sans-Medium.woff2 b/public/fonts/Blogger Sans-Medium.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..f3853966e0ac48d0932ad74c821a40f24136515d GIT binary patch literal 43008 zcmV)0K+eB+Pew9NR8&s@0H^=}3;+NC0YWeU0H>?~0RR9100000000000000000000 z0000Df~^J{fvprAmRbg20FMX(HUcCAkpL6B4g>}Tv~C9=TUSAG1>IoVK@+9YdE2J; zR{>;tHO#Y&!`(_6Ap+MKsaX$`{r~^}f@CAcJg_((-dEMEvd!5xVJ7H=TLFn+Mm0m} z(Ts2##5m0n$_PVS)*^5Hx}ml%w%v#N5YOw)%*-aH>&@q*fZ}y^^FEq*BSb|d%s^5s zFgLNonFSPX7x>abe9OBbaQvX)Ooc&>$j;vV*fhguUs1MCX69N&L_{1SV$n#7w{Um- z%BDB$4LhirQ=`3vf3v`ZJ6#l*66!-G>RbK9)c=kzq{VdKp2#Vc{bN+hpS$7?Dy*vQ z4L6hTl`uIZj%6PZA>BbN!ciQLyU4X*JJ8R8)JzQGywX{_HJHgcc>WkMzf|jPod=8^ z>Y4KIU#%Bsr<}DoG0J10M!h%9F8I_}fw9YDM6K(K6{4P>bMO8`wPHc5;(;(UXvNKk z=ePNP?ga!c^rhtrA}NTZk;ug8m4TRSGq$m~z`Ou5uewo7QGAzk4CBwFUF>$UdB<+AQBqjchR?9@qRZ+!5 zLI#4^NQNSi4U8c}#+(gj_EK!ku+adqfndQTLK7GWK`evC2&$P3I@l;f6u%#AXW#vY zHj_jq)A44ZX%bDeLMzlFM)Ywn?)`%CrlobO;H3*>BJdRw&`$j5pSaP!Uo(Mb1rp0C z-2YC~8?1x%@egmUE(hJ-NtjO3*@|V!PtuR85KtO`^9o@9f130E!;{Hd=Q~||KjDfB zRY@=9QlO58luVMzL~J5>D3UlKaR{ar4^;J<)~-|AlXv?5Z?61-g)HF(`0b`^i+l(< zRX_*qs#{?;K!x;;m;%Yx2zJ1#!T=4=_w3i~v&h^xgIL%g-te^=(X_N$s5Dtm?zelJ2 zPiDq%8S-oXcqYDgIQO?&vaO`NY~mD`B(}lW6dObpqDVpoNeHQfz__OLx107_>+=4D z0a|#uAGi%v>i<93=KpdT2iM&7?^=uV<`QfNb(KK(YNGROK)pK|-FUv$y`o|fxtYIyHX zrK{#wO>^^SCq?&~XDus=2468pY#Om_SW6HO*;FWfpONNqf*%|XtNxx+-i7_uE z`>wqc^23^@NiUcF5rG0gN0LyHoN@g8l$jDE+MKCcYW88CFjV2v5!s1eqow}Sp=y$c zhne6fl8L^?`x$Ha@WlRQ7Nn*HDJT|zOQ0?m-*aDwG`03O3|j&O64Wdfg~PnE{Jp7Z z``!|ib`=3doFm}Kb0qEDh1}Uy=W_RdfV+Q}I4zbZ30&|b5SO^10+L1mE`mxiRnAM0 zR9I4h%ODs$bMC-%;yK=(laxEh*riZuR93E9g~~Ct?i)9~ipGB5w2Zo+4TzorHUa@a zGoq^BH8nMVdgYMEF`$SpsU_{6MwbHt2Uz0lFggU!|C;_Q^_l(ag6y?BD|N@nfXTl@ zH-Ov${L;SSeRpKJblFa+@=I^}((Y49@2K?3GJ)wRAt)#SW&%h62|#-30EW@v1V9p= z|K3)m`_E#g*()^XiOW+Ooqv5ldkG+i$Nf30cUunC$0@bPiT-JT1lTNV znvo=w+C_1!R6rt+_dRcrO&wN)-#fD!6tkcSiNgi{omkksFPgO74K#=#24jp6!h0V( zG5_Oe`bzE*}8n7?0f%9^8BbVdf(3n{rO=1xa0#jbJF~? zu*$zn`qiT&)QKwz=&~tBnhlsoQNqS0J5gg*UR8>baF_LxF#~|sR5s{LqP^W=LCmp>}(-v*{ zSXABBPeUuOs`{E6+tk)-qqeNQ@l9@*_Ugc<_h|)v-uza#scr48vD01an~wCYB*Tf6 zqN+OEyAL&*h4qUOXk1w|maNCKVb4vkyKt>-Xd%Wxel>`3H-08`h*6JmY!f@KsXBG0 z@wA$laZbnSG5u%QJQ=~{j%+GNF^!|0o*5kTOwPhsXKN1T%|Vt%8OhY*>Uy-jyL!{k zeVKfzVWr^t6K->cj^C9j$oW}n+1x|qTSk-UWQklOtmHH?r8VMYv1uj3 z-9tXxpfTZ~lN6IoV`LHcY~sgu^8fM)`PS>-{$snG+3xE`sv8rnJUrW=<5YKti(C}{ znpj02mqVsqE(_KgbeC2&iK!&rV^m{L5u=IAYBIjAaGPVB+-QuwXz&La2SxZT#~zXI z)if9?eB{&K`yX9-`f=V>Fa~OeZcm6H*d;mvfR{YTb?JiE!i*Pl^#F8; zFrkbKskC7?Vrnf8BWg8yLw*K9kV4o|N)X8mte zqSNZ0bsO~@@5IDM*5m14o|x)=5Y)G=C)AE#?KGW>nf$7!5Yx@Ljj4ycJM%}T?yZVW zL#jUQe5z-e8D4Sp3&}!1=Sn>ee~`?Mt*X4Q`n=j49(6By2d!|CV#Q08ELGa-&Os|y zqGYKuO#csBVj_Qc;i|Og>hmxNdgo!pd|6aVb-4unG;JcEMxyKuJ%wax*)BAEemMe} zmAyPv?kR;f%I#x_KP%FwFE`#yqoMuza{U;Y)(=JdP2iXP3T=4qM~P`+XniinS+-YB z8TqZ83i6J|IQ&9(WScs&Mjh(N4z*>6YO*8S)S*t;ku~bT#5lf$%j@E(lVm#CUj;sdWq$f_B17 zJcePlL2dKq>xwmdS8zQ7Qo(A3|Iqpy@IXQo^R4!{Q0w&9rxQB5tsUzAieEF=rq#JV z4$}lq#_XT1d3Ve`KJV(?dp|3M8@6GcGjGYp3m06zytMK3sn!N~M_14t^jhpR(M5{S znPnS8F*c^dOjr~aho!mP)zX@+Gvz4_&baEPZx|#7i@{?M3Zvhvrp__1A$JIFz}5huQa@IMpz=u&b!}}J@m=%lYp}o*u-N~3{GM#H&U&Dz(={0 zkQ}&`=tz6+sSt@sTD|wa2iwT&_c4$-58ntzu+y>ffw%1_mOKY+r-jwYIuOV(fcG@< z)ix9i1mXa6fK@oqANwDH-V=>v8XsBe8Lv@eQ$E&^tAYSzR-DnkmU^86avZQ-iN z5r0R9E^YIC*YrW?nv@=^FGMXN)d|pvs68y?|V}U-W_NT>qgN1|638A~Za-t^VjpobjA(t8Q?zkB7i5`V z{}KI2@rli@)D_pv9VBqL+E@JJ86ig^V&CrAN0y!4F+E1I-E3P%ht#rij*qAUNHt|W zTjZtyJP$rpYBO4oxDq8lQMUC_Pae=4J&ug_UTp3NCNP6sGSNiI0BE#sc7$+jz zSzUs)l~%lu_^4|Ruz^=!Og=NOC2VIk6{|e4FVqE2A<1F8YGI+gTrSsn;7!`V7^1YH z`v{qu=gQA2iL2&vC@87+0eiGPYPeq9;0aIEn2R6PUQa_7k=QJgeVy3sDzt~MS8Q~o z?q@>{+XAU|l~MsEIK6Jwt)>MHrzU=OBz86Sv#(D(d+YMeJdUyXnfzo49!n=gj3|2z)I!YFp-JzlK&F^tqyd|M1!$!$RvVS zeFugM4k76E&jkHoqb2piesg-p#Nl#NNKF-3iewv_?ghd%Kp`Qu@%qb}hvJ7%mje8e z3gWCrp(?_GfuZ2zdGEauTB}Q zu@I>*=Iy`ovDiP;Zi>?3M7^;_N+8#7``|G^}IDyp+9@5orXI}9x8j_`59q+-j`_??Bzp?spPhn{tRYxSX*FS%gta04(w^3{Qx(s~n zEB@iL1bbuhn-`+IclBgj8k4$d*cvlDf5{Mu&}HnX^DMH{22SXKmW8DR|C|WFBBH*B z`XBZVK8faNk#$)za3Eudg>kA;B*^opcWaQ1w$ZA9Msraif@8)IARj*UoidPw21kE*eRwSJw7b#JU0 zq-ZOCcNKi%S@-kO?3(>AhPmH-&NjnBOINJXbV!rY+&NNUp;^t$ZTIdw^TORbaUy;| zTup2_>V?=^&=!C1ppEJzIs+V}LzS8+ZmKR4;D59~97Y58vfa78_sbrhd zXpb6ez(o~_p^`;uwMQf9=kkF+Y|LbcX#of{n&r&FU%tT%mzl)WZR0>H-K9C#K?KLN zztM`eZ_5BL%QheW1y)9=+7JYQ0IMjd8b(qzh`0>Y zQk5Lx-(bZ+(W81{kDCXTzw9Qf!W4n$nj3nA*7cP7OOHGR9MrbB*(ahMHk2GHf!g;z zXLsQPE5=}3JSlWLG?LyM(JMW<)opK$Letn0&R({~7H){E!%9R(41d{$flgWn-?s5z z`7r=U@11;Ecp_>0?zbvgwa3P0>H|z zm^sGcCoVQ`YcA9&5bWfGdewl<{{#>eMtIvCfOO+vNUe~V8UXAX^sPzgOU;9?bl#GRY zD}WdN*@8y^SVkF$2}xKO`7*DhJF8^DniVd=v>IEb|VW1QF~MK(QUD#fv5+4pvJC z^l6@t#rL@Fi$O33!7F=4#r;4e9#@=59JB^?24PWx5p3B)u|Sn9fv|>RBG^yiw)Vlc z)Ww6C+dy3{<$p6z*>Jn3RPEP+L-tgmg0Mp9b$x(DQ?kFoJ0PMuLiOS{21pn)HQtep zmFAHlIZjrR(5|MYp9`XQ|22@|QU2h8x|HbRO}0WYN5mlF4sf1C8XjozrYP|omU$JZ z?nI&5O1jyOy%v2*L}fddVKHQ9JHxR^Xu?^8A3>qyv=Z5oE+63YcG>?S;j=U(d>@$? zR=+NM_w;y?*4m_-xGbVMkE}8%18la^w1S`=OoiG&BFdjY78|$z-&<3optCrIGnjyLxPR)$Y3d4et7m(+y zW%6JW7$REth>!kppDv^O`O=?l(qXHgxd6QI^-zc9lvm%a>Ds6d*q%>$X+%^(QPxX)LL6|UXoBEo%K+UN2YL_}sZB;+f&^0{GI8DB$SEJPEG+$|+YF=q^ZI{kj zr_e>|5_M&|GF`haN7ttZ$}N4Nev96%FV*YxcMYf^*U)EZHuM@k4;O{EhI_*E!<)iQ z;m^Zg86%AIjAx8L81I{?CY{M*N--@p6`8i0jHX(XD8eJ+>xf?>9+_EYgV}0!o0pp_ z%`$UCq*vtj$g0RLi_vn?(rbBOd2VG}Mb_BeZzsB{<|pE(Jq!Rd77IX5{S&OzsW=S%0CsIaKMsMcubXlZn4 zba=EWdSeVSrY7b8hc2GBxVv{NBYercB|m1o&Xg@ZFu0PX zT^7Bpav3*VF?_eg%fHNin&V!vY=vt)m|L?lG5KHaP#&1NYHO8tRs1UVs7MF{+i&?RGEwz^9f05YoZ>L)yZ8c@It!HBUSN`A~JH}n%CVy2jboO^jo!9E@ zy4dtxue#SA@5bGBcV3x#u3{Oxw5P9Ur*DkP-XG1Wkd~e`omlv=9M|2#Qf`Jp9CSy26A>{Du;&*cf;t}3}o}; zl||w3vxm77%iz(!&Twrh5UAZsUW!HZW5>pgl+FH(rI8Tozy(#`6;EY+T1=3Wj6rj_|cEUx@Qq&ALPP0 zU2fXs36up%>Oi{?=!7r!At(m!qxR>@MM$HR=}GL6B(q?D)ba?e<)wd)EaIqQG0yycP<1N%PVNHD+5R% z3uolLB-1;^k(kX!m(ab6+6H@9SYSIzyqEKPI4_*|{j7uPZ-Q1`=YFu-oiq99*x{Nh z?_GZQWAAwne|B`E0U!su}@F<%Okt?g061Jiq(u7HN;zF5y`qGug_f`-CQP`qoc> zVO#0&?LLvbcBg6oHpbO5CH{X}FY7FjAQJIDLpTS7dq8$}yIDa(R-G41I$3)iMzQcG zVij$Sbqk5*Gz*Y(SzMWHB=pMcy2gb>Cg``t9aw~*hIg`J789nrU0d{tQ# z(uucLG+q8G!&6bOrA@G0vUNcEzWbXnxD)v zzGwbxNt>&Bs9d2M<>4A#0bdj2ggevppQ5H6wMHEsG>_@iLEIc2uP_zJdfC^xCkUh{*jb&U=@1!}{dbzg{M75yxWdT!|yn44gRl zrc;RE(3t!;S{R_D3C)xe25p0YAS}iPNszi)7hyvU5R_W-GC}^rAL&9HR!j0@gh;u~cJe~-Iy(okwr5vE3sqbonSTivY1Pz{ks-(I3JEjR?4?S{MBmmo~8cT25 zgFSe$K6@mOu%C{kAdIaP_1a>l?=4vZp{Fz8 z);5JH;DBv`-4aE%v!Gztu$DrZ9W}OvtTJ0#HUcvXJi)J4+qg=qOa#ZI5n#dn#VAs% z1I@LtHn`t-gmFM@2R|Kc4C2W@SZSx?$ANo_4pV{ zB*&D0OdW2!HY-AQNM~Jq-m&eEr%T_t*OTHGCod*(P&6_24j8cuTm-q&Z2cZw(EuZ8 zkNo3a4JcZH*telK5e)i>*jIpLP~VO{!xf*jg)QstA{t%#*!~*JrAJCj%VBWCc=#n0 zK>yG+rhUC7Bb-7z9@3R2uIV@M<>t~q{ZUr?{6|sO8{9i_K%T)5(Y&l4i@d%+8ufF(A(Yz<(YH2OSd0gh@PnFyZ!bUkjJkxCe%l!5?c09_)Z+Cdq#P8>vO}H+3+0*DC&B^ zDnu;BPrPs=-QvSMPuJELW5-)YA8uY#_AF5MA@UQ?C9@- zh>&LMHy!~M#%pjzg1-n5v;wsqJQe4evA>kR&me>1OAG6$y<)6r*JF zjdTKS zjHI0mC?J_CG2*R@*c!F{Zd%s`B+YOox!5~ITkehM*&tU>QpGf(iRAV$0U8vAuLYYn zkjEI$MvI%Y2t!2ir#)WOK~a#cO8kbffhyFJB!i2B9F?VAm`UScl`NWzrjaK2LmWy* zSxRD41uQHifLQAOf8!=DVHG!?18FnDVxYay#ge8(+02nL%Vv3}r} z4%EVQ;mX;-nTH4JajZ6|1_~#wo}jljPWkh7saUzWN_3k@w!HEWlnAYO3_Ze6ywB1v zt=t?t{NYBKbS2Us6;j5#-isdm=+xBfOH%Uo1__PqrLU8ZYA)0wMaT%1dYL3-k;*tJ z1SV1xZQ4~37!x+4fqiwmpT46F_iofr%uJ#TnjYuQM`Bb)TEj9GsXDLXBdr{(PyayM zkv==plPpa`57406gDs2!PsNAIO0~)AuVnT*A|951x**0H|C7OGN23@>q z!vPu`Ft$X%dZJ|r8}=jo8OzSZ+antiEoq-?<#g1^W9m|A_}5gWk}-U|(QzY)cUh9k z)(Ut7yZZS*a>1Q`;yUEVP)$%~1171Gnq9_3>2Ni%aQ8b9$3&eyhh0pRwzgT^$+Ceq-R-e4;$llyw6n#K#$L1)-ucPD`t;v(vA9;qL7-(=Bl0AvH zM-eaUEKn>3DfqqqJ(!@s_#CPnc{~h*or>XN+k#@^K)KEhPvq)lf+GJv<>y&m*e2_O z_NGKoWd2j8Rz_%|GNqARmRvOl%=5K_$}|0WdTKR{d9&ntuapv!xY8Y~-m=NSj`jH+ zvM%fgZ32UNs507X%{r>ARKz9Im2>bT+28L!g7>}mtKu#UzS!@=ThJY?w`AM_yvnQ$ zq|qGG-S=NpZ=~O?+H`vG*?y;c-t2j+*R7Dn9+xz1sJ3|IAeE)%s`7GWD5zt5eoQt6 z1CJ+FVEPw~^C6;ek@SxGZbX(SV%YGa-o!))p$Oz4mgY>B$6cRb4#9)BlwlnWfkQUh z7FMmClLrow;}U}7YQJ@bv#~*@2-(S8y-47ZHx!vm!3jA4nbG`%kq>Vmrg1&nFxX>X zt#Q#TSG(P;q#(P(Ndo_02Qsoa#2fQcz4UD^kp~~YGc?6oSXn0mFhKGah06iiQz zX>uhhRwpR>7j(q*dg0>_%6%srh-+c9s4Vd(_ERolnpfd`1ycr4O*#0R%96XCF>Z@r zd>Qd|3XbW)u4D88m+8sE3qt?8%-1qQb=f6Nrt#C`zfjVoP$w zz}5$&LgOSXi7P8BT1S!@|L7R7NGHI5k=H)7&ac1G;8i$-@K;*ND<&k~m@$$fC-k{F z3ovz!(#qlb9E4#`yswv`i;{rw-VfF&{a%tCFO^)v-!%b$jEqhc{sNQ3=y)oDXO&S+ z??SY8NHj*k>A3m&$PzTDBM5({l@pS$_eH>O;;Wz0)6MaE$<9B2#<@DUz4VJrSwT}h z!;xC${eoUD^6UHSJi|Cd$5e{(aYl2!j;zX_m{2_<57Dcw#vgV;quc0wdEn7LM|(HQ zv0M?tCRUN4?iEkt@2> zPfnp6lBLG%y7b}C8I@z)t(((jt%_1~)dCKat?bccE5!VDr1MmVTXn*cxYE2gtcwj5 zLpvg64o~y&ZZA#qq_|YZSpmHd_kDu*>~0L(hs+{} z$M2##n%5Xu-=ZnQ_e1owdqr(X{g`$-W#O&+-`rT555IhV(rOTsQ({gy>Z;$m=W zud++F506gW&uDQxT(BF(d|!p}YyU!mUb_QcmS`TKPvpm|LrsaEibFMqf~X5r*tl96 zFsFDf7T@D{E(C)y$UuqyQ_xI|mwg&wSNX?blC5A{mzy?ugU+HTb>OIw`Y(-m*W`of zpx$7CRHJ7OO9cBUzd9KH(X}@4URvogN1sM=wp9(q~uf*kBt6rP73 zYqB*Hz67Cp2#BzByvI{VU~|h{u7mSEf>b95TI7z3z`8~K6u(_fWrZgmX_n)e6lB1qkKYF0BMp0C>dtb5MwXmoIIPLNvHA+4=RH?i5TXqW#sxAd1*EqmTmPW4idpr0W| z$t27#r8!+im;~sB;#1&;@h} z51<^Xejb84sQXzLP=y4j!=XEMj_tRf^_W6MX>|*655)unZKc~$;a<7W`Oc8!4ymN! z{r42W*_&BpKY+Vfc zTOc`0>UXz;G)Y5mis-BCb7}^)>HQ&TwpzW4D7EOjJHJK| zRT&MUbtf!LyY$(DHT|VQ6F>cT>Nb(e)EO)5v)YgG=LPsL23mdrvu-fT@h88yyyv`o z)9tSJnS0*zUiy^Bc(>ule!3HavyGZN7mlNe!gU&DaKPHU1lQe~JDsagxawdp&DmZ{ z7fUFz)3npk7`3D4Cko9XfmliuFBkQp5fqBZ7K{Uwse~j_4qyoo!U1AOLoT{_?TRv`BT>becKUlrjzT>5^jx|p#T`4P0yUT~ zaRnZa-?;ZH>v}HthomqzQ8jk+E$d?y3RjqyBq=qTE-}(h(jNNQuaDopI2epK=K}gP z$HhSY1}=QNix6~Zl-jpx&G1Tir#{I#(36+`rvu+!jnGqf)6n5UhZyzFM)dTjV(N!%DY6IFc_DKynC{Ak|ryetp25bZb z4^(yw+mx_OH%Ha8+9u8tYu^G)b|5eBgECx<;8!_9`8US=Se%ZPDh&*N<-Iilg=)&g zwdUjoke!ieohi0{3SnVCFGla5C*Z%tkW8d-stFciHuG+C6{#&(6x%}TPsZ%e`clTmt= zlg2AMg}%c@lR6DrHt(Y6{1~r%n&7a{g#W5O8pz!N?Ew_KceIxJVJTdh+L2mdpu%?o z#o?gHJE#babxqjdZA}}Tb0^x_8E?!}@0Oyhmc|(MeZIx{cpLlhHs5&#D{j*cKG8Jr zK0o886jxPhPO8lGN|ZXl?6+_3rmEr$6O!W54?t}7~HB`KirLyOLd->Akg~^vTT^--OH2ozgsSr!xSUWLELXYWCbJ;%<3L`O8~V z6aZOpl zI@q@?57c71YoB<}rscAyfLaJ!LP{PVMqvcO#Eqhkd2i8&z@V5>v7bRv6PMKwfqnKg zf?Syn^!#6n(9Z}nypbL@V-!@I)%@JV($mNCn5SMTeAJFMauki^NU!9m0uoGe2Tb+c z|9uDrabbT~0evy}!Zgd0zPcg#(Wd&1*f*p3A=lN1Eaf4(ZPauKe3QthR_tlYggh4f zXNXF}A-I0ZGp($piy$$DLau;)qPzW%7r}5Tcl&*B8r=A3U(D_IVgf_B@pSFAygfo| zRU{3GsF^;o{vIAbGIHH96y=y->XZ9CT%9G9%lR>1;U0Q^lE*CQ@bTTAslv}s%mB)+ z<5MPX!1~nHrFUi=2XoSlO99+w+!FKoO0@`7&SlQYDH_kL-aR1o!tJSH)x|eqW`8qV zXAe$J&cGSBmVW=v_D6>gCnuX z5?sS!-bjPU;7uAuhC0$PitvSN6YNbm0hxh{@WWO3{=cR%bZj1$$?F1F8*1l2qO6-v z!|F5WM_}Z&33>BB->vDNBU2Db*Or9``QnxrGI_+12lCyY(zBRG7 zyuOaoG+jqI8rkKn^CCIYC(Ln!^_D67#%E3@FiWzZV7}l7K1CFyXD(qgXnn7BKIxvR z`)hW4QxMVKdZq>}^+n9GuHt8h`_CMySiJY`%Z~Pu?Sr(;-fE#-bH@d$uu*9j{lWHZV+u{QZqCNOfW%Mc_oMGTCYr zg;+5OTV_83y$FS)fmz<|`f&r%v5Q&`Mldg_egw+G_b&MkL(K+Yhf!(2)(xj#%0F() zp<<@z{F)Ce6o&Vb;&`d;JbvwjIGa`|aMK{Wu(b#bl?*h{8G#4Cr#-9gWNLrAI=H*mCE=gZ&AXtr6uHKhrIo+kKaAeXbbR_M zB;Tw;KITV++%HdiI`$j;PeB<6ORcK&u2<%B-@|M7kGz=HWOKcRNv%(-=-f3uve(T^ z3K|eP0~eUD`i~wewInqj`)b6Vn)GjUSo?7ioG|>)Xdgd5Lxg!ce^cjG3lj;eF#8yV z@}T~MW$Z5DA5-2wq!CUJM-Fxg^3%P58SB}%?;pgMBm2b3X1!*_6C-OB#7^zsu(mWm zuG@Siy_z>F#c)&cuZ_+*3Q=A;Xr^O8kFn`0;oh3LDQ*_8W8uAbjxSEm1Y~1#aJU6I znvSpKBJ^^`57uBzp(+ouyTCULm+94x1?57YeC-w{<)<}0R8z&8)-J8mG`mt6vpGw=pjG7Pb5T>xQMyH{A`r|Rlh0VXDec5Wmp zKJmt8{Macz5%Ngfyy%W4BXXp+HXdvLE(Nm^+8n>di65iX{Fs*746!7jo`j|9>4b#>r5JD!98Cnkp5}&> zHl3eP(D4cX8K!05`+B6!n^13qtAeMgld}Z9w{>{T;&|B(P5SLP^{ehULPnoY_P!Vg10+Zj!@e-V7@C@nR$H-w}N`JrVV^K@-K8|-zk3z6RM?2b#fWxaiCQ+Je zdRwjJ)f(LFMvqRNgEMYz{eycY-HGQwCY?+m^q&%!sg*gYzhvz2wBGH=4e0y27i|=Z z(B_%3wMc~>`6*cdz3hz{qQ38lD&L$@m+)%gX0Kc+buBh$xY@y1<|qs~14>EWgqZ0Q zdx5;2Bxl&4F69E;8+?=ad@XTT?3PAMku4XVg}8GaJ>{b4*@blUIWB7qP#74t5%@Wm z1(###TLSX^$Xj<;1@Rqg<2{$g)=+ZGxUEnyBTF)T4h}0p>xfHZ~wi14w?T#Jvn1}`cR z|EbikUUrq0k^LUdIa-L4O`<0vj1h7N;740 zBn{LRQ!i&lV!NZnlpwvCsX=60F=LS+?fMfG*E>VGTU)XycEOmb85TML+>R$rJ3#M; zKcy$fOZs(-s7oXrG7M2C`;hmN7Fs{`liZL%$#)Eegr4^QPayk*Y?00Ve-Gq4jn}xa?3xWChKUw;(pXIUpO;|Ea z^YkVl>`QR(?c&h%LI1SRrGJ)0_N<$)Po20oqwQ2 z@=C&?=*HdQbSYBJ$tT`9rpyQI-4QWa$=g<@r)KL zazgTpM!4GkBv*Nd?0i9ss44S4-!)cv+~EFjVd6rHJ9N0#bux&m60>h!Y{wkcfdCP^ z+)XS!#sG%03C$Y<8RgSE)DU9<`MT8AY_4&aJ^wFGs&%yQ+Ly;}m^tO3oBp(?&p8sU zL;m~(SSPv>a>W#i6hHw$YvAZX%aEIXZ%(%#P@`H{s;5$2SF~|S0Q}cQd zg<=i+bL@ZH?UoD~4<~yeg6}j6!zBof9vRbI0vEGi!C?>+CpV($8-8YcXyImTPQ}7C zvF!EGTiT1A9?%e++RQmr{K#v(#e{UPS7(&tXbk@7A^Nx5vobpeP&iMImqI@D{SFJ+ zn#J^n&EA)*VU_(Jel{Gle@!A_Iee%^mwpw9opk4l2u?L}-f@hD>s6SgpIGWo2c_>3 zyTEP~;h~Lr9+Q=k zLGN86nXvA$^tlPR57&tM?RL3a$oa`~&Uj+TC6jb@NWFfHp>pI$Ft650iG(omRh%}h0&3wYe&wG1xc0!{3 z7o7cS?go2Kc3RZUc5tD`yb#V-TT8J>8Mt)x;lZWv?INPXf=+EoP7(o~lb0z#Wt0>p zDwU@wHWglU<@^^0O#EQQ*j*7vEHz}<;gx9#*Nk%4HWtNxvfWM>@TGp9UEBWt-?{Ks z61VTLiv}j&XryU8^qqx2oQjpl4yyJs~p4Y0`V^v8* ztSA2)SFRpK!*w|U`V#g!GGid?*Sa;nnIA#r#ekaJtMxQ{Knf05Rq;A9@6z)E^UE{Z zo*s6Jo)|?ubgTg|JYny?;WfO!f^(3Hka)2qG)j0z+sWpB3%quy>b{~6NoVb@PhOLS zEuIX^Sb%ShS%xvuehxjRilZ`RMF#FC=9jz)&YFEf{~GMFwTf&p;$Nmkh7`(EgjP73 z-_)J5{S&*LtRN%m-`BbH*|d>ele)a5W~xrXN?1%+khp@e@LkA5R1llJQBlBU=BK;0 zrm+}QsEdPs=avZae>VzaG3{BcGZm;*|lUQfoN;6Z&hDXlS+F2hraq9V#a4T%e{7VYaTH}Vrc9DpD?G6A_>T==2`Q^C0h=gtDvG+S zu@BX+?44(M;!PC*P!;WtI^g80hzq-!JtB85iZ#w^5Zn#d1HJ@;>~b!Iu!Mo#6LY!0 zTKDy+D~WoYhpgcyFhk&sg<7Q z`^Gllf+JZBH}I0Y_o9lKSUf+}In=`KY_r#!g6_Qk%bxxM!WfHM1!M5fu<;PZ2r&J& z?#LKG_- zpG)8nM#r%O?rk9LzmG6PJm1Nx@3-chX@q1r$)2?Q{smKPg%VhnH|&6jn!eO>gIC`l zc}gto!kPam*kGO<40RUuoKyFr%@f|C{S<I2h!eZB9tjnW_@zN4jcQ8=> z-zyKzRG9)$1tGJ-5lAL`%{$sCtkvIkT4mjUC-@jnjv-_qht*H z3p5sm+D7P!P zwUzmio_)9d8#>e9 zN89`kzExlOhn}26!AZHl=eRx~m!Ns>Hivvwnzg3^DOtS~k(JTtVEmAs=N2g|nJ(IS z;S;EmV=B(OM0IgRcxXu*QN`&aeLuoo@_^dyuJb%Pqz;lRPR?Efu9Tz7kCLyprJ)~a z5X=9kcvR2){~Ne4Drq9YN;5^d^2m^s2Ya?2RRL(5deD=;zRX{em z-5w3E0at+9DK3pc7TUj^LcMcUJJ^MFsbA1JWY=1ZcA40c>f^9D#3X2}lfMGp>$ll0 z<%t3|NREPP=*+V zp43F<13FBiCr~`O`8%QZdBcB8)w&w9AHCzY+Q;qfxV8rr`-2fZ?MAIK3WmSZ8ScSL zs_mG#V9=mWQ?b6C-SSpA7S<}{_&w62%Z?O%J@WSuBvVdi)C14&k#> z;k*N_;^=AM1wF1~H@2vQ#`HSIei{j9Cnz>g&U}9E^WdBF{H&UWZnM%9g+jx4V_WGN z3c!u6>JaJIRFjfx=0j;`3ow7ibx4t|ibAyW3rl^nGUB;>l`pjkXW$^fRJ&Zo=QfnG zUgDBt=pHP1>zBtDzCASDs+k-vj{qu@g|J8damS;Z79e&BUk5MWS-Ag2yNGO;7f#*! zV61oA9|1)cGrwCSZ5qx-uPa(Wd2VCK5AiKq;VZ992%eiq5sisj4_Y=n?p1(FzR3OD zduQ0pjo~L3RIV1Mf!4KU3Uvw_7#-J^B)@(MRb?MgSAtBJkNsyY@SGCd`D%9B##n*9 zn{W5wdLhQ!(09?Y=k|ZzL*=i1iBUvXD^Mb3vNxiI-Jx=a4j+tN$9&}a*L8558F_gIBxdyt4LUFU0EUB3XroM6 z;u`vL*!|IG9^mi|I|A^_pkI};h+M;G^XmF${`GU4j?z95a|i<)S6QknC2NVXb$lX> zPQs;0HT;rY<|5-)PGd=r@q3qRkV@$w0=J6)~)NQ4h8d zaj+#uMixh{zfOSK{g9K6Uo|>o2*)Fu;H1*ub?rVNGTrQf)GTvN$70tt>6%vpcb=Eo z@=`7vu1QFqG1~wIaxNu?&9PO{42{RF8UCY-Y_iL3LDtHsXZD1mq=U{X&lV4kdGiS!Pm>EtM_Z75R75x zT%`+fZC5Qj?qDNz8Z-M}|U;Hi_P>1-hOq0d)+EUjz(jjkr@KovgIWqtf?f5%_vJYysQ?)vE}97Pwm^|YNo-3fB6nszQehsOUUMUtIHZEfus8!~qX!jh z{>YP?=)1M6pBcXH*aZhobg$y*Wk>#z!l&;~@OJ}63s5`$wCUpaPyBqnr-=2k zK&4nK*&JaQ*36>TRs}#Z4yvoXLX$)0N`pPy>4SPi6*4agY}V{~=T0wApy}<=*BYFc zfl49kiCfQo(-pR;Cf5Ep+^E4K??62O6m+8M`N_J!fQ!I#~+-D>2YzR8ivNd>^ao*Yt ziC8iTZ)*N6#1-J4A9Q&VaR`#hG=Oi-IWBC6WyNX%a_LDm6R7X#tZipbZ|FK&W24i> zvGFbR3D@&Vxes5A)dlnCd~7H(_P@7M)}z zTA%91&s7mKfKjth0`L_8+rcNA#mpaSquk`i&{i_x&*wL-mf5NpDnKVGhy~Q~ubxZF zXbcp42{&5^skNfR?(RCS0}xP=!A}4=bo+>2q5q9C=YfMcMHf#=kA`0u1rbpQwX|VD z6bt-9*7U}Hzo0}-SPNh;fWHcI3fdIiLNJik_`^Vyit;V+#r{?qQ#^)bHONICn2B7F zkTlxE$&JpGO=GYNo};?3;UlIk)>;_`geKEKc072>rFmeYtI%)yyY!FgP@!>kNx`9v zgU8TT$2yk>FeO(=l9X#M1{HV85YYpm@5}*C6$$9bm_0Ya1`2So8}kw;v_MX>|M4l% zaT=tjy4~?HXts^#m>~ZD*~f&@@%gwye>!>nC{Uhbpc^;wu|w)JdUoiKw&sR4#AzA@ zM6*^EK*@EUT_l!lcfcjmHsy2HNPTYtnkCWIUSH|%`Fhk>VZac?K21|}UkEn&hHfvv zg12vx@cRia>XN!5c?R2D3x-QOBG`M`4@Kd*K^g&e_R;9>3?oX&9a>>FnG)g~w5}xF1e}Elz?gh{%0DX2B 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 YHF4B%x;gQG^vI?7UiEW2z5xIL08K)+TmS$7 literal 0 HcmV?d00001 diff --git a/public/fonts/PTSansNarrow-Bold.woff2 b/public/fonts/PTSansNarrow-Bold.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..2040bb0de525e89e5eef79fad4a6c6ebcc14e116 GIT binary patch literal 124496 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
  • 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 Baccko literal 0 HcmV?d00001 diff --git a/public/fonts/PTSansNarrow-Regular.woff2 b/public/fonts/PTSansNarrow-Regular.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..af5a3c6bee4986fd04eebb9df73cf848179fb113 GIT binary patch literal 91440 zcmV(}K+wN;Pew8T0RR910c9`%5dZ)H1D3!50c6Sm0RR9100000000000000000000 z0000R>J%K08U|nhg?tDw34;?65DJOz9Eq!c3zkFx5`q3q0X7081C~GpAO+qm2dhyG zf?QiVX_JT1M0R;(II*pa(8wbv;`W(M6%2X}E0Q*g;N@#r;GiotC;YN7Z&}=Q4WKeqRR=^6DMr|3`T*<;0f4A<~r#i;&QW>|!tx`N2#m zl)9B=_WtAY`Sr-dhitkgrSvA}Te8K{WZ1d|n)Ep{>YGJzkPl*d737`2fiF_6`@;9V$BHLrxO$Hqnu=Q($AVp9FtjUWz32d)TDlm2|3(ATK$ zI~5AFLcEP&QY`0(a4#$LWT@KJ0-`u_R&I(g5*kC*ejh|z+*j~X*sxXV>j94KPgv_v z_?wWdLV(RL>JBVAR)7&YG_oSk0d(B_B7{cRq7#ULn221)+xQe0)qNSC&7ch%RH*cxFp|t@pn8F#(u!t0?V%bP({c=w3IUV$iT(c|YS;gfi)Rw!nrTSpJ zJ9y&Rk6(A@VV1OVX#A3hVvR_Kn7mY4(-3Xfr~B<;C{sbVoBee zqWtAE|GD(vE9sJSr3=!PG!l5=fLBPT{GG9P_AN1R(dj0Uf;lmGZ z%FUWS)i=F*QC?C0e^GfYru?Zy{M3mWxdfsR76~lLhK&%k(?YLIl0?cdnuhJB=biff zfm`5SK=+6$Kr+}WHMzW4sQXl+Y6o5<)KCJkC86d(o&ZT8 z1^)cJ>ivVZRPPMT{Jhdu`lWhiU|Z!dUAC`F0Ap!NRkIBwSNfIe?=J=;on%`w??|bo zWyUQPb#7y5p)6NB%a5qI?SyzxQuR+=|6d|FLd%k|?Z(#^9?ks#JeAK<5OWl7nr-E~ zEVa7V#UN0rU^`R#PFzkTv`D+ef3DH6YUOtNo4$*SS8>r2;VCKx3-hYWrzE5TzHWn& zb0K$4or6x=kZ7$&j zfM|k|AZ?B43ay`iem~jySOkL?5e!S+5cA(-Y;DYxZTv`~>j8kVgNL(W%U~{mvSdn? zb&Y@jM3WPsv8}GO_ zGTPzjR$-Xr4O?Y-JBj$0h<&GKYl__XTZuG z)oJ|N+E)Y@0KOqPwluGNPP_L0?U2$8A#rOm%<`^{5t>H=>?GS)%Zp~WNENcc%e9d8 zhXl?J;{VrNy;gM!ML`y^RKUbE_#N!d=%mEj#b)>Fo;v&l-_x2kgu$6WXK(v}BXt?^ zN@)Gz`&XC0mhu5uo3J3U(Wdg_{ax<< zzgPlTfC0Ot0u+p(KmycBAWuF3)g8ZxGP+g zK6fb;Ws}NW*1oD#>zmcxAgUW6+}$K)0Fu3cjv0V+(R+SL+1@!$d++rKc4$~?EAOR_4{AuCsj%6 z4S6=w1n_c)1c(7N;G?Q~bGPeF={cmC@kkEn?>|P)tY2uUyCugAP)4T429zXZ0F6=P zAO4p)J2$k6qaMF<<$AX;v`6oDP89TSaj`N%;akgBDn04jzB03Jg^>>z9)oRv*4dML zWhoV)m|cPnrVS54IR5`vrd8W_uXC{L3WZ=6l_!ZFN%bVvsuoL1k=et%?_Ff!Rb^4D20Nq94J@vR7jao2{@=caHp!@>BC6(oe(wwY z&y8*Hen`V)FdFh<_*}55neDBwwi6%$61Jo$c#I9QWvF_`&*>eG-_16>Oswz=>UB(3 z{?mP#+CSPH+}OE4yOWTT0oZuUl57L<`Qd#3uzi&~$uo~b3Be@L`v0P{{ydnvyZQAF zXS5IpQxXW(*v6$vwq#2#l>awzR>#okahEWK-8f*1L9!(~ng2zc)*=560GiVJg(PgFH5^EGVTJ+5ON!31N35aMBk5JH4}e3n8;y4ADdsUhkUtJoi3 zvIsybM)rd&-Wk0cD8AkiyBCnb0l-Bt5EOij0IUf@uWDfUe8B#g{Xl0|uR@~t0=3G& zSOmZZ5GSqEK0`$ymf8G4b3*Ar5+rv6zyV5c%aj5G`Tz>bQ_#u8Bc)Zb_Cea`13m*N zlhwJSx8EK_JM8pVQ&rY-guy8_HJf|)2FZ98od>jvz3q`Fu>%8)Bg3>AQL*fk3nvn# zY{mb8R}uOX8vxi+6pjSQ5ugn8ZdL+4;DNz&gU{q&D)?%i1@MZIKH~`{xzSH7uQLC! zlCbpHiJT~b%Breim(Rel1B1iu3*QB1R5GDAQUuIH2ur|6jhhOQUdDF7?y??NDbCR? zqEFt))9&J8dZ1rJ1PkW&zn*bgtix zY{x~<4PsA}UbKqOz=1Sb@bs4IIE7ObP^Hy=WWH{ZfpCK> zG8?fzsMdSZwGVDfUs#27=t=OkffVc13@kj$P%(xb-=wK`0c>i(Ye}AO@5%F<+owyu z5E>!CyJ=KT;L)9dyl&vMHqBF)M)W)wxsSq9?e9JWn@|EAzP*BGlnIqc0dQoxN_F0VHyxKNLfp-YY%2@w+ zT#+}-x|ZgQ*moGO8?RX!K~+Gh({H=6Pnu@d+sY1NA}DQ2!fRu~c^7VSYu+?27pD#; zV24Ir=Oe6gdv2sb?GVkAM4Z{^0Ff9(VR2IujbDOw(OUlG1b0*`4ORqK+je6!PykI^ zt^RJPo3xf$wH+ko8PugU=W5Y0fGBvu!9}KF*~G;|TDq+U{~FM|rKW^;5+ktMwm%?9 z0E3f1jj#~UyWx{zP+B0w$dc@ZQw!(*L1g{-Fbil$+>!!n&`^iWp+&+ptdlinaaD>0 zR1bKO)5XxSQv|))6`P|`0cSB;S&L6vl6@#E!-n`~3s_4Z(>ITcQwX?uQ8n1`Vr{jr zE?G&I)P$QROhtndWD);nw#n1(=q2P=+<~Q_;mQjy1uy00EaBvy9cWq&KTxAi7|X%8 z@@TmRPA*B(`(?}hwrKY;=p&v~PRQC(^uU&s(Ff<3E@Wm#UfAhp*y;WFYtt zC3-n%<9^1as3{xad-FwFx4a+PNs|Bdtbg~DkU$D)D5zwqP@|4RkD;~JS&z$@2~%b^ zGG~P~d~9&Q1y|hh#GCE-;ENyr1hJ14snVp&kSW_~`3jtM&UuBdx~5365~a#it5K^? zy#_5>wQ1L>OOIZC`VAN~;<2a3yztF;Km78?v}OMu*n{C{Jei&68L*)3xL!7e+~%m37-q+i_m^^ZFwwMo@w%E1GVYmhE_c5Jqv57G=|R{V-BXXY!`w zdVWyY+TPjQC;h=tI1-B|GC8JL;c7e(L}hM%VR31Bg(IL?Y<8)+`2w+#Os-U^jWs4( zovGee2t~A5;h61R|NiWU&Q8m0Dx6Smg_{P7naWR}551=7$bhAVnQo zLXglW;kOCO)@iPOil^?8K#pPtevucsy01CaN=C!}OIt$P!=KH+*Wgi({!UH60Q!mSCyr)1t0qcSL0rqX*7XUQ08R*7&hPtu%L4oV1h7R63Pgy`C2ri>APaz7p z_Hal+mPEe=$({1~&6G~X_?E|OOHENH0FNmc@GeJHN0%2eNCMV8Dta}SROjR#3G`X; zVEnI4uL2WL83(vm$X2Ms^O!6H%a=5at`!gC-}6v>)Xexl*apVegv9n<3!L;l)3#& zo8@GVLv09QoHMYWEeay4;p#$ z#M1S*9g=`RpT|W2S2(~6U>H#@d?oZLjhvAh(fFg-{t?g%O^ zQT^{|_vY@j!;RM1gYXd%0kLUXK^D@HY%FjjX&_sWMwKNFI8))hKcR@KjaQlmJGow9 zK9eJ~M=?68L?tODCvq{Db3He6J4M$JUem3Xv|T-*yYR_%W3cZMArL_kA|ip%jeT99 z%{*$Cr^68a+ob&e1v!Z2U*TouHC7Hj&_cS?29-5;9yAL0Knv*(PCSVd+2Vzi2DpI_ zZ!ze;?=vqXU14}_fthXKMxHq<9Yne#Wfv+`u#LNk`%K;fbkh>3cvRpcMOJ_hw2*Gr z>X7y-fdtZMX=n)hk*O0hw4nZdlrakmvhP;oD|=mbP>!tejwDbv@+w#rc1ap*R_${g z@v=wsX>A^h)ACk8G#>(owo!B@C0Ma^)a;Xai_`L9M$F%0JHqZ!XT^I~g4D7pk9(&ixt?|5 zroz=lm%4VY+Ix^`tSK~Wsg>F)+Uro=yPk2_14i6y6ptFq*GY%o`uN^AeRA68N?&QN z-u&7^ShQsMzDV-7<3S)$IFzU!ZLW&$O9@ypyV#QtJLrhh9d%e@B#@NSGZ|${mTWn4 zidemGke~ z>5B*TiAf@}$c@rohB5**MwO9M8#OIsXx%QC4CA4hjHWBjY+xISXRDMGswmGdi zlMA^9H|}|8_4M$($a`Fs0O51y3Br6Ntb44J!GjmnN%z5-{Rb6(-@ z)xd7FyPIyg?e2IlqoN4qR2ix?cu*rXp?T9DxelEk>Z<#0?TK1%wLUfA4O^oa>*d-w z{_hRV-Lz0|DO%Ruf0}_Ad=hm33SLwaaU(U-kO|$xR;{g3a!Mf^6&+CWB9>Dg)t#c@ zM6~j>>yysi&NI=y!8Xcns@kaK<~o75ayzOb(;Bfy0tuC^Ns&}((q+ihu2a{IS%Y$) z^1>XMaBw#enkMbJRXf|92<%T_X9Vxqb8Kc3aQM^K_TlG-9BMDst{zDD zw9^8QeUdjs34g+Uyjgl31K)k@Hw6Bs)iT_XX*T&3NN6CjdF8<%ep@;G#eAlU0NU5^ zpvJz5){B55qO+G0SiLZzU|WkGc5jCK!6PN%Xd|DKAb?gjny>-H4V*GL+CFl#5-Fov zfljT1f_w(Z0$1q!N411yd2u**geWYNNy0ky%)Z${p64l|t+UQWlOWAj5O>vTzYh4J zSsjpqN@^xB>(GFz1QZnjkM+G6LT&z=b89iW)rN@TL!ml5RNFi(bG!03aB3{`cPQ~N zrUBd3Xt)$Bfp{E<_Jg!PW3o4s9F*j4BWJAt{LQ6cQ#rq^D+_6>@eaRkzj?tgUoh>R zW_`fC_geNL|NKKhbhn7;X*kjC5=0FpiJBVcxI~|-U~^6R@Qj>itvp9OubP>^*%nUf z5~;T)4l2=wrs^mfLqq9oIB4v=hTis&CJzP>fSvuRweqD1;g^X+$W~?vlmTRdL0N!7 zx*c-)gGM(+qCL6MIrQvBSko?75S;{9*`xfzE{>OCAXPwW(mx=xJUy-6of<;Op zBX8kO!`odyogGu*aF?cci~2hVG!Z1~<%u9UNc>w__dz%0Pdlp4g9hy;Sh!eKz$O zh)8D$G?b@K7+ppB-e)+anQ=y&HFUvF_KbvRLVhSGHyv~f*Lf2CRQ-8;P^#CJ^!KguRTf2U zYjA8@!dIl2z$?9qDZ9f{F?%IuE9I)pPXF;Fgoce+tI44@vyQuZ^R=kFO{{)C=y#OI z_It|M3-(@d^x8)6TkR{U6|O|RcGBdSz6l>DlbI4;Yow#=47XiYWAc`HrfOhnP zBB7^xD}B+ZPpE38N;?Z=e@dK?44gOcz%}76f>Xz#iTjw>`y2!N4wH$&DzOttis+&q zxKeA{iS1vjBBF}8LGWMqQ6$krgF`F4GE9L#N%kvutzEFh5E=M)M0OesL=uU$F~`H7 zKz6c+1d>n3bj#pmqEI|v{s5~6Xqt&_tqWxhfPgEUfkw+ri2-G$EPG98wy$UrjOfYw z44CE{dVx{plKkP$k}XHBJjWb&!bzu`c4nnsbjf8`xK?-brjGxBhBIb6U_6?i}CKFPSQJ19=|y!4jFm zv6T&JyCR9qDn2n@KoCwm!0c2YQE25BhnE>iWC|5lXVCqI&G8;;``^RyTr~|DW{|Pt z?J=PC+;JNQD1eIy@JK+lngSMex)*)mAVI+(uNtB=2I8QIBh4yuRB7Mk88n&yB=`C5 z9C3|oM?%RP<<%NOL<+h!>ZoguOhAMrG)!I=8aOX^?2d(Q`x&r!=bru0A^S7kj|b#e z{_pScfELe?H4$MupxOQR?c5DF*!AsN&j^+E(ZPG6{4-$lf&DR%A=hno6JY+q5)F-Z zoSk6D+r{l9I}s4gUYX>WeE7{gY~6eLBsi^gV(`ODmCPu5%Hj|tLD@~b?dXxT#6?{E zNQhf$Fg7wM2par>@W29Oe0pTqj<(z>1VV)hegDnP*V8G*O{dW7#Y(~ESQDQl8RvD`>5O}#+k?2%}ZDgVlL$GHa ztUfJ{4eg&JumOh}MGRyTAx(mGRhr{ioFX(ET5$QK34K#6r3Z_{p^d8zE+=1e90wXv z_vmD%SYeF{xui^v`#2hc6}7kr?a(CwYv@WN`j|>mdQT;Tlcu!(R8|l;Kb4YD3Q|Oc z0KkZZ1PX)(5-sKT5>#2S6&vhuz!6Wbt2AuXq_;l!?zg{YLKR)A(ov)ml#??#pKGbi zkS2^_fwtfJZNP@KVu(BYev;pQwm<tO<4`pqR#;*c&SsY_c1;>uinZBvM1l%&&{F*)N} zW4rBj0MY!T=x97zLrI)t=ohDv2)q0*s^RzwlMNQnx_#}EjxjNL38zG?oXHl z!4NihG=1#nm7iVH1JloDNVDi3U{6#$!rGElx?|mQ+I)9#SJ%I6Q z%qqfC2m^<2f=E0Iwy6oLg2t<@g{bN<7cXURECn%`{(OUUz<3tNPEdz-1P)%P9x$szRfoPqf~WbafQ4L&3hjsCEywb<)U5~N@zJhc zR+e%smXd-r+^a)>?j^*s>Lu7dqaJ{=PXNwDt@YU2PF@uQfgZl5VUNAO7$1vW`A)+nI@G(VBLJY0F=mw9Ef!rL;S3vIwZDl<1LTqn* z3AhL}a6iQbq7njO{w(hwg9{}nRPo?hzEC^1m2f@O>7b}A7pZ3bIaGUxd_BiJHP$kW z#j1aBl50nZ>1$Ki(0>M!?^6_>6PPR9zZ(?$5*1#@$y-sg0gg@3NDC?^G}LWMBOhy( zl#X0$^%gxE%M}qhjuyRH(AGY6X)~xagVh_{8D=la$o4Auz;9|gl0FrBS^8J8L;mqL zYwTWNs2Kl`LSU7eM-vyVl2xNglTpd*#04zuCgn>3R_g%@16IK8H>>6`>VuChX}!Sj zqQoJ^z3;)Cf#o1-jIrettD z@wu?AZ@_#Dqrb>cKb;<4y{T8wIs!l%I2YoB_0<`Gy-Hh}pd}H-^iiy8xC93k;+RiKwRM7`h5dZ2&MpbQvPEaqeQWuZ{q0vv$~EO@oVCgVsaqeIJKbJEgq8 zTn>j%-*jDTt>qNGzujK)yLjFKAm>tIoR)Q~ui!~O!m~Ub=ArLXnwELyF?}Rq9_8g` z%({H^v@f*+Oz#=Xx!yo2<_^16FH>8?0az?q^`l&}iVT)m=E5}7!o=BI06iQI$4{p= z_%WLE2Rd^Lz&U3=&UeGuzmoj_xTw*Bq9)@49)M70Q>vyHoUQ>J>RCj51u5^iNknGV5o3#@A)Y1MVl}6743D?wE z7Dqc^y06~f4mkvO)^+U4L%@s~Ym-!JW|)Fz%-bNWzQj(Jn{I=jv_+M#OmV{w*+nfHjfWCw*kVJWlmUq(u>lPl zlaVo^$E-jQR=F!QpGQK=DV=R}w9l&|2+i9wbUv!?>S zRkDYBX>>fZV;>F0bG?t8kOoP|(*7@W<65<>QM3pW-6-3-|k=1s?rFijO;z6-%F$(@po&>!Goa zq~9q}NT!gun8yq>&5~TltT(n_69&;aR!w%VnxgCT2{dB4gtAx*U8`R~H%tS|OUgYZ zp36nkqfYBT_3cSoAZ6EJ2OWO-FmAW31u6=??SnU z-N5>yr9bf}8L1{yb>P+F3H`Ur#Rh9gAq|dd5Cq*#I-->%_k*}YOSLn;PvwL-`dUD+H_7z^P!s#rPpuagEW&j({U;j~)N z&IBxrH+9i;Fr2tFE5+h4F@yjVBCnMlrN@OHFqw$I$I zfp|HxZu?N^>bbKk&9oFMp~4sRLs3we>4&0*tgq2vIZ_HU1`f@NlDyd$!V8^9^iB(=2!7*)yINVaK34g0`0|?A9@%zJ7A1J$AJeZD40(b#@YulhATUWZ zb!P&&LGw=A=4f{7Hl;3fX4ULW)oKPH!*D}sGU$b!jH#ARDaKazE1GM<2UefzDEhpT zK!?Uzyfp~s{DNe_vx+E7RgdjOe8!%Joi$~LmfQAo2Wi(NQP&Zb^l~{Dh4?W1Vpb@0 z4WF!5KvbiQhR~Ei{tK17_|@bWrHL)i!PLoSX(?@{hIr^ZEpdl;y?WHqbisVvMp_GH zQ+#W`#;UfXT*`bs={GQeKk1ntqZj3aY-D@)vPKSTZ(b+Wi24X|xh7pnRAi8noE5@V zN75~kmYM_ltxLU`Lu@vDX{wvP$>sF=w}H1en5^CS8OfLHb>3}yhsfppMr-Orctcp5 zJm6y2lZ1c{J{&9zCjmT^_(uAzoo{IBBCbP@ygoS)2HRo+-02_^%2hXneuL4zNmcJB zi;T)GbIyKf54jM(jrecGUt|4foe-)xqL#Znjan=O2a4WHThxhVm@!F4Ai7g8+}21c z*t8UuhZ#-+`wnv;*^gF9D1QJFa8_bulQ-)e`3>l(=^(5jq|p(=f*W+ zy*jcvfEiw6V0RE)lcQ<4=mU#mOHzxSR*v*V18&UQtFD{W!KYBXb$S*ikcRz{o$66NESPH&j zE}SpcFUh#m+MKfbjI$ATR%Bwgep_mZpSPcI?@a!loc@g#1a+pmimx{>o?=UA6m5@z z;36$Tqvkb)X{HHXsHJ|(vzWQ)#C3?i4|3bSR;LF#8z%`-nbH*q>OJP9Z-$o)zdJpU zS$=%>jZe3AtT)bXIrVz6$`V$3(|W5E)y1F{OJk6e<;`NQwIHT}ctoKc6yAAYL3zd( zn~ram$#A~hd}88huW>V1e47%}`t_`jlLEoxAzW|!Xb}hdtousLm)?iqS)VP1jTuX~ z%P|U=FD~aEasd!2*H*=8QadyRfUBa<+hn7?ycb$#49RS`KQp^nx4wGiIdApYHb^5+ z@RRSnJe)xCOaQSc3l=?K2}NNyv?2KNL&x+*&S|Eg@Z>zGa7fb*n+?|mh~kWDp1cod z>;1-fj<1~bnBR>xxe$-xl$?zQj`T9jbal#Kd{RVF-K=vp8^an=p_Pvj04nB}B|U^} z;>nxZt;eH2Na9^gV}?)kS{oxfJ}$8ROdvZaE>QoA2y(dggZQDKDeEz7K|!J@;rxLt zf3!c8k8w1@Kf|&6n45*bG0)3)T*-Akorl=wB?*c`a&%gu4Q(Ji{Me{kykS5Sj#_i( z!Q!3`RsF=B%~)9?MA(+L#lWuGt`P%i81YTJh%Qgfz)lV}^~FCLNkBZ}8vb|FE)>*o zHl&Sy!5PePEiNQ5?->)>EwiTAgdS=%gb4R1ARMEY=yHU1Xm*Z^k&?jvtiprJiR_G$se!cLwb-6u}}}TYZzj%mC!NIW-HICZUDt`%0erHgQdUj*m-H}7aO;~EsG`KYdN_uW1O zD=x60dQ}g7TDP0Fdm)+dM~!RbG3gc7`ly~!rjLvGndL1+0I$h*El~klM3|y#J~dL& zGm>^Q38pCAK+6CYr{Ol`tr%e;o(SuOC7Y8SOBW3d!}!Hqg?tWT7yU}gifBr|Fh(Ko z+(rpOw!VtTnWkw>X5d_!wYD^D-o&lM2=|6Bd5RT9Wn^)SzmdD?}Y8{EcpQ7uK(j>@h7w{4{gMJiMA1V{5IZ~0QW z&-h;X^mgt^NF)K8_G~2W8e`HjO=IGmX9Jbyl!`%rwxhExhQ0URAq}_f6G)E+V74rM*zCV=m1dRkOcXx?mHBe{iHcsFhQ*=iyZ-OGx;3LRQc zVNqx-5HO|Z_4K;Ibe=#st3}T!v=S_1#lPaYkB@A8k2ttcL^%{QAP(bSU~eA2gX(;) zB<P{sOE7fM`cqdGt&l~etR=@MfASEBT z-y&l0Ub}XT_LJI=oZvQbGuzdLmfOo0F*RZAZ zu(2k0ceX=Qk8B|>+tIxO08ZnAU!C?lJK_qH-jl9H{XHp(NX|y|=k_k|9Y#n`F%qTI zDh?v@!omEU>z(E@!$@S`ppS9(Zy4?zsz!|k+Lvp=&w>p`$UP-8DyQ}8kQKIhqJ{4# z2*i9OUF_(-8y?hSV~N?mJvUp40qe{-6){|WqhVithKdh3$)_tf9I1zrekQ#8bm_QA zG2}GjgB7%;EcmMlob!@SpyUPai>rwYI36prhWIBgBnn+2LL@JTIENw?Jr$8>k|bf< zNuo59M6RibCVQ=$t^J|8Q7qJ2qmgjdk+vBoxMOltEk|~>#aNhd$Rcu)hRr3Wx!GM5 zE;wL|(y@`hamh;iERovG#^Te?)r_6RV!aNDEXvoC-`05_{wCGWp5@EqGtd?PlV7xlB2su|k} zT1_`Jgx7G6zV)ey5KKIbqL!~ewbcT!ypduUh43!wg58$D3N5h=JwB>WsYAIHEM50aNo+bT ztEdw4+|8y=&vdenaS|f97B++Jdi_pG81;W(BDuj#7kOj_+W!Ing=B?&RDI=Td&vkl z{%27oWGq+eubWTi<>e_0W|qJH(AG!>dlLmvxUf{L7MP1)3o~>gd4&y&q_ajNP^a>4 zFVf2bVwkp^o zziDHcBMNgR&8jkbJ`G%b@0JZ2r)U}7lyBoO{NIdGTwsdDp!n6KXFX|3@D>iATo#;t zEv4DNF<|xM{HQvy_>%>}tO)`Fq8;aXPO|UvLA$a;O>Q-bTiwyrpzNije*|_EiuaeS zi~ZI1GO&3!yK6_Zsf6KeC;M+PgagZ#oCE*6R0uz?G^`tcmIeJYU$b*uigo8ioh&F* zB2N~#&IPlq6noK-^tQnkMbhSHd`*j)RZb5j##QV%md~eFIo?rXU7b0eRmpe`uM&ER zoZ=}d`eo}YDA6>q)N5;0GQ%N9k45?pH8n6^Zj>bc1Yvd?#HF-<>GF$0nNYUd|L?r+ z+5a6;`0tT+8V{%;fZ}vH3&iNH#V)w`rP~!M_o~_DV4>7ZL#b!x%7FCR+ZgPuVz0Ze z>>2wq?#5qvei;99OAh^aHFO0*;Q!(uC+}!=A^xdVzaIOC<>(Q#*nWlGl9a9m2~kt? z;}Lglg)EG=qmS2|p-=n-=Z|OvO+%WlLn&?pY#`=1@N=b^F^EiQSix_^W0N*O8Bqa5 zSiIa0v(Y=_I&NBUJKV;OjXpuLEz?5VUp&R@P;2^Uua9#fIKL}Rh#<6rZOe9;jZ`RO z)enj%-os$`69P&b7S5=G*jSE&Ki+CCNWMgN{CKIj{eDj8u#%SU*U&!`1CoV4`g7dB zkO3p=8juUl(5_*kzel!-sT}mz$^-=%e*xlxbL-=!Q*eg;rOWE7F;@}lxCC_^v6ga} zKsZdHI;-a8y?vQY->0MRGhES;hICi7)GfNf$fiM^?ujP<4O;sogT7DCeeEX=`KKbj zh^;UogLv~lvwW20UuRAenN0acc#*E4T-|^-MsN8I){85fD+FzoCS*`2-ja4mE`1Uu z?_2nuAzu6!H2h=X7@uHkLa$a(T|(luJNKBZuRpnn7o`?7TtV13@QHN)x^+gnv1wam z-}EmoDNVN+2Q%qB3z1220#QvOfCnHCn$wQFVKC*)&k`}gh)wJ7&;&ot|DHgpqfrL` z51X)$Srb1M(N8@omCvNNBRkX6kR9|+<(%xxzYC@lXToPFq_Hzevjojo=BAvzB4{Sf zik&G{z-JI=3a7umoUNQg??iT_r6W7(?TVS1A2yy#{d&T3y0)-EsNfYg$`4q%Z!8~G zC%qFZ#H9TE|HG)P*-N%qwk$Ejr*@S(@fv{?BVmT`fB&}ce9aGY<5J0=B^$o7enn^+ z^i|7hg;+UplwaPHM-$N2P-G$GKUBXxf`Ku@f(`huTwbWTJ>T9-|S=4zyKZQM{x6dHhr7D^q zv{Cu&Ck+to*!|!G@WG#~=xeFRgL_`Yx`$ES&F8XeX1=T%vz@z|kQq|6E2N4@%Pq81 z1=dw`;wfr|Ejz>s+|~{Q5S}}}=5{C}`;w6^$SLXQX%Oypv{iyb8CM)>X_=hLy2}?N zV4&LGyt;u~dX$m~54pNuN|B^zLfcC(d8L29wdRuF?%0*F)2s^S>KPlqX8Cf0PHR?< zGeea3z1M&B@1)$q8Xxb>*3!*4Z}I&?h0G%5Ez;BJcS|BbG}|Ifi)7+L{A%&!e}=VF z6OwQ1^4s!rio1GS1p6E_D}hbIQeyo&WR#mHWE}XM9BpovG#T?f zuT2}i`>wbbFH}42PR6|Spi3#DnnOHo$FVeRk`q^|knCZ^{qcHi?Npoli}Pt;IB%a9 z+&=Gp7kN$lAfXPH&;Y4#qL4cJZh{Dvv}z!{;$Bu%3d@Y}GmK}k zQ!u|vKsJZ?SmiTlc9iUdS80+lDc^4*kXG&d14=0)4Y<(4)B>I{z+PNl#b0dB z%}+{^{#1`PtBcs|=P4HQbl8BFsWJXj9{=`Cgm!pvT@D+G&dfkK{CYD6@k&FV%D`+vEGIz4+`$uhr^c(peH;x9G9 z%&u{l5~loku6xIv8;gfZ&sOG`;x9ai*i!k7slhR4Z(f5MyW{#7i>A(F|nCTMA3n%`2{o3j|7 zw^r&z8C}j6Z3bWk(^Pg9cGoT_S6wW&;Kk`ym4?^xp(XhvoG-r(YFKzZQES6xo`8)wTJ2^0ceS$S`E% zv@0pw&ikeYFIVo*D{T5vt)BU#|7h09hWz$_nmt|rK*iD}r0fog~h?J&@2#oc|kJ3UK(AgfdNU;b1PWN3Cy7QK?F51hMwfb4=1_PoU^I zhZUjOd9r`QpPd%^ygdth%ldPv__XVw9sfi~O;wjxiQ%?N7a7FlKpxf1ISzs##ljI= zu%+7G;9!8#e1_!Gp}E*85z>0|9h+=^M!g?uE3xvEQ?21n$UAOAM=4451EjSDRKgpS zOzBPzw+^Tq0Y`LC=itk8i?Zdvsy*qDvQBKyN(%ckk>_)DFX*f2FHbR}H{0beQWU!4 z8exoWwwug7y&iIFq&5a9WB0AC1;@d^!ZLP(72E5 zFMN;T{;UatE0Y9#aNrG!BIH~wD%zm|m8}cHUczou|%SdaL9n=HMCEV)^>!81; zG8fAv;TwjVY(%*+TE-*^BNQHQPqRQ6=l#Osxq;$9-@u|^PwuxrXTKP3@9(B46~%QT zI2cBxPzE7C^@L(?xC)S&>7BE{kXV&svv7n|ym~r_OlPg)WTRF8@%WRF_r?W9(IKGI#7Cgi=o^z6=}xltH+NL&&q`f12qs3?toGTUyC?pP&kvM#Wdf+1w1#PKL68{>6gkpbnm3Dk* z6VN0S+lbhUkP#oVB?{;h!tlz-Dx`Rl!6)zlr_h%2mpFOIp3t z)Dfq?t9|q5?<``$OY9u_ZTWxf=O8 z9Z^rCuq9X7-N@5fns^?!pjl&8a|-^;rORaj`hP*FEeca6&xO~u%rDgcGA#Ch)8o!I z(2JG?_)!S1q2*bA=mY)eb*~FA2h?!&WzXJ%N45~QFd4=}l z+zjK4_bME=5SlyzOZ@uR%nkYeoVC9ZANRgR`!?qL^VYF;u@~fh0(9aT2K@@{->cZ! z7qcjm6d&ayR<;V@_avue_2ZpbtHsW<(G-)Gs$kLn4cVUarh|==rOR-@!<$Is#qbQbWUcm^C zNli{L@?Vk3FS!YTRGI*AU*2uHF$G{!Q1yQ=WwVyPuSdnzzh4RwZp0>j9p|($-=DMY zSGjo@*_%ePp1D`1Qrby^Ec}AiP}25acf1qQ|M~OEF>g8zrR&TG-$g$E`Vkzf%unaEtlks@}#}nG;#!i~zmA7+Km^zHNS`qH#D5Rp$y>G^@av(=zR^q|Leh zHb*lDg)~G8WP(}~jf@3$edeA>tjzY=nSHxvGMQ7>KZu0ou5tS!Atkk- zBPr>Jpw{({!jf?5i%Je<( z@h;?DeSmF>FHWZp+v##;ZrkWt^68Jl34%fP3(L^1pwbo_)GCUZo>v#Z?;u zl-V-SMCVDZNg@ljOp`$JMIv$=iF=G&oPhsLK>WsC(ZBWY8e;fDXqgT^3N*}e z&4SUV)Sxk-TxOWrg)$5cE`Vh~F=6dSGidJ9^mX9A0+0@-=#7w9;Jc)43n0yxpyUlD z>&BK~xc>{-;7f#vY@YxpQHCwCsTHYnrxmu-9GT14 zYU1mYGCvU!CjNCOTUpwGJgtN@;6E|@qZUr&fMPrktq=QzWT(I9!EJ*xD79aGN76cv zQuq5TVW7MyuyAf~@nAq<5vQlxQe>2AczczTupwZW)L6)Ko~>zh6NGYmO8aJs%HF@@ zI~Qszu}>{UqvJVLG~?>AH@nmce-!}U*O{IcJH|8hf!wE=PG!D8i{~cKaIJq8LQ-YZ zMN=i_k5jl)wH|3hK+M6Qv-HwtJ+~LnBH)DAAI7dEqgAPcdRDSs6eg}rCy=FuAL-@l zY5uYy8fqPNCw~9I!wI~bky5+*qPgOsK|yHsLyDaK2uWV2qr@Bg%JJUW`rS7hU_WWZyaY=@j5RIkL?J-{EAv55K zHpPH)yO!MG&=@$hnKfWJ0I48Q1Pzs&40&MN6L$Vd108rD!v-|h&Lwe+Pg-a|O!8sU zeOht#&OcPj!7sgu-rx5SQ*6NDOpVT79fg|t!gE~C_bL1vT<-Wk1QjYiiAc1eP^r-G z_L$*#2BO67|9MFS&uZ2z-MImc>S}T!V)%!vyRGr4&gMcyY~i&nd1Kc2j2XOjy{`D8 z8N%;kRWI&jU)h;dYs9s$M7M-tXF-$L1EmtJpt5^8hpSggn4d$GEJJ&7ODU<>XWcmi-@Hu} z^V`ux)My)C_8xznG~g*U{T2Wq>l4hvAvWXSV_GoG{JV7`d_m=cEOs^p3JX;v;ybX| zdOW@ki*28V!`EZ69e8{@7F#E?xyD_PaYO62sGdY535+8%s2Ol`YW&+n35BSkn3m8a zS^Vb_bUv6ckCCO<(egI>$coqyQ}CoyGwj3Y93Gzt1gMlK851LgD)M}=Y}dFe36|ta zlCoO*V${L7E~ZDPrRS{8BFbaqP1O@l?d}$=7PNVV77v^p1pr}Es0MH6E<=CkwUd+C z^Sg1*^gmqRyPnHA08#N3Im`IIj{k0RjqgHKro;_zGK^(de|~U#5F>OXG}FCWEiF*v zA|<1Y71dumwYxvVs?1im)M<#JM4_1z(r;Q?zdiYPF?nlrZ)$AsK&&A3ytsF+9I4c--RW|N|c4MaDNiC^#S~YLXZxw;MEd0{z z|2iijKO(NEw$iigJkH7}jp?A065o~nvnH1DbpOprFUSb*x$Q&qjMNkpsm}F5-KxUa z(7u4H;O1OVC)R;ZYNNtxWAS6;tE*h|vtng?4z_$4Yh-O|k)k{oj@=oK!S)O_1&Vahmy-Gyy%5hiQ?`^I&XGh=Iq=P7B8xxgw*SJfpx0A(;mo()|>_Zd28%%~=S;eRhsY0Vy=IGy<)1(h_Dt%6hy zEr&RqWU^AX+21*U+vRY@XLAPMh9{QwxVbCc!4qzbFs*=V$Yn3CsN^lN<_5WG0u!!Em`jm~T}aLA{O|oXup&>-^sVqDh{>jihkdD}r&62H z<1nYINV``;w(4!$CZx`+Ssg>c!5oQ+C3fQ5as#LilHd2=(8L<*%W&&9^=V6A0^5!A zXkzyYVr^@tk(G+_+H6soT%#(5M%BNc03wooR;`}R0LsGu=~Q@&tVOK5!*=bfomj>9 zDV({fW=A?|i*-DnXO<98e7XSw`NR80z{#I$_RW>Y&gCQK%05jgbYkjI8$;@sMl}61 zTS$@B$SO?HjmMupo&MC<`R3?g zcYW-!aQMK;q^7%Z!}{T_+s{ZBpnv>J*wfDtww~_AgMn@zVd6{MSGUXI{4*Vx66?a8 zMc(M)Szp*{2H_*S2U-}2irdBF;Fm*i>aPAUnG|JVeQ|OlG*=|ZMzTq8WbX)VoO)5? z#HvL5(``8RiH~1{li=--I3nuvS1~#VA8G1jK33652$ywC)x+m_+?IX2-FW+Rgu$nB z$*>f8`;MM%iWja+`;%T2@Res&kK_Y8zL;;kmnhAaN=zv`A5tNY7qmv*Uogv8qOP6< zu^<@`?}t%R`F{3UuGBn$W(z+LlJ>#2rRORczr9;j24F;mIei2DW%Khr7YsrTaeBo5 zeb9_{c)qJ6yv6gX?|*%JBd29G`wHBPx(9vpPK9ek+p0^bGC^UzDB5lola-P(C=)+) zrRwwC;=>aQ)6MF_vdkQM-QaKF|7X^$hU+sG$*X>Yt|*7*0aajCucmitn8|T5GxU9& zRjH^30uDHUKmIzE^N*KdlCzulq=QrdDljY|lv&U$sg09t#+7O2)eYuz8(qoj$3&Gr zGa~Dh{uCPV^J6CY*T+yUZYcr8VnG7VfyFxNu#XIRzch})yGSX5?u-~z!HCd?34yJK z*C!DE<-ua)tvh;!EMB-qH8~B5Qcd;iBTDVjts}QU$Z<#lhUeWVFeJqyXU|=$8pvW- zS(7!B;PC^;!O7MbH-aDP+v;3(`+$8tQh9j`oDU|D8Zl6FJd?n$Z?sfNwb1) z(c+<$B{=WF`J9E%6BMV21CT2Y6o;WjXNzkMerPf zk*sEN=)*kMxc024hD54&Oz*PkrGz8m9_bWzZfR*?N=bpb_!mP(k!XG?b>B68P5E)< zqEeEKHSH2)C@v0l;!AZY^s$89+Qpdxdp`Wj6!*ivj@3%d8Q2_kH6Y=Mgo-Chty3h~ z7&2Xcg^u`qewH6ge=N;e*!u0?M+`@dE@P%4Qzx&G4e#5$M6=`>_{^fQJpFm)kZW9S z{T91=hmdvm4@!}JNpM~%sU^$0vlpMPC@oRMn;+~Tk(2lQ)DKSn4D36-Iz&kCA13Bo z`m;NWNi9BLr4O%4DJ+noOsC3-vY9HVckfXWJOJC?y;bP*y4MU~zzKbnSi97t+ z(L{*|PN~R;j7}?-D$VU7;Bbyn0|nig1v@l-O_M+ePMgK;SAS%lx;j=Sulbbb9Rf89&`JSB9fW187zF4dKuZyrtyjEIfv zFIY>yF!L-f^)x6S7Xk#pK(D4ZanVKe^dTVvpvwaElQXL-zUp`SEGT$8TGHM>b)R)y zVD3vU2J@przr+HRF`~V4)Ar{%N?T=K$Tj8dR86XSaY+5oe_toeSJ<+GHQR-(H-C_e z?2C(gOGz_))|I`4G(~Ap5pRCDBa!SKfDp655y<=3Xn(FoY0(FECkD&|*_}aBxer*` zf>%jPa;0&=>2f0Z+$_kBJl~nObiF>YG1&`<1<_?Q`=^n-s6y$s`t3O-1*;e6F%8T- ziE)*0XN27KADX7Zgrrj4HNC!61_YUdIVZbD=TNITvED?md6jno&4a1bB*Qa1%c&_q z*VM^}=juW~7oxy7Kha}ys`v8hEGeh})3jd10}@dlF+a|+IhLdrW2$drsEId!n|+j0 zT)wEMCx2mKh*4zBth_iWX>rr$#4JP;u0RpMRO?ZabR|q;e+ug0d51JLK55Ny9AcMtQ zb5)W@qpN^9+%WI;Oi}R%Ge~CL=lb(cONPD-(e?DUBi4TFQaNQeX8u4YD#}N?02wfC z=H7#8PT_c3#eo#%Qu)av(WB_35JWB7h|RCI9Rdg7@Xk$mTPn=;yXn~NzKrgHQ_m8D zO?|X$U0VjEzwda2(l39-0rCyt2Z`y|E0_byKK6~aH?(0Gt>=`plu&f_k9LVk!7&mQ zj-&2u9y=wO-PetCWV~PZy*^^V-y7gO_LPjcNQ$O;Tf<8!)*}S!gQM1GXA)2WI^jh4 z#Tf@1YO7W)Byn|C6P1kOBf)P&*iP#r*g@z-+nny_Aro5+;EH2nv^^2wO+QNcEE3w%yWru;pEC zu`>3qf;&MG^Cy0wwmM{ki-os z;jZlS9Mrn=P^IIdU-k6ajt3CE%Jc4TzYe(<{p2E6Lc4x1jwf3OE+jdhufVZCJ@gWs zbj8ksAzGad@DkX@ksAOt8IBnfPxY|D8z;PHh!2+e|cCoB-vF3Sm1O3qs~k zM$YqeXD3-m;*u3UiXtPIpAn!eE<4&ZK3n1D$sLIeCNkd(5oCAzodjVpcS+Y^QLm3O z|0N~ch-PC#5T?quP)yG{>LjVzp_ymHwkdO<%~D|bLU!}%bhFE6vU<&K8+p~&!sv6> zEb6x3o`rSuOo@=JEm=j&?#QCb_*v-Y1dG;^0IgZIg7SvTWrAj_E`v1dl`C}zz@zs3 zbQN~{Rl^K|HCaXT=Q}7O_IN|4kPKZjvngbiifVh3nM^F3Eelp=wX}ZgV_T2Q=c^}v z2KLPiZ>7ODG@?f=Cpsa^B|ZMI_;je;f=%~j<-Qu5-x&=MKY6EsQf+(cNj`3wE5`u` zK8@8CB-;PeFX{BH_XW?_{e1i4V6$VfZ}68X3eydb>)m6?u-HLR&oW}+O&)h*YH@RQ zqf4LL7{1ZJ^h9DZ#V9Z*a3vnBB(vxiRrQ&cO1@d8_{@hw0g&shm#TLhE=ER6hKoeI zgt^(7Rz>~wa4C&I59;(O#)Rbs@Rzh4cl_1dBPgy8x>`%NntAZsZ*zHVwzyb&EQ6L2 zYo4Ew7%{7{MIY_Aq6zys4B)6k9sy9&8ljF@ryysaDB&bj2fET^83K;WwyGb3w=wEy z`->=N9HogyAo8oA5eBPJ;$c5^|Cti!X*E-orV2qy_w^&Nvz}0YbzxKK?84|1clHg& zT2$5cx5T8TWt(g!&?-?y6a)Fzd|CG7*$q{+RfLUL z;!PF<3S2YL3||DNZEV4%(M0s$Yt`HKf_t~AYk@l9rd5dUl-P?aHziZ+cC6aCrR96{T$14B*B0T8~+4wFe)L(RZV|R^UrYqw`CHy`Eaku8MiJxjwcWk+^v@f>oe{!d_Bf6xgUJVLX(4CrPgq&%#IR)T3;dpoXkq% z4ED+&asr!IKKkx|2K8w;#sXB&Ze5>IKrz^uv-79Zx20EmQc}EG)g=IFPHI7>Qf{PR zI2K%mfw(0bOXQ_cs}bG0*HsW@WowkdHL!KSHGO)?gxosQ`eDi08^?>+v}E@FY{+QA z_%2Jn_^kC7WCczDb6e`%&ak~vkblB9ED5+mIjKm zs!i0eme}L#B?Mv@o?7f*o3g3_wPBpXI`Jfx-LBS)~DL&8JxAfZ2Ju6uEzDJyhn0A!4<%8Mc$)1 z=kSH05DOc~*tGt``9^}>p4;SZ^gklmwYNIBJn?nI&t6@!C_5v$0Y0lnUR{kdy?p&j zX2fp^>!9M!kx18Zgli+0HvE4!%A( zgv$r!Vxz3W;LialgC^yY8TQ8cF|vc_2D^#GQVUVUlC`!Y(0F_*i_8PlM2MyRRM6KJ z%)9yHS1BG$zOiI1XVdIqjj_-JAGZH;PUjF;9?aiNCe5G7+T_Z>&nW5~a^ zaQH=Au|eP;srbiNz|H^u0?aMLRTe}}Wc%VXi$EGD{qE%xWe>dv}kh~?2tce z&vd1}Ynzw^M>elZrG{6ZQsT;S$iRfg#-76r3JhyuLPXKroqKVlJCiDQCXjjO+ir)Z zg3S0`YplC1Oc5IYvE#xe9QTD9vW*&}{Ohl&dwvJ$lPm?sz;Up3MkGSd_eHh;5dhSX zRsthH0?;VF0Dva(GEE!{5gA4V(m0iB&ipB(-i=E)0h4yZ$*7vS<0`^$DCLs|IOa3` zEJTTjK0qIJn}MJ*LbJHq^%Cmkh=BSKHPmK;-ALOnS(zu-*8!bf2Y#iAh=Di6OB%2f z*=anYhRWOs>FNaDPd#`YYrWuhUPSZ4!_LnUe9wnzG$Ttjuu?S!B_V%UX*#udL3Qw( z>fjO8!INgt8KcGUylZ0EO}hJuTG=9aa;Tn+Z&5JQj2ba&VnkPBEP_Xdh|zmy6_O0g zpTL%mZx=Vc0`;m!>+`?8$lT+#y*QH(#z(>+6X{tU2UHY0s3bk z03I=C5@;5e(U#u9#qC&udhJ7)s?Q^9#cQ;s8@RabD^M>U0CnbD9&8As$VfG#p7yMa zqOx-?sBRe=WbLW(E|o)Tc1%sEgBh^`^~$}@xw(Fos-vRcinuh$ulop`RxdH?DQ0^V zRRR}bt8x`+xZ3M1%k>*g3$UcO1y8S|7c`+TsO?~-oeI^)ShIWMCez^zkLu?ROotfE zbZhy=Q|WfaOTx+9_nSk+RMI2zj(l=tA;t6p=BndVl^dL01KTr@N6Oiml71pXezlz& z0SW8G;H+~(?jIuQx3ekrMDy1$HlixQPYu5c_@`p2ZaUMSd8t zIXQ>t7U21vAVLDfY+%PhfeeXC)?0syW%CbGXK|c0S=M*cs70RgxwzD4?(gZ#u^ffX zkcVwn_hBkKQIt||x*y+&bKWyuqL!nYL5P^CQQQ)z@Qc|}+cg1R7%+#0?K`$`>FY$j+&<{=JE{i z-Sst;Hnr!eg{`9}Le%uXSpRI@Wraifn;p19AeA{zmN2=Fz!4~rcCb(2x;j&35Oepe zc$X8bNl}_}W1D8C2`K!w6F)MqzO?d{x?I?>YiQWosV^mf>Fug{%!x_mvWGoSjZBnNzFodj zw3Lzcn(CBhQfIJ1w_eM^TlTb_K`xLTBIBqt|YK40DB zy~K-F{~u`iE86sJpa2e@QCRr+@uvHtiVH_9%rxI1{4hi zy0Qt1Erab^BU7~#G{-KYb`&1M3{K%W0Pjix1d0Ttv3965$;b)@Zr%0_F)e|Tk84dw zr(BJli(>l=wVr|XLWgx;OTm@Wsrm)PidmXmL579&U5~#;2I#)86!#gDNT0UdP7|IQ zy0C7rbMMAG7jLx0iOog4cKHzsWu>`R05UCJ(MICYzXY-u zrOc9gor(Wy>c>s?02cTra71k7jxsO5Mv1F;k4t!a4(dzVye44Xn(0WX7Ukgh$oF<| zSzo3piX@S&F@DPprce%Kq{!)lkC;`ewX9tWfZo_zb85@o#V+SW0XQ=2g*4sDPlnWD zFA*&qdI7_DFMz8tajtx_Qo&y9;(t}@c>mj|wMd}JNl#--;|(x{!xA?Xuz*uOJSd)p z*0i%(DzW0KnPxwB3KSn(_ak<}UIkz!AE6}5dR2CaN#NA&IPlci*?5WeJDULTuw_sp z#r}>+o*Y$Dw~L+{I-5Ft%h#D~BP#Hhn8yZJ>o)*n095XFQ=~$cY z(k+sdl;P@GG94aD`z_T@lxiY?rfJqGh&flFy3wKq5;AjLCmSunZ$JGcKJmZy`f5?s zURE1jX66!c$S>b;gkrYS`T+XQ0Io(_*PG3{;U$vw76&9q23icYneIc)lUb;=aZiZ+%(*UHhFdzdY|T0u_#wH z*4cUL2%X&~cA*-hQ1dHI0DD7!w)&bhK;ty+Lf4$|KGrSll@_L<3*AsTcYeC{sFouy|pa>D4Q6F$Tewo zx50qQf?^m(MyuE{K<^bR@e(XF3^+8ZyV(ZC3xO*~DOmjLh>KnABsf^RGE=LxM(k-sM3#(#7nSP~ejR`^ zuTv3G3BocWs&6I1K%&^4cE)xA7Lqc0-6on^YE&a}Ygxo`^MpJngj}UC3bnP8ZU_~Z z{ti7vO#Mb_8llGQBULh-I57ibnJfo@J`O8|oOPPpG?DnG@;BkD@jjIXo;Efnu&sJ6Lv$+u z00?{K6EvblR`Kr!{vMaqK465Rq5aT`!{R2#XCtAQF{8 z1)JI_5&%opJpRc57$c5K@KyuVSr*n-f6A*H@*c3A7_pp~^=x3E0H5pNJ^D*1+l$Ze z#P385z|Z&@zr)W0i2ljj(|;ISa(~)((Zi?o-@!bk;qTAe5&`S=0Il{_e{Um+{GF4n zbn6dL#Um>fgEea)1^Yd?wygZ>w6QI0cG^I{tkmoQEk4|T82gER ztnL#8Q*WK)ZERLClw)>+h9@Uj@nQF=K;L?thrfB4BQ0(V_Z$@w&sXuWUNJd|mb=ph zvCZYX_I->96_x4KMKp}Pk`djB+TG1m2Sw@l&kU{958qI(^;INnp;c1u*M5-WG z5z@4>np_6hN`i3lOeI(SSaEQiWUl)0Ok%F|1c?*rre1%N^*L4V>3sZ_SS++<`0OtW zj^=WzIk4dHR~#i1a-NKK^Oo{5T@ZLX@}0IwkHoSI*%4(L-VT{NwY27`OH-v!)u_r3 z1NAzXrVZ&@pP_Xci}~r6QvpMbq16!Pwb1Z(f-$sZ_@Pw~Y+eT};3e&Gu!e1vP(OR? zI)&XoA0#+`DlBRl9F77h;IhDlgNqAy|DdDtsZmQ@P8SVLB**6ulj2k37lion z{q7$)2K0oef61Dp`#toCvBXE;8vc?qpvEs1T@v{B$WA>Hex4@_Z5iFDJg7AE9iuiq zFknwcH>V#?KlaVGMUGnnG+r@MM>&StaJFH<;P_Ev<GR(16+5E1}uUNrZ+&%x! zb+rAqums|1>?Z(%1(I)0-}A6n<5Bbo^u#hZ!Zf!uSZd9NIG zllD|stY^5ata?gw7u(n?(#`7Y>6?~D7YLr6&;RA*p^Mkq84BW9E9%$EySB`{{_^!+?H`j?vMmd!?@+b*hKR z+Ycfz>i!3&ze1F*9{h$Z8x4Lr`XUq62$1OePvOHY9HGOTxay2Qekg(ovFt3~6K2vB z@w$YkRw*TW9*w-gDn3SV*`7T>a48vdZjAKV6pW4J3gKVo*g?J4d@+&{HGmf(YcM|d@Jskbi$W7OEfLT~vE^=(gncPeq5}1M0E#}?gBSP{ z%_5HUX{ZD2N))>PK+B-T(1QZ{Y4*4f+x+MY?@Le4$a2$h_b8&cH)#p3w7UdePog}D zPkGEI>aQ9aG`wWJhi;lINU%`M|kgwRU#F3Q!toZ}^pJz+> ztGM{s$twl-76p$Cq#L1EFePc7_bNJ+(O45XgZa)AZKq%*jNS2Lc)PgSVU*7dm;~;y zU+Aj%oL9t5kGY0Ge*_aZ60QG4(bdJ2jQbc@%zkxwCX1jImK@3B$F;efGM1!1KvULI}UQfjiy= zBRN=oKBFxdjQ%)Jqo^5bk4KCkbDca7-bRq|RK$@gi+ z3q$U2-tU)y$KE&=)-#3T zRti4ca{Rqsn<#)Lm=R$!kuDi ze34wJ?%fW8Nn*|pctZt|sYRUsdq8y?|B(q&cnpll11u;D9U{So17{LdEU;3~?{ z>9nP&J>I5WrbzFb@`M<7T?!ow#zk@}HE8$F0BJq`jpkCq2sv7qvVrsO?Zic=b&C~p z25!3YgB7ysw+e%{qK=}(lS7QZ=x)1?k@)mutha>B7p`%BvG6LGfM|hM2FPrv$#r~U zCRiYiI{#*TFDA{>7STY)%61AW2;&+_i}ESsTMZHbKw#e+5UG@@lxI@$jNe!PeQR4t zDX$3TCV!buZ1;#uvBNs7C>w4z8#ez{Ugx^)22uVn){THifL`@v|$L04vb!aFe5ie zY7_x42Y;s8f*9T0<7uiaZz6j|_&CJ6DUf^cFu14VNgFfIdE`+yy5NngFN1Bi+Jq%* zH=Rmy*~(fz)Zao1SWh*Vu!~31LD7AatVS2A*C+ClRby@rcwP|V?DV3*#+NdQLtINd z_p2YSwQ%m^$J&D+j)S}h?lYr<$O0r1NB8^a!PQBGnGJ|e0yl9;>q$C5=0+@CjjpHc zX9GXrK^GFgM|gmp)KcQjWO0wp5DMAJMjob)AMmIRl+a_P)~GqCwHnwOCw1ND6Fj?^ z2gS}a_lNul_?gu-i6qz-*M9@K(sDS$%UdL8X?jbmA%jq+FLI`t2f?jTKg!```%lP6XKr3 z=jBxF!}tgTCj@8k1P>|lhZGb!D|Q5sKq$HGL1VD5n(UP~S2@=x zcV-J>T`8z@l*6r|2nVIQt{gTD$VSDG?@(w{0XXOD5pp9K2eZC;Xa1DKygiN9C$)5EZHb{7+8MPy>z`uxegTsMy!stWlw%*nm~% z(7JRgtwoUxH)?H)cD(;3RRf0`VSe93f_|TA9Z`^HDt zPaZ`(lAlEOJpx>S#??1v`|im1-4%P+J~7bDg6?qlXb`>>>rN=*LQ8~?Nq5q3XCL`L ztiM~g1O5-{;_ttn|Lvi@bbEm4c>Mzz4A-ydi2ptgzXN`G{U`&r{?uO57>widZ++Gj zj{E)J1#%3D8! z7Me!RYB=U3D--7tNAk0Mp|fX2UTgCsUnV?K!;d&=U8QxX_|fv4M!w1TKYnE^e(~_< z+hy%B{FB*f|ISGb;H(qk6gkXcPB2mww;Q%H%rS5EGK<+(EkezcJt{s{?r4uc&;PyZ zxYzTGITq&WhqvO{anMYehdqVi)<-W7+NU{wd@*eL(T}4~ui{sgKUx`4a`y12b1nJB z`#+zSve^H-?F5$36c98z0)7X-6@EV>JXq@^F9bMM^TB~KbGV8r0RMXEp7@MkJ!?Z7=jMta+Qkq1j>Sa~_23h3&9 zy>0yq?tXwc*GjslZz>~_l175LxMAuL`W|X=YLiRiHRs;gf&dH@!Ux@Pcr$k#pG`Z!HqR8}`w$t5+K`>olba@H3;hy+mxPxX_S%Q6C$g^D* zKPDibH%IfUefVAs!3EW`p>Yhlbkhs-BRLgh`+l$3N+{8?yQb~I<%GDG^gV=&x={bv zK^#l=wx?KB0O%NK3iLJMQ_HG0Xl2;?%?U5-HaUVKrpTXoe$&XS8|U)(q{45^qI_u4 ziEN*6l^At|m$$ViIQBURPAP-CtmQ*Jm~1<~K}V^Ev@a%Sxo{2YtmMA96lxH%y(9=Pdh7<92NV{A-X z-kxw!(1m9@=8URKi0&dtZ?$aTzL=UhknT{u;HbffUj;!q&1*R3`bV(5>^iaLO2>1Z(ofktX2YSqJ>S&d z+r94^wOa#K;|$l`^Yt|b%J zA()<_b&|3`dYkpslRMcQT2-6M3ReZLqh4|}cQq4dAv0f|EX~Bz@StCxo0{5Myn*0q z&-64InCf&WOe^zC_zMZhJme$LX0S;oM6FL0@(V$VBFzcwcMe&ryoHVgTd*Aki*-f6 zo2Ib;ObhGHkkYYv|2$d#Y=`qw<}%vXCe7+u87Sb6=ktlo1oRkh$~^_p4ykDvpb;i{ zo#HNB^_LPJDWqCS?)tfO(0rcAI5<@IM?>sgL2?G}cj zdJov5hJhPg)czvvoDp`|dSGj|$763?Qo48#D4ywzIw-Sdu@bZff;39Zw#il& zLxkW2x2h=Rze5>~nD>O?^+8E%30Qw$sQX!~Wwr*a4X1Y_rh{apRFG@;Z;phU%~9CQ z@z*BO7P3+Gu_%m3osnKFq6AR|GfbR#8)(JkjDEpF&oFZRx zeP@I8fb?uML+X&WWJ2mg(13#J^TkSk)=7_mzhl-5Wq}?r-z&6vu}8E z>c^CiBBFpg_$a821>?^%>OGAD>mAGR93By332T7{-0#nkf3RgVDfui0Blh zNhB7)!%owD=+J1;>ey=E`#GqPKaeYb;hDmV%m=P9(ytaZS)Z+(KP9?uQ&z)y=07t@ zL8KSxFBnJP0WCsUP4KYo>0mW#09in$zxkd{yzhV#p^hQ$%2RmEONADV9eBc7y3@%v zYQ9CIUOQW^VIv`*a(;AvzZQ=GU2`>00p!2k%drmjh8kK@G;{rdMrat|S7OgPWJnW2 zY5Gxk4oS%r1D=Fu2;xLB7<7-p!CTanzoLPyHt)pX3qM-?<-u)SrAFn2ZTya9=-v2e6njlIJ}3gvI(Q zKk=?=RbC}J7(YhE(T^4;qY6j^`eGmO+ceIFm2vn&hTH9h3lCufo?#V+A#=T@-Tv%5bBG@-V|n8vL$ z!30xo>lm<_(sl>Y*O-{O(+R_d?0fPtqHA;oD~z2Nb!0#6j^Pu)l2a_QpE)uYq^)9( zgCt$G2?hXe%_TsBaEpLIK(7f*pjts`F;nuuSVM0MgcALrKkq{f<4eX+inf zm>vWH)LT^+*e{u_9lbc?bizl60?xjzz6Z?5b+Q;8E;yE18cq;>N$q6cfusp~`oVl| z?>w0n`GFavPeYxGa!!#HF88KkL~2d=`B13X1mfg^s~fStC*ej9^~5h_EaY%^N!R=2 zh@nPQ&%yPzAoa<_T*H(tktTS~$hT45Q-G70NX$XgjLVwj`%|)2bLaGQKGC#~0|TRJ z_sLeW>_#NuIY$$Fw^Z=SFZ-0#>yNR|Vq_6;L1^}V87sRIJ7QH#D9w|!qTV^W*!L^c zDahuOhlF>qABLLsC^%*C-Xt&_ztHnJns`gyZ4b zL<*o-F;~}rU+DHtSr^eXO1^voYmsDOdd@Zaw9qeFAYrBgfXJnFYu?<*8FDdL0Dmo( zB%^-5n(cM$XPL3ZiUv`G|3ar&n~>qJC%dMS8JR}{$H2ym__f1N&+f3Mzi-&c8B<4` z{JR-u*&_w4A5d-bi9&H!<}94LP;8h$YyS&iB&wO&$P0guAVx{cF9OIn1ypE8Dv0Kg zh{Q6^;Qo`69wizW$#S?uk*sPqB<`fz1}&wUto`()_0hx|WTxosb9TxZLbVv-bhIqJ z@;IT>Gxw*tM%0+CNMJ&bL1?NA>C!t$aRY|dP7^`1Bp}j4lUzgPkSA{FJWWjJ@F5G?*Sy-2 z&Nl;CR~x!AXVbZAZ#Hyas(qTmqD3QTccY&P{h81YW%}5djX{^&Kh?=04GtrG)4`Bl z4THzlVMpIwNZ11Zm_OC2@K-&wb4DD4{}{A#8!y)mm-*bFuPd4MK7HT}VEVA;aNWVUekUZ-*GP&`GQln0f~*DaIHL<0tORM0L6e)OIm0S zkGxq%Ej+^#Sy*W1Oxo1s*AjR*fV|+4?5aFte9!!kUEV{@mk2l_Tuea#g7#)0KgZ

    0 zMdI^*Vj?=7cNz)`oy5fWXwc*J7G?n#fuIpz`z0Ek8pB&lndn$Ngi|e2A@}cvQdcmX z@J|q$O&=i(oRRO~SM}!^`9|=4s7=2y!SZ7UbYQgOJdA`FwPK25DZ7=F&;9i)j@@@O zHZ)n5w7!(J=ErJ0GavV!wy|Df`HjSdm%%w3F8uBmd({oP{?pM*NXg`jj?p+kRpp0qmm9`TXkfqH8pJ#9B>t6WTS>LU}wGYC>5N3 zjc-B?AY2?{gLD$%BwE+F30s`8eDYYY87!70PSuZj3%);Bk|fm{d$~Kx)_;%TuUlnO zHc2)o6JXS#L+}vnf7moGlfg~z7F^LH5|~3;4=(4kfB|zyt%5(p@L1_}9?}ZJ)3Y%P zP6dcRQ9r6y41Yc8r_DBWm9Z92!Ra8W6>2i);SfZpvl1pC+4S$pVxB8Zzmq#CP_!u^ z6p=czy0FKgh&lh1{OV*g1)YD6YunAIquI-R{W8FTwBhSOl&sSD<=B1Mi;~Lhs0I{p z?XH+|2->_udls5F00e_F2|dpRbeKIuAXC-S5gA@9mdGX+NN+gpZU*qKW-yNg(zWWa z37foYhIvp&Bt{Eq$V>S`pLXPioE1S;QaKLRnJgTy9NsOY-pn?WOt^Yf1QJ&*C;9zW z1q3AFlX|^FJ>eI{i9-iemMBP)i!LiDzmgJ@Ryt#y$`Uirjs44=6f&MIZ~?_f2qJ+i zq;Z4njJu%T(TEBK1@*r=L0eZkS38AK1Pt3Vz3SLr?-2_C0*ok?vh(yK6QmQ8^HO~i z4jbQc{Bctd*T|hv80oK51wzx@{2WraMh3YD=-@J++h0Ng1XqMKZjk*Vwz|giWS5w5 zx;rAAa4U=k;4&CRLKfZd0~d@1)MLf)Hd#|klx&l{odt8|a0=iqs2D2t1^9n-(V)SJ zH(H$Q9 zsAHnKslWvn4(^tN00jl5GLDZ>=8#ni?&niUl|mcxe#gK$_+@k_f&YmoA3*t02HY1@ z)dTj`W;DcO&e*Z0nJu1lMxVy{?zYJv$Fylc~4 zU8tWu(1_vnx&4GfJT-(CJit-Di2Hbgm-sNAGxiHnwi^obILk_)eV}%2B#OOl>m1J8oU5o07w>m&KStsT2>(C3m_@5`du2j}#j6sS&Amm~jR;?`k4y z5eW^dW`C~YI(6PV`~vDbZN+yImg&$@>nQEjZK9zh(F#h4vtQ@{?f=#kw7KT}vp`OR zeBB8E0Gld%^yY8v0m%RB|AMsOvod*T(n}NY0T!n7v^@uM8hcaR)yZuABlS1vXQNzn zyO~rLXlBP0yHw*Gj9?MbAW`7dM}2gOOBAJC%|76m2Eb5K3%A8qMB=Q< zoiB)E?l^!FR0~a*kX`^Xv z;=E0UbE!92|67VH(y8%ygHV6xJJD&o4g`Z}J`HYZW8yTH#1eO9nIxG{q0%hSkLWkrUGyf;uPGqTciTx48+#h+~A-17wjXeIC6-DO`T0=fX>f zA(s+4nl#!l`p8hc!1Z?fW8z2JSbPbv2B8TU@Pv%CZp78e-5P@pTI#QyTCzgd>z+lF z)MaoA3?#<+OE`zBaYnV$k@O00wC{mY=U)ce6ZJq=pP+02%QtjKxRh|3NLS+y)Qf5) zhMPknaN@=;bK`(w%P5Q9@O`QFn9ijXyst(MixdyGEQQp{xnWli7?x1n2a{iF-D-T8 zy4^+M`t&v)J^UdZo)!26!?GVa)M&6Vv9)~wC*E{d<_J56qj-ZMo@$@X)_LRjTo0K} zm|B^?&zl^=o#AC5UMs&J@-D103t)vU0tZ9JKng$!s|?1W2(q^Zm<5x<;*U`oaq%>$ zva)mvT(GtPZx%l1?pU``Vrh^w@!&D`qg$Zg(Z&p<2B}KfUohM0mXg=#+)AN!Xj8Rr zDohRAlW{$cF2vasmYPnFmzlV?8?b#3-vowZi~Y_Ek!m^&#D)>w>4nf&8IVxNc>qqWc6G5&4t|m+`fP$ zqaakF3EdsWz;Ui*w**VBG=`5SU-bg+C?QOwm2m5t?!j#RNM}{@RbAHSyb3nIw%Wz# zJsOUH6eGOCYy1jtR`_@oY1+S(!T)(>4?!ZzUt4?t#=^vzqm#6KQiw{<;QbWL=X`E3 zn5C=|b`Zi>EA04tNeTS##GisO$KUe%`1yXF%dLP{t@-7z}K*vgUfpI0eaRNE@!CVSB+YQvwA zT#)=xa!2x)x9i}{HT^W}K_52ELD~$sonK99Tmp?BW&8LG&%jk9GK8+1g=-ctEbO@b z8i*zyz~Tdwdm3q0O^Qe+GB$k^il;0LASBs7tBD7=CvX+CKsz)e*z$76nE+qkjfTcFXpO11#$| z5i_SeGyP?}5SW7j6JyPM18DwPH6&r->vx2|MguF-0ao`1X)oAZAQh8Yg*cNG$w?_e zx*t4K%&5XB;#KMJGWt%0)mqiwMEJohVzx0Sf+c?JBQZgUuq6EJkI#J_L#AR!Xx}m;ZJ@NoE*k{g{|W6E(<44ek}R1zM@?3UTt?c)9p^Of@25d= zY$_g2Y^?Du<^y0J5Kk0I86oVbNADb*A@Vh|f&R<^_&yqd4^9)5fOnvCY>V351pC~E zfQ{C-a?1TgqY0Sujvvc-SSxx>6{mtu!~t7`73J4VWd;U1EAfsa)!P;}5r; zub9tPqH6mL)^gTEV5x{Dm2BZtJ`#DrCMwy(8jP-dcD(K%FKM$t6Z6^QUIfDm22KIK z@%NR=?3S?^&+l0ofN2C%s!iTKxuHtP!YN?%pH@thkhakSi#b$f-rQ73X~(HP;!Eg- z+vb}_qUUY{;&s-`hX@uIbtcO9Z72y)8ITU^HuT>Czu<=y;qJ;6{F&S;QST#hjj)bw zaIBPedHx^f#2PWedJfQk4eb#(Y@?&A!}56fzOaJ(lyizrjQTRj=QbZXuIT!f-eDX> z!Bg%GS0j|ZS=!aX=N#|m*cjLDxWN0Fb1X+kbvRD>0C^xqnT#>f0&Hmkl@&|jRd78~ z;h_nP=>xUgfo>j)8et+PkE6q^K`a8Yl3i3BtvENtialq2?tIIN?R@z*19alz_qdTg z#OI2_jn8XvRV!8v ztT*xW>l2wFDQ~7zP!+@8Xz2KjghKWqhW>yiqwkOqPq+L)Jx`Y0;^DZHbsC%?&a0-H zL$iu+En!RrNLr91PtTY5a^;KVH7^hDN384_@F0F{zUrQrUG{zsz{N*oO89-Y$Y7CH z45AaJk8=qCghV4#tX<@`%+Y0Gicrlw4kO}?u!$eGiAtVDHBHU2vE6Q0H@cPE6UCeq zVm_C26jMw%;=4kJ&o&A$zxN|@k5s`ep2nD94^yP-`lo{o88H6sXE(f0C zEJ~KYtbi*(cL;cv0vkb0;eeJ{@i>}^Vgg1mM6H&{j)Oth(S~#-pxx+`t{h& zq27)atYA-%lY`4rDD3v6_$JZv1^`GvmGSDZjn<(HoFy1D<3OvacU4kLujBXCzqChDN#7Al#|vMQhUQ5UG^m?9HtoEvXlgGW9EVE1l5=+`ld7G3fs__JDEdwtFMbYwOY5H~{Q2Gn zzQ^T!N>fm=bd+@H5sSBqlM)!!K51}Gob_8g_%7+ocZ&Z_-7nl?T%UZR*yr3<~d#*daV^!3aJA|FFnAe~_81L@1%~il#4HWT3H#78J^+O@Crg z-vt0Y1MzGcCa;MEEx6qq>aos5n)N3Ya|ecf7O`0;Y_%C_uKBHec)SZ86nn5@ z{b+6X@;Xvmaa|73e$sO8W%O$c#h|~dV0$>p=j?gid559=&_V0+l@DuPX$j;39VFid zFSL*)ZY3QwzU(Uxu%-35)6jZmg_J&@2_Gxp6?d= zLcEk|{$A`Q&c=GTK;+6lkc~_yh{>ag&@ssJ<5gkj%F&A06FKSyJBDUTd!}4n z6*x<*)EQPFJmrhYBr<-OXL8%AMvx+lG1vaWL3-lTyXaFyJ+~CK)`E_EY$U>Ir=s~$ z7OK&TO9kS6L_lJ|5l>@#`G+sr_iqG3jiz6zss(7beH1t^(vL&YMIB2MDcf3yDG_J3 z5d=O25JFU{wQSewd4r$l$Ay3(YTta?juDq}h1qmOH{+CLRmL+K%3owJv)?21Ww!A= zW0|>uXR*jOvy7MIS}l)6wYq44?rwlXK?!aS@!sfiO5r9(W0X-D7$IeX+Zg5+E)H9} zhD!9GRb>k|PAw>zk>9r&pty%(+t6h^4Y?SsOw z{a$`ye5VItx)a5>dJui|2En|qM+yANu~IV5CA&~g8G(?7`P7398b&O))Xn*n)v#qa zkuC{Cd?rY%(Q)Qg;X%T1w-#{J$cOh(>JWOgT)IQrR?!v&u=Q;Wd1%Wp=HG2}wtPSi z3y$_GRy+u;qIXJz=`Bq6!j2+{rse(U4@DIIrEd}GDS|Np3GP?4r{5Awy)QOOOha5@2v$c$#csHCobe71SVQ zHu^v~3w^a7M{!=0dEqY9~w zVAzvWIG$^G z=|*l&x-ujC*c4;VeZm``4^CbRv3^@&Vb$*0TDHeoj_j3S^wNZw ziH?W?w07ME6Y){n&|b}N9s@a&k<09F1rc#O#uo_(u=48m`&`;}3|E-HkI;yRu1g2G zpw?7I-Cjfte(J$VPXK)1Kn;8gFnjZ%6P2`Hn8H}#k~X{WLh}?N1eI5ACaO@@x1*{@ zjy<%b#L{lje)TQbMeso<)>PE3Lh&!bfHo_mIIea}h)-+WLeiYNj%`RN?_CpJ60tOs z>*SbZ=U-!0`i*oN%MkIegArBjX?bf&ydDmys$}XCQZO~KR`3hl3y767o*AvgV=832 z$NX(juX|inDN7f5Xh#gRIl@3;~$(>ZF~uBam0b$+g#}C z!q_VlNc)h+b0xM$o!L~P#hFWpoBCX_u&(!_Dy`(o4h!zRF4y@l=_yJe!Os3JscjpK zcL*;vUsudmzNTw8m6)j|z+BCJ33>-t%&5N=nG&O?+*oHO!W?wxYnoJK(Yyb>LS)wvfkx0LZw%BACxlDdU;GP`yk1lDE8Bq^8=5$oDgciNOG|K0vq=6$*wx;>!c>Z zLsoNy%Y4iWexfpofx2nd-}h3zQ&=?D!kY^90)c*VUMc&^@qN3ul~6K>C$8aOmcE38 zd|D`6-#ZlikP9g4%V6Lq*A*5#LRzD5MiGR591famG||1Qb`omjtDE-j56(dWf-OT?^lN;{x zYxINMEPU!w;!)aJJO!4a=k%&k(XrqoAKP3}arVF$J`TDuS2bTbAgUC6{xQrhFg%j-RqbZu->caeW_*hnCDqDj-k(BMe``5;_k1f-md>N&kN9f~ zl%E@caaYX}R&6IF#mXKX##pPJS68#oNT?M^hV12_I0D;B<4ImGvYj<@@fcd$FTXC! zuQF5M+NrbK!Y1;gVV1u8%7(|h7stb#cbp!wId+)@mdAR4H*TJmaNhjM-EFzb|KqB= zv0UVYsb?0Q-hF0;C=y1Fhq;=oI8v>ywf=yG=Zd4j{f#&;E)C66gY;7I2tDc5ihs6zHd_LLKp+5uzYl7}`=;pZb)f)%PtOQ&N(TRr@iLu^?U&hs zKfcj+-7#tFEM)x(&n&o2cE&!A=djm>a(PeB^&CNA}Zu;(E?KI*cTB zQ?R?MHhc4=YjANRhehncDj z%yj(;EwA5KP#`_gx8Y$p+!tHh!_odw5Ajh5aNgnF_NTuf6tYeo$?Bl1Q*|1;;?!q= zOGVD8d4->~=!#p^qjNy1Ug-wYMhA(OivA48DajQD_oc?iB$%AXC=Br!*|>}TPM5bi>@Hf-LHtY zv^jxra+>d2i=7-sOOcclt5j)@S_Ml*8BdaqaM(1}!Ra?${sjWBDeijXms0kYAV1NmBxZs-+$7SmdAIDpj z{=!o|NU_t=JQgcq z#|}H}Z1=(~!=l-fKYqLClkR8gk_DbXectq&xob(OnD`LTzkyY2Y>4dfCM3cM6hhL* z-sPCHKnhzt{+t!*h>Cv}99gu^I?<-EV1|;5h3n_`6t_@rQD}`?_lDgTrSl`}mXv%l zqlK|?K~n!SBp~9~oyB!Ao;zK8y6NQt1|MPfpz3x*#mj!KYhLy%^~KxB3RW|~VOW=S zxHf|gYbxo(>?<_oM|Pg^S-nQ6tLkX+kFak&`Q=l252V2-PV4-6Zu!Iy} zLf^8J%C&URCG*7Y#6|ESh{R)TTv@UIh25?B*QAjUZ8-dvHdABa8hxyuJ=+zkrC(vG zRi7}Ev9tzXYC2h>-65pABU_qzUmo}Q$))2qB(=;KdvUjO-kXi)mXg$0?RpiRpRec9 zF2YjqH#5_bPuCcwFk)}etV~bC-wCD_S|@r7OkiN_P08l!GyjgPNvac*b{1sByZqQ; zr<(kZZ8TwRHRZMbx3%rJ>I{_9M*~R9Z;G@9GM-NL+_;+P!Wc`LaOAp55TOuJlu z&B9jDjHXJz4ohEOj=W!O1RMB(My)Ny?#Up(&(Tl)*hlGAb z1KSVBOJc9OZw@;8ZpwMUtlArL3Z*wF>No_My8o1o=`ODw(&lMjvVS2Z=8l13mTA&*QDVbYVy#s%R1Z^rOvm$sqs}&EmlKEg z>-8lyYh|_z%QCR*@zI|FFQf6~wF$$$8M4^bq&Iv?*G=91qo(rjcd~B3JN`t8zQ6ltg@3QX z`AHlNHPlN_D3UpwrNiZloIL4@b*dJL)pED>MY(D(bGMaH2khP~3_Ov8>TT5GzG?Tg zpU%*eDBpbx_l4p1U}enh6xa}(i7JvmbAdzj;6WS!wK;VMtUBt>z6DxEtpS=Lsn z=!_Jqki3wgL=0L6Y%DD+ghfMXhd0QwNpG_ggr0jZOe%isqB8j)Gw%W)JlIv`KF+Vj z4}&+OLjyQ{{-m-^MZHhjo{k6opRXeuLfOlFfM>&BlfB#JvlvX?d`l+ zV$UPO6JM!+1uwV3uONyXhGRF@W8kO3NWUCi@VQ6x0-oR$UCqPT{fX;vg57HUO^mV5 z+)vwjDPNvoM$3AFX2~@hGS|^y*J!@^K*1p39|nXF(NE2)#^3oJ86dyrhC(HK=$I@)U7-d` z;P}|sZJoWG^hwm{6JH+mvJAw82fcbB`aJ;_#7VN%q-22oJ=PQsTGveM*m+CoY8v-* zBd`H3ff@@Tp{VN(;KzMdKzzd7YKKGd4=m6o5G~*X$mu5CCt`~Wz&!!1fg0guowmEA zh+u3$nwGGp0Xx@}wjXKrYH2!gPTtiViH5_kc0>`obbB%L+tCq6GR$GktuYE9dU3!& z0S?JS`EZ@3m~bsY(}86)8Fov*O9FtG01-qG1uoBr5XBYeS6!_OXraw}V-B@vUp}?f zqr4hCmco%QMagRNwVn4*d#_r2i(@p#?KShQKcjL|rQL~E^h2*u)#P!y%4VOKZHZ_A z;-4DC`%ADCsYGB7bx-eX6VOEDH>=?hC& zzk~RYg7JKgH=$|utCf*hF3^c3=GZjw&?7JHRt*o5pC>d0uWukA@Y{H(mPiV|inlka zz3~>0dv)L6s&*S@%xKY~O}uxpE4&1Rp_wtf_E^ zxJ0%At$kyQB$nBb+UWO~k9-U?vWqLU%f?~+sdn++XY-*1hl!_1xa_3@q3gYOvid#-q*Da_$9K?i=wK?M~RXW+^tU=*SyXQb@(GYj$P~KeN+2=?y zS$wdbj<3V#NDx!P8`*6dJ(%|NAE9}=Q^sAWowCc7sKU}l*cn6D5T*tdcK09!fTxYt6U$0%~=&1ex}YtiiGjB00*MrT@B z?t3QlkMAsw6?B5xg|KMqBO)Xm1xD9nmzEX@jAtS$jQS8*VU|&n&~zdhGPl9=L0cX% zotnYrcd~$XZx4IeN?_)?tgYKhL<}XekAMwQa^QLvR>i>+j6=tO3qJVZGo5nHE4A2y zj-RRTcvy#{mfBjlvS7Uz#Px2VmN?61vDykXV|<(h?G?qBVr!3Gd|Ho~?rIs&f;qTc z+*7ZG`{0K8=_~04E41xpUGTnMQVk3Y3|OsyH&nYRF0&?(nO%PT`-&H-9+m?^@M~my zJ^k4j|I3?)I)dTCQxj+1X(v~$Es0%Xc)+<=*VEji1KeW3VXii(1|oY?utOXJ!DC56 z?khPZx$(=hj(=0Ly${4Z>Fd*FE_)wlE%Z_hMYBkYP{*}SN6iDks+x`&Gg`E+%-^e# z2I@Y#k1%A!I!|lboyR;nx|^sE9=6XuU{n8r0Nxg|bcmrVqhL+lPh%$S%4gxKRXFKG z6xPzf*J!Bf2-$qtEJ4tas0Xi5{UQb?Yz{)y*FFIVi+y3P@e#(;Ebe4=2oNJieABnW zib7ioC{UoVwcRmj(W14>vQQaWH^4Oi2B@yfdAn=NEkJQA1@*EpX4Hjyv7_ihEq%St zaY1N)iNhnfHGB=&# zFs5&Aa)K4Wi96l+@b9`>hwm2+g#CxWm;D%0(;lVxbZL$z9vkZn+FxprH6Msd^n=lW znS{iTD`{G5S-xrHayRKpzr*xaRoPGg&IC$6nsdDs( z_n&js+I%Paq&?#NGxpa~a{gBgM0D;9ZNh}taK=SO@glc5vqtO%@rvFQ*FFJE5g%o_ zE0k{##w`(k3FpwaBGptb)_3yURk%+fE$IZ32E73JD8T~T)fOjJ42`E8cB4Bo_V*%e zPYP#(SG|AM5<319K9NE~jkN^Iw!6e5@FRXnJ#7{U5s1D({TF-ydY|h#AKvG8yF#3p zPCMs<`;bRL>}#Qnb9%T=ckR@DS~joJ>*A(ID)5Wqi+0lNCjl@MCnPNusNy0v{nA{+ zbF+z_2@?jhb{J<>Il6;V)&RT7wI`=ICg+jybm>G;4cA6=>i2Xfs~Xw@7uNS~{E#Q* zksrisfq3}QyiK^Tf$(-t(15GXcrO(`@PrS8ligy}!QRF!Tg6p`D%SHlDv#dWv>DHe zP1*J91FFTA9T%@we`A{#RJWOa0pVqT z`L6X+>&&W%ty=_!7+12SIV$i69XGf-TE(i(cBZoiIjJS*C3mX!0;M*sIqmfvox-ng zyYr+q)f2yf=D8wDUufRt3%1cQjncHKw9@0wX>wH+U!m{#&2%_Zcb;FNaP<_-yE3lp zIm5)Gr0%Z+t$n#IPE6`@Hj|EpNW>!cU1q= zl>O|`#akg?kY0{>ac?Tn99md4HSky9o^U@mORe|_>ea^B`(lI5L%yZkal71ipc$xB z$Sv2W*9S|us2SI}2V>bpmoD7&K=2MB6kU22m_|SBE2ElYvSH_C9AcyE(ZZU{^9@v7 z5F&9f*C|{)V!!2g$(Yqja_fB`4~AR2J33X|G654Yc8YCO)mU}Sy~g!Z5AL#2shmbl=p5kB;`4%)>)S0szg6yx3Qt@Q)Q%Sh<|27E1{& zcSNig`HWgG3ijgLGd4gG_N%{;<$aCrg0)}yi8DC(j(_-$x;{OGYagLIt!MGJhB8-! zZk9^f5L5h`Y|V6pwLaw|qMgc@uQ4DeND!D$5Fm%4Hiu)0a&iSZYd_s~xVf3Xet@at zD%>f-UDInYik!K?(p~#sz-8S#mt`^JFX~YbZ;S9o$?FuoKHa=aGC8J>fodSnRTrZw ziD9h24KX3&@+sX66|TJh6GHr4VqHA*!x{gP_h&o#Y~Pt-HZvdHT1#ExQ5%hSsX>H& z2IyMjfWB)v&mvin0uI^kE!c(qCdl;+Zn-u)XfNy?XOa(e45_^OtZv zB(20Z464hEQ>!j9l08uk!zjA!+vUDA)Th=c?KQy82l9kKzy zf_bdNk5lIuzreUUWKSLLI)tmMKk1YV0+U$42KI4QpNfo(jEn*WinYQld*xOAxuzz| zbChElhr=r+k(zAiRWo5SR*tiyfVlCKMJQOhkO4Hdj%(dGyU`PHvWp#pFq=rk60@ z&0hb#&GsUGn;6_u*fda>7L|vOm`WT_ugI))?l$v^%|qB#$&g1A1u7*~ecyrDbP0`O z4R!rUu3cJ9T&6)-WnwmCw3mIxe5*MR((AHErpyX^UfKYe((XfaS$aQ@m)nemp@wG~Y(Y3%?k8{(0WnZs}*Fb#boAoQ` z=3rLBV3$n$Dm?Sd^YZ*nmNgPIIE<*-f?8YJF&eTP2!vSrpgln8I|Bwv!@l8u{Wz$l z;=^Hv&vXsvqZ9Jg!u8whd9hu-%;mmBWaKSNZ~mGQufiO=jz0Whv&N;KU`cSCk0pu6 z&^oBb-KGVyTOQXpp^$V`uq(J%C{v`jE}$3S#Q-0N0*n@f;o+*Xk++dPV_IbX0d$r* zg@ct#`BYLp?8zM|?^F!#bN%iyJ-b*=uJepbb7*17pSrV;0NbOq{beBU-w$_OdMYOvc7%ASj2eaaXNm@1ufZO13^=#0H2;HZynTFCaTX=0)5VcQSbBFDOR3_gtZ!f zu3D5;QTw)9nzm6fV{#U<;Cg!W$anI$modQ7+x@pF{My|3AvXC?cgxF7%~Qw*?xH6B z-xI}07Y?%i0q>~xSMLFr8RKJl4|?y&PgQwB1-r>Z^C$97*JY2=YVvMBpFdt7S01ll z1WRomk^!SQr@rKyM9oF(`E1lIKn?m}Bi zzce>?UmJ|bAM4-a-v1~a*q?5&88``E1Q17Z2ajAER9GMw7`Sx5#s~MTi6EeC#Rgnn z=S;*N=kWVqH_d`Fi-BChy4on+))bw;wrQkRPcG6C50(%lS<}BEOA`1bkJVMKN6iZiN1^7M?#5TeWLD`9XM403)K(bez)JsF?XRmbYQzu zswaN`+8Ixhz)BIWkvT(0%2&&L;QhH=>3O>_n3u@{iVUMEM%Wg0WH3RF}QSm!KnWipRtG8;Z%i^4@8oB^Pki`IE+f*I!$Fda{$mFQ2C(d`9;@9SFSx ze`E_ct8sxslI_w+(xKPOJsc*yV4OD6p#JE9EP8fR7wnpo@#F^p`cuNs@PF`+yO_#V z*O>nVbtL29>hIN^c)(MgeE*bc@bt6a9r7?}8c630CBIX@DEI1T7SzCLJ{$%E)_4V44<$5a8D zP5(S#57jW40jE&=!kmKlgMi`B4`i-n2sJEF7j2yoh-o4K0001F4lCal!hAfAslE_G z2%!nXoQ)4$PrHLvtw@ll1L&n5^uJpqxucrymM*9K0MP{6h6>nn9b$2jHLuGzYN!^3=RAWE`fOlst^n`aTQOZ!IdT)$b*w9n{{sq zWNd}RoHLYIwx2v&4?k&_Z9Q8$nxI*Ol4+7t%n*+B$t`?u6TaDf>-3E4ga8%{J2;~v z3YU*S$m}5uofcFTJ2C-UvFAiyoY5VU3Oaq}vX9;G>_azthwpq5x{+tMgNdqNVnm98 z1E3L_6Pj@nn2XE58Z7yqajHK71P~C=*)@{^^1JI}yS{6Tn#b@7#;bh?7%*Vfmd@k+ zzRKAOB}^v5^?4~?Mbb*c2K(nyJB7Q6pl=t9H zsS`JvB4)HBxHr+;6B1YPB3DjU#gLOjh^QfSBD5k-2vmOuWJ{3$4YuUV(&<9(EGtcd z#Kq@EV4AZ;*uvoiEh_$Iv(in$jw-paA10(=QK)1hE_p@=;=^tcp6dNAzK0<#4>nGP2!wMqFek z101J{k#(QzYTELU9#tOEBmbkCANi-y`Wvmig?|;D<5% zw{S}Wyn@N9q&Gc`XKM6WLIz;QYoM!Wn&0@GDE+wQJUkwU0+AzdVl<+=3dXb`{;rx)JEaL&4K z7KFKc06zj5(wM3Qp*Gks5d9OGy5@Z+mWLY|aBeQ?4@j@>iWI+j^~E&eYAP*dVpJzH zRG-}xKb(3vAQZCf**^=2T1$#l_*c%goyRs#8H@7Cy~=09`E_5U)72Spm|7~T=MzAx z&TI+=Aog3hqder7zO==ndh#q!TM8zZr+hLjo^6J{vUNZCya76ErR3vl6z3_2v!|+= zOvEGW0mY=JmU@OjSHM~g`AFa$3}|(l1Oo;JhM13e5y&49)X$Y9n}}tH!;n%!o^6Tt zKu7ay{UL0)aroDjqEy$OQ20~?8VvL>!Um^#1DP=L^wg|9Q5PdL)zEc|7Gx-x`gH=G zD0v?mp_n<)`$YL8A$bXU7GMiKRlO2UABjS?uIkj1O87!RGaWZkCy1L7$}mi5UWM>w z7o^~+jfx6cNG?IxY#s715FR#2l~8WS^L zQah_UcSp=(bt@q83~6n90m7w4FgY3%_w~Zdg*l10D96AW`rV;Qs0xRbAZRG27h?Rgd);9SsG`tnusPl8XR zaF+X~FRbQkjM1gJpKtK`JGGv9SL=Ckm9 zmUCuTR;dCvwdijVMkGmf5MhQ?dv#VHNz7QXMYGf3o&m3Dn!tBo$W9CPP18WVUL`Qy zQ{}gz%Nu9cMhcFXd*O144y8g0?6ThG;L(qU8}A^$jz((f z%|&RUhmyudwfYpEC&yhm^fXW z0)yBqFN`B4Y-u+tj@(*#)9l=#ef{s6z~Ccd3$9Zn7M*y}>+i9+P2L#|--pdOI5HfM znAL?5WpPz-;nYQ7g|rObGqd!5Y-=0dF`|IYdm1PWha}ie{d_SJ<=W84&?XDn7xCs# z-WJ~wg<022DB)G^)fzs~hJR~xj7^!_KBOE1I2U|~<5@B(TPI}|&<{1`q4{*FO&>+mc4z{qE7`7%vTzOV_4ai`8Gf>k>2%E8rS$Jx?W`23m*2F$n05v{f}Fc9rN^{4;C zCfu{q_y2SC`@isiW?6%PJp!Q=WVH*(yIDj;IpI)g@HHkm}|ua@_v1|1MY66|g;EQC-(2iyCu$=Nc(lZb&YbqHMM1N$JjqM}5t z)HevkO0$hWiuGzgAA)JowZ!T}H=fEh;_gcAq%>a3m%Uc$!1!_=2_)|xj@FAhs2a(v znjE8_+^0PxjM+?}e$~TZ;rw243cggdTF~E=hV5Kw2v5|$#FOZCyUSREsUIXEB}t%V z)Sd{?5|_>8{f-s|**B zYaot>ZMdwOG<4Fj*#^kPk`Qy2zAq>i*>IoF2-o`!15uO85M(2~k%LxQWn5Os<-E@>kMJRf@O4az%>Ut03g(RnuP1PPkHW#Karl=EU(!J*A)cx(j$U?1 zSg*07C%oN@0747+)VU*~@jBUYfQb(I-9Q;lCz7Cv>RsU3n>$jM?%;)L;tJqOuxI@v z{s#^lilAh3johM~+&*e5RS;Z2cxyf#{C$ViQhHTtGUtcWnrRmdqv#qEbqfT?97XFp zO5jaB<=E1>R0@RxTh&k<^d#B7m>UJS%-~w$oOSzhdslFZxvgT$Kojej{3;s~^;y)g>57hrY^Ki8WdU_3? z&{boa&PZCfgFa;E$qPZd#kG5GDdHi3JE+4FIq`>fguu`xJJ24LXAx7WmfLF2N?1Au zJ)Q8R4BXmHdidKgy~l;9U8^-KUb*OUGawC7>Xl*YMtHk;#z^&IOq~%& zyC1@gM4p(QRy-*K=gOt3)}HAX4Ic_z--H`4SY3pt<@jM+J0y8yz;)c1n9=F1uZ2^; zrxHp?SLPjowogwqgT`abfkVwfEZI9yWLfkzPzL{cM_wOjb3R%ct;!EDzT0I>W&HBq zY=WK6qbEQ+z$`FX09W(C5QNs9dqF#{7AY__)f$-FQ$5hZR;yBwFw8;odPpGdKgf+3 zX)Wa&ITX)G?{g&I*@i8HqyP=}%~l>xlJufVq;o2ZOlPY0aqjNkeHaolowxZIhU??A zL=AJV1Qq?HbtY`jCvq58Nr`+Lyf=OJr+%hZS)6BKQDY3Z9mbxJ(?tV@{`qvYYsJ@h zr1Ly+CEi9AR9K6n9aIqiX>{F%%ut^aNc@I%C3zKuu#{V;V(GJZid2kc^neZ2f!osN zrwy9RXnH$l-G!Sv=dHusSJZ1UA6K&Epv&JlYW%YdIYbw#h`svq5`_tlNPTJMRF*U66PdE*0H=nZk z>9uAQG+DUaqv@w8Guro{j@3P+o|Ctb8a9Z=cq0^#k`84ZfqG4|sk>?c2_XQ5_`%?W z8qA+SsOvweF)u38$ik?ZcFnBmCLA@wRc5);M-T3kCm1waN2ovnLu52llE;>%!&y5+ zKJ>wHYR*7QB!x9Q!3rl!PlcvcucR3iU%Fg8m@mPp%wYKVWYVRoQ!e~=VTRIT4t8?5 z-t3yeYOq!F7tkN$JXI2JInM227%h|RLIr-F!WP|q?sY;gE?UzMn1 z#DV*{3ZeqP;9-S7W75G)(!F&eA4*YLa+aW@k0!8$uI!7t#R%Po25{rdP^l{G3aQ@YPHnosHB|#ORz#XNWQ_f8SuRA1j4oprp;oTY; zu07d;=*A4w<(AMPJ0*%MM&@gpcB!Dku9akac{z%@GBoj1RC|7Y8O_xbSK4j|kNT>7 zrbo@IJoA(vtXmkrV$bh)@z%Rt5}*8?-~V%6+ks`R3ki7*CCZ{`Jz@&v(A<>6H@7Vv$;JE1-9tW(q( z^rD%8m6?!3HLAr)OHaT}4h`HGj0?nEEBV0==HqG>e&(|U-ZvDx3ac}eT|aY;v;v8T zqge%uPiiK8uAZxiAN(4_JK(yK<28LJ_cRQd@G$c1=%H8$F`M=^&xaN1J@{^LYOL`j zJVkx3y&IRnSKeB-l1s|3BmrIvpjAZ4rJ>h2eaEkssH*(X#N4r?UKvPc!Sd@fBIh*i z>!P*m3oi`9z6ehOkH4sE_R5<2#rfqBI*T(VgW`xRlMBsS#zbFx1@15kA1>kn(DiWMnu*6-MHS%|$`8SsU!o;7O5CE)0%l&o%5$7w z18c3FRcQ1@3|L+BqnFF3?sV#OKYJ25p;(}IF$s(mYwtAUFED-Vo8pRs z^xiL|ersq&vmdaecY!Ln8rPZW977x`7~q1r2?INq;h*Y%Y)|6{=?QlqSids%zd@jX zdkjOa^|s6}fWF}lS3RCp*uDqg$}NHL9$p>IBs6%rFnd}AzMHxHe?g;le+^@2EKhEd z4VAPU-v2r3(F-Zmazh22wU`1a=ST9zqMLUWk9aB%6wM}9T?SEps{a5uKOUh))y{?+@?v<^x7h~9b!YS-{x>BF8nHiRlt~@D#q2B&u3Y6 zi&1?O{gWno-BY!fSr>A9Ee^YwWfUFW&+WNTNU>1;pE+(alcstZ{?57|4nyh zwD#85e|>-cYYz`us6}pjLDf7F&eJrh!y0h5e&3|nbox2w$Rw3dY!MGlVIEk&dgnYq z4#Tl>!I=>mreLTAH!MO$y&f{fPNU}D8G+TS-Z*?_BY`&*B9uB6jBGk<+a;DZrG`eq zFnk~5o@Q9K#=OH0efSwL+}dPL3PxG!6PiSff1B4SRZb|toQ0s=Fgw*PSR?4SFaS3* z5E~U2HE#sx82l~R%W`JsXp;A7+JFi50Ug|<{Q9!diV9La<{g@8DKz?x2Gpe2$zFa1 zW*x4;AmCPIzYxHCUgJkOH-s6{B8gM9$-J%?GgJ%I(+N?|eD~ z>qES>DCR!wXlatDA|Rjx17U6;qlk-Yfvz_VGfJ}!ClJrpjWCK=-8lh6;o$qU1uod4 z20gc`*41_hwxC#grhCDV{-@qiMEeM_swA68QKlv z=Jsi=ERn`+c!ge(4y7P_4_SRyh%|JY23CS`|48;&!v%i}AVmcA#)ug8uAX09X_)#l z3K+Mxyh6B(TK6~twG*m{*&Z=0F4A)RVf#S$4^{X5p!a;C0-(Py)`lke!iq}~y9;3!cAS-5LER4$}_ zWQHBiYwm#Cur^1PT7q|T&_JismgwqD*|VQP!M`;}jyTtPlRn>3B4p|7`LHHeGw~+P z>hflM*GI=>T*a#BDb(}G_V~)dwbYmzbkDE=URLYHjx7*aPu;fZQr%ZKGk!C;T}$-l z0lzw+y$eqhat0PCIvU)0pPXP4Y~Y>Ov1|X#(te3Lz_WCyStw*n6lcrt#43Mlw|a0jFl& z3kL*yAcx*J32ek^-#z>qp$L+m>eGW%K<{5`>O!mgx)z?XhyHqTnDM}Y4^%~WaG_qv zfzfrE0GyJ6+P|6L>VcJ!DZ8b4?w)H;Cyml6hO4c+>Sj7XbJ{Yzb#n4scgkYQJ1EJJ zPI~|6P3o?a_8$u~{qbKOhwEu#;-x@oZhNZ|gCH~P+bCw607eDhR>&^NWDHUqn`C~y z*!>k!?c6=8tZeK27f13yg`~~8yJ<67LluA0`ymVY=tcoXPqF{L3)@cCqv9ZS=QQkk zSJepWl?d~mag!gnTXxDD;V&*<}B+z}V|R3_ABh za-6EO1#cJQMw)I0qsPNCzZL%NgIyx!cn>{AUHL^wy%04QBLTEw_>=JJNYjd-lJY7& z@dDP9g6t*0vj-QK;YiR;iKlVD*IiIUc5e%nOV%g1R3P3iV? zTrCzUkWVF0R_g!qEA)C)@3qXJn@K?dRh$`&SKEsW6Y~6;E=|1_!|$f}7vZ5imbznh z{cH+Z8-1X_E6fiuc`bVlpkcqKCxx-l(jKmY+P+e!v=lgPQS2bHjGhZajS#7JUxnC6W= zVtc3qkn*9@U(VQ?dBg{J+e{o3%09sXf(OgXOrEKPPzYqG{k_*9b0M`BT)>YHm+{2E zkmvNu<2uu-lKx}jYqJ)>x1xiKFnV5n1q{hIaRs3#6LKN+r*g8d{k^7gTWNbVlhE0I zcy;}q0qaS^!%AQ~thJ#mQUcPnD)D-9E8OcOJ9`@O>pYZ(6cB$+DP$`o<_TT@ZU@*z z@#RS{04C?-AHhrukKh~8)MaUCF6fPE#C-e&2h@Cj7dA`Zx&Fk*#6x$#MP!J>52bdo z_`r0)vG)$FU9W@JMzIB6%{Es;WwrH}%8*m<9d#61Qke}~<9>4+TY_{tX!k+<`U2^% zUdgQvTjhc`5(~T&oFu_Y3`e{rlVkCSpV$OyjHLCU;a zWUBNw(=A4SU;>Y>ylLvjMxnNS%eA-8w1cAO%20(@_GPQ*H{x3ZKd^j|lk^HDU{ zHOlA6E4?Mv_E!bnHr0#P#b=f98nX_IlY4c8J_4#Et_$wuNM}JSold8t-<_Fbbk8^T z$#ZZW1dkFuicGT1SQzY=)xBTT*EO!TwlMec;J{v2kora^a&~cWzC{6gaOL&46GxMl znRpH4iDzgYJDsCTkUQmyioG`@Z`>o$$KVbcO2w&)uT#9>dQ62b+h}nRvh3|H!Oy=V z6QLlXIoHJcFod1yz8aiuXfIB5ff8A~yh>_ymB(ahAj1@F&DsyIBLL6oofo{%IH1p$Mn_jY_$7#YS z2e3`C#wh%eO_-NGz2Ed9wq{U)N0uY{GbBcRDZ~|tF&n=W%lLgHE~&LS5@oGKOeo8G zMQO<8oEIuR60Hth-FYzY?WQ`K)_SJ}N?Ubjc6xb&N(YckP|RtRdzHc{42hs{o?Oh% zuiM@4vTbV*V%I*JHdAXq#2Rzj+fn8YuHX<|)Mvi}(Cx%l2B!@zE^S?hxP8T#Q0>Ce zIFY~B!Tb@`kYK+Q!=fot8+*lyJ=cB1@5N23j))gSqLR2oHA{%AwlO?7qh$5#4UL53 zI@jFA40AVWeY$J=J?g-i~ zFs>odn>*g?Wp^DTn5=NvzMT-R&jtok&fI3=hv$|o1jURoodf382f4^4OxS^8pcxGL zI~WEZ99#LjY{2dp>F9YiPakp##40Nvr*T?82SqL_vfds=1J@}5HF}FlIP|acHe3%g z=5Q6<+6+^+~QnE8xy|GI$FJg}R!X38J&G4dodRq5T>fZCfgZ+K|2U~Q?ml2#|IEvP#QQU?}SC_DF6*|7T zP+;x@63;C=Wkv`|%SUJ_^)nypW@V~yGSC;^;g#NT^_lgS%U4UP?liC!uu=d7IR@B&52#{f^Qyf`8mL3 zVVR$e_yG0p&=Tz`nN@q%gI2Akn_-sGuUO*o;-Gp1qxCQ1UKcg(i+euV9hSVU`m;#= zYL0f$c<2A4|4xuP4)47}AN<2-9YODiBhU{30AT1Rg9lh@UJ%2dZ`?RX$DzMpNkF3C zbMm+};}RsbIVzMRGye1eMsQZbGCVj!46pDSzrvdpdF*ku3JmUxS?qhYM2p+@I{dN! zD3QBX^fHglPjy!gZSgw&S?MGL@N=9Ec;+ClbPfX^f(uzt&O;=mXh$wbT$P*5N0e;- zOUlpfC|_|EHs9Zb(lg*X22BjKH&|ad4a*(4CbE8OQ2ly5J@usiA@o|ay=8F&!ki4w zs^<$-?4^EhbT*1Ro1dTY)fDEW=7q}wCnS`;8x{HJGn>OKQByIDXYqyAe z;_vY0zP|bva#6+;!YF-i++@x2VOeTnq&_@CpkN=50)8PXk7~Oj*u%G#kt(~P4L(ub zllAa^b9xn+mFR$E8j~@~zu2-b8B-7VQ{qd0py(uI){=Fg@q!$etgi{HcB^%(lgg97 zD~JQf$G_QG54|}f%oAbquM|}e2&twj9>p1F*~V^ocy7Bc;n!yPA?hv?Vht1CrZ}H5 z%-F`rG!N9z)V7$|{`u~3AFxS+Ey>#sK?mFML z`L>JL(5Y87sy;8!gpQ}iJ%B<7Je&6(;W^nuuZ2mXCU-mxuIoNyFJ~E|mJ{65rsajo zj5ihM3M&-;T>(Tco~28UurmpIaC|;&U6aT8(hA4kU4Jy%`~uu=a~W{e<0d1$A}`>b zxf3+c@0S5z55JB8uWRJR5Xqarq^55VYSgRAeaUFIQo#S8+phnj7|?V>?~G6EC0hrM zSdPm_?-yLszs_5Il!wgjbkS$dN9o65)T6$0-{3rCUO%aP zuip+{oYavvEIl#w{$j*ydvvr-`zY0~)beP7V>lpYhwezV8ih??X9$`;UAVO1fuPL^ z(a<+1^og+5d&`;PVs*$iv^O4wXyj4={Q2Ze?e>ddb-@W55deOz7*qePh6DSbBt_>h%i-p)9 zW6}I4j(ywU4;fuI+Fl!9DDYKHk9Pv#?`%d75x3%vZZ0@l&Nkk7Z@$qE)Q`p44HGGG zw{Gv7<0g7kXj{@}(`dQBeYGD%v|a_?()pmtm5ba`^)dN&E4X(5*sUm}>S9|{&kJkgso_=O}1?( zD6}suw$7{=(VWu+JHGzgql8Z65-Axw1nclw^@nfL1?m*5=JB$iFsNV|!Hos^zQN!P z)6CZpCcAvxjQe@8_EI)L4;@~N>T(nq^}%&~KO{?)lBB8veK)_@@nXC~LmcWJxCz#5 z?N&`R7&3deZg;r>A!ygm0Lu4#p~aC;w6M+}A3`xcdd$M1)bRU2_!>{S481vm7dJ*P6(CKVl_H5q%AG6w0rdI?{5o!`Pp3xtmJUHpP8T8l zple+F$f~2X6k9Cd%M))AVVx3oZ=nLE?OIFKwE6zpY_b#yv_UgWBvERpg z#>Q~(j_EELpp}jPuB$*qie&y`JwsRjNs}VogkhTwnw0KzukGQFTwIS51O|PzWV}S< z!y^SX#JKT|?_1%tH7`XHUXwyDFtay;MjtPp3<$x9`yMZb04psIf!B4LBehGcMR5uz zVlPt&zl}Lz6{}TqR>q%ushYAbpJd}gT3Zeo$2(O|4x2dqWx1%u4&_@WOn+K1cxNat ztQbKNit193*+<6~z6h1VE#B@1$CHGG+hi8)14 z_7r{W7!Q}c>Mo;cOEYL5_aCQ(_%7|Qw%EZi%K^hYx)w_S^$XCPQh^no8=bGN=9s6#& zgX}zzz>H`uU?^_s?6l-co=)E**LGKOdqTQricD z;i6FG<$aCVz4(WtivKoIuor~Jj_Ll!c}694PTz&c?#x^53j)2RUM^45zVpCFT&-*m&!-8e|{HA~r?#b#q=xWncQ|~13)OvA@GIy>dxMIs8;s{=|W`gk7 zaWyBB1{3zn<{jNPc0zGmvMLo?TG&Jdz7jKog@`k`a@JKU@jSt2#}WDr%{Em_Xz)uw zs)J3lS?IS#7!qCA-ZBiNDDoQcp6Yq(RsjTRNU9Y288ap@_K;P_SplHEydQZ}Sk_CE zZq!abKk~jQdD37DshmID2m?`@iD4=7J8VY91*f4X4L7u(AXYnwP6{`!TRhRgOfeeAUu?!kHLeGQgCTj zHykJG!#OtBAG@W$28d8#Yx(Eb;?Lc~SMCNv2lIluB))L^hsso>$71qi20u?%YD{qz z#P~2l>c8>l3ljSGmL0hg+0Uw$`@v6$#=j~`u8MRz^6UHeRX7b`p}-lk!vz&m7yK%Z zCgJF#Jwnspw~dlhTEf>7o2tx3^%fC3_ zhZJj~{00#Xz9&)vA^jq(o`(PmoyG{lb0~({%(}QZ`?|m? z*`jnP!-QdnFGGU;Ds=u=`!J~AH&`Cy<802(xvP>RBnr7ni8X1?TMC;BY(JspjoplT z^OawWq}9Bp#590bi&VXt&-sj~;;I z2!c2tP$*SZZ>b)*D0E)9p#O^s-NvLv@&K#y+}||-eHs@K2Plfe;mD#fB6H|jcxCnj zg=tHt4_xR`$wf(fWNV!PS z*1Sta1*HkAGndJW%Ke7`8QJoIDUP7jKviEXE?r~;CQii0z^ui~;7%AbL3`1hgcxgF z%{LbA;XsC>5Q(|oslJ8HK7=ukrqI|4K;7qpHVtFI5#VCvmDhgdjemW>St@XFSeAV~ z@?Fc0hj5I}NP=`lo76m}yj~CO&y~!$<%;<_TLl#Ns6Z>)DL!Lj_p>WftC!8Nd-&d|^;&Gl#q*TrAkJ0Pd$lNqiTM zDS_w;?g>;f2^l0}LAS>ZUGdJ_2vRk9rLYy4^bEG5EWq$30T$@n1ZN1^hY|FKZ(rHWOH5vQf>4y1D}}w>w*Lz1rf9GiE&yGqkr>u4f&;;c|BJ;ZvdJIr1DLvN z43FxbJlEde9yJf*YP%K0_-2Gi$E=4W8}$MFU_^D-)L6C>D~kKr%S6!kt-0mcPZEMK2OL zw16c;Ip?3Tdm~7K-snfxyzMFt<9$uByvUba{%9(L z1F|Lc21GjnClBM8xi+Sj7+0*iya8{)bu)8_>$ALja^!8R^{C<`hOV@v*Tk zE75FzxTnL+r9{%xrAsDeakPBefu-a12r=mY+(+R`hKSg6gHMIN zvP>N2pB9X@`h|)YFTl%MFngDi#U(k#qK}YIu5+7Mo$9EFgo9%DOWSr=v%jf)S z4O92s%MinR!zZq*X^(>r-0ujRGx?=^nO-)bt_(CzPU=kU4l^buPbFK&C63X^16gL$ zZ8E^KneEOzyI3}IcTz&BD5h{PcJ0OG0Yy?hBjYW*B_%~gXF@Br#k_mjX|(e_(9h+5 zA0Ee*J9ZjV%OE_0e6Wdm5i_4@n~X?2t*k(rg0<0Oe|65^yu!4u_g)0b_T?!G70i2nqTU;f4ypS$P@w$k3Z1bkUP8UdF+yomkKI%Y z_Plvl-dr_OH4o&?nE6sP_#?g!jy`3L9-as?GUyGouYn!!n^9D6N5HWvU*sa#ATKzE z-lKT$#kYEwuVFjzl{6T%r5{@EcR3lbb@^q*geyX<4vC_h*uEhAkViE-&|YQ zAuAYE?sJv@FmkQ@Ho)p)^i?4*OGT4F(TI3$d{oYkL@5L-y|+N$_vb z$3A@w2B#)!sWR{ZuHg1PG^2DCoimO%L`4@3%{#(7!iAnzqxav>Q5W{bwAE07TA>x{ zCrCTg?F$-T4_UlZL3Y(jlBCISgFnZhi?_o02$#N4uMDM9DXG+^*16uMBFm^mo?c^z6gO`S-<-2zqJmMyH+pYY-%)*P6?ez93A2jSH|N@@WED)#|I{;Xfz1Ep-tuPu z*PB`J@4x6DxZ|Omm!O=`1cIp{&vMK^!<8>V0luF6`pZ)Mi1;;4gb!JC&83$?a0=k> zcV-oASa%4TrJ6!>qDUuHt*=hGvj5K52c(>#Yr`+_Dt;mTQP>l6Za+oeL(K?|Tk<~& zzmYJrg;2OzK0n+!L<}~OD^6IruT|aSIg;f^@ZflSwZokRhLv!SD@3m~V&XYCTvADG znuMx6VH+F!uJ8eBeHZMqXgLju;+f~eZd*$lwx1w149eNi8PH9$Q_kK|Y5lK>suNJnO)vLG2R}T@01%xJwKU?jUJVpg4@nZ))tUE+ zLBogC)j+Tg76`la50cWMO`H2f4;fg9^hAvi2*<;^(Mzom+K|HhSY4AxH~)*_8CvlM zNN@WbBdl4Y` zk5E9F$;WvWQbqLcZux$0Eem7hRN313ejpmLw7?|239J^6C}ip8ob3fi5+8dJ@$H_u zEgjs$dXyvqo}J0-WI61H4+O@5CqTngJqC^Hc}=FeD%x?93!t5P>se;@gLbqgMR+Qk zvsqzv7`Z6EoW#9ElMLRg9c@P2!uiq41efXP5#8m)&8!(-=%U2Iy^`WLo+7WClFyQ` zxg;?vxbay21zg)MmZ1x7Y-*3y72WGW5n1;EyAteS4FyR_uE{+j0{6`~u_$|w#{HP} zg|feteZLFxTUzx;K`yH$(if&?Yu;D$7f4U7NgA&HMt)cEa<+1d`(HFB?+GnGl9ZV> zKq@YD?RqMs3`|u(gYop}Y-uRfml3{2is_cL-p*tO%A-{2?rb`OwOWn+gBFC#1a6y+*`G;RL6nvHCeF16_Lkoq;T;PQum*s+Vm-X_eqo> zP0ext$%)-rfE%GKB@4v-MbJe$Z&;?<(2Okiv~9Z^k}fX>=_;<{A88zON~f~t3wDIo znCH4VILA>+$TX+FZRpN-ZQU;dio(N7?2GY^GP*a%*!uannw6mt;zPz3N9 z%)49|cT9?c*F1syE$HN1l~?4?C%W|XMvPOi?e3Vx!!y$vs4EB|mweI6D>*Jrw%;6K zpqP_Q80A8{zW(ff#PNronmWx(7Mj$^V=unsI(>!}4*OVryxRhYiK1X#uSOBi8g{hW zL9ybib{0XMs=k{t2pgOLE77%bGrY)Thk?OV*f~#z45kQ+*u(+OTbv7Byb%oz4K-@k zi^x!3yarDmh59ZqKPBgIpRzumzwEzF+e;plucG=7Jxe-sHvG>iJYM=3^dcG>8fw&W zuy9oWiKm*lP>OzI!vCt-bedeEI0)=K;&|(JCgfQ5tTmjp*~;(`m){x#tL8tm&v{vO z(aU7E1n^eMFM`^c>B`ztFdp&tsL(4ykVi2BosF@w4mT@BR1Nu6ZLd8BT4I7wfz@It0&VVD80T`# zE3`Cvcy<2vCZcJ(W?~QfBeV|o7~eUVg9$#`=1oZFPgKxqtZF@1;yS)Zn@laZ#0PA^iKx=k%N$B-F z3h_FLS{(cmH5X)E;_0(Iyk~O#LDa%VY(Ki2jSaVj=c2XnWl8w7B6NpkVOJR71UXys zdO8#|2XULkfi7H1I#D~i5jdAq5`k!UZ(#i^C#DNjfLGcE#X$}_UT$(h*WKhdYO)?} zNpn=uEkmwKc(f&@5vG@Qum=ozh*#%#V_%|y>a7^$h8a#Rte7E<%=4!dA}@Aj#8fe4OynHMZ7`kNA-B7? zZ)bo1TwZSL?roO^)4YP165B{*Qi(B=GJyNn6_cdVc78^t+T%iMMn)LRcy^`2wmJEh zT6k~d0RwuT!8YvbuW&gbjJ1{>>AFk~dix|c6?1$T?XZ$9X%1u*2(A*|!f+fiLsDbL z4&h}O%&6u!`ta_YMGE#ls&tr&_^vzei5?u zqabK+0^a-)usyFCZS5Gy%hEg}*$`j0iVobvNYh+Txo%NbtB`ehO{A=36PMWIqu>X9 z#U*s3`QL^TfQ>nTU-G~8gmE49lj$sFb>MWHz4-q*sq9t(+uTAxuh|dTZulP*d#Q?P zj1CaEJwo|=O|9d2NJ$B~$6Z3u$wixLJWs3w5%(VBr^&d_03NHhKI!{{6yTkI9F3#_FVPZd{dR^94aGRJ1@DD1r-<5c>?B&%{XFYEp z(qeUtLj6+R+j;H3I~* zl`#*LeN5%k`KE3-=V9~$wczFO?eGqXT!>>-l)fA`WYhX(SPs*s(B=5*2Vb(+TKr=} z6bJS0Rm;Z-kzANqU5;YT;&t@UIAPcJ8_4%?zD-0MfXUVOD98uQPN{BVs7zFKm{$Z< zjkVqk){A4(?eSYp6(|Sl_aj(U!1V!|IDz}|H^wu8E(c_2uySTG+~AFPfqhjv?`>_^ z-zJ;yzIt0R+7M@#D*G-c;ErA6I@EK%l!pVPV|2c)M{U1{=^G4n?YPoD_mGU0aLX(& zktO*&J6MtT%G$9?^|9Lx1GlV85ZLr?P@MGkyf@&qCBmzj2k(<#&lU}C7TqZ13$aM? zA{7;$26fS1+#c%89JBZ;haW#I(*IxPA3tV!`u5l}@$9?%306Vet1R>F3KOr#r|@3P zu=Q|&<#;L3D$MiPOer%eMHX%nWX{Qzlh`sc#*g3UCF_?Tq;)xD>vpSt3UZ~(uiBrS z-ks~(hb=~CE~D5%v$%o(7Bo+CgPQ_*o|biah!RFQZ#rT}ae*Vd|_)lIbN1UpEB_Ds9i%=Z5Xrhv^_K~Hz>L0f4Uy;@JojEcqpWM_$4_4LN@?+v|6+{YH~4tBNq zN6Ol5BkB|NDtEif@0rP`25k@cQ$C#DO;Mk(?pA}`vt3!zW8#3?FxlMO$iWGN=i7$2 za0hRG1u*&W)|7MTpqe@r@E)`V5W<8R_nB4b3lsFg7z=`B8E8s7umN*{AJDYslrYlK zp<~c&c;5n$!HyGTpK7=+{_G4>czD?ngS4^(vEo2M6$iz8$H|APPZYbd_~29u4rF$! zzH)4rL%_~7!7hmFe>Gsi`OoEAFIf)^+SXG}KtMoT2a2UlD`Ax4x^e(?NxfTH=`D1LhqLu7vGfbj zaeyjD4A{|#AXhS5HUMW&{xeYiknmseKODVnjv79yRqgy+@dHtWqWb5xU}iyv@k^es z>(Mg4^9XOYpXsOiAM^KM{Zuz7oCiUMb^@l6okx+9B7xNkTm{gO$musXNQFw^YaFew^JWcEYQ68(P z{d5GU1JEBs_7yC0C!Lck<;IoC3m4sb*sr%|L5C_;#yJfZq5EgyoWhdl4HnA2^Zz`7 zmx>om%D5;iNehC7_NxXj<=<9f$yi{9P5Sn^hEu_3w5Fj{IQFuw03$7>entJ{Zav9_ zCWz)q>qlXS98Q|_p#hr~(k0{sLkgYQNR&W&lOu&uVV&VlgU!dLwNeUaazhZ3xih=6 zXw|wzjLA*I&WWM#?dB%N4;qK2q^xU9Sw1nCDxpr8j-DX2eAOhp=u>r`23zMPWW!sx2ECX)04x}r({QYK(p(FSmQWff)}Ru+~4cHA>77K(6R z?uIaAVGT?i4vCbMw4l6ulQJsk{geP+8z4;u<{IJ=Yif|O*s;m*jOH<-92f$4xn;_9 zH(k+UT($9{i5S%v($0obX6CZl-vnHQyk*dfQwjq6D-*N!Uu=Na1ZFz(ZLnv8 z$;`yt&18Mx)J~b_4s#|=BC2v4#Lhm1YvCP%syU@u!PPHUr(B93?_$S9I8Y;Hg0(_c)@ra~L9-P#il}*TeO>d&GjzG%{e)Nx z2p)L2gXiEBC5Idr%$8RZ=Z@${Kl=9^cUFSq0H9{JalL%Vz}oa;4*Ux!Frna9Gjds_ zM=!vjd8)RiL_~#CK#3CVRj=-#hLNm%-&Kk8EVDGS&(sGKPOf@Av0KlhNn}rSpItWf zq8)XOiw21SF9CMb2*L_`zAo>+19oEnBT-&lfj11+EdvB?W0@ItycQPTn%vpe7szY2 zzkN&jvf%)Afb0ptef(}?ezR z!29vIAif3foosu{J!FgvjL)xmS~d;smEg$+D5MstcS93WLrRO<+Zvn|6IR>$K@G6K z=n#AwT8Jb#J?l)f?-N2kIiV7bhiGY`X*R=RYygSA_kWH<{rAV3+%Z5#` zYT|IOy9)j_=>NeSBRajB@%#QiK~vIoJG1UXsA`2znM`0drapk~11X#E%eBEm*fWap zL{Fs?_d839f=OuEH>Sz6b-NZ8Rp4qN%4r!l)+7(yw;6?x_zTL(?QyfCIyM9J)0vy- z1!!o~W3uw=CZKSJ)A4jQ-AJ@QgJ6SX{Nw}=75 zXVYI6bn7;Tb&B^l9NbH%BSj?*)vmsgG291JsaVm_x;`dPKb^{+MB^Ut%&r|kGQln7 z=-vAo7VR;}lCoz0>PX%H`un0g5SPcg4fw;R3HdmSmhDpyM{Z2%oq5=wIiHtxFp3uS z&!NqJfB%3@>sPhEq1gr+F+}Q9?jTw;23+9|9ceWyAm!yoCwD&|2kmYOorg=;Q`a9w z@4nRc=DA`kC%hiVeSHkDn;a71EMyk#56vGGP_rua|1*6=;FsY~F&pN@k=jH-2dM{Q&%r2X@sQt+PC9OUpDY*Uv{mQ6u|m9$ z;F2#kty!~eP3J)FJ}OC9Li|Qe9hKy(bF{`rvF)^Woer+I-6#p{{+79HibIsw_Kg{#)@NX-6Uv82wsqs2Va!c~_#_qZ z$TZtiXu#Yv!O$SB=)=1(>}O`ot#7MPH%(?9O)|w?VK$s2lb9qu>$?mZ^wN#pxK6`h zv~hov4#8GG5(sblMyuzE4R7C#VRRK4+{I_5Y1!gY*)1$P=8;M-^ZUl3tShMDA0e+H!)gIU+larZF#3?xCewHvPfD5e6xl zB|}qhDmcBanYQlioPB$PKIjit<81gpn{BcieW@Gffcfc9r|o(QqEb;8z3w?cxbe?j zG`{ibYl`xR0YcpIj-}h8%OTX{F>xKq0zs;Mnxm0(U|;|aipvuwCG6&NY(MD*btQmr zu|?-Nyl1<}R;2iws=Nu{z<~pgc8P%=Q7Ng`L=TE$7NthKL^XoEV(yQXc2Q`!8O80b41xY>ym+NN1!4U7ulZ>z9Be7xbW9 zad-q1<7CEkdrhlCd)tt8Wt;eCT50GvHi zBWz?G_5&0!1`Ln&LmW6f$GhJ(Nj5D&GOW4pZ3J}xz$!dg>MQyGqUFk|aat5X(l{@- z@lrrt+|uTR)Q&v{T@fsi#dluForsBFHFM_Ngs+8!xBTK66?3I%jtEj*u&05FVPBa;=$R6Y$gN$#-6#z|J2@>RAq3OUU3PePkIGwHt%1@)G+i06xM z^Ud(}5jQ460ZpeQV>qTp>3Eh@4Z4 zs?fn%�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 H1^@s6diG)a literal 0 HcmV?d00001 diff --git a/public/images/Logo_Landesverband.svg b/public/images/Logo_Landesverband.svg new file mode 100644 index 0000000..4ec7ece --- /dev/null +++ b/public/images/Logo_Landesverband.svg @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/images/kigu.svg b/public/images/kigu.svg new file mode 100755 index 0000000..4d96dbd --- /dev/null +++ b/public/images/kigu.svg @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + diff --git a/src/Contao/Manager/Plugin.php b/src/Contao/Manager/Plugin.php new file mode 100644 index 0000000..b86f412 --- /dev/null +++ b/src/Contao/Manager/Plugin.php @@ -0,0 +1,34 @@ +setLoadAfter([ContaoCoreBundle::class]), + ]; + } + + public function getRouteCollection(LoaderResolverInterface $resolver, KernelInterface $kernel): ?RouteCollection + { + return $resolver + ->resolve(__DIR__.'/../../Resources/config/routes.yaml') + ?->load(__DIR__.'/../../Resources/config/routes.yaml') + ; + } +} \ No newline at end of file diff --git a/src/Controller/FrontendModule/MemberSurveyEditController.php b/src/Controller/FrontendModule/MemberSurveyEditController.php new file mode 100644 index 0000000..12ac2f7 --- /dev/null +++ b/src/Controller/FrontendModule/MemberSurveyEditController.php @@ -0,0 +1,273 @@ +getUser(); + + if (!$user instanceof FrontendUser) { + $template->set('loginRequired', true); + $template->set('backUrl', $this->resolveListUrl($model)); + + return $template->getResponse(); + } + + $survey = $this->resolveSurvey($request, $user); + + if ($survey instanceof SurveyModel && $request->isMethod('POST') && $request->request->has('_survey_action')) { + return $this->handleAction($survey, $request, $model); + } + + $questionChoices = $survey instanceof SurveyModel ? $this->buildQuestionChoices((int) $survey->id) : []; + $surveyForm = $this->createNamed('survey_meta', SurveyEditorType::class, $survey instanceof SurveyModel ? SurveyEditorData::fromModel($survey) : new SurveyEditorData()); + $surveyForm->handleRequest($request); + + if ($surveyForm->isSubmitted() && $surveyForm->isValid()) { + try { + if ($survey instanceof SurveyModel) { + $this->surveyEditorService->updateSurvey($survey, (int) $user->id, $surveyForm->getData()); + $this->addFlash('success', 'Die Umfrage wurde gespeichert.'); + + return new RedirectResponse($this->buildEditUrl($model, (int) $survey->id)); + } + + $createdSurvey = $this->surveyEditorService->createSurvey((int) $user->id, $surveyForm->getData()); + $this->addFlash('success', 'Die Umfrage wurde angelegt.'); + + return new RedirectResponse($this->buildEditUrl($model, (int) $createdSurvey->id)); + } catch (\Throwable $exception) { + $this->addFlash('error', $exception->getMessage()); + } + } + + if (!$survey instanceof SurveyModel) { + $template->set('loginRequired', false); + $template->set('createMode', true); + $template->set('surveyForm', $surveyForm->createView()); + $template->set('backUrl', $this->resolveListUrl($model)); + $template->set('publicUrl', null); + $template->set('survey', null); + $template->set('questionForm', null); + $template->set('conditionForm', null); + $template->set('questions', []); + $template->set('conditions', []); + $template->set('editors', []); + $template->set('submissions', []); + $template->set('activeQuestionId', 0); + $template->set('activeConditionId', 0); + + return $template->getResponse(); + } + + $activeQuestion = $this->resolveActiveQuestion($request, (int) $survey->id); + $activeCondition = $this->resolveActiveCondition($request, (int) $survey->id); + $questionForm = $this->createNamed('survey_question', SurveyQuestionEditorType::class, $activeQuestion ? SurveyQuestionData::fromModel($activeQuestion) : new SurveyQuestionData(), [ + 'question_choices' => $this->buildQuestionChoices((int) $survey->id), + ]); + $conditionForm = $this->createNamed('survey_condition', SurveyConditionEditorType::class, $activeCondition ? SurveyConditionData::fromModel($activeCondition) : new SurveyConditionData(), [ + 'question_choices' => $questionChoices, + ]); + + $questionForm->handleRequest($request); + $conditionForm->handleRequest($request); + + if ($questionForm->isSubmitted() && $questionForm->isValid()) { + try { + $this->surveyEditorService->saveQuestion($survey, $questionForm->getData(), $activeQuestion ? (int) $activeQuestion->id : 0); + $this->addFlash('success', $activeQuestion ? 'Die Frage wurde aktualisiert.' : 'Die Frage wurde angelegt.'); + + return new RedirectResponse($this->buildEditUrl($model, (int) $survey->id)); + } catch (\Throwable $exception) { + $this->addFlash('error', $exception->getMessage()); + } + } + + if ($conditionForm->isSubmitted() && $conditionForm->isValid()) { + try { + $this->surveyEditorService->saveCondition($survey, $conditionForm->getData(), $activeCondition ? (int) $activeCondition->id : 0); + $this->addFlash('success', $activeCondition ? 'Die Bedingung wurde aktualisiert.' : 'Die Bedingung wurde angelegt.'); + + return new RedirectResponse($this->buildEditUrl($model, (int) $survey->id)); + } catch (\Throwable $exception) { + $this->addFlash('error', $exception->getMessage()); + } + } + + $template->set('loginRequired', false); + $template->set('createMode', false); + $template->set('survey', $survey); + $template->set('surveyForm', $surveyForm->createView()); + $template->set('questionForm', $questionForm->createView()); + $template->set('conditionForm', $conditionForm->createView()); + $template->set('questions', $this->surveyQuestionRepository->findAllBySurvey((int) $survey->id)); + $template->set('conditions', $this->surveyConditionRepository->findOverviewBySurvey((int) $survey->id)); + $template->set('editors', $this->surveyEditorRepository->findEditorsBySurvey((int) $survey->id)); + $template->set('submissions', $this->surveySubmissionService->getSubmissionOverview($survey)); + $template->set('activeQuestionId', $activeQuestion ? (int) $activeQuestion->id : 0); + $template->set('activeConditionId', $activeCondition ? (int) $activeCondition->id : 0); + $template->set('backUrl', $this->resolveListUrl($model)); + $template->set('publicUrl', $this->resolveReaderUrl($model, (string) $survey->alias)); + + return $template->getResponse(); + } + + private function resolveSurvey(Request $request, FrontendUser $user): ?SurveyModel + { + $surveyId = (int) $request->query->get('survey', 0); + + if ($surveyId <= 0) { + return null; + } + + $survey = $this->surveyRepository->findById($surveyId); + + if (!$survey instanceof SurveyModel) { + throw new \RuntimeException('Die Umfrage wurde nicht gefunden.'); + } + + $this->denyAccessUnlessGranted(SurveyEditorVoter::EDIT, $survey); + + return $survey; + } + + private function handleAction(SurveyModel $survey, Request $request, ModuleModel $model): Response + { + $action = (string) $request->request->get('_survey_action'); + $itemId = (int) $request->request->get('item_id', 0); + $token = (string) $request->request->get('_token'); + + if (!$this->isCsrfTokenValid($action.'-'.$itemId, $token)) { + throw new \RuntimeException('Ungueltiger CSRF-Token.'); + } + + try { + if ('delete-question' === $action) { + $this->surveyEditorService->deleteQuestion($survey, $itemId); + $this->addFlash('success', 'Die Frage wurde geloescht.'); + } + + if ('delete-condition' === $action) { + $this->surveyEditorService->deleteCondition($survey, $itemId); + $this->addFlash('success', 'Die Bedingung wurde geloescht.'); + } + } catch (\Throwable $exception) { + $this->addFlash('error', $exception->getMessage()); + } + + return new RedirectResponse($this->buildEditUrl($model, (int) $survey->id)); + } + + private function resolveActiveQuestion(Request $request, int $surveyId): mixed + { + $questionId = (int) $request->query->get('question', 0); + + return $questionId > 0 ? $this->surveyQuestionRepository->findByIdForSurvey($surveyId, $questionId) : null; + } + + private function resolveActiveCondition(Request $request, int $surveyId): mixed + { + $conditionId = (int) $request->query->get('condition', 0); + $condition = $conditionId > 0 ? $this->surveyConditionRepository->findById($conditionId) : null; + + if (null === $condition || (int) $condition->pid !== $surveyId) { + return null; + } + + return $condition; + } + + /** + * @return array + */ + private function buildQuestionChoices(int $surveyId, int $excludeQuestionId = 0): array + { + $choices = []; + + foreach ($this->surveyQuestionRepository->findAllBySurvey($surveyId) as $question) { + if ($excludeQuestionId > 0 && (int) $question->id === $excludeQuestionId) { + continue; + } + + $choices[(int) $question->id] = sprintf('#%d %s', (int) $question->id, (string) $question->question); + } + + return $choices; + } + + private function resolveListUrl(ModuleModel $model): string + { + $page = $this->resolvePage((int) ($model->surveyListPage ?? 0)) ?? $this->getPageModel(); + + return $page instanceof PageModel ? $this->generateContentUrl($page) : '/'; + } + + private function resolveReaderUrl(ModuleModel $model, string $publicAlias): ?string + { + $page = $this->resolvePage((int) $this->getContaoAdapter(Config::class)->get('surveyReaderPage')); + + if (!$page instanceof PageModel) { + return null; + } + + return $this->generateContentUrl($page, ['auto_item' => $publicAlias]); + } + + private function buildEditUrl(ModuleModel $model, int $surveyId): string + { + $page = $this->getPageModel(); + + return $page instanceof PageModel ? $this->generateContentUrl($page, ['survey' => $surveyId]) : $this->resolveListUrl($model); + } + + private function resolvePage(int $pageId): ?PageModel + { + if ($pageId <= 0) { + return null; + } + + $page = $this->getContaoAdapter(PageModel::class)->findById($pageId); + + return $page instanceof PageModel ? $page : null; + } +} \ No newline at end of file diff --git a/src/Controller/FrontendModule/MemberSurveyListController.php b/src/Controller/FrontendModule/MemberSurveyListController.php new file mode 100644 index 0000000..a8aa428 --- /dev/null +++ b/src/Controller/FrontendModule/MemberSurveyListController.php @@ -0,0 +1,80 @@ +getUser(); + + if (!$user instanceof FrontendUser) { + $template->set('loginRequired', true); + $template->set('surveys', []); + $template->set('createUrl', null); + + return $template->getResponse(); + } + + $editPage = $this->resolvePage((int) ($model->surveyEditPage ?? 0)); + $readerPage = $this->resolvePage((int) $this->getContaoAdapter(Config::class)->get('surveyReaderPage')); + $resultsPage = $this->resolvePage((int) $this->getContaoAdapter(Config::class)->get('surveyResultsPage')); + $items = []; + + foreach ($this->surveyRepository->findEditableByMember((int) $user->id) as $survey) { + $surveyId = (int) $survey['id']; + $isCompletedInCurrentSession = $this->surveySubmissionService->hasFinishedSubmissionForSurvey($surveyId, $request->getSession()); + + $items[] = [ + 'id' => $surveyId, + 'title' => (string) $survey['title'], + 'description' => (string) ($survey['description'] ?? ''), + 'isLocked' => !empty($survey['isLocked']), + 'published' => !empty($survey['published']), + 'questionCount' => (int) ($survey['questionCount'] ?? 0), + 'answerCount' => (int) ($survey['answerCount'] ?? 0), + 'editUrl' => $editPage instanceof PageModel ? $this->generateContentUrl($editPage, ['survey' => $surveyId]) : null, + 'publicUrl' => $readerPage instanceof PageModel ? $this->generateContentUrl($readerPage, ['auto_item' => (string) $survey['alias']]) : null, + 'resultsUrl' => !$isCompletedInCurrentSession && $resultsPage instanceof PageModel ? $this->generateContentUrl($resultsPage, ['auto_item' => (string) $survey['alias']]) : null, + ]; + } + + $template->set('loginRequired', false); + $template->set('surveys', $items); + $template->set('createUrl', $editPage instanceof PageModel ? $this->generateContentUrl($editPage) : null); + + return $template->getResponse(); + } + + private function resolvePage(int $pageId): ?PageModel + { + if ($pageId <= 0) { + return null; + } + + $page = $this->getContaoAdapter(PageModel::class)->findById($pageId); + + return $page instanceof PageModel ? $page : null; + } +} \ No newline at end of file diff --git a/src/Controller/FrontendModule/ShowSurveyController.php b/src/Controller/FrontendModule/ShowSurveyController.php new file mode 100644 index 0000000..f2bf974 --- /dev/null +++ b/src/Controller/FrontendModule/ShowSurveyController.php @@ -0,0 +1,126 @@ +resolvePublicAlias($request); + + if ('' === $publicAlias) { + $template->set('errorMessage', 'Es wurde kein oeffentlicher Link auf der Anzeigeseite gefunden.'); + $template->set('question', null); + $template->set('surveyForm', null); + $template->set('isComplete', false); + $template->set('answers', []); + $template->set('survey', null); + $template->set('progress', ['current' => 0, 'total' => 0, 'percentage' => 0]); + + return $template->getResponse(); + } + + $survey = $this->surveyRepository->findByPublicAlias($publicAlias, true); + + if (null === $survey) { + $template->set('errorMessage', 'Die Umfrage wurde nicht gefunden oder ist nicht veroeffentlicht.'); + $template->set('question', null); + $template->set('surveyForm', null); + $template->set('isComplete', false); + $template->set('answers', []); + $template->set('survey', null); + $template->set('progress', ['current' => 0, 'total' => 0, 'percentage' => 0]); + + return $template->getResponse(); + } + + if ($htmlHeadBag = $this->getHtmlHeadBag()) { + $htmlHeadBag->setTitle((string) $survey->title); + } + + $submission = $this->surveySubmissionService->resolveActiveSubmission($survey, $request->getSession(), null); + $question = $this->surveyFlowService->resolveCurrentQuestion($survey, $submission); + + if (null === $question && '1' !== (string) $submission->isFinished) { + $template->set('errorMessage', 'Diese Umfrage ist noch nicht vollstaendig eingerichtet. Es fehlt eine gueltige erste Frage oder eine verknuepfte Folgefrage ist nicht mehr verfuegbar.'); + $template->set('question', null); + $template->set('surveyForm', null); + $template->set('isComplete', false); + $template->set('answers', []); + $template->set('survey', $survey); + $template->set('progress', ['current' => 0, 'total' => 0, 'percentage' => 0]); + + return $template->getResponse(); + } + + if (null === $question) { + $template->set('errorMessage', null); + $template->set('survey', $survey); + $template->set('progress', $this->surveyFlowService->getProgress($survey, null)); + $template->set('question', null); + $template->set('surveyForm', null); + $template->set('isComplete', true); + $template->set('answers', $this->surveySubmissionService->getAnswersForSubmission($submission)); + + return $template->getResponse(); + } + + $answerData = new SurveyAnswerData(); + $form = $this->createForm(SurveyQuestionAnswerType::class, $answerData, ['question' => $question]); + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $normalizedAnswer = $this->surveySubmissionService->storeAnswer($survey, $submission, $question, $answerData->answer); + $nextQuestion = $this->surveyFlowService->determineNextQuestion($survey, $question, $normalizedAnswer); + $this->surveySubmissionService->advance($submission, $nextQuestion); + + return new RedirectResponse($request->getUri()); + } + + $template->set('errorMessage', null); + $template->set('survey', $survey); + $template->set('progress', $this->surveyFlowService->getProgress($survey, $question)); + $template->set('question', $question); + $template->set('surveyForm', $form->createView()); + $template->set('isComplete', false); + $template->set('answers', []); + + return $template->getResponse(); + } + + private function resolvePublicAlias(Request $request): string + { + $candidate = $request->attributes->get('auto_item'); + + if (\is_string($candidate) && '' !== trim($candidate)) { + return trim($candidate); + } + + $queryValue = (string) $request->query->get('auto_item', ''); + + return trim($queryValue); + } +} \ No newline at end of file diff --git a/src/Controller/FrontendModule/ShowSurveyResultsController.php b/src/Controller/FrontendModule/ShowSurveyResultsController.php new file mode 100644 index 0000000..01c8744 --- /dev/null +++ b/src/Controller/FrontendModule/ShowSurveyResultsController.php @@ -0,0 +1,93 @@ +resolvePublicAlias($request); + + if ('' === $publicAlias) { + $template->set('errorMessage', 'Es wurde kein Umfrage-Link auf der Ergebnisseite gefunden.'); + $template->set('survey', null); + $template->set('questionResults', []); + $template->set('completedSubmissionCount', 0); + + return $template->getResponse(); + } + + $survey = $this->surveyRepository->findByPublicAlias($publicAlias, false); + + if (null === $survey) { + $template->set('errorMessage', 'Die Umfrage wurde nicht gefunden.'); + $template->set('survey', null); + $template->set('questionResults', []); + $template->set('completedSubmissionCount', 0); + + return $template->getResponse(); + } + + if ($htmlHeadBag = $this->getHtmlHeadBag()) { + $htmlHeadBag->setTitle((string) $survey->title.' - Ergebnisse'); + } + + $resultsData = $this->surveyResultsViewService->buildForSurvey($survey); + + $template->set('errorMessage', null); + $template->set('survey', $survey); + $template->set('completedSubmissionCount', $resultsData['completedSubmissionCount']); + $template->set('downloadUrl', $this->buildDownloadUrl((string) $survey->alias)); + $template->set('pdfDownloadUrl', $this->hasGotenbergConfiguration() ? $this->buildPdfDownloadUrl((string) $survey->alias) : null); + $template->set('questionResults', $resultsData['questionResults']); + + return $template->getResponse(); + } + + private function buildDownloadUrl(string $alias): string + { + return $this->urlGenerator->generate('mummert_survey_results_export', ['alias' => $alias]); + } + + private function buildPdfDownloadUrl(string $alias): string + { + return $this->urlGenerator->generate('mummert_survey_results_pdf_export', ['alias' => $alias]); + } + + private function hasGotenbergConfiguration(): bool + { + return '' !== trim((string) Config::get('surveyGotenbergUrl')); + } + + private function resolvePublicAlias(Request $request): string + { + $candidate = $request->attributes->get('auto_item'); + + if (\is_string($candidate) && '' !== trim($candidate)) { + return trim($candidate); + } + + return trim((string) $request->query->get('auto_item', '')); + } +} \ No newline at end of file diff --git a/src/Controller/SurveyResultsExportController.php b/src/Controller/SurveyResultsExportController.php new file mode 100644 index 0000000..df41ae9 --- /dev/null +++ b/src/Controller/SurveyResultsExportController.php @@ -0,0 +1,61 @@ + 'frontend'], requirements: ['alias' => '[^/]+'], methods: ['GET'])] + public function __invoke(string $alias): Response + { + $survey = $this->surveyRepository->findByPublicAlias($alias, false); + + if (null === $survey) { + throw new NotFoundHttpException('Die Umfrage wurde nicht gefunden.'); + } + + $finishedSubmissions = array_values(array_filter( + $this->surveySubmissionService->getSubmissionOverview($survey), + static fn (array $submission): bool => '1' === (string) ($submission['isFinished'] ?? '') + )); + + return $this->surveyResultsExportService->createExcelExportResponse($survey, $finishedSubmissions); + } + + #[Route('/umfrage-ergebnisse-pdf/{alias}', name: 'mummert_survey_results_pdf_export', defaults: ['_scope' => 'frontend'], requirements: ['alias' => '[^/]+'], methods: ['GET'])] + public function pdf(string $alias): Response + { + $survey = $this->surveyRepository->findByPublicAlias($alias, false); + + if (null === $survey) { + throw new NotFoundHttpException('Die Umfrage wurde nicht gefunden.'); + } + + $resultsData = $this->surveyResultsViewService->buildForSurvey($survey); + + return $this->surveyResultsPdfService->createPdfExportResponse( + $survey, + $resultsData['completedSubmissionCount'], + $resultsData['questionResults'], + ); + } +} \ No newline at end of file diff --git a/src/DependencyInjection/SurveyExtension.php b/src/DependencyInjection/SurveyExtension.php new file mode 100644 index 0000000..b372962 --- /dev/null +++ b/src/DependencyInjection/SurveyExtension.php @@ -0,0 +1,33 @@ +hasExtension('twig')) { + return; + } + + $container->prependExtensionConfig('twig', [ + 'paths' => [ + dirname(__DIR__, 2).'/contao/templates' => 'Survey', + ], + ]); + } + + public function load(array $configs, ContainerBuilder $container): void + { + $loader = new YamlFileLoader($container, new FileLocator(dirname(__DIR__, 2).'/config')); + $loader->load('services.yaml'); + } +} \ No newline at end of file diff --git a/src/EventListener/SurveyDcaListener.php b/src/EventListener/SurveyDcaListener.php new file mode 100644 index 0000000..fe23866 --- /dev/null +++ b/src/EventListener/SurveyDcaListener.php @@ -0,0 +1,477 @@ +surveyRepository->ensurePublicAlias((string) $value, (int) ($dataContainer->id ?? 0)); + } + + public function generateCopyPublicLinkButton(array $row, ?string $href, string $label, string $title, ?string $icon, string $attributes): string + { + $publicUrl = $this->buildSurveyPageUrl((string) ($row['alias'] ?? ''), 'surveyReaderPage'); + $label = 'Link kopieren'; + $title = 'Den oeffentlichen Link in die Zwischenablage kopieren'; + + if (null === $publicUrl) { + return sprintf( + '%s', + htmlspecialchars('In den Contao-Einstellungen ist noch keine Reader-Seite hinterlegt oder der Link-Schluessel ist ungueltig.', ENT_QUOTES), + Image::getHtml($icon ?? 'copy.svg', $label) + ); + } + + $copyScript = sprintf( + 'navigator.clipboard.writeText(%s).then(function(){Contao.flashMessage(%s, %s, "confirmation");});return false;', + json_encode($publicUrl, JSON_THROW_ON_ERROR), + json_encode('Oeffentlicher Link wurde in die Zwischenablage kopiert.', JSON_THROW_ON_ERROR), + json_encode('Bestaetigung', JSON_THROW_ON_ERROR), + ); + + return sprintf( + '%s', + htmlspecialchars($title, ENT_QUOTES), + htmlspecialchars($copyScript, ENT_QUOTES), + $attributes, + Image::getHtml($icon ?? 'copy.svg', $label).' '.$label + ); + } + + public function generateShowResultsButton(array $row, ?string $href, string $label, string $title, ?string $icon, string $attributes): string + { + $resultsUrl = $this->buildSurveyPageUrl((string) ($row['alias'] ?? ''), 'surveyResultsPage'); + $label = 'Ergebnisse anzeigen'; + $title = 'Die Ergebnisse dieser Umfrage im Frontend anzeigen'; + + if (null === $resultsUrl) { + return sprintf( + '%s', + htmlspecialchars('In den Contao-Einstellungen ist noch keine Ergebnisseite hinterlegt oder der Link-Schluessel ist ungueltig.', ENT_QUOTES), + Image::getHtml($icon ?? 'show.svg', $label) + ); + } + + return sprintf( + '%s', + htmlspecialchars($resultsUrl, ENT_QUOTES), + htmlspecialchars($title, ENT_QUOTES), + $attributes, + Image::getHtml($icon ?? 'show.svg', $label).' '.$label + ); + } + + /** + * @return array + */ + public function getQuestionOptions(?DataContainer $dataContainer = null): array + { + $surveyId = $this->resolveSurveyId('tl_survey_condition', $dataContainer); + return $this->buildQuestionOptions($surveyId); + } + + /** + * @return array + */ + public function getQuestionOptionsForContent(?DataContainer $dataContainer = null): array + { + $surveyId = $this->resolveSurveyId('tl_survey_content', $dataContainer); + + return $this->buildQuestionOptions($surveyId); + } + + /** + * @return array + */ + private function buildQuestionOptions(int $surveyId): array + { + $choices = []; + + foreach ($this->surveyQuestionRepository->findAllBySurvey($surveyId) as $question) { + $choices[(int) $question->id] = sprintf('#%d %s', (int) $question->id, (string) $question->question); + } + + return $choices; + } + + /** + * @return array + */ + public function getMemberOptions(): array + { + return $this->surveyEditorRepository->findMemberChoices(); + } + + /** + * @return array + */ + public function getCategoryOptions(): array + { + $rows = $this->connection->fetchAllAssociative('SELECT id, title FROM tl_survey_category ORDER BY sorting ASC, title ASC'); + $options = []; + + foreach ($rows as $row) { + $options[(int) $row['id']] = (string) $row['title']; + } + + return $options; + } + + /** + * @return array + */ + public function getSurveyOptions(): array + { + return $this->surveyEditorRepository->findSurveyChoices(); + } + + /** + * @return list + */ + public function loadMemberAssignedSurveys(mixed $value, DataContainer $dataContainer): array + { + $memberId = (int) ($dataContainer->id ?? 0); + + return $memberId > 0 ? $this->surveyEditorRepository->findSurveyIdsByMember($memberId) : []; + } + + /** + * @return list + */ + public function loadSurveyAssignedMembers(mixed $value, DataContainer $dataContainer): array + { + $surveyId = (int) ($dataContainer->id ?? 0); + + return $surveyId > 0 ? $this->surveyEditorRepository->findMemberIdsBySurvey($surveyId) : []; + } + + public function guardContentSave(mixed $value, DataContainer $dataContainer): mixed + { + $this->assertSurveyUnlocked($this->resolveSurveyId('tl_survey_content', $dataContainer)); + + return $value; + } + + public function guardConditionSave(mixed $value, DataContainer $dataContainer): mixed + { + $this->assertSurveyUnlocked($this->resolveSurveyId('tl_survey_condition', $dataContainer)); + + return $value; + } + + public function guardEditorSave(mixed $value, DataContainer $dataContainer): mixed + { + $surveyId = $this->resolveSurveyId('tl_survey_editor', $dataContainer); + $this->assertSurveyUnlocked($surveyId); + $this->surveyCategoryAssignmentService->applyMemberCategoriesToSurvey((int) $value, $surveyId); + + return $value; + } + + /** + * @return list + */ + public function saveMemberSurveyCategories(mixed $value, DataContainer $dataContainer): array + { + $memberId = (int) ($dataContainer->id ?? 0); + $categoryIds = $this->surveyCategoryAssignmentService->normalizeCategoryIds($value); + + if ($memberId > 0) { + $this->surveyCategoryAssignmentService->syncAssignedSurveys($memberId, $categoryIds); + } + + return $categoryIds; + } + + public function refreshMemberSurveyListMetadata(DataContainer $dataContainer): void + { + $memberId = (int) ($dataContainer->id ?? 0); + + if ($memberId <= 0) { + return; + } + + foreach ($this->surveyEditorRepository->findSurveyIdsByMember($memberId) as $surveyId) { + $this->surveyRepository->refreshListMetadata($surveyId); + } + } + + /** + * @return list + */ + public function saveMemberAssignedSurveys(mixed $value, DataContainer $dataContainer): array + { + $memberId = (int) ($dataContainer->id ?? 0); + $surveyIds = $this->surveyCategoryAssignmentService->normalizeCategoryIds($value); + + if ($memberId <= 0) { + return $surveyIds; + } + + $previousSurveyIds = $this->surveyEditorRepository->findSurveyIdsByMember($memberId); + + if ($previousSurveyIds !== $surveyIds) { + foreach (array_unique(array_merge($previousSurveyIds, $surveyIds)) as $surveyId) { + $this->assertSurveyUnlocked((int) $surveyId); + } + + $this->surveyEditorRepository->syncSurveysForMember($memberId, $surveyIds); + } + + $postedCategories = Input::post('surveyCategories'); + $memberCategoryIds = null !== $postedCategories + ? $this->surveyCategoryAssignmentService->normalizeCategoryIds($postedCategories) + : $this->surveyCategoryAssignmentService->getMemberCategoryIds($memberId); + + foreach (array_unique(array_merge($previousSurveyIds, $surveyIds)) as $surveyId) { + $this->surveyCategoryAssignmentService->syncSurvey((int) $surveyId, [$memberId => $memberCategoryIds]); + } + + return $surveyIds; + } + + /** + * @return list + */ + public function saveSurveyAssignedMembers(mixed $value, DataContainer $dataContainer): array + { + $surveyId = (int) ($dataContainer->id ?? 0); + $memberIds = $this->surveyCategoryAssignmentService->normalizeCategoryIds($value); + + if ($surveyId <= 0) { + return $memberIds; + } + + $previousMemberIds = $this->surveyEditorRepository->findMemberIdsBySurvey($surveyId); + + if ($previousMemberIds !== $memberIds) { + $this->assertSurveyUnlocked($surveyId); + $this->surveyEditorRepository->syncMembersForSurvey($surveyId, $memberIds); + $this->surveyCategoryAssignmentService->syncSurvey($surveyId); + } + + $this->surveyRepository->refreshListMetadata($surveyId); + + return $memberIds; + } + + public function refreshSurveyBackendStateIndex(): void + { + foreach ($this->connection->fetchFirstColumn('SELECT id FROM tl_survey') as $surveyId) { + $this->normalizeSurveyBackendState((int) $surveyId); + } + } + + public function persistSurveyBackendState(DataContainer $dataContainer): void + { + $surveyId = (int) ($dataContainer->id ?? 0); + + if ($surveyId <= 0) { + return; + } + + $this->normalizeSurveyBackendState($surveyId); + } + + private function normalizeSurveyBackendState(int $surveyId): void + { + if ($surveyId <= 0) { + return; + } + + $survey = $this->surveyRepository->findById($surveyId); + + if (null === $survey) { + return; + } + + $now = time(); + $createdAt = (int) $survey->createdAt; + $updatedAt = (int) $survey->updatedAt; + $tstamp = (int) $survey->tstamp; + + $this->connection->update('tl_survey', [ + 'createdAt' => $createdAt > 0 ? $createdAt : ($updatedAt > 0 ? $updatedAt : ($tstamp > 0 ? $tstamp : $now)), + 'updatedAt' => $updatedAt > 0 ? $updatedAt : $now, + ], [ + 'id' => $surveyId, + ]); + + $this->surveyRepository->refreshListMetadata($surveyId); + } + + public function guardContentDelete(DataContainer $dataContainer): void + { + $this->assertSurveyUnlocked($this->resolveSurveyId('tl_survey_content', $dataContainer)); + } + + public function touchSurveyContentParent(DataContainer $dataContainer): void + { + $surveyId = $this->resolveSurveyId('tl_survey_content', $dataContainer); + + if ($surveyId > 0) { + $this->surveyRepository->touch($surveyId); + } + } + + public function guardConditionDelete(DataContainer $dataContainer): void + { + $this->assertSurveyUnlocked($this->resolveSurveyId('tl_survey_condition', $dataContainer)); + } + + public function touchSurveyConditionParent(DataContainer $dataContainer): void + { + $surveyId = $this->resolveSurveyId('tl_survey_condition', $dataContainer); + + if ($surveyId > 0) { + $this->surveyRepository->touch($surveyId); + } + } + + public function guardEditorDelete(DataContainer $dataContainer): void + { + $surveyId = $this->resolveSurveyId('tl_survey_editor', $dataContainer); + $this->assertSurveyUnlocked($surveyId); + + if ($dataContainer->activeRecord?->member) { + $this->surveyCategoryAssignmentService->syncSurveyWithoutMember($surveyId, (int) $dataContainer->activeRecord->member); + } + } + + public function guardSurveyStructureSave(mixed $value, DataContainer $dataContainer): mixed + { + $surveyId = (int) ($dataContainer->id ?? 0); + $this->assertSurveyUnlocked($surveyId); + + return $value; + } + + public function resolveSurveyContentPalette(string $palette, DataContainer $dataContainer): string + { + $type = (string) ($dataContainer->activeRecord->type ?? ''); + + if ('' === $type) { + $type = (string) Input::post('type'); + } + + return match ($type) { + 'range' => (string) ($GLOBALS['TL_DCA']['tl_survey_content']['palettes']['range'] ?? $palette), + 'text' => (string) ($GLOBALS['TL_DCA']['tl_survey_content']['palettes']['text'] ?? $palette), + 'choice' => (string) ($GLOBALS['TL_DCA']['tl_survey_content']['palettes']['choice'] ?? $palette), + 'yes_no_maybe' => (string) ($GLOBALS['TL_DCA']['tl_survey_content']['palettes']['yes_no_maybe'] ?? $palette), + default => $palette, + }; + } + + private function assertSurveyUnlocked(int $surveyId): void + { + $survey = $this->surveyRepository->findById($surveyId); + + if (null === $survey) { + return; + } + + if ('1' === (string) $survey->isLocked) { + throw new \RuntimeException('Die Umfrage ist gesperrt, weil bereits Antworten existieren.'); + } + } + + private function resolveSurveyId(string $table, ?DataContainer $dataContainer = null): int + { + if ($dataContainer?->activeRecord) { + if (isset($dataContainer->activeRecord->pid)) { + return (int) $dataContainer->activeRecord->pid; + } + + if (isset($dataContainer->activeRecord->survey)) { + return (int) $dataContainer->activeRecord->survey; + } + } + + $pid = (int) Input::get('pid'); + + if ($pid > 0) { + return $pid; + } + + $recordId = (int) ($dataContainer?->id ?? 0); + + if ($recordId <= 0) { + return 0; + } + + if ('survey' === $table) { + $value = $this->connection->fetchOne(sprintf('SELECT %s FROM %s WHERE id = ?', 'id', $table), [$recordId]); + + return false === $value ? 0 : (int) $value; + } + + if ('tl_survey_editor' === $table) { + $value = $this->connection->fetchOne( + 'SELECT COALESCE(NULLIF(survey, 0), pid) FROM tl_survey_editor WHERE id = ?', + [$recordId], + ); + + return false === $value ? 0 : (int) $value; + } + + $value = $this->connection->fetchOne(sprintf('SELECT %s FROM %s WHERE id = ?', 'pid', $table), [$recordId]); + + return false === $value ? 0 : (int) $value; + } + + private function buildSurveyPageUrl(string $alias, string $settingKey): ?string + { + $pageId = $this->resolvePageId($settingKey); + + if ($pageId <= 0 || '' === $alias) { + return null; + } + + $page = $this->framework->getAdapter(PageModel::class)->findById($pageId); + + if (!$page instanceof PageModel) { + return null; + } + + $baseUrl = rtrim((string) $this->framework->getAdapter(Environment::class)->get('url'), '/'); + $pagePath = trim((string) $page->getFrontendUrl(), '/'); + + if ('' === $pagePath) { + return sprintf('%s/%s', $baseUrl, $alias); + } + + return sprintf('%s/%s/%s', $baseUrl, $pagePath, $alias); + } + + private function resolvePageId(string $settingKey): int + { + return (int) $this->framework->getAdapter(Config::class)->get($settingKey); + } +} \ No newline at end of file diff --git a/src/Form/Model/SurveyAnswerData.php b/src/Form/Model/SurveyAnswerData.php new file mode 100644 index 0000000..16f5455 --- /dev/null +++ b/src/Form/Model/SurveyAnswerData.php @@ -0,0 +1,10 @@ +sourceQuestion = (int) $condition->sourceQuestion; + $data->answerValue = (string) $condition->answerValue; + $data->targetQuestion = (int) $condition->targetQuestion; + + return $data; + } + + /** + * @return array + */ + public function toArray(): array + { + return [ + 'sourceQuestion' => $this->sourceQuestion, + 'answerValue' => $this->answerValue, + 'targetQuestion' => $this->targetQuestion, + ]; + } +} \ No newline at end of file diff --git a/src/Form/Model/SurveyEditorData.php b/src/Form/Model/SurveyEditorData.php new file mode 100644 index 0000000..e2af18c --- /dev/null +++ b/src/Form/Model/SurveyEditorData.php @@ -0,0 +1,36 @@ +title = (string) $survey->title; + $data->description = (string) $survey->description; + $data->published = '1' === (string) $survey->published; + + return $data; + } + + /** + * @return array + */ + public function toArray(): array + { + return [ + 'title' => $this->title, + 'description' => $this->description, + 'published' => $this->published, + ]; + } +} \ No newline at end of file diff --git a/src/Form/Model/SurveyQuestionData.php b/src/Form/Model/SurveyQuestionData.php new file mode 100644 index 0000000..b671b34 --- /dev/null +++ b/src/Form/Model/SurveyQuestionData.php @@ -0,0 +1,86 @@ +type = (string) $question->type; + $data->question = (string) $question->question; + $data->description = (string) $question->description; + $data->mandatory = '1' === (string) $question->mandatory; + $data->published = '1' === (string) $question->published; + $data->allowMaybe = '1' === (string) $question->allowMaybe; + $data->allowMultiple = '1' === (string) $question->allowMultiple; + $data->jumpOnYes = (int) $question->jumpOnYes; + $data->jumpOnNo = (int) $question->jumpOnNo; + + for ($index = 1; $index <= 10; ++$index) { + $property = 'answerOption'.$index; + $data->{$property} = (string) $question->{$property}; + } + + $data->rangeMin = (int) $question->rangeMin; + $data->rangeMax = (int) $question->rangeMax; + $data->rangeStep = max(1, (int) $question->rangeStep); + + return $data; + } + + /** + * @return array + */ + public function toArray(): array + { + $payload = [ + 'type' => $this->type, + 'question' => $this->question, + 'description' => $this->description, + 'mandatory' => $this->mandatory, + 'published' => $this->published, + 'allowMaybe' => $this->allowMaybe, + 'allowMultiple' => $this->allowMultiple, + 'jumpOnYes' => $this->jumpOnYes, + 'jumpOnNo' => $this->jumpOnNo, + 'rangeMin' => $this->rangeMin, + 'rangeMax' => $this->rangeMax, + 'rangeStep' => $this->rangeStep, + ]; + + for ($index = 1; $index <= 10; ++$index) { + $property = 'answerOption'.$index; + $payload[$property] = $this->{$property}; + } + + return $payload; + } +} \ No newline at end of file diff --git a/src/Form/SurveyConditionEditorType.php b/src/Form/SurveyConditionEditorType.php new file mode 100644 index 0000000..54c5153 --- /dev/null +++ b/src/Form/SurveyConditionEditorType.php @@ -0,0 +1,48 @@ +add('sourceQuestion', ChoiceType::class, [ + 'label' => 'Ausgangsfrage', + 'choices' => array_flip($questionChoices), + 'constraints' => [new NotBlank()], + ]) + ->add('answerValue', TextType::class, [ + 'label' => 'Antwort', + 'help' => 'Bei Ja-Nein-Fragen bitte genau ja oder nein eintragen, bei aktivierter Vielleicht-Option auch vielleicht. Bei Choice-Fragen den exakten Antworttext verwenden, bei Multiple-Choice mehrere Werte mit | trennen.', + 'constraints' => [new NotBlank(), new Length(['max' => 255])], + ]) + ->add('targetQuestion', ChoiceType::class, [ + 'label' => 'Naechste Frage', + 'choices' => array_flip($questionChoices), + 'constraints' => [new NotBlank()], + ]) + ; + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([ + 'data_class' => SurveyConditionData::class, + 'question_choices' => [], + ]); + } +} \ No newline at end of file diff --git a/src/Form/SurveyEditorType.php b/src/Form/SurveyEditorType.php new file mode 100644 index 0000000..1e11795 --- /dev/null +++ b/src/Form/SurveyEditorType.php @@ -0,0 +1,44 @@ +add('title', TextType::class, [ + 'label' => 'Titel', + 'constraints' => [new NotBlank(), new Length(['max' => 255])], + ]) + ->add('description', TextareaType::class, [ + 'label' => 'Beschreibung', + 'required' => false, + 'attr' => ['rows' => 5], + ]) + ->add('published', CheckboxType::class, [ + 'label' => 'Veroeffentlicht', + 'required' => false, + ]) + ; + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([ + 'data_class' => SurveyEditorData::class, + ]); + } +} \ No newline at end of file diff --git a/src/Form/SurveyQuestionAnswerType.php b/src/Form/SurveyQuestionAnswerType.php new file mode 100644 index 0000000..690b918 --- /dev/null +++ b/src/Form/SurveyQuestionAnswerType.php @@ -0,0 +1,40 @@ +questionTypeRegistry->get((string) $question->type)->buildField($builder, $question); + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([ + 'data_class' => SurveyAnswerData::class, + 'question' => null, + ]); + + $resolver->setAllowedTypes('question', [SurveyContentModel::class]); + } +} \ No newline at end of file diff --git a/src/Form/SurveyQuestionEditorType.php b/src/Form/SurveyQuestionEditorType.php new file mode 100644 index 0000000..19f25c8 --- /dev/null +++ b/src/Form/SurveyQuestionEditorType.php @@ -0,0 +1,155 @@ +add('type', ChoiceType::class, [ + 'label' => 'Fragetyp', + 'choices' => $this->questionTypeRegistry->getChoices(), + 'attr' => [ + 'data-controller' => 'question-editor', + 'data-action' => 'change->question-editor#toggle', + 'data-question-editor-target' => 'type', + ], + ]) + ->add('question', TextType::class, [ + 'label' => 'Frage', + 'constraints' => [new NotBlank(), new Length(['max' => 255])], + ]) + ->add('description', TextareaType::class, [ + 'label' => 'Beschreibung', + 'required' => false, + 'attr' => ['rows' => 4], + ]) + ->add('mandatory', CheckboxType::class, [ + 'label' => 'Pflichtfrage', + 'required' => false, + ]) + ->add('published', CheckboxType::class, [ + 'label' => 'Aktiv', + 'required' => false, + ]) + ->add('allowMaybe', CheckboxType::class, [ + 'label' => 'Vielleicht anbieten', + 'required' => false, + 'attr' => ['data-question-editor-target' => 'yesNoMaybeField'], + ]) + ->add('jumpOnYes', ChoiceType::class, [ + 'label' => 'Zur Frage springen bei Auswahl ja', + 'required' => false, + 'choices' => array_flip($options['question_choices']), + 'placeholder' => 'keine', + 'attr' => ['data-question-editor-target' => 'yesNoMaybeField'], + ]) + ->add('jumpOnNo', ChoiceType::class, [ + 'label' => 'Zur Frage springen bei Auswahl nein', + 'required' => false, + 'choices' => array_flip($options['question_choices']), + 'placeholder' => 'keine', + 'attr' => ['data-question-editor-target' => 'yesNoMaybeField'], + ]) + ->add('allowMultiple', CheckboxType::class, [ + 'label' => 'Multiple-Choice aktivieren', + 'required' => false, + 'attr' => ['data-question-editor-target' => 'choiceField'], + ]) + ->add('answerOption1', TextType::class, [ + 'label' => 'Antwort 1', + 'required' => false, + 'attr' => ['data-question-editor-target' => 'choiceField'], + ]) + ->add('answerOption2', TextType::class, [ + 'label' => 'Antwort 2', + 'required' => false, + 'attr' => ['data-question-editor-target' => 'choiceField'], + ]) + ->add('answerOption3', TextType::class, [ + 'label' => 'Antwort 3', + 'required' => false, + 'attr' => ['data-question-editor-target' => 'choiceField'], + ]) + ->add('answerOption4', TextType::class, [ + 'label' => 'Antwort 4', + 'required' => false, + 'attr' => ['data-question-editor-target' => 'choiceField'], + ]) + ->add('answerOption5', TextType::class, [ + 'label' => 'Antwort 5', + 'required' => false, + 'attr' => ['data-question-editor-target' => 'choiceField'], + ]) + ->add('answerOption6', TextType::class, [ + 'label' => 'Antwort 6', + 'required' => false, + 'attr' => ['data-question-editor-target' => 'choiceField'], + ]) + ->add('answerOption7', TextType::class, [ + 'label' => 'Antwort 7', + 'required' => false, + 'attr' => ['data-question-editor-target' => 'choiceField'], + ]) + ->add('answerOption8', TextType::class, [ + 'label' => 'Antwort 8', + 'required' => false, + 'attr' => ['data-question-editor-target' => 'choiceField'], + ]) + ->add('answerOption9', TextType::class, [ + 'label' => 'Antwort 9', + 'required' => false, + 'attr' => ['data-question-editor-target' => 'choiceField'], + ]) + ->add('answerOption10', TextType::class, [ + 'label' => 'Antwort 10', + 'required' => false, + 'attr' => ['data-question-editor-target' => 'choiceField'], + ]) + ->add('rangeMin', IntegerType::class, [ + 'label' => 'Kleinster Wert', + 'constraints' => [new GreaterThanOrEqual(['value' => -100000])], + 'attr' => ['data-question-editor-target' => 'rangeField'], + ]) + ->add('rangeMax', IntegerType::class, [ + 'label' => 'Groesster Wert', + 'constraints' => [new GreaterThanOrEqual(['value' => -100000])], + 'attr' => ['data-question-editor-target' => 'rangeField'], + ]) + ->add('rangeStep', IntegerType::class, [ + 'label' => 'Schrittweite', + 'constraints' => [new GreaterThanOrEqual(['value' => 1])], + 'attr' => ['data-question-editor-target' => 'rangeField'], + ]) + ; + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([ + 'data_class' => SurveyQuestionData::class, + 'question_choices' => [], + ]); + } +} \ No newline at end of file diff --git a/src/Model/SurveyAnswerModel.php b/src/Model/SurveyAnswerModel.php new file mode 100644 index 0000000..20efccb --- /dev/null +++ b/src/Model/SurveyAnswerModel.php @@ -0,0 +1,12 @@ +getAnswerOptions($question); + $multiple = '1' === (string) $question->allowMultiple; + $constraints = [new Choice(['choices' => $choices, 'multiple' => $multiple])]; + + if ('1' === (string) $question->mandatory) { + $constraints[] = $multiple ? new Count(['min' => 1]) : new NotBlank(); + } + + return $constraints; + } + + public function buildField(FormBuilderInterface $builder, SurveyContentModel $question, string $fieldName = 'answer'): void + { + $choices = []; + + foreach ($this->getAnswerOptions($question) as $answerOption) { + $choices[$answerOption] = $answerOption; + } + + $builder->add($fieldName, ChoiceType::class, [ + 'label' => false, + 'expanded' => true, + 'multiple' => '1' === (string) $question->allowMultiple, + 'choices' => $choices, + 'constraints' => $this->getConstraints($question), + ]); + } + + public function normalizeAnswer(mixed $value, SurveyContentModel $question): string + { + if (!\is_array($value)) { + return trim((string) $value); + } + + $answers = array_values(array_filter(array_map(static fn (mixed $entry): string => trim((string) $entry), $value), static fn (string $entry): bool => '' !== $entry)); + + return implode(' | ', $answers); + } + + /** + * @return list + */ + private function getAnswerOptions(SurveyContentModel $question): array + { + $options = []; + + for ($index = 1; $index <= 10; ++$index) { + $value = trim((string) $question->{'answerOption'.$index}); + + if ('' !== $value) { + $options[] = $value; + } + } + + return $options; + } +} \ No newline at end of file diff --git a/src/QuestionType/QuestionTypeInterface.php b/src/QuestionType/QuestionTypeInterface.php new file mode 100644 index 0000000..dc0306f --- /dev/null +++ b/src/QuestionType/QuestionTypeInterface.php @@ -0,0 +1,22 @@ + + */ + public function getConstraints(SurveyContentModel $question): array; + + public function buildField(FormBuilderInterface $builder, SurveyContentModel $question, string $fieldName = 'answer'): void; + + public function normalizeAnswer(mixed $value, SurveyContentModel $question): string; +} \ No newline at end of file diff --git a/src/QuestionType/QuestionTypeRegistry.php b/src/QuestionType/QuestionTypeRegistry.php new file mode 100644 index 0000000..65545da --- /dev/null +++ b/src/QuestionType/QuestionTypeRegistry.php @@ -0,0 +1,46 @@ + + */ + private array $questionTypes = []; + + public function __construct(iterable $questionTypes) + { + foreach ($questionTypes as $questionType) { + if (!$questionType instanceof QuestionTypeInterface) { + continue; + } + + $this->questionTypes[$questionType->getName()] = $questionType; + } + } + + public function get(string $type): QuestionTypeInterface + { + if (!isset($this->questionTypes[$type])) { + throw new \InvalidArgumentException(sprintf('Unbekannter Fragetyp "%s".', $type)); + } + + return $this->questionTypes[$type]; + } + + /** + * @return array + */ + public function getChoices(): array + { + return [ + 'Ja-Nein-Frage' => 'yes_no_maybe', + 'Offene Frage' => 'text', + 'Bewertungsfrage' => 'range', + 'Single/Multiple-Choice' => 'choice', + ]; + } +} \ No newline at end of file diff --git a/src/QuestionType/RangeQuestionType.php b/src/QuestionType/RangeQuestionType.php new file mode 100644 index 0000000..03893da --- /dev/null +++ b/src/QuestionType/RangeQuestionType.php @@ -0,0 +1,56 @@ + (int) $question->rangeMin, + 'max' => (int) $question->rangeMax, + ]), + ]; + + if ('1' === (string) $question->mandatory) { + $constraints[] = new NotBlank(); + } + + return $constraints; + } + + public function buildField(FormBuilderInterface $builder, SurveyContentModel $question, string $fieldName = 'answer'): void + { + $builder->add($fieldName, RangeType::class, [ + 'label' => false, + 'constraints' => $this->getConstraints($question), + 'attr' => [ + 'min' => (int) $question->rangeMin, + 'max' => (int) $question->rangeMax, + 'step' => max(1, (int) $question->rangeStep), + 'class' => 'range range-primary w-full', + 'data-controller' => 'range-preview', + 'data-action' => 'input->range-preview#update', + ], + ]); + } + + public function normalizeAnswer(mixed $value, SurveyContentModel $question): string + { + return (string) (int) $value; + } +} \ No newline at end of file diff --git a/src/QuestionType/TextQuestionType.php b/src/QuestionType/TextQuestionType.php new file mode 100644 index 0000000..85f77b6 --- /dev/null +++ b/src/QuestionType/TextQuestionType.php @@ -0,0 +1,48 @@ + 5000])]; + + if ('1' === (string) $question->mandatory) { + $constraints[] = new NotBlank(); + } + + return $constraints; + } + + public function buildField(FormBuilderInterface $builder, SurveyContentModel $question, string $fieldName = 'answer'): void + { + $builder->add($fieldName, TextareaType::class, [ + 'label' => false, + 'constraints' => $this->getConstraints($question), + 'attr' => [ + 'rows' => 6, + 'placeholder' => 'Ihre Antwort', + 'class' => 'textarea textarea-bordered w-full min-h-40', + ], + ]); + } + + public function normalizeAnswer(mixed $value, SurveyContentModel $question): string + { + return trim((string) $value); + } +} \ No newline at end of file diff --git a/src/QuestionType/YesNoMaybeQuestionType.php b/src/QuestionType/YesNoMaybeQuestionType.php new file mode 100644 index 0000000..862fa60 --- /dev/null +++ b/src/QuestionType/YesNoMaybeQuestionType.php @@ -0,0 +1,61 @@ +allowMaybe) { + $choices[] = 'maybe'; + } + + $constraints = [new Choice(['choices' => $choices])]; + + if ('1' === (string) $question->mandatory) { + $constraints[] = new NotBlank(); + } + + return $constraints; + } + + public function buildField(FormBuilderInterface $builder, SurveyContentModel $question, string $fieldName = 'answer'): void + { + $choices = [ + 'Ja' => 'yes', + 'Nein' => 'no', + ]; + + if ('1' === (string) $question->allowMaybe) { + $choices['Vielleicht'] = 'maybe'; + } + + $builder->add($fieldName, ChoiceType::class, [ + 'label' => false, + 'expanded' => true, + 'multiple' => false, + 'choices' => $choices, + 'constraints' => $this->getConstraints($question), + ]); + } + + public function normalizeAnswer(mixed $value, SurveyContentModel $question): string + { + return mb_strtolower(trim((string) $value)); + } +} \ No newline at end of file diff --git a/src/Repository/SurveyAnswerRepository.php b/src/Repository/SurveyAnswerRepository.php new file mode 100644 index 0000000..62825ff --- /dev/null +++ b/src/Repository/SurveyAnswerRepository.php @@ -0,0 +1,104 @@ +connection->fetchOne( + 'SELECT id FROM tl_survey_answer WHERE submission = ? AND question = ? LIMIT 1', + [$submissionId, $questionId], + ); + + if (false !== $existingId) { + $this->connection->update('tl_survey_answer', [ + 'questionType' => $questionType, + 'value' => $value, + ], [ + 'id' => (int) $existingId, + ]); + + return; + } + + $this->connection->insert('tl_survey_answer', [ + 'pid' => $submissionId, + 'submission' => $submissionId, + 'question' => $questionId, + 'questionType' => $questionType, + 'value' => $value, + ]); + } + + public function hasAnswersForSurvey(int $surveyId): bool + { + return false !== $this->connection->fetchOne( + <<<'SQL' + SELECT ans.id + FROM tl_survey_answer ans + INNER JOIN tl_survey_submission sub ON sub.id = ans.submission + WHERE sub.survey = ? + LIMIT 1 + SQL, + [$surveyId], + ); + } + + /** + * @return list + */ + public function findFinishedAnswersBySurvey(int $surveyId): array + { + $rows = $this->connection->fetchAllAssociative( + <<<'SQL' + SELECT + a.question AS questionId, + a.value + FROM tl_survey_answer a + INNER JOIN tl_survey_submission sub ON sub.id = a.submission + WHERE sub.survey = :survey AND sub.isFinished = 1 + ORDER BY a.question ASC, a.id ASC + SQL, + ['survey' => $surveyId], + ); + + return array_map( + static fn (array $row): array => [ + 'questionId' => (int) $row['questionId'], + 'value' => (string) $row['value'], + ], + $rows, + ); + } + + /** + * @return list> + */ + public function findAnswersBySubmission(int $submissionId): array + { + return $this->connection->fetchAllAssociative( + <<<'SQL' + SELECT + a.id, + a.question AS questionId, + a.value, + a.questionType, + q.question + FROM tl_survey_answer a + INNER JOIN tl_survey_content q ON q.id = a.question + WHERE a.submission = :submission + ORDER BY q.sorting ASC + SQL, + ['submission' => $submissionId], + ); + } +} \ No newline at end of file diff --git a/src/Repository/SurveyConditionRepository.php b/src/Repository/SurveyConditionRepository.php new file mode 100644 index 0000000..8dfa675 --- /dev/null +++ b/src/Repository/SurveyConditionRepository.php @@ -0,0 +1,93 @@ +framework->getAdapter(SurveyConditionModel::class); + $model = $adapter->findByPk($id); + + return $model instanceof SurveyConditionModel ? $model : null; + } + + public function findMatchingCondition(int $surveyId, int $sourceQuestionId, string $answerValue): ?SurveyConditionModel + { + $id = $this->connection->fetchOne( + 'SELECT id FROM tl_survey_condition WHERE pid = ? AND sourceQuestion = ? AND LOWER(TRIM(answerValue)) = LOWER(TRIM(?)) ORDER BY id ASC LIMIT 1', + [$surveyId, $sourceQuestionId, $answerValue], + ); + + return false === $id ? null : $this->findById((int) $id); + } + + /** + * @return list> + */ + public function findOverviewBySurvey(int $surveyId): array + { + return $this->connection->fetchAllAssociative( + <<<'SQL' + SELECT + c.id, + c.answerValue, + c.sourceQuestion, + c.targetQuestion, + source.question AS sourceQuestionLabel, + target.question AS targetQuestionLabel + FROM tl_survey_condition c + LEFT JOIN tl_survey_content source ON source.id = c.sourceQuestion + LEFT JOIN tl_survey_content target ON target.id = c.targetQuestion + WHERE c.pid = :survey + ORDER BY source.sorting ASC, c.id ASC + SQL, + ['survey' => $surveyId], + ); + } + + public function create(int $surveyId, array $data): SurveyConditionModel + { + $this->connection->insert('tl_survey_condition', [ + 'pid' => $surveyId, + 'sourceQuestion' => (int) ($data['sourceQuestion'] ?? 0), + 'answerValue' => mb_strtolower(trim((string) ($data['answerValue'] ?? ''))), + 'targetQuestion' => (int) ($data['targetQuestion'] ?? 0), + ]); + + $id = (int) $this->connection->lastInsertId(); + + return $this->findById($id) ?? throw new \RuntimeException('Bedingung konnte nicht angelegt werden.'); + } + + public function update(SurveyConditionModel $condition, array $data): void + { + $this->connection->update('tl_survey_condition', [ + 'sourceQuestion' => (int) ($data['sourceQuestion'] ?? $condition->sourceQuestion), + 'answerValue' => mb_strtolower(trim((string) ($data['answerValue'] ?? $condition->answerValue))), + 'targetQuestion' => (int) ($data['targetQuestion'] ?? $condition->targetQuestion), + ], [ + 'id' => (int) $condition->id, + ]); + } + + public function delete(int $surveyId, int $conditionId): void + { + $this->connection->delete('tl_survey_condition', [ + 'id' => $conditionId, + 'pid' => $surveyId, + ]); + } +} \ No newline at end of file diff --git a/src/Repository/SurveyEditorRepository.php b/src/Repository/SurveyEditorRepository.php new file mode 100644 index 0000000..840bcfd --- /dev/null +++ b/src/Repository/SurveyEditorRepository.php @@ -0,0 +1,177 @@ +connection->fetchOne( + 'SELECT id FROM tl_survey_editor WHERE COALESCE(NULLIF(survey, 0), pid) = ? AND member = ? LIMIT 1', + [$surveyId, $memberId], + ); + } + + public function assignEditor(int $surveyId, int $memberId): void + { + if ($this->isEditor($surveyId, $memberId)) { + return; + } + + $this->connection->insert('tl_survey_editor', [ + 'pid' => $surveyId, + 'survey' => $surveyId, + 'member' => $memberId, + ]); + } + + public function removeEditor(int $surveyId, int $memberId): void + { + $this->connection->delete('tl_survey_editor', [ + 'survey' => $surveyId, + 'member' => $memberId, + ]); + + $this->connection->delete('tl_survey_editor', [ + 'pid' => $surveyId, + 'member' => $memberId, + 'survey' => 0, + ]); + } + + /** + * @return list + */ + public function findSurveyIdsByMember(int $memberId): array + { + $surveyIds = $this->connection->fetchFirstColumn( + 'SELECT DISTINCT COALESCE(NULLIF(survey, 0), pid) FROM tl_survey_editor WHERE member = ? ORDER BY COALESCE(NULLIF(survey, 0), pid)', + [$memberId], + ); + + return array_values(array_map('intval', $surveyIds)); + } + + /** + * @return list + */ + public function findMemberIdsBySurvey(int $surveyId): array + { + $memberIds = $this->connection->fetchFirstColumn( + 'SELECT DISTINCT member FROM tl_survey_editor WHERE COALESCE(NULLIF(survey, 0), pid) = ? AND member > 0 ORDER BY member', + [$surveyId], + ); + + return array_values(array_map('intval', $memberIds)); + } + + /** + * @return array + */ + public function findSurveyChoices(): array + { + $rows = $this->connection->fetchAllAssociative( + 'SELECT id, title FROM tl_survey ORDER BY title ASC, id ASC' + ); + $choices = []; + + foreach ($rows as $row) { + $title = trim((string) ($row['title'] ?? '')); + $choices[(int) $row['id']] = '' !== $title ? $title : 'Ohne Titel'; + } + + return $choices; + } + + /** + * @param list $memberIds + */ + public function syncMembersForSurvey(int $surveyId, array $memberIds): void + { + $memberIds = $this->normalizeIds($memberIds); + $existingMemberIds = $this->findMemberIdsBySurvey($surveyId); + + foreach (array_diff($existingMemberIds, $memberIds) as $memberId) { + $this->removeEditor($surveyId, (int) $memberId); + } + + foreach (array_diff($memberIds, $existingMemberIds) as $memberId) { + $this->assignEditor($surveyId, (int) $memberId); + } + } + + /** + * @param list $surveyIds + */ + public function syncSurveysForMember(int $memberId, array $surveyIds): void + { + $surveyIds = $this->normalizeIds($surveyIds); + $existingSurveyIds = $this->findSurveyIdsByMember($memberId); + + foreach (array_diff($existingSurveyIds, $surveyIds) as $surveyId) { + $this->removeEditor((int) $surveyId, $memberId); + } + + foreach (array_diff($surveyIds, $existingSurveyIds) as $surveyId) { + $this->assignEditor((int) $surveyId, $memberId); + } + } + + /** + * @return list> + */ + public function findEditorsBySurvey(int $surveyId): array + { + return $this->connection->fetchAllAssociative( + <<<'SQL' + SELECT + m.id, + m.firstname, + m.lastname, + m.email + FROM tl_survey_editor e + INNER JOIN tl_member m ON m.id = e.member + WHERE COALESCE(NULLIF(e.survey, 0), e.pid) = :survey + ORDER BY m.lastname ASC, m.firstname ASC + SQL, + ['survey' => $surveyId], + ); + } + + /** + * @return array + */ + public function findMemberChoices(): array + { + $rows = $this->connection->fetchAllAssociative('SELECT id, firstname, lastname, email FROM tl_member WHERE disable != 1 ORDER BY lastname ASC, firstname ASC'); + $choices = []; + + foreach ($rows as $row) { + $name = trim(sprintf('%s %s', (string) $row['firstname'], (string) $row['lastname'])); + $choices[(int) $row['id']] = '' !== $name ? sprintf('%s <%s>', $name, (string) $row['email']) : (string) $row['email']; + } + + return $choices; + } + + /** + * @param list $ids + * + * @return list + */ + private function normalizeIds(array $ids): array + { + $ids = array_values(array_unique(array_filter(array_map('intval', $ids), static fn (int $id): bool => $id > 0))); + sort($ids); + + return $ids; + } +} \ No newline at end of file diff --git a/src/Repository/SurveyQuestionRepository.php b/src/Repository/SurveyQuestionRepository.php new file mode 100644 index 0000000..dbc6fbf --- /dev/null +++ b/src/Repository/SurveyQuestionRepository.php @@ -0,0 +1,163 @@ +framework->getAdapter(SurveyContentModel::class); + $model = $adapter->findByPk($id); + + return $model instanceof SurveyContentModel ? $model : null; + } + + public function findByIdForSurvey(int $surveyId, int $questionId, bool $publishedOnly = false): ?SurveyContentModel + { + $row = $this->connection->fetchAssociative( + 'SELECT id FROM tl_survey_content WHERE id = ? AND pid = ?'.($publishedOnly ? ' AND published = 1' : '').' LIMIT 1', + [$questionId, $surveyId], + ); + + if (!$row) { + return null; + } + + return $this->findById((int) $row['id']); + } + + /** + * @return list + */ + public function findAllBySurvey(int $surveyId, bool $publishedOnly = false): array + { + $sql = 'SELECT id FROM tl_survey_content WHERE pid = ?'; + + if ($publishedOnly) { + $sql .= ' AND published = 1'; + } + + $sql .= ' ORDER BY sorting ASC'; + + $ids = $this->connection->fetchFirstColumn($sql, [$surveyId]); + + return $this->hydrate($ids); + } + + public function create(int $surveyId, array $data): SurveyContentModel + { + $sorting = (int) $this->connection->fetchOne('SELECT COALESCE(MAX(sorting), 0) FROM tl_survey_content WHERE pid = ?', [$surveyId]) + 128; + + $this->connection->insert('tl_survey_content', [ + 'pid' => $surveyId, + 'sorting' => $sorting, + 'type' => (string) ($data['type'] ?? 'yes_no_maybe'), + 'question' => (string) ($data['question'] ?? ''), + 'description' => (string) ($data['description'] ?? ''), + 'mandatory' => !empty($data['mandatory']) ? '1' : '', + 'published' => !empty($data['published']) ? '1' : '', + 'allowMaybe' => 'yes_no_maybe' === (string) ($data['type'] ?? 'yes_no_maybe') && !empty($data['allowMaybe']) ? '1' : '', + 'jumpOnYes' => 'yes_no_maybe' === (string) ($data['type'] ?? 'yes_no_maybe') ? max(0, (int) ($data['jumpOnYes'] ?? 0)) : 0, + 'jumpOnNo' => 'yes_no_maybe' === (string) ($data['type'] ?? 'yes_no_maybe') ? max(0, (int) ($data['jumpOnNo'] ?? 0)) : 0, + 'allowMultiple' => 'choice' === (string) ($data['type'] ?? 'yes_no_maybe') && !empty($data['allowMultiple']) ? '1' : '', + 'answerOption1' => 'choice' === (string) ($data['type'] ?? 'yes_no_maybe') ? trim((string) ($data['answerOption1'] ?? '')) : '', + 'answerOption2' => 'choice' === (string) ($data['type'] ?? 'yes_no_maybe') ? trim((string) ($data['answerOption2'] ?? '')) : '', + 'answerOption3' => 'choice' === (string) ($data['type'] ?? 'yes_no_maybe') ? trim((string) ($data['answerOption3'] ?? '')) : '', + 'answerOption4' => 'choice' === (string) ($data['type'] ?? 'yes_no_maybe') ? trim((string) ($data['answerOption4'] ?? '')) : '', + 'answerOption5' => 'choice' === (string) ($data['type'] ?? 'yes_no_maybe') ? trim((string) ($data['answerOption5'] ?? '')) : '', + 'answerOption6' => 'choice' === (string) ($data['type'] ?? 'yes_no_maybe') ? trim((string) ($data['answerOption6'] ?? '')) : '', + 'answerOption7' => 'choice' === (string) ($data['type'] ?? 'yes_no_maybe') ? trim((string) ($data['answerOption7'] ?? '')) : '', + 'answerOption8' => 'choice' === (string) ($data['type'] ?? 'yes_no_maybe') ? trim((string) ($data['answerOption8'] ?? '')) : '', + 'answerOption9' => 'choice' === (string) ($data['type'] ?? 'yes_no_maybe') ? trim((string) ($data['answerOption9'] ?? '')) : '', + 'answerOption10' => 'choice' === (string) ($data['type'] ?? 'yes_no_maybe') ? trim((string) ($data['answerOption10'] ?? '')) : '', + 'rangeMin' => (int) ($data['rangeMin'] ?? 0), + 'rangeMax' => (int) ($data['rangeMax'] ?? 10), + 'rangeStep' => max(1, (int) ($data['rangeStep'] ?? 1)), + ]); + + $id = (int) $this->connection->lastInsertId(); + + return $this->findById($id) ?? throw new \RuntimeException('Frage konnte nicht angelegt werden.'); + } + + public function update(SurveyContentModel $question, array $data): void + { + $this->connection->update('tl_survey_content', [ + 'type' => (string) ($data['type'] ?? $question->type), + 'question' => (string) ($data['question'] ?? $question->question), + 'description' => (string) ($data['description'] ?? $question->description), + 'mandatory' => !empty($data['mandatory']) ? '1' : '', + 'published' => !empty($data['published']) ? '1' : '', + 'allowMaybe' => 'yes_no_maybe' === (string) ($data['type'] ?? $question->type) && !empty($data['allowMaybe']) ? '1' : '', + 'jumpOnYes' => 'yes_no_maybe' === (string) ($data['type'] ?? $question->type) ? max(0, (int) ($data['jumpOnYes'] ?? $question->jumpOnYes)) : 0, + 'jumpOnNo' => 'yes_no_maybe' === (string) ($data['type'] ?? $question->type) ? max(0, (int) ($data['jumpOnNo'] ?? $question->jumpOnNo)) : 0, + 'allowMultiple' => 'choice' === (string) ($data['type'] ?? $question->type) && !empty($data['allowMultiple']) ? '1' : '', + 'answerOption1' => 'choice' === (string) ($data['type'] ?? $question->type) ? trim((string) ($data['answerOption1'] ?? $question->answerOption1)) : '', + 'answerOption2' => 'choice' === (string) ($data['type'] ?? $question->type) ? trim((string) ($data['answerOption2'] ?? $question->answerOption2)) : '', + 'answerOption3' => 'choice' === (string) ($data['type'] ?? $question->type) ? trim((string) ($data['answerOption3'] ?? $question->answerOption3)) : '', + 'answerOption4' => 'choice' === (string) ($data['type'] ?? $question->type) ? trim((string) ($data['answerOption4'] ?? $question->answerOption4)) : '', + 'answerOption5' => 'choice' === (string) ($data['type'] ?? $question->type) ? trim((string) ($data['answerOption5'] ?? $question->answerOption5)) : '', + 'answerOption6' => 'choice' === (string) ($data['type'] ?? $question->type) ? trim((string) ($data['answerOption6'] ?? $question->answerOption6)) : '', + 'answerOption7' => 'choice' === (string) ($data['type'] ?? $question->type) ? trim((string) ($data['answerOption7'] ?? $question->answerOption7)) : '', + 'answerOption8' => 'choice' === (string) ($data['type'] ?? $question->type) ? trim((string) ($data['answerOption8'] ?? $question->answerOption8)) : '', + 'answerOption9' => 'choice' === (string) ($data['type'] ?? $question->type) ? trim((string) ($data['answerOption9'] ?? $question->answerOption9)) : '', + 'answerOption10' => 'choice' === (string) ($data['type'] ?? $question->type) ? trim((string) ($data['answerOption10'] ?? $question->answerOption10)) : '', + 'rangeMin' => (int) ($data['rangeMin'] ?? $question->rangeMin), + 'rangeMax' => (int) ($data['rangeMax'] ?? $question->rangeMax), + 'rangeStep' => max(1, (int) ($data['rangeStep'] ?? $question->rangeStep)), + ], [ + 'id' => (int) $question->id, + ]); + } + + public function delete(int $surveyId, int $questionId): void + { + $this->connection->delete('tl_survey_content', [ + 'id' => $questionId, + 'pid' => $surveyId, + ]); + + $this->connection->delete('tl_survey_condition', [ + 'sourceQuestion' => $questionId, + ]); + + $this->connection->delete('tl_survey_condition', [ + 'targetQuestion' => $questionId, + ]); + } + + public function countPublishedBySurvey(int $surveyId): int + { + return (int) $this->connection->fetchOne( + 'SELECT COUNT(*) FROM tl_survey_content WHERE pid = ? AND published = 1', + [$surveyId], + ); + } + + private function hydrate(array $ids): array + { + $models = []; + + foreach ($ids as $id) { + $model = $this->findById((int) $id); + + if ($model instanceof SurveyContentModel) { + $models[] = $model; + } + } + + return $models; + } +} \ No newline at end of file diff --git a/src/Repository/SurveyRepository.php b/src/Repository/SurveyRepository.php new file mode 100644 index 0000000..559e7c5 --- /dev/null +++ b/src/Repository/SurveyRepository.php @@ -0,0 +1,346 @@ +framework->getAdapter(SurveyModel::class); + $model = $adapter->findByPk($id); + + return $model instanceof SurveyModel ? $model : null; + } + + public function findByPublicAlias(string $alias, bool $publishedOnly = true): ?SurveyModel + { + $qb = $this->connection->createQueryBuilder(); + $qb + ->select('id') + ->from('tl_survey') + ->where('alias = :alias') + ->setParameter('alias', $alias) + ->setMaxResults(1) + ; + + if ($publishedOnly) { + $qb->andWhere('published = 1'); + } + + $id = $qb->executeQuery()->fetchOne(); + + if (false === $id) { + return null; + } + + return $this->findById((int) $id); + } + + /** + * @return list> + */ + public function findEditableByMember(int $memberId): array + { + return $this->connection->fetchAllAssociative( + <<<'SQL' + SELECT + s.id, + s.title, + s.alias, + s.description, + s.published, + s.isLocked, + s.updatedAt, + COUNT(DISTINCT q.id) AS questionCount, + COUNT(DISTINCT a.id) AS answerCount + FROM tl_survey s + INNER JOIN tl_survey_editor e ON COALESCE(NULLIF(e.survey, 0), e.pid) = s.id AND e.member = :member + LEFT JOIN tl_survey_content q ON q.pid = s.id + LEFT JOIN tl_survey_submission sub ON sub.survey = s.id + LEFT JOIN tl_survey_answer a ON a.submission = sub.id + GROUP BY s.id + ORDER BY s.updatedAt DESC, s.title ASC + SQL, + ['member' => $memberId], + ); + } + + public function create(int $memberId, array $data): SurveyModel + { + $now = time(); + $title = trim((string) ($data['title'] ?? 'Neue Umfrage')); + + $this->connection->insert('tl_survey', [ + 'tstamp' => $now, + 'title' => $title, + 'alias' => $this->ensurePublicAlias(null), + 'category' => serialize($this->normalizeCategoryIds($data['category'] ?? [])), + 'description' => (string) ($data['description'] ?? ''), + 'published' => !empty($data['published']) ? '1' : '', + 'isLocked' => '', + 'createdBy' => $memberId, + 'updatedBy' => $memberId, + 'createdAt' => $now, + 'updatedAt' => $now, + ]); + + $id = (int) $this->connection->lastInsertId(); + $this->refreshListMetadata($id); + + return $this->findById($id) ?? throw new \RuntimeException('Umfrage konnte nicht angelegt werden.'); + } + + public function update(SurveyModel $survey, int $memberId, array $data): void + { + $title = trim((string) ($data['title'] ?? $survey->title)); + + $this->connection->update('tl_survey', [ + 'tstamp' => time(), + 'title' => $title, + 'alias' => $this->ensurePublicAlias((string) $survey->alias, (int) $survey->id), + 'category' => serialize($this->normalizeCategoryIds($data['category'] ?? StringUtil::deserialize($survey->category, true))), + 'description' => (string) ($data['description'] ?? $survey->description), + 'published' => !empty($data['published']) ? '1' : '', + 'updatedBy' => $memberId, + 'updatedAt' => time(), + ], [ + 'id' => (int) $survey->id, + ]); + + $this->refreshListMetadata((int) $survey->id); + } + + public function ensurePublicAlias(?string $alias, int $excludeId = 0): string + { + $candidate = strtolower(trim((string) $alias)); + + if ($this->isValidPublicAlias($candidate) && !$this->aliasExists($candidate, $excludeId)) { + return $candidate; + } + + do { + $candidate = $this->generateRandomPublicAlias(); + } while ($this->aliasExists($candidate, $excludeId)); + + return $candidate; + } + + /** + * @param list $categoryIds + */ + public function updateCategories(int $surveyId, array $categoryIds): void + { + $this->connection->update('tl_survey', [ + 'category' => serialize($this->normalizeCategoryIds($categoryIds)), + 'tstamp' => time(), + 'updatedAt' => time(), + ], [ + 'id' => $surveyId, + ]); + + $this->refreshListMetadata($surveyId); + } + + public function refreshListMetadata(int $surveyId): void + { + if (!$this->hasListMetadataColumns()) { + return; + } + + $survey = $this->findById($surveyId); + + if (!$survey instanceof SurveyModel) { + return; + } + + $categoryIds = $this->normalizeCategoryIds($survey->category); + $categoryTitles = $this->fetchCategoryTitles($categoryIds); + $assignedMembers = $this->fetchAssignedMembers($surveyId); + $memberIds = []; + $memberNames = []; + + foreach ($assignedMembers as $assignedMember) { + $memberIds[] = (int) $assignedMember['id']; + $memberNames[] = (string) $assignedMember['name']; + } + + $this->connection->update('tl_survey', [ + 'categoryFilter' => implode(',', $categoryIds), + 'categorySummary' => implode(', ', $categoryTitles), + 'assignedMembersFilter' => implode(',', $memberIds), + 'assignedMembersSummary' => implode(', ', $memberNames), + ], [ + 'id' => $surveyId, + ]); + } + + public function touch(int $surveyId): void + { + $now = time(); + + $this->connection->update('tl_survey', [ + 'tstamp' => $now, + 'updatedAt' => $now, + ], [ + 'id' => $surveyId, + ]); + } + + public function lock(int $surveyId): void + { + $this->connection->update('tl_survey', [ + 'isLocked' => '1', + 'tstamp' => time(), + 'updatedAt' => time(), + ], [ + 'id' => $surveyId, + ]); + } + + private function generateRandomPublicAlias(): string + { + $characters = 'abcdefghijklmnopqrstuvwxyz0123456789'; + $alias = ''; + + for ($index = 0; $index < 20; ++$index) { + $alias .= $characters[random_int(0, strlen($characters) - 1)]; + } + + return $alias; + } + + private function aliasExists(string $alias, int $excludeId = 0): bool + { + $qb = $this->connection->createQueryBuilder(); + $qb + ->select('id') + ->from('tl_survey') + ->where('alias = :alias') + ->setParameter('alias', $alias) + ->setMaxResults(1) + ; + + if ($excludeId > 0) { + $qb + ->andWhere('id != :excludeId') + ->setParameter('excludeId', $excludeId) + ; + } + + return false !== $qb->executeQuery()->fetchOne(); + } + + /** + * @param list $categoryIds + * + * @return list + */ + private function fetchCategoryTitles(array $categoryIds): array + { + if ([] === $categoryIds) { + return []; + } + + $placeholders = implode(',', array_fill(0, count($categoryIds), '?')); + $rows = $this->connection->fetchAllAssociative( + sprintf('SELECT id, title FROM tl_survey_category WHERE id IN (%s)', $placeholders), + $categoryIds, + ); + $titlesById = []; + + foreach ($rows as $row) { + $titlesById[(int) $row['id']] = (string) $row['title']; + } + + $titles = []; + + foreach ($categoryIds as $categoryId) { + if (isset($titlesById[$categoryId])) { + $titles[] = $titlesById[$categoryId]; + } + } + + return $titles; + } + + /** + * @return list + */ + private function fetchAssignedMembers(int $surveyId): array + { + $rows = $this->connection->fetchAllAssociative( + <<<'SQL' + SELECT DISTINCT + m.id, + m.firstname, + m.lastname, + m.email + FROM tl_survey_editor e + INNER JOIN tl_member m ON m.id = e.member + WHERE COALESCE(NULLIF(e.survey, 0), e.pid) = ? + ORDER BY m.lastname ASC, m.firstname ASC, m.email ASC + SQL, + [$surveyId], + ); + $members = []; + + foreach ($rows as $row) { + $name = trim(sprintf('%s %s', (string) $row['firstname'], (string) $row['lastname'])); + $members[] = [ + 'id' => (int) $row['id'], + 'name' => '' !== $name ? $name : (string) $row['email'], + ]; + } + + return $members; + } + + private function hasListMetadataColumns(): bool + { + if (null !== $this->hasListMetadataColumns) { + return $this->hasListMetadataColumns; + } + + $columnNames = array_map( + static fn (string $columnName): string => strtolower($columnName), + array_keys($this->connection->createSchemaManager()->listTableColumns('tl_survey')), + ); + + return $this->hasListMetadataColumns = !array_diff( + ['categoryfilter', 'categorysummary', 'assignedmembersfilter', 'assignedmemberssummary'], + $columnNames, + ); + } + + private function isValidPublicAlias(string $alias): bool + { + return 1 === preg_match('/^[a-z0-9]{20}$/', $alias); + } + + /** + * @return list + */ + private function normalizeCategoryIds(mixed $value): array + { + $categoryIds = is_array($value) ? $value : StringUtil::deserialize($value, true); + $categoryIds = array_values(array_unique(array_filter(array_map('intval', $categoryIds), static fn (int $id): bool => $id > 0))); + sort($categoryIds); + + return $categoryIds; + } +} \ No newline at end of file diff --git a/src/Repository/SurveySubmissionRepository.php b/src/Repository/SurveySubmissionRepository.php new file mode 100644 index 0000000..6bac2f4 --- /dev/null +++ b/src/Repository/SurveySubmissionRepository.php @@ -0,0 +1,117 @@ +framework->getAdapter(SurveySubmissionModel::class); + $model = $adapter->findByPk($id); + + return $model instanceof SurveySubmissionModel ? $model : null; + } + + public function findOpenBySurveyAndToken(int $surveyId, string $token): ?SurveySubmissionModel + { + $id = $this->connection->fetchOne( + 'SELECT id FROM tl_survey_submission WHERE survey = ? AND token = ? AND isFinished != 1 ORDER BY id DESC LIMIT 1', + [$surveyId, $token], + ); + + return false === $id ? null : $this->findById((int) $id); + } + + public function findBySurveyAndToken(int $surveyId, string $token): ?SurveySubmissionModel + { + $id = $this->connection->fetchOne( + 'SELECT id FROM tl_survey_submission WHERE survey = ? AND token = ? ORDER BY id DESC LIMIT 1', + [$surveyId, $token], + ); + + return false === $id ? null : $this->findById((int) $id); + } + + public function hasFinishedBySurveyAndToken(int $surveyId, string $token): bool + { + return false !== $this->connection->fetchOne( + 'SELECT id FROM tl_survey_submission WHERE survey = ? AND token = ? AND isFinished = 1 ORDER BY id DESC LIMIT 1', + [$surveyId, $token], + ); + } + + public function create(int $surveyId, string $token, ?int $currentQuestionId): SurveySubmissionModel + { + $now = time(); + + $this->connection->insert('tl_survey_submission', [ + 'pid' => $surveyId, + 'survey' => $surveyId, + 'token' => $token, + 'startedAt' => $now, + 'completedAt' => 0, + 'currentQuestion' => $currentQuestionId ?? 0, + 'isFinished' => '', + ]); + + $id = (int) $this->connection->lastInsertId(); + + return $this->findById($id) ?? throw new \RuntimeException('Der Umfrage-Durchlauf konnte nicht angelegt werden.'); + } + + public function updateCurrentQuestion(int $submissionId, ?int $questionId): void + { + $this->connection->update('tl_survey_submission', [ + 'currentQuestion' => $questionId ?? 0, + ], [ + 'id' => $submissionId, + ]); + } + + public function markFinished(int $submissionId): void + { + $this->connection->update('tl_survey_submission', [ + 'isFinished' => '1', + 'completedAt' => time(), + 'currentQuestion' => 0, + ], [ + 'id' => $submissionId, + ]); + } + + /** + * @return list> + */ + public function findOverviewBySurvey(int $surveyId): array + { + return $this->connection->fetchAllAssociative( + <<<'SQL' + SELECT + sub.id, + sub.token, + sub.startedAt, + sub.completedAt, + sub.isFinished, + COUNT(ans.id) AS answerCount + FROM tl_survey_submission sub + LEFT JOIN tl_survey_answer ans ON ans.submission = sub.id + WHERE sub.survey = :survey + GROUP BY sub.id + ORDER BY sub.startedAt DESC + SQL, + ['survey' => $surveyId], + ); + } +} \ No newline at end of file diff --git a/src/Resources/config/routes.yaml b/src/Resources/config/routes.yaml new file mode 100644 index 0000000..00c2a0b --- /dev/null +++ b/src/Resources/config/routes.yaml @@ -0,0 +1,3 @@ +mummert_survey_bundle_controllers: + resource: ../../Controller/ + type: attribute \ No newline at end of file diff --git a/src/Resources/views/pdf/survey_results.html.twig b/src/Resources/views/pdf/survey_results.html.twig new file mode 100644 index 0000000..e82388b --- /dev/null +++ b/src/Resources/views/pdf/survey_results.html.twig @@ -0,0 +1,338 @@ + + + + + + + +

    + + {% for question in questionResults %} +
    +

    {{ question.question }}

    + + {% if question.description %} +

    {{ question.description }}

    + {% endif %} + +
    + {{ question.totalAnswers }} Antworten + {{ question.responseRate }}% Ruecklauf +
    + + {% if question.pdfChartDataUri %} +
    + Diagramm zu {{ question.question }} + {% if question.type == 'range' and question.pdfChartLegend %} +
    Die Punkte sind farblich den Werten in der Tabelle zugeordnet.
    + {% endif %} +
    + {% endif %} + + {% if question.type in ['yes_no_maybe', 'choice'] %} + + + + + + + + + + + {% for option in question.pdfChartLegend %} + + + + + + + {% else %} + + + + {% endfor %} + +
    FarbeOptionAnzahlAnteil
    {{ option.label }}{{ option.count }}{{ option.percentage }}%
    Noch keine Daten vorhanden.
    + {% elseif question.type == 'range' %} +
    +
    + Minimum + {{ question.minimum is not null ? question.minimum : '-' }} +
    +
    + Maximum + {{ question.maximum is not null ? question.maximum : '-' }} +
    +
    + Durchschnitt + {{ question.average is not null ? question.average : '-' }} +
    +
    + + + + + + + + + + + + {% for option in question.pdfChartLegend %} + + + + + + + {% else %} + + + + {% endfor %} + +
    FarbeWertAnzahlAnteil
    {{ option.label }}{{ option.count }}{{ option.percentage }}%
    Noch keine Bewertungen vorhanden.
    + {% else %} + {% if question.pdfChartLegend %} + + + + + + + + + + + {% for option in question.pdfChartLegend %} + + + + + + + {% endfor %} + +
    FarbeAntwortgruppeAnzahlAnteil
    {{ option.label }}{{ option.count }}{{ option.percentage }}%
    + {% endif %} + +
      + {% for response in question.responses %} +
    1. {{ response }}
    2. + {% else %} +
    3. Noch keine Freitextantworten vorhanden.
    4. + {% endfor %} +
    + {% endif %} +
    + {% else %} +
    +

    Keine Fragen vorhanden

    +

    Fuer diese Umfrage sind noch keine Fragen angelegt.

    +
    + {% endfor %} + + + + \ No newline at end of file diff --git a/src/Security/SurveyEditorVoter.php b/src/Security/SurveyEditorVoter.php new file mode 100644 index 0000000..1b5d91e --- /dev/null +++ b/src/Security/SurveyEditorVoter.php @@ -0,0 +1,36 @@ +getUser(); + + if (!$user instanceof FrontendUser || !$subject instanceof SurveyModel) { + return false; + } + + return $this->surveyPermissionService->canEditSurvey($subject, $user); + } +} \ No newline at end of file diff --git a/src/Service/SurveyCategoryAssignmentService.php b/src/Service/SurveyCategoryAssignmentService.php new file mode 100644 index 0000000..bc8b2a2 --- /dev/null +++ b/src/Service/SurveyCategoryAssignmentService.php @@ -0,0 +1,111 @@ + + */ + public function getMemberCategoryIds(int $memberId): array + { + $value = $this->connection->fetchOne('SELECT surveyCategories FROM tl_member WHERE id = ?', [$memberId]); + + return $this->normalizeCategoryIds(false === $value ? [] : $value); + } + + public function applyMemberCategoriesToSurvey(int $memberId, int $surveyId): void + { + if ($memberId <= 0 || $surveyId <= 0) { + return; + } + + $this->syncSurvey($surveyId, [ + $memberId => $this->getMemberCategoryIds($memberId), + ]); + } + + /** + * @param list|null $categoryIds + */ + public function syncAssignedSurveys(int $memberId, ?array $categoryIds = null): void + { + if ($memberId <= 0) { + return; + } + + $normalizedCategoryIds = $this->normalizeCategoryIds($categoryIds ?? $this->getMemberCategoryIds($memberId)); + + foreach ($this->surveyEditorRepository->findSurveyIdsByMember($memberId) as $surveyId) { + $this->syncSurvey($surveyId, [ + $memberId => $normalizedCategoryIds, + ]); + } + } + + public function syncSurvey(int $surveyId, array $memberCategoryOverrides = []): void + { + if ($surveyId <= 0) { + return; + } + + $categoryIds = []; + + foreach ($this->surveyEditorRepository->findMemberIdsBySurvey($surveyId) as $memberId) { + $memberCategoryIds = $memberCategoryOverrides[$memberId] ?? $this->getMemberCategoryIds($memberId); + + foreach ($this->normalizeCategoryIds($memberCategoryIds) as $categoryId) { + $categoryIds[] = $categoryId; + } + } + + $this->surveyRepository->updateCategories($surveyId, $this->normalizeCategoryIds($categoryIds)); + } + + public function syncSurveyWithoutMember(int $surveyId, int $memberId): void + { + if ($surveyId <= 0) { + return; + } + + $categoryIds = []; + + foreach ($this->surveyEditorRepository->findMemberIdsBySurvey($surveyId) as $assignedMemberId) { + if ($assignedMemberId === $memberId) { + continue; + } + + foreach ($this->getMemberCategoryIds($assignedMemberId) as $categoryId) { + $categoryIds[] = $categoryId; + } + } + + $this->surveyRepository->updateCategories($surveyId, $this->normalizeCategoryIds($categoryIds)); + } + + /** + * @return list + */ + public function normalizeCategoryIds(mixed $value): array + { + $categoryIds = is_array($value) ? $value : StringUtil::deserialize($value, true); + $categoryIds = array_values(array_unique(array_filter(array_map('intval', $categoryIds), static fn (int $id): bool => $id > 0))); + sort($categoryIds); + + return $categoryIds; + } +} \ No newline at end of file diff --git a/src/Service/SurveyEditorService.php b/src/Service/SurveyEditorService.php new file mode 100644 index 0000000..bad0032 --- /dev/null +++ b/src/Service/SurveyEditorService.php @@ -0,0 +1,107 @@ +toArray(); + $payload['category'] = $this->surveyCategoryAssignmentService->getMemberCategoryIds($memberId); + + $survey = $this->surveyRepository->create($memberId, $payload); + $this->surveyEditorRepository->assignEditor((int) $survey->id, $memberId); + $this->surveyRepository->refreshListMetadata((int) $survey->id); + + return $survey; + } + + public function updateSurvey(SurveyModel $survey, int $memberId, SurveyEditorData $data): void + { + $this->surveyRepository->update($survey, $memberId, $data->toArray()); + } + + public function saveQuestion(SurveyModel $survey, SurveyQuestionData $data, int $questionId = 0): void + { + $this->assertUnlocked($survey); + + if ($questionId > 0) { + $question = $this->surveyQuestionRepository->findByIdForSurvey((int) $survey->id, $questionId); + + if (null === $question) { + throw new \RuntimeException('Die Frage wurde nicht gefunden.'); + } + + $this->surveyQuestionRepository->update($question, $data->toArray()); + $this->surveyRepository->touch((int) $survey->id); + + return; + } + + $this->surveyQuestionRepository->create((int) $survey->id, $data->toArray()); + $this->surveyRepository->touch((int) $survey->id); + } + + public function deleteQuestion(SurveyModel $survey, int $questionId): void + { + $this->assertUnlocked($survey); + + $this->surveyQuestionRepository->delete((int) $survey->id, $questionId); + $this->surveyRepository->touch((int) $survey->id); + } + + public function saveCondition(SurveyModel $survey, SurveyConditionData $data, int $conditionId = 0): void + { + $this->assertUnlocked($survey); + + if ($conditionId > 0) { + $condition = $this->surveyConditionRepository->findById($conditionId); + + if (null === $condition || (int) $condition->pid !== (int) $survey->id) { + throw new \RuntimeException('Die Bedingung wurde nicht gefunden.'); + } + + $this->surveyConditionRepository->update($condition, $data->toArray()); + $this->surveyRepository->touch((int) $survey->id); + + return; + } + + $this->surveyConditionRepository->create((int) $survey->id, $data->toArray()); + $this->surveyRepository->touch((int) $survey->id); + } + + public function deleteCondition(SurveyModel $survey, int $conditionId): void + { + $this->assertUnlocked($survey); + $this->surveyConditionRepository->delete((int) $survey->id, $conditionId); + $this->surveyRepository->touch((int) $survey->id); + } + + private function assertUnlocked(SurveyModel $survey): void + { + if ('1' === (string) $survey->isLocked) { + throw new \RuntimeException('Die Umfrage ist gesperrt, weil bereits Antworten existieren.'); + } + } +} \ No newline at end of file diff --git a/src/Service/SurveyEngine.php b/src/Service/SurveyEngine.php new file mode 100644 index 0000000..9962c08 --- /dev/null +++ b/src/Service/SurveyEngine.php @@ -0,0 +1,38 @@ +surveyConditionRepository->findMatchingCondition( + (int) $survey->id, + (int) $sourceQuestion->id, + mb_strtolower(trim($normalizedAnswer)), + ); + + if (null === $condition) { + return null; + } + + return $this->surveyQuestionRepository->findByIdForSurvey( + (int) $survey->id, + (int) $condition->targetQuestion, + false, + ); + } +} \ No newline at end of file diff --git a/src/Service/SurveyFlowService.php b/src/Service/SurveyFlowService.php new file mode 100644 index 0000000..4ca62da --- /dev/null +++ b/src/Service/SurveyFlowService.php @@ -0,0 +1,134 @@ +isFinished) { + return null; + } + + $questions = $this->getOrderedQuestions($survey); + $currentQuestionId = (int) $submission->currentQuestion; + + if ($currentQuestionId > 0) { + foreach ($questions as $question) { + if ((int) $question->id === $currentQuestionId) { + return $question; + } + } + } + + return $questions[0] ?? null; + } + + public function determineNextQuestion(SurveyModel $survey, SurveyContentModel $currentQuestion, string $normalizedAnswer): ?SurveyContentModel + { + $questions = $this->getOrderedQuestions($survey); + $configuredJumpTarget = $this->resolveYesNoJumpTarget($currentQuestion, $questions, $normalizedAnswer); + + if ($configuredJumpTarget instanceof SurveyContentModel) { + return $configuredJumpTarget; + } + + $conditionalTarget = $this->surveyEngine->resolveConditionalTarget($survey, $currentQuestion, $normalizedAnswer); + + if ($conditionalTarget instanceof SurveyContentModel) { + return $conditionalTarget; + } + + foreach ($questions as $index => $question) { + if ((int) $question->id === (int) $currentQuestion->id) { + return $questions[$index + 1] ?? null; + } + } + + return null; + } + + /** + * @return array{current:int,total:int,percentage:int} + */ + public function getProgress(SurveyModel $survey, ?SurveyContentModel $currentQuestion): array + { + $questions = $this->getOrderedQuestions($survey); + $total = max(1, count($questions)); + $current = 1; + + if ($currentQuestion instanceof SurveyContentModel) { + foreach ($questions as $index => $question) { + if ((int) $question->id === (int) $currentQuestion->id) { + $current = $index + 1; + break; + } + } + } else { + $current = $total; + } + + return [ + 'current' => $current, + 'total' => $total, + 'percentage' => (int) round(($current / $total) * 100), + ]; + } + + /** + * @return list + */ + private function getOrderedQuestions(SurveyModel $survey): array + { + $surveyId = (int) $survey->id; + + if ($this->surveyQuestionRepository->countPublishedBySurvey($surveyId) > 0) { + return $this->surveyQuestionRepository->findAllBySurvey($surveyId, true); + } + + return $this->surveyQuestionRepository->findAllBySurvey($surveyId); + } + + /** + * @param list $questions + */ + private function resolveYesNoJumpTarget(SurveyContentModel $currentQuestion, array $questions, string $normalizedAnswer): ?SurveyContentModel + { + if ('yes_no_maybe' !== (string) $currentQuestion->type) { + return null; + } + + $targetId = match ($normalizedAnswer) { + 'yes' => (int) ($currentQuestion->jumpOnYes ?? 0), + 'no' => (int) ($currentQuestion->jumpOnNo ?? 0), + default => 0, + }; + + if ($targetId <= 0) { + return null; + } + + foreach ($questions as $question) { + if ((int) $question->id === $targetId) { + return $question; + } + } + + return null; + } +} \ No newline at end of file diff --git a/src/Service/SurveyPermissionService.php b/src/Service/SurveyPermissionService.php new file mode 100644 index 0000000..15f1714 --- /dev/null +++ b/src/Service/SurveyPermissionService.php @@ -0,0 +1,29 @@ +surveyEditorRepository->isEditor((int) $survey->id, (int) $member->id); + } + + public function assertEditorAccess(SurveyModel $survey, FrontendUser $member): void + { + if (!$this->canEditSurvey($survey, $member)) { + throw new AccessDeniedHttpException('Sie duerfen diese Umfrage nicht bearbeiten.'); + } + } +} \ No newline at end of file diff --git a/src/Service/SurveyResultsExportService.php b/src/Service/SurveyResultsExportService.php new file mode 100644 index 0000000..d5d9d00 --- /dev/null +++ b/src/Service/SurveyResultsExportService.php @@ -0,0 +1,242 @@ +> $finishedSubmissions + */ + public function createExcelExportResponse(SurveyModel $survey, array $finishedSubmissions): Response + { + [$headers, $columns] = $this->buildExportColumns($this->surveyQuestionRepository->findAllBySurvey((int) $survey->id)); + $rows = [ + [(string) $survey->title], + $headers, + ]; + + foreach ($finishedSubmissions as $submission) { + $answers = $this->surveyAnswerRepository->findAnswersBySubmission((int) $submission['id']); + $answersByQuestion = []; + + foreach ($answers as $answer) { + $answersByQuestion[(int) ($answer['questionId'] ?? 0)] = (string) ($answer['value'] ?? ''); + } + + $row = []; + + foreach ($columns as $column) { + $questionId = (int) $column['questionId']; + $value = $answersByQuestion[$questionId] ?? ''; + + switch ((string) $column['kind']) { + case 'option': + $selectedValues = array_filter(array_map('trim', explode(' | ', $value)), static fn (string $entry): bool => '' !== $entry); + $row[] = in_array((string) $column['value'], $selectedValues, true) ? 1 : ''; + break; + + case 'range': + case 'text': + default: + $row[] = $value; + break; + } + } + + $rows[] = $row; + } + + $response = new Response($this->buildSpreadsheetContent($rows)); + $disposition = $response->headers->makeDisposition( + ResponseHeaderBag::DISPOSITION_ATTACHMENT, + $this->buildExportFilename((string) $survey->title) + ); + + $response->headers->set('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); + $response->headers->set('Content-Disposition', $disposition); + $response->headers->set('Cache-Control', 'private, no-store, no-cache, must-revalidate'); + $response->headers->set('Pragma', 'no-cache'); + $response->headers->set('X-Content-Type-Options', 'nosniff'); + + return $response; + } + + /** + * @param list $questions + * + * @return array{0:list,1:list} + */ + private function buildExportColumns(array $questions): array + { + $headers = []; + $columns = []; + + foreach (array_values($questions) as $index => $question) { + $questionNumber = $index + 1; + $prefix = 'F'.$questionNumber; + + switch ((string) $question->type) { + case 'yes_no_maybe': + foreach ($this->getYesNoMaybeLabels($question) as $label => $value) { + $headers[] = $prefix.' '.$label; + $columns[] = [ + 'questionId' => (int) $question->id, + 'kind' => 'option', + 'value' => $value, + ]; + } + break; + + case 'choice': + foreach ($this->getChoiceLabels($question) as $label) { + $headers[] = $prefix.' '.$label; + $columns[] = [ + 'questionId' => (int) $question->id, + 'kind' => 'option', + 'value' => $label, + ]; + } + break; + + case 'range': + $headers[] = $prefix.' Wert'; + $columns[] = [ + 'questionId' => (int) $question->id, + 'kind' => 'range', + 'value' => '', + ]; + break; + + case 'text': + default: + $headers[] = $prefix.' Text'; + $columns[] = [ + 'questionId' => (int) $question->id, + 'kind' => 'text', + 'value' => '', + ]; + break; + } + } + + return [$headers, $columns]; + } + + /** + * @return array + */ + private function getYesNoMaybeLabels(SurveyContentModel $question): array + { + $labels = [ + 'ja' => 'yes', + 'nein' => 'no', + ]; + + if ('1' === (string) $question->allowMaybe) { + $labels['vielleicht'] = 'maybe'; + } + + return $labels; + } + + /** + * @return list + */ + private function getChoiceLabels(SurveyContentModel $question): array + { + $labels = []; + + for ($index = 1; $index <= 10; ++$index) { + $option = trim((string) $question->{'answerOption'.$index}); + + if ('' !== $option) { + $labels[] = $option; + } + } + + return $labels; + } + + /** + * @param list> $rows + */ + private function buildSpreadsheetContent(array $rows): string + { + $spreadsheet = new Spreadsheet(); + $worksheet = $spreadsheet->getActiveSheet(); + $worksheet->setTitle('Ergebnisse'); + + foreach ($rows as $rowIndex => $row) { + foreach ($row as $columnIndex => $cellValue) { + $coordinate = Coordinate::stringFromColumnIndex($columnIndex + 1).($rowIndex + 1); + + if (is_int($cellValue) || is_float($cellValue)) { + $worksheet->setCellValue($coordinate, $cellValue); + + continue; + } + + $worksheet->setCellValueExplicit($coordinate, (string) $cellValue, DataType::TYPE_STRING); + } + } + + $lastColumn = Coordinate::stringFromColumnIndex(max(1, count($rows[1] ?? $rows[0] ?? []))); + $worksheet->getStyle('A1')->getFont()->setBold(true)->setSize(14); + $worksheet->getStyle('A2:'.$lastColumn.'2')->getFont()->setBold(true); + $worksheet->freezePane('A3'); + + for ($column = 1; $column <= max(1, count($rows[1] ?? $rows[0] ?? [])); ++$column) { + $worksheet->getColumnDimension(Coordinate::stringFromColumnIndex($column))->setAutoSize(true); + } + + $writer = new Xlsx($spreadsheet); + ob_start(); + + try { + $writer->save('php://output'); + $content = ob_get_clean(); + } catch (\Throwable $throwable) { + ob_end_clean(); + $spreadsheet->disconnectWorksheets(); + + throw $throwable; + } + + $spreadsheet->disconnectWorksheets(); + + return false === $content ? '' : $content; + } + + private function buildExportFilename(string $title): string + { + $baseName = StringUtil::stripInsertTags($title); + $baseName = preg_replace('/[^A-Za-z0-9]+/', '-', $baseName ?? '') ?? 'umfrage-ergebnisse'; + $baseName = trim($baseName, '-'); + + if ('' === $baseName) { + $baseName = 'umfrage-ergebnisse'; + } + + return $baseName.'.xlsx'; + } +} \ No newline at end of file diff --git a/src/Service/SurveyResultsPdfService.php b/src/Service/SurveyResultsPdfService.php new file mode 100644 index 0000000..dfdfbf5 --- /dev/null +++ b/src/Service/SurveyResultsPdfService.php @@ -0,0 +1,409 @@ +getGotenbergBaseUrl(); + } + + /** + * @param list> $questionResults + */ + public function createPdfExportResponse(SurveyModel $survey, int $completedSubmissionCount, array $questionResults): Response + { + $gotenbergBaseUrl = $this->getGotenbergBaseUrl(); + + if (null === $gotenbergBaseUrl) { + throw new BadRequestHttpException('Es wurde keine Gotenberg-URL in den Einstellungen hinterlegt.'); + } + + $html = $this->renderTemplate( + $survey, + $completedSubmissionCount, + $this->prepareQuestionResults($questionResults), + ); + $filename = $this->buildFilename((string) $survey->title); + $pdfContent = $this->requestPdfFromGotenberg($gotenbergBaseUrl, $html, $filename); + + return new Response( + $pdfContent, + Response::HTTP_OK, + [ + 'Content-Type' => 'application/pdf', + 'Content-Disposition' => sprintf('attachment; filename="%s"', $filename), + ], + ); + } + + private function getGotenbergBaseUrl(): ?string + { + $url = trim((string) Config::get('surveyGotenbergUrl')); + + return '' !== $url ? rtrim($url, '/') : null; + } + + private function requestPdfFromGotenberg(string $gotenbergBaseUrl, string $html, string $filename): string + { + $formData = new FormDataPart([ + 'files' => new DataPart($html, 'index.html', 'text/html'), + 'paperWidth' => '8.27', + 'paperHeight' => '11.7', + 'marginTop' => '0.5', + 'marginBottom' => '0.5', + 'marginLeft' => '0.5', + 'marginRight' => '0.5', + 'emulatedMediaType' => 'screen', + 'printBackground' => 'true', + 'failOnConsoleExceptions' => 'true', + 'failOnResourceLoadingFailed' => 'true', + ]); + + $headers = $formData->getPreparedHeaders()->toArray(); + $headers['Gotenberg-Output-Filename'] = pathinfo($filename, PATHINFO_FILENAME); + + try { + $response = $this->httpClient->request('POST', $gotenbergBaseUrl.'/forms/chromium/convert/html', [ + 'headers' => $headers, + 'body' => $formData->bodyToIterable(), + 'timeout' => 60, + ]); + } catch (TransportExceptionInterface $exception) { + throw new BadGatewayHttpException('Die Gotenberg-Instanz konnte nicht erreicht werden.', $exception); + } + + $statusCode = $response->getStatusCode(); + $content = $response->getContent(false); + + if (Response::HTTP_OK !== $statusCode) { + $message = trim(strip_tags(substr($content, 0, 500))); + + throw new BadGatewayHttpException(sprintf( + 'Die Gotenberg-Instanz hat den PDF-Export mit HTTP %d abgelehnt%s', + $statusCode, + '' !== $message ? ': '.$message : '.' + )); + } + + return $content; + } + + /** + * @param list> $questionResults + * + * @return list> + */ + private function prepareQuestionResults(array $questionResults): array + { + $preparedResults = []; + + foreach ($questionResults as $questionResult) { + $questionResult['pdfChartType'] = (string) (($questionResult['chart']['type'] ?? '') ?: ''); + $questionResult['pdfChartDataUri'] = $this->buildChartDataUri($questionResult); + $questionResult['pdfChartLegend'] = $this->buildChartLegend($questionResult); + $preparedResults[] = $questionResult; + } + + return $preparedResults; + } + + /** + * @param array $questionResult + * + * @return list + */ + private function buildChartLegend(array $questionResult): array + { + $chart = $questionResult['chart'] ?? null; + + if (!is_array($chart)) { + return []; + } + + $chartType = (string) ($chart['type'] ?? ''); + $sourceRows = match ($chartType) { + 'pie' => $questionResult['options'] ?? $questionResult['responseSummary'] ?? [], + 'line' => $questionResult['distribution'] ?? [], + default => [], + }; + + if (!is_array($sourceRows) || [] === $sourceRows) { + return []; + } + + $dataset = $chart['data']['datasets'][0] ?? []; + $fillColors = match ($chartType) { + 'pie' => is_array($dataset['backgroundColor'] ?? null) ? $dataset['backgroundColor'] : [], + 'line' => is_array($dataset['pointBackgroundColor'] ?? null) ? $dataset['pointBackgroundColor'] : [], + default => [], + }; + $borderColors = match ($chartType) { + 'pie' => is_array($dataset['borderColor'] ?? null) ? $dataset['borderColor'] : [], + 'line' => is_array($dataset['pointBackgroundColor'] ?? null) ? $dataset['pointBackgroundColor'] : [], + default => [], + }; + + $legend = []; + + foreach (array_values($sourceRows) as $index => $row) { + if (!is_array($row)) { + continue; + } + + $legend[] = [ + 'label' => (string) ($row['label'] ?? ''), + 'fillColor' => (string) ($fillColors[$index] ?? '#D3E4F1'), + 'borderColor' => (string) ($borderColors[$index] ?? '#0064AD'), + 'count' => (int) ($row['count'] ?? 0), + 'percentage' => (int) ($row['percentage'] ?? 0), + ]; + } + + return $legend; + } + + private function renderTemplate(SurveyModel $survey, int $completedSubmissionCount, array $questionResults): string + { + $templatePath = __DIR__.'/../Resources/views/pdf/survey_results.html.twig'; + $templateContent = file_get_contents($templatePath); + + if (false === $templateContent) { + throw new \RuntimeException('Die PDF-Template-Datei konnte nicht gelesen werden: '.$templatePath); + } + + return $this->twig->createTemplate($templateContent)->render([ + 'survey' => $survey, + 'completedSubmissionCount' => $completedSubmissionCount, + 'questionResults' => $questionResults, + 'exportedAt' => (new \DateTimeImmutable())->format('d.m.Y H:i'), + ]); + } + + /** + * @param array $questionResult + */ + private function buildChartDataUri(array $questionResult): ?string + { + $chart = $questionResult['chart'] ?? null; + + if (!is_array($chart)) { + return null; + } + + $svg = match ((string) ($chart['type'] ?? '')) { + 'pie' => $this->buildPieChartSvg($questionResult, $chart), + 'line' => $this->buildLineChartSvg($questionResult, $chart), + default => null, + }; + + if (null === $svg) { + return null; + } + + return 'data:image/svg+xml;base64,'.base64_encode($svg); + } + + /** + * @param array $questionResult + * @param array $chart + */ + private function buildPieChartSvg(array $questionResult, array $chart): ?string + { + $options = $questionResult['options'] ?? $questionResult['responseSummary'] ?? []; + + if (!is_array($options) || [] === $options) { + return $this->buildEmptyChartSvg('Noch keine Daten'); + } + + $dataset = $chart['data']['datasets'][0] ?? null; + $fillColors = is_array($dataset['backgroundColor'] ?? null) ? $dataset['backgroundColor'] : []; + $borderColors = is_array($dataset['borderColor'] ?? null) ? $dataset['borderColor'] : []; + $counts = array_map(static fn (array $option): int => (int) ($option['count'] ?? 0), $options); + $total = array_sum($counts); + + if ($total <= 0) { + return $this->buildEmptyChartSvg('Noch keine Daten'); + } + + $centerX = 140.0; + $centerY = 140.0; + $radius = 88.0; + $startAngle = -90.0; + $segments = []; + + foreach ($options as $index => $option) { + $count = (int) ($option['count'] ?? 0); + + if ($count <= 0) { + continue; + } + + $sweepAngle = ($count / $total) * 360.0; + $endAngle = $startAngle + $sweepAngle; + $largeArcFlag = $sweepAngle > 180.0 ? 1 : 0; + + $startPoint = $this->polarToCartesian($centerX, $centerY, $radius, $startAngle); + $endPoint = $this->polarToCartesian($centerX, $centerY, $radius, $endAngle); + $fill = (string) ($fillColors[$index] ?? '#D3E4F1'); + $stroke = (string) ($borderColors[$index] ?? '#0064AD'); + + $segments[] = sprintf( + '', + $centerX, + $centerY, + $startPoint['x'], + $startPoint['y'], + $radius, + $radius, + $largeArcFlag, + $endPoint['x'], + $endPoint['y'], + $this->escapeXml($fill), + $this->escapeXml($stroke), + ); + + $startAngle = $endAngle; + } + + return sprintf( + '%s%d', + implode('', $segments), + $total, + ); + } + + /** + * @param array $questionResult + * @param array $chart + */ + private function buildLineChartSvg(array $questionResult, array $chart): ?string + { + $distribution = $questionResult['distribution'] ?? []; + + if (!is_array($distribution) || [] === $distribution) { + return $this->buildEmptyChartSvg('Noch keine Bewertungen'); + } + + $labels = array_map(static fn (array $row): string => (string) ($row['label'] ?? ''), $distribution); + $values = array_map(static fn (array $row): int => (int) ($row['count'] ?? 0), $distribution); + $maxValue = max(1, max($values)); + + $width = 560.0; + $height = 280.0; + $paddingLeft = 58.0; + $paddingRight = 22.0; + $paddingTop = 24.0; + $paddingBottom = 44.0; + $plotWidth = $width - $paddingLeft - $paddingRight; + $plotHeight = $height - $paddingTop - $paddingBottom; + $steps = max(1, count($values) - 1); + $dataset = is_array($chart['data']['datasets'][0] ?? null) ? $chart['data']['datasets'][0] : []; + $lineColor = (string) ($dataset['borderColor'] ?? '#0064AD'); + $areaFill = (string) ($dataset['backgroundColor'] ?? 'rgba(236, 124, 50, 0.12)'); + $pointColors = is_array($chart['data']['datasets'][0]['pointBackgroundColor'] ?? null) ? $chart['data']['datasets'][0]['pointBackgroundColor'] : []; + $polylinePoints = []; + $areaPolylinePoints = []; + $pointCircles = []; + $xLabels = []; + $yGrid = []; + + for ($tick = 0; $tick <= $maxValue; ++$tick) { + $ratio = $maxValue > 0 ? $tick / $maxValue : 0; + $y = $paddingTop + $plotHeight - ($ratio * $plotHeight); + $yGrid[] = sprintf('', $paddingLeft, $y, $width - $paddingRight, $y); + $yGrid[] = sprintf('%d', $paddingLeft - 8, $y + 4, $tick); + } + + foreach ($values as $index => $value) { + $x = $paddingLeft + ($plotWidth * ($index / $steps)); + $y = $paddingTop + $plotHeight - (($value / $maxValue) * $plotHeight); + $polylinePoints[] = sprintf('%.2f,%.2f', $x, $y); + $areaPolylinePoints[] = sprintf('%.2f,%.2f', $x, $y); + $pointCircles[] = sprintf('', $x, $y, $this->escapeXml((string) ($pointColors[$index] ?? '#EC7C32'))); + $xLabels[] = sprintf('%s', $x, $height - 16, $this->escapeXml($labels[$index])); + } + + $areaPoints = sprintf( + '%.2f,%.2f %s %.2f,%.2f', + $paddingLeft, + $paddingTop + $plotHeight, + implode(' ', $areaPolylinePoints), + $width - $paddingRight, + $paddingTop + $plotHeight, + ); + + return sprintf( + '%s%s%s', + implode('', $yGrid), + $paddingLeft, + $paddingTop + $plotHeight, + $width - $paddingRight, + $paddingTop + $plotHeight, + $paddingLeft, + $paddingTop, + $paddingLeft, + $paddingTop + $plotHeight, + $this->escapeXml($areaFill), + $areaPoints, + $this->escapeXml($lineColor), + implode(' ', $polylinePoints), + implode('', $pointCircles), + implode('', $xLabels), + ); + } + + private function buildEmptyChartSvg(string $label): string + { + return sprintf( + '%s', + $this->escapeXml($label), + ); + } + + /** + * @return array{x:float,y:float} + */ + private function polarToCartesian(float $centerX, float $centerY, float $radius, float $angleInDegrees): array + { + $angleInRadians = deg2rad($angleInDegrees); + + return [ + 'x' => $centerX + ($radius * cos($angleInRadians)), + 'y' => $centerY + ($radius * sin($angleInRadians)), + ]; + } + + private function escapeXml(string $value): string + { + return htmlspecialchars($value, ENT_QUOTES | ENT_XML1, 'UTF-8'); + } + + private function buildFilename(string $title): string + { + $normalizedTitle = preg_replace('/\s+/', '_', trim($title)) ?: 'Umfrage'; + $sanitizedTitle = preg_replace('/[^\pL\pN_-]+/u', '', $normalizedTitle) ?: 'Umfrage'; + + return sprintf('%s_Ergebnisse.pdf', trim($sanitizedTitle, '_-')); + } +} \ No newline at end of file diff --git a/src/Service/SurveyResultsViewService.php b/src/Service/SurveyResultsViewService.php new file mode 100644 index 0000000..bdd26d7 --- /dev/null +++ b/src/Service/SurveyResultsViewService.php @@ -0,0 +1,395 @@ +>} + */ + public function buildForSurvey(SurveyModel $survey): array + { + $overview = $this->surveySubmissionService->getSubmissionOverview($survey); + $finishedSubmissions = array_values(array_filter( + $overview, + static fn (array $submission): bool => '1' === (string) ($submission['isFinished'] ?? '') + )); + + $completedSubmissionCount = count($finishedSubmissions); + $questions = $this->surveyQuestionRepository->findAllBySurvey((int) $survey->id); + $answers = $this->surveyAnswerRepository->findFinishedAnswersBySurvey((int) $survey->id); + + return [ + 'completedSubmissionCount' => $completedSubmissionCount, + 'questionResults' => $this->buildQuestionResults($questions, $answers, $completedSubmissionCount), + ]; + } + + /** + * @param list $questions + * @param list $answers + * + * @return list> + */ + private function buildQuestionResults(array $questions, array $answers, int $completedSubmissionCount): array + { + $answersByQuestion = []; + + foreach ($answers as $answer) { + $answersByQuestion[$answer['questionId']][] = $answer['value']; + } + + $results = []; + + foreach ($questions as $question) { + $questionId = (int) $question->id; + $values = $answersByQuestion[$questionId] ?? []; + $totalAnswers = count($values); + $responseRate = $completedSubmissionCount > 0 ? (int) round(($totalAnswers / $completedSubmissionCount) * 100) : 0; + + $result = [ + 'id' => $questionId, + 'question' => (string) $question->question, + 'description' => (string) ($question->description ?? ''), + 'type' => (string) $question->type, + 'totalAnswers' => $totalAnswers, + 'responseRate' => $responseRate, + 'chart' => null, + ]; + + switch ((string) $question->type) { + case 'yes_no_maybe': + $optionCounts = [ + 'Ja' => 0, + 'Nein' => 0, + ]; + + if ('1' === (string) $question->allowMaybe) { + $optionCounts['Vielleicht'] = 0; + } + + foreach ($values as $value) { + $normalizedValue = mb_strtolower(trim($value)); + + if ('yes' === $normalizedValue) { + ++$optionCounts['Ja']; + } elseif ('no' === $normalizedValue) { + ++$optionCounts['Nein']; + } elseif ('maybe' === $normalizedValue && isset($optionCounts['Vielleicht'])) { + ++$optionCounts['Vielleicht']; + } + } + + $result['options'] = $this->buildOptionStats($optionCounts); + $result['chart'] = $this->buildPieChartConfig($result['options']); + break; + + case 'choice': + $optionCounts = []; + + for ($index = 1; $index <= 10; ++$index) { + $option = trim((string) $question->{'answerOption'.$index}); + + if ('' !== $option) { + $optionCounts[$option] = 0; + } + } + + foreach ($values as $value) { + foreach (array_filter(array_map('trim', explode(' | ', $value)), static fn (string $entry): bool => '' !== $entry) as $selectedOption) { + if (!array_key_exists($selectedOption, $optionCounts)) { + $optionCounts[$selectedOption] = 0; + } + + ++$optionCounts[$selectedOption]; + } + } + + $result['options'] = $this->buildOptionStats($optionCounts); + $result['chart'] = $this->buildPieChartConfig($result['options']); + break; + + case 'range': + $numericValues = array_values(array_map(static fn (string $value): int => (int) $value, $values)); + $distribution = []; + + foreach ($numericValues as $numericValue) { + $label = (string) $numericValue; + $distribution[$label] = ($distribution[$label] ?? 0) + 1; + } + + ksort($distribution, SORT_NATURAL); + + $result['minimum'] = [] !== $numericValues ? min($numericValues) : null; + $result['maximum'] = [] !== $numericValues ? max($numericValues) : null; + $result['average'] = [] !== $numericValues ? round(array_sum($numericValues) / count($numericValues), 2) : null; + $result['distribution'] = $this->buildOptionStats($distribution); + $result['chart'] = $this->buildRangeChartConfig($result['distribution']); + break; + + case 'text': + default: + $result['responses'] = array_values(array_filter($values, static fn (string $value): bool => '' !== trim($value))); + $result['responseSummary'] = $this->buildTextResponseSummary($result['responses']); + $result['chart'] = $this->buildPieChartConfig($result['responseSummary']); + break; + } + + $results[] = $result; + } + + return $results; + } + + /** + * @param array $optionCounts + * + * @return list + */ + private function buildOptionStats(array $optionCounts): array + { + $total = array_sum($optionCounts); + $options = []; + + foreach ($optionCounts as $label => $count) { + $options[] = [ + 'label' => $label, + 'count' => $count, + 'percentage' => $total > 0 ? (int) round(($count / $total) * 100) : 0, + ]; + } + + return $options; + } + + /** + * @param list $options + * + * @return array|null + */ + private function buildPieChartConfig(array $options): ?array + { + if ([] === $options) { + return null; + } + + $palette = $this->buildChartPalette(count($options)); + + return [ + 'type' => 'pie', + 'data' => [ + 'labels' => array_column($options, 'label'), + 'datasets' => [[ + 'data' => array_column($options, 'count'), + 'backgroundColor' => array_column($palette, 'background'), + 'borderColor' => array_column($palette, 'border'), + 'borderWidth' => 2, + 'hoverOffset' => 18, + ]], + ], + 'options' => [ + 'responsive' => true, + 'maintainAspectRatio' => false, + 'plugins' => [ + 'legend' => [ + 'position' => 'bottom', + 'labels' => [ + 'usePointStyle' => true, + 'boxWidth' => 12, + 'padding' => 18, + 'color' => '#555E68', + 'font' => [ + 'family' => 'PT Sans Narrow', + 'size' => 12, + 'weight' => '600', + ], + ], + ], + 'tooltip' => [ + 'backgroundColor' => 'rgba(34, 34, 34, 0.92)', + 'titleFont' => [ + 'family' => 'Blogger Sans', + 'size' => 14, + ], + 'bodyFont' => [ + 'family' => 'PT Sans Narrow', + 'size' => 12, + ], + ], + ], + ], + ]; + } + + /** + * @param list $distribution + * + * @return array|null + */ + private function buildRangeChartConfig(array $distribution): ?array + { + if ([] === $distribution) { + return null; + } + + $pointStyles = ['circle', 'rectRounded', 'triangle', 'star', 'rectRot', 'crossRot']; + $palette = $this->buildChartPalette(count($distribution)); + + return [ + 'type' => 'line', + 'data' => [ + 'labels' => array_column($distribution, 'label'), + 'datasets' => [[ + 'label' => 'Antworten', + 'data' => array_column($distribution, 'count'), + 'borderColor' => '#0064AD', + 'backgroundColor' => 'rgba(236, 124, 50, 0.12)', + 'pointBackgroundColor' => array_column($palette, 'border'), + 'pointBorderColor' => '#ffffff', + 'pointBorderWidth' => 3, + 'pointHoverBorderWidth' => 3, + 'pointRadius' => 7, + 'pointHoverRadius' => 9, + 'pointStyle' => array_map( + static fn (int $index): string => $pointStyles[$index % count($pointStyles)], + array_keys($distribution) + ), + 'fill' => true, + 'tension' => 0.32, + ]], + ], + 'options' => [ + 'responsive' => true, + 'maintainAspectRatio' => false, + 'plugins' => [ + 'legend' => [ + 'display' => false, + ], + 'tooltip' => [ + 'backgroundColor' => 'rgba(34, 34, 34, 0.92)', + 'titleFont' => [ + 'family' => 'Blogger Sans', + 'size' => 14, + ], + 'bodyFont' => [ + 'family' => 'PT Sans Narrow', + 'size' => 12, + ], + ], + ], + 'scales' => [ + 'x' => [ + 'grid' => [ + 'display' => false, + ], + 'ticks' => [ + 'color' => '#555E68', + 'font' => [ + 'family' => 'PT Sans Narrow', + 'weight' => '600', + ], + ], + ], + 'y' => [ + 'beginAtZero' => true, + 'ticks' => [ + 'precision' => 0, + 'color' => '#555E68', + 'font' => [ + 'family' => 'PT Sans Narrow', + 'weight' => '600', + ], + ], + 'grid' => [ + 'color' => 'rgba(162, 168, 180, 0.22)', + ], + ], + ], + ], + ]; + } + + /** + * @param list $responses + * + * @return list + */ + private function buildTextResponseSummary(array $responses): array + { + if ([] === $responses) { + return []; + } + + $counts = []; + + foreach ($responses as $response) { + $label = trim($response); + + if ('' === $label) { + continue; + } + + $counts[$label] = ($counts[$label] ?? 0) + 1; + } + + arsort($counts); + $summary = []; + $remainingCount = 0; + $index = 0; + + foreach ($counts as $label => $count) { + if ($index < 5) { + $summary[$label] = $count; + } else { + $remainingCount += $count; + } + + ++$index; + } + + if ($remainingCount > 0) { + $summary['Weitere Antworten'] = $remainingCount; + } + + return $this->buildOptionStats($summary); + } + + /** + * @return list + */ + private function buildChartPalette(int $count): array + { + $palette = [ + ['background' => 'rgba(0, 100, 173, 0.16)', 'border' => '#0064AD'], + ['background' => 'rgba(236, 124, 50, 0.24)', 'border' => '#EC7C32'], + ['background' => 'rgba(157, 82, 118, 0.18)', 'border' => '#9D5276'], + ['background' => 'rgba(0, 174, 151, 0.22)', 'border' => '#00AE97'], + ['background' => 'rgba(252, 228, 214, 0.9)', 'border' => '#EC7C32'], + ['background' => 'rgba(162, 168, 180, 0.28)', 'border' => '#555E68'], + ['background' => 'rgba(233, 233, 235, 0.9)', 'border' => '#A2A8B4'], + ['background' => 'rgba(34, 34, 34, 0.12)', 'border' => '#222222'], + ]; + + $colors = []; + + for ($index = 0; $index < max(1, $count); ++$index) { + $colors[] = $palette[$index % count($palette)]; + } + + return $colors; + } +} \ No newline at end of file diff --git a/src/Service/SurveySubmissionService.php b/src/Service/SurveySubmissionService.php new file mode 100644 index 0000000..3eacc4d --- /dev/null +++ b/src/Service/SurveySubmissionService.php @@ -0,0 +1,113 @@ +buildSessionKey((int) $survey->id); + $token = (string) $session->get($sessionKey, ''); + + if ('' !== $token) { + $existing = $this->surveySubmissionRepository->findBySurveyAndToken((int) $survey->id, $token); + + if ($existing instanceof SurveySubmissionModel) { + return $existing; + } + } + + $token = (string) new Ulid(); + $submission = $this->surveySubmissionRepository->create((int) $survey->id, $token, $firstQuestion?->id ? (int) $firstQuestion->id : null); + $session->set($sessionKey, $token); + + return $submission; + } + + public function storeAnswer(SurveyModel $survey, SurveySubmissionModel $submission, SurveyContentModel $question, mixed $rawAnswer): string + { + $questionType = $this->questionTypeRegistry->get((string) $question->type); + $normalizedAnswer = $questionType->normalizeAnswer($rawAnswer, $question); + $surveyHadAnswers = $this->surveyAnswerRepository->hasAnswersForSurvey((int) $survey->id); + + $this->surveyAnswerRepository->saveAnswer( + (int) $submission->id, + (int) $question->id, + (string) $question->type, + $normalizedAnswer, + ); + + if (!$surveyHadAnswers && '1' !== (string) $survey->isLocked) { + $this->surveyRepository->lock((int) $survey->id); + } + + return $normalizedAnswer; + } + + public function advance(SurveySubmissionModel $submission, ?SurveyContentModel $nextQuestion): void + { + if ($nextQuestion instanceof SurveyContentModel) { + $this->surveySubmissionRepository->updateCurrentQuestion((int) $submission->id, (int) $nextQuestion->id); + + return; + } + + $this->surveySubmissionRepository->markFinished((int) $submission->id); + } + + /** + * @return list> + */ + public function getAnswersForSubmission(SurveySubmissionModel $submission): array + { + return $this->surveyAnswerRepository->findAnswersBySubmission((int) $submission->id); + } + + /** + * @return list> + */ + public function getSubmissionOverview(SurveyModel $survey): array + { + return $this->surveySubmissionRepository->findOverviewBySurvey((int) $survey->id); + } + + public function hasFinishedSubmissionForSurvey(int $surveyId, SessionInterface $session): bool + { + if ($surveyId <= 0) { + return false; + } + + $token = (string) $session->get($this->buildSessionKey($surveyId), ''); + + if ('' === $token) { + return false; + } + + return $this->surveySubmissionRepository->hasFinishedBySurveyAndToken($surveyId, $token); + } + + private function buildSessionKey(int $surveyId): string + { + return 'mummert_survey_submission_'.$surveyId; + } +} \ No newline at end of file diff --git a/src/SurveyBundle.php b/src/SurveyBundle.php new file mode 100644 index 0000000..820dec9 --- /dev/null +++ b/src/SurveyBundle.php @@ -0,0 +1,15 @@ +