From ecb6bda4d45be7fe49e1dc79e5cec5de250179be Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Fri, 17 Jan 2025 12:48:37 +0000 Subject: [PATCH] Add latest changes from gitlab-org/gitlab@master --- .rubocop_todo/gettext/static_identifier.yml | 1 - .rubocop_todo/gitlab/bounded_contexts.yml | 2 - .rubocop_todo/layout/line_length.yml | 2 - .rubocop_todo/rspec/context_wording.yml | 1 - .../rspec/example_without_description.yml | 1 - .../rspec/factory_bot/avoid_create.yml | 1 - .rubocop_todo/rspec/named_subject.yml | 1 - .rubocop_todo/style/format_string.yml | 1 - .rubocop_todo/style/guard_clause.yml | 1 - .rubocop_todo/style/if_unless_modifier.yml | 1 - .../clusters_list/components/agents.vue | 2 +- .../javascripts/rapid_diffs/adapters.js | 7 +- .../rapid_diffs/toggle_file/adapter.js | 21 + .../components/work_item_parent.vue | 10 +- .../rapid_diffs/diff_file_component.scss | 12 + .../rapid_diffs/diff_file_component.html.haml | 6 +- .../diff_file_header_component.html.haml | 3 + app/finders/notes_finder.rb | 3 + app/models/application_setting.rb | 2 +- app/models/concerns/has_user_type.rb | 1 + app/models/concerns/web_hooks/hook.rb | 206 +++++ app/models/hooks/no_sti_system_hook.rb | 25 + app/models/hooks/project_hook.rb | 2 + app/models/hooks/service_hook.rb | 2 + app/models/hooks/system_hook.rb | 13 +- app/models/hooks/web_hook.rb | 196 +---- app/models/users/credit_card_validation.rb | 2 - app/workers/web_hooks/log_execution_worker.rb | 2 +- config/bounded_contexts.yml | 3 +- config/initializers/session_store.rb | 9 +- ...ckfill_ci_pipeline_messages_project_id.yml | 2 +- db/docs/design_management_designs.yml | 12 +- .../design_management_designs_versions.yml | 1 - db/docs/design_user_mentions.yml | 1 - db/docs/system_hooks.yml | 10 + .../20250114105214_create_system_hooks.rb | 37 + ...esigns_namespace_id_not_null_constraint.rb | 14 + ...4_ensure_backfill_for_pipeline_messages.rb | 32 + ...xes_for_ci_pipeline_messages_project_id.rb | 17 + ...traint_for_pipeline_messages_project_id.rb | 20 + ...cts_organization_id_not_null_constraint.rb | 13 + db/schema_migrations/20250109064713 | 1 + db/schema_migrations/20250113060954 | 1 + db/schema_migrations/20250113060958 | 1 + db/schema_migrations/20250113061914 | 1 + db/schema_migrations/20250113104738 | 1 + db/schema_migrations/20250114105214 | 1 + db/structure.sql | 59 +- .../visual_studio_code/index.md | 40 +- gems/csv_builder/lib/csv_builder.rb | 8 +- gems/csv_builder/lib/csv_builder/builder.rb | 7 +- locale/gitlab.pot | 15 +- qa/qa/tools/ci/qa_changes.rb | 1 - qa/tasks/ci.rake | 55 +- spec/factories/no_sti_system_hooks.rb | 17 + spec/factories/service_hooks.rb | 8 + spec/factories/system_hooks.rb | 8 + .../clusters_list/components/agents_spec.js | 55 ++ .../clusters_list/components/mock_data.js | 24 +- .../rapid_diffs/toggle_file/adapter_spec.js | 66 ++ .../work_items/graphql/resolvers_spec.js | 47 ++ spec/initializers/session_store_spec.rb | 46 +- ...l_partition_id_ci_pipeline_message_spec.rb | 89 --- spec/lib/gitlab/database/sharding_key_spec.rb | 1 - spec/models/hooks/no_sti_system_hook_spec.rb | 92 +++ spec/models/hooks/project_hook_spec.rb | 10 + spec/models/hooks/service_hook_spec.rb | 10 + spec/models/hooks/system_hook_spec.rb | 25 + spec/models/hooks/web_hook_spec.rb | 739 +----------------- spec/support/finder_collection_allowlist.yml | 1 + spec/support/rspec_order_todo.yml | 2 - .../web_hooks/web_hook_shared_examples.rb | 705 +++++++++++++++++ .../typo3_distribution.tar.gz | Bin 87859 -> 89672 bytes 73 files changed, 1697 insertions(+), 1137 deletions(-) create mode 100644 app/assets/javascripts/rapid_diffs/toggle_file/adapter.js create mode 100644 app/models/concerns/web_hooks/hook.rb create mode 100644 app/models/hooks/no_sti_system_hook.rb create mode 100644 db/docs/system_hooks.yml create mode 100644 db/migrate/20250114105214_create_system_hooks.rb create mode 100644 db/post_migrate/20250109064713_add_design_management_designs_namespace_id_not_null_constraint.rb create mode 100644 db/post_migrate/20250113060954_ensure_backfill_for_pipeline_messages.rb create mode 100644 db/post_migrate/20250113060958_sync_indexes_for_ci_pipeline_messages_project_id.rb create mode 100644 db/post_migrate/20250113061914_add_prepare_not_null_constraint_for_pipeline_messages_project_id.rb create mode 100644 db/post_migrate/20250113104738_validate_projects_organization_id_not_null_constraint.rb create mode 100644 db/schema_migrations/20250109064713 create mode 100644 db/schema_migrations/20250113060954 create mode 100644 db/schema_migrations/20250113060958 create mode 100644 db/schema_migrations/20250113061914 create mode 100644 db/schema_migrations/20250113104738 create mode 100644 db/schema_migrations/20250114105214 create mode 100644 spec/factories/no_sti_system_hooks.rb create mode 100644 spec/frontend/rapid_diffs/toggle_file/adapter_spec.js delete mode 100644 spec/lib/gitlab/background_migration/backfill_partition_id_ci_pipeline_message_spec.rb create mode 100644 spec/models/hooks/no_sti_system_hook_spec.rb create mode 100644 spec/support/shared_examples/models/concerns/web_hooks/web_hook_shared_examples.rb diff --git a/.rubocop_todo/gettext/static_identifier.yml b/.rubocop_todo/gettext/static_identifier.yml index 5cfab4577aa..3a5c43c78df 100644 --- a/.rubocop_todo/gettext/static_identifier.yml +++ b/.rubocop_todo/gettext/static_identifier.yml @@ -9,7 +9,6 @@ Gettext/StaticIdentifier: - 'app/services/security/ci_configuration/base_create_service.rb' - 'app/services/users/banned_user_base_service.rb' - 'ee/app/mailers/ee/emails/admin_notification.rb' - - 'ee/app/mailers/emails/namespace_storage_usage_mailer.rb' - 'ee/app/models/integrations/github.rb' - 'ee/app/services/ee/projects/create_from_template_service.rb' - 'ee/app/services/security/security_orchestration_policies/policy_configuration_validation_service.rb' diff --git a/.rubocop_todo/gitlab/bounded_contexts.yml b/.rubocop_todo/gitlab/bounded_contexts.yml index 63fa647f378..05957e372dc 100644 --- a/.rubocop_todo/gitlab/bounded_contexts.yml +++ b/.rubocop_todo/gitlab/bounded_contexts.yml @@ -2630,14 +2630,12 @@ Gitlab/BoundedContexts: - 'ee/app/mailers/emails/epics.rb' - 'ee/app/mailers/emails/group_memberships.rb' - 'ee/app/mailers/emails/merge_commits.rb' - - 'ee/app/mailers/emails/namespace_storage_usage_mailer.rb' - 'ee/app/mailers/emails/okr.rb' - 'ee/app/mailers/emails/oncall_rotation.rb' - 'ee/app/mailers/emails/requirements.rb' - 'ee/app/mailers/emails/user_cap.rb' - 'ee/app/mailers/license_mailer.rb' - 'ee/app/mailers/previews/ci_minutes_usage_mailer_preview.rb' - - 'ee/app/mailers/previews/emails/namespace_storage_usage_mailer_preview.rb' - 'ee/app/mailers/previews/license_mailer_preview.rb' - 'ee/app/models/alert_management/alert_payload_field.rb' - 'ee/app/models/allowed_email_domain.rb' diff --git a/.rubocop_todo/layout/line_length.yml b/.rubocop_todo/layout/line_length.yml index 849fa398b7f..7fe8c9fffda 100644 --- a/.rubocop_todo/layout/line_length.yml +++ b/.rubocop_todo/layout/line_length.yml @@ -487,7 +487,6 @@ Layout/LineLength: - 'ee/app/finders/projects/integrations/jira/by_ids_finder.rb' - 'ee/app/finders/projects/integrations/jira/issues_finder.rb' - 'ee/app/finders/security/pipeline_vulnerabilities_finder.rb' - - 'ee/app/finders/security/vulnerabilities_finder.rb' - 'ee/app/graphql/ee/mutations/boards/lists/create.rb' - 'ee/app/graphql/mutations/analytics/devops_adoption/enabled_namespaces/bulk_enable.rb' - 'ee/app/graphql/mutations/audit_events/external_audit_event_destinations/create.rb' @@ -1103,7 +1102,6 @@ Layout/LineLength: - 'ee/spec/finders/projects/integrations/jira/by_ids_finder_spec.rb' - 'ee/spec/finders/projects/integrations/jira/issues_finder_spec.rb' - 'ee/spec/finders/security/pipeline_vulnerabilities_finder_spec.rb' - - 'ee/spec/finders/security/vulnerabilities_finder_spec.rb' - 'ee/spec/finders/security/vulnerability_reads_finder_spec.rb' - 'ee/spec/finders/snippets_finder_spec.rb' - 'ee/spec/finders/template_finder_spec.rb' diff --git a/.rubocop_todo/rspec/context_wording.yml b/.rubocop_todo/rspec/context_wording.yml index ce5e0ff5ec3..3f945187a52 100644 --- a/.rubocop_todo/rspec/context_wording.yml +++ b/.rubocop_todo/rspec/context_wording.yml @@ -183,7 +183,6 @@ RSpec/ContextWording: - 'ee/spec/finders/productivity_analytics_finder_spec.rb' - 'ee/spec/finders/scim_finder_spec.rb' - 'ee/spec/finders/security/pipeline_vulnerabilities_finder_spec.rb' - - 'ee/spec/finders/security/vulnerabilities_finder_spec.rb' - 'ee/spec/finders/security/vulnerability_reads_finder_spec.rb' - 'ee/spec/finders/snippets_finder_spec.rb' - 'ee/spec/finders/template_finder_spec.rb' diff --git a/.rubocop_todo/rspec/example_without_description.yml b/.rubocop_todo/rspec/example_without_description.yml index ee74e5e5f42..ff34dc41d0e 100644 --- a/.rubocop_todo/rspec/example_without_description.yml +++ b/.rubocop_todo/rspec/example_without_description.yml @@ -426,7 +426,6 @@ RSpec/ExampleWithoutDescription: - 'spec/models/event_spec.rb' - 'spec/models/group_group_link_spec.rb' - 'spec/models/group_spec.rb' - - 'spec/models/hooks/web_hook_spec.rb' - 'spec/models/incident_management/issuable_escalation_status_spec.rb' - 'spec/models/incident_management/timeline_event_spec.rb' - 'spec/models/incident_management/timeline_event_tag_spec.rb' diff --git a/.rubocop_todo/rspec/factory_bot/avoid_create.yml b/.rubocop_todo/rspec/factory_bot/avoid_create.yml index 4c643efa3df..a16979a2e9a 100644 --- a/.rubocop_todo/rspec/factory_bot/avoid_create.yml +++ b/.rubocop_todo/rspec/factory_bot/avoid_create.yml @@ -89,7 +89,6 @@ RSpec/FactoryBot/AvoidCreate: - 'ee/spec/mailers/ee/emails/projects_spec.rb' - 'ee/spec/mailers/emails/group_memberships_spec.rb' - 'ee/spec/mailers/emails/merge_commits_spec.rb' - - 'ee/spec/mailers/emails/namespace_storage_usage_mailer_spec.rb' - 'ee/spec/mailers/emails/requirements_spec.rb' - 'ee/spec/mailers/emails/user_cap_spec.rb' - 'ee/spec/mailers/license_mailer_spec.rb' diff --git a/.rubocop_todo/rspec/named_subject.yml b/.rubocop_todo/rspec/named_subject.yml index 3c3388bcf04..6698145500b 100644 --- a/.rubocop_todo/rspec/named_subject.yml +++ b/.rubocop_todo/rspec/named_subject.yml @@ -81,7 +81,6 @@ RSpec/NamedSubject: - 'ee/spec/finders/projects/integrations/jira/issues_finder_spec.rb' - 'ee/spec/finders/security/approval_groups_finder_spec.rb' - 'ee/spec/finders/security/pipeline_vulnerabilities_finder_spec.rb' - - 'ee/spec/finders/security/vulnerabilities_finder_spec.rb' - 'ee/spec/finders/security/vulnerability_feedbacks_finder_spec.rb' - 'ee/spec/finders/security/vulnerability_reads_finder_spec.rb' - 'ee/spec/finders/snippets_finder_spec.rb' diff --git a/.rubocop_todo/style/format_string.yml b/.rubocop_todo/style/format_string.yml index 8c940cf05b7..6186bbbae2e 100644 --- a/.rubocop_todo/style/format_string.yml +++ b/.rubocop_todo/style/format_string.yml @@ -133,7 +133,6 @@ Style/FormatString: - 'ee/app/helpers/ee/timeboxes_helper.rb' - 'ee/app/helpers/vulnerabilities_helper.rb' - 'ee/app/mailers/ee/emails/admin_notification.rb' - - 'ee/app/mailers/emails/namespace_storage_usage_mailer.rb' - 'ee/app/models/ci/minutes/notification.rb' - 'ee/app/models/dast/profile.rb' - 'ee/app/models/dast/site_profile_secret_variable.rb' diff --git a/.rubocop_todo/style/guard_clause.yml b/.rubocop_todo/style/guard_clause.yml index dfdf20d9a42..cd26a4f819c 100644 --- a/.rubocop_todo/style/guard_clause.yml +++ b/.rubocop_todo/style/guard_clause.yml @@ -215,7 +215,6 @@ Style/GuardClause: - 'ee/app/controllers/smartcard_controller.rb' - 'ee/app/finders/ee/template_finder.rb' - 'ee/app/finders/iterations_finder.rb' - - 'ee/app/finders/security/vulnerabilities_finder.rb' - 'ee/app/graphql/mutations/concerns/mutations/shared_epic_arguments.rb' - 'ee/app/graphql/mutations/iterations/create.rb' - 'ee/app/graphql/mutations/projects/set_locked.rb' diff --git a/.rubocop_todo/style/if_unless_modifier.yml b/.rubocop_todo/style/if_unless_modifier.yml index 1ec427fa02c..cb7716057f2 100644 --- a/.rubocop_todo/style/if_unless_modifier.yml +++ b/.rubocop_todo/style/if_unless_modifier.yml @@ -224,7 +224,6 @@ Style/IfUnlessModifier: - 'ee/app/controllers/projects/path_locks_controller.rb' - 'ee/app/controllers/projects/push_rules_controller.rb' - 'ee/app/finders/security/pipeline_vulnerabilities_finder.rb' - - 'ee/app/finders/security/vulnerabilities_finder.rb' - 'ee/app/graphql/mutations/audit_events/external_audit_event_destinations/create.rb' - 'ee/app/graphql/mutations/audit_events/external_audit_event_destinations/destroy.rb' - 'ee/app/graphql/mutations/boards/scoped_board_mutation.rb' diff --git a/app/assets/javascripts/clusters_list/components/agents.vue b/app/assets/javascripts/clusters_list/components/agents.vue index 79a057760b6..be38f764e09 100644 --- a/app/assets/javascripts/clusters_list/components/agents.vue +++ b/app/assets/javascripts/clusters_list/components/agents.vue @@ -128,7 +128,7 @@ export default { const filteredList = sharedAgents.filter((node, index, list) => { if (!node?.agent) return false; - const isDuplicate = index !== list.findIndex((agent) => agent.id === node.id); + const isDuplicate = index !== list.findIndex((agent) => agent.agent.id === node.agent.id); const isSameProject = node.agent.project.fullPath === this.projectPath; return !isDuplicate && !isSameProject; }); diff --git a/app/assets/javascripts/rapid_diffs/adapters.js b/app/assets/javascripts/rapid_diffs/adapters.js index 3ba1e747e3b..fb9c404263e 100644 --- a/app/assets/javascripts/rapid_diffs/adapters.js +++ b/app/assets/javascripts/rapid_diffs/adapters.js @@ -1,11 +1,14 @@ import { ExpandLinesAdapter } from '~/rapid_diffs/expand_lines/adapter'; +import { ToggleFileAdapter } from '~/rapid_diffs/toggle_file/adapter'; const RAPID_DIFFS_VIEWERS = { text_inline: 'text_inline', text_parallel: 'text_parallel', }; +const COMMON_ADAPTERS = [ExpandLinesAdapter, ToggleFileAdapter]; + export const VIEWER_ADAPTERS = { - [RAPID_DIFFS_VIEWERS.text_inline]: [ExpandLinesAdapter], - [RAPID_DIFFS_VIEWERS.text_parallel]: [ExpandLinesAdapter], + [RAPID_DIFFS_VIEWERS.text_inline]: COMMON_ADAPTERS, + [RAPID_DIFFS_VIEWERS.text_parallel]: COMMON_ADAPTERS, }; diff --git a/app/assets/javascripts/rapid_diffs/toggle_file/adapter.js b/app/assets/javascripts/rapid_diffs/toggle_file/adapter.js new file mode 100644 index 00000000000..13185213b78 --- /dev/null +++ b/app/assets/javascripts/rapid_diffs/toggle_file/adapter.js @@ -0,0 +1,21 @@ +function oppositeToggleButton(clicked) { + const isOpened = clicked.dataset.opened; + const parent = clicked.parentElement; + + return isOpened === '' + ? parent.querySelector('button[data-closed]') + : parent.querySelector('button[data-opened]'); +} + +export const ToggleFileAdapter = { + clicks: { + toggleFile(event) { + const fileBody = this.diffElement.querySelector('[data-file-body]'); + const button = event.target.closest('button'); + const oppositeButton = oppositeToggleButton(button); + + fileBody.hidden = !fileBody.hidden; + oppositeButton.focus(); + }, + }, +}; diff --git a/app/assets/javascripts/work_items/components/work_item_parent.vue b/app/assets/javascripts/work_items/components/work_item_parent.vue index 51e3c76d61d..3ae098a32d4 100644 --- a/app/assets/javascripts/work_items/components/work_item_parent.vue +++ b/app/assets/javascripts/work_items/components/work_item_parent.vue @@ -215,10 +215,12 @@ export default { variables: { input: { fullPath: this.fullPath, - parent: { - ...this.availableWorkItems?.find(({ id }) => id === this.localSelectedItem), - webUrl: this.parentWebUrl ?? null, - }, + parent: this.localSelectedItem + ? { + ...this.availableWorkItems?.find(({ id }) => id === this.localSelectedItem), + webUrl: this.parentWebUrl ?? null, + } + : null, workItemType: this.workItemType, }, }, diff --git a/app/assets/stylesheets/components/rapid_diffs/diff_file_component.scss b/app/assets/stylesheets/components/rapid_diffs/diff_file_component.scss index 6069cd92e1d..bff4a918452 100644 --- a/app/assets/stylesheets/components/rapid_diffs/diff_file_component.scss +++ b/app/assets/stylesheets/components/rapid_diffs/diff_file_component.scss @@ -2,6 +2,11 @@ padding-bottom: $gl-padding; --rd-diff-file-border-radius: #{calc($gl-border-radius-base - 1px)}; + + &:has([data-file-body][hidden]) .rd-diff-file-toggle [data-opened], + &:not(:has([data-file-body][hidden])) .rd-diff-file-toggle [data-closed] { + display: none; + } } .rd-diff-file-header { @@ -36,3 +41,10 @@ border-radius: inherit; } } + +[data-file-body][hidden] { + display: block !important; + // https://web.dev/articles/content-visibility#hide_content_with_content-visibility_hidden + // content-visibility: hidden preserves element's rendering state which improves performance for larger diffs + content-visibility: hidden; +} diff --git a/app/components/rapid_diffs/diff_file_component.html.haml b/app/components/rapid_diffs/diff_file_component.html.haml index a4cfca8fdb5..948278b97c2 100644 --- a/app/components/rapid_diffs/diff_file_component.html.haml +++ b/app/components/rapid_diffs/diff_file_component.html.haml @@ -3,6 +3,8 @@ %diff-file{ id: id, data: server_data } .rd-diff-file = render RapidDiffs::DiffFileHeaderComponent.new(diff_file: @diff_file) - .rd-diff-file-body - = render viewer_component.new(diff_file: @diff_file) + -# extra wrapper needed so content-visibility: hidden doesn't require removing border or other styles + %div{ data: { file_body: '' } } + .rd-diff-file-body + = render viewer_component.new(diff_file: @diff_file) %diff-file-mounted diff --git a/app/components/rapid_diffs/diff_file_header_component.html.haml b/app/components/rapid_diffs/diff_file_header_component.html.haml index 155aecfffca..3d328292654 100644 --- a/app/components/rapid_diffs/diff_file_header_component.html.haml +++ b/app/components/rapid_diffs/diff_file_header_component.html.haml @@ -13,6 +13,9 @@ -# * submodule compare .rd-diff-file-header{ data: { testid: 'rd-diff-file-header' } } + .rd-diff-file-toggle.gl-mr-2< + = render Pajamas::ButtonComponent.new(category: :tertiary, size: :small, icon: 'chevron-down', button_options: { data: { opened: '', click: 'toggleFile' }, aria: { label: _('Hide file contents') } }) + = render Pajamas::ButtonComponent.new(category: :tertiary, size: :small, icon: 'chevron-right', button_options: { data: { closed: '', click: 'toggleFile' }, aria: { label: _('Show file contents') } }) .rd-diff-file-title - if @diff_file.submodule? %span diff --git a/app/finders/notes_finder.rb b/app/finders/notes_finder.rb index 050dd3616aa..42a92410953 100644 --- a/app/finders/notes_finder.rb +++ b/app/finders/notes_finder.rb @@ -80,6 +80,9 @@ class NotesFinder { iid: iid } end + # the reads finder needs to query by vulnerability_id + return noteables_for_type(type).find_by!(vulnerability_id: query[:id]) if type == 'vulnerability' # rubocop: disable CodeReuse/ActiveRecord + noteables_for_type(type).find_by!(query) # rubocop: disable CodeReuse/ActiveRecord end diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index 3f47c6ee833..70a1eb0bc2a 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -16,7 +16,7 @@ class ApplicationSetting < ApplicationRecord encrypted_vertex_ai_credentials_iv encrypted_vertex_ai_access_token encrypted_vertex_ai_access_token_iv - ], remove_with: '17.5', remove_after: '2024-09-19' + ], remove_with: '17.10', remove_after: '2025-02-15' ignore_columns %i[ elasticsearch_aws diff --git a/app/models/concerns/has_user_type.rb b/app/models/concerns/has_user_type.rb index 9f599ac1859..204dbda8013 100644 --- a/app/models/concerns/has_user_type.rb +++ b/app/models/concerns/has_user_type.rb @@ -42,6 +42,7 @@ module HasUserType # `service_account` allows instance/namespaces to configure a user for external integrations/automations # `service_user` is an internal, `gitlab-com`-specific user type for integrations like suggested reviewers + # Changes to these types might have billing implications, https://docs.gitlab.com/ee/subscriptions/gitlab_com/#billable-users NON_INTERNAL_USER_TYPES = %w[human project_bot service_user service_account].freeze INTERNAL_USER_TYPES = (USER_TYPES.keys - NON_INTERNAL_USER_TYPES).freeze diff --git a/app/models/concerns/web_hooks/hook.rb b/app/models/concerns/web_hooks/hook.rb new file mode 100644 index 00000000000..f230461f090 --- /dev/null +++ b/app/models/concerns/web_hooks/hook.rb @@ -0,0 +1,206 @@ +# frozen_string_literal: true + +module WebHooks + module Hook + extend ActiveSupport::Concern + + InterpolationError = Class.new(StandardError) + + SECRET_MASK = '************' + + # See app/validators/json_schemas/web_hooks_url_variables.json + VARIABLE_REFERENCE_RE = /\{([A-Za-z]+[0-9]*(?:[._-][A-Za-z0-9]+)*)\}/ + + included do + include Sortable + include WebHooks::AutoDisabling + + attr_encrypted :token, + mode: :per_attribute_iv, + algorithm: 'aes-256-gcm', + key: Settings.attr_encrypted_db_key_base_32 + + attr_encrypted :url, + mode: :per_attribute_iv, + algorithm: 'aes-256-gcm', + key: Settings.attr_encrypted_db_key_base_32 + + attr_encrypted :url_variables, + mode: :per_attribute_iv, + key: Settings.attr_encrypted_db_key_base_32, + algorithm: 'aes-256-gcm', + marshal: true, + marshaler: ::Gitlab::Json, + encode: false, + encode_iv: false + + attr_encrypted :custom_headers, + mode: :per_attribute_iv, + key: Settings.attr_encrypted_db_key_base_32, + algorithm: 'aes-256-gcm', + marshal: true, + marshaler: ::Gitlab::Json, + encode: false, + encode_iv: false + + validates :url, presence: true + validates :url, public_url: true, if: ->(hook) { hook.validate_public_url? && !hook.url_variables? } + + validates :token, format: { without: /\n/ } + + after_initialize :initialize_url_variables + after_initialize :initialize_custom_headers + + before_validation :reset_token + before_validation :reset_url_variables, unless: ->(hook) { hook.is_a?(ServiceHook) }, on: :update + before_validation :reset_custom_headers, unless: ->(hook) { hook.is_a?(ServiceHook) }, on: :update + before_validation :set_branch_filter_nil, if: :branch_filter_strategy_all_branches? + validates :push_events_branch_filter, untrusted_regexp: true, if: :branch_filter_strategy_regex? + validates( + :push_events_branch_filter, "web_hooks/wildcard_branch_filter": true, if: :branch_filter_strategy_wildcard? + ) + + validates :url_variables, json_schema: { filename: 'web_hooks_url_variables' } + validate :no_missing_url_variables + validates :interpolated_url, public_url: true, if: ->(hook) { hook.url_variables? && hook.errors.empty? } + validates :custom_headers, json_schema: { filename: 'web_hooks_custom_headers' } + validates :custom_webhook_template, length: { maximum: 4096 } + + enum :branch_filter_strategy, { + wildcard: 0, + regex: 1, + all_branches: 2 + }, prefix: true + + def execute(data, hook_name, idempotency_key: nil, force: false) + # hook.executable? is checked in WebHookService#execute + WebHookService.new(self, data, hook_name, idempotency_key: idempotency_key, force: force).execute + end + + def async_execute(data, hook_name, idempotency_key: nil) + WebHookService.new(self, data, hook_name, idempotency_key: idempotency_key).async_execute if executable? + end + + # Allow urls pointing localhost and the local network + def allow_local_requests? + Gitlab::CurrentSettings.allow_local_requests_from_web_hooks_and_services? + end + + def help_path + 'user/project/integrations/webhooks' + end + + # @return [Boolean] Whether or not the WebHook is currently throttled. + def rate_limited? + rate_limiter.rate_limited? + end + + # @return [Integer] The rate limit for the WebHook. `0` for no limit. + def rate_limit + rate_limiter.limit + end + + # Returns the associated Project or Group for the WebHook if one exists. + # Overridden by inheriting classes. + def parent; end + + # Custom attributes to be included in the worker context. + def application_context + { related_class: self.class.to_s } + end + + # Exclude binary columns by default - they have no sensible JSON encoding + def serializable_hash(options = nil) + options = options.try(:dup) || {} + options[:except] = Array(options[:except]).dup + options[:except].concat [:encrypted_url_variables, :encrypted_url_variables_iv] + + super + end + + def interpolated_url(url = self.url, url_variables = self.url_variables) + return url unless url.include?('{') + + vars = url_variables + url.gsub(VARIABLE_REFERENCE_RE) do |match| + vars.fetch(match.delete_prefix('{').delete_suffix('}')) + end + rescue KeyError => e + raise InterpolationError, "Invalid URL template. Missing key #{e.key}" + end + + def masked_token + token.present? ? SECRET_MASK : nil + end + + def validate_public_url? + true + end + + private + + def reset_token + self.token = nil if url_changed? && !encrypted_token_changed? + end + + def reset_url_variables + return if url_variables_were.blank? || !interpolated_url_changed? + + self.url_variables = {} if url_variables_were.keys.intersection(url_variables.keys).any? + self.url_variables = {} if url_changed? && url_variables_were.to_a.intersection(url_variables.to_a).any? + end + + def reset_custom_headers + return if url.nil? # checking interpolated_url with a nil url causes errors + return unless interpolated_url_changed? + + self.custom_headers = {} + rescue InterpolationError + # ignore -- record is invalid and won't be saved. no need to reset custom_headers + end + + def interpolated_url_changed? + interpolated_url_was = interpolated_url(decrypt_url_was, url_variables_were) + + interpolated_url_was != interpolated_url + end + + def decrypt_url_was + self.class.decrypt_url(encrypted_url_was, iv: Base64.decode64(encrypted_url_iv_was)) + end + + def url_variables_were + self.class.decrypt_url_variables(encrypted_url_variables_was, iv: encrypted_url_variables_iv_was) + end + + def initialize_url_variables + self.url_variables = {} if encrypted_url_variables.nil? + end + + def initialize_custom_headers + self.custom_headers = {} if encrypted_custom_headers.nil? + end + + def rate_limiter + @rate_limiter ||= Gitlab::WebHooks::RateLimiter.new(self) + end + + def no_missing_url_variables + return if url.nil? + + variable_names = url_variables.keys + used_variables = url.scan(VARIABLE_REFERENCE_RE).map(&:first) + + missing = used_variables - variable_names + + return if missing.empty? + + errors.add(:url, "Invalid URL template. Missing keys: #{missing}") + end + + def set_branch_filter_nil + self.push_events_branch_filter = nil + end + end + end +end diff --git a/app/models/hooks/no_sti_system_hook.rb b/app/models/hooks/no_sti_system_hook.rb new file mode 100644 index 00000000000..6d9ecbe158c --- /dev/null +++ b/app/models/hooks/no_sti_system_hook.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +class NoStiSystemHook < SystemHook # rubocop:disable Gitlab/BoundedContexts, Gitlab/NamespacedClass -- Copied from SystemHook + self.table_name = "system_hooks" + + undef :web_hook_logs + + attr_encrypted :token, + mode: :per_attribute_iv, + algorithm: 'aes-256-gcm', + key: Settings.attr_encrypted_db_key_base_32, + encode: false, + encode_iv: false + + attr_encrypted :url, + mode: :per_attribute_iv, + algorithm: 'aes-256-gcm', + key: Settings.attr_encrypted_db_key_base_32, + encode: false, + encode_iv: false + + def decrypt_url_was + self.class.decrypt_url(encrypted_url_was, iv: encrypted_url_iv_was) + end +end diff --git a/app/models/hooks/project_hook.rb b/app/models/hooks/project_hook.rb index d28ca039d18..1226a76433b 100644 --- a/app/models/hooks/project_hook.rb +++ b/app/models/hooks/project_hook.rb @@ -28,6 +28,8 @@ class ProjectHook < WebHook self.limit_scope = :project + has_many :web_hook_logs, foreign_key: 'web_hook_id', inverse_of: :web_hook + belongs_to :project validates :project, presence: true diff --git a/app/models/hooks/service_hook.rb b/app/models/hooks/service_hook.rb index 2b8459e4848..ffb90b85856 100644 --- a/app/models/hooks/service_hook.rb +++ b/app/models/hooks/service_hook.rb @@ -7,6 +7,8 @@ class ServiceHook < WebHook self.allow_legacy_sti_class = true + has_many :web_hook_logs, foreign_key: 'web_hook_id', inverse_of: :web_hook + belongs_to :integration validates :integration, presence: true diff --git a/app/models/hooks/system_hook.rb b/app/models/hooks/system_hook.rb index 27aacd4732f..fcac07b7574 100644 --- a/app/models/hooks/system_hook.rb +++ b/app/models/hooks/system_hook.rb @@ -1,10 +1,16 @@ # frozen_string_literal: true +# This model is being migrated to the NoStiSystemHook model temporarily. +# Please ensure all changes here are reflected in the new model. +# More info here: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/175729 class SystemHook < WebHook + extend ::Gitlab::Utils::Override include TriggerableHooks self.allow_legacy_sti_class = true + has_many :web_hook_logs, foreign_key: 'web_hook_id', inverse_of: :web_hook + triggerable_hooks [ :repository_update_hooks, :push_hooks, @@ -16,7 +22,7 @@ class SystemHook < WebHook attribute :repository_update_events, default: true attribute :merge_requests_events, default: false - validates :url, system_hook_url: true + validates :url, system_hook_url: true, unless: ->(hook) { hook.url_variables? } # Allow urls pointing localhost and the local network def allow_local_requests? @@ -30,4 +36,9 @@ class SystemHook < WebHook def help_path 'administration/system_hooks' end + + override :validate_public_url? + def validate_public_url? + false + end end diff --git a/app/models/hooks/web_hook.rb b/app/models/hooks/web_hook.rb index 2fe96f69a25..d88c9b7cf7e 100644 --- a/app/models/hooks/web_hook.rb +++ b/app/models/hooks/web_hook.rb @@ -1,199 +1,5 @@ # frozen_string_literal: true class WebHook < ApplicationRecord - include Sortable - include WebHooks::AutoDisabling - - InterpolationError = Class.new(StandardError) - - SECRET_MASK = '************' - - attr_encrypted :token, - mode: :per_attribute_iv, - algorithm: 'aes-256-gcm', - key: Settings.attr_encrypted_db_key_base_32 - - attr_encrypted :url, - mode: :per_attribute_iv, - algorithm: 'aes-256-gcm', - key: Settings.attr_encrypted_db_key_base_32 - - attr_encrypted :url_variables, - mode: :per_attribute_iv, - key: Settings.attr_encrypted_db_key_base_32, - algorithm: 'aes-256-gcm', - marshal: true, - marshaler: ::Gitlab::Json, - encode: false, - encode_iv: false - - attr_encrypted :custom_headers, - mode: :per_attribute_iv, - key: Settings.attr_encrypted_db_key_base_32, - algorithm: 'aes-256-gcm', - marshal: true, - marshaler: ::Gitlab::Json, - encode: false, - encode_iv: false - - has_many :web_hook_logs - - validates :url, presence: true - validates :url, public_url: true, unless: ->(hook) { hook.is_a?(SystemHook) || hook.url_variables? } - - validates :token, format: { without: /\n/ } - after_initialize :initialize_url_variables - after_initialize :initialize_custom_headers - - before_validation :reset_token - before_validation :reset_url_variables, unless: ->(hook) { hook.is_a?(ServiceHook) }, on: :update - before_validation :reset_custom_headers, unless: ->(hook) { hook.is_a?(ServiceHook) }, on: :update - before_validation :set_branch_filter_nil, if: :branch_filter_strategy_all_branches? - validates :push_events_branch_filter, untrusted_regexp: true, if: :branch_filter_strategy_regex? - validates :push_events_branch_filter, "web_hooks/wildcard_branch_filter": true, if: :branch_filter_strategy_wildcard? - - validates :url_variables, json_schema: { filename: 'web_hooks_url_variables' } - validate :no_missing_url_variables - validates :interpolated_url, public_url: true, if: ->(hook) { hook.url_variables? && hook.errors.empty? } - validates :custom_headers, json_schema: { filename: 'web_hooks_custom_headers' } - validates :custom_webhook_template, length: { maximum: 4096 } - - enum branch_filter_strategy: { - wildcard: 0, - regex: 1, - all_branches: 2 - }, _prefix: true - - # rubocop: disable CodeReuse/ServiceClass - def execute(data, hook_name, idempotency_key: nil, force: false) - # hook.executable? is checked in WebHookService#execute - WebHookService.new(self, data, hook_name, idempotency_key: idempotency_key, force: force).execute - end - # rubocop: enable CodeReuse/ServiceClass - - # rubocop: disable CodeReuse/ServiceClass - def async_execute(data, hook_name, idempotency_key: nil) - WebHookService.new(self, data, hook_name, idempotency_key: idempotency_key).async_execute if executable? - end - # rubocop: enable CodeReuse/ServiceClass - - # Allow urls pointing localhost and the local network - def allow_local_requests? - Gitlab::CurrentSettings.allow_local_requests_from_web_hooks_and_services? - end - - def help_path - 'user/project/integrations/webhooks' - end - - # @return [Boolean] Whether or not the WebHook is currently throttled. - def rate_limited? - rate_limiter.rate_limited? - end - - # @return [Integer] The rate limit for the WebHook. `0` for no limit. - def rate_limit - rate_limiter.limit - end - - # Returns the associated Project or Group for the WebHook if one exists. - # Overridden by inheriting classes. - def parent; end - - # Custom attributes to be included in the worker context. - def application_context - { related_class: type } - end - - # Exclude binary columns by default - they have no sensible JSON encoding - def serializable_hash(options = nil) - options = options.try(:dup) || {} - options[:except] = Array(options[:except]).dup - options[:except].concat [:encrypted_url_variables, :encrypted_url_variables_iv] - - super(options) - end - - # See app/validators/json_schemas/web_hooks_url_variables.json - VARIABLE_REFERENCE_RE = /\{([A-Za-z]+[0-9]*(?:[._-][A-Za-z0-9]+)*)\}/ - - def interpolated_url(url = self.url, url_variables = self.url_variables) - return url unless url.include?('{') - - vars = url_variables - url.gsub(VARIABLE_REFERENCE_RE) do - vars.fetch(_1.delete_prefix('{').delete_suffix('}')) - end - rescue KeyError => e - raise InterpolationError, "Invalid URL template. Missing key #{e.key}" - end - - def masked_token - token.present? ? SECRET_MASK : nil - end - - private - - def reset_token - self.token = nil if url_changed? && !encrypted_token_changed? - end - - def reset_url_variables - return if url_variables_were.blank? || !interpolated_url_changed? - - self.url_variables = {} if url_variables_were.keys.intersection(url_variables.keys).any? - self.url_variables = {} if url_changed? && url_variables_were.to_a.intersection(url_variables.to_a).any? - end - - def reset_custom_headers - return if url.nil? # checking interpolated_url with a nil url causes errors - return unless interpolated_url_changed? - - self.custom_headers = {} - rescue InterpolationError - # ignore -- record is invalid and won't be saved. no need to reset custom_headers - end - - def interpolated_url_changed? - interpolated_url_was = interpolated_url(decrypt_url_was, url_variables_were) - - interpolated_url_was != interpolated_url - end - - def decrypt_url_was - self.class.decrypt_url(encrypted_url_was, iv: Base64.decode64(encrypted_url_iv_was)) - end - - def url_variables_were - self.class.decrypt_url_variables(encrypted_url_variables_was, iv: encrypted_url_variables_iv_was) - end - - def initialize_url_variables - self.url_variables = {} if encrypted_url_variables.nil? - end - - def initialize_custom_headers - self.custom_headers = {} if encrypted_custom_headers.nil? - end - - def rate_limiter - @rate_limiter ||= Gitlab::WebHooks::RateLimiter.new(self) - end - - def no_missing_url_variables - return if url.nil? - - variable_names = url_variables.keys - used_variables = url.scan(VARIABLE_REFERENCE_RE).map(&:first) - - missing = used_variables - variable_names - - return if missing.empty? - - errors.add(:url, "Invalid URL template. Missing keys: #{missing}") - end - - def set_branch_filter_nil - self.push_events_branch_filter = nil - end + include WebHooks::Hook end diff --git a/app/models/users/credit_card_validation.rb b/app/models/users/credit_card_validation.rb index 8db0a3efc7c..d196cbe2903 100644 --- a/app/models/users/credit_card_validation.rb +++ b/app/models/users/credit_card_validation.rb @@ -6,8 +6,6 @@ module Users self.table_name = 'user_credit_card_validations' - ignore_columns %i[last_digits network holder_name expiration_date], remove_with: '16.9', remove_after: '2024-01-22' - attr_accessor :last_digits, :network, :holder_name, :expiration_date belongs_to :user diff --git a/app/workers/web_hooks/log_execution_worker.rb b/app/workers/web_hooks/log_execution_worker.rb index 443cb6c0855..97ad8870d52 100644 --- a/app/workers/web_hooks/log_execution_worker.rb +++ b/app/workers/web_hooks/log_execution_worker.rb @@ -16,7 +16,7 @@ module WebHooks # treat this worker as idempotent. Currently this is set to # the Job ID (jid) of the parent worker. def perform(hook_id, log_data, response_category, _unique_by) - hook = WebHook.find_by_id(hook_id) + hook = ::WebHook.find_by_id(hook_id) return unless hook # hook has been deleted before we could run. diff --git a/config/bounded_contexts.yml b/config/bounded_contexts.yml index 7859e3f76ff..59b6e26b48b 100644 --- a/config/bounded_contexts.yml +++ b/config/bounded_contexts.yml @@ -66,7 +66,6 @@ domains: description: Authorization layer feature_categories: - permissions - - system_access Backup: description: Backup and restore @@ -177,7 +176,7 @@ domains: feature_categories: - user_management - groups_and_projects - - system_access + - permissions MergeRequests: description: Code collaboration and review including diffs, MR widgets and mergeability checks diff --git a/config/initializers/session_store.rb b/config/initializers/session_store.rb index 8cc8c39ac74..a40f9f2a062 100644 --- a/config/initializers/session_store.rb +++ b/config/initializers/session_store.rb @@ -18,7 +18,14 @@ raw_config = if File.exist?(Rails.root.join('config/session_store.yml')) {} end -session_cookie_token_prefix = raw_config.fetch(:session_cookie_token_prefix, "") +cell_id = Gitlab.config.cell.id +session_cookie_token_prefix = if raw_config.fetch(:session_cookie_token_prefix, '').present? + raw_config.fetch(:session_cookie_token_prefix) + elsif cell_id.present? + "cell-#{cell_id}" + else + "" + end cookie_key = if Rails.env.development? cookie_key_prefix = raw_config.fetch(:cookie_key, "_gitlab_session") diff --git a/db/docs/batched_background_migrations/backfill_ci_pipeline_messages_project_id.yml b/db/docs/batched_background_migrations/backfill_ci_pipeline_messages_project_id.yml index 042379a665c..45d34b23092 100644 --- a/db/docs/batched_background_migrations/backfill_ci_pipeline_messages_project_id.yml +++ b/db/docs/batched_background_migrations/backfill_ci_pipeline_messages_project_id.yml @@ -5,4 +5,4 @@ feature_category: continuous_integration introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/169208 milestone: '17.6' queued_migration_version: 20241014081026 -finalized_by: # version of the migration that finalized this BBM +finalized_by: 20250113060954 diff --git a/db/docs/design_management_designs.yml b/db/docs/design_management_designs.yml index 2596a74d3f1..85401b0a98c 100644 --- a/db/docs/design_management_designs.yml +++ b/db/docs/design_management_designs.yml @@ -9,14 +9,6 @@ description: Information about Designs, image files under management by the Desi introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/9801 milestone: '11.10' gitlab_schema: gitlab_main_cell -desired_sharding_key: - namespace_id: - references: namespaces - backfill_via: - parent: - foreign_key: project_id - table: projects - sharding_key: namespace_id - belongs_to: project -desired_sharding_key_migration_job_name: BackfillDesignManagementDesignsNamespaceId table_size: small +sharding_key: + namespace_id: namespaces diff --git a/db/docs/design_management_designs_versions.yml b/db/docs/design_management_designs_versions.yml index 3161c8f5b8a..67569654ffd 100644 --- a/db/docs/design_management_designs_versions.yml +++ b/db/docs/design_management_designs_versions.yml @@ -17,5 +17,4 @@ desired_sharding_key: table: design_management_designs sharding_key: namespace_id belongs_to: design - awaiting_backfill_on_parent: true table_size: small diff --git a/db/docs/design_user_mentions.yml b/db/docs/design_user_mentions.yml index 19d7116ddc4..964e24263fc 100644 --- a/db/docs/design_user_mentions.yml +++ b/db/docs/design_user_mentions.yml @@ -17,5 +17,4 @@ desired_sharding_key: table: design_management_designs sharding_key: namespace_id belongs_to: design - awaiting_backfill_on_parent: true table_size: small diff --git a/db/docs/system_hooks.yml b/db/docs/system_hooks.yml new file mode 100644 index 00000000000..cb36f03fbad --- /dev/null +++ b/db/docs/system_hooks.yml @@ -0,0 +1,10 @@ +--- +table_name: system_hooks +classes: +- NoStiSystemHook +feature_categories: +- webhooks +description: Webhooks data for system hooks. NoStiSystemHook is a temporary model whilst migrating system hooks from web_hooks to system_hooks. +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/175729 +milestone: '17.9' +gitlab_schema: gitlab_main_clusterwide diff --git a/db/migrate/20250114105214_create_system_hooks.rb b/db/migrate/20250114105214_create_system_hooks.rb new file mode 100644 index 00000000000..80c04c98851 --- /dev/null +++ b/db/migrate/20250114105214_create_system_hooks.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +class CreateSystemHooks < Gitlab::Database::Migration[2.2] + milestone '17.9' + + def change + create_table :system_hooks do |t| + t.timestamps null: true # rubocop:disable Migration/Timestamps -- Needs to match web_hooks table + t.datetime_with_timezone :disabled_until + + t.integer :recent_failures, limit: 2, default: 0, null: false + t.integer :backoff_count, limit: 2, default: 0, null: false + t.integer :branch_filter_strategy, limit: 2, default: 0, null: false + + t.boolean :push_events, default: true, null: false + t.boolean :merge_requests_events, default: false, null: false + t.boolean :tag_push_events, default: false + t.boolean :enable_ssl_verification, default: true + t.boolean :repository_update_events, default: false, null: false + + t.text :push_events_branch_filter, limit: 5000 + t.text :name, limit: 255 + t.text :description, limit: 2048 + t.text :custom_webhook_template, limit: 4096 + + t.binary :encrypted_token + t.binary :encrypted_token_iv + t.binary :encrypted_url + t.binary :encrypted_url_iv + + t.binary :encrypted_url_variables + t.binary :encrypted_url_variables_iv + t.binary :encrypted_custom_headers + t.binary :encrypted_custom_headers_iv + end + end +end diff --git a/db/post_migrate/20250109064713_add_design_management_designs_namespace_id_not_null_constraint.rb b/db/post_migrate/20250109064713_add_design_management_designs_namespace_id_not_null_constraint.rb new file mode 100644 index 00000000000..1d2c258666c --- /dev/null +++ b/db/post_migrate/20250109064713_add_design_management_designs_namespace_id_not_null_constraint.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +class AddDesignManagementDesignsNamespaceIdNotNullConstraint < Gitlab::Database::Migration[2.2] + disable_ddl_transaction! + milestone '17.9' + + def up + add_not_null_constraint :design_management_designs, :namespace_id + end + + def down + remove_not_null_constraint :design_management_designs, :namespace_id + end +end diff --git a/db/post_migrate/20250113060954_ensure_backfill_for_pipeline_messages.rb b/db/post_migrate/20250113060954_ensure_backfill_for_pipeline_messages.rb new file mode 100644 index 00000000000..2822ddfa0b7 --- /dev/null +++ b/db/post_migrate/20250113060954_ensure_backfill_for_pipeline_messages.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +class EnsureBackfillForPipelineMessages < Gitlab::Database::Migration[2.2] + milestone '17.9' + disable_ddl_transaction! + restrict_gitlab_migration gitlab_schema: :gitlab_ci + + MIGRATION = "BackfillCiPipelineMessagesProjectId" + TABLE = :ci_pipeline_messages + PRIMARY_KEY = :id + ARGUMENTS = %i[ + project_id + p_ci_pipelines + project_id + pipeline_id + partition_id + ] + + def up + ensure_batched_background_migration_is_finished( + job_class_name: MIGRATION, + table_name: TABLE, + column_name: PRIMARY_KEY, + job_arguments: ARGUMENTS, + finalize: true + ) + end + + def down + # no-op + end +end diff --git a/db/post_migrate/20250113060958_sync_indexes_for_ci_pipeline_messages_project_id.rb b/db/post_migrate/20250113060958_sync_indexes_for_ci_pipeline_messages_project_id.rb new file mode 100644 index 00000000000..35d904096ff --- /dev/null +++ b/db/post_migrate/20250113060958_sync_indexes_for_ci_pipeline_messages_project_id.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class SyncIndexesForCiPipelineMessagesProjectId < Gitlab::Database::Migration[2.2] + milestone '17.9' + disable_ddl_transaction! + + TABLE_NAME = :ci_pipeline_messages + INDEX_NAME = :index_ci_pipeline_messages_on_project_id + + def up + add_concurrent_index(TABLE_NAME, :project_id, name: INDEX_NAME) + end + + def down + remove_concurrent_index_by_name(TABLE_NAME, INDEX_NAME) + end +end diff --git a/db/post_migrate/20250113061914_add_prepare_not_null_constraint_for_pipeline_messages_project_id.rb b/db/post_migrate/20250113061914_add_prepare_not_null_constraint_for_pipeline_messages_project_id.rb new file mode 100644 index 00000000000..343fa250798 --- /dev/null +++ b/db/post_migrate/20250113061914_add_prepare_not_null_constraint_for_pipeline_messages_project_id.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +class AddPrepareNotNullConstraintForPipelineMessagesProjectId < Gitlab::Database::Migration[2.2] + milestone '17.9' + disable_ddl_transaction! + + TABLE = :ci_pipeline_messages + COLUMN = :project_id + CONSTRAINT = :check_fe8ee122a2 + + def up + add_not_null_constraint(TABLE, COLUMN, constraint_name: CONSTRAINT, validate: false) + prepare_async_check_constraint_validation(TABLE, name: CONSTRAINT) + end + + def down + unprepare_async_check_constraint_validation(TABLE, name: CONSTRAINT) + drop_constraint(TABLE, CONSTRAINT) + end +end diff --git a/db/post_migrate/20250113104738_validate_projects_organization_id_not_null_constraint.rb b/db/post_migrate/20250113104738_validate_projects_organization_id_not_null_constraint.rb new file mode 100644 index 00000000000..aaf2218e41c --- /dev/null +++ b/db/post_migrate/20250113104738_validate_projects_organization_id_not_null_constraint.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class ValidateProjectsOrganizationIdNotNullConstraint < Gitlab::Database::Migration[2.2] + milestone '17.9' + + def up + validate_not_null_constraint(:projects, :organization_id) + end + + def down + # no-op + end +end diff --git a/db/schema_migrations/20250109064713 b/db/schema_migrations/20250109064713 new file mode 100644 index 00000000000..8b1519f03fc --- /dev/null +++ b/db/schema_migrations/20250109064713 @@ -0,0 +1 @@ +99d9003c96c9706ba3b96fcd758418684af607775eeecc79a34810a211940425 \ No newline at end of file diff --git a/db/schema_migrations/20250113060954 b/db/schema_migrations/20250113060954 new file mode 100644 index 00000000000..cf7bbf5cfd1 --- /dev/null +++ b/db/schema_migrations/20250113060954 @@ -0,0 +1 @@ +2705a1ff207a6d3d19030445e3ddb015188ff9129d54b6d41424998e2a02cd87 \ No newline at end of file diff --git a/db/schema_migrations/20250113060958 b/db/schema_migrations/20250113060958 new file mode 100644 index 00000000000..0bb60fcc590 --- /dev/null +++ b/db/schema_migrations/20250113060958 @@ -0,0 +1 @@ +cb9dce644dab1213ece0db2d5bd013208f25016f9110c7306b3e836d218f82fa \ No newline at end of file diff --git a/db/schema_migrations/20250113061914 b/db/schema_migrations/20250113061914 new file mode 100644 index 00000000000..868c27d7de3 --- /dev/null +++ b/db/schema_migrations/20250113061914 @@ -0,0 +1 @@ +2956d1d9d67f7dca3c1a8f24528876e356122e3b142240f2cb077dc2b807a516 \ No newline at end of file diff --git a/db/schema_migrations/20250113104738 b/db/schema_migrations/20250113104738 new file mode 100644 index 00000000000..19725941d7d --- /dev/null +++ b/db/schema_migrations/20250113104738 @@ -0,0 +1 @@ +c2b012d1fda5f54ab3392c717eb4d780875ebfbc98c0ed9334efc9d0434530f2 \ No newline at end of file diff --git a/db/schema_migrations/20250114105214 b/db/schema_migrations/20250114105214 new file mode 100644 index 00000000000..f293e677fee --- /dev/null +++ b/db/schema_migrations/20250114105214 @@ -0,0 +1 @@ +52007ce16202a4d5dc18538fbe9e3ffa0b5edbf2cdb338c759b50bfba69a1552 \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 666ec4b794b..7a07ebf5fc4 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -296,7 +296,8 @@ CREATE TABLE projects ( suggestion_commit_message character varying(255), project_namespace_id bigint, hidden boolean DEFAULT false NOT NULL, - organization_id bigint + organization_id bigint, + CONSTRAINT check_1a6f946a8a CHECK ((organization_id IS NOT NULL)) ); CREATE FUNCTION find_projects_by_id(projects_id bigint) RETURNS projects @@ -12312,7 +12313,8 @@ CREATE TABLE design_management_designs ( namespace_id bigint, CONSTRAINT check_07155e2715 CHECK ((char_length((filename)::text) <= 255)), CONSTRAINT check_aaf9fa6ae5 CHECK ((char_length(description) <= 1000000)), - CONSTRAINT check_cfb92df01a CHECK ((iid IS NOT NULL)) + CONSTRAINT check_cfb92df01a CHECK ((iid IS NOT NULL)), + CONSTRAINT check_ed4c70e3f1 CHECK ((namespace_id IS NOT NULL)) ); CREATE SEQUENCE design_management_designs_id_seq @@ -21388,6 +21390,46 @@ CREATE SEQUENCE system_access_microsoft_graph_access_tokens_id_seq ALTER SEQUENCE system_access_microsoft_graph_access_tokens_id_seq OWNED BY system_access_microsoft_graph_access_tokens.id; +CREATE TABLE system_hooks ( + id bigint NOT NULL, + created_at timestamp(6) without time zone, + updated_at timestamp(6) without time zone, + disabled_until timestamp with time zone, + recent_failures smallint DEFAULT 0 NOT NULL, + backoff_count smallint DEFAULT 0 NOT NULL, + branch_filter_strategy smallint DEFAULT 0 NOT NULL, + push_events boolean DEFAULT true NOT NULL, + merge_requests_events boolean DEFAULT false NOT NULL, + tag_push_events boolean DEFAULT false, + enable_ssl_verification boolean DEFAULT true, + repository_update_events boolean DEFAULT false NOT NULL, + push_events_branch_filter text, + name text, + description text, + custom_webhook_template text, + encrypted_token bytea, + encrypted_token_iv bytea, + encrypted_url bytea, + encrypted_url_iv bytea, + encrypted_url_variables bytea, + encrypted_url_variables_iv bytea, + encrypted_custom_headers bytea, + encrypted_custom_headers_iv bytea, + CONSTRAINT check_32d89afab7 CHECK ((char_length(push_events_branch_filter) <= 5000)), + CONSTRAINT check_6439bc2682 CHECK ((char_length(name) <= 255)), + CONSTRAINT check_6e64a69bc5 CHECK ((char_length(custom_webhook_template) <= 4096)), + CONSTRAINT check_f6fffb36bd CHECK ((char_length(description) <= 2048)) +); + +CREATE SEQUENCE system_hooks_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + +ALTER SEQUENCE system_hooks_id_seq OWNED BY system_hooks.id; + CREATE TABLE system_note_metadata ( commit_count integer, action character varying, @@ -25171,6 +25213,8 @@ ALTER TABLE ONLY system_access_microsoft_applications ALTER COLUMN id SET DEFAUL ALTER TABLE ONLY system_access_microsoft_graph_access_tokens ALTER COLUMN id SET DEFAULT nextval('system_access_microsoft_graph_access_tokens_id_seq'::regclass); +ALTER TABLE ONLY system_hooks ALTER COLUMN id SET DEFAULT nextval('system_hooks_id_seq'::regclass); + ALTER TABLE ONLY system_note_metadata ALTER COLUMN id SET DEFAULT nextval('system_note_metadata_id_seq'::regclass); ALTER TABLE ONLY taggings ALTER COLUMN id SET DEFAULT nextval('taggings_id_seq'::regclass); @@ -26271,9 +26315,6 @@ ALTER TABLE ONLY chat_names ALTER TABLE ONLY chat_teams ADD CONSTRAINT chat_teams_pkey PRIMARY KEY (id); -ALTER TABLE projects - ADD CONSTRAINT check_1a6f946a8a CHECK ((organization_id IS NOT NULL)) NOT VALID; - ALTER TABLE workspaces ADD CONSTRAINT check_2a89035b04 CHECK ((personal_access_token_id IS NOT NULL)) NOT VALID; @@ -26307,6 +26348,9 @@ ALTER TABLE events ALTER TABLE projects ADD CONSTRAINT check_fa75869cb1 CHECK ((project_namespace_id IS NOT NULL)) NOT VALID; +ALTER TABLE ci_pipeline_messages + ADD CONSTRAINT check_fe8ee122a2 CHECK ((project_id IS NOT NULL)) NOT VALID; + ALTER TABLE ONLY ci_build_needs ADD CONSTRAINT ci_build_needs_pkey PRIMARY KEY (id); @@ -28035,6 +28079,9 @@ ALTER TABLE ONLY system_access_microsoft_applications ALTER TABLE ONLY system_access_microsoft_graph_access_tokens ADD CONSTRAINT system_access_microsoft_graph_access_tokens_pkey PRIMARY KEY (id); +ALTER TABLE ONLY system_hooks + ADD CONSTRAINT system_hooks_pkey PRIMARY KEY (id); + ALTER TABLE ONLY system_note_metadata ADD CONSTRAINT system_note_metadata_pkey PRIMARY KEY (id); @@ -30976,6 +31023,8 @@ CREATE INDEX index_ci_pipeline_chat_data_on_project_id ON ci_pipeline_chat_data CREATE INDEX index_ci_pipeline_messages_on_pipeline_id ON ci_pipeline_messages USING btree (pipeline_id); +CREATE INDEX index_ci_pipeline_messages_on_project_id ON ci_pipeline_messages USING btree (project_id); + CREATE INDEX index_ci_pipeline_metadata_on_project_id ON ci_pipeline_metadata USING btree (project_id); CREATE INDEX index_ci_pipeline_schedule_variables_on_project_id ON ci_pipeline_schedule_variables USING btree (project_id); diff --git a/doc/editor_extensions/visual_studio_code/index.md b/doc/editor_extensions/visual_studio_code/index.md index f6a4d3a0fdf..113e4961dcb 100644 --- a/doc/editor_extensions/visual_studio_code/index.md +++ b/doc/editor_extensions/visual_studio_code/index.md @@ -56,34 +56,50 @@ or **Accept Next Line Of Inline Suggestion**: ## Switch GitLab accounts in VS Code -If you use multiple GitLab accounts (such as personal and work), the extension uses your `git remote` URL -to determine which account to use. In some cases, the extension can't determine which account to use, and -must ask you to select which project and account to use. This can happen: +The GitLab Workflow extension uses one account for each [VS Code Workspace](https://code.visualstudio.com/docs/editor/workspaces) (window). The extension automatically selects the account when: -- If you have a single remote URL `git@gitlab.com:gitlab-org/gitlab-vscode-extension.git`, but two accounts for - `gitlab.com` (like `@sidney` and `@sidney_work`). -- If you have a single GitLab account (for example `@sidney`), but you have multiple remotes, like: - - `origin`: `git@gitlab.com:gitlab-org/gitlab-vscode-extension.git` - - `personal-fork`: `git@gitlab.com:myusername/gitlab-vscode-extension.git` +- You have added only one GitLab account to the extension. +- All workspaces in your VS Code window use the same GitLab account, based on the `git remote` configuration. + +In other cases, you must select a GitLab account for the active VS Code window. + +To change the account selection: + +1. Open the Command Palette: + - For macOS, press Command+Shift+P. + - For Windows or Linux, press Ctrl+Shift+P. +1. Run the command `GitLab: Select Account for this Workspace`. +1. Select your desired account from the list. + +You can also change accounts by selecting the GitLab account status bar item. + +## Select your GitLab project + +When your Git repository can be associated with multiple GitLab projects, the extension cannot determine which account to use. This can happen when you have multiple remotes, for example: + +- `origin`: `git@gitlab.com:gitlab-org/gitlab-vscode-extension.git` +- `personal-fork`: `git@gitlab.com:myusername/gitlab-vscode-extension.git` In these cases, the extension adds a **(multiple projects)** label to show you must choose an account. + To select an account: 1. On the vertical menu bar, select **GitLab Workflow** (**{tanuki}**) to display the extension sidebar. 1. Expand **Issues and Merge Requests**. 1. Select the line containing **(multiple projects)** to expand the list of accounts. -1. Select the option you want to use: +1. Select your desired project: ![select project-account combination](../img/select-project-account_v17_7.png) -The **Issues and Merge requests** list updates with your information. +The **Issues and Merge requests** list updates with your selected project's information. ### Change your selection -To change your account selection for a project: +To change your project selection: 1. On the vertical menu bar, select **GitLab Workflow** (**{tanuki}**) to display the extension sidebar. 1. Expand **Issues and Merge Requests** to show the project list. -1. Right-click the project's name, and select **Clear selected project**. +1. Right-click the project's name. +1. Select **Clear selected project**. ## Use slash commands diff --git a/gems/csv_builder/lib/csv_builder.rb b/gems/csv_builder/lib/csv_builder.rb index 0f5aa538633..f19d4727488 100644 --- a/gems/csv_builder/lib/csv_builder.rb +++ b/gems/csv_builder/lib/csv_builder.rb @@ -29,16 +29,20 @@ module CsvBuilder # * +header_to_value_hash+ - A hash of 'Column Heading' => 'value_method'. # * +associations_to_preload+ - An array of records to preload with a batch of records. # * +replace_newlines+ - default: false - If true, replaces newline characters with a literal "\n" + # * +order_hint+ - default: :created_at - The column used to order the rows # # The value method will be called once for each object in the collection, to # determine the value for that row. It can either be the name of a method on # the object, or a lamda to call passing in the object. - def self.new(collection, header_to_value_hash, associations_to_preload = [], replace_newlines: false) + def self.new( + collection, header_to_value_hash, associations_to_preload = [], replace_newlines: false, + order_hint: :created_at) CsvBuilder::Builder.new( collection, header_to_value_hash, associations_to_preload, - replace_newlines: replace_newlines + replace_newlines: replace_newlines, + order_hint: order_hint ) end end diff --git a/gems/csv_builder/lib/csv_builder/builder.rb b/gems/csv_builder/lib/csv_builder/builder.rb index c270db77f84..faeda38db33 100644 --- a/gems/csv_builder/lib/csv_builder/builder.rb +++ b/gems/csv_builder/lib/csv_builder/builder.rb @@ -6,13 +6,16 @@ module CsvBuilder attr_reader :rows_written - def initialize(collection, header_to_value_hash, associations_to_preload = [], replace_newlines: false) + def initialize( + collection, header_to_value_hash, associations_to_preload = [], replace_newlines: false, + order_hint: :created_at) @header_to_value_hash = header_to_value_hash @collection = collection @truncated = false @rows_written = 0 @associations_to_preload = associations_to_preload @replace_newlines = replace_newlines + @order_hint = order_hint end # Renders the csv to a string @@ -57,7 +60,7 @@ module CsvBuilder def each(&block) if @associations_to_preload&.any? && @collection.respond_to?(:each_batch) - @collection.each_batch(order_hint: :created_at) do |relation| + @collection.each_batch(order_hint: @order_hint) do |relation| relation.preload(@associations_to_preload).order(:id).each(&block) end elsif @collection.respond_to?(:find_each) diff --git a/locale/gitlab.pot b/locale/gitlab.pot index e0af3a1ef57..4fa9ee41710 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -36884,13 +36884,10 @@ msgstr[1] "" msgid "NamespaceStorageSize|%{namespace_name} is now read-only. Your ability to write new data to this namespace is restricted. %{read_only_link_start}Which actions are restricted?%{link_end}" msgstr "" -msgid "NamespaceStorageSize|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}." +msgid "NamespaceStorageSize|If %{namespace_name} exceeds the %{storage_docs_link_start}storage quota%{link_end}, your ability to write new data to this namespace will be restricted. %{read_only_link_start}Which actions become restricted?%{link_end}" msgstr "" -msgid "NamespaceStorageSize|If %{namespace_name} exceeds the storage quota, your ability to write new data to this namespace will be restricted. %{read_only_link_start}Which actions become restricted?%{link_end}" -msgstr "" - -msgid "NamespaceStorageSize|If a project reaches 100%% of the storage quota (%{free_size_limit}) the project will be in a read-only state, and you won't be able to push to your repository or add large files." +msgid "NamespaceStorageSize|If a project reaches 100%% of the %{storage_docs_link_start}storage quota%{link_end} (%{free_size_limit}) the project will be in a read-only state, and you won't be able to push to your repository or add large files." msgstr "" msgid "NamespaceStorageSize|To manage your usage and prevent your projects from being placed in a read-only state, you should immediately %{manage_storage_link_start}reduce storage%{link_end}, or %{support_link_start}contact support%{link_end} to help you manage your usage." @@ -36920,7 +36917,7 @@ msgstr "" msgid "NamespaceStorageSize|We've noticed an unusually high storage usage on %{namespace_name}" msgstr "" -msgid "NamespaceStorageSize|You have consumed all available storage and you can't push or add large files to projects over the free tier limit (%{free_size_limit})." +msgid "NamespaceStorageSize|You have consumed all available %{storage_docs_link_start}storage%{link_end} and you can't push or add large files to projects over the free tier limit (%{free_size_limit})." msgstr "" msgid "NamespaceStorageSize|You have reached the free storage limit of %{free_size_limit} for %{namespace_name}" @@ -52397,6 +52394,9 @@ msgstr "" msgid "SecurityReports|New feature: Grouping" msgstr "" +msgid "SecurityReports|New status must be different than current status." +msgstr "" + msgid "SecurityReports|No identifiers found." msgstr "" @@ -62995,6 +62995,9 @@ msgstr "" msgid "VulnerabilityManagement|Dismiss as..." msgstr "" +msgid "VulnerabilityManagement|Dismissed: %{dismissalReason}" +msgstr "" + msgid "VulnerabilityManagement|Enter a name" msgstr "" diff --git a/qa/qa/tools/ci/qa_changes.rb b/qa/qa/tools/ci/qa_changes.rb index 5dbe90b93fe..5f092299342 100644 --- a/qa/qa/tools/ci/qa_changes.rb +++ b/qa/qa/tools/ci/qa_changes.rb @@ -50,7 +50,6 @@ module QA # # @return [Boolean] def quarantine_changes? - return false if mr_diff.empty? return false if mr_diff.any? { |change| change[:new_file] || change[:deleted_file] } files_count = 0 diff --git a/qa/tasks/ci.rake b/qa/tasks/ci.rake index 07c0620f787..e2781fb80b2 100644 --- a/qa/tasks/ci.rake +++ b/qa/tasks/ci.rake @@ -8,7 +8,7 @@ namespace :ci do include Task::Helpers::Util include QA::Tools::Ci::Helpers - logger.info("*** Analyzing merge request changes*** ") + logger.info("*** Analyzing which E2E tests to execute based on MR changes or Scheduled pipeline ***") pipeline_path = args[:pipeline_path] || "tmp" run_all_label_present = mr_labels.include?("pipeline:run-all-e2e") @@ -30,32 +30,37 @@ namespace :ci do end diff = mr_diff - qa_changes = QA::Tools::Ci::QaChanges.new(diff) - if qa_changes.quarantine_changes? - logger.info("Merge request contains only quarantine changes, e2e test execution will be skipped!") - next pipeline_creator.create_noop - end - - if qa_changes.only_spec_removal? - logger.info("Merge request contains only e2e spec removal, e2e test execution will be skipped!") - next pipeline_creator.create_noop - end - - feature_flags_changes = QA::Tools::Ci::FfChanges.new(diff).fetch - # on run-all label or framework changes do not infer specific tests - run_all_tests = run_all_label_present || qa_changes.framework_changes? || - !feature_flags_changes.nil? - tests = run_all_tests ? [] : qa_changes.qa_tests - - if run_all_label_present - logger.info("Merge request has pipeline:run-all-e2e label, full test suite will be executed") - elsif qa_changes.framework_changes? # run all tests when framework changes detected - logger.info("Merge request contains qa framework changes, full test suite will be executed") - elsif tests.any? - logger.info("Following specs were selected for execution: '#{tests}'") + if diff.empty? + logger.info("No specific specs to execute detected, running full test suites") else - logger.info("No specific specs to execute detected, full test suite will be executed") + qa_changes = QA::Tools::Ci::QaChanges.new(diff) + + if qa_changes.quarantine_changes? + logger.info("Merge request contains only quarantine changes, e2e test execution will be skipped!") + next pipeline_creator.create_noop + end + + if qa_changes.only_spec_removal? + logger.info("Merge request contains only e2e spec removal, e2e test execution will be skipped!") + next pipeline_creator.create_noop + end + + feature_flags_changes = QA::Tools::Ci::FfChanges.new(diff).fetch + # on run-all label or framework changes do not infer specific tests + run_all_tests = run_all_label_present || qa_changes.framework_changes? || + !feature_flags_changes.nil? + tests = run_all_tests ? [] : qa_changes.qa_tests + + if run_all_label_present + logger.info("Merge request has pipeline:run-all-e2e label, full test suite will be executed") + elsif qa_changes.framework_changes? # run all tests when framework changes detected + logger.info("Merge request contains qa framework changes, full test suite will be executed") + elsif tests.any? + logger.info("Following specs were selected for execution: '#{tests}'") + else + logger.info("No specific specs to execute detected, full test suite will be executed") + end end creator_args = { diff --git a/spec/factories/no_sti_system_hooks.rb b/spec/factories/no_sti_system_hooks.rb new file mode 100644 index 00000000000..b9090838389 --- /dev/null +++ b/spec/factories/no_sti_system_hooks.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :no_sti_system_hook do + url { generate(:url) } + name { generate(:name) } + description { "Description of #{name}" } + + trait :token do + token { generate(:token) } + end + + trait :url_variables do + url_variables { { 'abc' => 'supers3cret', 'def' => 'foobar' } } + end + end +end diff --git a/spec/factories/service_hooks.rb b/spec/factories/service_hooks.rb index ea70d2fc433..7502eafed7f 100644 --- a/spec/factories/service_hooks.rb +++ b/spec/factories/service_hooks.rb @@ -4,5 +4,13 @@ FactoryBot.define do factory :service_hook do url { generate(:url) } integration + + trait :url_variables do + url_variables { { 'abc' => 'supers3cret', 'def' => 'foobar' } } + end + + trait :token do + token { generate(:token) } + end end end diff --git a/spec/factories/system_hooks.rb b/spec/factories/system_hooks.rb index 94eb889ca04..b21f4713f54 100644 --- a/spec/factories/system_hooks.rb +++ b/spec/factories/system_hooks.rb @@ -5,5 +5,13 @@ FactoryBot.define do url { generate(:url) } name { generate(:name) } description { "Description of #{name}" } + + trait :url_variables do + url_variables { { 'abc' => 'supers3cret', 'def' => 'foobar' } } + end + + trait :token do + token { generate(:token) } + end end end diff --git a/spec/frontend/clusters_list/components/agents_spec.js b/spec/frontend/clusters_list/components/agents_spec.js index fff9925a2c6..f8272437a9a 100644 --- a/spec/frontend/clusters_list/components/agents_spec.js +++ b/spec/frontend/clusters_list/components/agents_spec.js @@ -234,6 +234,61 @@ describe('Agents', () => { }); }); + describe('sharedAgentsList computed property', () => { + const ciAccessAgent = sharedAgentsResponse.data.project.ciAccessAuthorizedAgents.nodes[0]; + const userAccessAgent = sharedAgentsResponse.data.project.userAccessAuthorizedAgents.nodes[0]; + + const createSharedAgentsResponse = (ciAgents, userAgents) => ({ + data: { + project: { + id: projectId, + ciAccessAuthorizedAgents: { nodes: ciAgents }, + userAccessAuthorizedAgents: { nodes: userAgents }, + }, + }, + }); + + it('filters out agents from the same project', async () => { + const sameProjectAgent = { + agent: { + ...userAccessAgent.agent, + project: { id: projectId, fullPath: provideData.projectPath }, + }, + }; + + const updatedResponse = createSharedAgentsResponse([ciAccessAgent], [sameProjectAgent]); + + createWrapper({ + sharedAgentsQueryResponse: jest.fn().mockResolvedValue(updatedResponse), + }); + + await waitForPromises(); + + expect(findTab()).toHaveLength(2); + expect(findTab().at(1).attributes('title')).toBe('Shared agents'); + + expect(findTab().at(1).findComponent(AgentTable).props('agents')).toHaveLength(1); + }); + + it('filters out agents duplicates', async () => { + const updatedResponse = createSharedAgentsResponse( + [ciAccessAgent], + [ciAccessAgent, userAccessAgent], + ); + + createWrapper({ + sharedAgentsQueryResponse: jest.fn().mockResolvedValue(updatedResponse), + }); + + await waitForPromises(); + + expect(findTab()).toHaveLength(2); + expect(findTab().at(1).attributes('title')).toBe('Shared agents'); + + expect(findTab().at(1).findComponent(AgentTable).props('agents')).toHaveLength(2); + }); + }); + describe('agent list update', () => { const initialResponse = { ...clusterAgentsResponse }; const newAgent = { diff --git a/spec/frontend/clusters_list/components/mock_data.js b/spec/frontend/clusters_list/components/mock_data.js index 29deea82c1b..7e3edbabe4e 100644 --- a/spec/frontend/clusters_list/components/mock_data.js +++ b/spec/frontend/clusters_list/components/mock_data.js @@ -318,14 +318,22 @@ const ciAccessAuthorizedAgentsNodes = [ userAccessAuthorizations: null, connections: null, tokens: null, - project: agentProject, + project: { id: '2', fullPath: 'path/to/another/project' }, }, }, ]; const userAccessAuthorizedAgentsNodes = [ { agent: { - ...agents[0], + __typename: 'ClusterAgent', + id: '4', + name: 'user-access-agent-1', + webPath: 'shared-project/agent-1', + createdAt: timestamp, + userAccessAuthorizations: null, + connections: null, + tokens: null, + project: { id: '2', fullPath: 'path/to/another/project' }, }, }, ]; @@ -346,12 +354,12 @@ export const sharedAgentsResponse = { data: { project: { id: 'gid://gitlab/Project/1', - }, - ciAccessAuthorizedAgents: { - nodes: ciAccessAuthorizedAgentsNodes, - }, - userAccessAuthorizedAgents: { - nodes: userAccessAuthorizedAgentsNodes, + ciAccessAuthorizedAgents: { + nodes: ciAccessAuthorizedAgentsNodes, + }, + userAccessAuthorizedAgents: { + nodes: userAccessAuthorizedAgentsNodes, + }, }, }, }; diff --git a/spec/frontend/rapid_diffs/toggle_file/adapter_spec.js b/spec/frontend/rapid_diffs/toggle_file/adapter_spec.js new file mode 100644 index 00000000000..45c6085777f --- /dev/null +++ b/spec/frontend/rapid_diffs/toggle_file/adapter_spec.js @@ -0,0 +1,66 @@ +import { DiffFile } from '~/rapid_diffs/diff_file'; +import { ToggleFileAdapter } from '~/rapid_diffs/toggle_file/adapter'; + +describe('Diff File Toggle Behavior', () => { + // In our version of Jest/JSDOM we cannot use + // + // - CSS "&" nesting (baseline 2023) + // - Element.checkVisibility (baseline 2024) + // - :has (baseline 2023) + // + // so this cannot test CSS (which is a majority of our behavior), and must assume that + // browser CSS is working as documented when we tweak HTML attributes + const html = ` + +
+
+
< + + +
+
+
+ + + `; + + function get(element) { + const elements = { + file: () => document.querySelector('diff-file'), + hide: () => get('file').querySelector('button[data-opened]'), + show: () => get('file').querySelector('button[data-closed]'), + body: () => get('file').querySelector('[data-file-body]'), + }; + + return elements[element]?.(); + } + + function assignAdapter(customAdapter) { + get('file').adapterConfig = { any: [customAdapter] }; + } + + beforeAll(() => { + customElements.define('diff-file', DiffFile); + }); + + beforeEach(() => { + document.body.innerHTML = html; + assignAdapter(ToggleFileAdapter); + get('file').mount(); + }); + + it('starts with the file body visible', () => { + expect(get('body').hidden).toEqual(false); + }); + + it('marks the body hidden and focuses the other button when the hide button is clicked', () => { + const show = get('show'); + const hide = get('hide'); + const body = get('body'); + + hide.click(); + + expect(body.hidden).toEqual(true); + expect(document.activeElement).toEqual(show); + }); +}); diff --git a/spec/frontend/work_items/graphql/resolvers_spec.js b/spec/frontend/work_items/graphql/resolvers_spec.js index f5de7b81aa1..66558d0870e 100644 --- a/spec/frontend/work_items/graphql/resolvers_spec.js +++ b/spec/frontend/work_items/graphql/resolvers_spec.js @@ -7,6 +7,7 @@ import { WIDGET_TYPE_ASSIGNEES, WIDGET_TYPE_LABELS, WIDGET_TYPE_DESCRIPTION, + WIDGET_TYPE_HIERARCHY, } from '~/work_items/constants'; import { createWorkItemQueryResponse } from '../mock_data'; @@ -143,6 +144,52 @@ describe('work items graphql resolvers', () => { }); }); + describe('with parent input', () => { + it('updates parent if set', async () => { + await mutate({ + parent: { + confidential: false, + id: 'gid://gitlab/WorkItem/1259', + iid: '56', + title: 'PARENT', + webUrl: 'http://127.0.0.1:3000/groups/flightjs/-/epics/56', + workItemType: { + id: 'gid://gitlab/WorkItems::Type/8', + name: 'Epic', + iconName: 'issue-type-epic', + __typename: 'WorkItemType', + }, + __typename: 'WorkItem', + }, + }); + + const queryResult = await query(WIDGET_TYPE_HIERARCHY); + expect(queryResult).toMatchObject({ + parent: { + confidential: false, + id: 'gid://gitlab/WorkItem/1259', + iid: '56', + title: 'PARENT', + webUrl: 'http://127.0.0.1:3000/groups/flightjs/-/epics/56', + workItemType: { + id: 'gid://gitlab/WorkItems::Type/8', + name: 'Epic', + iconName: 'issue-type-epic', + __typename: 'WorkItemType', + }, + __typename: 'WorkItem', + }, + }); + }); + + it('updates parent if cleared', async () => { + await mutate({ parent: null }); + + const queryResult = await query(WIDGET_TYPE_HIERARCHY); + expect(queryResult).toMatchObject({ parent: null }); + }); + }); + it('updates the local storage with every mutation', async () => { const AUTO_SAVE_KEY = `autosave/new-fullPath-issue-draft`; diff --git a/spec/initializers/session_store_spec.rb b/spec/initializers/session_store_spec.rb index 917f7c535f5..e7367bdd6c7 100644 --- a/spec/initializers/session_store_spec.rb +++ b/spec/initializers/session_store_spec.rb @@ -14,18 +14,46 @@ RSpec.describe 'Session initializer for GitLab' do end describe 'config#session_store' do - it 'initialized as a redis_store with a proper servers configuration' do - expect(subject).to receive(:session_store).with( - Gitlab::Sessions::RedisStore, - a_hash_including( - redis_server: Gitlab::Redis::Sessions.params.merge( - namespace: Gitlab::Redis::Sessions::SESSION_NAMESPACE, - serializer: Gitlab::Sessions::RedisStoreSerializer + context 'when cell.id is configured' do + before do + stub_config(cell: { id: 1 }) + end + + it 'initialized as a `redis_store` with session cookies prefix that includes cell id' do + expect(subject).to receive(:session_store).with( + Gitlab::Sessions::RedisStore, + a_hash_including( + redis_server: Gitlab::Redis::Sessions.params.merge( + namespace: Gitlab::Redis::Sessions::SESSION_NAMESPACE, + serializer: Gitlab::Sessions::RedisStoreSerializer + ), + session_cookie_token_prefix: 'cell-1' ) ) - ) - load_session_store + load_session_store + end + end + + context 'when cell.id is not configured' do + before do + stub_config(cell: { id: nil }) + end + + it 'initialized as a `redis_store` with empty session cookie prefix' do + expect(subject).to receive(:session_store).with( + Gitlab::Sessions::RedisStore, + a_hash_including( + redis_server: Gitlab::Redis::Sessions.params.merge( + namespace: Gitlab::Redis::Sessions::SESSION_NAMESPACE, + serializer: Gitlab::Sessions::RedisStoreSerializer + ), + session_cookie_token_prefix: '' + ) + ) + + load_session_store + end end end end diff --git a/spec/lib/gitlab/background_migration/backfill_partition_id_ci_pipeline_message_spec.rb b/spec/lib/gitlab/background_migration/backfill_partition_id_ci_pipeline_message_spec.rb deleted file mode 100644 index a29725e421c..00000000000 --- a/spec/lib/gitlab/background_migration/backfill_partition_id_ci_pipeline_message_spec.rb +++ /dev/null @@ -1,89 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Gitlab::BackgroundMigration::BackfillPartitionIdCiPipelineMessage, - :suppress_partitioning_routing_analyzer, - feature_category: :continuous_integration do - let(:ci_pipelines_table) { table(:ci_pipelines, primary_key: :id, database: :ci) } - let(:ci_pipeline_messages_table) { table(:ci_pipeline_messages, database: :ci) } - let!(:pipeline_1) { ci_pipelines_table.create!(id: 1, partition_id: 100, project_id: 1) } - let!(:pipeline_2) { ci_pipelines_table.create!(id: 2, partition_id: 101, project_id: 1) } - let!(:pipeline_3) { ci_pipelines_table.create!(id: 3, partition_id: 100, project_id: 1) } - let!(:ci_pipeline_messages_100) do - ci_pipeline_messages_table.create!( - content: 'content', - pipeline_id: pipeline_1.id, - partition_id: pipeline_1.partition_id - ) - end - - let!(:ci_pipeline_messages_101) do - ci_pipeline_messages_table.create!( - content: 'content', - pipeline_id: pipeline_2.id, - partition_id: pipeline_2.partition_id - ) - end - - let!(:invalid_ci_pipeline_messages) do - ci_pipeline_messages_table.create!( - content: 'content', - pipeline_id: pipeline_3.id, - partition_id: pipeline_3.partition_id - ) - end - - let(:migration_attrs) do - { - start_id: ci_pipeline_messages_table.minimum(:id), - end_id: ci_pipeline_messages_table.maximum(:id), - batch_table: :ci_pipeline_messages, - batch_column: :id, - sub_batch_size: 1, - pause_ms: 0, - connection: connection - } - end - - let!(:migration) { described_class.new(**migration_attrs) } - let(:connection) { Ci::ApplicationRecord.connection } - - around do |example| - connection.transaction do - connection.execute(<<~SQL) - ALTER TABLE ci_pipelines DISABLE TRIGGER ALL; - SQL - - example.run - - connection.execute(<<~SQL) - ALTER TABLE ci_pipelines ENABLE TRIGGER ALL; - SQL - end - end - - describe '#perform' do - context 'when there are no invalid records' do - it 'does not execute the migration' do - expect { migration.perform } - .not_to change { invalid_ci_pipeline_messages.reload.partition_id } - end - end - - context 'when second partition exists' do - before do - pipeline_3.update!(partition_id: 101) - end - - it 'fixes invalid records in the wrong the partition' do - expect { migration.perform } - .to not_change { ci_pipeline_messages_100.reload.partition_id } - .and not_change { ci_pipeline_messages_101.reload.partition_id } - .and change { invalid_ci_pipeline_messages.reload.partition_id } - .from(100) - .to(101) - end - end - end -end diff --git a/spec/lib/gitlab/database/sharding_key_spec.rb b/spec/lib/gitlab/database/sharding_key_spec.rb index 2846f48e8a9..f5bdc091a15 100644 --- a/spec/lib/gitlab/database/sharding_key_spec.rb +++ b/spec/lib/gitlab/database/sharding_key_spec.rb @@ -192,7 +192,6 @@ RSpec.describe 'new tables missing sharding_key', feature_category: :cell do work_in_progress = { "namespaces" => 'https://gitlab.com/gitlab-org/gitlab/-/issues/476209', "organization_users" => 'https://gitlab.com/gitlab-org/gitlab/-/issues/476210', - "projects" => 'https://gitlab.com/gitlab-org/gitlab/-/issues/476211', "push_rules" => 'https://gitlab.com/gitlab-org/gitlab/-/issues/476212', "snippets" => 'https://gitlab.com/gitlab-org/gitlab/-/issues/476216', "topics" => 'https://gitlab.com/gitlab-org/gitlab/-/issues/463254', diff --git a/spec/models/hooks/no_sti_system_hook_spec.rb b/spec/models/hooks/no_sti_system_hook_spec.rb new file mode 100644 index 00000000000..dc1e63dc50a --- /dev/null +++ b/spec/models/hooks/no_sti_system_hook_spec.rb @@ -0,0 +1,92 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe NoStiSystemHook, feature_category: :webhooks do + it_behaves_like 'a webhook', factory: :no_sti_system_hook, auto_disabling: false + + it_behaves_like 'a hook that does not get automatically disabled on failure' do + let(:hook) { build(:no_sti_system_hook) } + let(:hook_factory) { :no_sti_system_hook } + let(:default_factory_arguments) { {} } + + def find_hooks + described_class.all + end + end + + describe 'default attributes' do + let(:no_sti_system_hook) { described_class.new } + + it 'sets defined default parameters' do + attrs = { + push_events: false, + repository_update_events: true, + merge_requests_events: false + } + expect(no_sti_system_hook).to have_attributes(attrs) + end + end + + describe 'associations' do + it { is_expected.not_to respond_to(:web_hook_logs) } + end + + describe 'validations' do + describe 'url' do + let(:url) { 'http://localhost:9000' } + + it { is_expected.not_to allow_value(url).for(:url) } + + it 'is valid if application settings allow local requests from system hooks' do + settings = ApplicationSetting.new(allow_local_requests_from_system_hooks: true) + allow(ApplicationSetting).to receive(:current).and_return(settings) + + is_expected.to allow_value(url).for(:url) + end + end + end + + describe '.repository_update_hooks' do + it 'returns hooks for repository update events only' do + hook = create(:no_sti_system_hook, repository_update_events: true) + create(:no_sti_system_hook, repository_update_events: false) + expect(described_class.repository_update_hooks).to eq([hook]) + end + end + + describe 'execute WebHookService' do + let(:hook) { build(:no_sti_system_hook) } + let(:data) { { key: 'value' } } + let(:hook_name) { 'no_sti_system_hook' } + let(:web_hook_service) { instance_double(WebHookService, execute: true) } + + it '#execute' do + expect(WebHookService).to receive(:new).with(hook, data, hook_name, idempotency_key: anything, force: false) + .and_return(web_hook_service) + + expect(web_hook_service).to receive(:execute) + + hook.execute(data, hook_name) + end + + it '#async_execute' do + expect(WebHookService).to receive(:new).with(hook, data, hook_name, idempotency_key: anything) + .and_return(web_hook_service) + + expect(web_hook_service).to receive(:async_execute) + + hook.async_execute(data, hook_name) + end + end + + describe '#application_context' do + let(:hook) { build(:no_sti_system_hook) } + + it 'includes the type' do + expect(hook.application_context).to eq( + related_class: 'NoStiSystemHook' + ) + end + end +end diff --git a/spec/models/hooks/project_hook_spec.rb b/spec/models/hooks/project_hook_spec.rb index aff2c419154..7e5ca52a10c 100644 --- a/spec/models/hooks/project_hook_spec.rb +++ b/spec/models/hooks/project_hook_spec.rb @@ -17,6 +17,16 @@ RSpec.describe ProjectHook, feature_category: :webhooks do describe 'associations' do it { is_expected.to belong_to :project } + it { is_expected.to have_many(:web_hook_logs) } + end + + describe '#destroy' do + it 'does not cascade to web_hook_logs' do + web_hook = create(:project_hook) + create_list(:web_hook_log, 3, web_hook: web_hook) + + expect { web_hook.destroy! }.not_to change { web_hook.web_hook_logs.count } + end end describe 'validations' do diff --git a/spec/models/hooks/service_hook_spec.rb b/spec/models/hooks/service_hook_spec.rb index 7c868f419d7..cc672798d9c 100644 --- a/spec/models/hooks/service_hook_spec.rb +++ b/spec/models/hooks/service_hook_spec.rb @@ -16,6 +16,16 @@ RSpec.describe ServiceHook, feature_category: :webhooks do describe 'associations' do it { is_expected.to belong_to(:integration) } + it { is_expected.to have_many(:web_hook_logs) } + end + + describe '#destroy' do + it 'does not cascade to web_hook_logs' do + web_hook = create(:service_hook) + create_list(:web_hook_log, 3, web_hook: web_hook) + + expect { web_hook.destroy! }.not_to change { web_hook.web_hook_logs.count } + end end describe 'validations' do diff --git a/spec/models/hooks/system_hook_spec.rb b/spec/models/hooks/system_hook_spec.rb index 3d7fdeb3fe8..2c7a89ad47e 100644 --- a/spec/models/hooks/system_hook_spec.rb +++ b/spec/models/hooks/system_hook_spec.rb @@ -41,6 +41,19 @@ RSpec.describe SystemHook, feature_category: :webhooks do end end + describe 'associations' do + it { is_expected.to have_many(:web_hook_logs) } + end + + describe '#destroy' do + it 'does not cascade to web_hook_logs' do + web_hook = create(:system_hook) + create_list(:web_hook_log, 3, web_hook: web_hook) + + expect { web_hook.destroy! }.not_to change { web_hook.web_hook_logs.count } + end + end + describe "execute", :sidekiq_might_not_need_inline do let_it_be(:system_hook) { create(:system_hook) } let_it_be(:user) { create(:user) } @@ -228,4 +241,16 @@ RSpec.describe SystemHook, feature_category: :webhooks do ) end end + + describe '#pluralized_name' do + subject { build(:no_sti_system_hook).pluralized_name } + + it { is_expected.to eq('System hooks') } + end + + describe '#help_path' do + subject { build(:no_sti_system_hook).help_path } + + it { is_expected.to eq('administration/system_hooks') } + end end diff --git a/spec/models/hooks/web_hook_spec.rb b/spec/models/hooks/web_hook_spec.rb index 7f12807d380..57dc52c49b6 100644 --- a/spec/models/hooks/web_hook_spec.rb +++ b/spec/models/hooks/web_hook_spec.rb @@ -3,742 +3,5 @@ require 'spec_helper' RSpec.describe WebHook, feature_category: :webhooks do - include AfterNextHelpers - - let_it_be(:project) { create(:project) } - - let(:hook) { build(:project_hook, project: project) } - - around do |example| - if example.metadata[:skip_freeze_time] - example.run - else - freeze_time { example.run } - end - end - - describe 'associations' do - it { is_expected.to have_many(:web_hook_logs) } - end - - describe 'validations' do - it { is_expected.to validate_presence_of(:url) } - it { is_expected.to validate_length_of(:custom_webhook_template).is_at_most(4096) } - - describe 'url_variables' do - it { is_expected.to allow_value({}).for(:url_variables) } - it { is_expected.to allow_value({ 'foo' => 'bar' }).for(:url_variables) } - it { is_expected.to allow_value({ 'FOO' => 'bar' }).for(:url_variables) } - it { is_expected.to allow_value({ 'MY_TOKEN' => 'bar' }).for(:url_variables) } - it { is_expected.to allow_value({ 'foo2' => 'bar' }).for(:url_variables) } - it { is_expected.to allow_value({ 'x' => 'y' }).for(:url_variables) } - it { is_expected.to allow_value({ 'x' => ('a' * 2048) }).for(:url_variables) } - it { is_expected.to allow_value({ 'foo' => 'bar', 'bar' => 'baz' }).for(:url_variables) } - it { is_expected.to allow_value((1..20).to_h { ["k#{_1}", 'value'] }).for(:url_variables) } - it { is_expected.to allow_value({ 'MY-TOKEN' => 'bar' }).for(:url_variables) } - it { is_expected.to allow_value({ 'my_secr3t-token' => 'bar' }).for(:url_variables) } - it { is_expected.to allow_value({ 'x-y-z' => 'bar' }).for(:url_variables) } - it { is_expected.to allow_value({ 'x_y_z' => 'bar' }).for(:url_variables) } - it { is_expected.to allow_value({ 'f.o.o' => 'bar' }).for(:url_variables) } - - it { is_expected.not_to allow_value([]).for(:url_variables) } - it { is_expected.not_to allow_value({ 'foo' => 1 }).for(:url_variables) } - it { is_expected.not_to allow_value({ 'bar' => :baz }).for(:url_variables) } - it { is_expected.not_to allow_value({ 'bar' => nil }).for(:url_variables) } - it { is_expected.not_to allow_value({ 'foo' => '' }).for(:url_variables) } - it { is_expected.not_to allow_value({ 'foo' => ('a' * 2049) }).for(:url_variables) } - it { is_expected.not_to allow_value({ 'has spaces' => 'foo' }).for(:url_variables) } - it { is_expected.not_to allow_value({ '' => 'foo' }).for(:url_variables) } - it { is_expected.not_to allow_value({ '1foo' => 'foo' }).for(:url_variables) } - it { is_expected.not_to allow_value((1..21).to_h { ["k#{_1}", 'value'] }).for(:url_variables) } - it { is_expected.not_to allow_value({ 'MY--TOKEN' => 'foo' }).for(:url_variables) } - it { is_expected.not_to allow_value({ 'MY__SECRET' => 'foo' }).for(:url_variables) } - it { is_expected.not_to allow_value({ 'x-_y' => 'foo' }).for(:url_variables) } - it { is_expected.not_to allow_value({ 'x..y' => 'foo' }).for(:url_variables) } - end - - describe 'custom_headers' do - it { is_expected.to allow_value({}).for(:custom_headers) } - it { is_expected.to allow_value({ 'foo' => 'bar' }).for(:custom_headers) } - it { is_expected.to allow_value({ 'FOO' => 'bar' }).for(:custom_headers) } - it { is_expected.to allow_value({ 'MY_TOKEN' => 'bar' }).for(:custom_headers) } - it { is_expected.to allow_value({ 'foo2' => 'bar' }).for(:custom_headers) } - it { is_expected.to allow_value({ 'x' => 'y' }).for(:custom_headers) } - it { is_expected.to allow_value({ 'x' => ('a' * 2048) }).for(:custom_headers) } - it { is_expected.to allow_value({ 'foo' => 'bar', 'bar' => 'baz' }).for(:custom_headers) } - it { is_expected.to allow_value((1..20).to_h { ["k#{_1}", 'value'] }).for(:custom_headers) } - it { is_expected.to allow_value({ 'MY-TOKEN' => 'bar' }).for(:custom_headers) } - it { is_expected.to allow_value({ 'my_secr3t-token' => 'bar' }).for(:custom_headers) } - it { is_expected.to allow_value({ 'x-y-z' => 'bar' }).for(:custom_headers) } - it { is_expected.to allow_value({ 'x_y_z' => 'bar' }).for(:custom_headers) } - it { is_expected.to allow_value({ 'f.o.o' => 'bar' }).for(:custom_headers) } - - it { is_expected.not_to allow_value([]).for(:custom_headers) } - it { is_expected.not_to allow_value({ 'foo' => 1 }).for(:custom_headers) } - it { is_expected.not_to allow_value({ 'bar' => :baz }).for(:custom_headers) } - it { is_expected.not_to allow_value({ 'bar' => nil }).for(:custom_headers) } - it { is_expected.not_to allow_value({ 'foo' => '' }).for(:custom_headers) } - it { is_expected.not_to allow_value({ 'foo' => ('a' * 2049) }).for(:custom_headers) } - it { is_expected.not_to allow_value({ 'has spaces' => 'foo' }).for(:custom_headers) } - it { is_expected.not_to allow_value({ '' => 'foo' }).for(:custom_headers) } - it { is_expected.not_to allow_value({ '1foo' => 'foo' }).for(:custom_headers) } - it { is_expected.not_to allow_value((1..21).to_h { ["k#{_1}", 'value'] }).for(:custom_headers) } - it { is_expected.not_to allow_value({ 'MY--TOKEN' => 'foo' }).for(:custom_headers) } - it { is_expected.not_to allow_value({ 'MY__SECRET' => 'foo' }).for(:custom_headers) } - it { is_expected.not_to allow_value({ 'x-_y' => 'foo' }).for(:custom_headers) } - it { is_expected.not_to allow_value({ 'x..y' => 'foo' }).for(:custom_headers) } - end - - describe 'url' do - it { is_expected.to allow_value('http://example.com').for(:url) } - it { is_expected.to allow_value('https://example.com').for(:url) } - it { is_expected.to allow_value(' https://example.com ').for(:url) } - it { is_expected.to allow_value('http://test.com/api').for(:url) } - it { is_expected.to allow_value('http://test.com/api?key=abc').for(:url) } - it { is_expected.to allow_value('http://test.com/api?key=abc&type=def').for(:url) } - - it { is_expected.not_to allow_value('example.com').for(:url) } - it { is_expected.not_to allow_value('ftp://example.com').for(:url) } - it { is_expected.not_to allow_value('herp-and-derp').for(:url) } - - context 'when url is local' do - let(:url) { 'http://localhost:9000' } - - it { is_expected.not_to allow_value(url).for(:url) } - - it 'is valid if application settings allow local requests from web hooks' do - settings = ApplicationSetting.new(allow_local_requests_from_web_hooks_and_services: true) - allow(ApplicationSetting).to receive(:current).and_return(settings) - - is_expected.to allow_value(url).for(:url) - end - end - - it 'strips :url before saving it' do - hook.url = ' https://example.com ' - hook.save! - - expect(hook.url).to eq('https://example.com') - end - - context 'when there are URL variables' do - subject { hook } - - before do - hook.url_variables = { 'one' => 'a', 'two' => 'b', 'url' => 'http://example.com' } - end - - it { is_expected.to allow_value('http://example.com').for(:url) } - it { is_expected.to allow_value('http://example.com/{one}/{two}').for(:url) } - it { is_expected.to allow_value('http://example.com/{one}').for(:url) } - it { is_expected.to allow_value('http://example.com/{two}').for(:url) } - it { is_expected.to allow_value('http://user:s3cret@example.com/{two}').for(:url) } - it { is_expected.to allow_value('http://{one}:{two}@example.com').for(:url) } - it { is_expected.to allow_value('http://{one}').for(:url) } - it { is_expected.to allow_value('{url}').for(:url) } - - it { is_expected.not_to allow_value('http://example.com/{one}/{two}/{three}').for(:url) } - it { is_expected.not_to allow_value('http://example.com/{foo}').for(:url) } - it { is_expected.not_to allow_value('http:{user}:{pwd}//example.com/{foo}').for(:url) } - - it 'mentions all missing variable names' do - hook.url = 'http://example.com/{one}/{foo}/{two}/{three}' - - expect(hook).to be_invalid - expect(hook.errors[:url].to_sentence).to eq "Invalid URL template. Missing keys: [\"foo\", \"three\"]" - end - end - end - - describe 'token' do - it { is_expected.to allow_value("foobar").for(:token) } - - it { is_expected.not_to allow_values("foo\nbar", "foo\r\nbar").for(:token) } - end - - describe 'push_events_branch_filter' do - before do - subject.branch_filter_strategy = strategy - end - - context 'with "all branches" strategy' do - let(:strategy) { 'all_branches' } - - it { - is_expected.to allow_values( - "good_branch_name", - "another/good-branch_name", - "good branch name", - "good~branchname", - "good_branchname(", - "good_branchname[", - "" - ).for(:push_events_branch_filter) - } - end - - context 'with "wildcard" strategy' do - let(:strategy) { 'wildcard' } - - it { - is_expected.to allow_values( - "good_branch_name", - "another/good-branch_name", - "good_branch_name(", - "" - ).for(:push_events_branch_filter) - } - - it { - is_expected.not_to allow_values( - "bad branch name", - "bad~branchname", - "bad_branch_name[" - ).for(:push_events_branch_filter) - } - - it 'gets rid of whitespace' do - hook.push_events_branch_filter = ' branch ' - hook.save! - - expect(hook.push_events_branch_filter).to eq('branch') - end - - it 'stores whitespace only as empty' do - hook.push_events_branch_filter = ' ' - hook.save! - expect(hook.push_events_branch_filter).to eq('') - end - end - - context 'with "regex" strategy' do - let(:strategy) { 'regex' } - - it { - is_expected.to allow_values( - "good_branch_name", - "another/good-branch_name", - "good branch name", - "good~branch~name", - "" - ).for(:push_events_branch_filter) - } - - it { is_expected.not_to allow_values("bad_branch_name(", "bad_branch_name[").for(:push_events_branch_filter) } - end - end - - describe 'before_validation :reset_token' do - subject(:hook) { build_stubbed(:project_hook, :token, project: project) } - - it 'resets token if url changed' do - hook.url = 'https://webhook.example.com/new-hook' - - expect(hook).to be_valid - expect(hook.token).to be_nil - end - - it 'does not reset token if new url is set together with the same token' do - hook.url = 'https://webhook.example.com/new-hook' - current_token = hook.token - hook.token = current_token - - expect(hook).to be_valid - expect(hook.token).to eq(current_token) - expect(hook.url).to eq('https://webhook.example.com/new-hook') - end - - it 'does not reset token if new url is set together with a new token' do - hook.url = 'https://webhook.example.com/new-hook' - hook.token = 'token' - - expect(hook).to be_valid - expect(hook.token).to eq('token') - expect(hook.url).to eq('https://webhook.example.com/new-hook') - end - end - - describe 'before_validation :reset_url_variables' do - subject(:hook) { build_stubbed(:project_hook, :url_variables, project: project, url: 'http://example.com/{abc}') } - - it 'resets url variables if url changed' do - hook.url = 'http://example.com/new-hook' - - expect(hook).to be_valid - expect(hook.url_variables).to eq({}) - end - - it 'resets url variables if url is changed but url variables stayed the same' do - hook.url = 'http://test.example.com/{abc}' - - expect(hook).not_to be_valid - expect(hook.url_variables).to eq({}) - end - - it 'resets url variables if url is changed and url variables are appended' do - hook.url = 'http://suspicious.example.com/{abc}/{foo}' - hook.url_variables = hook.url_variables.merge('foo' => 'bar') - - expect(hook).not_to be_valid - expect(hook.url_variables).to eq({}) - end - - it 'resets url variables if url is changed and url variables are removed' do - hook.url = 'http://suspicious.example.com/{abc}' - hook.url_variables = hook.url_variables.except("def") - - expect(hook).not_to be_valid - expect(hook.url_variables).to eq({}) - end - - it 'resets url variables if url variables are overwritten' do - hook.url_variables = hook.url_variables.merge('abc' => 'baz') - - expect(hook).not_to be_valid - expect(hook.url_variables).to eq({}) - end - - it 'does not reset url variables if both url and url variables are changed' do - hook.url = 'http://example.com/{one}/{two}' - hook.url_variables = { 'one' => 'foo', 'two' => 'bar' } - - expect(hook).to be_valid - expect(hook.url_variables).to eq({ 'one' => 'foo', 'two' => 'bar' }) - end - - context 'without url variables' do - subject(:hook) { build_stubbed(:project_hook, project: project, url: 'http://example.com', url_variables: nil) } - - it 'does not reset url variables' do - hook.url = 'http://example.com/{one}/{two}' - hook.url_variables = { 'one' => 'foo', 'two' => 'bar' } - - expect(hook).to be_valid - expect(hook.url_variables).to eq({ 'one' => 'foo', 'two' => 'bar' }) - end - end - end - - describe 'before_validation :reset_custom_headers' do - subject(:hook) { build_stubbed(:project_hook, :url_variables, project: project, url: 'http://example.com/{abc}', custom_headers: { test: 'blub' }) } - - it 'resets custom headers if url changed' do - hook.url = 'http://example.com/new-hook' - - expect(hook).to be_valid - expect(hook.custom_headers).to eq({}) - end - - it 'resets custom headers if url and url variables changed' do - hook.url = 'http://example.com/{something}' - hook.url_variables = { 'something' => 'testing-around' } - - expect(hook).to be_valid - expect(hook.custom_headers).to eq({}) - end - - it 'does not reset custom headers if url stayed the same' do - hook.url = 'http://example.com/{abc}' - - expect(hook).to be_valid - expect(hook.custom_headers).to eq({ test: 'blub' }) - end - - it 'does not reset custom headers if url and url variables changed and evaluate to the same url' do - hook.url = 'http://example.com/{def}' - hook.url_variables = { 'def' => 'supers3cret' } - - expect(hook).to be_valid - expect(hook.custom_headers).to eq({ test: 'blub' }) - end - end - - it "only consider these branch filter strategies are valid" do - expected_valid_types = %w[all_branches regex wildcard] - expect(described_class.branch_filter_strategies.keys).to contain_exactly(*expected_valid_types) - end - end - - describe 'encrypted attributes' do - subject { described_class.attr_encrypted_attributes.keys } - - it { is_expected.to contain_exactly(:token, :url, :url_variables, :custom_headers) } - end - - describe 'execute' do - let(:data) { { key: 'value' } } - let(:hook_name) { 'project hook' } - - it '#execute' do - expect_next(WebHookService).to receive(:execute) - - hook.execute(data, hook_name) - end - - it 'passes force: false to the web hook service by default' do - expect(WebHookService) - .to receive(:new).with(hook, data, hook_name, idempotency_key: anything, - force: false).and_return(double(execute: :done)) - - expect(hook.execute(data, hook_name)).to eq :done - end - - it 'passes force: true to the web hook service if required' do - expect(WebHookService) - .to receive(:new).with(hook, data, hook_name, idempotency_key: anything, - force: true).and_return(double(execute: :forced)) - - expect(hook.execute(data, hook_name, force: true)).to eq :forced - end - - it 'forwards the idempotency key to the WebHook service when present' do - idempotency_key = SecureRandom.uuid - - expect(WebHookService) - .to receive(:new) - .with(anything, anything, anything, idempotency_key: idempotency_key, force: anything) - .and_return(double(execute: :done)) - - expect(hook.execute(data, hook_name, idempotency_key: idempotency_key)).to eq :done - end - - it 'forwards a nil idempotency key to the WebHook service when not supplied' do - expect(WebHookService) - .to receive(:new).with(anything, anything, anything, idempotency_key: nil, - force: anything).and_return(double(execute: :done)) - - expect(hook.execute(data, hook_name)).to eq :done - end - end - - describe 'async_execute' do - let(:data) { { key: 'value' } } - let(:hook_name) { 'project hook' } - - it '#async_execute' do - expect_next(WebHookService).to receive(:async_execute) - - hook.async_execute(data, hook_name) - end - - it 'forwards the idempotency key to the WebHook service when present' do - idempotency_key = SecureRandom.uuid - - expect(WebHookService) - .to receive(:new) - .with(anything, anything, anything, idempotency_key: idempotency_key) - .and_return(double(async_execute: :done)) - - expect(hook.async_execute(data, hook_name, idempotency_key: idempotency_key)).to eq :done - end - - it 'forwards a nil idempotency key to the WebHook service when not supplied' do - expect(WebHookService) - .to receive(:new).with(anything, anything, anything, - idempotency_key: nil).and_return(double(async_execute: :done)) - - expect(hook.async_execute(data, hook_name)).to eq :done - end - - it 'does not async execute non-executable hooks' do - allow(hook).to receive(:executable?).and_return(false) - - expect(WebHookService).not_to receive(:new) - - hook.async_execute(data, hook_name) - end - end - - describe '#destroy' do - it 'does not cascade to web_hook_logs' do - web_hook = create(:project_hook) - create_list(:web_hook_log, 3, web_hook: web_hook) - - expect { web_hook.destroy! }.not_to change(web_hook.web_hook_logs, :count) - end - end - - describe '#next_backoff' do - before do - hook.backoff_count = backoff_count - end - - context 'when there was no last backoff' do - let(:backoff_count) { 0 } - - it 'is the initial value' do - expect(hook.next_backoff).to eq(WebHooks::AutoDisabling::INITIAL_BACKOFF) - end - end - - context 'when we have backed off once' do - let(:backoff_count) { 1 } - - it 'is twice the initial value' do - expect(hook.next_backoff).to eq(2 * WebHooks::AutoDisabling::INITIAL_BACKOFF) - end - end - - context 'when the next backoff is just before the max backoff limit' do - let(:backoff_count) { WebHooks::AutoDisabling::MAX_BACKOFF_COUNT - 1 } - - it 'is an exponential of the initial backoff' do - expect(hook.next_backoff).to eq((2**backoff_count) * WebHooks::AutoDisabling::INITIAL_BACKOFF) - end - - it 'is not yet capped at the max limit' do - expect(hook.next_backoff).to be < WebHooks::AutoDisabling::MAX_BACKOFF - end - end - - describe 'when next_backoff has reached the MAX_BACKOFF limit' do - let(:backoff_count) { WebHooks::AutoDisabling::MAX_BACKOFF_COUNT } - - it 'does not exceed the max backoff value' do - expect(hook.next_backoff).to eq(WebHooks::AutoDisabling::MAX_BACKOFF) - end - end - end - - describe '#rate_limited?' do - it 'is false when hook has not been rate limited' do - expect_next_instance_of(Gitlab::WebHooks::RateLimiter) do |rate_limiter| - expect(rate_limiter).to receive(:rate_limited?).and_return(false) - end - - expect(hook).not_to be_rate_limited - end - - it 'is true when hook has been rate limited' do - expect_next_instance_of(Gitlab::WebHooks::RateLimiter) do |rate_limiter| - expect(rate_limiter).to receive(:rate_limited?).and_return(true) - end - - expect(hook).to be_rate_limited - end - end - - describe '#rate_limit' do - it 'returns the hook rate limit' do - expect_next_instance_of(Gitlab::WebHooks::RateLimiter) do |rate_limiter| - expect(rate_limiter).to receive(:limit).and_return(10) - end - - expect(hook.rate_limit).to eq(10) - end - end - - describe '#to_json' do - it 'does not error' do - expect { hook.to_json }.not_to raise_error - end - - it 'does not contain binary attributes' do - expect(hook.to_json).not_to include('encrypted_url_variables') - end - end - - describe '#interpolated_url' do - subject(:hook) { build(:project_hook, project: project) } - - context 'when the hook URL does not contain variables' do - before do - hook.url = 'http://example.com' - end - - it { is_expected.to have_attributes(interpolated_url: hook.url) } - end - - it 'is not vulnerable to malicious input' do - hook.url = 'something%{%2147483628G}' - hook.url_variables = { 'foo' => '1234567890.12345678' } - - expect(hook).to have_attributes(interpolated_url: hook.url) - end - - context 'when the hook URL contains variables' do - before do - hook.url = 'http://example.com/{path}/resource?token={token}' - hook.url_variables = { 'path' => 'abc', 'token' => 'xyz' } - end - - it { is_expected.to have_attributes(interpolated_url: 'http://example.com/abc/resource?token=xyz') } - - context 'when a variable is missing' do - before do - hook.url_variables = { 'path' => 'present' } - end - - it 'raises an error' do - # We expect validations to prevent this entirely - this is not user-error - expect { hook.interpolated_url } - .to raise_error(described_class::InterpolationError, include('Missing key token')) - end - end - - context 'when the URL appears to include percent formatting' do - before do - hook.url = 'http://example.com/%{path}/resource?token=%{token}' - end - - it 'succeeds, interpolates correctly' do - expect(hook.interpolated_url).to eq 'http://example.com/%abc/resource?token=%xyz' - end - end - end - end - - describe '#masked_token' do - it { expect(hook.masked_token).to be_nil } - - context 'with a token' do - let(:hook) { build(:project_hook, :token, project: project) } - - it { expect(hook.masked_token).to eq described_class::SECRET_MASK } - end - end - - describe '#backoff!' do - context 'when we have not backed off before' do - it 'increments the recent_failures count but does not disable the hook yet' do - expect { hook.backoff! }.to change(hook, :recent_failures).to(1) - expect(hook.class.executable).to include(hook) - end - end - - context 'when hook is at the failure threshold' do - before do - WebHooks::AutoDisabling::FAILURE_THRESHOLD.times { hook.backoff! } - end - - it 'is not yet disabled' do - expect(hook.class.executable).to include(hook) - expect(hook).to have_attributes( - recent_failures: WebHooks::AutoDisabling::FAILURE_THRESHOLD, - backoff_count: 0, - disabled_until: nil - ) - end - - context 'when hook is next told to backoff' do - before do - hook.backoff! - end - - it 'causes the hook to become disabled for initial backoff period' do - expect(hook.class.executable).not_to include(hook) - expect(hook).to have_attributes( - recent_failures: (WebHooks::AutoDisabling::FAILURE_THRESHOLD + 1), - backoff_count: 1, - disabled_until: 1.minute.from_now - ) - end - - context 'when the backoff time has elapsed', :skip_freeze_time do - it 'is no longer disabled' do - travel_to(hook.disabled_until + 1.minute) do - expect(hook.class.executable).to include(hook) - end - end - - context 'when the hook is next told to backoff' do - it 'disables the hook again, increasing the backoff time exponentially' do - travel_to(hook.disabled_until + 1.minute) do - hook.backoff! - - expect(hook.class.executable).not_to include(hook) - expect(hook).to have_attributes( - recent_failures: (WebHooks::AutoDisabling::FAILURE_THRESHOLD + 2), - backoff_count: 2, - disabled_until: 2.minutes.from_now - ) - end - end - end - end - end - end - - it 'does not do anything if the hook is currently temporarily disabled' do - allow(hook).to receive(:temporarily_disabled?).and_return(true) - - sql_count = ActiveRecord::QueryRecorder.new { hook.backoff! }.count - - expect(sql_count).to eq(0) - end - - it 'does not do anything if the hook is currently permanently disabled' do - allow(hook).to receive(:permanently_disabled?).and_return(true) - - sql_count = ActiveRecord::QueryRecorder.new { hook.backoff! }.count - - expect(sql_count).to eq(0) - end - - context 'when the counter are above MAX_FAILURES' do - let(:max_failures) { WebHooks::AutoDisabling::MAX_FAILURES } - - before do - hook.update!( - recent_failures: (max_failures + 1), - backoff_count: (max_failures + 1), - disabled_until: 1.hour.ago - ) - end - - it 'reduces the counter to MAX_FAILURES' do - hook.backoff! - - expect(hook).to have_attributes( - recent_failures: max_failures, - backoff_count: max_failures - ) - end - end - end - - describe '#failed!' do - it 'increments the recent_failures count but does not disable the hook yet' do - expect { hook.failed! }.to change(hook, :recent_failures).to(1) - expect(hook.class.executable).to include(hook) - end - - context 'when hook is at the failure threshold' do - before do - WebHooks::AutoDisabling::FAILURE_THRESHOLD.times { hook.failed! } - end - - it 'is not yet disabled' do - expect(hook.class.executable).to include(hook) - expect(hook).to have_attributes( - recent_failures: WebHooks::AutoDisabling::FAILURE_THRESHOLD, - backoff_count: 0, - disabled_until: nil - ) - end - - context 'when hook is next failed' do - before do - hook.failed! - end - - it 'causes the hook to become disabled' do - expect(hook.class.executable).not_to include(hook) - expect(hook).to have_attributes( - recent_failures: (WebHooks::AutoDisabling::FAILURE_THRESHOLD + 1), - backoff_count: 0, - disabled_until: nil - ) - end - end - end - - it 'does not do anything if recent_failures is at MAX_FAILURES' do - hook.recent_failures = WebHooks::AutoDisabling::MAX_FAILURES - - sql_count = ActiveRecord::QueryRecorder.new { hook.failed! }.count - - expect(sql_count).to eq(0) - end - end + it_behaves_like 'a webhook', factory: :project_hook end diff --git a/spec/support/finder_collection_allowlist.yml b/spec/support/finder_collection_allowlist.yml index 56fcdd02e4c..e79c96bb591 100644 --- a/spec/support/finder_collection_allowlist.yml +++ b/spec/support/finder_collection_allowlist.yml @@ -73,3 +73,4 @@ - UserGroupNotificationSettingsFinder - UserGroupsCounter - Ai::FeatureSettings::FeatureSettingFinder +- Autocomplete::VulnerabilitiesAutocompleteFinder diff --git a/spec/support/rspec_order_todo.yml b/spec/support/rspec_order_todo.yml index 4da798e7b81..a8ebf95a9c8 100644 --- a/spec/support/rspec_order_todo.yml +++ b/spec/support/rspec_order_todo.yml @@ -331,7 +331,6 @@ - './ee/spec/finders/security/findings_finder_spec.rb' - './ee/spec/finders/security/pipeline_vulnerabilities_finder_spec.rb' - './ee/spec/finders/security/scan_execution_policies_finder_spec.rb' -- './ee/spec/finders/security/vulnerabilities_finder_spec.rb' - './ee/spec/finders/security/vulnerability_feedbacks_finder_spec.rb' - './ee/spec/finders/snippets_finder_spec.rb' - './ee/spec/finders/template_finder_spec.rb' @@ -1144,7 +1143,6 @@ - './ee/spec/mailers/emails/epics_spec.rb' - './ee/spec/mailers/emails/group_memberships_spec.rb' - './ee/spec/mailers/emails/merge_commits_spec.rb' -- './ee/spec/mailers/emails/namespace_storage_usage_mailer_spec.rb' - './ee/spec/mailers/emails/requirements_spec.rb' - './ee/spec/mailers/emails/user_cap_spec.rb' - './ee/spec/mailers/license_mailer_spec.rb' diff --git a/spec/support/shared_examples/models/concerns/web_hooks/web_hook_shared_examples.rb b/spec/support/shared_examples/models/concerns/web_hooks/web_hook_shared_examples.rb new file mode 100644 index 00000000000..4a31a208ad0 --- /dev/null +++ b/spec/support/shared_examples/models/concerns/web_hooks/web_hook_shared_examples.rb @@ -0,0 +1,705 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.shared_examples 'a webhook' do |factory:, auto_disabling: true| + include AfterNextHelpers + + let(:hook) { build(factory) } + + around do |example| + if example.metadata[:skip_freeze_time] + example.run + else + freeze_time { example.run } + end + end + + describe 'validations' do + it { is_expected.to validate_presence_of(:url) } + it { is_expected.to validate_length_of(:custom_webhook_template).is_at_most(4096) } + + describe 'url_variables' do + it { is_expected.to allow_value({}).for(:url_variables) } + it { is_expected.to allow_value({ 'foo' => 'bar' }).for(:url_variables) } + it { is_expected.to allow_value({ 'FOO' => 'bar' }).for(:url_variables) } + it { is_expected.to allow_value({ 'MY_TOKEN' => 'bar' }).for(:url_variables) } + it { is_expected.to allow_value({ 'foo2' => 'bar' }).for(:url_variables) } + it { is_expected.to allow_value({ 'x' => 'y' }).for(:url_variables) } + it { is_expected.to allow_value({ 'x' => ('a' * 2048) }).for(:url_variables) } + it { is_expected.to allow_value({ 'foo' => 'bar', 'bar' => 'baz' }).for(:url_variables) } + it { is_expected.to allow_value((1..20).to_h { |i| ["k#{i}", 'value'] }).for(:url_variables) } + it { is_expected.to allow_value({ 'MY-TOKEN' => 'bar' }).for(:url_variables) } + it { is_expected.to allow_value({ 'my_secr3t-token' => 'bar' }).for(:url_variables) } + it { is_expected.to allow_value({ 'x-y-z' => 'bar' }).for(:url_variables) } + it { is_expected.to allow_value({ 'x_y_z' => 'bar' }).for(:url_variables) } + it { is_expected.to allow_value({ 'f.o.o' => 'bar' }).for(:url_variables) } + + it { is_expected.not_to allow_value([]).for(:url_variables) } + it { is_expected.not_to allow_value({ 'foo' => 1 }).for(:url_variables) } + it { is_expected.not_to allow_value({ 'bar' => :baz }).for(:url_variables) } + it { is_expected.not_to allow_value({ 'bar' => nil }).for(:url_variables) } + it { is_expected.not_to allow_value({ 'foo' => '' }).for(:url_variables) } + it { is_expected.not_to allow_value({ 'foo' => ('a' * 2049) }).for(:url_variables) } + it { is_expected.not_to allow_value({ 'has spaces' => 'foo' }).for(:url_variables) } + it { is_expected.not_to allow_value({ '' => 'foo' }).for(:url_variables) } + it { is_expected.not_to allow_value({ '1foo' => 'foo' }).for(:url_variables) } + it { is_expected.not_to allow_value((1..21).to_h { |i| ["k#{i}", 'value'] }).for(:url_variables) } + it { is_expected.not_to allow_value({ 'MY--TOKEN' => 'foo' }).for(:url_variables) } + it { is_expected.not_to allow_value({ 'MY__SECRET' => 'foo' }).for(:url_variables) } + it { is_expected.not_to allow_value({ 'x-_y' => 'foo' }).for(:url_variables) } + it { is_expected.not_to allow_value({ 'x..y' => 'foo' }).for(:url_variables) } + end + + describe 'custom_headers' do + it { is_expected.to allow_value({}).for(:custom_headers) } + it { is_expected.to allow_value({ 'foo' => 'bar' }).for(:custom_headers) } + it { is_expected.to allow_value({ 'FOO' => 'bar' }).for(:custom_headers) } + it { is_expected.to allow_value({ 'MY_TOKEN' => 'bar' }).for(:custom_headers) } + it { is_expected.to allow_value({ 'foo2' => 'bar' }).for(:custom_headers) } + it { is_expected.to allow_value({ 'x' => 'y' }).for(:custom_headers) } + it { is_expected.to allow_value({ 'x' => ('a' * 2048) }).for(:custom_headers) } + it { is_expected.to allow_value({ 'foo' => 'bar', 'bar' => 'baz' }).for(:custom_headers) } + it { is_expected.to allow_value((1..20).to_h { |i| ["k#{i}", 'value'] }).for(:custom_headers) } + it { is_expected.to allow_value({ 'MY-TOKEN' => 'bar' }).for(:custom_headers) } + it { is_expected.to allow_value({ 'my_secr3t-token' => 'bar' }).for(:custom_headers) } + it { is_expected.to allow_value({ 'x-y-z' => 'bar' }).for(:custom_headers) } + it { is_expected.to allow_value({ 'x_y_z' => 'bar' }).for(:custom_headers) } + it { is_expected.to allow_value({ 'f.o.o' => 'bar' }).for(:custom_headers) } + + it { is_expected.not_to allow_value([]).for(:custom_headers) } + it { is_expected.not_to allow_value({ 'foo' => 1 }).for(:custom_headers) } + it { is_expected.not_to allow_value({ 'bar' => :baz }).for(:custom_headers) } + it { is_expected.not_to allow_value({ 'bar' => nil }).for(:custom_headers) } + it { is_expected.not_to allow_value({ 'foo' => '' }).for(:custom_headers) } + it { is_expected.not_to allow_value({ 'foo' => ('a' * 2049) }).for(:custom_headers) } + it { is_expected.not_to allow_value({ 'has spaces' => 'foo' }).for(:custom_headers) } + it { is_expected.not_to allow_value({ '' => 'foo' }).for(:custom_headers) } + it { is_expected.not_to allow_value({ '1foo' => 'foo' }).for(:custom_headers) } + it { is_expected.not_to allow_value((1..21).to_h { |i| ["k#{i}", 'value'] }).for(:custom_headers) } + it { is_expected.not_to allow_value({ 'MY--TOKEN' => 'foo' }).for(:custom_headers) } + it { is_expected.not_to allow_value({ 'MY__SECRET' => 'foo' }).for(:custom_headers) } + it { is_expected.not_to allow_value({ 'x-_y' => 'foo' }).for(:custom_headers) } + it { is_expected.not_to allow_value({ 'x..y' => 'foo' }).for(:custom_headers) } + end + + describe 'url' do + it { is_expected.to allow_value('http://example.com').for(:url) } + it { is_expected.to allow_value('https://example.com').for(:url) } + it { is_expected.to allow_value(' https://example.com ').for(:url) } + it { is_expected.to allow_value('http://test.com/api').for(:url) } + it { is_expected.to allow_value('http://test.com/api?key=abc').for(:url) } + it { is_expected.to allow_value('http://test.com/api?key=abc&type=def').for(:url) } + + it { is_expected.not_to allow_value('example.com').for(:url) } + it { is_expected.not_to allow_value('ftp://example.com').for(:url) } + it { is_expected.not_to allow_value('herp-and-derp').for(:url) } + + context 'when url is local' do + let(:url) { 'http://localhost:9000' } + + it { is_expected.not_to allow_value(url).for(:url) } + + it 'is valid if application settings allow local requests from web hooks' do + settings = ApplicationSetting.new(allow_local_requests_from_web_hooks_and_services: true) + allow(ApplicationSetting).to receive(:current).and_return(settings) + + is_expected.to allow_value(url).for(:url) + end + end + + it 'strips :url before saving it' do + hook.url = ' https://example.com ' + hook.save! + + expect(hook.url).to eq('https://example.com') + end + + context 'when there are URL variables' do + subject { hook } + + before do + hook.url_variables = { 'one' => 'a', 'two' => 'b', 'url' => 'http://example.com' } + end + + it { is_expected.to allow_value('http://example.com').for(:url) } + it { is_expected.to allow_value('http://example.com/{one}/{two}').for(:url) } + it { is_expected.to allow_value('http://example.com/{one}').for(:url) } + it { is_expected.to allow_value('http://example.com/{two}').for(:url) } + it { is_expected.to allow_value('http://user:s3cret@example.com/{two}').for(:url) } + it { is_expected.to allow_value('http://{one}:{two}@example.com').for(:url) } + it { is_expected.to allow_value('http://{one}').for(:url) } + it { is_expected.to allow_value('{url}').for(:url) } + + it { is_expected.not_to allow_value('http://example.com/{one}/{two}/{three}').for(:url) } + it { is_expected.not_to allow_value('http://example.com/{foo}').for(:url) } + it { is_expected.not_to allow_value('http:{user}:{pwd}//example.com/{foo}').for(:url) } + + it 'mentions all missing variable names' do + hook.url = 'http://example.com/{one}/{foo}/{two}/{three}' + + expect(hook).to be_invalid + expect(hook.errors[:url].to_sentence).to eq "Invalid URL template. Missing keys: [\"foo\", \"three\"]" + end + end + end + + describe 'token' do + it { is_expected.to allow_value("foobar").for(:token) } + + it { is_expected.not_to allow_values("foo\nbar", "foo\r\nbar").for(:token) } + end + + describe 'push_events_branch_filter' do + before do + subject.branch_filter_strategy = strategy + end + + context 'with "all branches" strategy' do + let(:strategy) { 'all_branches' } + let(:allowed_values) do + ["good_branch_name", "another/good-branch_name", "good branch name", "good~branchname", "good_branchname(", + "good_branchname[", ""] + end + + it { is_expected.to allow_values(*allowed_values).for(:push_events_branch_filter) } + end + + context 'with "wildcard" strategy' do + let(:strategy) { 'wildcard' } + let(:allowed_values) { ["good_branch_name", "another/good-branch_name", "good_branch_name(", ""] } + let(:disallowed_values) { ["bad branch name", "bad~branchname", "bad_branch_name["] } + + it { is_expected.to allow_values(*allowed_values).for(:push_events_branch_filter) } + it { is_expected.not_to allow_values(*disallowed_values).for(:push_events_branch_filter) } + + it 'gets rid of whitespace' do + hook.push_events_branch_filter = ' branch ' + hook.save! + + expect(hook.push_events_branch_filter).to eq('branch') + end + + it 'stores whitespace only as empty' do + hook.push_events_branch_filter = ' ' + hook.save! + expect(hook.push_events_branch_filter).to eq('') + end + end + + context 'with "regex" strategy' do + let(:strategy) { 'regex' } + let(:allowed_values) do + ["good_branch_name", "another/good-branch_name", "good branch name", "good~branch~name", ""] + end + + it { is_expected.to allow_values(*allowed_values).for(:push_events_branch_filter) } + it { is_expected.not_to allow_values("bad_branch_name(", "bad_branch_name[").for(:push_events_branch_filter) } + end + end + + describe 'before_validation :reset_token' do + subject(:hook) { build_stubbed(factory, :token) } + + it 'resets token if url changed' do + hook.url = 'https://webhook.example.com/new-hook' + + expect(hook).to be_valid + expect(hook.token).to be_nil + end + + it 'does not reset token if new url is set together with the same token' do + hook.url = 'https://webhook.example.com/new-hook' + current_token = hook.token + hook.token = current_token + + expect(hook).to be_valid + expect(hook.token).to eq(current_token) + expect(hook.url).to eq('https://webhook.example.com/new-hook') + end + + it 'does not reset token if new url is set together with a new token' do + hook.url = 'https://webhook.example.com/new-hook' + hook.token = 'token' + + expect(hook).to be_valid + expect(hook.token).to eq('token') + expect(hook.url).to eq('https://webhook.example.com/new-hook') + end + end + + describe 'before_validation :reset_url_variables' do + subject(:hook) { build_stubbed(factory, :url_variables, url: 'http://example.com/{abc}') } + + it 'resets url variables if url changed' do + hook.url = 'http://example.com/new-hook' + + expect(hook).to be_valid + expect(hook.url_variables).to eq({}) + end + + it 'resets url variables if url is changed but url variables stayed the same' do + hook.url = 'http://test.example.com/{abc}' + + expect(hook).not_to be_valid + expect(hook.url_variables).to eq({}) + end + + it 'resets url variables if url is changed and url variables are appended' do + hook.url = 'http://suspicious.example.com/{abc}/{foo}' + hook.url_variables = hook.url_variables.merge('foo' => 'bar') + + expect(hook).not_to be_valid + expect(hook.url_variables).to eq({}) + end + + it 'resets url variables if url is changed and url variables are removed' do + hook.url = 'http://suspicious.example.com/{abc}' + hook.url_variables = hook.url_variables.except("def") + + expect(hook).not_to be_valid + expect(hook.url_variables).to eq({}) + end + + it 'resets url variables if url variables are overwritten' do + hook.url_variables = hook.url_variables.merge('abc' => 'baz') + + expect(hook).not_to be_valid + expect(hook.url_variables).to eq({}) + end + + it 'does not reset url variables if both url and url variables are changed' do + hook.url = 'http://example.com/{one}/{two}' + hook.url_variables = { 'one' => 'foo', 'two' => 'bar' } + + expect(hook).to be_valid + expect(hook.url_variables).to eq({ 'one' => 'foo', 'two' => 'bar' }) + end + + context 'without url variables' do + subject(:hook) { build_stubbed(factory, url: 'http://example.com', url_variables: nil) } + + it 'does not reset url variables' do + hook.url = 'http://example.com/{one}/{two}' + hook.url_variables = { 'one' => 'foo', 'two' => 'bar' } + + expect(hook).to be_valid + expect(hook.url_variables).to eq({ 'one' => 'foo', 'two' => 'bar' }) + end + end + end + + describe 'before_validation :reset_custom_headers' do + subject(:hook) { build_stubbed(factory, :url_variables, url: 'http://example.com/{abc}', custom_headers: { test: 'blub' }) } + + it 'resets custom headers if url changed' do + hook.url = 'http://example.com/new-hook' + + expect(hook).to be_valid + expect(hook.custom_headers).to eq({}) + end + + it 'resets custom headers if url and url variables changed' do + hook.url = 'http://example.com/{something}' + hook.url_variables = { 'something' => 'testing-around' } + + expect(hook).to be_valid + expect(hook.custom_headers).to eq({}) + end + + it 'does not reset custom headers if url stayed the same' do + hook.url = 'http://example.com/{abc}' + + expect(hook).to be_valid + expect(hook.custom_headers).to eq({ test: 'blub' }) + end + + it 'does not reset custom headers if url and url variables changed and evaluate to the same url' do + hook.url = 'http://example.com/{def}' + hook.url_variables = { 'def' => 'supers3cret' } + + expect(hook).to be_valid + expect(hook.custom_headers).to eq({ test: 'blub' }) + end + end + + it "only consider these branch filter strategies are valid" do + expected_valid_types = %w[all_branches regex wildcard] + expect(described_class.branch_filter_strategies.keys).to match_array(expected_valid_types) + end + end + + describe 'encrypted attributes' do + subject { described_class.attr_encrypted_attributes.keys } + + it { is_expected.to contain_exactly(:token, :url, :url_variables, :custom_headers) } + end + + describe 'execute' do + let(:data) { { key: 'value' } } + let(:hook_name) { 'the hook name' } + + it '#execute' do + expect_next(WebHookService).to receive(:execute) + + hook.execute(data, hook_name) + end + + it 'passes force: false to the web hook service by default' do + expect(WebHookService) + .to receive(:new).with(hook, data, hook_name, idempotency_key: anything, + force: false).and_return(instance_double(WebHookService, execute: :done)) + + expect(hook.execute(data, hook_name)).to eq :done + end + + it 'passes force: true to the web hook service if required' do + expect(WebHookService) + .to receive(:new).with(hook, data, hook_name, idempotency_key: anything, + force: true).and_return(instance_double(WebHookService, execute: :forced)) + + expect(hook.execute(data, hook_name, force: true)).to eq :forced + end + + it 'forwards the idempotency key to the WebHook service when present' do + idempotency_key = SecureRandom.uuid + + expect(WebHookService) + .to receive(:new) + .with(anything, anything, anything, idempotency_key: idempotency_key, force: anything) + .and_return(instance_double(WebHookService, execute: :done)) + + expect(hook.execute(data, hook_name, idempotency_key: idempotency_key)).to eq :done + end + + it 'forwards a nil idempotency key to the WebHook service when not supplied' do + expect(WebHookService) + .to receive(:new).with(anything, anything, anything, idempotency_key: nil, + force: anything).and_return(instance_double(WebHookService, execute: :done)) + + expect(hook.execute(data, hook_name)).to eq :done + end + end + + describe 'async_execute' do + let(:data) { { key: 'value' } } + let(:hook_name) { 'the hook name' } + + it '#async_execute' do + expect_next(WebHookService).to receive(:async_execute) + + hook.async_execute(data, hook_name) + end + + it 'forwards the idempotency key to the WebHook service when present' do + idempotency_key = SecureRandom.uuid + + expect(WebHookService) + .to receive(:new) + .with(anything, anything, anything, idempotency_key: idempotency_key) + .and_return(instance_double(WebHookService, async_execute: :done)) + + expect(hook.async_execute(data, hook_name, idempotency_key: idempotency_key)).to eq :done + end + + it 'forwards a nil idempotency key to the WebHook service when not supplied' do + expect(WebHookService) + .to receive(:new).with(anything, anything, anything, + idempotency_key: nil).and_return(instance_double(WebHookService, async_execute: :done)) + + expect(hook.async_execute(data, hook_name)).to eq :done + end + + it 'does not async execute non-executable hooks' do + allow(hook).to receive(:executable?).and_return(false) + + expect(WebHookService).not_to receive(:new) + + hook.async_execute(data, hook_name) + end + end + + describe '#next_backoff' do + before do + hook.backoff_count = backoff_count + end + + context 'when there was no last backoff' do + let(:backoff_count) { 0 } + + it 'is the initial value' do + expect(hook.next_backoff).to eq(WebHooks::AutoDisabling::INITIAL_BACKOFF) + end + end + + context 'when we have backed off once' do + let(:backoff_count) { 1 } + + it 'is twice the initial value' do + expect(hook.next_backoff).to eq(2 * WebHooks::AutoDisabling::INITIAL_BACKOFF) + end + end + + context 'when the next backoff is just before the max backoff limit' do + let(:backoff_count) { WebHooks::AutoDisabling::MAX_BACKOFF_COUNT - 1 } + + it 'is an exponential of the initial backoff' do + expect(hook.next_backoff).to eq((2**backoff_count) * WebHooks::AutoDisabling::INITIAL_BACKOFF) + end + + it 'is not yet capped at the max limit' do + expect(hook.next_backoff).to be < WebHooks::AutoDisabling::MAX_BACKOFF + end + end + + describe 'when next_backoff has reached the MAX_BACKOFF limit' do + let(:backoff_count) { WebHooks::AutoDisabling::MAX_BACKOFF_COUNT } + + it 'does not exceed the max backoff value' do + expect(hook.next_backoff).to eq(WebHooks::AutoDisabling::MAX_BACKOFF) + end + end + end + + describe '#rate_limited?' do + it 'is false when hook has not been rate limited' do + expect_next_instance_of(Gitlab::WebHooks::RateLimiter) do |rate_limiter| + expect(rate_limiter).to receive(:rate_limited?).and_return(false) + end + + expect(hook).not_to be_rate_limited + end + + it 'is true when hook has been rate limited' do + expect_next_instance_of(Gitlab::WebHooks::RateLimiter) do |rate_limiter| + expect(rate_limiter).to receive(:rate_limited?).and_return(true) + end + + expect(hook).to be_rate_limited + end + end + + describe '#rate_limit' do + it 'returns the hook rate limit' do + expect_next_instance_of(Gitlab::WebHooks::RateLimiter) do |rate_limiter| + expect(rate_limiter).to receive(:limit).and_return(10) + end + + expect(hook.rate_limit).to eq(10) + end + end + + describe '#to_json' do + it 'does not error' do + expect { hook.to_json }.not_to raise_error + end + + it 'does not contain binary attributes' do + expect(hook.to_json).not_to include('encrypted_url_variables') + end + end + + describe '#interpolated_url' do + subject(:hook) { build(factory) } + + context 'when the hook URL does not contain variables' do + before do + hook.url = 'http://example.com' + end + + it { is_expected.to have_attributes(interpolated_url: hook.url) } + end + + it 'is not vulnerable to malicious input' do + hook.url = 'something%{%2147483628G}' + hook.url_variables = { 'foo' => '1234567890.12345678' } + + expect(hook).to have_attributes(interpolated_url: hook.url) + end + + context 'when the hook URL contains variables' do + before do + hook.url = 'http://example.com/{path}/resource?token={token}' + hook.url_variables = { 'path' => 'abc', 'token' => 'xyz' } + end + + it { is_expected.to have_attributes(interpolated_url: 'http://example.com/abc/resource?token=xyz') } + + context 'when a variable is missing' do + before do + hook.url_variables = { 'path' => 'present' } + end + + it 'raises an error' do + # We expect validations to prevent this entirely - this is not user-error + expect { hook.interpolated_url } + .to raise_error(described_class::InterpolationError, include('Missing key token')) + end + end + + context 'when the URL appears to include percent formatting' do + before do + hook.url = 'http://example.com/%{path}/resource?token=%{token}' + end + + it 'succeeds, interpolates correctly' do + expect(hook.interpolated_url).to eq 'http://example.com/%abc/resource?token=%xyz' + end + end + end + end + + describe '#masked_token' do + it { expect(hook.masked_token).to be_nil } + + context 'with a token' do + let(:hook) { build(factory, :token) } + + it { expect(hook.masked_token).to eq described_class::SECRET_MASK } + end + end + + describe '#backoff!', if: auto_disabling do + context 'when we have not backed off before' do + it 'increments the recent_failures count but does not disable the hook yet' do + expect { hook.backoff! }.to change { hook.recent_failures }.to(1) + expect(hook.class.executable).to include(hook) + end + end + + context 'when hook is at the failure threshold' do + before do + WebHooks::AutoDisabling::FAILURE_THRESHOLD.times { hook.backoff! } + end + + it 'is not yet disabled' do + expect(hook.class.executable).to include(hook) + expect(hook).to have_attributes( + recent_failures: WebHooks::AutoDisabling::FAILURE_THRESHOLD, + backoff_count: 0, + disabled_until: nil + ) + end + + context 'when hook is next told to backoff' do + before do + hook.backoff! + end + + it 'causes the hook to become disabled for initial backoff period' do + expect(hook.class.executable).not_to include(hook) + expect(hook).to have_attributes( + recent_failures: (WebHooks::AutoDisabling::FAILURE_THRESHOLD + 1), + backoff_count: 1, + disabled_until: 1.minute.from_now + ) + end + + context 'when the backoff time has elapsed', :skip_freeze_time do + it 'is no longer disabled' do + travel_to(hook.disabled_until + 1.minute) do + expect(hook.class.executable).to include(hook) + end + end + + context 'when the hook is next told to backoff' do + it 'disables the hook again, increasing the backoff time exponentially' do + travel_to(hook.disabled_until + 1.minute) do + hook.backoff! + + expect(hook.class.executable).not_to include(hook) + expect(hook).to have_attributes( + recent_failures: (WebHooks::AutoDisabling::FAILURE_THRESHOLD + 2), + backoff_count: 2, + disabled_until: 2.minutes.from_now + ) + end + end + end + end + end + end + + it 'does not do anything if the hook is currently temporarily disabled' do + allow(hook).to receive(:temporarily_disabled?).and_return(true) + + sql_count = ActiveRecord::QueryRecorder.new { hook.backoff! }.count + + expect(sql_count).to eq(0) + end + + it 'does not do anything if the hook is currently permanently disabled' do + allow(hook).to receive(:permanently_disabled?).and_return(true) + + sql_count = ActiveRecord::QueryRecorder.new { hook.backoff! }.count + + expect(sql_count).to eq(0) + end + + context 'when the counter are above MAX_FAILURES' do + let(:max_failures) { WebHooks::AutoDisabling::MAX_FAILURES } + + before do + hook.update!( + recent_failures: (max_failures + 1), + backoff_count: (max_failures + 1), + disabled_until: 1.hour.ago + ) + end + + it 'reduces the counter to MAX_FAILURES' do + hook.backoff! + + expect(hook).to have_attributes( + recent_failures: max_failures, + backoff_count: max_failures + ) + end + end + end + + describe '#failed!', if: auto_disabling do + it 'increments the recent_failures count but does not disable the hook yet' do + expect { hook.failed! }.to change { hook.recent_failures }.to(1) + expect(hook.class.executable).to include(hook) + end + + context 'when hook is at the failure threshold' do + before do + WebHooks::AutoDisabling::FAILURE_THRESHOLD.times { hook.failed! } + end + + it 'is not yet disabled' do + expect(hook.class.executable).to include(hook) + expect(hook).to have_attributes( + recent_failures: WebHooks::AutoDisabling::FAILURE_THRESHOLD, + backoff_count: 0, + disabled_until: nil + ) + end + + context 'when hook is next failed' do + before do + hook.failed! + end + + it 'causes the hook to become disabled' do + expect(hook.class.executable).not_to include(hook) + expect(hook).to have_attributes( + recent_failures: (WebHooks::AutoDisabling::FAILURE_THRESHOLD + 1), + backoff_count: 0, + disabled_until: nil + ) + end + end + end + + it 'does not do anything if recent_failures is at MAX_FAILURES' do + hook.recent_failures = WebHooks::AutoDisabling::MAX_FAILURES + + sql_count = ActiveRecord::QueryRecorder.new { hook.failed! }.count + + expect(sql_count).to eq(0) + end + end +end diff --git a/vendor/project_templates/typo3_distribution.tar.gz b/vendor/project_templates/typo3_distribution.tar.gz index 8fe5e9476c4e0843a629ba45402604512b98bbb0..9af827be92be4f42a71c4ba8ecee7fc792f6739b 100644 GIT binary patch literal 89672 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�oMz<-?>3=Lp^`w;pidnTadDOpGHJw8k$lIC1rrX~nAA0En#(`9bu)*Ct#ooQ>>sCB};UV6Vg+xTC#E~QJGAEeNkF!h*C3e z)v8Ks&Xg+Dqct=19!*lB)GF;!q_4E%Th^yWlP*i8JoLWxggw+0+LhX(Tr8^e;nAy8 zxoIpJPP^k>-&Oxl0i78`VH7(O$m7Zl<~$i zDMX~t7!v|~NWEm$76jUZ3M2a79N~<{G}pIGy$3`BwKgi!m{or${mp6_2v-yOiKdjt z*xB0}t|pbjN{d?~mtvhS0cS=NOlMlRiN;Yh~ zSgTTvUGccSk^l?+Y+>$dgOQ*6OD3(&8;W(VMVh(8S!p%9X0>XEC`tI)JOr+0oGi~G z&G}>r`K@JQ;90z`<_hcNQoQnC$tyvc=-63xY&BVX1C4PNE~*XoUFXH7EiaSjb&SN+x%_E#~EGN?x*w3_OBdg zK#n`#+xQ2;+w=Ua-wlnv_j&d9^DBG*L$2}m=la;!<<-}2H~;h2Q#}98VtiiD=`2If z@lWgem*gkE>pbnV4>r}bd>uYCRYHs_Nt4Vp+Ye@UuQDKRSD$yDl6ugdC{P8Y$G zq@U^4PwM@zIUajp`7gEw_podEh4+%XHoG7xpHeBGP*Pv?47v=Yunk~(ud7Wz6M0jV zC{q3AsB{Z{%JUq|fw$et<&3WGZ3n@`@NU2Pq*pIexbt-$Obk-o$;-VTzY_4ij>zXf zuTVIwpz!>0~%yp62qV}1-i62QIa!J+0vuOkG~lWjnu6^5;_ z4Q<;Ms$-&ttx+MoMJ?dtKeE129ERS1&<1GPnSA{)bwTQm!87p>CNs9{vh)Pf1`Xud}H(u@D16Vy)+;& z_8;Y&;Tzz>Q6uB@uB z8lU5wSD&AqPoHO>bDwLUW4^I@=X}t;aX&ttf1DGn0#@DEo>m}X$D7<04NxX61K;DSFQ$D~fx?(?&yy3m+x>I|zHiz_v?97vC$MwD=G@q@x zo>M<6xzW9WdvAXk-S{^?^Fu@%#JSG$jtkv+^OHl_Z#)$^?70G(D$j*!M|h6%SMCVG zbSY&B^1K8(fCxtHa*k>Da?86J?*huXoFBJt`-bpBxy=AuiWyY6UDrFHTh#ue80j00 z_4U_4>zz-GpO?S1eGH89m%O|u`h52($D|KDJUQLZg`pXoq&$!qfWdjbY`=5243>!zHmA@w7IuD}^LM6;zu7wkULQi;O!6-ACq%3yA{! z9_)lv2x0@)0^I`Xf_3aQS6k2?yajk=Jyt}t-`)4PW0l~U<2OK9Iu+(DoN4hGsZ&&4pU!a$vQ4wU6tm*c45C7{b%mYy#qF|)Qp?T zpF7NJ#&T-7sOK_)7B3qouEK2oW*dpugCWuH;mQQfX*dK((9FJ*&n@^r7l2ZMy`e~b zZ=O92O-v5@X1+E>o+CajRDv;sUUTo&*Jgf2`Mf(z_1{oI>CJ_s*}lT>6u3Y546lIXoKgZNc&OoI}z8ufq_xJD%q4VuAU|G(vE-QkG%>!R=TtBvTiqr^dPLeE4*3hzD7UKb;+_H?bCOxOqN>!)^~jj zCbaRw*H=5-xpTL6_DjLXLy>nn9o1a!UF%tVRV=p_83ErkIPO~tVht`0CfIL?z-_@D zcf@BrFh9uu8x!WOL?Qcw2d)S)k^!X%PE6pr?rtK@h*44s;|{Rg%)o+n!BVMmDz+xS z1F?)|!dG}0M7~c$08fl}ZKR-jaff}cPt*gx!r|J1pQ z0Unquu>tJBD)Djfr0*yW0r+FUb?7lo=%L&-nLuHOIk|8nw-Zi8EDeQvI53{dokAK6 zrAty@EZo-S4;LG6yFTI`^{R6|AMq;XVmL&`J^n6L$dMjq;95kb>CT(hW*AquZ-9}H zB86#qxwP*TJ5Syr49x)Iwl|GnFlr~|JIDIjUqvC|BUePegqoDe3w=(^?tRw>?ibs$ z$u?|Gdu)Sen&8<7W$RJVMB}Vriy;A7hzckmRzd=@P!-U?--rsx|64jK{`Co%nsglz zkA+4d(PpT-L=;&EdWI$*R_1*a7_o<5x7_7np?8<>6Q#loU9YLx?ESZ=81TBUC^IYA z*Jw^JMP&Os(LK6QTlBxZx)J{YFnf%kcG$u7(47mRYd0c~f9VlQf6o|}i3o~4_%!?{ z$jLJv;cBl@FBS@@!tIHS0qi0A-zwXNiY6Wa=E`^{7871yanJ8$jwClNTQAyILbdKl zM|h{~pbrARC45H9*?~yP6@3=szjkkZd%AR=U2`py(}~7k6daIoZ#=X}7mOkgUka@JKFEE=*|!0vAQb@E8V>mJ<8^gQA|NO4+2uLGYR5X~jvD3ufMjLK9H(Mf3} zfCL(asW1{i4DnY0i^5SF#o!xt07PtfA&AWv0`8p>j1b7A$0%fvwSuN48nB?*NCwSF zS7X4k6Af69ZN&bOk)ac6e4*^|s}sanabUxVHp9C{l*yQrwsowc6iRJ6lRcmVc;$e& zg(EIG0$d6m5DU~6tQHIxC>JmnoMXE=NP!N5xP`Ixq$1Kygen-F5)h2a0a0p)5*VKf z5Q3@!W$Nn`7@krP`O1GV3P%OaLn_of8svQ9(T}r3!ei<{(8-xlZ{mRZMnItc&`FiI z0kLvACVqC2_`b`l3>%4l<7F?>#cOYr+g*n#by`lh@oi&$_T+@~=+XIUtEar$dUhHY z_U`%4>scVuws@Sh&2U`4>9!sE%0yu;;m+Cnp6hDd#Q=4TW2a?cPD0rl`^~=NCG3tN z4@J7#4UX@Nd{LKvWf|3I<3OxPTf+r4R?|fB$?EGS7{9 z{IYeAhZ&P!SGTqgt#jHz0wWa=a3UfE20iKNe7Twyl5-rws=UJ4Jd+RIB_+$TcQZ#(er)Ofn^cH3^Z zDJzt&53UIt)s8Q!gl2z|8dTF%N7IzB8qOp&u!cE76{2ZUKn-jBum2yCmO#{E{Q5UM z-V~o+Ss3%Tb{Tk6D@tYIOzcS!LSQ_IO`tA37r-&!oN&RIfDYVPC8S~cnN^{nkbR5g zAaoT^In(?XMfqvqdr=#-s3S8BO4LwD5n~~x4CTMU3Tq+7422X5oZmXPZFYBawp&ZK z_+8V%={zpk;eY#|BHZqI%m&yzEL`XDnEg}eEBvl4ZX=Xq-zJdfGw)V&JLwH0WLk80 zIWg<_100^4LUkMKyuPDMs#{srwsW{V9_na5s9BFzhOn#J96x-+i&Q!i_(-fq5V#t` ztv%7>=40WtUgA#uCJPB@%%dxw#&a^@9~)-<>;bUhn8H$w)hD3z4~@xL4`1kRjW-#f z?-l~+eh>^B!Ufp_>>xKmy8!oy$4q%e zU361Q!cDex(Q}azo6Lz`#53bC+;;6U?TMwJnow2+NORzSEWkIzbMA+qBV$n=@gEaFVYQkx^fpO{!08TWn5c4F*&6(wwSuQ{1Qkup*%`y*$ z(f-^sEg)L{?_1{h1Z^`^g629;4seN|Hp9o9bboca-*G8{*GahEYvF&uPqtpl5{QEo zVMFnG^Gc^)$_ft4bu;9)Ocz_0iLZZmcWIa=ZJ(xd@so@arw`8+ej7O%6xYwd!u}q#@t; zv6})AKvgs(nukK*e~#2@@N1)C9lDyUA0{!lZ~gvZ$K>I+6BE0N%dwAAIn9@Rw=!*H zzY*KHu62XTS*x`->g^AZK}mN4*&;DcMCQM@fhVA}P3%svL6{mSK>UxWoT3E{W@e=P zS2RTnVqvCqW+JTSMbnCgmmb%Z9uM>(NY5KmasAU9Q1Q}=hLv12qW;Li?my8f#WhfT zz&h&(nW9`J$t#T=bHf4367aw!ST3QCV|7)tZWm9yzE*hdAitsXF|Asil_=J{mQd3t zMdrJkCr!UrTykqwnsu66u|nac9H=pad+gQ0q@^}&*4W-+xkSBNr-)k`sH2jp=kt0! z7#z+WHd$73VHan25~J;@%|DjO2>FcO!bi?HNdKucJ3 z3q-=Qzygkd7N~?ZkR?1}E%0CeM*{uCj!{Y(6G#~~u>|U?KOm{B-vX#SfU157sPe=6 z9tRln$BKc(ef(K>RskH3p#Q>IA-4Bd;Qr6HzQ}!y^nu?VatLMA1c#QKQXtC622vn0 zk^xlEjAX!Nqys5n8A(9@Q|kWX$9&Up9lDE2H6DP}cZ)ni z(Q9ujSt^^9q~6@?Qt-%JKI5bbo{ zs~BlX0sea%>vsI{j##t}Z=v?E{==pP?P7okK?VX*OhJK)+r$tY41JmnkFSjl^=FTv z30JR|jse9!sqa%~xLBu1VLlzU(|hS5IDmZjH`^n>J;pu;VWWixdBE03HI1{8n*9Xd z`SU7NX{H;OsV&Y0fXd1<1~`(LVU%buwLCJoZ-ho`@DOx#c}BDYFBdB+3Ny1QZ$O(i#!! z_hZYVC>VUR12e=JhU+u%Mh|CYmhqnD z{L~!t6)VgytT5m3_&?xk>@v!Z6^M@P&LUVx7LfXXm4Iq!hi|}j#c9-ivIE!g;KnAhebo?pzd#2W*c-e0wvc}-h26xM96C zW-TIhXelF<>}vRvn&IqSbj_RU^JwGj&X~nzdC}QT>z8@#*Ec+?U0kmR+BEFtWs}Zy zHydH?Hf&PcdX2WX)NSZsx6yc&>^i!cG7u)bn0-vnn=X0<>8wX;Eygx}P2lxvjkiC4 zBLy?&&eEQ-{aypFezE2D@;ztl42^BR__S5GUFW)J<%*V!T~D45?eP`#cPFt@t83j% zaLL{dl{i4|@`x*!e|`ESuS}Bx(xU5xo%_?N<8k!0@2$==|M_-w<^9o^pjgvS3s~59 zm0@tEh}D7ECnU!tSJ(`(aCIUSO(SSeD+mPr&k7=~U;qt6D;P*d*#HKfRxp5!su46q znZf@Z@`(~dEr&CoB^7r4hHUqKuW4L2T+6kF&+nIGx*XU1np;u0+C8`|L$M2kq zg~%?tbJBK3@2zq74ZVKE<7Vy}UJi`r4_mlHH0M9*K02TZSB4&3IcgBYglP=-9WB^# z)If&`Qys20Vz9&Lu>rr<=eXF+OXKH+j`gttpU^y_l~wY(6lgDv=RAJB?gfHloP zE85O4m_MSU4May9xUTlUbcdt`Fn;Yound+Ab=&8!TxBCmJg_U}cqj&d*=^|f^)fIE zFDri%Ze;ngd2L(^ZY#E$Uobt9p4Xju|4CK)23I=FOWQN(>nY6)=T)h-%fw1l;ShU4 zFvl4pIrJ-_i9W$m?1<6ARPqzklpy7x{c4Jj3iX~T~9Se(ji1kTG^3FBN z5(}57VDaN%Uz;I0g=z7UI5S`M*aj7}S3tk16A4YNOo!Tp%Cv=Iq-7L3U8UKk(qn0s zHe|E)LT5~>WSn5;aGJyXC(X);rGCm${QUNh@9F2=r?Tcp=|8BxxzprB4(GcQ;fGlI z4dwd6-q>uVwz8CXR`py_>aR((L-~M*UeF4s%v*~V+pu!dL1p{jY+ii|`FK3$oB4BF z$G3Mpgst8y_6hvV#WAb(%C-4iB+)I}#{l&KONz(BHm!}(;(y<~x}G?5?r$^j@ErK=mAt z`Y!%QAH4pBs3T?4puH1yoR;_>>cE;-;I&K<>lV?VwvHIKjsL9CPT9zxD*Q zasToENXrAXIrJloyX!&p6m$d5=VaVev!Tl0J1R~N)SMitxH(b?a%7O@Nx{k!ga56) zFRvVXJhQfAA90HZF`cM}U^`H=iqQCet^Q(S<4+imxzNqss=#1Fh4J+iopCv6nR)I5 zNDs~>DX+nmHyuto&vbj$UOw?HvLiosUAG$3uQk(uhM&+EHSh#^C|j#ddBCj2 zH>e^DCRI)6k^QZ7!BGr?K}}c)g8Uz%%TWxRR0ScDG(J$exZ^Pd-pOQ7ABB8R7w1j* zM28-E##Gs_+Dgj*v--$QhZ!4#7vB-~6DslaN5=K(+UP^vR{z9-C+CAhZ!L5+S~0Zr zg;ru)Ux8g^`sKc{Gw>1K{W-J)@0n~oea~}lDz7)6^NzDV68Q=(AEd6oum!!J^G#P; zzZb9m6mx?Q-2m*f_)nG>p{z39)jJZ>QTwf5xBf;*2coOlHZco9@e#q!YgoJ2Pl|}d zJ};Ujwr%#I<|)S^_d-b)Pr0O#0@iw*J2f8-+enYRrU1!NT&g$>iUW}X*%?^v~8TP zT-EA2NGL>S8swI{KJ)PGd)&i49`5WzTDBursJu5|-0t?jbnS2W-Fipy5@qZw7qcTf z>fi4B@XnSmju$ppw#|D($C+N(=bC@O1X<2zq>XpYROCfht?M>5ZwgF_*J@N;Qd*pd zgvpuwlEZWva#$(-CG3^S(uKby9$e~cw>_`PE9F^M4Sjz*DUEfw8@D^tg3LEdSzh!O zvqdM|{aC_0(fZO@%geMo=Da?~ugz1JBK9_hF2)kw-?T8XcX|<*>#OlBzeQmIfSK>;DZ*$t$LW_0&m%d=&#vPYpf% zwDj z#XtZxV*w0Y1qf)>zrj6h1#k$J-QF(D(@F=!#9-O=RS8fWOAH)K0}^lQ-8R*f9GRYj8o}?s=R&f_M!hE>x*;lxTOr_%!U~ZEegXP_KKIB8$;h*4 z)MD!rik+DZLt_z@rpQSkqm}2)8Iygl?Ic}Li-8`^s56q`YZW>35*N%C^cD;k5Ep0< zyoB%t3VAEUTzKps8}~%qZuzyT2UV5Md%z|Q-?H9#9lEu<&d_0*Z(QxX+2|Wfv>qo- zrTIMDjDRhnCmk)n`j~~6hm*A_Q1(u+drr+wfh8W}Lw3J_YUi0yd)jOcBFSC7Nan|N z(XkADb{gX9I@HBwsGHkRC#RuK0auL@wgf$V8e-_$Ceek4G5rN{y9%ogFlC<68P8um&{TBQ`l!tqsSN^^k%7E^~`2SdYGH7+9*1S zZ0pW6mMBK=Zf0(x((rz5q-y0#$d^1cmAtU9@z*Eq#!ebN}qfMewo=3HDMI z78N$|z7%ElUAnVJum5%Wd-!f(tGGhg_{uY3^mRP-7yH;Rr`h0G#-m-qSZG1M*PRzo5M2`)u(uCZhe+l{IE_~Wwe{OPq zg??__`VB;V;$jwAMk1Zg>iRt--tj%h-2wWa2fFzQMbPun^hk3)qV;LF`kyH}*yD`8 zfZxH^*67PFO0R{q`On;+RDPwuy_^h6d(ZO(*qv2$e4$|UJhmP|Ekx%dm4%*R_*16X z_AERP*7jVnI%v_h^D9c0Au3!@P>W}YIZ6;pcOCF!5Fn12hs0{Poue&iKXUm_p|nGH znWIfMogW$T+^bZ~X8vpupLvCpnZ`HOc-}}=$G`FMxNQGoYd5;!+Mh+Z2OP`xp09r{ zT;$Dc<2RjQ@;KtWxwpp!T%e?x4Sm?*Jz9jZc^stXb2A@F{`hdi@TdRHJEVA{?$a`z z3t8@!_UeX6WZ6^+dqmLXb(LN3$9pM3{~6t2eKX7|i35kGXq~jA;ARdM>%fE!s?A zw5X58DqPC=og0^I5Ka4iAF4LVG2A8l(ZdMEu_=-}J0e+jWP*IpzLXIA@`QRbjNAaU&HtGgg1|GP(by}Gq7Qp>E2i&1lBZ{n&{`eujzTfPcc zuaZt<)9#+fRov!qC;}A^PRudhS=XoTycxMF3l;}$=7Ea-+A_&#M*JP7GLqXoTp%yD zOqr^!HfUB!;&)@#33&AtDOngdDW`3<7DO~U5mDIxgiggpp%oTuy*}=gh<2u!oKm^>m21ve zKJZ6lD8byz8nH!ay2sh8+;@tnMq#jKr4(eLF+~Y{Z)7;ltmbrnujZQ!7YYk&$9w$I zMqW#8svl=oFwWm^0R!mKK~AVY0bO@~Uk8qFruz?l%H)V&bo=*e);XU5tfF*z{Gu;i z;k%*0-yKV>h1`ZNcE^&n@+J`0kvcr6Y))Qd3dE>TC&uCK_B{5jWPkn_1UKfbDSC~> zo4uYlHUkFijB2QL+F65(@XB{hoPJ>|b7ooD_Hv}EE#oyGB}KI{l!(Vf&nY5tQ45KS z9#=r&p%oSryQqZ3Mg6x_|La%FiqRzV7J~0`w=&e8zdzD%W@>fW+4mN#`@*E+tL-XG z08wLMP-6*@fmWCRrNR{?0jn?vNJ0GL|B-X6f8;K2;9e3a*#U9M@{7V-Qc`F%$e~B< zkKaw!EixXv$!26&MC+&1A;XbQ<(V_FS2+Ib(?!n*N9E*8E^_EfMHzT&jaBBZoWHP1 zdU4uP&Cnj-ll)1yCDw^8Y@5xfC{P%1oAYHPa#@d33D?Mfm27{W3k+tO#HSh2!LNdMe0%m&8}P6q*MmCf)Hl#aYz6;) zc(fDRMMryw@Ov{G<(MdG2EJ<+L_WKw6H+*N9kpcUw05yQl230{=50FrXVQ`p?}<;1 zK`y5a8Ezj6P_p?<)SW~xo9cPpY`7PfHqu+i ztC=gW_%=1ULFi-QDEK^gu9=KNG)rzzn5>b}x_^^}f)ipM&<^d^mcbYG%sG-Q9u^m~ zzhwSmO!KXe&<-8n_&?3^17`CzX7dK|o5Cq=`*XV ztu98k>(FB$ypP5bk5SdlIaJQ_>l!vg4>Q0V8Yn7|u>ov>j{)?cx_~aUd$+ka!F&kb zQ?H}3n?uXX+(8Vf?8e=1pdQm5*IB?lW`S5IN9ZxbJh>tI3p)Od(EGy(MR~9^HPJhwrdd57&2Ka>QaDPft(%oL&RvCocsP-V zz`|XV=4u|qi_0^`78RA5tkTBLnaiI9^4YM3CcNxx1X7Dlm32Nc8G5TH@|aC~H=+q{ z%VAQ~A6?^SubshOZE8rodWv{V&aoCoW(FQr=&=xoJi65}R$@5V>{XUz7H(a$p2_ZgY z_I=s2E?iW=0fyCMbB7o|8l6@=G&RQo*s9V<1fQ9P*w=Z{`N(b$4|gV43?2Ff;u`$N z=h80t5A+vn2KL!56*MwGk>2FGmwiGVev$O;(Bl+7>}n}zbNhb!uWed8XAG)!gILFvri@s^0g>yXr zr_eX8W}m*dL&>M<{2TT*ehFv)f>n3QOS~xW!o97kYi^6E@jUzDwK*4UboD`N)cV$g zJX29~my?j>%$|UuVi)3HZbiOLSD%x;1BN^f}UTRs8cW3evV(?_8$T~Ni zG~sP5op*{4)wJdPV4e8I!cPz)3TPUYxOaB}})AzrV z6!|asAJf9ko+@^l;dWH^Qvz>+ft7HMkDerdu#rVOQ*&L=bhn_%K|zzFf)-Z=9f2Aa zGBq@Ka_Ili%dUUnT(X$S%@5x~_ADtHnJ@c%dvT?^lHc`G6eG7=oEfK6XE?=c?7J8E z)#KDMd9pRby5GXXO24Irv^>vNv*~e>Zg&n-%jVEnp*FT~_swsat}fKHfJM4wE@xv~6Q#ywF(q@mnrRoE?6-`bLIxb0?0o3Q z+4I~&Bz8I!zOUbfZGfn&OKhJLRi7SNpMDR60|lJ+{mmiB0&DE2wIb1^wT-yj3hNqja;)kI2j?`blt;n(@i;RYaVs=@{%b5W zkk02FtPq6}kq^i<^k}%o@j49?KGS)i*dVsx z#~=hIuMX)j4U-7bKXFYYOzTwrMc8fxcpylFU_$bI|7Gwk4Pj!`qRJv9#60^XNPOey zW-J=-X0)Ego4-yU7NcN#bEx{bGaFK~9>vuQ_e%I?Emzvi?&v7yd_oAR-%vas!XKmr z0{c*R3&LR==n`kZ7qr73=m~zOZ&xfIVqn{$SRQo8z9rCqlyugA%%_bPQl(8*GmLtw zj(SSL6bml3aFSW&Z~s%OXoXWvE1KX`(+2JT6z((h9QyFFwT{xQKCIkeXBG-5jGX3L z>sa*3w5rCAQgG!~+p`5;YnlflvdwKnGu7=8&9g6$BUav?lRHn-;Ut<;0T-_pz0 zElqzBwx9Dzl3PE{c?bOHQbsX`1^wb`*uTHgF`3uq4e+8i3p$)8vQY3pmz^Zy7F*77k35CjYG(RnWBL{{6EiO; zK8t(@ze`To`1?}Q>&CBgOJn$YoM9Oy=7-TACLO$^F6s;5+4Acjw9ZwMko4kJ5T%<@7oXm0WCPie$S74S;(i$ z)%FJGF*!lacW}&g>T`Xc{AWapcXnSn_!@#i447)?CRRz#TcR2h-j{{0PWhF=T0c$6o4j%ujh zVg-@Wq3*5A0Xh+F^*W$?+@UE1I-L+9_Pow->=*=JTj`-gX>@l(pLA~>GWO_2c}#5M zhWMO!-kDcv|TSyO{p z6L8-u6Y{;6sxsBPn-HqXz5=pZEQKF7D$gkXJz4%P``GauWD#92Hf=Q3ULxQOvsqn~ zGLd=Ta0sSJbR0Z!`EJl35%s-`+IfwMI^HOT76G&RC!KHY;m>&m?673*v3}-jEtf6x zS8a+1*-k(EXvwz3fD2q>SSw5!eEti*DEZr=JlDJD=8M^8&B+P!T3NydENQ`|_xJ+&N zlHbEX(BpAu&^X$0xBL-ve3W8~xJRo5JhorwluTva3;Kc+LlpazE)0*C>|#qOiJw~= z6#i}^h_tEf{~qMOQ?jltL2M|+1+ARV($L_89g|-%7diR!`YQ9xB3rnH+IiG%pDq_X zCO=gz)d+`udQ56QnPMw7$?bqBzV&dgR=h5azDEJhLoUmAd+#nfyfcP=Lrzu5NR5e@-siP;;?1Ld{R#Elw{R8R|OgBpErM z;}P!AC7MS~_>|Bxd%cVd{$tPL*jWyL^52Gp=X6s?+Lm-Ny@#`QU0X?eQ4gFm4u_R1 zpQE|>X}@_8&g@<=j+|{(q6da*58h6h))U9HvVqwmJ-}{OXMeyPey;Q!eyjJ}250Es z&3Uu)nzpX%Jk09sV&X!w zhGm@rU8H#pl4e>ufxSf`qrh?N3NW`|p+6iCGgGY)Pi+Ry00nZU2XY27Kmhsy9KZ?0 z2nlouG=K~A*Z(66PyWaw8P#@%Qhct5me#DRY3@7XDT)SemXFj9URmPzo!^xB7ue>@ZHxZdh~%?H@%=^q+VZar&+wc&x*MlOJqoO0SV-3Q41xnt)PAr+8a56_mh^}h0OfUS^D zO4Os=kBr?+oR+Ef$=c$Lt^H(&@)``Ft5J+zAP)whE!co3ke&ZRY3{_(fLpzS9t_GW z@JVk=0u~`p28Atad;2vuSzjmr)vd+*l30e#OBUPf&`W^+MgL55vke)tH1B~38+s0h zwe7cLEjMO;9_x#zk47c2b|0;I7^^7KoCT&Ds^QSM`6O!3cCeC)M40;2-<^eZM6!6( zY+{pEtKDk^QP`4H+IJJ$;jB{%KI1Ys*bknnB=A2lH1ac$EeG7t-eyaA_bu8#ied+d z=agLLmB6&31f-ETC_(5%3re9{Py^Hc_tIorfue3h1-*s}25r^<)H?rwqy2te;IUHrGW&e8@4YuU#Pms$=lt)`U*=aa zKd;W+N{aO+$zP(lf8lNFc_|PS0&6;tz^!Jnf<7F?EA_Io=<<8JJRHAPREe#`*Wu^q z6X@>yWfjbLn-w6(t3xpVw%0Qm;dZd~07F2$zcLmd3%egVK1J}!lCVEMUd_T`jH!Tk|!jYw|V?AFuihd03}4?rw!3ka)>{T4~Z=@I<@$?!DEnCm_$x z*zWfc=KH4gG|yEpPe^aF=D#`%cJ#Kf#;>J_=(gY zi9t@$`YNJt*hhqq5MGi|DoZbxV`{vAFt5dfyLZdeNcoO?dybARz2D8+W?c`~$gb|N zGXHS9CaPUTDyyX|+Nn4=5z7@vm#yy+IQFF$6UWiblj}8)$G>Yc)ZjAoGK%e2v@nsk zVd}|BgWKL*!LeQ2jereo3vvOh3(Q%Lu$z5OrF-7>h1Zrj$5*^U`vhL~fH zA!eDG*)hk=%*@Qp%*;$NGcz+Y%Ixdpz5BpD`+PsXs!?Oj@ysrDwYt|*bxR6oRa@bx zoI=sOWC37!VA!!5} zyj{O-A{)2a zo-mwT%#7Vq7&u#Vg-~ZGRzM0iKgm~sNpv~MyP2-YP8v*VP7+QcPyYR#&8GDC{EzlM zgL!%JRL^a>U{AqH*CuxdF>Xqyz2US8v)s}6mPBH{(9ReAI=UHm3iCvAb#i4ExVy4S zQ+(Og!@FBJAcFPUSe48UM_=EBb1i|%_p!9L?VhezGTBjby$$Jos4D8ZS$yADs%{tcY|z0h#l zX{NS$rezjjca3mggrE@z&w(FcvTULfxOQ0e5psJh>=wfjTBo#G*iVH%V8tKaZeH9w z9o8q?aTl6eKXnRmMtJ5;y#R~GxVrYRcIFD40J`M0$5Fuu`F6B> zI})Qe{f717r>M$kZDFtBSNK?Wk0Y3vL9Dd{%AtdAr?0Fp0}~R|hQf~-w7ZyahKXLW z={c{dm`u#?9(@wu#E3{EE053daZk^ULmGQ)ACr^@`&tH+9ql6{muz*(g_b53zmiyU z(2M|EpT(XDK{}~G7)ZEDHUq&AyBPkCFHv3uD3|=89wNUdjCzmh$D0^Ctw+aIUd@Tm z92&i&QEd$^&xY__ld%}i<`ZbX%ewMJ_1m!s)NVB)2kpsU4OvN>-|}JFC}obS~<*(i`MyHAw{K!09JP~>rt7P|>xlg{g)S6}|GI%Cdjg_nDoWDxdvVYyr%L+}Fk5H5N z%)PmT?)GkX1@Zs}A#w56?(m{s9VNVz?v_FY*LXK=Hj@}R(~Y&P&~Ah#`G6`@e}rri z%+20#anQYj?r99TiEJjIJ-#@}0?a=Kv~+%{Fl^)I>(sW(cvuMPxD{_*Nf6qz9XP{V z;G{m_1etzIRrYPr&-C8d{4rV3HBW80hbh^zvXfe`dq4aMJN4K&JfUn6*U~s5LzIGqx-@1|5>;>jt7@JL)`xaQ)pQDCPU$~uC%iQyh6iSDD#yO5HrZH81 z83~wT6AO7c1gq2DslJo5EhgO7x^jeF$A2ZcDx5cm7QThNYO1j;$>shukR&{YN z(;F;{*ri2fON%0X54hmLn9!n~A-0rJ!G#mcW%G;Ox zPwPop>_-3fPpMI75v^Mhtt~nNKg>|`Ovn79?*-eMxc%-kcB>6|x z&0y*>57tSX*exfMG17KjIKLgV0X4yA>*}-&J+!V}2_g0;JL%&-$2f^C{Z!+T&A znRE8)3sa)>Rz<2c?cOhSQ>2p+{S_+79D4W#;)sDhDr3KXCO%#4Z2IuYBq1XSVx|IQ z>>23rKN#$f*JTI#S?mO!HfZpXoGV7dejzNO3Q`=O_!)k^?Zn(Vjdi-?`xM05)h-Zq zDGA*V#saAV)~5yc!p?|Lx4RCgHt1FuTnvH z$2)RG3XeG_CS9(buFG!!z*H*%i)_B<=O>di@uPzh(qb6E^;@|yCstp?6F?d%j9}{JQO?d_GPuxCXn>=w^ zS?`=i_0IM>fx|XM!(6-b4RK3;IZBy89uVxS4`J^0S{G_YKuB~Vf;In^t z=x}wYx$aJ=9L;59H?g|&fciYN?)jF|L|*1y$sX%(x&crY?imlk2D!R>#8s*X-ct_) zAfzy`WzF2u7_(<4#H6zw`Ll!nD5W2cHl`%9Uja0qJa{&R&mLYb zv;H^;lVB;6hT%vdbR#_(lt8E4No`-BUW#)D*Vn;T&_`(}mi%4u^L zNT$K61x~JqkKc6TI8>jl_m&dADXTS%cyvj<`m7ydoGQq0fGmI1=}!rrY_uzw(`c<@rMgAQSMyLUreRo){8H_@CE2&g(yd~pn*I|*{&jrj zRP7o`8FV#2$Devd>PL~(xYFoq9Vg&c3QnipySs6&=ZIl&RWz8~o||ivlIz}FZs<)b z6P~e-UXj*c7wg&x_oJaYu8S&^Eosh+#4#BCH+{RD_oBfJ`xt_&OW8A@$^49C`x>QX z*}^278_uc5yw6De8-i> zj39>_Kn>V|`4^6-`@k1m0w$~WrDTAy9H_lx?g%i zY+%I)!21GKYHM$}o_`{0DPbh5;u7eDhQo$8LI^%S4irdvxyzQf)9%N(Z&m7F?*TqU4oKB%2AowZaCMBVfDMZL|t0u;}|yz z3N)sFx$GlUuRS5d$BHTOW#NFj-a@j+h+O4J=1FfB)M~d{&cQMrZU_aFC+EH*T8<0nb+(XShbA8<`NJ;p-y4?RhJEt zd*z9J|0o;_8Ab+=DT)34gEATaHk$UD$^#i{D>wjc;2BEZP#EqzuPF~SE5xly6vw-4 zD_vsxk{v-_n!No9h&&)$GZjWP(e(8?CFJW5d88}@m=^`!a4|c?@C4J^YDmMe)GjY!swsSpSq$Y#9J@;!6q9Q!zdtK5=8ihu!@ts zcHZ~+NhHODnWBUWwPXQL(sEvIQ8W?i=yZ@bQ8xB#kF}^hZ&RZN8nrK9=Tj9a=WnWI z{CI+GHC&*dqfFl3n<12$qRy~fV}+;tcs1s8(*v}cPvwH$*85#iUfyg{JEN6}ISVPmh2>n+>=bJZb3b*X4@AixSvEq}6|I~Em1K#_adAoE!@dpj z)5A`@G`9xZW#!Lj)r#>ce;LHrfM*NRc?uYO+v>K2y~(VL1-SAwPZrQ+nCQMF06$-Buvr08H}a;Xp?$Ie|@BCPF!*?SXHiV z1=8YB8PHY+tm7AsO0pVjD%J~@5wMmWFbHO1lV_m8-oE>C>=L~R)UMA@*axQ3j{)wb z76zIPD}`_7n_8O=#&&T~FtD&NwoPBs4Miy>bvF;L9!1wYr{v9 ziW#%H>Ho|}xsLXvHl3^f-8HOlz%Yo&o>?)4muvz4k`L|-x3`W>-gn!4s~~IJNKHpU zRn$XIB8y@kJ>8t%UuXbg$p(dAXJ`9t8_N+G-MtoAq{Te4tB*1xsVgUMYg>?!C*{YsRC_o8r#rb+PM>XnCf#sMUR5_7J|ryg+r zdaTilDAOAWwkJwBcW{5Ez>f64FopF8>$DT$j+tV!WtF!DpOMSew0j&YeJZ`iSD>`> zw_q3S!Sk&5<(4*YqEM`D&=x9x?Q*=#cJG&c4$D|C9Hu)O?Y1f0l9n=b5D!YB$ai~^51m|FF7K)XZ!VrnVQd|h=-#`1 z^70^BOG_QcL$#1pn{39@6#Js1`%3pmRa7va;xX0s;#79X!{G68ERz%DaZO;WoSvQZ z!TrFWLKMY2J)||y0g-fCPY>n-Zfr&oSF7PK<6x7D; z39}obWYk28Xh>$!QA}WA>i;zVg`oxUc!mp*jE9F{#(FNske;!tEnL+Cu+j-MWwWj8*b zAB4T+`AiIi4BxYUPNY@BwyU!^V<>_fjB0A!_YwctAqq7qkS}Bzfyu=WG5_$@m#6xYg%xnU?WhCZN z7_T&;%e5T(A`iy_9urPD)Q|bsqx5t|YUoLpFk{T%M41CfaQOd)nKTnxyiR^Xtq|lk zl5I8U)N!m3ds0&E*s6X(y_oiEq6+1$2*z`Ypp=s9mxunVpeYK!fPbU7lRukz#V&;Hi=;CK+KuB* zv)PK^+Fp9X0}!Wgz5zC}3WGB)rf>LNJVt2)^2U?-*$u}hIjXjA)!eKlTjhnx*YO#- zzR}L0n?+1S+|Z}`O7I4Ebs=|kcnDAjgLJm)as$K8b%)fM^oQH(s#`2jn#p1-%Sk$| zV#XH4-%B~{Y=4tnT(~bVVXRyE);;!PWoy5pH664CB%=XkG534Y_$*uv7tjlQM9k>u zpkFsmaPWb}=E>jR2;@yNSLVy!%~l#*Av;`r8{<8d_Pa(v#X=%a6mbrs0_x*dRS>ae zuj?eeQY@|qrt;;JW@Rt{!~7B*7X1QKyF)_2f;?W3>qz4e&wHrsYpm*Ycg}@V$B@ z2>WiQ2TpsxW8OmA^qJDkAppiP3<^8Oio9$DVd#d-B9ckvMy$ANV#>HZ&V7O(Ya%dalNKJapJLW zm)aE$$bF`B7{tXh@E%GY6w>{#qj({f`EnfIF9H|7rlsgL_d0DVWfZ{iwMyn`@sWyg zVxLwWJaa~ITDkevdRUmH%2@#J2Mm+RLg-}P)hRXIWK#v2l1Dk(>2#Nz;>H~%8Cu=B zACtn@wry@Rz9Gkn^huL|lcM;b!0-n9WeM=f5D|WhMv4=G7W)qj`PUE4+4R?ol24|I zhrbb6Bxnlm+6Yu^U6x@!5$mAA)3e=6Mr&Apeu=(*?>qF8FFKLTu3+(RSw}l|`R^g@ zp9+r6*@U+H$1YO?wllsj&i%2?4qC-?&?=(3@GfX<=;?k^PRVxBcGaOVv#ILn;#boW z`_)mI&ZH)5?*g@n3B@OU+V|y>080g-$g2$DGxKSFDrEoz+bn^weS3FUk9|sYhXdRb z<4?7r{_xpJ-EjLKiOhI5A^kIxogyx#0SQ4FXJr%wzYR}4Y%u;C2RlPfe%96>Svovo^Z zt9-zYiDL?HHVEdYt6_W42_+^$oa@)3E*zrdR#=# zg8#Ffy00f~5RW{D@yJ?4Te-!oulo?K`y6a<&wXz%rnuSVX|*}?6>f1ZxKQ+St10}z zNQOvzxFQ26UpzHdej5T-8M;}Xugt=c<5t%uDa4{@q6B4I%Tk^jv z$$Qw=keBQgAHCA4s(I(`;R@{L3H^rh{@*UU?tNqrI}4Dt9N?ynY~g!HV;*Jbg$*u( ztxBozcG%fg8R<&N!ljR4;OixdNW;n~aHhz?#v7V#?}OXk7(!J64IT}d64|e}j+nM0 z=auO0QEGV!gb~94KwD%c@QUPqP<5yMMHcgnq+|`KIjwq4WI8lbmEd%_D>xs6p(3uS zN8=n_|35-v{}*TP9~z5SAy8k?I0dEhuLQjir=7R+4Oqw;q)Iv?;d7NfKz~e zSbvl%?}Uqs!_*B4An@oBA8-p$;n)2IzciZb=oqDtp6&P(_JYj51tjnyjNj?DF#+)e zEAak-jwRl^vt z6ZDvrzNi%cyniKZ#3ve(AF!fhd~&szazbh=Ib8di%xj z@cmyrD1{GA>dhnC=6oCR*c3)Plg=zj9rvnwo!;d`Yq^Qz=o6aQEr#HtS(-pBRn>xX zv9)0t0O9Top2H7~L}E zCvV397uN&tNmcp`=(`=wE)2+kI&zN7u$-I`m~cFLBm{6Xw*gSCKiuHt^Pa@wO#5l{kap`A;=9s7T!aFs%h~<(j%=lfY}EaV#8H zYiFS-cY)d+AZKt5rweJMOoH&Y5#qQ#*eP_tO?pMRfr-GkN{n0ec`r}Z@RkAUK z<8UKUfuTfRRLNcOoZb5xjL)langT+iT7$1K$tcyyev1-df1S^ajF34NDOEIRjHK59 zMTZgQUpW5j2d1!Gii(K$JAi;Z-krCy^^CSIkUH`e)f+$`9}7vrLS_3={(XSkO#P>e zaZI0*LNqdfg2=!{qG-+Js=8N@G`>JE34Jt0Fn54XqI?+P>L&e!(cro+ug%(^lD;~5 zhLL=93;}0{KiZq#*xK5dzH7aMp6#Ye>$c>9{;AUH>P+e4RmF^a)V}T~dTb{MwgM5^lz!35jdQ*#E5z_>*c~(+D*R zuo@%fy@b)nOiN1_<|IakDJ!~+S}o6p<4x^n3_GcZhbX3rnUvG1e;Z%mA8|)C#t6HX z%_dD9MJV1x(i`N?4F#tJsfFDTD(}KIJM`P`86TQ#9^U&^l?N(CBvF+crwT(1CFdYo zloRR5&PUh9=GJG{04u&CQYA~SeEso>L1IND(HN)r{$5Q(=qSowevjNENVk7QwYV*U zRrPHfa5|i=_#=>J=>4+jTT)o21~!a%jXPVQrIxPs=9t!4Hg@^gF5&Y=r+M-lra6^9 z>w}w6|4goWYO=$bTA9CIdFT3MqBc$yIswi><7P{tB znkN;F4PE-&`i$@CMjF-};60<$;AFQ6(1vOtjby`wOI^~XQuJ9i;OyUv5Gi_;SmL%( z`%#*L&>Ql&Hqq?7p14;@yMME#VxPw>WQ;do!|D7jOfK)6QwX?9oFP`MPD3lT1DiG7 zL0>0`d%yC)#&kWxl%z?F{5rCg3he`wrh~msc3SBsEP7_F`|RvH?jhP!WiRy-$l8P1 z`e%T_`sX8V;TImycxpeQa=%x?_mJA70`EhIYd&e1jCrv=nbQch8>#+<35qZvzR#ieU1LzeNvKb(7ctFO>xqm(PH|GlT7V>O_$#Vbx)Bw zIMOgrbFv`Fp7V1oc7uTP{B=Pm={NbH&sRg8Qv<@?`e4L`P6w?a`rjpF3t0-AnH~@L zg{mosGEoSt@u8zT2Aw)VE;y2AZ=Qd3A8Matqj5ANwwQ|eW%;($Xa2l@@5qc|&*7=3 zO$K@nXy)u99+Jv&MKUB^Kk%P$Yte1ZgH0;~70kVjxbhV#Cz!9%!>5u7!Ne$GNaOut z#P~!>v-4tPWnY31Kk#NFyK;>7)PzC=)9g?C$1f0#^4n z9mMgUoaxCx16Ucf+!}*$wy$1l{T*R>#>{imyvJ3(dOYPcMC~>j{Y8HCkn`^8%Aj7jma>P6n9IEMEXtue%z;ng|rjg$D* z`SzSs%oAVhtN77G?(Ko>)6KWPoe!4J9XXvTd^ExT1Y5)@@5!BRi0z>Ytf=4Y-XeFr zP^F)TPu_`l1zdbts1M#YPG~>Hxe>OnGz?y9U$C_UIv4<}==#*|9oGA+)tQC$a2PQJ zJ^k9#PwDOJ?j6J|uWXo{7dY4jtE|or-RA3a8GotYv)Vd6jg}o6Bm2_vAx?y1*JRpO zG@4%@hp3d2sl2vBX@#Ee6t*_l4&N2_=qdLZiK>=hlD9KhamViyTCazWzslDwQyPt4 z-Iy7I9(n6c!%a;JoB}v`O>(Z-91|!qqp;jJyikyoV4$f$x=lWHi+NR{d@Te2lm189 z+Zq2!+rLFb=}p)6CIry--W;*x%=)^6Ba<1E@n#?_G*)jgIvf!)N;_iX`miFQtIv85 zds%UbhsvORRN=&eYjl4<9ZUR^jWvaG^Uh2J+>4mR+m$Arl`jIC3|Wj&oz;zI~Ctw_n&VaNUkpzOxCF6*G=%mZY~4eR#w~M zeQ}-1gECe1CTD3hN4--3rK%OTLA(6Nurp&+apRcw2Z~|fW%2QtjCf?R-uJNc#(JBgJ1{S!PM3hcf)a@pnsQE_F5#iRekM74QZX&GAOPS8$ zq!kH)=VwAJtd<~oKx>`Uv0lIY z_l@jf4&{fKV7>gnSWYFOAGvaLvh6R^MYHs*f<^_Jaf!8~Oyl%3tOF7|xQyYp{~2og z&vR(A5AE|T^yex%LN?9Ue&sQkVenAo?ylUd|{ zyS{0daN9faD_;V#AcKu-27sK$9BtBf)w!%C3754)2>n8MVc{S5!bd-G?7uS~|1z8H zS}gLdmW9&I{g2*9BljPg5N3pWY&WQ^5#7Qsjx2qn4?Zm&o36p2Hz=v+U>{;pcgfdo_o>%| zO0(^vFW_=zr|&|kjD*5ZGNhV%CNosXzgeS zQ#}EhG{?;6_sp3>lBT*q4db|XWcQHQ^QXADm6Bk1rjDi+u06OanNf1orBcPED&SM>t`x_WA2ro;`FRVPS(>k-y*~!R6L2ltPpGyZsgd z@09B#%6aU>SnLEpm$xO5SB~4e!fDT{l9`%*!Pe8gj%*=>P zG#)ue;5!UEdE=wwUa&~SKR3(6)EE0LEAW|9W;4gjq>2?u{U08@A0C%r0RZ23=@X#TKpaV z#+A(HNf(KxeEjkXmpWOIagp9uQ>OEYCZTe)5cx8kY^N{S%?a@u-0FgsahUkk72c|` zB`1bnOWw`ax$ga!_i zz&K={XU?U>#uu75Dl{aPRxM zbI;WWl$NVOqt8KMGJc=;_MM@U)em9{U|Lr-$FXORF?1wD83!U^f?y)xnF3$O04o=j zk6(%>CDb%^iW0e$7ivTLE+Fxd21<693(7JLWw@EQ?5U<#Yn#Iuk7!g~fN?I23jT{p zvv1#ixPBg(38z?@D%TDzO}83a+^xP3lW7%7#cv1zTIJ%a_T3Fj!(1F}@ZJ+4Di}}@ zGanrBkGCdvX24 z)TKAx`}-dM;~+FwoMBI3&E)A*I}x%ehwlajbmPYC1r6Q%J22vP3mBolhKrOb`zmO9 zF&OK#`Ut(JF8m9Qjzhi!6;hK{BZgoa3%>dLNP7~a1SzkGN%NTad^iT_KqHm2?3&Ym zl`*H_(!ZW3^lQ7!hGWcyV+0VTsJiS+=4}B^)gvSC24Ca)w@a<-Rhpb26BkR=%scDc zq7RX2z$!1{8}?cnJtYisl9;O0>qgTB*C%@i}uRpUkoA;3fDv@EUCWmFm2U}Vee)t;1%;a$1RdLqc z?P<<|s0+f(4Z!8l^;l98GpgnXlWO3D)D~oeHK-6y%=IAsS2%y3;X0P^`|& z?9wahFKk{nr1_Xq6IpjxXbkS5htcav#C`JB$y3O|QwEiW-3ZJ9=64JOi^To*&nw$GZnuGMZeXZn2V)w5MkghkP0S0nbr9sf(*5bqgV}wx zwl;UW(|6)&;p+V!%eh0hKNyH6~6GNgl3twyoz z5W3&!+RbC7=(bnLR>whzdPc-gm3Hhr%iOOSx2y?0`ma1YC!2you3Q_67+s##l3+LfzaAsN zB}$Y@5-lAwNG`e?OL8sxe{n~@W1)IhU}}mfqK}G3!)b0ls>Af72WPhwyEb`xRjkya zDEVpL2ZP}_@=Le-i`Rbt^&YxYBS;oiypKlUe>O%Y|01i+`bDcTOYB__jd3FM*7Q3J!_ev9y~U41 z{szdnsRrShNc*V9;qap>-wA1{b(N&LXVq6WRCmVKiv^Ldw%)osH#0vcN{d3nCMl<) zqHO|%f%nXU@!a>Di5=~u=rPJ`I0;-o+@+ik^JsuhJEzpoHLr$?fVLsWDvj@Mp;rbg zWOZMec+dnqJG1jI#5;XEcZIoH^PUvfFo3_`J6=mJJa;_m$JQ$QlRA}ZMbxJWur99; zmF=&VSnh-=sirCmV&H+ebBbO{Oxr`6(qN+_)QF)X7pZy>U;I~j@NEx~Q4wpLEa3=zi2*u9 z|BD!IgMx2^hMF+GdfBOaW$%DO7lFj_e>!UVG;Ix%w*x9N01*`d`xOs^hn@D%7X80l zc@TljZZIYhDNJ#Md1*ovg;*4YTU^R-o&WPI=D_xMt*ikV28hIZc`KxWzDNbIXptYX zIN;Hc3((^X}n*yj`Ce~BMT3>RrORk3pkze?_8h8QlQ zaB+KZ4YaaUt}=z{lQBb;1teOY#npjZk8b!_y6qV_hf@D27;^8Xu^|JDa;}?%)6fM^ zATk#Y$w*yV(_JJ%%fE#ccNDPUwoQ%kJ`A`?agyUUCFINP;FJDr&W4s(R??$1D%iCA zGysNh$~GunUTe_(mCe6YV|y>jY0*C`M_V^>rIx5W=Jb9t>GX2YXVJ>l2ax8|GoT5J z*xNGEy@~YlTB-Inwj))p-d1cFRg;z{s{FdnW)?F9_KWwkzMCMiEAQN#UwQ%D^Viy2 z56VT&t9p!;(9f4>lbwC9uoG`4LUUnQ@W+)-x8m_Q%nCk670-%yd`76 zI*0-2Jv8MO(H6#7pNF<|1)Cb%^o=%u$Of&*CQlCMbpH8Q+Q|&dI(C7#>t(|CGUSw z=_%Wr$0&QPM%5t*1z@=L3GLvo=&b-6&KmfwTl?qw0!bf8(?ruOxD%PUjXiCCU6<_I z?nvk974+vN&v>MFaOt}DTQYPeEoC?pn;OhNmQgKzSt_lO)_DKTM{LB%mBr%xw-M)JrCKDYB{k`tt0QD~T5tSh0Aw4Ebv^X|}JUwL= za5TJoJaj_tX=?Ml3oI;4o(AkC%Ckth+Z;z1zs}G~N~cwu8JtpA);#JXCc3L;up4Uj zIZ|qtHZeF}tZGfP$}Iu7P2PYQ5?WREU0eR8=!(kb#VrlHZ=@@U=c+DtOUenIa^@8s zl~1oJc`2EdMJ4WK_j@h9E$#M+$`M+R{_!m56rBg#?XRVf=b=B-?cQsk94e;f-AvCO z>d#K<>`xW|&zp|(juuYVJBZA$&-{C8^Gv&3W*!d*k#6tNk&Oiw?lvdI=IJY1i&O14 z)42ra84v!hZ+y?87#&Sl;=EcePt_#@2%Pgb`gBj++atwV9*+`LZWjxU9I=lwWUBHa#Nk+|KqybBs*itRbw4#hc%mLz{eH71)*3q-O6eGCUE!OK^Z3EpMCw%ap)2xyVRXobNYx zk3!4~t0&$#u1YVL2?xV^SK)_RB5yq5UL|K)HftyPGfNTvEJASPy~>`P9!B>`*P;D^qHZ z@V-jsU(=8h%U+^5-;Ke@%zx*>C)I(({)PQpE39rfftEX$=C~c@{}UgVs4Q_(+N6ZbR{_IHtvzf_&A0^164M^!{Qov_fU85 zx^kNPvyjK2)j)@HZ^2N%4A+eNtPk?R4)eJV@re(CTB;b~{m~{Rth&B;DYaERL`4mB zby^K-9R|I7)~cM%)c+q{Pa5uJHxB2z(V>iel}rtEyNR;Izm>xmtx7b)n)?`|jM)*ch7M5Cg|rT zb@Rh-uIb4pQfr7fYx$Z<{mlHGfA3;?*D)V3xo$lIN#p z0)dy0Bbw}axchc!J!#O}xVfS<$vo*Wi7+WOIpg#Wcc?OHo28LO=d1ZCv(l?0Bx!+1 zOL!Cq8u;~v>`*Pp8D}dLy3_ZPbkY&o7HbR0vmrbR1?>s_gskJj`;2r$Z^S)(2eV!2 zqY2iI;Np8Iz&CEM>74^4N3ltQ^j-eDqBFsK+@CjRJ!UapnPPR<@{aIQA!+$vqD<-s z6$?8N+iZNSoLBHc8z3#Hb{N}^#H-LPh_|1%5sBQO>pqtM?MPo{;(ew=tjXG}1D;kM zt^U+XpAN_;$V0U(4Bib0cY<5uj|J8v?-Hh4nYYqg6RMrJ4qSH*B}_v6I|EJEU>!Jn z!+*%nzJnrCXdQk+1+#+d`hSDp4$JPprt}VZj%g02C177U`QIH2SZ- zy7E5raCbfbvxB`WON#h&fCG(FEFK)BEDkm4u2qt2vfM30zJh}XIf5Oo5z6*IC$-s= zA|Kl+*a*w`NUj8=U@z-Skd}yfRh%8d%>RC|a{hC%5_f=HsdddcOyYf8kebwRGGyrv zcd{i|XY)cs@QLNml6<)P{(rb{>!7-#Hr*3<*WeH=K!6b3H9&yiesF@j>%rX}g1f`P z_23%Z-QC@FlCN)n)3@bLPuKi4RZp$=_dM&}r&iV3d+oK?1jA~`{@kfAW}Z&}`nI_) zj!gc3og62ynW847`)$M`8$`K>8sLH9g?+==3y!?_7O*b-@aJg{X^yz?$UdjsgAVw+ zxw5on14AA^)RCoo`zdPu>+SpNr;-yUBhAZ5Z-@uYqOy#1iI;KQ=eO`;XnopAjhi>R zTt2)MSRzY2%PNfT9o(t%dtZ4R%NclD7luMXj?N1R;pKQ3RD_3+o=-ENQ}YvetZa`Yo3| zWWPDQ`N5e9IQ);((naHSNsza2f>KH}&K_mpMwvcqwS zr$1fX8Ijp(LPSDD!suINfBuUQGdL%5W?EC`saUPsX%MpB<7XenYKWvBD0NumiF0Nl z<_-wpmdHg1#tSpdJ95{ih;0)FF_V}Ma_qdwPCbSjV|Qct#py@SR)lq?e}`7M?G;d@ zr9Q#*8#zd>#s4X)N6g?+*7r$Tu_yxmD@-D1WR<+?0@mQa@bTr`E3g_ebRg?NRZ4@ZqAh=wQHlX8HJqR*N^ zcl9X1v#)g^BU6pxiJGJ?`ZDoTmAt!B1&`U{HuD)Bc5@J6y;|hbzr^OncU~fF2%CBV z&3EQ8#;8-}!l~@VzX@l4qMFyhIjQ^elnY0(4_3o*&vnj~`c|kw1Ipl3RZ(YY_iL~n zIZY|I?#b8vU9bP;bo9T!6Fqr^JuVYJQ!Yz06z8{z`G@r2Dl4MVDl#$1PvL$#L`rak zrP%KXN!l!1%>Mi2f<#;q55D%!kb|M<<|(wIFT?{leL2XD;jdN^TZrl~FFj(OA@iLv z&dH#xx?J=yh3&#eJXM8HWJjS97`G`WQ<_Dgg5D zIgy&bD5VxYHJj^LpP~TzCSCGJeOm5}#*-ElU7C_rcn*j4DbgTVoBE9kJn*bvqvlBZ zJY=v_r#^|TIy~{5?=p`q0N(nz(~6|20=m&@qXBK@pP^3=&qfs*S2;A=zr%!Fw1VRQ zkp2TjzaPs_@g&rtQCC2tsfi#lC{!kXnwLtjpytv=98>eVPAuL}6q=OEHl;pt`-hzW z%3dp!SncCL;-DS%Q3EN1&#gLS`2dn0|36JI4d{>lMh_+Mf`1cuwc9GaV+HBk;z;)y zaenhW(t3sHrD6%I8AI5rzgKNkkbBls=wrb=20zP`#1PoYBB!R{hj_Z_ixJoYPm-DV0r)R zp5@h^v%lZz_j{4C{T7&+6;KC1`|JZ#s@H>47yqN+U(TW5?*DWPUM)p~?ehH?I6Y})O zU>Twt`=7eefVjf(w>Bf1+KBLT=47VHkN+s%r@k3ch`z-$x z|7Aj`PvK;OD~yCtqFQwOld~!Dw3`S!Uo8|=Y}Ddt zStJ{^(4Njd<7of0Fk_<@+tb-^T=rrSQGmD0g!bVC=6@8rVa?5a|1)}K!er5Q?SCIJ zOz-9E|3^XjQ}ogUn0OGi9kDbIs4Pq47r33Vcn4$+thT7i%j4Dkxex)zR9u3gk74mC zATGq#W2%$N_)mS`6Sk@Z6|CFT&Jowz?a$ z8}gz_|MZ|tK2&};Lia1Sn;o-*-_sNEMLD!`e;Ol6ci7xxSOxW8|R!CWeE@ zK7wiok3au+(P8kI_=+bOJVx=~#3Kpyb;8^gf;?|)fnl=uJL zGX4u=I{&Y$dAI+&nt!`AL}e~tBwG1R82WUfK?*BiA;0U|k;glkGf|g^W zgWTkta3=CMs4eEdgRbxkLx?x*C5Ze@MI8ZT@MB*kLQ1E=g$cvShbOc>$VI1z7qpo% ze=%m^y3Y>2=9%&)IqZnK(Uo{w?X==FE^dhx;Z!{6A5!4lD`}a0cFDUx7e8N*T}w|abOa~TGTGsh=Y0-G-{R|QJ)-4gxK~Q#^bBWyj%xc1*93%K zX@|7-z*zTxAnm;;fBVtf5&FQ1`A)O7E;0%Zv~T;XR5xVyYdrHkE6-<+b|BGud!!As zUwrt(?MJV+5MAc2c^8a#w5@gF7v7MLfCuS+8NBh+!N{^}u(aoX@h)AzTQ_#Twzoyt zFmEppKiu*6b_74%SB2e^dI9BLhmKv&{g>}A_nuv^f#7R_wMU3cGV(X*UT>cVbj){( zEkUuD;E;EO6)zZTL8wMD-{t7eQ;CfR{4&Nib*sZZb7^MxYaQFE@C1)oduCODd-c*( z_-v9+dBcrCeF44&Lz_C_uy09N(L0G~tXf6ux(4g#$vke9RZ z8-$rH{dE@L+CG^vOD%=pCI}=Hpc@^EYCOp&2_)pA7aWMvJ;{gte}P+uw$Ch0uOB+R zB6OcwdM2U?g1kn)+~hgFrsy9Gpoj_@e|XY&xit*RAyWkkmOuTS>}fccSf50Hd+st3 zd^my6dflic^StvP|2y}$5zj;L^PSum=xan{J%KKi5n7=!+A0V^$fJLl6yHY})-PFl zaC`LaZDBT`t>vi5~9Y+S`2p117zP zV{O|>CB2u$@52ZWOm+NBiQX0{?)I$o2uJdm5L zI8Y=IgV$mC8f103iwbBMm|kbMXtZ**9bRI;yg!f9t#QBZIo`&%TB~w6oqJ&C-7=|I zYpK`oX&8BUSy{N92UQq;9V?r+EiYD508zG zW{7cHr?DOE3%?iZv^p&Z1u!vmG--A<3JEan)paB(6r%J$I<+ z<*P}rZWbcqt?#b~dC|r;fL8tIrS21WLQ=xsG7f2r3DP-d3qU<8O#AJU^TV~9kaS+h z@WDD!ofQs!QDegf=i@p1lIGK}u4T>yVOVq4RLFdiX<7Yf0;vatrdST@lI#qX!mLopE0eQ^&ouoW`1;-<0brhOWFA&$kK}LwSn+bBVk+9-31;v zz~cX&C~>~G_5QsyV)+x>)jZ|9V&qG6uNL~HzhY(X`4;9~gtnZGb&>ndy-Q2`;2ct2 zXyfmqu(!$rjAXSW&y3QJ(*&&P+Xo}Al1ol>`N0i4lGoLv%TbotDro zRizW>d>28xZCNAap=w`6W4fR3lPsH$ceWjZVehpHOQ;FYniVl`eYY{It?mAmWk#MS2;)*^~RYuiXGrJ`& zgRjEUGbfr@VE+PnXsPL`dK4&EJeFi=)1CMOWW)pPIs-qUP*o}NU*$h03(cqN4q;w@ zEg^#$5=xz-RC7jW_b`jD>tUBfO6%yS&ZJ$VQybFnoy-_q@uM0PTP0f600pxa_X-qQ zlce+Ql^K(nQ>i75TxE|If)kn3V`kb*Zl~|2>+|iUuaZ?ZO*W={ckdpjZWV#ze6+>x z_pv`-qAor%+|@K>olM^UZh46*@9mgIGaVT0ezK@g^3Z%nTbu#Fc%n-dY+#WH^VgaARQ0BdB^wOU|0BCW@MSai$T5ox??!4yK}%gqrqAehng0J;N|R)klf(?{=!?Q z4O7uE(OwJ`evZ2vUou=$tLvC)FW1g_yTJD(OTNGp=vI3$^QP=K9jNc=*5%Cw0$@Uf zPHpOKLaRSY@|FVCo(r8NpLIW~r__62jIGreUhicG&s(ofRPFiJ0~$c9EzXhSqGetA0+vsC;#U|CJvM%SwAyIL(z_fE^W=>-KrlCO-h-q*;loSb}3 zo4&JYYBn0%t%dr}qGgSs0l9CiL)xlcw%IqdmWk#D*GH!SghZXriyzq!QfZamN3YNwmhZQ|>*!CBkJB;hfv95c-%J38hJul; z#NPCm@>BTzAjynhq)C^se^6(^KO{%ADI!kld&73uH12Q4kPX;MFiJk^Du)Cb{3^!24|OuAU7&CO)J~s?^W3L@S?8+C$IR15XQ#vUExL(H0Ivh5 z12Zd(s3n@TIQT%pJv}qO=s566xlJakNbPX;iT~;K$sHK}_U#oB2zq0Dt$M3_D}Mv8 zeWx~LP#!1|7hq)m;=yF=rx0A=f%a|b0LE;u8I&b z05gXP+rJFui4^e>M%5d3F34%&UiRfVdw|FT=Uq)N7+L)aDyis2R!>KHz%@r@7H)r- zSJH6=_GZ&Xwhh{>LY^3T;R$N4qm!_x^Q0omE)W}x=N~K&WyKBzo{so+?a)MWr00te3D_f$y_(3x98DeiT^FE)AJQZ?y5 zVI23l`kWip@R-_d1uDZM?yM5+vt`=N4wa0=B>&QY^GgucJ-npIBf|akbw-IKN8sTZ z+#>wC56~36Ao`e#&{Og;&6Y2|?i_0hOw{LmnX|V>N1CoXK&TjyAjuhN+YE=i&vDr~Fbo#XV{0U^4 z=y^3tWa9If&XiTKdtK>CGYd~E@#sjKmAWw<y7%(!@8bj?$5iSy|lyy z?c_`EZk1qXFfo=G(nRc+%cPKPbC-L8HNszfYlW}ArAd0D4oXunTzl0FIL9U4s$`#g z)#ai$(h5o1^4kk*t%|X0&iWriet#PO5OHObu^UZf1paYpY zZ_S4uWN~|aTuME8{9)fn16(YKv4wpywaq}NlOw4)RkAn9bcKsGfn83Vd#Q_T?Z?%>uQ3=1luH_hUE0$n@N|d#uRMUb4!nX9+HS$Fu`!OZH?z2xC1(ZC$JliDC<`p&86TRG7ZOd+28hJJ z%Uq41x7A~&Uxn`JB-D#(2tk>IIF-}aCS3+eK;3<<`cUJJSc9idjipYUz(8#(rCkI_z zmXd&a-SlS@)fC;F64dzm9vFla=_BpuCqCHnZXSGzRMFje^g3Nf#lo0NLz-$eu z(0&n$WLjxhD$4iu%l1{gwd{@|CXlqq#xz3qwOkWTYYAE91uG2@WxBgYb3DVj;fENe zS2-!=d7b;Yz|CQ45#B{?pnJog^!U7D*=l+s#Q>o$et8S5kDEM>i}X`ha?HU4A{g`B z`_fJb9?G%C$R^V~Wkbg42ItO0>BwdT@9izE?BoWTjzy!xu~}n|aly;yarncr9+0{R z>iu6pCs*c-pw6pOb3yktMWf?pk0ix922yEDu~O#drJTBc5>j0p2I;c-yb40q82mMT zMo)yLC~BREq$faxGmq9f+8l7G<=*txnxJ$&&MBKVsK4E4iLXMcj3%-!ux^s{MjyZA zJ&d-3HG^%;UHy3-%3bHk2iH$yS3wS-sIO7nn$H%hWz>^t6*&ns;eD1h8mT#p%{oPa)? zM4*p;*4oIXY9F$pejyLS16@xJ@&vaNh74jvn&8SxVF`pkXxM!D{e!^mM<-R5i6?-% zlmHiE7w^Sm05rgZq)Pq){|x@;VP&hWMFeg^;QBFzaKq*Yhk{{sQ)t zL9_L)CWHb;CR?B=svijGgPbDcW9>?k?g(a|srX%8i%u-y z*aqST`^bwsKp4}6$?u9A^MX#x!e=xgg{_OHLM0AIF?+k~wtAz|Iyc}B0@FGhu zyRT{v3y6$qSNZLQs8L&1%)BUaC74?u$9VNMGDm=lw^vRqglY;7`x|>?TKhMy13deL zY1G%LQx>>Wr$f#Xm$9a$i3;N9&S9K!-0J&Jq*mSsshkFm)qx*bR>E02>O@e<#zYQ@pUP3@vWXj5%Jj{|5VlE?HJjil+>UONVB}piRy>79YcM;Z zB+OTPt$q(=(RlMNYsLFQRL1`D>XAY)lF~(`K#zFnd_*o$fYl-`gR?5uf`}@$n{ZZe z9GV};l&{E?D78EFtpy{O4S^so1&c+$^c{TOI@e)x&XRXn;xOiLGQi8~@&5ciuesjX zeyq73cdPOFIP6VuIrdZdbp3q>U#~{b>+wpNfMmmw@hRu{B>jMK%lzjG<(*QoN}(O| z9=_3T&x#K_N1cthDxW8i1S|KphxqRT7_OS0tb_Xt-BQktOh0}tB~pq`2OfeSlh&k* z24=@4#OG)il0y%2Ct~{))>zYj9C`l2T|;8Lmc5+|SF%5ml|uX!JJM>Xy*yq|`A~ zDZ>Dn)}z0vU2+JuFC#|DRVMHQK5-L2646cd&ZNxrtKc|%_d4|)r|V|OEqtNX4N zQCg8K`s%2LA01Vfmj`&n)05J|q8;xHYa^SnqB1w>n&%tQ6p=_rS+q@y^p%kelsUk- z3FcG(lorhz=P=O+6HdLXp&zc2J)QsSKmlD<>v!acBdB0XdG$tMa!kX8wR;dVn&x$!AMUeXCv?6Ze)Ny9}?qk12E#GA!g&+S{6;sHq#3&?1ll)uxhL1!2IqA2B@82p^1b9nSRcjn%b z*Y|TA5!NnCbj>8AJ=gNbMEx&MA6aM8lMeV(f@M-=)S69bHfUh59@BWZL6*+AT+*s^ zR_LXW>V>f}b>YHqccA$1!P2qvy_cx|lxl2=`$fAJ2i@xDF-sdt`yJDP$+u-u7TGc2 z6BtP48?NjS<>2E*Wz{kn=7(PrL~JooZA@&@S1nF#(Nj%By#L9fv-%D|eMx0lhN%WC z5GIQF==)F+rTJC&d62I4L!uMQ{*^!p4Rg$-%s|!{(a9Nqcjy|!Pd4%^l;L(c9jvK8N#>r^4znvuLf+9bC?bs{=lD+s#6HN;456Cyn41CfJ{Wwq`5(%t#5Su zq`PLRn`UMLgGWNy1IykU+yIHb}V)F&-yal;EHKS6p&FJps>B9|wZo6TBhEoY4s zI4)Ia^0qIwfO1Mu_kO55B; zl4@MMs~YF&%O$&4M((gpNi0g0bIr`c(S`J0Ki0c{LpCNGwHbu%es5HkTQsm~v%Dt+ zfe8qd>P5y9N8X8sR8+*+pNxC6wA+6EOppH>Rl_)#N_jK~Wd-O|GpAf{5j@}>!&}rG z**MAOuq?Okk{{V}LtMP*6KK!;Shf_oAJ%j}fK6g*Rd>7g9lqW-F8@~}e@iG$U+(wR z(#YB&SAMtQ$5I;7!%OqaR>vzZv}1v(JcEn@%&YA7NRKaxJ9hWiZ?o=~QKjpTYqTb+ zQXR(z-^`}E>sGMXtFQClG#OvibP^ku%lwW?avclVdu5!jo}h^Iu}>%gB^uzYB5N6w z%M)yI21~88rsgZ^(@f~FerpYD2&_-_?Q69> zf{`iXXDA|MzrNdNjCXyJ`kv7(x$AmcCG_~g9@XJ%gyvV~p26LZ9ex3i1ma)Ro@S{M zVj_Ni#jj$`L=UmdtnorFjlxs8k7G0Lx2THLXUAR`j;tHX^|s9$cacRX6vr&zfdAIg zIwTmDuUlg&8~(gEqIk7JU`+pOU7c!}HLUka88VZmQwhe^9YPLu!wjX5fM z3!-sm{5w5C8;Tt?Wo+qO`UWJA6u!AQ&u;<2%z}|<0DbjWFNbQ)ezN@o4QjQMsHolg zFW)+LrJQjS+*`(*ig4ieG!{RcPS-c!uWox%x%y98~jfMkr z0053bP#Y1Rjm;!ek{O~=nJO0(R{m~p1(SrfF$Z%k9})eq1=ME{Y6D4v^@lnno+nom zoL3a^es8ObnpiyTZUwsZmF5m#Kb-+jPZ+^)LKFLfDxZCZC-ISZKkxMp^SIhdJcGIG z-M8$gf!X+-Q?g&DzK+IHiYUeQD{+!DqTX+-QmtSjL*nVE{txIqWtFQI_W*tm6wuQh zjL!2?_+8Ga$@;caxm9-=yXHzJEknNxB>UVNS>t(;o9BQW5iceVFG1X+jA~=l`F8U} z<%D&z*V6jeg)?JRQNCN@1@-8S=Df=p+D(G!fq31TP>$a;%Q&j@)db}Uxwu`(mcJ@E zPN^F*Ovitl%keJA#TSkB4 z;>~$}Ia|@)1l08;NY{VPoCv|R+!z=<4L1m1%4IBim`e}5bEKQi-0_l=7&m!pAMcA7 zsPzO`m%U6kY`XQi8yKE$gdJc-3eUV3C%bhlkDJ~YdP$@#u5ARRn2z!{N3u{x2?bA=xGAsQ-9TgBPO~wLK$Bla7a>Z!@RW^2ln5}41(e=9ytLDu zrD}#KyiO&VH_l0&P8(#+Kk1y`yjC9HSI*u5UHDyI+rQ+jL&v+5UU*91MyF598}`{P zt){>`cm4a%tqNSk?NqC zX$Y0O@6)D-1{hTMGWwAYs^s>nmcr*ee;VAV65UJee<3`Tcr6Z?WU}C^Wn;2t<4z*} z-D`*9iev@_va92sYmKsP=s5DRAK-K+ESZQgsYztnW5@32BfK;POZWeh8}3xeANI}t zj>s-mEI+(%k@eLyhU>|9|C3@Fi`>E$j=dwISbS)X7rY%9}@%0^v0C*4+5rmneWt9d*GZi!Ku?ZgVxdI-vGB_s;A$=r2j39%mtR zZ=}6a-9t;EYD5+0KZ7-pU9@eZ-s?i&m)+)tV>aI_&%HT%-{+bnIM_xoJO)jdRbbbz ztmn5~&ZH}H*4>X9mFvit-%m=iLdU(dvgZ642eUjLItC6+SHTg5g598aGEU2WqHr}wmdDW6^r)<*BpmdZm!a; zOA%iR#ad4I1-pG0bU@33+;GTTgX=8}sPSQEBvKzXhj7r#V8NCwN0rWBxT_=9BUy%S zN}fe?5s^AWEQcqurZxU*N4Ctc0!cUndxre(1YaK8=KI_ez3R&`ADjsEsiFWcouh>u=c~TKt4eLIAZUpc<9mcA}$a-K>wWi-C28zqleFnyD%$@+!36>P2yUa z0eM1mf;PVA!8<+{Q19BVYNe%T5?F3EKC`LkS zl5Xp-jbvjAed4sWTNTDB6z&MGW40f-E}WK*4jy8HxC>;yB&kEL?$E}mY%HsQ|1!=5 zhgOx@={tw){6O9c;~IIPd0cU{ooxRjSsSm?-?NF>6}tS~DdwXZ)H@v*^X{3`IbIu< z*c|A~*~9bRZ(aS?2{=8ntyrZ2lc>IFy5d9oxGV{6XjeVX3*~7;6VrePDq+`<1@%zt z2@HMeS1#DHxOD8AF5Dcqw3OnKsm?OkWp9y=8aHf zwaY%y%cq<42c5h=atj%qEYA2B-#3*mXjPY{FA`KmMAx8+E$*QPy2v!l#+P0rdJwW| z;eEz?u(ct7T`+IJczk+6;&I@*pnfpd6?Va*UF_MkH~k$eG`FXPX2pf{5XO(>IZKM1 zyr{fsamRJxM1<=@t}So=DAbZ_?U*IWeI{5Y@8Q8YxRaEUBuc<=7_xfFEf z8KJ350L~f*Z;7_^+=>a@PG(7J8xKT!ncRbJzB6jKg7h*MTol<*eMV^-#e)pDWVtYT z=1VtOK1JR@+mr=BeQsd(?NImPn)j+N=v=oX_)@pKx#A7I+%qc&f^vJi-M%|=V6(#@oC22%s<8^ z7zU+HQWWNHuV2Dqdc@OInUY!r0VOB#`92h32321R@20s2lD%4#COoF7itXo?%W~2t z6LFIZSbvi0B+Yv~4AflA)(#8Ene$e*k6BtZYr(p8;5ksVGXdLMDX?|;P%+_op5D+kiZ@BU+TMa}cJIFJ& zXfMO_{1~qj>!?C`lbi|ynUGBAuPfG1PaZ!l$sZs$wpgwj8XmDR`UHAs4AdXMqq-xN{YWd9u#)Et>;;9;S|wrhSxw4M zKWx(Mg;47Qt{bxTC2-8I;N~QQ9vljjT_X?SxX6|a`67W2vCng7H~4xkGGg!T4I^YHzZWjR`?KcF zKh%6?f)~AJMmOlmJ$`&6|LrY0E_Z87(r8AHj;w@MrC(>H-<ZW^)$+n`VGN|_L)O^xZRD7nN=6( zxq;A#_UF_x)N8A^lj2{J1cK_56)20N7nsP1$#EiU431q_HM%UsTA!IPB{Xsi+1YBK zJy@r)NefdX&u0az=%b4;L#M}kr?DGoC#y<_q|+r|i0*Jzw;Z^96#a$xyurP&3Q;CH zomyHbYay42K{gy+-EsuiX`{QlZk6HLL3up`ZGEU%W}1rn8Cp;m@_l*dZynFag~)?c zaef{zw`od@+>eV9dPNg-cGci}$(b&=BC)NfLDWgf`A)$j_{(y9V1L}TL>`dRL&80( z!!rdhB9P^>u! z6aChh_zxJm4a3n+i?Av$EKynvuk;gjYTU*0H-vtrm*?(8gQE0Uml;!1FR97T3e)gl|28_tZ znzD!FRY=hWWtpDT#MR|v2B~sz>{U*tg@lK$Ba1?L= zZ~vyHD^N&_b%^j3A3Yz6Ti;Rjrmzvn`Mmo zNWl5g<-phbU!$VBz6ncQ@8H~{YmoRG4RcvFAb$*-70yJ}mMJ$oip1qiESUG7SJBqB z3&!%wz3bK~SCAYy_CgNNA3}desL>v*FAK+Hg0O+*f~6kYlbrbxf(yZ-Fh|>aVphOd zv#N7Yxt+)_Hk-}09QX^fb#(8NHwa3c-mbXQX_hu?&3w==Nc?lfi98$~(UhvUN8IPw z{096)ojxYG78H=}vA?^!F|D!+brbh4?PSCeMys+|ExQ z=PE1P%WIAzsO)lx3k?a-Yke)9hMQkB$r_L=%FJ8)zU0C;D>Yev!Hqs|XZ@sg&Wm9| zaZHxIb$b{m_G1EBub5fZwX|)O%VHLSWL}b2lk|l=-{4Wf@oAxYZHA3=jcGFTO-pa^ z=M=&490`fE2N8RHeQZEv21)YR)KKuG((!Q*wb3ioTw{XXhYIoO>B5yMJXzD#jo*-X zjNevkYa(przx+^8%jNqDBjEWZghAHimZ}mB)F<^p6&0Jjo3NMGKF@fQrYKK^<>Wi} zOi$CSA*s7~2!h#3fk63N%G2aYIr)o#tn8WIR8IvC#jhlw!;bl_UYId-D~8i|@-0_z zzy;Qd6oT$*uuvd7G?K0Qjbp70GD;@BlHxV7`*^64u?NATOA^x&rL?Y;nFTq@|^-xqVomf?8eT5{PLsya+kH zDh7)~zrUEl@`larTdUu+K0=s-zwCkya>W%bFz%uYeQI~;7(f^24@(UKE;_3(^AKyf zv~tm_0u?^pL*dRQLQ3Pq397`G^Qj*#C-OVQ9v7@RgNP>67zAS)?yis+O%`>2nQt9f z4*?F9f93z)*%^l%1m}E^fp40%(JxtvB~GZ1Df>YlHd?J+u5uUKN}KDfti0f4mpZH*>g9*eIo&(FFqx{CfN< zNtpX5gZHbF=splCQs1t8AwLvyb{F>zm&mAy1N^gf>5&FA;ie~q3E6M)B{Ng(9o0Ffj%}oSs5PnAY~?|w{{R6Jojy|$ugG&SpneTfIt=@Ta|ktkaPep4JyWnllwH&LPt0tiY|#9|&XG6L z53t1k(avI1Ly}Z@m~*oH#1*%D$Qj}7xsqpE>?&YfL~h$#(wHR}=!+#qfUwDaMK#~1{GfhLB zA8&9?UHNK}uuHrvlKSef;d&d16LU3;*ce3!_C7ez?9`dDF0nhekyBdSbim>`PwVD4 z6nbHBGCEA(=cqAFm|)Ml6MZGwh;r3(ggP{w;ce~}GqV-H4k~VWNNTPPs%=i2I*L)q#FE5m*CQ9qyP`U0M z1eP6q0phTlLgjzJeK%2)GOztDMD~MwZR&Mpl4;90+}oi1V_<5lHUaH4pIuv7P$&f{ zV1U>D{f)D0&LEsCk~jVr4U29ykqCYG5|#C#bh5zP2Rcf&Lt3f9G{lDFX{8vMJ0!Gr z@9(Fz3}%I>L4Bn1y=r_WbfYKTXuWlv$8)dL;QWyhLb;!7=by-7QA+NYZnNakf%RZF zcR$9`;g&uc*CMOq_T|Lk6GK0914>T(lWv2(;C#<9-0!R*5Zjfb?h9%opVcr!0Iq5_ zL-3R-8-ikD2CwjlOiD{ciG7ax#1?tG*v5#?cKvaAyym9~%|Z1?WIE zNPNI$tgyIQevAH=?m)!SQEdkCcAtkzek)_0e9XoF&P*T7DAnlXnqHxD$hnM2^h!M? z-yagjlGJ;pX-=Xf4KOcbEH;w2@(TmvONUhVf31%wEeH^HTKif`Wo|`n)tlNdm#bo6 zQ9)fjAE(g&0)1X|&%G~jzv7YUaK?Q<9KWk)LO00Vg%079jXN}Q84>voi{jqUEU^>D z>L;e%Xurps1|yI)!U_~14vd2GId6T34GHzwaxf0t9<|xdu=R5FGs$NbBFA8Z>ha41 z^Y;MRZDZezh~}vvAb6~ejJJr9x0;%B(@(vr>h2iA`Ch?&)Al>yb}J&{yK|9H&PCF=>4i8l%1`*gZc(jD zAAuH39{+c_?r)>pZU!Re^!|m|j7mk@bu;6cBq)@}`6c2!5}3o-o(fXJf1!=6tdIozpMsktcRA$-DhnS=oRg zFMFpPTvwPr|0Ry)tNjOybk7#tv6PJ6ewKw3dA!a`c0VCHQjrgKc1}(PRG}ij_q>Dp zd##4`ZGM!aU|%jS!ffd1&TyzJH^p9H_j1{Nr zU9PpMd~1hi{N*8k?FSE4Uv+XuK*TBqa}IPWdflk9gM`CYJJa@x44c=jZ^Xrcu|uZ- z^UV}-TA!RMtv66ld36N7@rHc$Yq4V__+1DG4ExYs+(>qM)?BZ9VKtnknnCtLIRosw zE!Q`HydIYuGZK9WII-EdREk>B-6lFiu)n3(Y>1a-S4Lvm6)4pFEW@^QCNW(w+Qr;t z#C3T!55j&|y|!ZI<7cA2w107KRh&hA(Ez9^r5fhXonAv8|B|;Uw_d2{dT7B%fuEhP zZ8+4fchh~s2z?m+^4PoBmzt+(W{TFHGI+ShK71q93JkZE>Nu?=mY}g2E65-wL*L<( zT+(nzFc}d%N-&#v(s~b-pfErRt*h@F#o}z}_CFRNbU*zrsY)2iuhT_dLxE;NST5Zg zfeO>EY zOux7>Q;Suc#|xu?c;l{~uG;gq>2*N3#S4wSN@474;G8N2yrS|};Mb)?$CdPDca%92T1_?#1T@~Z6scX@QgqVa4hitZ<>*XNC6h=UGo$j~ zo?BXRiQ4c>k99~vtClis)~pf}<%v+{HAbfYxT`^6ZJc z0Us#l8wTW>li(PPkEE7SGS;@rlU_WLD&R_z zJC@G*ech=}+vz$hLDk>X2B!RiGJ{QBX)Zt2d2tNVC)k>bL1Hp46Vn@52Q&I{=J(EI z^^&(!)W~n1ueHZMVJ1Jhk;f%J%sa9l<&F?0)b%SbjokTZ1JzA;u3}v}#?pn*vrXt} zmA^ojDS-Oh4y)%#1gQ`83q6z$pLh$5v`-7Gz>Dn`tw4iG)0SdVE|nGYCL()u{bi9f zZLDAQ9Z+k0>^vYk)`L3|jZIEn^{X1Db8j{ysN`_KL;lrWf{O(~u^{U-#s&tO8_2m+ z<7(aA4^UUvpl+I`@ArAzW%I?xudgqAqyoep*|n*uwT40T1vRwfVBxoB;nRi-e#yia zIL)Ww2*f?`;9)^53Hd!4s6PCV>IfsUN{yV7T0UBPJjujnkwdcA1mMf%&a6-YYK@-dzWrk zB>Vxagd@35CsXd;8r;{d*v*SFS{g|PvY4V9D5@%^Is1NfQi+C3uI&o%BUm{GM)!+{ zgN55Q_y~fXlCOSOyn`@*P^8`r?07F7?8=ox`$gUapf6awolKyU>;#-sZYu|{pppY@ zcQ%RYp0#hSHl2-CY@W2x2~p3;vm9vCe_}w83HP(Z&(dD~ zB{N)k-%Z-CIy~_}e0CSd#ci74v`cMr&^utsK0|()Ka+lq^J~7%p}K(}WnyjuPghTo z#W7TJI48X$cfxpU^`k+RAV>8(pIfKI^68RwTV_nu$=HxEK=C+fQ?imAt9;0Er3WjC zluxa6)?#cJzl@Ia5Z#+%7N$Xlf8Ief%2k(fL%-QX(^Jc6ZElk{8P)#I*0+(d-;wm$ zf_iI~(CxT9nm&Rt_7+fV_sE@7-t1V7%x~C)3SpH=ILDyY{|d=2s!OJB`G?u{^)ND! zFQ`>g8$1}I`Snw{w9s|Jl+8~+iGdvvtjkyuLvTQ(`U2WM`n1%<;agXqEGf-h0lJDa6H&4r=lY%&Y^_Np@3M% zVMtJtXA2y1As*`^+uNGWkwMJV{l=Mtyds{4&uCLa-Wm3h91zM#zzD5!^n|0N<75UF zKu{pT@oWJi5Z?3D0Uyi+1V;NaEAF+wEzBFX5rBoI3nRoJ(ot?xDfM?sLhWe>-;PhT`9nVmO+G6|Nc^28Dhsl;y)lDftT$6W~3WLDeTCkcz#I_bMTvY z;KYyJM9zc%1r!N(94rU=&opIBMp|N-c9v#*Zj#EB;UjT>_p`Z3hVo$PT*eC+d-IdH z8vqv%L7*4WJ)0+9P73%B%FyjMN}RkpC>x>|vRWOTGRl>R@L7ikS>4ertH-*gWN)X{ zFkYB}FH^MQ+y^09=nMzJF6LCcy%t45Phd1es>fKXWXw?8xZ+{CG+|8TBqoQ{o8-I@X^Ev@M&-4UJh|G*Ja_U@Wk#&eJ%+k1bm=!W=M_h3l%%cWHCN1Y z?3!v?qF~=so2RBA@a4O~^UFh5d@b~e&XI*u4W(1z>;Os-H~8=<;>{TLT7v0jc-G~< zmcIyN>aU8d5AjLZ<3&-rZTgl{NSofQF96D<5myoTe@-TxUW#TyT6#i)c7W!lu|3w|fq6a&TqfsYW<-KFBVnFS z_`|gdgt4#P=oGln(?nddFt!rH-c@v?IBCE(d-v=ZWewYZH21wq2_`y6=1w_Fpu5SEq` zCg+(eEp2t~xGwoaVsx>7pNxUDy3LEFB(IAa_+2n741q4T9c&ireJaHiSc8#>K6c5I zVM694Op7a;OLZu@nUySYrSv(mM|bY`bO{9nS<$7JvnGREiDEmzd{o=vClDhvYUfE) z@$>Clg;(2O%XYE}asb7)2y>QLk2FW^_@io11JGR=tLY1G%hUIdiN?^{XLC6zCybFz zzQgpxxa(H~kn~oy~2~=JmcPg|iSr@Bu$p zdB*A4Jy;(c1jdbWg}GeZRpHYSpiy8+r3%v_(MhJQ3(0^QmMbel56=5t1=*w*8pk$; zP-1SLeoLf!BGqwt{<_<=Hly{|GkWc5ocS}5U}E>|%RR3lW&`{x6$M}4abZjeUtG}9 z!l@w~+>nE%!YSs51fY2UtqY1PSLm3(;~4*z*^c|Zt9UPU^ z0BJu|-A?>}sy;zRZjb>c^!6LIG|fd&25xH&&_Q6c7_!+xAY3T5qlWxcNMgf6@XJjR zc4!FDA?lm=@9vu708bOwzyj%7o2h;;}lPV^faMB~Z279Fh@Dac~$8HaY^9 zbR@f=a4;_^zFi3pFRwNUANqkabm^t%`L&hr%(9T*aw+j#+9RbKy^cdaAbb19g6s7#{c#2OhA}h0c z?@6m~5b^eEv^LFusj=Z-$H=*^LtsZMupSi(k_N>hkcz@GPo)Djf1qh95Kk53U=958 zic7984?mX}=q_`+m5uYxnN3Hft^bT1PI9{xDJnwLx(WIOW_*CCVIu|BIZ(K~IzL>_5FzmZurj}mfVZA%j+a5QMz__uB1)@$h9k6J z2rq^J1Sdn>Mam+be(uZWUsKc)C?T?Cw|2jw_)3K=T{OwVJjRd%Lz%W7Uq-Fql?7!us++8FzT7{Xtlw^@){pf-gh#=K3R*DI zrHhxp5pX$~XhfVqqe#+O=gE!NLZ9U0K5$1*p#X=a&mFK&@IN;$9~Vhc*F(Ws`wfdM zTd=Q3aX*wrKs!yV{%Y5K9dIU`Q@u8H&z)Td*K^jxWal^dl(pErBgsGG*C(UB?EDx5 zcY17n=QCz0kSGB9@12g2gNcL0C2g?VXeB)q_UO(Yo*sKg$sPRAP0t(?fcYD^@O;q! zr0ty4KMW#0J4r8Tvi9X=x#x3JHc$B64;yzgtIp=L-^vz>pb|kz$#3%R5y9aJiU|sn zwmA6SYj#R~1mcwHq$a_eVj`UY06@HepV|QEo~^VbCoM5fGd?vdH8oE?MzIG3z}yXb zQE%v;U8Afcx5HCuyyC^9FL)dn%m*axXR+DsBS^}Gz_je*>-ZF6F<|cOTZ*!x& zT@V#>Rv+9Su?i)>iORbsAloHNdszs`6Ml0?=KPfGz$OA3VulPw!59MnAt6Tt#7fZn z?Rke+{a^Mj(-2~XDz6Wgji>da#IY>x-#292 zG+vbb9_v4hb~+JDf{$aR#a2quR&wj3=lF6#ZFWbw(sSOrbe*gG&4FSIl_L(SIQrA! zmyLf-~}kvsjR9|jJS>E+Zp9MK6f5kk^j2pX>l5XPP43R&z=3Or1%p1+k{ zLoa}}53NN&uJl1T%-CFaucfS{R>ozM$Y#*uv0%;2>Xu5lt-?%=V)wh9yP2ugQMQZ^ z9avPChG4~lQZ!|+2ezkp!4jz2*kxc4^_9Ejk)pRB;GRdtltlp%U8eCm z{Q%!UfUjj6>1IJ+^@tFtWH&S1Rs-M~lhjehT;;Fq4i#26YM77aI#v`XkD_lI687MvXIZWIISxl#?c5lzXT617XGoS(`1h zlBqd0i*h?{m0(=z3rTv2AN>g3`@7XzPybKYCdw!UF(8D_-ce)Bm_jef@`-kP-JNKV zlUjAckzgX#Z^Z4|BK7@6FGCm4^?B8CP4mGiNnA~@Oq~VSJo%2AC|JfB6+D(#9XeL_J%h5 z+vR+?Ajvg##99@V&CdDZs$eUApx3!Gw3+iD;>b=?Msz79spIwa)b`XQhxgzM9u&bJ zV+-6^+?2E#xB%-r2RBH!^8j;W@U%Fwwt%5ZNf-JCK$vc9hh=4Hbj z*>L#tuTjby(gaiwj|+^8Qc*}!jE|2PJ+FVEG$=CHl(lf9R@3kLXFYT8eZo0syQUJS zhO(y&!v$~crF3D@@ILEc6h39I?Yi$2FQ#$B2lAH=z7`6N^GjMcNwCA&j zPwlewVeElCd+@7IAb=_uZq#7?k zLSlTOxg1%m<>>@bdB4To#0PMBnEmR0;RPO@rt`26!~qe z6g5N5?iVT|UfLkII~O6aXOR!OyEF3rMf0}jQ$Rwn?M4h18X;LrR`kV1AneF=)jmLa zsRgB^0a4~$)@mJU1{tVKfUb9uT>V5buNjCpS0o&$j~T6GbBnVNLJMMGuv-bYci3Y$8Ezb#Ii`WC;I=06&c#SX4WsJ-0y*H7p)iUDe?1lGSG+oG<65OZO7tE&9Z?I5)E+-k8&f$ENh?av-ZmFJ zSto{}rX|bS%zP+rnOn9vG6<2n+8TB2e0jf~R(yOeWG#OR=QOgKPZ;OAp(}*;6{<{fm9Bdxa zW{C5fn04?p>NY6qk1=FfrO5oAWsq|4%STXEcyiXawe&@+Sb@mTyW)@3v*I_P5)~)j z|1GlrUWX!0v$}p(nbr4SAkqrb%*djr%j$4-{7yP`gJ7gByG}>+uJrCY+ zyyE3~)p_yGBu+JAL3{N%M3O-Nla{U6y#sv( z;*%6?*=MHT_lGvE5(aQsFrT`MKw!eM3L(P`<)p8epB7BB4oy*RL>2&{;a6^m824Yc2Y9W;V8c36iK5Qo$DJkXbYEW3&7S>L#aJ?mZv z+2tAjMg_GJ#v1XYKtysNaE`rFe!5t$jnIN2QouLaw7kE8Wz6+*F$sbrR3be-9W-9l ze7o0{*!x;gMt2$P8My@Jtz@BsdF^Grv^FYPgrs(vQh~D{rkI2VO;m94PBP74XOnR{ zXvlXhb!p107%5L_AU9c_^J-r@W+;CT_NnD96gVWes_IhRM(smZF13u@uUeMor>KKyt(LRp+mxeB zCzI8VaW?CaoTZ`kIQwM!%3~P!6pfgpf`k*cecMTOhVlfbw~MNmn|a00oQ7BV;X*{= z-m-mzEpT(Y5`6@jB~qj|M}wxI`784_v!eJZ(s12%cFPW>(psJwXF1^Zdh81v zr>4`5TU2`bdY??CRS|sNS%XVvwJpeWqF2aEebw0H8whJU^}7K1f8`)SJ2qY?O$$X; zJ0-R9UsAZbGyP6&k=R#@z0oAIa=sYNX>WiFMHtQ5ScoWE>X}>GhS-=$Ny%Hd z8z@i>cN!0W>(C#s-%xs;B5tZnbF$UCN@fLJK+4ckOvr$jRme_G7=q8Q=hEil&9$5N zFC&@Ai|Mhoe=49G*x6f((+!A<(m0&U}`8_-^4u^uhrE zo|OCr+w=cHfEINHyG>RE-`6^J6wo7-zsoIac-bw(sm5Aig_MaX!||Y0v^mDCNEM06 zO09Q(ySSw5i8Ux|D<{KCxbOF!hxa$>d3wo{j?9XM{92J1`zVvzb@MoJqWeXN+<{dk z&G8dB0lrcOIA5uCRu}h+ zQzwFh8EF_|Tow|bJv#{jp|JujZYp@*u1AUk$MdVod8 z(i7+NW#E<90)HJvL)g|@Eius1_#wP8Cy=!TpwknewhyBP|H5=kP`tIOkK*YwVYx5_ zE{G9%_$@ljVE2>PVABt^Z(;VvQ$5}NuHLQvG71EK!H>Yzi2mP|cHVWz4mH zq|A6fX|d)2JugV&z zqS2bg*M^Tj^B!*AxJd_xV@BA*$=spg$J>3|(|@inM6i=lU5h?9gu2>9FeEs~;@J6w zp51=Vh=&;pj9bomxfPpUzdr2ZWhIeu3Z!`xa|&;?#bCjTfl8N2${}md`!l`=J~30l zmYSDlJ6=L67cdI-RP>UR@DN`>v*j>q67n4?E6bj0$}issJR|T8d!!JU%#Iwb*QHD) zrGC&P)pE@Y8-8XW6m5$s$+iMzx!lwIc^1IjyV3Md#F)P5#g%6H??X|Qd;jp z#atQhq|b7^dq#R84ns8{Uz zXUU!2-)vR@gLp+DfNap=ub))~o(XtbK=3stu8gO@QtqCD50Z7V;HFGjLl&8I-ZmBSc6}b zx?{&oNyl?q0bVmRMWuq;4E^W%{ozR}srjLUd|DA@c6hoZGmEK+%15M59s!FvNvk(( zc73Z%L9W+%S8lgj^92<$xlzXxn2#Jvit;BbHrRbhkz)0cvz$P~IzP|L*wgZGsZ<80 zOfL(z=-SpOPiZ%d8j5Ki*6uus-f`YZijFV-2cG9-Pw}SNE#dE9>GIDfSVcNz)%m4T zL&YY^7$kd7O-Ng`3iN`%i(-AbJl7K*$MZccGM{&YsoF#>7bU0Oe2X=vvKD)r;Iq8m zlTUALM1bBT|IKZCd{n?;EOR1c-c=^fZ}A^ne#Dif2Gk>d2Gt!pnJ* zcuIH?W^1^0xcTK+em}h{Duxw|FiT#X;jp2HFeMmW_3BlojF~({jelKUT`5KP#L7=! z@j_9^*FhjB`!&vIVVgE-EI!zA%4irda+k|^@4frWIX@4!%s@T&!qJ5P^n$s*=j--Z z0cP5tvbps3S}=*ot=JS}D&#J>#aVBPIzjRfwv-rjT%a&!eEfH;&& z@CHv6xrf)^pUICOT7(=UKrG&YP-(jv6A-~NU3#(7O(E2s@vKR^SUFs*`1wfP_}O7y z!a6-uGtC$mIHza`YPS|S$kS`$?gF}L$;$eq^dNofdINmva0&e%aE73gaFLLaqM4?I zq>!YQrJb*mo|-mj!<_XwjlO}7{ma_QlomUZh6CC30|U@BielZw`wurO^~WwUAatKn zht{YD0N?YlL5NiH8@5~rU^`|@7+$Q+Pq~*sy}4zJb~+Yx6VRo8pLCzzH+2VWGlL_U zvuFX6z3spyG_UPJd(k=Q0Ca`m^N$fG_G3+4uL{Wo?oJ_cQ3og|K`$Q~RN+xz82|Mx zm-Tcc{rVu!y4G~B!~6}K4T=hS{xVdt-qTst$;JNQCm)g znG9!$oN7_5=v#JzRynAerYgidWqNsie)hL0Wl1=Jldp*veAZ$}zY@&iJMUNUThOM1U zRc&q}11`Lc&wfrfpfQf4AP!-V#?<|xaZ=4rSc}g&2D14bpmX7srA2bhqdhHV?I8W+ z+n2Jj^u3#$UV`&#*JQBZ@6aUTie44jU36LdasI3>NV{i_J7Z!fah>8|!m83?vRoi* z>0{egJR#I7r5TW++egV|=$?_#8}j}^pNx|0t$TxAXeUHyM|aPTneB!fAV2}#%PG^p zG+gYjc{clFD;xV4m^MvPF+kha%G;}L(*)b-+hX z9QIDZD$NXd0My}K3Vlc+Ri`s{-HTB_W?P@ira5tNx_i?ISYRBPu?B>P8-TUisS-6P&LHS#6M(we? z@$1iiaE+}(PP%9CDPVgIPNBNygs$H|NOPNJ2b@|+I$QdmgkNoRn45}+4dDr z^?D0m2Mbsp0Mk|g^*;@#_=&);y`#dZKqRnG9GCC+R`{i(I)|(w?#D|KkGKt8Az)x8 zWaN;eude1P=kAH2Eu7Ge_pO_Wxb6cUa=*Ine1c0(nHxDEWeo>Q2?GUNwC-=N!lt$TDTH z=CK3qm!%^taeN@i;kI$gfD!)AYkvz&E`e6B858qKyqDL*94G*ZV@x&i2RpgxoYPt0 zfl`d^UMao%nPiA&>Eh08a04SAZnq;{DwzQOozJY|$8WjdUs2}Dx1v~xF4aU>bogHY-2JzA}eSw-CSIIm2WS7eJF~6dx z6rCr=OA{Ibo2ubA;a7-${#vhyR@R<1Id^+0|9x*n@#@9b&Ksi(d6_;sC?uA1PZL=o0tV}+i#pMjCo-=>I zJBUDFJtjR~%M>^~E?m|dLLWbaxQ|9OctoU;PO-k1>q7iXjFo zP0?%Nyppd%T=TvB*LNs`pA!aU8DbCapzuQ81<43to5D;`xP2jrkf} z&o$=9Yqn7P5qv`&M|M-t4gc=w)EtkHhV;-lahy(x5EJf6Qj1Ll5JtpWmN#3rJ%iy|rT84w zu8#DtYghZdbX3E<$|fIq(^n2`|6T?s)5ZV49){!r00$^gy&L%;4mN#=XnPY^byti<4%{KQQjy6Jx}2$k+4Uq%S5-PmC03fFhGOl6P*v1v zWFF!d>%Xvxx*ZSc8i@Hhoh~M#orVqbZPE3T^G&Z6d1apP^!>Pvu(2wOSfV}Pq=@hw$=09<=2 zKbIs6*g8Z@VjXZC-R)x>I5U{Up=Ka6i0WV2g#fpn$BAe7uy%i1=Y4~{`oq)~|BqpT z{x&WZ7EUEE8HVCosUWX8TD9Tvy;gKKi>*7aR%A>AoWjEmSO2eRQPk4J(o0O!j!Do+ z{8vA4>{BVt%DY?p-X+miFI>%GJC+pG3DB?@akcYbMaKTiXec88GMa?I`JO6hSh<#h zIBqaagGUX#CDMXg{qN2j=+6C?*PiX)do)a^xdL!<5ho5@wZc6@hcJRD7Ne8t=*kua z!T=6rIPs=+K8UaI{?(ODyqmpqEtM1(*(6eHcy@ndZn0?bdS`aUflJ|a7aS7DtTY-tC>l=u}hKLDn=dc;B-U(MsI6k5bdd4D<|CbL_iOQj?z9$OEZW6v) z9OqcQ{P{k!A*A>_7+4tT8R-~f%pF6^)kz9ZN12GI3H zwPEd2SIlJ^oY@Km3Ty{#>NxEcW1lO*g*uCt)<4%OF~GkU0De3wym)UM_u-^B`!en1 zk=E{9s=X-FE?ywb{F}%l*UkFN#i_|%jF;H4wVDBG(IDjsCXyhLEG%LltZwvWd*LR~ z(;x$#;T?5i^eS5r3zBQAs*KRQvW8w8lGw0x8_MX*Oms|lI(YzZN~;N0u~MVzwbaAf z?@BqYq^cs6%nd?$Qxw3`f2fMzelxeTbHKP~zB07Se%v;7rWg}q!u|a2c7%+t{sW-A zx(HBgVPx#eTfzPtxiIbBT}=G|e9c`7(E#I~E%o0m_of3y`7x;}nHEKP_z0LgHdXs^ z8am1eX)4}9ia^S<{yG?pG28luk-tTdrV+UGV%Le|GAg2 zdp~!Ke)%^ ztDAbXdUUT-u;YwC8)km&-ys;rGA*AtuaeRD@B%LB;wOR1(zfYI+EElh*X^_Edqki! z@6et|+WDF`^cj|yz{rIy>Ks3{OD#7_Xx^G71f{V?VnA7hD#{dw77j#A!7L9rcP~%A zIOPsVMSln-;~*!>9>1)YASQE}8R*}ako(p0X&0xO^r0lnI;%0}Y8?MVJwBhAn4G!n zOsoE))o^tic-*8)ljowZ@%nYc#ABX(ZM2`kJm~zl!A!Qwu;XaNG)TE-bFF&kaw9_` z{s220X`uyj;{FHO9tW=h7{V~LbHhWwAU*qH-_N11L#sV$hh`azN+nG1d}i^~WkV2< zC2G2I+}f7Tf^t>H(98AiYF=`plF#mDGBxpoLL?oW%B%UH5zB!s?r-YB2SCy&api=e zIo8j~iAdI;yT^$yI}d)3gi3B=qfB9CsQc9l{cmNpl2`wr7lhI-A4D`L+5)wWvtt^} zq6)O`#!L~@;xHI@_H;$g^OWAKN8@ujc^I?|!^=OjnUBNDpheWA^Q2hblgqEk(e7oQ1=7B7{nS<+;mKl=%++mqXQG|fbLlE>dOmXD-!6JLoIeS*soExbQ=S>$OXPx}M*d~pSpbR;QSixS9ySUUcsd`F#xxf)_YLuuq!mii)FdQ*b3&WdfhhTY!bC zMDk-rR6Ee7K9;h0z|%ZdO3$EUyLeAH#&UNz=qlLyh z&%`doOE$Q-ko`p=fNY)M1EEhOl53GLR5K<-^>n9(`JC--D)z7W_U=(Oa?vrXCmn)^N1`urG(fo!B}Q(C>9}ktE&_ zp^b=#4O5W;`=ts39vPzR?Wr69J-O|ziE;&AK;DGm3>_fZ%p6Me?pzG-SQHl+$tbTXRRjI3+ zYr|+PS9&$cNGo6=4pGMqsdo7z$ILIj9=me)OU=4sn`DaLa2i3+dhf(fL|I z^GdzE8SC7Ppp}eu`UR29(uzUOwUM!o5gGB9kBg5F?cVNmQ!8_6Hn}+9LK)wB*CPtdG9P`vrETJy6u-9x z#k{sYO5>3>DUATnOJ^RtPUm-#WA5%|=a8Ch23r!*YjY}~VJu-vmcl*I&cG9wT$e$c zWx@vXtc~k0Mjh6=HEKilv{e1J2M)QR*Kt*K_A_@XhI-;R0%ATTTETRO$mI#MQg87_ z!c}cA2w5*lq|2(#$fLR4TvN(w&FBG&?PAMG$F*}_fcfTiuvw2wTFPB$;3G$UB?~BG z3k{R$nk$_E63xztsTy+W9IKVagGH@P6kkbG7AJ^us8+;ni-mD+C_V2QH(u26(s zZrk_DKL;Lq4!l}%C$iZis&+0-1=smU13{D1Z&onyyv1uf4N=$AqzcHJS%Hb#?sjbZ z-Az`wf>_K4T{qDTrZpCIcx0=AfoV|L%$w1VO53-X`RbK_^jSg(3PIlAls{m`>S*NG zFeo`#UO@Jp6A|>J-T%tbnI|)r>vTb#alkxiw!UK8(FcKyqO8JlpNsBu;PKW1JY4(K1%koD|%&#UKi3MoNg7^l2 zkQ{#=AqOLJtDHR)wg506@RL==IlESeibKA{-ea6gaN?o2XbW-9SYosc9)2^YA#<7y zfjiGYli-RxOOr-Iq84O4m6P$aQ(40J9|+IOnoJ`l4tvb?C@&oV_y*dYXqIWXlxGlOQn{P$(t%uOMPR2=?MeY6aGil|&f4C<{>% zRv%N=-nf>FLs+k{ADhW^G+ZBWh<%bjS^{sbAnqqaW0|_dN}FkFp@y4cs#ZF^ zT;otCc?}3I^DtY8pN);8nMM>KLiA99ZHkZx^`kRZYy39A`P!gv>@dRcB{PH3@2%my zfDyu2%-E1`YxZkol~Ka>JpzKyV}7b?oX@!*)HteApm>qb1jp1EIRyHlXo-`&mYGU( zWtFIK_cN>C$`Kyi+-MK~jZD;JQ+D2;B%IWoM>unM(6MQoUddQlXh&PsqB((`_rI5K z@1lwI37W&49tn#6ZV!3nC{pA|xn57hoOekuLA}Z;b&YZs=S{=xTz53&Cx)o0ypejC z!gg#MP9VKGqFf*VXdamZGORSmtka&kM6bZh<&>Le8R}YCH*e*ZcR#U!Zu#uGF4sOT z&>Av_4MEtf{)?w}x;WTl(^pvxBGD(3I!T+YA#_@6)rQN$QXNFTR!3yly^|DxH%9P; zX0BmY3rnF1oqyOk&AM-)^|}qlwdu;Xg#oqM9QDLA#fH2-u)~tYxU$gMgk87X(}~$I z+emJ!`vm88Xqw^jcg5@Iq}{Do%{Jo&?qzBk!ghnJHGa+%e%tcFVbOFvDcAM@_EyGc z?hSHwq9k_~fh5cKhDm*8tPQ4kTWqd6;aZV@n$!KIPI9)6wdKWcb$AI2+L>*~m9L@Y z{FK+wItJ$SzIA(KgO$?b4_xbFx)$-_vinwQL+g1N)+5?z_{VswLzRBb{G5$W$Cl?p zo4`d+YO&4q=BJhx?~N9AVT{$}DEO$Y%{x;aEgxSqtY$|Ix!&1>^Y=#MN^0e_*zS5D+qP?xOUK5x zEAnQ;iVa&kwwEvarc6hSlHSq^vR9GOBV*{dV)Ukuq13=NuS2KYjmhhH5Zv>%{cFVY z-3kh!wSgClC`26mC%sPa9g`RY{=!XC*~%Mj>$kB263abLlTIO7*K6^Y+5pmOFa17k z){ffA$%wI1^3+GLr}EkqtXai#gsJ@avjo=5kuoK#ia8+WrhFnQ#${>ecVhV=uumvbUtsSL`Brfp*~=)B!Y2ukIroF`|KGUe~a-@Hvu2bFe@` zJpY`QkULNh>#-H4)ixsT+#eOR62{l@PDPMEb6tIRG~7Y=H_=xw5xtiL5zz@&kJWn# zqL-*qqO&2(_m*?se`n6QbI;73&pr3v`P}I{ zq3}Md8jg@t(28NG*o7?G^EC+H2Nl-O2XW<%p%g|GTlWe383XweJ;L>|$2rl8@ih@5 zU(_AbGNHpc9k?t+Ge;5PHkrt%x?ZLiIBvm@T5jG|tZA^JrT6*8A=zm#-UUduI@9vo zNVk_;5&%k#&_isZ)-y*eU*-Rw}kDin4 z7TDmCayUO-EUK&HVg0usUDW>0ZJ44j)_g`jJpDiv*AhkE%Nb{GHRct%YV)~;_4RL5 zx6$d`*>VoOc|UzkpkHr;`4}ly)W$M=7e(IZbJ+|!oSRYqT>54u=`VfNIwcu+W3io> zt+&B)i5#=QNftL@ZWwDVc3QwW(q%s8@sw&YPH|-Ty zjZJ2$eX%1EWgW1LgY#|{Y2J+Ys+$+N-ixR+B{7Q?YlWVWdjIEaex>l1O*Kduwx!P7 z=9X|p>FK9-3H#$YYENt8>>_(+>2{s>jT=c*ylq#Q0@&W*9jb>WEg`GD|y z@ALYExLobRQwUp*`A)mDDCD0vJ6Wns?9UF_0XY~#AVsot(nK0!b_{F&(rNWThz8x! zUw{?1s)iR@60j!35RRARgWHAOS_S2nT8BmI$m>?qt^Ii^9vt|bvnzLO_Q->9{92G3 zJ-|+K_WnsgX@s5gM`}{09T~p~;qZL@=(X+i61}_W^+vW-Y4iE-pzk`P>@*DT$!((-!@O3EO2pXcyHq|l9RE-ej`H*Le@ zX$k4Gn3ada-lgS@Q_$Mvqey%BI$o>XWogfZ^_&@F1=h7yj&n-xxMEZ!cieYf!+U-* zR9Ny1Cb7nRf31{6WdrFJafVt9k}k)%v=in(Vr&yPIrRy0%CzaDdPRI`>qJi^LpMln z{f22IF~U~j!2BhM*txbU!uEv)L?=s#od`ujD*5yHd1PeF(R+L{C!DV@lYTq04A%#k z#P~eJ_G)2v)R84%c`C9cL>RAiqv-rrx0E^YBEY50sPWx z!Md<3MHeD!v)2Vh@XN)_&l-Qs;%v`G_Hgch80>~sr3GE<6&~}NTx)yg>AI{leTfma zqwn3bW3$_)xfqm+b}FY?ojMhb@xThaMyc)QZPYjX_?)vos(fLbBjU45L~|kF+}A-i zck*rBAvD$URS(z->6o``$kA$UGq0z&Ebkz4@kYAOH%ib@@^+h=bYuKfIh}ec5XAOy z6GtxTN%D`8bO&sW#LTWKx6nJtqbY^5+>4KptQ^wvYH>S z=7l~5Q8pg`B3z9>0ar%O`i{VcfW460i(DzEwY$)wKR4aSfooSMlU%`NZaK5(hxN5x zyn+uThV-=alR-IR=)U1MZ4ABss5RdpaeeQjUQvmKEoxN8bLwC^MzU8gz7adXcfhxt z3p`RtKf#j7U)}b8Da-GaDj+po9`8&a4FseVG&>bVI@zyk-wMcZzO9>0@TVkc;pcW| zK{UmwGb6^911v?t4Pys4F$ZVy@%ff{WXtNvI*X zM)HT2^tW5x8mEh>wPZ(sn}g1P5gs2}?#^-EEv@+xje_(v=TcSug|(QFpeIr;q41_3 z#5b3lK0KA~!{?@!Mm6~aN9${~VdVk+pV5!FqhAN8f@NU9WOZimjY!!%0UxWeM&kMs z&Hms@-DT&kc|NTe)R*T2HH#&a*f&^9a(89EbMbW0s(e;K4G`tz#=s(KF$l@2WUQJ~}dv zBwuf2r0V#+@>R5t3q{T6O(99m$nwIZM8fp@^j1kguE6B)&9=~ars?K2ubUEtf%{m! zAl@@?85G)Q|C+C>D52_dBzA>q&G6%3LAUECf=twXlA~LDM@F5dKxY0MpG`&AP}`u% zPL>5U6DKKY%0?h5H*iGbztj?DYfPhWgT;lvziz^bZ2)x5WW1)bWUa6 zNnyqAm^FAf?BABBm~i8|!QM33dy_cF?4^%4FJ535G720rumlo}sSRXLICKwiGy~tI zj<`DdOQSaxZT0(cB7((k8vdN!s#Yfdtm`)Y{LSX!4feC}cY)R$57z`WGS30$UmC`D zzB8F$-`>fYv_psjoy5(fkb0E&!H@|&rpdFQGVw109CEQ7nOn`58Aan!TDzYn4NGj| zO-w3^aztic&lEbZb2_*~LVtAe&_3l-_`A{Q#(V@jHPBW#+k3zC z=$~Oaj{eWSan@r_@8 zf`jUwEsD}fDwD^DFzbn^a<@oGsM-Z+S@oygE#X|hSbG>u)bSPe%f-)mIhNg|72nV= z{=O{DB7JzUN-X6Tb*QMnnZLn9%RhhA=5fb$HJD59A0~CtKK#b5`N>|>4<(fqO`jj^ zdlls`&v?f3-3q@gCdu_N=eW_)ojRh5os1stv%GXLGLLr)`Br&6B47fZo3WSQTO_LT zEr8Tau(<)~)~e_zH>+9~5X7yG0RQD`BigIuFx67~>w$n@r;OfV-7S~fsFv}k@hi$R zbOcI9;x681P_C&oX)KF8h(XFf@(sSE@B2#krJ8-6c6~=Fq%`vD^7F6Kx0b%rzw?C8 zeMim<_D3g!YWX`txWKl;lTY>Rgd{l4LxZ4qMxi*Ys$CXgS35lmkr0nJL(S$jnA3wk zy0EOQsD*QE4aAt|&duqs{qe^{-DDzKXMMB@q5*aESXg0ro_HFW7(G zck#fYj=5Cl`xg1kq3Ad*x_#iH{?ye^SZpiW1X{~-VLndXG<-7psJt}NCU?3~;j_QD zF~RHB^Tq=ygg?!{jU+>60>svmug~c0PxkO8!^<9jGO~Qi%&r<~Uerh;M&Yw1|K)tf z3%%qw94xPbqQ%5#1sELZPCm_A!7GEwgv)Q+Kuvk)*KidbO%2tdmw3FiDu~J1J^$ue z_-K^KOINpJim;vHx6zP1-bxtw6Q!G|q(`IgRU5cHw(B236z#xM{*H5xr?Z}BPG0M0 zaZS+9=2N>0`}3kIxImouWyRvZ_OgF2L+>9hRl`CyJ*#zQl1nN=-0CU?E46+sv}AG- z1RxK+#xfIVoG0>7YaDvtF?e0k>d2Y3hzEx$xHpY`uT!tX{<0#DcPZgJ4f_^5GvPlz zAok@REKVLOM&uUEsu~s%2LYI;(2S@L%82Xo@WM8~fAMV{NC5=X;&aOPf!t4{{vNwSLiRYV)DWP*Mmo!dnmkC#GTIilii z*4Dl^%-JE3W!|KflT^mlZnR}|^iy?vV7U^~y%L?nV^U2oxD!lpY(8WDz_0_}dw#h2 zRqXZNjDLpQaI5eVKjhc?NVP@U^zVak*5`%CkF=tl5Ygpz1$M$SJY2hE7Zd?U4Q0ur zSC4XyD4w9;k!BHpdw%}H^pgm3 zVi~slkWou76U-u)O40epvfjLExsO{LRecvYWZ5~%;2wO(u~S|6!U2VJRjIpa+o8Tx z(QJ9bpAabb;-Xis?HQUX)QNdp`dzc5uf=ZHf(@Q5Gtr8qc~)+8sX1|2gMrc|1UUvl9%s^~E{;l0BZY}CEA z-y9g(Pu+e{xD;CU1bp(U&?VLq1_|Y1aBEwtW&OmmeoF(z6upd+_C@Wk^>Oz%RZj}G zUc|4jp6_rAx*x}$&afTk&bU=MfGZnFh)Z{zg6hN$K7$gzvp*ZTT&gH|boxpQW6#GA zgQ`8~?5qzit9A56=Ja*+qE^T47(8W(m3~FE`h352 z>(E-Cze?H~aD7B)Vr=L?#;kY4ac9={Nd4QLS5$8Uq*{!9CD3wu+km{!C2DURb87ru zFO9rv*uHiYG*Vn&h)HX^J5DbkjO&2EY27CI*}ax0YYro<9X?p>+=C zNg*+&N1MKcQv+9bP3=U%BDBwu{M+;${*L82PgmWge>o7#`VG9j!#VCV!GE^|1k4J# zaDThLOzc@8N@bkW7D&qf;vc~84boeMdwMx2$HDjHN)N>~T|Gwk6z=)z0kHMqh`K3K(a<2%MsrV0Y?(w-?cg9#6wyK|$vW&PZSJF|}nn z!W$ZTqis?(!q1)i#}+A7@3y**=g-OD9;-(-MczQ#_D^IsOuWPLPvU*sQ+Ow){xz^Iu3kUOD7s{c>-p}W6u0IX_V%Z%wE%0mix<>Omf{*_b z;j3@I0!$Qp);99;1D1^zBBCvSlt&*ITG9wC>stRsHba!AR`WJd!H?oKux0g8KVO`; z$&3WHnEg4b%37gF>U4Cd3(?WIHr|&TKMNMg7$}MTkDA={dKJZm?7VdX}mfd|3VC%Y7(~?A9V;b z_Q-54O)X@#GWkfnbO7$u-Pfn#R&VqW=-N$FDp=m4|EzjmC<^7OUmz@F{rYE9+kR!R z>9LgXx1e*rjy`VZ;2&x#1?#rk*g|+)jU;aZGD{@R^-xR!;pK;0e-PkDw#adYT(QqKny*l|{HD&Ph)m?g({-w7(vl zM&l%?w;o;*pZUq2cnI;+&#N1*5aSZ>t>~k-Vt(Myp$o?LP{GcM750PYDr%wS83dfP)BXc@0ae5 z`A$p6UQqeU$ucYTRKaF&oBdNEukPs#yRYib&-d5C-m?wgS&tsx9sOYFPsd5|;3@zg z6NV{1gH4{{J-a0T{qgOeppTB8KP>e6;NOJ=+qPqgS4+-eMke~}3(kUcvQo_t5R|^kq=hy93g?wRHMmjM<#XsMmM%e@?vpCo(N-6eEE8`>OCSptmXNb34my3L zcp>aTM!ReA(TlnFns)lRzW9l~#dKKq43WKt&#{&}xj<~$qii(%>hE(VKBzp6?vL>!F}a)|k7kg*>>xNJC-a(LbwG zI@fxDMJvJ=6#xgD3y4N@QDM6YDhw*r6H+zUWNKIQX%zG%7_~{2iGSe=&$9N|z>n1Y z$WE5C@)%GnBJvM&7u~e?Zp(2B`mmisF0oPbD(WUA7GuDUkR9( zsS2;%nYSvvj1266+`SCZ#$bDk+>%fI{di}B@64pZ5IN!~)RymQN%LSGOA@$ZI9}6E zvx=TShw|mBb8cHbVY`M#tJ-1KUk4TcL$d;G*Kpyf2LOS<2$nqOHQ-Nv?w5{Az7_xo z{%UO(^>G;x-NHz)c4&N-TLp2$J@I{r=|TOATv#(>*h1!xENl;fc$$!huO@+AL;PMK z6DI=jcb**s5D@tnf5Y!r<;m4NftJg&1C?g_xmhH_nZJQ`**zqjxfXCj7AbN{AOTwqB16%$;c)1%*>M%t^j6HW6F>XZ}n{wPW`vYZK5a>6XseI!DO$f#44!eR-wEbWt zuKr>M*GD}lo$`jflt3m#fnFekkd6LViduS+-XeKg9~%!UEJ8KbS{>VfaM6E?d?!wi zt|rkqj~%38Lx27Jy(zBxw*G648=p2)LIvk0CW5i>RD#^AWUO>Zqv-(h4OpAE>O{I77C7KO*lz~^5gpvc~d+w z7tFN%pbD}jz3`mfQ_O_>T%p`g@r`%iClKi-^%ja6vI$=`5LIy zV$O#3++dVRsWg<3p6xQ-)&UVjp{&d#S;oFao)~MC#H*SrMEFQ3CGlMs%?8Ioy9V}l zw1$Z#4bgUTqCuf1PwITqb{2k+WgIJRX}LA25keD2kveh$l8BEWP_17}w=M_KmM#|4 zN;K<~3Mn2?WyB#L&!2@op4X9~*c@eGfO$P@#It?!8dor(&(z<0FKRQ|>sjWlol%Wz z%(A}C6SeXbfZ(&6%v8O+z8puYb(JVd6nP`#NP?{E?tpSH3nzb}); zxr+-bM%S(bt;R#^SXzI8!&Cx~t9`AlY!on!wRr>gmLCURh`#y+v^ua9Wdb`Gs6Ah1 z4#1BSw*v@BCyqDT>kGu*0RG83e*oIUG{m26*6i#G3?QnB**(<%#Pj#}*?JiOK9NuO zNPJf>^`R~191J7+hPoklq@W{-0G{CC0{c_W9Kb|?wfWz0V=(Ypm(HG{7s$X?K~GXy zPv;2G${zsNm}zCqN-qlf8nbKYO?^W^=PPUjWQM=hzrzVf5y<-XWEjF{`H3@oxcJk| zS5w$>)3){L@F>Yf;@s4!VjU8*8umB!wIFUZb(YVf?M*d7@}Kjt?L~TirYp8^;22}g zPqzTRa+0`cHoU z2Any{bq&`qo&r9oa+*J|r)>bXZeLR0coOXYM-_i8_5--E{0WehxPt+EKOt8}=2RFj zqv36UL^@;~$i)2*jx`?uGk!t8`R9Q*qP9S*{!|1Y5jn(VE=-64R!ge@ofUHccHe%0 zClPW07=s8g>kZQhz*ahxkh1r&={~Q~pWob+#1wvi7xq5R!vKR_`#wNN>c0T|fAuU- zbf7|8(d+&N`ioP|1VCOGR|5I}(KGO-Quq@JFnFT5i6$s#%b%@B;`n=3Vp;v})8RA^ zOC^SeN>Va$^e3CSP^HYtuyGAcCY>V4r`dBEx7L6h?mikkKgf^{KuIjrk2@N0A0ZPH z_jsP#m_D%0wy*iEHHm}DVTmEw|L)X@X8d#x#kKd5e z9YezpFaEQwVO(7ID32Yv4_sq2VZ}pu?p;Q5#r zb?-w*u-F0h2fg>;BX^5|iBI9wS^&G)B6cQ(I-q}qoF{?g}jMn z&nRURUyC3F5!mu(A9v{eLw824=Ru zkeP{*l?8yFfu4nd9sr-^|NW%_0Ju0g8#v#88FQEzu+!r^nwUD# znVT3GJJHz~I60d*{(t{eaS;JwNJx1BA*sI?@aykGFCNuB+a^v%YKR{`^yY)=csXd1 zI4kZNH6bz(GBB{`k-dw{qLnzOJ_Gl>jx7ZeH+$$7``ANI6cGX4DqHkVO%>%;j7u>D5vc+(C=^8-uF?Jx>0h3k5>`E^i0#N2&iiq0fqURr%=Z+tp@ z=4c*Bik2QkVoZ<7!L#mAS>xB|bdNGcI7XPurq!yzx6{~`H$Z#!T`AXd1Mp3wNe*JK3=|mJWGV##$ zk*5eq9M6SdkOe=Zp03kmrI#sxu5vwbBvxh*6K@?#_e^YJhe|$O$g<`#gk%) zm2lHLq7g2H^6t*r^$ya-s2z=*MFl^5X4U3ymiMO_Jq$eLJ4~KLpf;Aax7M?R0{XWv z%SAHdmNW`Qjqy;5{ zXAwy2dDM)%oR09L+=aQ4#xB#+JPptWxXSAE0YPe(>*X(Ss5+nl%((PbN!;Jk4Z)Zy zsTzruU=HZB?4aW_Jd7bOH)~{Dy$vsWz+fqY|1A($RLCo+$Jmyq{!CIEi2tw@jvRdliG=`#Sp zwZT_)1p~Tg$EfVsZLq@ouIM=w#4uw}a#=KldDug>F+kc$8Lmo15<)>sa*k@7C?3Ia zZFm0oh$$*&Gs8VZl@NJ+_IBNHxxnV%L|>Z;J}cPbADE^P=fGwcjJK3m%R2%fQB?1i zykhO0Pd?t$C~JO&bUb0z!Ssy+uIiL*mj<%F@4g1qRV5CJ1Y~`+4CjX+;}k}r6wCpDT@@qW<4#ZiW`m(7#|~84 zjn*?rVRR)R)=^A_%Jq^AB>}`3VGe+tdBI(Sl-&`?)BTuFA@Tl!WofeEi)|IUoqWLy>4Azk%#D=E+EXAAS<9bI7$`A7K(LZIlEg{+LHU-tP%})hJ z?P>LzdIpvXqI+@vR#8Sll_}(ec&W5>ZbKy{zflpoL_tqmV!8ODs8bzmCMgypnZ&t; z(FiajQJfevbXw>7DslVei#D?edPXjlTDVL_f^ULUff?8~xh8wxGInMIwrwF`&>Xg& ztcWFUM5&IMDj7DS->&M8bK|!!ij^K#|H}PMk2hocy9tCs|BokvdO>-!V#2Am3I*l0 zF(aS2tzE&#AOZTXI(CW^vi7bAm?-;N@TvF_6jbk4G*w`krcASVIT&V{moezBI5YDQ z@}oyOqsCDV!D*YC4|LL>?G3Z<7|Jf?%6mywt7fX5-!zg?T8X$kwZJUp85}l%UiQ;& z8b(OxT$dTi8qgZ91wLS7;AESMiUm8E9r`3PxKOykC_I0RBIV|(i3iiDBF@9 z<;b^Ld+(@`yYyWqJZHc8WAqbnUPU7UyA@K3rKK*OXyR%&tnToK+PTdEN-d!K!4gH{ z{lH2wscI2Y7g3~6ixfZkt^dq|eu6_ene#if*&BR*AbagJ2Ws`!v3TcaZ{Gz0oMmi5 zw$-*bRVsIjC$28G-Zflp3clp+hMZYD@@D#IXwQ7VrY&U|`PEXOWu){bJOK=Y{W;sf z=Pr;*o;T#}?aZYWH9JX)8ez#eH+1IZ_02S!h*_i5`Mlv?nDhRAb95E;Ff2^g{L?uD ziu1tIS#4f%jA{~Z(L%D@KuqGss3(AZJMQP6+YVgyzkjvR$WDvPP)teC7?!6W8@}hu z@A!OMj%;t|tgKJp%g%xU2oAvabv zsj!TIM>(|&TaAg=EF^tDi8pWzat408dEQ)aFU0T?$FPhGR0b<(1qCWZdGt6j2*D>j+RM4Tfg@2y8 zcWCq6e9e7(v~2Oz_KC9R31rNM7eXX)_!9bxFh9qG_Z`~@A_w_-N~0g@z_K&KG$z=*P$}~cC^7KNV&PC$PBWI`=cm@9%d~T_27iE1k8g4+%sPd>5;@3o)A7QDsRzb|pvGQAuMF28!G^A;hEte?ZV<5M zC;ij=S#~XB)}mHeOc{?+LyMi~5*t^K6U_UyTFs{m{oabO*K)|$>ELn@$kst!F~fD; zM13H>zDPWJz<^LoIn*52<>U9W@szgowJ?|w`e{p9`yt|5rm5H51?4+xb5X+8*XR%_ zU%x1FkH+|f@BuWAb0yV6;GXT0pd&Rzj~sgQKs8vaV?h&+4C!jsAE_mk_2z&wPik5G zR$s9Z`MMK>a?IN5^u~MRF*7c~hmJeoOV0@`&6cz513YE66$zToCbZn$Bv=J5TiY`U zv3k3HKOIqwhqY8Czi}3o;6InUyvTV4_01r`C7|I0_`~#T2PzQa6Er4Ow5zzsJFS-a z;Ko(&VKgDQs^zpfQTqwOzqS;f56wgT_zkg$47<#GO3TI<28=r=q4^K4JjUdJZ}UES zEu}JT5=f+mPjqB)CGG*7Ch?jNx9aRAvJOzZ!=LzwYlHzoHX2 zv3>qkxPJXt1@iTG;{QsV2=q4E+CPk5OrFnPB%}qP;6z&MWd55J#R18`<$liz6{=@a zG0Is1I8XRukhzGGKtg@>II%|8S`3%c0{NF4TZN5LOjw9dlihYV+ok^$qQq}q%$$j6 z3FE?F%ploK+2!1LF`YL;MocqU^o%C*=*2rz70SCBM&U9TYbeZr#AsFk6>I!0%99uU zs}qx%8it^q30;2g0$KMgxpPExv!kIFBxovNN^_6ylOEZOCRZ#baRSPCSMivrN1{KA zysa(%h9y$puUHhk+v>-2Gd39*hdhhKsB@Hm;6Dv%}gWxWhn&dEfiD zc3Pm4n4%ezpq5x#Q3MEBj12rNMBMuG*!@|kObd|q4zbrx<({1)FJm=C58ZR3=6+QJ zkJZ{2kL!v~WrXZX8ChMb`-NalX7%%R=v;skG)UW8{POr%T;guKoRTPtbbGSF8!9*W z=PsSzyfW1g$UQiA7|Q+Iu;8gyF?TKp%CkP1k|lA4fbrwY=;3{sL%5|nUkuKP z91a7X!T}Dnk1a>?Bze3-m;-BvWDUcZtaxPm*4m&O zz$yd=T=fyHshU^JvSgb)gy3Gjr6Zl3lX`{uqNY6L%sc$CC^Uie>X{lN%)|ZIv%IPq?&%9@Nk6La_bf1-44r@2yvG zjlEUJo-^QrMrCKa_`0#L_3yhsqPk(b!4B{9q9(nCpH`T>Zd*?t%&J~@!79LtMr?s9 zq6OZ}+^ViroLYSOYSQNuhUjCnep%8FD$bvfoxybS2igb+uSkXy0Qzs`<R)w;g zQ$NjXS&iP@;NK8!1|oRahha6u$b%_SV1HFvp^~Mdh>^3BfuuRdz$P2*zDx?2?=Eqs z3l(Njw^zJY(@r%Aazh&l#EPZWIqn!}0&F5cdqCCP$%>Jqvn)i>_#5(u(tsXCck##!pkW}8Vzb-hqRS2zqV;U{XLLv~lt1e_^2P%c5e`_10t4hfxDZrJ1c=(cve z$x)lU;P)hczl!WM$<}ufX?u+5fXAx?2!$1t&LnoII2zSB(>+JF5_!;prX$c+$xyr= z+gN>%oMS}8JSawo1CfoSXu*}6N=FHCbBA8a*|~Mpt*nYNvSJMb4krP;%*puVDad58 zzP75(ne|)^`~!U4Kx(j-W%cZ^P{BTY4*0R7ErL3z!fF(U(g@MNlb8lKL|tH<3DZ)HN)nMXTsbwN>)+8u0xU7FbU4X&P~i-9=+kVXiF(U z3%!sirm&@fKx=JUOWD69n*mYlNafWyWZ+h}YUN0-82Ua^K^vAHEc@I$l zpH7eyV_zuD5{Q=QT4`E&!(avRvmGJ0KB%Zn;g%6^UrE`+DA)qwNCuyt96UW-95=c! zipzrFe5XBrh!4>6kYwP*u1o@O1b&FG`|hGP^t;7jn*@P`POq&!E(Q^XYpeIe4Qb!Y z$X#Ih_`IH%B!V*NZEw<&w9)lZJ~6~x$EUn5HhR5egs7ZG*E^N6U!eYw`evD7sK!!c zvlwYxfDL0aG~J9o#wQjA+JmS#shwR96zx6~W2{Y%OB&Ojg6utC{styYiNOBFPm!0a z_vxF9tEauA?Zy-I-XF$CBxHldzkcoh+CL>UCu(kh)Tq;?UlbW zqzq2?R`}8)X(JQ+g>4b1Sf=EcCg>@s+atLHUNabM3An@iUuTvJxR|xA&^T#(r8G<|kQb)Q&vmL6LTDBTd>_e>+^d za0WUbGMk3TF{Pm_Q}jN#E5xG{aMwpO-m(UMR#i>&OOu*^n+=Z#@^`7Z^@m?@1qm%# z4LV7E+XA1&2b!4~8Qa;?u8rq57gqnp%5K{Z^!D@ik89Gm=MvWq-c1PErPq56=f#aw z`<>sk59PPjlWMMCu)h|&Uv;RJ{7+LfTaVk$;yGQ*T?NwL37CqBarYO%uT6l1W(@ai zmG}Y6A$oY>oA*c(mSK*aZMB~lVD{3x?3)do056n#S zLkISl=v_#moJ&KvnJaDQN4*r$%8Pj1WaBl?GJBFwF|Fwh)JUiuqwYOM)G`I^{ndkM z^O(?Q5bO>-IS8C3a{+|vBxn62U^jCmRlt(MFgYT?cKp%PS#mDFwc>2Hi|9}!n(sWb zs3JF>&pK?i#PKz~3*q~;?N6y}JC@7oNDj`KwYAuu#F1mMWm1k%f~B-~BPQ^=j`-?oTWPweN+M9mLGqpk)!XsB zEX1Q3U~wGv1^8VV%GM3>cNrkt1sg;Uzws8CMO9!8{pV^LFJH-UuABf(M^X5vR}8GP z{*7cKBt?zc9EYng7{;P_K!5M~(?Ylh;b$LY$^0q%Mqw|@d^lq@KByduT!Qx%sHx%O z5jMRRQYQuFq2b8Zbc7^ozkqTyk51%^v8?+X+&w!-Tgz!k2faY zn%vNxJ!5-YoSfQAk(JaB%;-V^$3646w?m0s)TZy{THi`X6Q1w;SrEf>=j!#uqlwPi z!v)m)Z5`j!E0vcPr&-xZrKgmnnOzj89w`dVY*Uf<+zrNu8F$j*P9t;MLS$~O=QFF0 zij`LuipW}%T1egP=SjfV-9Z=}U+>Rt86Mwi*;)VUUKN!ah(dyAm&*}p4P{%iiUFE% ztjv9hPH8XYf`<-=)XcQS1x&AW4qL1Gnx%}L>Dl1X_L@mUIU8-+*O^C`I@z04X5VV_ z;Jt^!8u4T#Tia!p(w{xPxDqMWhd+B2YwICLJvt~QTeAk$aF_jlQYQ;(+GDkec8_~n zjZIyJv{RAo4b-f!zw6#SI1v^^$ZFr0b+1n8Jyb|@!)wjyQp+ZFGK`-aau=45b>+m& z#2+S(q}I+$WWz5|Ai%WNZfrtsr1RgtygZG8IDKT|3>J>rn?Z7qf)MM%MeVHQAQ!;M z6zw{T*Z4IXw@ir2HI=S(^Xxz-@=19@<_+sTJzl`yJ(`)7}r+YTmn)qEOnA| z+nWiF^2ubbL`sF{-j*^k&K}T=>4*zQub{yQ-Ae$xI|rZi;SB3dT)uZ z&zx0jVH36Xd!)#@V?aq7ae5-g^ZwX3C6X?2P6=L-+FdlIr5MJU%RG-1Gi|UWb>hZm z4@6JEOEznH3z7yzuu#z#+gqi-vgE4GI9PJoyD907vnxT=vxef`K9rg&1WtPH z>U`Q6_tZS43R`eWNYQb*u#xODe?p_567>SgVw#47lwSKz;uLF9*keS|(9A}>Q1beCf@{Ebo)mb-+?k2sg2CMDT%e@(Nte(zv3wQ~!d>hGKD3Z|Y$ zBcKbGO4JH8A1lJCA{WqNL>L@j8A^c}>p({N;sB_96_LNIFbj)7bN!*~^wjumCGDzh z@zRuy_q?mOFsN7+M9wa4vKHnOJi2f{32$EA-0| z#8MW&UGibW=oh0(unaO-0aV(6;Z?81uB9S<6?7;Zapc?@2J&voY=h7)_zWxZ+PYJg zop8Z!3*FfdlEB&6w!;M%Ll_9dW=?PhY3~W!blx5I%Y8<=2K}sfK2k`hS+hm0SM{K9 zZ4?ZI2h`*s6!Kw@OZ9m1dG2w~<}hpshEQ~Y1fQXTX6n=@!LeQRUuTJ~hJcP!7{YKA z!d4hCVmGG&HaZUe2reBXD{Hl*S;N;5#41*T$jBWQbdk@yCL#pEa&-+3QFTJm!)A1uG%L%r$ ztLyBrH5(?Uc924~k`p?5IizR6iy^~*CWf$gh^6!~y2i8%krAOD`3-#^Km}<;SX5fJ zDc1ed%HjrIjyr+}H2L`JX%2VPX-CTfWyy7stOn&zfqRyHDr&LjT0{H;Q~-h9fBpF2 zNzH^N%_wo9@2p;g-A$RZdZNo+T@3~MdVAx>@I75lnR8}E*XG`$@V&n6nL2ZI;{IJF zz8U2yEHbPXcaCS59e|g5P)*pKllmh{gl-e>BK^8!l~VR7AgF=UM8hDAk#mjoVG9knba-XPaGPvVkhIWxU)?C<($&Om?`h+Q`( zhsr&~2&wOgaDUHOK#y8Cf$=0@fRCl7gL^Yrr0L-F$sy7fDm(QFbjT)Jcox^Mi_4MI zY%%iQ)2zBcSL-5U6PU}G7H(GvfpU(+Mtek5-bau*;x4|#IndqG$?gY+@&I?EVi@S0 zV`~B|NC=h!Mn>NIw_1=P(CW3)sLpa9(ypW#gHhQ|sXS|gQ)HV{cxd$Gu~&)(%}h^R zo?$|%c^HR~a9H}?d0!`6s3d<-@DXnBD&mtt`5V$tCq2WJh}?9D!6Lty9`TB7!czi{ zM2ES~BRnwGg=Gxq#w*({!RNbI3G$3fLq7E5*_Y4Zx`~$X@7wHTl7wZqw2(TlNi@Ng>p!~J-(t{^~?vv3aOoQDjNA56ieG{xWh_c6Ruh<#{?)fB&bSm5)k_CgG z{;){1cH_COwk79wUj0BA{=di?t_zvQXlIWy5{ z*Uv%J)>rq5qUkX4+NbvSQJ!H$hsq}#;rr^dkN&jP*Hw6JJVbO$M%_+__0eE=RplY* za}jji(`tph8^r_8{g%RCb`ZB?7D%Tf3F;oY&t-3j1%oW(5C;FLSWrA?Xx!g6{DN9o zlz*LzK}K)qEgL9SP}^>7ft8h(fh6bOAxlQoylDm>`V_DnuLDQrw8-Frl`0qdBOtaP zm92VENgJ;)4$u&S}zMWn0Ha>F>ra7Eys$Wc53s?ooyExmhgx8DJR|V*$DDu3Ej@}Pa=z8 zV7VO#nQbae{I zS*Ntr;^yP-g009VtOH-ClH$RFa8eh-WTwWVKe6{^g~ZHh1&s)e6n@AMvl(I>j8V#* zJXq|VhesgVkdu}ZL?-}hu{6fd1*jil-?v=+hrjs9o?FH&7hlwpAKxp;x@JUiZA0O_15mcuCU_GVC!;ziQoJW4a z0IVh4T9pp$^U}lM(FBz%p+{x|PMBFLDQ@G#Hs4y*=f`)0XcBzc6bH;OjuzA=zcY>w zz-WL1mcN7_;Va%MWd%Jh9tSOnvV`0K2tcrG9n|})xI<~ytP-0@zUze%DrnIQ|3RR4 zm7u<4@xQz^mN1fwZufd-8CTSZbx%!jt8GUmJ6Z22J}i~VQlaNH46DDOz*PfCDQY4a zIo0;`ijHbtLqP-v=2HVLuZfO&Y8e$!cb}oUbmE4b`xrbM3vkFA-r*w+TKG&$`b1+? z&z`Sk27?+_5~iRUQiAzIjSunV#Z!SK1}eO_uaSsA)A7nA!mz%aa^4>)6~W<8&P`%s z1GW?^FTy`N^a10;u=wtCaP+|X%52dLtHE(sl6)SUv-|*$b3EuHLYrf{R_Q{i2#=)M zE<(P)%A9}%SHMuFvSDi|`gwSKN^=6uFsB%AC9UVm*4<@|;mHK%Ja^J85u;3DlY}aH z*|_dxnCPxYJueSOge0E-YMXLgv8a<^diJm%Ht9??WddxCw2u}p)gt}79&G8JTFP*D zHaA?>LoCn_WFg=xdWSQ$9ZJ2`%|3TkyL~IHyx@r4`MF(TRoN3$8mrGWwpyn$q?7T^ zd>SG=Ae&ZGYL)oM6u6!s#?;x9mJE1gM?6M{bar?sM(-2?W~5xvQMK;@MS!iAVc^bn zCQdk_UGpSbEB)A%s;Hbt0qTg;Da{M{Pz}tSKobX^su951wpsdjr0gSxW=`930F3Bp zL~Dr#R=Z?PIcv8G;L12l&_oXiY%^WI4QNp}x{m_W^vf}N^`*N6Gqr!*MViauhSF88 zRE$$oNj3#0X9Vh66{^S|{jpm<8sop!0fu-aOY)ZkgwC!Nv?izgV0fXR$CjN|vIB?D zyf|LBN3injs<1~yvY{46D7zgrXjIZh-ZsuP5)G+>fGrjYOCf(r1GE5f2sRhZERk`> zZ)hODfcy@=#aGn|bp|HE(VUVf00aO{Wdv(Y2ZL||nhk;MQ2JKvRK!NC_I-YUlAu$M zxgS**(pVBHBuN|%XFt@rkW1QWmV$&0OFEDT3dzI*xv9*eB(zJbtOFpVrqH6Cw?JUM z$kwgeTGYp}pgef!N`aJ}8}Bh>Sj25&ViS^=i{&%!nqv7p5<3|py@%nUhcQlMEy(7I z6RxuahnB*ix);fp6HQ%i4a2_pd05Z5C{ZipA7QCZ91OK+y}1U_9tLRaFF#LjK?kAU zHKTpq&>|%`zcVSc5=l1MyYZL!@0;xQ$P=t*Xz>(049EK4yK~Z~6c=oa%!HzwHN>Jl z-~4DAY+Z$rIW}&EbeN?Si##RB=*_krl~UKLE~awKAXZZ6H`Ym3m3As%{hl(_>P|sb zcAcrkLzKS~$s0<3^!R0KKrDqQ?tgp7_5@%0eYiF!wofl1GtQOL`J?koeDqx$L8;vX z7YUD7H0QwpDga}n;c8ZJ3%vjwVS3TVoXAubg{^mzI@RR#oo0wbVL&nAX&~ftop3@1 z2|=g;f1=0Bw_>x}@;r%vFQC5@F;yU+vT0qeiOXf$7*2wtk^30#kTT}_s+H0?BSY4W zqI?Msw2uP7Riw$Wxrmyc7po9oK}8bKK~ibe+3lCgFt?qEr)qo0=`M`<;S1y6wSx86bD6dhUFmi!kwmaenpz#R|a{Wj*#e|Rt$?gz~*BOV-n`;5uUZI6reu5 ziKm07wS2=~EIQ4zN&^&^qKz)-)Q+BK7)zR+lkzSKe%O8OOa8ACDncvhqI88$K@*K;D5> z$^Ro)*}1Tfp>{F&CpY!H*fw63>k0&;)?_j%ZEI>Jf|QwEN7&%>?o1vA_Dk_RGDX(7 z_02_WIPlF&#$%~i-p3sg;!X==8hpL)D3BZ7^vW!?i0bssm2W+CCZ4K@ zrR1^$esWgB{S>oXKB`f5tI@tjUq+X^4iM7IoR|rG$sI zIhCS>1Fa4tAr8=t`_1FspHC1XjE{?x3%bjDMm-w1(HZnBz86mz(vz6Zc9qe4$hWK} zYP1kIerM?&MTW9bejp8<{Q?9qG>~~@!?BBO8nLRs;-{nNFT1@G?%F9OfvXQAObXjN z$8z-eg^YMPy!orA-nrNi!^=H`b)P0vL(;-Ap75TY*vLu;x=_#sWl1zV-dKB~U=MW& z$)hKut1$-|rh;L`Q8l~jhQ}*jEW9kb^o)5ncfid^vI?3i`)QpxmdF)-)?DgD;jKBU zY$#a$6b`g7k}(?ExfSx4t=VHf>~T0Jc6N`A890*bsCxYh;RXv3wTS=Q9!hcPXa$EW zhtP4V?tE&R~1HXAp3PAQnD9g>Ae zs0_S$XF@~P2hQ}3joXAS-5aA=g9AOI9XmENiRjKB-ir{JVftgPH2Sf7@uM^v8gyJg zip1!eESoxS7)!Epe{ETspq@uxEuh`FL6y8|5KN7VRb-ioSSo(T)p}yEB76tO8`DM7TCwqKmLwA38Vaf8unlNfypRB>+;+kJ~&wb5r!1N+U zhWvEl@XVesw(PBO>pxcz=9qF|ZU@b+`(#C%=3bHL!sj-}PZzfSZ1ZgHK$CIzeE?le z)2)vV7_(x^!pz;7I4|%luIWn}=dINht!)i0R1@HaVMXU%@rfQ}<>JJ;7wqxjkquGg z?98qg%?RJc_hQG?-Q?N2GrvZvqVxR;mvd$;bb9WuhL{Omia^)g@y3-6_d8hIwRGky zq+yWq=E{t*fXZdZ1wUGmdjaAcUO2on;1retqb?Q+-%FZ%#B-%*nON1!1Dz5a*3mq8 z(D$ASTt^~~waUZGg_k_td|`9%4+iTmFX+M8hOILzq9fMzOl-~I^}(g=D`PU9{p!Ji ztBcqkI9!trOQI{Xx*d=XjSE6(z*AaCf>8B9j~aSg4Z9VW3f0R8k~{Fqc4hp0ikNm1 zM*2G;Az5IhV~lTkkP+1=qm>!zt)_xw`M(@{;?>M|*)&BFC~}#8NL!|L(=yKO47~{xo#L z)YjvZ8Ed`;-p02ql{2<3Vt^Xi?Y5pO8keajJ8tU1iN4Mw1>+Ru;)923AimHfiqAJ* zh{C<_$Jv@!U2&u2*=Sfd^Aam;$DB6`%AzB3$6XtZr;!$$NCMLlcypiFn6r4hA_Dr} zV!Jj@x9r!bQZ_V$Mm`-fb3bM%AcP6St+NEzQ3Rfjq!Dolk-2I%aVC*9dt(m6w1l&)`smLdI!#?GdFUJQXk9<4`Y2IRk}(NS(sL`$OjvnLl?lS6YTW z5xs|~L%yY|QkYYLD#Sw62WTkS5y(DBktC0Id)`D3JC zyx2Tw;n-4_qqc_Ec;H(~qn?9Q-eFUYfH`#Egai+s&d9q) zJ+>z_oCm}^NqC;-j3rcC)2V4`;@%P~KlrM)zBB+|Z#RBS0JZh{-4I8??wPl1`!Oye|ylE`B(B^k-$TtPTF9Lu`5@q6zQzf@DFPVG{Ck^C&(WfOCa zeh!bWMa&3OqsPv6m&&qdU#p4%1x9}EmF#8;4Q5-droimz$ggIt%7UuShIj}PKTgnP z^cq#m1y?P_D8K1?Z{MG5cQAkVikTO|g#o1*;N7~+2;4$?9#m2=hiqOkZrk3`k`~h; z(Ozt!Vi3Fxt*_nk<1Nf~*I;7PUbtT8J0ngfwJqYRZU)ZPN_641rSnu4a48GUW*tm3 zkT`2chS!SYkjU6^ONiw0^lxU!2uStn!Gr9y|7vvbkb!o>`uXPZ<}lmpl`R3<{LBRC zu__EZ!r3%Mp z*6_+B!H;(~aontZaU6e;Jy}DF*0N@T#NxIdx#5>NQvL1JK$Y6HSyAGIW#4PXn#fR? z3eXC#kL)to$wBj2CqA=Nknp=G#5hLR7SO8-h$cPl4o&7MhV_H1yuodJKZ|M&;#-DP z)?P2W*|?QRit1j^^BJh1g>mW?Efb)142|bA7A`L|OJ7essQH)oARj9T#ua_b2>huW zwH|Fy`suy(gBN6`t2RbgA@I~@BR?J1w5jeql?=;hFoR?7D8wk;T;xWwAjF$0?yo4f zXv*7O3_XTU_j1+ZaSrOhUwqJ@q4C}8fbQ8LYBEk6 ztnfV#YL~-dnwUwK#9`B~vlT{M5lnCLL}WIj3m5{xrDz zdhT5xt}dc4elonh`B+!oOApIdN=lM-Eq-Lj%nip1D7n{5l@-Bi68D-On&>)or&?7} zbxWzN>vUX1D>r4tmTMMf5{|B-eNE{PgYU#|m&k7=h4acOYxM{eOPP>Onhlw3hx)xX zf$=xqx}@XQtXWWP(t*u8tj8jiR#$J_62A}N@NVoz4~XAVbTP1;`>wKeXP29sk*!1y z?trjfKfKR;4rm{;^BAjwgCm(kCY#4qa)j)3E4-O;i3*Kt#aGxXDM=t!`?E_*9CA08 z34T+v(`Z2vr54`{s$B=B(o31f5N$>ZVaCa5oC`)p;_g=KRIEdZdf~-Ur2f7aYn|== z?7u(U*oS7 z&ajJReEzE)uOC-w^`wdcR_)>s%>6tEY($3o5_r2Q-h--IqNJ5&ou!9yr>$yO>1%(h z%VMW>b%M=+TAb@myk~#;k3jz*6sMg%%Dt+HT1stSqCNO<46R%;Yz5iyuKqP6sFyq0 zS}o?BrxFH15nnSXq=OW+_L%R2ONfeg9%4hR zp4#NKk_F0)wcGw%3cjzDWI^F|HIY|ni7ya218PudkTn(5;m2cySZgF7DYc!ZU{8`J zIE=U+>W;HKIDg?Kl!kbp>#J+X*`itZG)4R$6(=L``TO`Ff*Qr@1Jc|fm3Pp_^VW=|t zKY$LBcshLsF%ren97du!kC|8>Z*T)Q8D52Yr}!wq@b%gAnja+5Jk$*F`V|-8(~Gh> z?QrUG<_aWaRHz+@`~&*=q_@FFbL_Ko0wr4rjn^*XVc??}V5XMUb>p|YRh z(`aip(lg!x2hH0m^}_j{HEzm*FDaW=QLih7=B=q#R~p1E*VCo1zfx0U8i2cYoHx&K zbiX1aj?yqpoKF87_JenK;mFr`9pr_)HpUbni5L*`uVpf6j z@k9;p_U~uHMPpSYdF{(0w7@3%m{M$IjX%2k99z}lvun9|=Gu%AVrKzeBWu34l(t-) zNm71r9q3h_a*_-s-@2<&_s@#BD2WNG#AEVW+kUC2q1=kfQP8}nmQ&i*E9Y$h$F^{;^{d_f#>x z>si+y9QJ?j#0F-eKCYkmN#r@=S3;xpzm-KpZ~0WSx~KKY{rV$+pKFoi2T0%BY*YgI zpZ{TM`|L&p^_5ykviU@064nXa9^+;4wj%dy9s#Dl%E(I3o#;>f+&zoFVf5bFncj51 zH}(7|u&J0KxYvy^i5M6c$p9gNUY0X5L~$j#lFFMTX)wB4$$MMoHm83fd4)7lUU|%m&C?QPtU}lAWls_J4tEkj_b$lbgcH0e?>=BcgQOC(`9r> z1PgFbBXm;ppL<^a9t=J$PA$0vBPl~SB|$w;MIm9-&eXAga~}aEXO%9hnUlKmy#6gU zg$rO!icr;l!|I-W*#nl2t(L;)S;eX5=Az>Ax4F4YCka^<&POvd&6^Wj8CxV;^+XRX5123NwzAQm+mM>-7H?9=P^|7+i(AfC=TB^fE=G$L-naP+3~Y zOn~lQ^4;luv5_$A?CLzP*Z!psCf~A0Ybmf{wVF!3_fi-Qk`^pfeR(!?(ZoJ;`|it1A$s@DGpqLY zCgHoKd3$H7is~Er^0L2u!EYiD;=*gy7m4fr;=oF~If^_7%(r7?;(*orn? zZiKl4KeJ#h|7zx~YmD3MAnXpA_hYyDz^eU2HMg%!3HOQci zWcaZEau@l~?w7bD_L3d5(zg39F?NE%O6HC9)R)C#FDLYh>h4Ze*GHYaYS10KyA5(` z58K#*-Wu>EB z$=ZW!;|2F9+*s=RgQ1HD2+?O+~8qh;o!?Zy

lD0;c1|+gDJ>x!mVp0pZ+Z5I|f4< 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⪙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