From 3f4873fe2e0fed40401e82b629efc3f6d70970b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Tue, 11 Dec 2018 12:47:41 +0000 Subject: [PATCH 01/13] Merge branch 'qa-project-ui-updates' into 'master' Update E2E tests to account for Project overview UI changes See merge request gitlab-org/gitlab-ce!23366 (cherry picked from commit 1d87276cddbc083c6b5536faf6fdce6c84cc844f) c61c5cf2 Update E2E tests for Project overview UI changes ed75b46c Update tests and Resources to use new file button a1d9a3c3 Visit project page after pushing 7aeddde1 Method go_to_activity isn't private --- app/views/projects/buttons/_clone.html.haml | 6 +- app/views/projects/empty.html.haml | 2 +- .../projects/tree/_tree_header.html.haml | 4 +- qa/qa.rb | 1 + qa/qa/page/base.rb | 4 + qa/qa/page/component/clone_panel.rb | 31 +++---- qa/qa/page/component/legacy_clone_panel.rb | 52 ++++++++++++ qa/qa/page/project/menu.rb | 82 +++++++++---------- qa/qa/page/project/show.rb | 77 +++++++++-------- qa/qa/page/project/wiki/show.rb | 2 +- qa/qa/resource/file.rb | 2 +- qa/qa/resource/project.rb | 6 +- qa/qa/resource/repository/project_push.rb | 16 +--- .../project/view_project_activity_spec.rb | 10 +-- .../squash_merge_request_spec.rb | 7 +- .../repository/add_file_template_spec.rb | 14 +++- .../3_create/repository/clone_spec.rb | 18 ++-- .../repository/push_over_http_spec.rb | 4 +- .../3_create/repository/use_ssh_key_spec.rb | 3 +- .../web_ide/add_file_template_spec.rb | 12 ++- 20 files changed, 201 insertions(+), 152 deletions(-) create mode 100644 qa/qa/page/component/legacy_clone_panel.rb diff --git a/app/views/projects/buttons/_clone.html.haml b/app/views/projects/buttons/_clone.html.haml index d82a3dd70f9..d453a3a9dac 100644 --- a/app/views/projects/buttons/_clone.html.haml +++ b/app/views/projects/buttons/_clone.html.haml @@ -10,12 +10,12 @@ %span.append-right-4.js-clone-dropdown-label = _('Clone') = sprite_icon("arrow-down", css_class: "icon") - %form.p-3.dropdown-menu.dropdown-menu-right.dropdown-menu-large.dropdown-menu-selectable.clone-options-dropdown + %form.p-3.dropdown-menu.dropdown-menu-right.dropdown-menu-large.dropdown-menu-selectable.clone-options-dropdown.qa-clone-options %li.pb-2 %label.label-bold = _('Clone with SSH') .input-group - = text_field_tag :ssh_project_clone, project.ssh_url_to_repo, class: "js-select-on-focus form-control", readonly: true, aria: { label: 'Project clone URL' } + = text_field_tag :ssh_project_clone, project.ssh_url_to_repo, class: "js-select-on-focus form-control qa-ssh-clone-url", readonly: true, aria: { label: 'Project clone URL' } .input-group-append = clipboard_button(target: '#ssh_project_clone', title: _("Copy URL to clipboard"), class: "input-group-text btn-default btn-clipboard") = render_if_exists 'projects/buttons/geo' @@ -23,7 +23,7 @@ %label.label-bold = _('Clone with %{http_label}') % { http_label: gitlab_config.protocol.upcase } .input-group - = text_field_tag :http_project_clone, project.http_url_to_repo, class: "js-select-on-focus form-control", readonly: true, aria: { label: 'Project clone URL' } + = text_field_tag :http_project_clone, project.http_url_to_repo, class: "js-select-on-focus form-control qa-http-clone-url", readonly: true, aria: { label: 'Project clone URL' } .input-group-append = clipboard_button(target: '#http_project_clone', title: _("Copy URL to clipboard"), class: "input-group-text btn-default btn-clipboard") = render_if_exists 'projects/buttons/geo' diff --git a/app/views/projects/empty.html.haml b/app/views/projects/empty.html.haml index aa690b12eb7..081990ac9b7 100644 --- a/app/views/projects/empty.html.haml +++ b/app/views/projects/empty.html.haml @@ -32,7 +32,7 @@ .prepend-top-20 %nav.project-buttons - .scrolling-tabs-container.inner-page-scroll-tabs.is-smaller + .scrolling-tabs-container.inner-page-scroll-tabs.is-smaller.qa-quick-actions .fade-left= icon('angle-left') .fade-right= icon('angle-right') .nav-links.scrolling-tabs.quick-links diff --git a/app/views/projects/tree/_tree_header.html.haml b/app/views/projects/tree/_tree_header.html.haml index a89df6adfb3..4e9a119ac66 100644 --- a/app/views/projects/tree/_tree_header.html.haml +++ b/app/views/projects/tree/_tree_header.html.haml @@ -20,7 +20,7 @@ - if can_collaborate || can_create_mr_from_fork %li.breadcrumb-item - %a.btn.add-to-tree{ addtotree_toggle_attributes } + %a.btn.add-to-tree.qa-add-to-tree{ addtotree_toggle_attributes } = sprite_icon('plus', size: 16, css_class: 'float-left') = sprite_icon('arrow-down', size: 16, css_class: 'float-left') - if on_top_of_branch? @@ -30,7 +30,7 @@ %li.dropdown-header #{ _('This directory') } %li - = link_to project_new_blob_path(@project, @id) do + = link_to project_new_blob_path(@project, @id), class: 'qa-new-file-option' do #{ _('New file') } %li = link_to '#modal-upload-blob', { 'data-target' => '#modal-upload-blob', 'data-toggle' => 'modal' } do diff --git a/qa/qa.rb b/qa/qa.rb index 10a50f5cc72..22af365d65a 100644 --- a/qa/qa.rb +++ b/qa/qa.rb @@ -273,6 +273,7 @@ module QA # module Component autoload :ClonePanel, 'qa/page/component/clone_panel' + autoload :LegacyClonePanel, 'qa/page/component/legacy_clone_panel' autoload :Dropzone, 'qa/page/component/dropzone' autoload :GroupsFilter, 'qa/page/component/groups_filter' autoload :Select2, 'qa/page/component/select2' diff --git a/qa/qa/page/base.rb b/qa/qa/page/base.rb index f4bba3c9560..88ade66f47d 100644 --- a/qa/qa/page/base.rb +++ b/qa/qa/page/base.rb @@ -132,6 +132,10 @@ module QA Page::Element.new(name).selector_css end + def click_link_with_text(text) + click_link text + end + def self.path raise NotImplementedError end diff --git a/qa/qa/page/component/clone_panel.rb b/qa/qa/page/component/clone_panel.rb index 94e761b0e0c..d37b63c716a 100644 --- a/qa/qa/page/component/clone_panel.rb +++ b/qa/qa/page/component/clone_panel.rb @@ -5,26 +5,20 @@ module QA module Component module ClonePanel def self.included(base) - base.view 'app/views/shared/_clone_panel.html.haml' do + base.view 'app/views/projects/buttons/_clone.html.haml' do element :clone_dropdown - element :clone_options_dropdown, '.clone-options-dropdown' # rubocop:disable QA/ElementWithPattern - element :project_repository_location, 'text_field_tag :project_clone' # rubocop:disable QA/ElementWithPattern + element :clone_options + element :ssh_clone_url + element :http_clone_url end end - def choose_repository_clone_http - choose_repository_clone('HTTP', 'http') + def repository_clone_http_location + repository_clone_location(:http_clone_url) end - def choose_repository_clone_ssh - # It's not always beginning with ssh:// so detecting with @ - # would be more reliable because ssh would always contain it. - # We can't use .git because HTTP also contain that part. - choose_repository_clone('SSH', '@') - end - - def repository_location - Git::Location.new(find('#project_clone').value) + def repository_clone_ssh_location + repository_clone_location(:ssh_clone_url) end def wait_for_push @@ -34,16 +28,13 @@ module QA private - def choose_repository_clone(kind, detect_text) + def repository_clone_location(kind) wait(reload: false) do click_element :clone_dropdown - page.within('.clone-options-dropdown') do - click_link(kind) + within_element :clone_options do + Git::Location.new(find_element(kind).value) end - - # Ensure git clone textbox was updated - repository_location.git_uri.include?(detect_text) end end end diff --git a/qa/qa/page/component/legacy_clone_panel.rb b/qa/qa/page/component/legacy_clone_panel.rb new file mode 100644 index 00000000000..99132190f3f --- /dev/null +++ b/qa/qa/page/component/legacy_clone_panel.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +module QA + module Page + module Component + module LegacyClonePanel + def self.included(base) + base.view 'app/views/shared/_clone_panel.html.haml' do + element :clone_dropdown + element :clone_options_dropdown, '.clone-options-dropdown' # rubocop:disable QA/ElementWithPattern + element :project_repository_location, 'text_field_tag :project_clone' # rubocop:disable QA/ElementWithPattern + end + end + + def choose_repository_clone_http + choose_repository_clone('HTTP', 'http') + end + + def choose_repository_clone_ssh + # It's not always beginning with ssh:// so detecting with @ + # would be more reliable because ssh would always contain it. + # We can't use .git because HTTP also contain that part. + choose_repository_clone('SSH', '@') + end + + def repository_location + Git::Location.new(find('#project_clone').value) + end + + def wait_for_push + sleep 5 + refresh + end + + private + + def choose_repository_clone(kind, detect_text) + wait(reload: false) do + click_element :clone_dropdown + + page.within('.clone-options-dropdown') do + click_link(kind) + end + + # Ensure git clone textbox was updated + repository_location.git_uri.include?(detect_text) + end + end + end + end + end +end diff --git a/qa/qa/page/project/menu.rb b/qa/qa/page/project/menu.rb index cb4a10e1b6a..835e1ed00b5 100644 --- a/qa/qa/page/project/menu.rb +++ b/qa/qa/page/project/menu.rb @@ -29,11 +29,9 @@ module QA element :fly_out, "classList.add('fly-out-list')" # rubocop:disable QA/ElementWithPattern end - def click_repository_settings - hover_settings do - within_submenu do - click_link('Repository') - end + def click_ci_cd_pipelines + within_sidebar do + click_element :link_pipelines end end @@ -45,11 +43,9 @@ module QA end end - def click_operations_environments - hover_operations do - within_submenu do - click_element(:operations_environments_link) - end + def click_issues + within_sidebar do + click_link('Issues') end end @@ -61,61 +57,71 @@ module QA end end - def click_operations_kubernetes + def click_merge_requests + within_sidebar do + click_link('Merge Requests') + end + end + + def click_operations_environments hover_operations do within_submenu do - click_link('Kubernetes') + click_element(:operations_environments_link) end end end - def click_ci_cd_pipelines - within_sidebar do - click_element :link_pipelines + def click_operations_kubernetes + hover_operations do + within_submenu do + click_link('Kubernetes') + end end end - def go_to_settings + def click_milestones within_sidebar do - click_on 'Settings' + click_element :milestones_link end end - def click_issues + def click_repository within_sidebar do - click_link('Issues') + click_link('Repository') end end - def go_to_labels - hover_issues do + def click_repository_settings + hover_settings do within_submenu do - click_element(:labels_link) + click_link('Repository') end end end - def click_merge_requests + def click_wiki within_sidebar do - click_link('Merge Requests') + click_link('Wiki') end end - def click_milestones + def go_to_activity within_sidebar do - click_element :milestones_link + click_on 'Activity' end end - def click_wiki - within_sidebar do - click_link('Wiki') + def go_to_labels + hover_issues do + within_submenu do + click_element(:labels_link) + end end end - def click_repository + def go_to_settings within_sidebar do - click_link('Repository') + click_on 'Settings' end end @@ -129,17 +135,17 @@ module QA end end - def hover_settings + def hover_operations within_sidebar do - find('.qa-settings-item').hover + find('.shortcuts-operations').hover yield end end - def hover_operations + def hover_settings within_sidebar do - find('.shortcuts-operations').hover + find('.qa-settings-item').hover yield end @@ -151,12 +157,6 @@ module QA end end - def go_to_activity - within_sidebar do - click_on 'Activity' - end - end - def within_submenu page.within('.fly-out-list') do yield diff --git a/qa/qa/page/project/show.rb b/qa/qa/page/project/show.rb index d6dddf03ffb..99d849db439 100644 --- a/qa/qa/page/project/show.rb +++ b/qa/qa/page/project/show.rb @@ -6,6 +6,11 @@ module QA class Show < Page::Base include Page::Component::ClonePanel + view 'app/views/layouts/header/_new_dropdown.haml' do + element :new_menu_toggle + element :new_issue_link, "link_to _('New issue'), new_project_issue_path(@project)" # rubocop:disable QA/ElementWithPattern + end + view 'app/views/projects/_last_push.html.haml' do element :create_merge_request end @@ -14,14 +19,12 @@ module QA element :project_name end - view 'app/views/layouts/header/_new_dropdown.haml' do - element :new_menu_toggle - element :new_issue_link, "link_to _('New issue'), new_project_issue_path(@project)" # rubocop:disable QA/ElementWithPattern + view 'app/views/projects/_files.html.haml' do + element :tree_holder, '.tree-holder' # rubocop:disable QA/ElementWithPattern end - view 'app/views/shared/_ref_switcher.html.haml' do - element :branches_select - element :branches_dropdown + view 'app/views/projects/buttons/_dropdown.html.haml' do + element :create_new_dropdown end view 'app/views/projects/buttons/_fork.html.haml' do @@ -29,44 +32,50 @@ module QA element :fork_link, "link_to new_project_fork_path(@project)" # rubocop:disable QA/ElementWithPattern end - view 'app/views/projects/_files.html.haml' do - element :tree_holder, '.tree-holder' # rubocop:disable QA/ElementWithPattern + view 'app/views/projects/empty.html.haml' do + element :quick_actions end - view 'app/views/projects/buttons/_dropdown.html.haml' do - element :create_new_dropdown - element :new_file_option + view 'app/views/projects/tree/_tree_content.html.haml' do + element :file_tree end view 'app/views/projects/tree/_tree_header.html.haml' do + element :add_to_tree + element :new_file_option element :web_ide_button end - view 'app/views/projects/tree/_tree_content.html.haml' do - element :file_tree + view 'app/views/shared/_ref_switcher.html.haml' do + element :branches_select + element :branches_dropdown end - def project_name - find('.qa-project-name').text + def create_first_new_file! + within_element(:quick_actions) do + click_link_with_text 'New file' + end end def create_new_file! - click_element :create_new_dropdown + click_element :add_to_tree click_element :new_file_option end + def fork_project + click_on 'Fork' + end + def go_to_file(filename) within_element(:file_tree) do click_on filename end end - def switch_to_branch(branch_name) - find_element(:branches_select).click + def go_to_new_issue + click_element :new_menu_toggle - within_element(:branches_dropdown) do - click_on branch_name - end + click_link 'New issue' end def last_commit_content @@ -81,24 +90,26 @@ module QA click_element :create_merge_request end - def wait_for_import - wait(reload: true) do - has_css?('.tree-holder') - end + def open_web_ide! + click_element :web_ide_button end - def go_to_new_issue - click_element :new_menu_toggle - - click_link 'New issue' + def project_name + find('.qa-project-name').text end - def fork_project - click_on 'Fork' + def switch_to_branch(branch_name) + find_element(:branches_select).click + + within_element(:branches_dropdown) do + click_on branch_name + end end - def open_web_ide! - click_element :web_ide_button + def wait_for_import + wait(reload: true) do + has_css?('.tree-holder') + end end end end diff --git a/qa/qa/page/project/wiki/show.rb b/qa/qa/page/project/wiki/show.rb index a7c4455d080..dffbc5d60a2 100644 --- a/qa/qa/page/project/wiki/show.rb +++ b/qa/qa/page/project/wiki/show.rb @@ -5,7 +5,7 @@ module QA module Project module Wiki class Show < Page::Base - include Page::Component::ClonePanel + include Page::Component::LegacyClonePanel view 'app/views/projects/wikis/pages.html.haml' do element :clone_repository_link, 'Clone repository' # rubocop:disable QA/ElementWithPattern diff --git a/qa/qa/resource/file.rb b/qa/qa/resource/file.rb index effc5a7940b..57e82ac19ad 100644 --- a/qa/qa/resource/file.rb +++ b/qa/qa/resource/file.rb @@ -22,7 +22,7 @@ module QA def fabricate! project.visit! - Page::Project::Show.perform(&:create_new_file!) + Page::Project::Show.perform(&:create_first_new_file!) Page::File::Form.perform do |page| page.add_name(@name) diff --git a/qa/qa/resource/project.rb b/qa/qa/resource/project.rb index 7fdf69278f9..1fafbf5d73e 100644 --- a/qa/qa/resource/project.rb +++ b/qa/qa/resource/project.rb @@ -14,15 +14,13 @@ module QA attribute :repository_ssh_location do Page::Project::Show.perform do |page| - page.choose_repository_clone_ssh - page.repository_location + page.repository_clone_ssh_location end end attribute :repository_http_location do Page::Project::Show.perform do |page| - page.choose_repository_clone_http - page.repository_location + page.repository_clone_http_location end end diff --git a/qa/qa/resource/repository/project_push.rb b/qa/qa/resource/repository/project_push.rb index c9fafe3419f..37feab4ad70 100644 --- a/qa/qa/resource/repository/project_push.rb +++ b/qa/qa/resource/repository/project_push.rb @@ -20,23 +20,11 @@ module QA end def repository_http_uri - @repository_http_uri ||= begin - project.visit! - Page::Project::Show.act do - choose_repository_clone_http - repository_location.uri - end - end + @repository_http_uri ||= project.repository_http_location.uri end def repository_ssh_uri - @repository_ssh_uri ||= begin - project.visit! - Page::Project::Show.act do - choose_repository_clone_ssh - repository_location.uri - end - end + @repository_ssh_uri ||= project.repository_ssh_location.uri end end end diff --git a/qa/qa/specs/features/browser_ui/1_manage/project/view_project_activity_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/project/view_project_activity_spec.rb index 275de3d332c..d4cedc9362d 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/project/view_project_activity_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/project/view_project_activity_spec.rb @@ -5,17 +5,17 @@ module QA describe 'Project activity' do it 'user creates an event in the activity page upon Git push' do Runtime::Browser.visit(:gitlab, Page::Main::Login) - Page::Main::Login.act { sign_in_using_credentials } + Page::Main::Login.perform(&:sign_in_using_credentials) - Resource::Repository::ProjectPush.fabricate! do |push| + project_push = Resource::Repository::ProjectPush.fabricate! do |push| push.file_name = 'README.md' push.file_content = '# This is a test project' push.commit_message = 'Add README.md' end + project_push.project.visit! - Page::Project::Menu.act { go_to_activity } - - Page::Project::Activity.act { go_to_push_events } + Page::Project::Menu.perform(&:go_to_activity) + Page::Project::Activity.perform(&:go_to_push_events) expect(page).to have_content('pushed new branch master') end diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/squash_merge_request_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/squash_merge_request_spec.rb index 6ff7360c413..4126f967ee2 100644 --- a/qa/qa/specs/features/browser_ui/3_create/merge_request/squash_merge_request_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/squash_merge_request_spec.rb @@ -5,7 +5,7 @@ module QA describe 'Merge request squashing' do it 'user squashes commits while merging' do Runtime::Browser.visit(:gitlab, Page::Main::Login) - Page::Main::Login.act { sign_in_using_credentials } + Page::Main::Login.perform(&:sign_in_using_credentials) project = Resource::Project.fabricate! do |project| project.name = "squash-before-merge" @@ -38,13 +38,12 @@ module QA Git::Repository.perform do |repository| repository.uri = Page::Project::Show.act do - choose_repository_clone_http - repository_location.uri + repository_clone_http_location.uri end repository.use_default_credentials - repository.act { clone } + repository.clone expect(repository.commits.size).to eq 3 end diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/add_file_template_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/add_file_template_spec.rb index 297485dd81e..de5c535c757 100644 --- a/qa/qa/specs/features/browser_ui/3_create/repository/add_file_template_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/repository/add_file_template_spec.rb @@ -7,7 +7,7 @@ module QA def login Runtime::Browser.visit(:gitlab, Page::Main::Login) - Page::Main::Login.act { sign_in_using_credentials } + Page::Main::Login.perform(&:sign_in_using_credentials) end before(:all) do @@ -18,7 +18,15 @@ module QA project.description = 'Add file templates via the Files view' end - Page::Main::Menu.act { sign_out } + # There's no 'New File' dropdown when the project is blank, so we first + # add a dummy file so that the dropdown will appear + Resource::File.fabricate! do |file| + file.project = @project + file.name = 'README.md' + file.content = '# Readme' + end + + Page::Main::Menu.perform(&:sign_out) end templates = [ @@ -55,7 +63,7 @@ module QA login @project.visit! - Page::Project::Show.act { create_new_file! } + Page::Project::Show.perform(&:create_new_file!) Page::File::Form.perform do |page| page.select_template template[:file_name], template[:name] end diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/clone_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/clone_spec.rb index 6a0add56fe0..571cae4a3c5 100644 --- a/qa/qa/specs/features/browser_ui/3_create/repository/clone_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/repository/clone_spec.rb @@ -4,15 +4,12 @@ module QA context 'Create' do describe 'Git clone over HTTP', :ldap_no_tls do let(:location) do - Page::Project::Show.act do - choose_repository_clone_http - repository_location - end + Page::Project::Show.perform(&:repository_clone_http_location).uri end before do Runtime::Browser.visit(:gitlab, Page::Main::Login) - Page::Main::Login.act { sign_in_using_credentials } + Page::Main::Login.perform(&:sign_in_using_credentials) project = Resource::Project.fabricate! do |scenario| scenario.name = 'project-with-code' @@ -21,7 +18,7 @@ module QA project.visit! Git::Repository.perform do |repository| - repository.uri = location.uri + repository.uri = location repository.use_default_credentials repository.act do @@ -32,14 +29,15 @@ module QA push_changes end end + Page::Project::Show.perform(&:wait_for_push) end it 'user performs a deep clone' do Git::Repository.perform do |repository| - repository.uri = location.uri + repository.uri = location repository.use_default_credentials - repository.act { clone } + repository.clone expect(repository.commits.size).to eq 2 end @@ -47,10 +45,10 @@ module QA it 'user performs a shallow clone' do Git::Repository.perform do |repository| - repository.uri = location.uri + repository.uri = location repository.use_default_credentials - repository.act { shallow_clone } + repository.shallow_clone expect(repository.commits.size).to eq 1 expect(repository.commits.first).to include 'Add Readme' diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_spec.rb index 92f596a44d9..ad6426df420 100644 --- a/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_spec.rb @@ -7,12 +7,12 @@ module QA Runtime::Browser.visit(:gitlab, Page::Main::Login) Page::Main::Login.act { sign_in_using_credentials } - Resource::Repository::ProjectPush.fabricate! do |push| + project_push = Resource::Repository::ProjectPush.fabricate! do |push| push.file_name = 'README.md' push.file_content = '# This is a test project' push.commit_message = 'Add README.md' end - + project_push.project.visit! Page::Project::Show.act { wait_for_push } expect(page).to have_content('README.md') diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/use_ssh_key_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/use_ssh_key_spec.rb index 9c764424129..509a639c130 100644 --- a/qa/qa/specs/features/browser_ui/3_create/repository/use_ssh_key_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/repository/use_ssh_key_spec.rb @@ -16,13 +16,14 @@ module QA resource.title = key_title end - Resource::Repository::ProjectPush.fabricate! do |push| + project_push = Resource::Repository::ProjectPush.fabricate! do |push| push.ssh_key = key push.file_name = 'README.md' push.file_content = '# Test Use SSH Key' push.commit_message = 'Add README.md' end + project_push.project.visit! Page::Project::Show.act { wait_for_push } expect(page).to have_content('README.md') diff --git a/qa/qa/specs/features/browser_ui/3_create/web_ide/add_file_template_spec.rb b/qa/qa/specs/features/browser_ui/3_create/web_ide/add_file_template_spec.rb index e7374377104..f176ec31abd 100644 --- a/qa/qa/specs/features/browser_ui/3_create/web_ide/add_file_template_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/web_ide/add_file_template_spec.rb @@ -7,7 +7,7 @@ module QA def login Runtime::Browser.visit(:gitlab, Page::Main::Login) - Page::Main::Login.act { sign_in_using_credentials } + Page::Main::Login.perform(&:sign_in_using_credentials) end before(:all) do @@ -21,14 +21,14 @@ module QA # Add a file via the regular Files view because the Web IDE isn't # available unless there is a file present - Page::Project::Show.act { create_new_file! } + Page::Project::Show.perform(&:create_first_new_file!) Page::File::Form.perform do |page| page.add_name('dummy') page.add_content('Enable the Web IDE') page.commit_changes end - Page::Main::Menu.act { sign_out } + Page::Main::Menu.perform(&:sign_out) end templates = [ @@ -65,7 +65,7 @@ module QA login @project.visit! - Page::Project::Show.act { open_web_ide! } + Page::Project::Show.perform(&:open_web_ide!) Page::Project::WebIDE::Edit.perform do |page| page.create_new_file_from_template template[:file_name], template[:name] @@ -75,9 +75,7 @@ module QA expect(page).to have_button('Undo') expect(page).to have_content(content[0..100]) - Page::Project::WebIDE::Edit.perform do |page| - page.commit_changes - end + Page::Project::WebIDE::Edit.perform(&:commit_changes) expect(page).to have_content(template[:file_name]) expect(page).to have_content(content[0..100]) -- GitLab From cd4582e4c950e307ebfcca7036726eb482527235 Mon Sep 17 00:00:00 2001 From: Victor Wu Date: Tue, 11 Dec 2018 15:18:23 +0000 Subject: [PATCH 02/13] Merge branch 'similar-issues-docs' into 'master' Added docs for similar issues Closes #55194 See merge request gitlab-org/gitlab-ce!23403 (cherry picked from commit e9a10f425887309b28f6c72f18f587b22bd7c129) 6df344b4 Added docs for similar issues --- doc/user/project/issues/img/similar_issues.png | Bin 0 -> 68153 bytes doc/user/project/issues/index.md | 4 ++++ doc/user/project/issues/similar_issues.md | 16 ++++++++++++++++ 3 files changed, 20 insertions(+) create mode 100644 doc/user/project/issues/img/similar_issues.png create mode 100644 doc/user/project/issues/similar_issues.md diff --git a/doc/user/project/issues/img/similar_issues.png b/doc/user/project/issues/img/similar_issues.png new file mode 100644 index 0000000000000000000000000000000000000000..153430d4be733f70c7e24fb3392594bbf685afa8 GIT binary patch literal 68153 zcmeAS@N?(olHy`uVBq!ia0y~yU^&gez?jOx#=yYv)j5AQ0|R4Crn7T^r?ay{Kv8~L zW=<*tgT}<59gP!-i3tfO&T4CN6_p2dbo2xz>_2?q?194yM-q-I%$pGt^FTu2 z!Qlqsn%&0^a4gb)-E_w5^PkGg%eL116Ej;svnWi}YRA_`#&WN$LL+8oW%dbk=LF4} z!=3V+;ilC|R##PrZ#)Xo+xIMCIAX_`(k;R$%aL-QapPshH~b1^LNm@DVG0u#dcu?9 z&2W>+Q(zlg$6UU|=!P37B|9}8wy~ek>ySRsaQU$7!8-?nu1{>(?a8*&a;br}!@{GJ zXNgPk6tN4OHmESzVW43!!&t%~!svyO#k3`1QyN69o{NWwr7laKqG7@0Y!-UZ(ti7b zEh<|*+z%S-NBX-TJaOOx!xBD`bb-b8?2W$ZBG&x^r{hl?NLYF1z=1o>0^YNZ9oSII z&)j@Ovt`C98#cDOY__)C=UhVFLJ#@U{~UAbh@X>|!;<*f!q8yDz2E=;ZLsS+C#C9D zLcXf-xP(TOAj)oG&-@&S^MAi)I|4RUd_P!wZh-&%$KQ;Rq{8n7c1PR7nu-=@e;Tne_ZF$tZHa@N)CS5jcYihP|M zk|HN3gehT_RZ?JD+t_eq)3pHaQ;V^?p~GRaz=VivDl?{b;8KvSps;a`>6J;JG_bot z>4FN2$~05XG*u;B3ZytZbh3H3F0ttv4T`}L6b{R;P4Ijg2u{5V5?S1O4Szoi-+bR~ zcCWXT*z|W|XsN$(nc9Vo%{P|_&pc}|Gjh9L@9e5}m59e`3valBlmD#A2l)5T-21<_ z_?bgyH(De+yyeg_SbNiC@-@AEk7k(gY@X542hz5HSMb1MAE!v^RRN-|V3&Z+0%fQJ zzb(F$N}V?0*}U3)crAKT-onQet7b4eKWp>MLk2!Q`_9D#|J@t^dcV-=EZ>liS9=(o zB$aOV7@y0KwLZnUDJ?-XaI=7fdET7AUoQK*?auQ$*kgHWk>ZrMds=SJ2|i|g3q2V- zyjC!%m~r#!`oG%Kmj1Tds@Eve5hWa2W2)TX9{K&fQN0c?<1Vm(3KYgC&paMY_Gi1jcKh8pqnGyo zejHx6`yboyzu)hBw_Rk#UP5Q&v#3nldPr*j?|Id^+bo}J{+VCex0Cz#ochmax4&6B zJ$~cr^*hf^Qu!!k_xVk6ot;?ulNEtwUp5}U-65#_NHZ6lEFltTMP*v3_Zrrg`xT4rzWsdQ`0xM1-|s)m?EU}lc5Ct8D&4Hxxx2U8{z<5RePLm9 z{Qkdv)^9u2=VvkQ%%7$6=f~rIvy2N0(zaD4b6GyF*!^|@sP>J#{0`8p_h?7g^k zwY2?@2h6))Eb6`$Ix{o^)t`;moE?%PU$0!fs_54T<^HJqcfWn8-gY}tz1oN)_4?g{ z#cQuroBmd+C{4L3TYfKf_4=)SUt@Mmf4kwb-nXma@#(DD7oX3o{T3NrdNnk6Zt1m+ zv1K=pPK(OY{C)rbzx0lj8!H|JmOtuL-xk@wYxlcdr}zDSw>xe1;w;w*&(7s(w{=e=fmfv11&iQy$eDl`pQJ3}heW;mTx9jDx?mrig%WY5Y zx4&q1J4JZ+r%&E%gO~fYoiHnVbK~QoZC8ZX@Bg>!?e_b1WgiZ*-(J0bU)Fj1|9kFM zzu)`q5V!sfM|RmOL7QVQ*UT-w7WwUF`uwXV=Z^KP+4^+5VdR!0J1YOJTzoYw`s}r+ zY+dX3dp_sf*pN8yYOufU)%8n1*WN9?elxLM_Sy0_e)&9hnSuu0-ETH+`+6<f~# z$qL^dhKjY%KWF#*%{|Wf8H+k!RZOn^`E>fW$9>kfKAqOjSD#xlsrLWh@2yFHzg~~8 z<7Z-&t!3GvA#lW@qd+=mL!<7-BSPEGn%%y!`~5y?{Yv%!bBfPx+Kob~Ms3!UGdvwmOF zSNrSBM(cMw77K_!%-{J`Z1l8?3LTrxx5d* z{dnBJ{q6Sq_tx!trM3I_yWPfubIWdJemf%UzhgyjfSXlC!zoZb0k1F|SX>rZf~r=& zSGopg9h>d8DLOh>{W~)G&wtD3bMq(ro6Y3?x23c~^I~HC|G(ew8ZVW2zvuJ0*N?8N zO!f)dQSxkN`mPD3pH8Yv%Vm~4S$wf@|NDKvV|=V1wg|_>{5oI%FZuDY-p>mC_WyQp zvvcH%#}qXB%DQ+QX|ee8aog>@&EoMj7x(4~Jd&$=vG7pJGy6Xunz`Azbv86``<>R= z+`}Dl=IhkdzrVh2o~Z18t5rPi#m~ff%eUXF%HFe}VQwn@Huv-$kD#8p$CUUZi)oydHUf8*or_v=2JaMqtS zy}siByEKcH#1tV%uc!O>{ghq*z_+4l*W%ubahFz~*mT}S*KVZP7RAXdD~m0OK^_;pAXLY!dvPqF63R0DfW#nzgx=tP&eCAu+2^Rz$3w~ z6}yi~W#6d(|2tm%(WXP&MfYj7qZaTEr&TYke46HKneD|?|L^DWuP-hxJ}2P2=S-FE zE|1`}#rHBFt~`?R?{X@S;n}W|%f9BNjGfv0|9tA^_HCE1+rb@Naz}8d*_{IC{iP3E z#mmmGV`OH#(WSla#k`Q$Yq!TG?vQK}UnF$+jDQ%&_B%zVC7UGLD%!S79ec!7vHPKJ z+r!qw69Nw@2#82OTsEi3Yj#2tXH$5Bzxc`s*9pHb9sBz8`TYBb&zjxNF*|Sb`A6!W zeHz+Kl5GVYC*0)(tv5ub&%OHXPO<;}`?=fi=FG4CR;b9&$eVA%B77*=?alT0`mLw+ z_utw3y@NaO>95!8^*?-Z`2R<9`u|_g%w_9?-v#q`)NBzyvhk>R{GG|^^DRH_aGS9$ ziDO6dv7V3LgigEsr{YcIaH$G>Ptf(_D zZ{6a`#N;U(;{-2i3HtH?tmG zQvF>sXM5~#F}=rYMca+V{I*?~+o?Y9MsZs~aOXo+VP3&5#gdK1e(ti2I=8l5_Iu5A z{lUTJSe@kEZ@1k(c6y(x&2z&enk=ks(VK2C95xjc*x+yX^N3a1n-|@DKRQ3Omw2Bw zZo4iuFNK5C{_mH`dw)Kg&8nz#FFwz^s$&7q{2sH&4-zVSHKyrqI>-y(|9JXKhbIK$U* zC+iZ!>vM|P)-Rc!8}Z?Q*Lg#c&D-9ZMT6?X+&EQ?Cg$7g1pYs=t|D{VVlDQYjVN}uMYybC4dsBsP6f}Q*`|?6yY|_fqw;$c*Hodd`_pPLB=e@Mq zYu~Om`1pI@Z~2UR*2dI(Kc8)_Q=c2~!JzA5)Te2lA0&--Ty&GZdQweJ-$(4+lgE{A z$7MIZm>M3ZS@K7+?8iZN`5$+Z?)Xczbw4x}>-GHgQK!pIeSRzBkMk4GWv}0Rtv#*i zz4iM&kDDBLPMdizP&(Vl%)TpJvUp1%jYr1X;V+AR)Z?^l;d zx9*paGfZ7JGp%T%;k@MN%zx6>`(N5zO|s`otN59idv>vo(IMuEJCDs++-Kxx@vx=r z-OlH?md~$y)om}pCw3w;y>4k9)d&DH0PCgQ=h%~w`8y&VQrt<03WTAaaYn2R) z<>lih@C5Js^=kFomCNUCiq7A=)wlBXRm~lIXcbG84rArCtv6P!)Jgt)-hO`V$Ct+s z-d?^={Yu*Gyd?fR<^GD3ET7G|`)=oJKItz9tIeLzDURrWkb9(-XYygIR=@Xx?Xp?# z_y3-@_v^9M-xB^;=g!@FUF*($sj?Y2{w?me+oarYb1A$eCaoKI7M)&*y86{%0xIp1)aa&U6Hs6}_{sz=q&c;s6A?f;e>{M>G{ zQA$nb!!0FQmhQGScYZwXxBu1Ek<%$HIBDVXqhX%^W-IMK`g7G$L#4nu&E0>uWmT9e z{kh~O*uL`f;y$ZYeua`+)vS^v-KdQ9=ptks4-Ri}+l zZFa9tmD_VYuKMili0HK0di%eDn%78mc9a+>XxIG8_;Tk$r*3+QpSIxCQ%5hxT>p@F zXmiibz8M|%Wm_USH|=PS*XutnQ{2<;{v|0xaq`p4ACGTlyPednTl3W0=9s`UiGL@# zW)%k2+GKo4S$z3?jsKbSvKI^6f9-9t{CXug*5|Pti|VK20cVpApH919`~9oQ4CQWD zW{E{%Sx*1W2dnU3aMSofI`ttJr z^&e*P9j;UTncwwC?D^`j<2=`MU$>P@-b>-wZ^Iq=dBVkY9N}*a+bqhS&n@4TaOT3@ zA2x@0@=gA^C$BI#A0cyZ=2SnP)fk;q6SGFXgT<SR` z&u5Iq_v~8L%ih>vxzek%y@S0YVyT+q@nW8hI=VtjJ|Eb7rgm!j66ctU*1GyO*98qO z9nvW7>XkBGl@h7dIoY5ik7vF0g9c_Be-5`m7adV|)t~um{!BX+Ts$w|WA{4$eewS< zz1eR6Z{O#Gj%mx+M$eBpw!hu1RpOX|@3T9%v)AuE#=pcEy~Q8k%+zj^vF)8ry}L!` zhxEvrXHstSy1eG4YD(P7wPyM7?NPlm&%)Jryc#%Mm$n#P(v4GDV4**iBlV86)m4tv zJCnsuS>*BbAKde4q8=on)jxNu&vs?l*yH(E@Z`0~^tn;4t1HlQq054soE|#a-?ReQ zTo!y4IMA%&_vl_#(b_p?Y>X{W>i+&Rb-U6Pj8RoiZ8)+i?dbX=t_w;9U;I6<#J*Ph z`YDVk=xE>w@muird_b%vcdH0mp7uhHpN*^SoZq@LG48C9S#LH1(C2H@YcV&JFu`YG-A<+~;Q#zB+e#lQDiTI1`@u&@Vg={?AZ)*sT`@c zRbMhLt?7|U{&s4Dnr~2NCoBx1f$6YVI3i1Ib6%{Jx@2c+@8QsmpfMMRZp9CW^V8nf z-%r}KxCg2fuG66zI?iOK(Y49kTSvRwT^v;4EXWl&aQMya__KA~&PK;i&fk$6vdT*l zC63;9FceQQ{8H3*QtJF-okvqZqb}MgDiFEg!aL54YhTLlv#=nQWYGA5h$sk6AYg!p zPWE?S2L=>f5WQehiLoSmOBG?|)rtl$6d zR@IjmiLtxO)=r-KI)Bf}u&6@T*`?DWU(H$nvjH~#OS<@JO6$>E?@RKcl+&U zvvaNDq^2GTm3g-Pe%qxjveX`vC@As<9&YE7ov3~!*Su@Xw1p6df zzu&X@to{E#Gq0Bhp=WJKQo3c-m?qt3S@tHv`uUyDxxHJjZ9Ti~#;s|wiK@3tzuUfD zyZwIQz52gjr^l9FH3jv+uXX?T*598L9$!3nA!{GcybyQ!>OH*@hKu3~Melz(D(?Jd z)#~+I^Y{N=_ams=PR^oW!QAqDm3mWjcRXk+dot1emgVy~kN@9%e&@XX|D5#swc8X| zZ8iD*?RLI%b;aSjpHHXHN`HH&`21Gw^?Now`*`W!zCWM5tH0kZ->ZAgrjbjj=2545 z&ep48oBi$oZfUx(R{cbD{@&F8zwiHl^Xv8c^^wc=|9mDLUHkRw+kd~`uaBJbwRgqF zTPardxm$CWoQ~MD|LwNhw>;J7hScm*JKifRzh@DVw$^F`ZSL7F%@lY1!M->$gqAWApU+Dz3#rox8W%lm72hVAKIdZD{o3;1>pESp_1piu5m)!~>8wwyG*?u)e7oSxAGtnm@0(q( z*BP^{i@M2g|L4J)B=yM^`ulz)fx3uUQ(caJyt2zzsY{_n`JP*Lcdqg@-E8Z$GZNJw zkBYwq^#@|kJqp?pk+ytCY|7EtXWzt%UtSH5-@3Tp?$)K;eTGKm&*zp`S=ESLJtgoU z<8mhZ&+GB^cVGYbe!qTwsL@(Ixw?==em@&|vboei9n9rF4>0p@iHO@;w>;>=Lg)4> z=_h-GdQ-RF&3c!AX2a3<+m3my*1VOP{519>sAg#3*uoErpW6R_`R%UoGcvvwd3N?z z{{6jg7qY+Gd~UAw@145a?_G=g@tpfa?cev?|H~Dvh%NuiyY0;&M<*zj-4JxY`N&&0J341; z@7?0}wXGYTu9K}fk!Uw(vw+2$oUL!aef!fO&b9pAj?a40wQEb)JU_HIr+sdj;V1F6 zF?S4o?kG(&s42Nu`FyLd+07&SUF<)fF}913JU`F&?alQ0rhVqObBx!E9}4^ZRDW6M z>9?2t?Q>tR+1%#~>KC2X-F{=Tzg?!gOkvB#k5R>EO`T=0ta}`Ky5@4A^OQetHlKgf zXZ^0=9;k6$z5d{S&D?(5Zw2{>o=%V7r#U(I%9ceHUoUy<-(1)(7qxkdSZqn)_ZXWO z3!1qKFWuAI@u2BYVfNjJlJ*}CF!MI*L`COFZ_J6jtrxpXLN4U{-S6+Mt-8Ih?LGRu z>$Ypyoul7h?AXTggR#SGuGs0kJs*#Ku>3jI*XX3mR^K(E$JNw&!z+E1our?z&&kqR z{Wh$)KDkY|Zo6q%RMzxf*Dz=_U+Hq#+?o1%&DLeyiSDwsITCW;W=?0d z=)M*g$1cSw{&rt|X0*TYwf;V5^BwNo^LxK-6aGCnr~2K#*|K#n6w4m_ZoknW{!eTc zM|{?dCmWB?e{nB6Jf^Jk>)q6J>+gR)b04-n{>Spz=i*~C({J}#=j5~h|L$GbXQt0uqQ^x3a0MdR`W#ro>}DZ9TN?zeC2`?>z*ieCM= zK!&O>8;|$y$rC#=Ra<}mmA!Ab-A-J7=)_W9j@ za}H1Lv2tiR#Ktf8=JvBc&DW)mP1o9UGAuGx^!4@i^WSd09%mOaMSsPgs&g{g?XqPN zimN-8ame4!+1xun`Q9#PKFcG|W+d~)pJ^yM9)FkHd}-OgKcD^k`#;>>UB12adhGUd z25xPfmrv?Ft!3Yxc)0CmRQB4Z&P`$*ag#ZOzuzhDul{f`Zo{6E7c53wT91m0MP(?8 z-?mt`ho^dB%$v`two**8&(B#r=CMC2Q_8WZVpri2uEpWmo(lv91qgWpd|kBWw` z5uWx~ciW9c1$=3@bGOe04ZeT|?{~OAZIjN6(D?lO{r>lBex%O*q`&n_ke<=w+9P#g z?H!8#Q)WI~u=~xXZeP=@A@3Ic{QLd>?&s3iSL{Bmw|mV5{<0sTd&}S7GyC~ua`j)i zx*rc&H}3a4P|x@27FVkEzaNk9KJI(|+y4L0eqJe)6YrnROgzDTY_l-y?MK@jcQ2{c z-F~OY?CqAzzy7pxOuBe#so>!y+n?SNcq^<|ez$b`{X^CLB`f=X)Ep35f5uaN?v-gV zMV{4vJ|5@3c)aY(jpY8H2FahgpW42@qWsw?Y3YuFx6fwhZ~J;Z{{HLYW?nOmEia4S zD#@A`3V;G`+skFM&sFAay&C4WyF=`>LBatB@#~e>D#RZBo>fr!Rc?NKoyUWpPb2qy zIK<8CKfl-f-i`V9Wy|kuJoj6BS$tOXsy8j5a%At`GXKJ zxS$HQ_xu0hCT2w?xBE{@%Fn{Cf2d=jX2}SDb!oYyG<8zkfKguFu>vA@SsM?y!@;rxfhr|G4Gp z&gYxgR&Zp^;(Yjd-e;R{M;g_Y4*#xv_v_2c$Ei=*oTOZH>U*1coxf_zp4sw0nQQbRIdkWEn@^Ij=a)-AeYm-8m&MN~lXu1h z-qy{VUiqG--{Na~&8NJ_pKF#*4f`Zt@$=7(jK#e+A*!W54*TLi=_qaZ%y%?7Rt?%U z@KdN+nJdN}e{IqO-DxcRYg4A(eC`z%S$p=$9&SA!r}mW-=06RKv8;UaQT@-4W3%)8 zp1s}~@bH(v{ogrf%%0nLe%Pbca=-fi-^mL5etvvgerM*I-H!72<;`k#EEn9z@uTnq zkN3Ynul4Ug_y549^d3i+9$)(f9-zBHFP7U{ztNdbUzx`ucw2Jzi8|w>fYdn3P&8Xh@ zsr+Rl6T(-Afs5}YO0PvJ}6!l!Fu!Pqu=$w`r@+1(Rd1b*E)V}1#9X?}H`h1aSNa%>rb0I6WlShR8-|X?Q=IQlodY>X$Pl)v{B z)Km`M*5_=Ry zUby+`wPS;K(~Su&e#uU88tT6tEwqk^mRq=2I=P#3K8h8xnouWW^~UqX19it4AHQAO zn0#D?NAm0KrV9`5G>PX5Sxx3#)2ZB%Yj|tb?I+)E=fBT2t6)`0)N@J~JQCHfU-Q%7 zN&Wog2F6?=?L6s?>rNPd40!jT_f_K0V7*?a1@&bWZl|{@-pUv7nykR0zL0q?%fnNj z-K7sTB|JWEGksz3n}-QMzTM9M{q;s)lAQDMtLLBFzILqec5=Ubc-kYOXE|TK$sPHr z!ZE?~g@B{^y<%w~>pO?K`%rn{7Z07#^mGXgZ63J8d_#d9&t*@W@ z>~q()Bh~E{73#^EYBJAlpI5&5Df7g5vdOf_w3#Y@J_L9a&#(Qa$oYTGlAM}zpLiy+ zAG%+1*|%=5ke%Fz`S#+mB@^%0|9-n&-0!klhy3bqkdo(|@p&80`GSdd-shR;ch}5c z^7ezJ)6O4n7XAISlW~4gs{Yk7?b_#8zi&2vU%BFov3~4-M;6~h{kfby4+LKC7ut99 zt;W?r9bleeWmNPrBp=?(;2} zE0plVX|vR#tKIthrnDqZJUQp{nfW=JZtkD^FKOeN^J@RguADS^c)#}hUZ;P*|GuA+ z@}K$t>*G(47#*2<-D&xcGn>zQ_Sw9ep`v3n;f-*MnNC;gLvaiHbH65wo!(LR$WvYY z^O^k#MF$+&)%k6H1UNRF+&xWwTI<5;o)TWOWXcb9w*KEM7O%DQ&#Bcm(N8aZWmswd z@OqZ`fu?kiS2>ef;tlsMc2YNxN_syjOK^=7P(TE0d1TZV1-&ER(niNg zPV9D|&9fNQ^Hot79?jFy+ahYAcq}h{1pr1Q6 zB#s!dtUn~7!Z|NYFXpnFcBQ+Epx(8MyykZvWG-R-GBa(KCa2u&R+CHCAMc7C-Lz-Z z@$&4P+ebomrXBqrRukS*DHY4JcwJ@w#d{BD_c05K7wTRs*9osVeyHj9%LI4lgeNi| zUA@Z>d_KbXZsqyU(wDn#uPIMdeLMg6iTV#k-&Xv1)5`c?aI#kAe5DP-?DL;W95Q|{ zbZ)B9=}(}lo`ds<{GM=I-+u~|3iP^EuNas5+)aMcEuZqJdXtb{-DCUuCii9addE!; z7ZmyTpAT7ct2|3J=kaIBJ(K^Rbe+_)^MTFX2Z3*&A96CTJM%N6GF3e$?DpC(bH(pF zU#%+(`(!g=`;8NFST_Hv*F8={-EDiKf80C3Z?r{MXWPoG zBSv*=9v4sl*7`Bo+}=##-$}?2ipzrF9|hTA$?GodhyO@eQ>+&fAE5Z7X5BfnyGh#ehqnF7TK#Lop7s0wrS0M9x-6yd@ajmQyIkJu zwcGP%xWCr3{&!^Zn=i)aH$~^|QRMNTaqLvAw`<^yr9Ky((oY`JKWkQ7P~5-m_`BUv z>s`e^9?p7{R>5|dZ{}&$nw=dNe}2$k*Lp7GVayMvXTNzkGyPs)TRU6*Jj<@iV*)m9 zGdD^wI2TCB9o#VOLgwZVt#{k!8l>o7)BgSE{H6I(g+nhv#B=5IjtdyC*W!#Pa~@6MO$ zl0ZG-TWb~ypE|gkp^qC|*CzH!`dZF%8Sg>ETk@al zQZlsO_PrEty6%;z#dgn|XYcV0?jzIX{=F2>`l7zCzeDf+&$C{ee#Az2{#KW3yK($G z^Ld7!98S(hxu<`yIWT!8lfko^)cNI}ny0JJ?OZSO`v;GakEN8eVe|1)n=kM6wm8~# zNBU&^`0&u~jE$Z1)K8s)MlLhA9Z0tk+g@`n>FU1VzstD(e~{}v_ODZYUPPHA&%W(b zwX1uy_pW_5SNwKXaBbPL&nN3v{!0H*Uc2^Exl_;l^Tqr0Kl}B5mN7o-G3S_SoA&lr z%lp|s`doh>I>c}C@9xA*?TYCiXDUNhL}%=0ndPg)9T&0flb7}_w^}ou3-i^_L?2?m z`#ip8qUJPFCbNX}2M50ERxG|Ly?)=5&kqDb=R9A-cyU)lYe(rDL-(Ie%;oos*DK~E z&N;v9nD{FFwwgc>vA`Fvrxch+&se+^wus@-ho=f0CJIvgKj7<=pgr z9qsY0wl?t{8#MO)bew7b;lPY)Eu)0p51P1l1%y7k_EB%5T5;`1`wF)obD~OG4(Xpi zw>QS>;N}Cbl`AB#bef-4jPvMT^HBU&#jZ!X@gbMvxs;io@i#NGF&~k&T6@vUaIK2{ zlE`fD<=%H9buOLf|NZiD+mq$9K7CM?X;jv|a4X$GJ1=)3;?^>ZsJa-j>k6&fHyVrtlZKCjUEWaOI-?{h#v=eeTrg4*l)dTR1IQ`tXv| z(?abHW9~egYTM?Wzq<0d>6W!&LC;F=b$w6%>n;}KZ|v2+UTrO?n0~j$=0mNaw~qEy z_D2tnPc5gGj|TZ6+gV+{z*;mvx=~P&T*OYCSSpQ3XdbdJ??j| zT~uo~qv~tamWxHkcfVZT$spL4c+2Qv_<45usvC!DlDB=Ebu-SbQu625>+!i)O|NZB z?zg*ijsITinomF9ZomJtJ$GmJk=wh!pK`olc~)F}0dvK>pW;`38tnuvBdHXR5oy`x zntL_0>h|UHHrefRWi5B>@86ZHUs2lLhza}xw)u(0oi`K*9FE^jJyM5YWhryE5 z&7WIktF?S2dQ|h;eJ>twwT4HU}1bfa9+MYJ=SaECB(shfT^Q^v@G_m&Av5IvevzHh<+9axm%)&F(+>Rzv zzZ2hCepk6ue!upw$-MNhrmq@Hy4G&I*MIb7itO=S+SmW>U($+jZeYHUImyFOJTL<5+BwUwOW=@W-0uJ^Y4ZQ#(rJzTnGmEtUno+B|vFL(BHSG@f^v-ut;forXrQEZ@NLH3> zPrAVVKI?ZoK6V|NUa^lssbZs(qO;tgJ$7~Wl@4>992PX6-ypn0Oghf8WXn(1`44kA zifSa^+~2={y@aURi_-iFdrHc?NHK4!@d^$fvUS+=pY_ z#bToA%U>n8xSx`H=JxT6z==b1bnbO(Z(XI<8K7SC(`8Ab1@l~oJ%48%ieT05TE*ks zd!OT{|))-6jDr+>KGpFd_4E$scsJGDf;hgxw7jR9=FTeov*Z?E>!Db{NA$v zr`GnTwhqz>sUa-3_l);^zU*dw=+Kcrb~xY#zTIIRCrq2Dn=~iCty~-n@D?@+T zOxRvDzw(cO=ikkX48NY=9Q$YQVyS&k_TMUJatT@2Hm@*;ljr8>8H;s%KK%`y>scjj9h`W> z<51SLty>?McvbU}Eo|*0smaaLH$CW`#B%Xi_^R%oX;(KWB#Gpm^lm@OFyqUd z8uo|B!-ML zJin65LmQijmWDlTd<(DpN-Ueq@^Gm@Tl&1tj+q`azcK7qF!<$_&f>McO){S=X}&(2 zqihRbqD}0LW1NQ`FF75fkf*k$-z`$pUm*6;%9hR>EA`I_n{#_z@LL>uTP;%6sA6U1 z&z1hSTs{bNU;Oz{B%ujO?jtc)_f4Fc%lXB^CCjKY=pCjU=m&JU5@78z!9uwFGa-LYxME4A}7s~Lj!?T}JCA1T068&p5>8-;-`DdTOQtJW`4(S|4!xL z=97`rW<9WfZ@Iq3_U-&~ky5w4E%J+N?EOBR-)-3u`Ojyv`6rLN8xMGGv9U9Zsgkba z`A~AGMCj$^eerLtP5X0e>}Fn=wu;Su zx92(Igvj^Xl5W(@YnQ*c=gbxRTwc44|2XF#-~J==Y_+<`^F~*>h!VAH-U7S+e75oX z5br71q&{=~iPK$&jvStLbnT;ZZaevm>@8mv7Kx@i9*3-E$(`fCeoEX~||Jiz9hwNk_XC_gt^}_RaC@eu_>{ zEYIYtC|}Z_{EPRlkbbUG3CHTLRU1D|p3eDfyYhNRhZVw8!e#HZUa{Tpk$gs3eA?Xd zeCIu)rzJld1+s57+hch$cxlb&TU>9arZ2oAWAwy6-@{YjLG7WxL8)t1dcW+A%&fQtto?N2zt{ZIM_SKAT?MwDv?|PiQ?z`a66IuV~q|Y;acI5GA z34ia3X}^3}19$g+XtMd8k+U3)d zy319ZFMf=R%G>$$PB+*2PeE_j{D=+kyt(<7-p4D?=T1MaTDv!7=H5;AT8rKI&3VDiw#04nM|9UO;gCP$edSiqxuTVP#_K-wa3-cIKQlQgbV@_N z$z|yxmWMCTe6T<5RhrdxxX9l5->Jx*B|Fv&F>W?&F}k!af6v#w{U*{$ORc(VCb|hE z`>D0r7|!SXT>a5?hT@vaX=0_H4uuu(ozf7c)wgF`kf*f!0gdz$n^TdhnM>ZE&*F}( zJYmKDJ?MO`Rqvy}S)Wh*J^FHbmiNmoTAAWckF=D;JpK0h)!sXMzwVqCUUuX~lH)E5 z*-tU&62edJUK=A5qrGnXnh%k=2HG*nb5^V59$8W}U$e6CfYJJMU8kpgpCjIW-s)WT z?WtGt<8E%cq+7o3R(aOam(QneMGn~TKF^O^y-vl%%zI>EaW2_uhSwz}8Mj$e3w~RF zxnI9ojNLOn-Cm#niu0WR+kV8&J6n{LUsxgA4PH*PMV3jp#d3CEw)N3K&s*Az&vq|- zd`!l1&5ZDq)Aw9E)uo?XaiKLa=@(OYs;bd{na{fn=Zk-?Hf)cSSQi$-yY18qkr+^| z^~$&5{F-}->r|fYn6lM|siyzHMR9cNu5a0TTF~B2@!F;Y-ePyN=^uRz*%R*Z zPdPi)eko+R+l5^m84_u)SLr{6RDj^+XwZQ%2z!Ab=M?$w%N?BBS%PS*7vbEDOcs;$ zNbl8xPu*Eu4jkKKeWY8(A{TAQY zcQj zO!>UktN)gLyne0nUf#9bzbm7{8K>TMQw7c4R{#BaJ@?6pi8EgsFqW>5+gro*;tYco z#sh7oE^oKzvp9{?zS6Ayj~@DR%|qT^eI2*N$&mGy}oOlKghf`Ne`dB1JL zN7Y@ex#QB6bASA6UUQg5c1`yDl{uf9({clL@$UWEZ~qUxDWvM#o0}I_oVxe_-R}3d zYCfNRzIxv@-iU)omz^qRja(TyVS0Ss&3QGSPIf&4?=pP3box2o-?#Jk-&C3GleFdw z`tJG+d(gVt`MdI_s{Tzq!x8=P-QC<9FXG?)7rS$&FQ#VsnW8x#ZcQyad0=<$s?KE_ z7-z?%O)h&kO|ow?Xw%-?eZLjM-UPzV0(f_AZL~RPnS^Zdnfp$6Rs=2vEhH;HKgC;b z=Mk&2HTQps->>=H8(Vl(6tuAKreeEHkdb`u%R`_w4AbMPGWWW&KGTri_g>++dwIo~72@ut6gyZ2mimm>zVOYYB{UCOul{r>;=&e{L3v3|K^@~JS* zx37@Ybb9qWdEIivm7#Yzlua>iI(Ph)}@0^Up*t^!qmRrrNy}sqYHT60`lMnm-?pzn-)D=)u_XyQ%$lzgC>J|Nm!e$GWS>4i@)L6*{%U z?6l724Ij%J-lzO=d{g&k}WzJ4fdI{-#^~wVglb`Oj9vCV&6&&RUVFFa^SO`j)_ys{BJ7g@+LTuN>*aE@ ziVqLY++MfynN)Pe!&dIYVjq(nQ*LK2pZjL_`+b{VuiJgDbq{F!*m+;er&Hwk4}XxW zdZGCH<8k@ii>~5d&(&OC7yGu6UGBreN}kp?mzH+RRy=4dz4Z6>`u%T~&CdI@$=~+t zmAJ5X#|0$T?faE={&h_8+0<_ReLJ2rE@ViYxMP0px5&eX(`Kel`)J}_d1vqcf4|Fa z=Wdsj3jysWTf6mIRGt3MyCs)>xnF{|#+H4#=zjg!@*F(m#`?cRK`$2m^x82Ip zUR;-0cwDx8$8?GB>o%XWDxGw0mHM8^9{pzSzZLH8d_M2?2M*^qk8FxF70;BsJCl<8 z?Bo6F_j}*14L=vnQ<$;1*KE`7_xpDH*Gb$pUoQLS-_F~;_TszQmjy09pHqCUiT%FGWuM1PGH+*>DL}@nAsIq|Q842- z%ah1!-(K$so&Mpe{6DeNVso|XIj;P0sh` z`RJ|FzJA+p5#l@JYQKi=XYW^Cr&wUHXUmPa>bIui7yIo0RopH(%=>m)bY5X#OF>6| zM?7d<9yjBX_6^OT1x0a{PesMczTL{!|NY@Gf9#dd-IDbmW;wCkta`on?q$x0{P#XM zwH&-x`CL{!s*82|MgRXP`{(^#+WYGN;$BIMLlRY%za}P{{aUziUwqA(fV1mXmu>G1 zdzlw&KFdnkJgr0ekAABC|3901Wv#arNFK~OGsCd1X8{*?g<(v;<;kSEyfPLSPBXsN z-G1j1Xz7!a%+gnxt5z=C^!MBC^QP+b^wL?lt@=qNk++5uD9F`F3G;qD`a=>**Zl3d&#cML9?P_*# z&w5#W3vJg##%@r>ad%g)u&VU*KX+IDOU~K%UEp5ojTu6TA6Ffk-19K2;+RYRyqC*n zuS*I$<68D~YPeL>@$2#Ru^($+HdF|J79i+JC`c)U6!7)y*zEmq;?Qfhg-;&$+m|g| z8NA%@ouS!rnc^QUk2&fqPP!g`%(_w0dxf*lL2WL7d6%7>>T@~cvgJsTCT_>?sm5@#^z@2N~2=_+=d_1V#^}) zled^2G41(wZi4$BiRv#e9xgIvO4=Ckv~l(a{zH~O58Qs&t-r6}z1ORr@^-YHsS9ca zE*PBo7I=Q`wkfu|&nNo-|JPRg;c~iJ>GinO(}o2~_kF1FbDdrL?PhI6 zl8xRyr4_EqI!-c5!i$6t^LjqteBQ43{bmWhy!!X{R~{9dy8mAORgy&Uv`C4r&UVRZ zcJm4*dgjE;xPRuD%D3av`;TRCMITv~@n-#|Q(7N4JjyMslsMM?Fm;;PpGyyS#I2jR zL+{*{6(fh0a`lFp$+n#V7rfK?me-;-mm9ZvIwVEjUUS_nc-1`HrigE6rOO^xm*4U-o+5Ty z$otJA0k-H3$A2VA&Qq%RtRUiRbW+9cNpC2tW&3gerETBEiuDwWbhlh^ntIPH&flj_mh{>pbjEUR zp1p4_EN%Y#^W%#B`s@qWT$z))a93@evCSE)^XC6fEw6Z`cp>pky5u3nrbLrlZnre} z@5M?y?d-X+Z08bNp4BVWUrC$Y&fi~a6?wls_EzzP#D`} zxV?w|dHtK4tTnB-I7a%zU2C(*>7BX9E04d=QSLE3Bj9haCqnRGFq{a!bxh^4_$< zyloP;&RLNPO4}}1*yWv`I#cm{#f67UU8R!^n>D6QQajum8PQf+9zx>zD)c5z3{cHZtdb{s{+qR+)Mu&I4xS4-%i}&H52lv-JUAntssdLV* zy!!QWkufn=7cN?N)b2@JWy-?M($FS#NZk37K-QyGjYm4oxhKzge6nfBAwwnc&vp+> z%WfpL{|q=K8WwS|b&A)g#^roT?83j#8=tp%_fYhG@($VO`n%s4+4om;l=HVGH1BA8 z;j&XOX2xc%(*h11vyZY1_(!-X+WLr0?3rrnz47&?3o6$t=dJtp+cq)jE2mY&_sh@C z+MuYCOqiueF zyOGTQ{HRU7`uv(r)z(H+w&ma7H;>gt<(X?TtM4uM_xJY3e(-s|e%9ZjN;jKbKOS}0 z{?KO%`%=>LF}PeODIkj@EpBG{jYRhS@_{|y+888qKc6-K{_ULBsx1q3^mj{ayQJ&f zGt<5Ae+7S7_7%-Hm1zR&1wTZbHSMaodTjXzcm{(o*7iHJUx;)sp3v#gt@a^B;3S_! zLEqmWzt7M7IcL{vk+N@}e&1eY+-F}|^Nd&bfy(6b%1tSiZ!S3Y7h5mg+;!dC^sw9K zcd7R@p0yuJ=5@A7$}@Z>)qTt+Y>(OpzSG7wEdttIhmF#u;zG}`hMse~`+G6};Xj}M zPQ2D@d9ul{J+j~U`L_G>f1Pa4>Z{6_@%QUNkJ)b?M6S8rc2hfXn)l)#QDT=T`&pfA zm1ePDcYNW>m(??Gckep!>Bp%q<9po7EEh6ljKAn>_gYBSt!z-wUt4^fvxk*IY<`v9?b1d& zJC@C+3<+E9_v{q#+|*)pYJ%#N!hQRkB3D*Rx^<{a#|878Ptj1iXP3F!ZH40+4{paJ zhh-voj&>I>UHVw>-tp+1J1aJRJ6x6j`^jHfwLj^6#wve5%(pz%GUa;agv3X7DmB~dn+c+MW9=j9p zGO_Dyq>b9P^rzl7XJ#C*KOMYE@#o>{-imJ4NkxTymE|qHmDMeOEi zz~wXh>l=%UBSbg18|G{_c?jEbaK3ulU>I7|eW?G+uIhF;{5+%pjnX0?q zZ;CP&^Fc0YOjA5@2}?1?-ah<`TW+@@VJ@6tF}$oJnpGJH>Ka^lSi&{9`i=f zU;=29$*mh3lW#j@hO|6W`Eb_!{*70w*XMn|UteFGw)j~lzr5X@`||!aA6?Eq&g&M; z+x>Rixz)PU*6uuYC2aoMXOC8vz|&%s7%1_rwwp4Whl$_*&j#>OJcoIVZ#?SO&kOc3 zY|Y*IbXr?Qn6~xTE5UCkdF!nVEiucwq5(QX4K&K3`uNYw<@4XXSlqvjU9Mt5%8YLX z3+w;?EBkgcJ$jN#>!W@De!c$os9XQm`~CmpET-Q(xl6rv@5XQKe6p`9RrA+goz)#% z{PEYrcKJ6?r^jyt4Me3yW^lf3u=()s!QUJAbl3a#OBx@$ufBfICojgUpiQLbKTVIX zi?moi_Z5f9vCW~ed?Hb>m~&u}>Tfu*=~(jW8QBgGUM`=%t@K*takV)GPP?B@i+*!b zef}2ZK8r)|_I&n>EDx{Ci0r? zOvdb*Pp{YS|F*~O%LQlCzMU@@W$Tssh9BCcsk`gNqIbPj7aZBI?!C~kc-sX&senIX z<=Jtw-(6bTUHj>zI%wcV^wYmLo6rB+{O99wdGT|Z%dMDtKjwr^XKqED=Gb^lSz+Uv zk2kcQNeTRTU;qF0Mum9~e7Bv_S{<>!?r+Zez27!{zgK-;K$neACgbyY`~9+IHxgS# zKB_$E{$qAK=kfD@KOXa2Kbhd1(`Wf?!_2f7>$+b0_snRDK5y}k{!d#&ttuK9bH z<1VMJTIcpIjFE6In;w;=x&H9;dDZ70yPoLa_m;J+?m{G;ceh)cr%? zvV_^*rDx>|4ltHobQQlDQ+)R6yeUttb1QQn9p<;+Qv2=Z@wAz#V(Ygz^V{usurRzU zHtb)9wM{t3%!_uv-x%AMACpY~vGT-}qIJ7otup(1CAd0L((d%;ZgY)A--7*ZMHfrt zN9*lpIi{V{E?c(YAUl)r=VEp~_`F!r>{g%%p^v^#y*!(wUXN_2% z*2d=LYKQk!=6}$+m}a@m?{Prcr&F6}oAqtKk<@)?rPq(ocR*XZ{`IWicueZs-|zQt zmtK#3o;mSb>h##Kj`bDl?`5YF#&*NFy>prGWEVq2Wa80`Q`@bUh3vG^XK4+Ev@TT^3yPw+OZtG4%>PQf|;2Fyy z@vNB~TRfN&IpT!cjMNfuqzYNxFa0EOWQIzK(PV`%)rFg2o0+kwbJDrF*6NNr9!|$^9d7r_RIG{H`DtDI!sT-5FI?0PChO14+x2o%<@34Q z1?pc|{3^ZC(pMv7byS=8-Zv@mbu)T3- z)pTN}O#Ppao-Z_1g?$Vhg{-RT{;pWu=XFRRdVl)$*m7Sd_S@lClX*u2Po>ARDs zwR0K&Z9Z>Tz3HNxw5p@Rm&XbXqCpzr?;S;a4%uYYolol4oyO9r$?2RqS)t+QPK9G4 zk2+%x3q;$CAF*72T49fxV~K++tJn4af6u=k56Uu!0+RH@U;Gi@Bw@9tPOs$J-}+wk{g=WYR`Hkz*OTWs=J+%nn8c!Z^l{Jo=|OKB$~n)!0Bt6FKSSY4_3isP zo6p+Zdt~n@@U3ULI-w zv1UpY`_rczLuU7VJf17?`|sZ)hVN(o__Kcdy(-Sagv$4;4bqoQZ~b&ZFJtx=+Zk;6 z>HW%xTmd>-f%B*RmkZ9572Z|ue)PBbsjc%y+v(MApKe9y8qn1D{P54_r_O=Lq?l4~^wcW_Jn>-}$4MaWRo|e?#?+ z2d>YKA9PmcbY8Znx%t82>3MH1y32p(G-wtp+dWCT;9FC;9XD`TBps9Bm%Qb_OLye(?JEy8KRI`~BvG4hBbeU7o-* zy5Xu%`Sw3k*WdHONzs4#{JLGsCHJiVBlGCdlwiM^Ec(j!eX=E1+a%`Nof6oi`$u9Q zhge6o#Gk_~PxP{i{=8bfzUs$=n+F$49}+EG!g{eNNzy#^?&Rs$HQuni-?Lwsuf91v zu&F`R#&(j|tG{cv-}|(uZRaAc!Vs-#fyZvtahZ$1z0kOAy zS7F?2hdqmHFU;(9YoGT2;-(vl(?p-Im)fXvOmJ$NE8MeK;KZV*OXr6lljuhpI}7k;ntN!v4LAwi z-BtRz#&BZkJl4iz?N<$MnjWr`kUE^iz_XY~mX}+p&(NmB^Sj}b*HDBd*&^wML(1KGm3sG%7aYmpIm#oK^|4@&?qMJ2<%inyiYC^!S#DC&I2>=G z7rxHx6t8mIMz-_Hzjb&vChy?=20G*{K=G689tNF?6+bKg8Pvz<@PB91XOeF^Zu(q+5Vt^8~=6c zaA?`_On$gFV&|{tRXfWCuFt;o>0bC1<=oav6T@4Azjed{R)+qbr?_`&c-+m~^#Zr& z>b}1#sOc{%8qZeWF%HU%=2qG>-SSxEp0m~Vtbw=k6D>*wmUC}^zBE2ll3Os# z9nosea&Rb~c9mh#q6`_Pl07qL%oIHXI_1!+^Fn6YyOkRIE^t0MZ9X^a+{dT0^}k6t zafux@x7YZrUa{gw=(E&?i%W*%N;xMtFxV9%*3mQBw)6=xaWj}MFXw)eiG z$)tPUV_M+(7SHW3A22@q>~J)_?f0px&MPY{{iXX0jolTCRh2?gC5xMneiu!Olwf-M z`HbMUOEqanPtR$*5?vF2#30k}W6Z8P%j3rKYlHsruKZv0e!-0XqRO7ctc_=@lG;imdt{gBx4V9#Gu zrx-qSjz)CySFkqLS9fjg@Gb0c;N`r)_&EGG=){G0`~TN1c9!ntJQ*oCne+1F^;b)5 z4%_&Owdq!E(3obZX!I>)Mv6@rTLp)KrKRvTLa;XuQ*ph=R5B~HEx6UuWSGmtiv#_;tLCvN7 zBi>dS9851euh}lF|92sg>$B}r|EKScS8JWjj!T&s9=BJR|D~JrltUj@b-2wnZF{V>x;Ea@|ed^S$3Ihg{aoKU4Jd>GX6H9`>*44X$d33UqdV zIK+MV=9j-;Hn&{o6+UzPTZGJvD!#*wccUkD-ZX5nxTGmIz3aWMo!|E68+C^Y^5@@} zzoFuP0Q=G-Mrza2n|@Zm+j(4kmxunc3lnNS$z0T{tPjwe#~-m-!u1vhGq;#p!u(d& z54X6B3oAEx{apTdP1^iDQ>)np!{g*GzkIs&Wyy^l^Vc2T^Ig>b#DQ-4tVPcgcfA!% zkE=_zUirkP?^a;oh0 z|9YK@IQzWNDi`T=YX?oHujT9-qKnUUgQEYS`;3K;&wEYa(B(;W(Kwu}#^tYa@`LKW zkoL|!+|CA;=d%h5UF}%R!%lGvt4TXYB^_@qxM<OK!IdA5~n);q~Xx z`45M@dVaq=VDyDsUviJ8z_(L3?^VBldss@+tvy}L*-3Dp2KU@ady1aME@$q&&~c&l zK*g=h<-OapWLN)ewJfvAZSkylVA}km{o=*r0_hS#Qfdpz&TqE3BRb81yLg}F`({3? z6Ni`oKa!ZchAHypg==f7KYg0zXPmu%QdPTk6W3uGP2st`O>&s^$K?FO_xe_nmwG9D6?b zs-xhP3bsvQ3;sTt?Ehz`>zzL5Clz^{dVU?;;b*%kNLh(PTO}+j@-4$gyEE^fe^hw! zvG0(u>6!iE68~al>>moo9*Sw)mz7o}daCVN@p6NbS>F{8alMyqJEo+uME4B)OSz0a z;+)REGW&NyVt)Um@_;xw&-Itg=AMh*!~X5#@uofBMSTqKm2VOMbj*0#wmpBsKF#wy zew<&|rhCise}8}f{w*qK5_Qj5q3KlB6o%FPB(XF?)JloaE1*L$6KF{12De z3chs#GH$uxAIqT+Y%@8wWH33N`6w#oto^-n%1xt%#*^=eN5AN(kWef3m!7O;tXcG; z^8DcJQ~%o&4LDcpx+Txg_7R$!dQ|w2uo{O(tEizf zyGG@kjmK@)FID^TTuyBg-#jk4zCD{?Fr;>Zd-jeE8f!L5J~RJx^5nzQl|5J8nm0V3 ze6Dz2&2i2X$#OHc*zw%|Vspr_q-K&q&NY2w&C(h9$0Gy#6f`O=9`%Sl3-da(Cv;zz zf_73;rSPA0P!rDLVEv0b$ClKx`kxZrlldnmZm)2Mt3Xr4qo*CY6Rt`|>NM4H^uS`!3rxFL=HB8|(Rf71fiD_HCOt z)m|Xu1;JwbCXnx01wwo!=Lu49I}57?fl}m^G{o1tfxT1B!yKK zzZLYviV{LYb^L73WwmXY`C#vhTvHxVy)`A#Hk_8w5xng?um)60k4cW5}*Sa@pCvVg4&xxvMleDLw-^2N@k}dK@<9D{o zg}kg2k6-Q*{#F(L;mzB%dLs|6{8>S z_GyN8*iC)A)|hDSl~LeChflyEy$jvrFrFg7=)=wS3YZvE#utG3)Ln zM_l5Zd%faC^s`H+vu2kvU45aj-uJ?}jQKqEXE*7TMLx8+F7i}sdc4gK39+acu{}y3 z=Wxxf;8t2!oi3=yC#)AbuR^YE%T0xvBf+8h-dmaXEc3Eme^u?$gqlNrWv6N?Z|Cpd z%W8PIy=~cT&GYJ&x<}WF{LeZas8@5(T0_78NUZN{zvr#LFXbw{uXUY!xTQQwpmI(A z{eAC#9^G&&W9pOblfL`(^qb5S?kNjBwQ1hMtoak$wrnlg_vxPh%MCC8?)kF$)QP_j z*|pMx&pvmzibXEF4IAIYg%oPYb~|t@95CSimwwaqdd%a)9TByC3mYSyB)?x&T(gY% zw9C1dC+A$wyzZ{?_+M75(K}7k=YrQafQnvy^(lh(bKeHN+1WRB_dN9}h4s5OpDI+H zR_d=>dA56Z%--YG-K|FFma}$9tlPM)GFNH++|-TQQ?D=62;ccY+O9(H zW9huw=Ix3z_s#HpyezEtO_kfK^kvqd0Ut=2$iO7kwz3R-!X|VI3YGm|V8wqIT_>bo zF`Ba6o`xfv%)%CG^`Xw$ffsj!PAhfz%bC&i|JUZrbA5dtTsKsH`>3(}=51&DZQI*x zbLLw4C2*I_zdLP4Ro(5q&ySgTK40fMM_Kjy4Hml}A402t&D{Owx4hl-UG6b9%3C-?Gqo|Hj?#_Fb`R z;k;Y^_x#3dOFz4meO&4u^?s`P*1zBER(}=sv&;)&VrJvn06NOgtxsm=Og?SVZ?CSN zo)%yC^UQ1X^~)Fbab`%Q{a*J!Eb!Oz{gsEeRsXRNKNU8&kh8ktZ}FSMYxBSUe^dPK zci`dN)9(F7E?e8AWZ!H|K5k|*tE~J#Xw~b51&*eg-ygc?r?ty&?JRw9;h%8SMfqhImdeg=-L=IKA9UUB3G75Ik)p|RdjAM$(lFY z>JxaGa_zU9lbj@fg0}wJ@FZ#*9#ZGj4S*f*1dZMca-fMw+bc!ddXM#!-EMG|zt21D z_CM+W_6KQYPaavPPJ7mJeccvswtKn3z9vWiZ!Q;W2n&gpk1tuQpkbz^5L6~!c09fO zcTf8D%}2l4{{H#q-Md3hK0Gdgf+7Mu0htpfS>6Aqd*k@dcFV$@1v|z6z5e}frloQ9 zw>N)pSD!2Xw`S|M+AY^(uPyOAe5FWc&%0f(-|TqYx4Dg18Z>v4DIQ<5ar)n{*W=%U zrX5xWFPA!WJ}P@{>hJga>+e-{%>~_^bhr4tZP@<0TI=U?in~PDe|s)?Dz4_EtM%_U zo3*b@pZ&kQtvey4DdO4!$K>e3*3h+id#fBxW~Vl@eJy^t=I^W6HSe#_kD9FJeZw@| z=KaE%qPq%N_5VHYw|_G&I&Y))x*dxWd?%~>Z;RVob<^y2PVk19TPK~q&k((_2Q(@3 z>9js*xoq0o+uQwDFFIrBvUH(y`>n)w*|297rT;$d|Nr;=(G7?B?e9#B&f9rqoq~Yf zuNR9G-}RF9m52TJx3{n5vNk+5PXx^al)b(6RCm2FG;Uxyw405wa+y(?f_=4!plRwJwWi&gHG9M4v)eEeqSLEBHC4p_733&u?nJPt~tIX9orufMme z>}?k4LXX(8o2lPGYfJm>|IM(CpC`KxbXMP*9WOV49hM!vhNg_slUZ|DVHqTAS+SK{|FY?{D-7j7D3A70Sw0zdA?oS2i&Y_$`Eu3xg-Fih@_7{5BsNN?%?&dMz?t*1lhyTj{o-yG-K# z|NnN|e!1YR_hRjyPp9f~RxX|PsR*>hzFMGH#`4nM`xP_uFDz)>`|H(ex81+La5e?q z-Bor>GJVR<_dSxvZ#Ev6D`wM;-nIqQBw4@w!URQU@MR02W$td$xhY%fw_XkV{F$TY zO0T%kBA(|v)6Y(@*E##3N2103ZX>%~hOAY|hwRMvpkBpvg^W7|hj~GhE>l-NpPg_2 zZBB}zd*tH>re()gnzJ5Uvo5y!u&1I(Uf9g{mzVi&&E0huz*B6QV_@zuv+}e_9Jbijd)NIM`LC5-LKb<{$%lnnf=NTQ6OWgW=UUk&> zcX!{e*?jJk*}reM^X>lE{d_7OU3N3|?Sp21vuA$~nH(vZ*Qh!@=F;qqUoLs?X83-$ z{J!L82ee{r!wVsg`rEN3zgN!-HD;RMH$!*Y+N+ByUR;(s8&&Z`GevoxUUe%=7u@zpZfMcqp@oCvn-%YrD(y#V_jZ z{SpL9d2c(_=bd<#SoLJ0d&~|{2fO)tm@VjZ;8>3(e228{f4?ynFY~kc=pt>9(9m7A z^Xuoi6YN^17N57hZg#(>c=!K*zxPVqc_{kXuJ-TO>)Q@-X-^S6rD0KUAw0EcN~?p9 z_^DS{);<3Eq|X1Dfwb+f>z1jf@&wF(oKELxIVn@h5qWu;@8?Gxt2eZZKdd^_YmxRu zeX;xowHWb_>QYJS-);VWx%~FYWdCja_J1xM-6p0Rbz|l7d9Rp!w&&fA>3JB}W1h@a zzvr;s&nLp`S6#4uwD*QlxZtTS$=nnkfmhd}^KIwrf1Fj5t5^Dl>#VQE*Z24D&#>R1 z6e9BOB1fmojHEoFe=^T~ZT1^%>nM9t;(cp|VRFm`AGyo>P}>d%7P&hl-CSh8tUIJX zjn!Z2&H9;_yT5V2H_C~cx2Yodp=TRITR^i$leoW84)4d;FPG2X20GaIsB%%-Qpues z-tGM!=lns!EGHsr;-cd_%$bO8^E9jXMRuT7h!(qN_TQY-hgYLX}aG+7INTKV2 z;kH++R!2QP)_Yf*H-BeF#U2H-C7h)dEe}Oo#ibU>ERx7|7jW8fBe~ypP37lj`&8#g zo3!w?=(`BN>s~H;{8CRHXj{ZP+bw^;-L8(auqhExn;wzWnPXJB&V9|vt^HMd)3)C) zo%r?Vs`L+4uVid~AKU4EGxWcuo`IzG_3yvFO8?TDd46xj^uLycK6#~jzaF}tkY{?Z zN8;@fYreGT{Jo`So%T-GrbXwyjQPOly>88kIZF8wah@D08y4Gq=3H;T?Za_ve$X;# z`%_9~j~2Fy?mE8bOY6=<7MJ(+n%}#z_g0ea&s#CCZivpBeMda3;8g0-8ucfF`L568 zADJ>GtqTyn9T|CBG(6_w?Z)kQ{q6rgxi_^(a=#){p9a*hYIL3L@YZ#A^{d!Y^$Qzs zuDVw2CI8yKtYd4=hO&e2zDOHe?~i!CG;H>28T}_MlU)Uw^k;#_Obu;zd{8`|bpNk#L;e@hHzteO1jWGi1-WU45? zx6f|=uL>G2i|bn!D)}i{3FdjM&`z9xT&_AtXWHFu`TN5J*!FK#bl$(cEZ2G8_6-b* z3#V61+4;0)zG-&agKe{TrR}a1&q&ptwYgbBviI-WZMU@QbSqEK>2SNxX?*m9kvCV} z$)YpndzMRh+pH6aD7%?DJ;Hb9+wb@5-`~sPNWRFCc$Dj|@-*Gj({s`q8=l;_^z4Of z+_ClI4DpMP{&<|Tw@?;Pmeb?t)^1qVdFteE&@FJ^?p444`ToeO z)$89i={IdaTj7~-QB7fE&PBQVS@(DMoo$XV+tYvd*W1n8ju!nqy2&RXG>9oq>TgRrQ!Dao|9m_y_wU-y z;`IG#adrZVCqmmI#6Bx1raee3{`qwJ`A}8;pB;7S^D38dC%3#7jEn5r`{5Axyv1EM zkzZ!F@))#m7P%^(P>k4cbh6sEc7p($`lJqx-#Jj9Z7k-FW+=z#{qnx8Fy)p6W>ddCZ`{|FfSqd!PK%u;=rtI7%X9Zr^d* zBC4np_cMDYRC(c(y%pG8HPVp zV$WbNo@dx~Z^{0y!kY{VTM~pj!D?*w^vpM|5>#btt?XVa!8!f{o;V0)?KTt-q^K;bJ^zY*nj)^ z_ZvND&g|TE%O9N-^`MzwXa0!>4bP(bTV3Mv3rji*Bc9w@?A~uA7g<+y?)W9$aIQ1a(XXf8zU^<% z&*RShT*vvw;mYoWd3P2q8;Rt3#^;m|JP@@=Jtd;w_oInD>dOZucG+SL26aH=cL^z&S9~# z&uQs5F20Y;EU*3EwAXmecG>HR{_PurJQ>jk@zejc#^Mr;D4<+r3U=I&^5=?sI!rsil5Ac5?ck`Jb0c9lCCGTIaD7 z@9&El+@9w?rgYxZ?TC4@@6hWWmR}Vvx!Z20$z76Iuf64HaQjsQ&o}qi#ae&=(Df9w z!pt5t>vOwJI`75L&5tZC6xJzPUCd{Z+4Jraj~Yi_#XiA0k3N%Ivb_ANVb{(aU-w$9 z`ljvo_TMf4XWRVr-!H#9A?bvsK-w4eXmkt0JDs7M9x#-f-_!M+`!J^17mlnr;I;eQ( z(arKdACLcz*kGi&I^xk+4~@5m$7LS-YLxV+NPFLXZnynj)#|ym-)`2)A6Ya*dQHIW zmHTgiGFHdx4&OB$p8pe$-sy9jXZ_6j`9}+%&zrhaz3)DH=pkqMZ_)DPmDhv%3{}rd zo#%OE$|SdX=dwzdY0KlLqAm7Z@rxykC7;WLeI`dpCX;QGN7*lT^P49$>(?)so>Op| z&HGmG?0IR?`u63Qex&RS`u0)bk?YP)ab2Ev_qS$WUy~lWsdvwU$8)D-SM2@3WUoK1 zTGyVjLP9a&V*0-F*VoP#cd53j9nnAcur>V54)#*jR-<)_pe4{xnogxVx7B4okJ}N> zF;zBI_FBYkj;&AjJux`^Iio7$_=ZI1ru1tn_I|dz-;}h>t-8efbCu4^3O#YXU7(vE zcPNHT`h2n`XJgQwEfU=l=Op?!KaII%I%l!Ir`^5n0>7q*?Ym&RV)dSB`Eh~%`^=^r zmBq|ICderIQLC!^p{@Im51i_A4yZ;tPw>&xn`j%@C%ebsVV6R?`<*`qb;2K>O@Z9M z02)6552WbGu{?>~R?$-Jqxwm(Bwco^oxveadoFuPL zb+_@!map9HktScfG%$VE+Dp48uifP({yQm$|Get-Gl|pA25x)&@S9)%^0&|9>o^`x z&km2!SS*{F+xNCPa8}3BpEbw3=X!IcPI+3rZ`UW;=esI5)_m^Tb?IH`s~d&2Qtr>r zeZ3z4KCZGOttH9rz2&;ju)u{qRVPlG?_ayAPWV~*?$G&Yd3ulFg!G$x3NME$1tc<6 ze4lV$Yo}FWtM*z4){6fETJA<=MYGT5JGUe!HUznD2X*E5{=R2i_U7XBh`qbMzP)Cx z$MNXqmI)XBuL$t3u6}&>_?wpcnB3ejZD})0``f+ZGEC?8w0t~!zD(!Mu2a@!nQxCK z_s%JhP@KK=T=SM)C1@3|1B;jnV`nP&q;;>v7zI}dH2!0@+n&Gwb!szveeV1EA4LL@ z*ET&n8+9}2?DXyHqW{cad$H~>*VXmi@O7Yw@iqm}Wk)eezx1G|X`^-Nl{VZE`cXY| z*HN)XD_lwxm^O2I=v?*zwaFMU#=bzqUzRK?(=xT-i3go=K!!=^w23IfQ4Wa7YLH+8 zA7f|gEG~4X!G;}_4B8ux82Pedvl{H48O{z#GnX}?MkzQMLtJu3QDLJ`up_FaNN#v0 zFd<^uO1O0xjA9NCoy#Gk-iL(%m&dsr*jWImkt%df(ztzqV0cKl*6h&g5$GQ?v4G{Z2aF zjIaNj3K}x`3%VP+_}Q7CT+dGH@81Gik;=v^WfK27R$%Jgn$Ks;-tYY$w&E42f4A*s znsj>P!mekZkM4XN5PI8k{_a@KtAF3u|KGg(-LBP7s?YXUPTOvgvtcs{>A4|Jk-?f<{um&Q%ne&^lp_j#sS zS2j5FS*qmE?3(lA`~LsA<#!6*PlhTu+^u-r`|Y&;{*?8S76l7HTk^l%&flNfA9~GC z(QfDC4GV7n{B&C1dbW>RaOBISF0;ei&#%IlkbXM{23)|1UNl(x>dHU-NbUNzH0v8e>Viv99uFrUE3E{fAs4b zx3l||I|NTfy(`@N_vce#vsYI?bALB+L$c~bnLr?%~>5i7BNzx%yidhpGpn;Q}j|Jk>G|G%oG1?#!YBeU0T<$1r@_`Hqr z?Kvj@K+E6%{(8M$uP>eZ-0``q&e*+;oZBBe|M{v{*Vev{+pfR&%O#uZfu~wCKQEl} zIs|g^IILJwP}u16d4ZSkkJs1r-}a~bZCTJ4xw=_?OVwJdn^)qi(uIGzFU)y%Wa78q zkKJ$2kh^|s$@}|0Z-o`3IZ{A3SP9PC`gB_Kt%vRMd7#A~ra3n*tlRr7YX7?yVZRNg z*CGzbZ%TFrwYB7b|9IU0_k#NTnxxtJ`*!N?d@@Onuk8EX^4mRKSmrLLJ z>;EkF`JsLR-rfelelNIg^zsl!V`WySwLXzsG=1R#_Xl zInAz~Q~sF1369Le9Lw(}H1qPTU(Ij##AB#tVDo;@=TB8fV(b5YwVPHbSK!~` zJTG+K?3(jhPbal)@IGN7x2+(F@8jI68UH07pURKD^kd)sy5Fh%7w-)LaO6E4_+;QI=-KjYYmbKV0a2q@w=)*^=G?FSUK*&m{olpK?$y>GyRt7V zXjE)dyrrn+a+sTkzuWfvoy*(q*HzbBK2NncTfw;OzUM}s#)-)soGq(A3H5KyynO5^ z*SC)!7Wwd$9)7(>K>k+qbn!#{`d=&lDg1CzY}pXda;E0(lX($_cALHb{+)T-FG5hS zyQ1=p;qf08@`XnPZ*qUIbJ1~*v31QzrMO!{9gai z>9QM%?7x4#UjMg7GugxX-{<-NC74bJy30OQ%!%DyRvNgZ^7FHMbz06V9^9*Vr?AdQ z4YXzB_lJXa$1U0gy>2h}m*@W&o7AbAGq?2G$HzP6x5yvtuiD98%sK7iiJ#lAhDBS- zvxpqy6Erw!G_CixQ|%(39O)*nc0SoPWp8iUiE-3PGzruy@(7(iK7Xg{PLsuaF0w2^ zNA^zBjoziv$(?+0O;N`<3#n<=O*XMJ;b=;xk^JiA}x|!Yz{eK^P@2Yc6 z?0@{E@Ueta!M=3UIQi|{?-X_0GhcC!uxh&9%y0MN>yel~=XO5b$DXIQK1qIJ(YE94 z598~Cu`}I!gg-0Xw^vZG`v2$i`8wOj2fo@?eJOC9v2&`(qdfuV+&A98QuA4Hxl}Dm zC$8}i%c1UlJ}j$r8s*pL%>MbW=hjTlc)O`HO*Xhc`)&OC$9MaAKbLR+c|Je>6wkgK z(fjhhFUr>Cow%C4_d9|1-SP9*?zz7_0#4D6FK7|CAUQgC>kHM))t;r{rmft{-7UE`keEu zCHoZ?q^;(k*LrWA!mM8#6>NT5xQ00@d?;gMRH*hXQt$Anv%Rypb^13Sj>Ts`@hNpq z=Tw>?u4&eG(AXe&b=cZ7>vq4BT7Bk79c$p>{@Sls!{gEg{%uNa+CD>`dtUg>WXF~- z$&Oz>Cm)o)xc_+7CRSl<`@dg;)t;O=&Emf}N4{yslk2ShD*8XaT=xI{eZp~_>eLTL zpORzxRi8&{)^_D~7dK>Al$GDkHD9m)MCtSU>9J)q>z^z4+CQ!AyVUc1PUWB9@Avs%QvPUT3q+{*USf*GdP(x-`DQgdT+i(oMXYa_w2GI0a2HYpU)}o zo9}OT+cD#F^1;RD*Lzln6>D?f>$2PDxZ_iB!L#jr*FGHl!OI~Rzfa!2DPtC=T>U>& zj^wz1OD6kuEjKSwns;Gk#zWS7w#E@th1V~RIc&_#FKDxiBmK~C zmVTW*aUYtzq;h-RDuj1l|DdFFMDTqdXo6+0>x%Ymj}4o}CFVKpbUSf%|G%&L%7#?} zpKWw_^mlxUFa$Np`u~34|NrX;t37LeD9ebwx9HihJH;a9*51>H)!$b2J#_Sl2A!sR zI9Ro+8Z`N+fABQBSj9_$XI>fM0`WBmTWd@YL5nW_|s(=6#7rg(64H zmCeHh{Pz5kkeeRu{^{P*ckGJi4!`*{^*FQEAO7}g)nh-Ix_6u}J(J(_yrr`FXhG;L ziM?c54zUzw-v%48nvFT$cf9$2cUOe^r3CulS4!I_|~wYE@n4%bu0v#``_1|!m1*+(j#D0n~w0pv# z{9NQw;s=>c;&BxR^>#iHO8&a<>9lCQ$k2O#KYchE&bjlBz}pjtUH7RS`Y=gsPkGOV z=(t;+ZhjR~sV7rIyACog?4Gde$&L9{uU5)+&0eE?U*gz>u$J=??6>{qTJ2mhagB1W z{6cN1+>@p*x3~NhKYfwCrzZQNz^O^skC+*iZ4qAF+hVP}?@5$S{2Ko)x<7lKo_l+z z>h$lq8(f{HOUl>rpEx;fPyCwo5{D!7@{<2|eOyp4y7kjG-Aem^j18|})?b>GEZeXC z{_w^pF-|3iCw)EgH)X~Oaj%~qvy(G(J>s|?fBLsfZT)rB={phSfNy7aMP$wuZ}d_# zNd53Taq8*if7WrNuKl+Aw%V6Uor+nqPj{YK#`pKgvM7&J=a?AS@4l}*`^j|To!}=c zl)i^>+&@)yTw#i0mx9j357Nr|!c7cLlJ&da@2lQsqkm({WBz`9o{OzlwLFi^%bubh zXm`(5<=n9kd5ddmR{F#>?{NK;^=YAM>#EuL`#=kCZO{9LbgghX^kHA^Z>j4?W1^op zXs4`=-d>h3{i`RU&D{S>nP;3hYvYrRJK}r%zf>uov@g4zyFHR)^(Ps>jdMFnejaK0 zd64~^igEg!pIw_e$M?QnImPI^`zU)z;BI6 z*Y~J5{FPfSxy;=1E1`4Z{oW^^C6w6br5U=X_&Z?UFYS^%d5ln?Zf8rvxN23 z1Wk{x+xdR-YW-)^A3NkIpBLD<-(ZjU!|7_%j(%GD<)pUubN46lZ;U>*8uC9lR58h4 zZ>IYO8=lE;lK*=>4O}xf^ZDf5?){oS_ZUvj^}cpgW~tmUVZMrcN_kJa4o-Ray?amE z8-6*P8++gXSbN~s*6ioeb+Z?3*ZqC6_@C-|cJA1+MO zuhU*9t?9V=>rNeOtI;g)PsL8J1q3QqDo?bz=iKuDf#yN4i5EW{P_hwlY)^T7vgPuc z4eb-B$gNkl+4wq6UW*i6_!i%I}s=udbYU$L?&BQvItVhjsrcZu_{%og+!} zn778loR+*zlhnR`Oo}1Fa@q%_4+<%?# z?EdknJNC$ktj(D?u=>uPsOO+EoDhd2kj!{rmThI}33jvauZ|fXj2taatC{z=dUVOfvHi6i!0iDZpMT8&8W82-M5fh`2TY}_y4P#B?^##F`ETd48~ItcYBavxcG`=&JfOjW z*X~gLf>SOD8ClDp_U@rSBcY|Ab&Of->S->ry7PL=)bD$0 zcutNqn`Ec*oF%zIJ;HANmWtekx(`#fw0<~RbFB7*nvay6 zyUOPED>iOmm^10`skM`<4bNAs^V%5nE5yt8q*3Od$|ehAAKv|K_{B)aLt?3 zhn4TGzoPqjl4W2{o>+BQ;(Y~(M7+PzegS~yV~AxWYa6-u&hi~!3U{b6Lg%O3N(Az$cwYD zSfZx0<@TJ)XEXP0Qa^c~^SjCsFEu8m4L<}=O1||=dI{A;{NK3G}NB( zQB~pmrlaL=t`?)14jW7s6lj!TisCh9@7M>qV;VAMk4)<9V-acF`J-=dl^)a8NeBAv z`!}n{zs=vf|EH}EQ^0k(AK&%NQeTxwTUKp4%cHnu^|~D?Ti;BV(#05Z4lw2L&{-|@ zctO|{hlE2@W|ked-XDEGUhU>}d;d+hOtT}}pGx1_wc2D;ea_ueQrES2b0u(wuJSNd zE;zh*{>^2t*Ja$jFQ2qIE%nV6-+lIw&!KJ;&acfRuAnvuzvr)th>9*&Ba(|+EjjW z5xJ^~N8S24mzH?0teIt!nUuYL@3!1sFPE)+UK)TDeGV)x3UeEdY%0;SifZN9 zbG?3#Y}Il8dyCdu=_IDV-?V3IUf})x{IaH3*VUHJP+TTk@%sC>4l)kyKaZ%{gz5AwA`^>ev z8eWk)_4=u8KTX-ScHeD%=RSX4cwe!s6D@f~!4 zMykYjUh^s2Qyn9$G*KdilWFSzXH$0UEOT8T(fDz4`VCF~|1XaE-6@N-uKzB2D&|t^ zQ8&E_vHuR~m!GTvMq~2+t>C6 zoU?pB=Tl6S?&(YS#p7!(p0oS?rZTVoOrRU<Jrarw4{ZO>+9-(qB!nGklC$=b~R*#V~PJ2oLU#m{`IU#(oeX+O7a z)RqlWrV}!}x69Z4I0!myH9CE6X->E9HjTfBTuz?1|9@w{Y~7EC+wK&dRz3G;@9)p& z?SKCW-Zmk^EbEF!z2EC=YqQ(ss$Sd|&G1J_Ut+;bLZ`(pH?G&aTet4JgtTp8TkfT8 zFJqh{H}Q+V+qkIKJZDqwhrcY<-#%X~JMzq1-9P<1=S(LD1)G=4=htm|Iz9g0`CbXb zL;rr?|9|V*?EH60k$WDzTD`t+_rATa*X@3G)B6=@q6ai$eRvTYzg*0+xZ0Ec42p{q zKd33Y-`x0nZRYvCh8Nydyz&12YNn}ia%t9etrsQ-iQS=Z_6VDu zi?0;5be6b#JAc2ee^TT^y$6+7R)uPVuB^^I)+1T=a_RJ2{r3MdRTEx&K-WD&hRZ*JMHC&_>M5`VTB zom;!*l2^_j^Yi6Fb^`A*gzwGY;*GY*G(l~n&t}lvz@Otc^;^_)x91!zdvv3)#^Y0e z#5L=f$!gQ~emo}q4RjFEkB^Vvf=(*o6jqZ^%=vz|e17isyJhckx1BLMy<@@Dvd#DF zexGIIlX-D+&*gLC)^0n*=4Ew={yegYU9RH5u9BCJ0X$Ys>xR4`)B=F+TU< z@ki!~6AFx+SSus%&icUTN^L z$}(0StL-Jcx~beB!dy}iwJ(sBFm zcZ%!g>)*V&)Cv05d+V~237q0>i!41vza8za8WEx*T^^hBqg??L&^)ajCP-c#H; zlH}$V9O7hsp0MxRvFZ&+wYd*U@|!=?yguPO_p^$~x4Yl(JNal||B3IQTgqdyZ*E$; zUGTkMk7e=yzu$jE2$@s`c}nw|Wyi?$0NMRciWhv52RK$KFm|Sf z76e>bvY)fYs$yHjwri()|2(k!FPku*XI8Dwv|B5Dg{z-U`L@k1LQ?p(ZAy|&Xxi!1 z7W(%e!rLGeV(*+it{(Rm(|F}$XPdD@Z+V6Ac*8O_vs4^?h{C>@5 z?x-)E{Sr$gz#PIfvgxNJ8PlhfjVP5j=*qPbRwW(QoMloih9`u=z)mVvXVq z(D^i=xy&1&Q}IBjt$bZ3X;rcUGz$|qE#*mvbcgfX+uO~LF)%W}H@p#8zi!6G4RtqV zQmfx@*!3{5Euiecy0?FCJ^9}DHM^Q`^S;0CH)_w9;HtFU+fY zwX*EA?)Hf7d3S5-4EZJBOC%kSsQGkK{oT)q7jhrt3QyN`x~+H)THX05&PHr|L3*9C zl<~ZZz>8r=j94Bmoj&jF%9;6mVp;in*p+0G`>%^SNnSU|e_?(6h4S0z+OJn1tL}Sy zclUPgy%k3l?*y{{O*#kK9AXzQU?f=n@lJ|ea)nRrx0~s9+XcG>?+DBjymBhLW6?!{ zdtMv+?f+SX>O8hw>2)l>4{bfl0-eTB|Anh>zW(aVBBs&!BktGro=5sCOrLFevR-oL z6|;vI4|>0s%3kwu5zoBTiZ?C`b-pgLWEb=nDE`3VX&kqpa%TO9gY0*;mtPTob!S(G z|Nnn~?+UkB3Fug~U1*fpewfcX;_@=zyUaX-%#2On9)H~QWRkbk&&dJ{1wt0B-T&{G z-ZPUdljwq;<2N5Yb$y{J7hiGj$mB4$-+FvgBeDLCa`TJy` z+l$n@yG&yZPX6_i3_GzVeEYV$)nECFuezU*oY(qiV|<)*!O__~j1z1EI^+Xun&sot zdKi_`i$o9AJZ^c>JmWBEQ;yz09tnd3GY?HQJQ{59Nw=imsWve$Z`;kZm7it%9gnsA zY)Lr!_eN5M)1~=N#Tx>ulV{JX`;~eBZvFqiwcQ$?a;Ec~pUEG}Ul-u!_)N9(nv_XK z0*AGM(}p7-a{lc9|J&ZVU`foUs%OH*v$s9=bhoqU3!QdReJ094bce%N6@~MgURmaK z`>wWLbKyb+@8J?#AVw>E&_13|rJD&2raYv*pvzKE;f!eD`cBjtZEyi_09ZIC=cG`c4goLu`K? z3aWlSoxYdH$&ZJ(=ex$1Ao;|3wpCv~d=pyN+0giq*UiqHWlo0Se?cbpze{s3Ce8jR zamw_S{-lT-AtcfyQ#Pk{*KO9lWq$T{m`#6Pb#+us>?1Co^Gv&BDhWx*ZW55*4|L9mW+Ev2{P67RPo? zXcw2*xlbVEgM!vk0Ve@14#^|Q?C&j$iW51wTOKQ(P@J(*RbTk+L%E91jfaxHoN|`& z;qo~7JD9JKc_H)SoEXLl`zFcr1a?mF_%$c{b!lGe`mcX3E@S=JUABQsEqV{%<)Ud{ ziwnSYTH~20(%ACe zaEor0L!oYB<AODuapF+DFP*b!f{TYry+N{`(RPkfzgyh;dmjA!!Xf&sa_@sC?ms4} zmDfIWbbnPm;hHG+P{&g2P4SvdI`=;t?0`MLM|z0bLul!}f$Ol*J7SNrP5#>Mm9J~)dwSGXKWu#Z|;c<3|x#4eix ziG_0wdgFpP;+{-C%ysuLw~F0|YtA`IanC+?^&AyEEx~T{-{82T1R^F|Czt`^j2foMrjYii6R)db(p7EdK(#0M6m8S%{J_xzK>27mq zIdL{ZVbbLC^+v9XPYIoVxAXbDJx-FJB@%b-xi@*@!fnU{9!eW_2+g?Nn_Q^6urAz_ z>9k(t^*pN*QR`>(9Lv7%u8-)id;C^D@v8TpGZpL8zMkG)^(U{{-RJAK`(;P6u4Q#@ zn&+}Hc~5{lzsR@68Up8+=T@#%Umt4p$8fF8ae>-r$4^@a@ z<2TdizjYE?r2Hsqmf|jj9dj$6&D86eP~TPN?yTZGWns*$t&uxt?)`DiVfW{c>(@AX ze2Z6p5%2!~_ED>C*@-Iuk6X3Xq|H>AHR+B#|CV20vu?k;y^S+2)q7cJq>0P4P@TkH zamkv=PMY()IeIEA6!R2aj#RbJhuBXk}UuN(7 zb}akmq{F=veD|E_v-_3tUiw~7#b?D1&`y$*kM`~Ve9pSMsO}fj^pp(kosTWf#XPb2 zEWmHX!zf(Hn<(;8YGPsBq~F2fhr)R>pUiZ*p_9_1K5xO)#4~|AK8f!&*M7WjS362s zsdI`Yt3~|N&i|VAf$ui{3e)A>gBT^*fB4}f+02_u`tBBd(ApN-t~#lG^;^4>&v&=U z_+8wrb5qb}mcXte-bDSj1yAQ`f012pbfo1;x0yY6#Wuw`3Mn7k+_S6b^rU{SkBYt;p4Yy5^&kB9-r9cS%KEb#+IU~36wfHlxO`~cp0|%T z?0Tg0y6n`lvPY`1j6drwzpnGwW@{ zwznSZ{H^-)!(4$2TMBhc`YYD6Zar(x&b`$-% zN+f2ly}0R+ljL`o4iB#Ijk1NakLk|SHW6z*_w-)>`=6(tTg%S^2x7K=IB;pChiekG57!e)w?PIjh%4 zoVjzn`OMK8Lwt~mf#mi*$y2AkUlF0qIbUU?JrhG>(dXL&G9J6) z+*-;gWkkjFA1><~$&`t+OYjC_NfU0^Hz&>0C2 z1tvsnE7)+CgC1F-@`9yp|^urcRh!Sz_Q6au#k-t|+# zH8|Vq?2vTx(8G1RagEM~I5G*HUiDzX3Qt__0h{0d5$ciQwm1&^| z9RnxB9frmb;{z>-Z{Ph+3*mhf>jGFgJ#eE3S>bJmp=59^uP`PLNF z?i8*0_wzYuvwCD@oL2t+zh&Uj%uwIiW@oFuzDfn%`}Hj%^-ax(gY4H9I2udc4?!Sgo+qcf}DK zZ;7p4{gd}W`P%sXb)T0eSCu{Eb_-QPq=0Ty#?I94uOGtyp8Njh=H;?mnd+;<*Uz*4 zctrTxVt0P)|9?Key_r6L>)Y-3@2UCEi&<**@kVn0O(Acc#I0FZH-S!H_S(W5_y70( z|C@4GMsHtNy=?E7OWrq=xvQRE_P5`3aPkN(=fUbA^mD`>R1dUEd8t6^nNr-t9^RG*h|zwYv5;DOL9!T!20jvCbdDp}wEslwsy zp3mn%XGW&I_P>2H#pv6U$^N%MgMG8}_f@WnaGULC|F>lK+ikbk_|7(a7g>7V_WP8T zd=qm)V|M&&?v~v?>w3tD^;wN$#jS$Fyt%K}Zr3aR_2Dr8cF>Y|fBU~F(m5L%|NeYF zzwJ5i?+=G=*nc{qy!pE5W8;Ja4AwuNOwL_8HSE)_^LD>;W*en?efy>8+!pcw-`~ym zi_0I_W?$2({_(Iq_kQj7t)NA{9Fq^t?%&w;*vDGJyQM$l%Gr&t*X`Dm+oZqm$DyO< zEhn#rMV~!q{oZE1dbC3NbI|Fgg_$=uEsZaKy>|OF&5OIs^KU10>#oVXyzJV(+G@}N z5vS%HpPWBCciYC)X_3c3SA$3!Cb`V~oEa~md_Ar@H{Gp1!QVcEyRBU1vr1;o{rvrZ zH?xjWx(yM60!`Tbnuv@<8fw2!Tv^0VUk-11vxw{xF=E(D!5 zZhpVUINIL2NAvSq&&g`r{{4D=`*!~R*k?6{eAnaa_ZEBF#e??T%FnhcU3I-x{3U1< zG5PYg-00+guKGrG{CPVbvgsdx&y;(_Yvp(O|3BJ6vqYd1u7A$CQ~iGL-&=S1kK6-| zErJfn7BBzkl6o(x!pCS`$IpvDWFJT<$rY>KFFs-U?BFGD{kQwQ)#ns6`OY%Y412sk z@lTwAJZNTOzWWA`kZ)BbM*JacKJ!M7m?QnIh3jj#C=Fr3Q*;25kKI= zk$HwiQ9(Fv*{Lmt985DOeAW_tY4Wj2u%w*V=J?YujGl zb4=yDS3gtXOzP_%>xWCPoz~xaC8)Uf@sUp9y|q1tVm7RM?HwIDrl%k3-XYJ;)G5!s zsO$SizqwX36%taMGM3M`f3;%qrt2!@JLYXtY%v!;vXiIu@Sn&1_IknckDcx}B|LrJ zY(8&(`k9&XF`F;CNvE3K&M|&|@VkP7TK?3#>30&3#0%ut?76))`*|tLdJlc^xM#+W zHK*ea^F0<}S^j3@ox)S|IIJHoz4QC%k4xppCYyndd5>Eo;&=2}@`=aKOW7JP-@Irx zZ!V{>+7H{N4X>Y9mg(*L@yJI&Z}0iq-`~D|URuDRwC%d!k+A)3{mgt82l@@?KQ52> z^E&?jDHg{w^97%oeY@bypK5k9MOc6TX}#SkdV4-N*~fY9wNW?VXxhJ{J6j3f$0oRr8)NJt>0{5-aZ|<6%$g-6n6IZ z`e*uwSSl)?wHANBTdsf0n??6jo6E&Gvwbgk4yiuZfJ8zoL;vG1=q^|yJu z-!{9J@VG~YM5ausoQ6}rE^2U#3RH=Q4G z?8he`mGjD7rg?WPs^eR@A_DZHHdbl2M;t3{otOPg_3OWXzu(81CU@=-+w=BMbr&y`>3(~`7N!r}S3xwcPwk1}v9=F#6J$K;_Q zc@lKGv-jo?LGKbBAGYd9ACnA!pmIm!EXQr0N4>c_pH4GNJ0o#^qgV?I|LH&H>;FyO ztAAZc&SgjZopfpE3mN&%Y`ky&{eHhaf8Wnz8O&~Z>rJ@hc=kPD{Hx|ODPaEt*VO8F zJJX{+UP=C9&Y^owSzi8~aNIjvNBfncn#Fg!HxSRSuCoW`OXZ`I)vh9*Srh+!f#PEwN zieFq<=(ZwUrr0TYv0zu_Y2EEd))(jQY_mGCy*<$Wcgx{(`pS}4Uym8Y9MhBJiqKl_ z^x3e&GEyMPcF!cs1M{orZ!+q$2)-O@fcGs{%2v-|VGnS0T+zaNjw z%Q?yJ5wiU=;ZKOD;V14-zbBrbWuE`;;W?Y=Esf8uIczHDpRD=%L@xbaV#`_~z3!s| zb~^+=^%&YYzWDg}f#fFFNw}1cQ%}~xR)bD!n*nW{89C0#r(?X?B zt~?yS+;6VUbII?X#-A)$`9+lN1s*ZhcSt@7Razc+=~1`-aiO0FY*|6*kmt_(yVzA&T;bd9j_;n-18K~4&C+I#rjB;$%~`f zgoUpsCi(+soU`5A>D)wdZnKI0A3{!s&AoG8&gV@5Z>f@&tM_iToBpQ`E)MDb?vUfL zImlAg^4YoL0{31prEr)RFYKQarKobTjbHv|w9+tDcza>u~pKCm*#xw!wpwN8sYgT9hlRR{Udm z_ILlG)%EwUHf#Ach)eG&bn@tK-Ei1wt*T-93E5P|H%8TSj=bQ=sHjK`)KONn`1Wr1 z`(M-e_egta&42b%__VUc#1pgk?^waW&9g*ub;6^CPMeDNRR8Fn=k+vFbaJS+;7ftu zpmVdi6<1_#*DmH+FA>IiRGK$X= ze(>`)J|?(c=T+z96A}++mR<5xudMA+ZTrzK&=elBC2nuk(b)TKcjDv1KUHw7{!+YA z|0K7^jJ_XD5y!OVD9)dDUh{~3Pxgc6@(`K)7NaAAEed=78iXbFPMdwiPOd-ti2bkA zH9ga+d6{_bl@)Gm5NL|l%U^mUZ_;`9!`wPgUVdKx^r^^ek37lpXUd-c+S&ZA#oQL` z?U8q4b@D$EpQczJJ55%uuU)37BRp7(olE_=jG?I%=UYkRcaBLFLR-{X_eJ#O7R@^> zemZ>pe4U5QtQHmfB4#v-#zbBfQZ$OXRXeHJcv|x8ocKAb6>V%zzgyI;_vxtjBKF8n zw<>S0=lQqvpWTsf$ITut71w=x^FhqMjooiP{Y^VsrM<~l`udYSE-ubCse#>~)99RL zto!eFY5kM`dQX4HuJO2Cf_w;zgQ@_>|AXqnjauFc9d7fE*zA!>Ka@3n=7z46wi?%m z7eCmTKU`{hyG+Qv*rvs|(&+n}&JDs&?6!i&orgW6?&QIPp_r`CaQh0l&X0 zez{b9V4`x@ujGA(pRRqJ`{b*l&*jgTC-Q5nP2g{uwteci$uV{nen0PcUYl5bf5vgG zJq76=QvN{|$L3`x#Vu24`&E9d-E89aPNSu2KhhhSUNtjYzE0{}x?_c_=A5px$3b_; zM+Vn_`0%AB*t*(-*XoxEM!`j$k>v-e($x&qdO07KKe*Z zr%2GI%*Ot<=JGj@avw>F{XEdL;8|%)!C9UANneX(El*dZaY@!bjC<0-y{IGp@So(5 zygkq7>z^vvO;Ib9$1pMF=oxkBLFtJ;J>foJ^t*V^QN(YBL5ddsD@wQjS;{NK{y zanqJ=Y5aMtNnC&bpH1f-#RL;=lInIR?eE?ajJ%8|z?4(tVEt7Y@vT~p3Ki#4!fPM5 zcI_9an&IjFOwNYyPmKsqlBvpD_msy=XYXGZyE{#Iaj;sr4)?v_e?dJQhvoGhIcze; z!dZAM*F3Y5oxJAw^k;X(x5aGiQF*qfq0pbD&0W6s%I{zgoyW^K919*kwZC3r$@_5e zz5G{)i{e$fKPD#2Ov z?(tzui4RP^H#MdOPCN2*&SQ(mCzE)-D9+y)70V(2C9L0JE9@+QPiv|=1;oT7A4suW z(J0uk)VJ`c`?18FCjJ%P!hIixz3HjPD8F`13^8(lzHg1Wwxuc&y*`N^4bFvT4*aHK(K$ z=GRL^A3NOqe9rp(?}HJCT0Sn^w?pb#>h#!W+Pp>czHPX{^n7u|F&UnFIdp|b9mkWTb#erb8og^>Aht($uP?{PKVld5{kRjX_STX|E<k;9k(&* z=I6w(j@6m3?+XeMwMtjz%@jt(-{>HGwyYhT+yud@7{?I7JU-7T*Jgk}_ zaOil1&^OQcW`zfx2a^Bxn7-xLzx^>_=XM+EE!G@8E3Z$R9-OE8@aX+RtJ?PkIK8vn zclrE`^V;`+CdpLP&8+|V%=Wv&pNSvNJGn(Sb4=C^T5~Vwppx~L`34W~?3}-6%@j*- z`=a^I>lVi^J@@#Dt@lm+R5`K7Azc4!_VZ`v`fSsDYjeD7Yp2oCy3HEFg4$bor<|U< z`{~cvH6GHX$VK&mKk5NyyMO#yA8*=qphnptDfizco`oGUiHar1ivKO)OpQ5yI-@eq z!_#M;kKeqq_pF6F-0?G8t8Yzf6*-mM+G6xdGc11JzvtP^XS#b+H-7&4%1`e6 z_n0F_M}LW)etO%;?%-p+`Y8vOFeUySu(}UjNUFY6>F1&uWRUm~v?8nfW!j8t309omyLpdZqqA6zpSMk9S%(gw&bhbnzH@ajWdFm*E~F@oAai!c}?B*w6Nv1&Z~Ea z39r7rvvARtGA#2F3rd)TPJ5*hkB{Spewag^bSJ$@edTq9KR%!N) z8Nu}%mc~b3&N9>4^C>-bOXzn{R)ptCFk?j>Xc}U_VYE*4o#cpo>%WU<=RBEGnELDg zy(#){_dbljrOdqhcD=dvVYB$MwMNgsre0Js`1v%@?CH_Ku-&oFs{_@)=sy0Rzcp-K zzG>F=4L(2OmisdQ{`@U5Ed6WSwSwzn-C_)1-7o?$p;0)X=|5{ii#Xx8MIW?X;ftZ_D*>e!s3mnTkNaOo{Sm+C`2JJh>;7!%Ec?WM zz1sT!%}jam!@G2@9-DP7_euR5^-yFM}-#^#Jl;17=_I!RlXe=9a zhuvv0=LhT<8QuPK0i-?-;YN&vGI5H zoHSNv#Gec_OPap#+x6-7wx0d~e>b38a zr0%5~v-y~FaUt^jJlk%whtuQh44)m_b7M#0<2N6V%lq%0vh&ZY)$4D4JT9Nl z%*JzKnq!Rh`#qoEfEIPv|9u^QZGZj$H#<+=JNdTy{k^?!H=nm#{U+@NdZ;Kp03DO0 z6q3nw{_l;;ZvL|Qv$wrU5?@p8a&KGQmV1G6O_o`&EUMEA`u9Bju*6X#`_ht5(D@cZidJ;+xAjuLmPcr{Bwzcm-{`*dl}~fhc)w?42H%$p)|L48 z=kxi`I@6xMR&bJhWN5UI{eE5cC1-Yis*B9q`7{S~bK>*)^>$x_TzWtkQ~KF{4T&x~sk-+J zxBi}lv$M^&>u$So=%@&b`K^85Ze>@`esx8$a{5k=?-$+WTld6D-cFh9n{!;Y{L5p| zxdotWP~HBU-zjhgo!I)P;*Wzy&9j;5Ha-0Tp6A>J3r|c?{Py86zw|tB>D(<7udWI` z9TuHyx<3EZ6wPlh7WZ3SMyy`mQ@EyVo$mMg-*30Ct^4~6bSLSq4?hkt^G8hAi_Mu^ zdhO#Uj!E%#KbOiD9uZ7kH($=?$gA8dCbJix@t?GRf0|N>!AIMfhjXsIc$xZ2>nV5f zlWn*2iqEf(_&3R0uQ0LmJx2iO7^322zKh>=x8J$c?KjKhx$IX;G&@^HKKmemm}57rXlw zn{>{Dqyn4&hxzRz7Q6Ls%8jmkI<@xQ_t)3YUyCU|8*yfP#W6!Y&)Mx5fbO}0DemKZ3U7CEx`Pu!~>-WF=yF~xY%PsqY<-{tgE``0@ zc|EQ=@^Blk<u9fosbs^XG_}vTsjb5g(Ar2qEEV%jTrmayT z=gYUcZN7GH;rA0?3XE80etUa+_k=Cy?S9_?O*QEM-ScDpjz?Yprn3npE_Uq}+xF|# z>g99wih0(Xp4#kd%(8rz>1X@0Ig54U>;IO1`{Zx`_sVVC+*>B%N*TXf#p7PwbDCfC zsdM`8zu)ik1~z{VvCj9c$Tx-31`jyrZ~H}ioCkEc6PTzhsy^C3)PlQ?)`FY3@wUThVB9t-|yGg z?_WOu#7_qwCymovK_}#XGMT>Tgjs-%wzu#`(9vU8db?>f68+W*VaX4`3F}I<9 zT>FkjcS$FSdAT`@)A_F}T`TCRUcdj}uY2om%!??$a|kqqS*ovb%gOc&Z(&DFYjHFvh#i%I3ff z{f-M9dvpo}ayOqf`~0)%!k z>P{?e3{DnlMN^OLSfniH_(fcQN5+%t!_r)d%GXz@cR9>i{N};I=GYIN*A>MANT6Xs$&$tJY=0}(|$qJ_C{B4@TYkjjucPWa66+TMB-j-$Eu4v z+$($L)PC@n%00YW=j^nIq|P^qzvjuD-c|Z~*9FhoGvA-oG@d@t$Q*lTDU-|n4By#i zrq2THPKS$aoV_o;_Ul!<^@6>Z_dM51j(eWHyAQd2-qFAjk`G#D^ZkeJr?u~I*mR^G z{(WQZeY@;vo$2v9+y@KGqBWXJv+TA2yRsxvq4iZ%%^D<5c_k8?6*mId2~R zkoNGYyd%r`nM)K!9#lH-P`v$#%V49Pi?Yqs4?7O+?zn1c$Rgp=1e(GUJDX?!??>`? zrrj?Vb;mdy-n~}DIYRl$qze{@rc=^T(eBZHoL^>9x?ECp zkc!v6`9&QC9J&&zC&OD^{jGkeCY)?#l;1 z&wiK~w*2oKoAAz8cak~N?o1ZA67$%iDfx}HlhDJCi!ZoqyOgp;+#Vjyl4B z!iN+SH)lEtJl~Pd6REqtT;{Xz`F%?Q-EZxkl*;w?@-m5E(x)#TyYpOS-t6nT=XK(0 zpJX~a9CMx!)8Lu7Ytyr@d%ihdN1j*#1#T{=|8wi{<{R7JtuQUydaP8c;?cjn`R!MK z8ExJ>Z&HHAv7P;O|8LE@mYdSPJ}&IYA{{2S#2k)@mTeQmIs1*i3D$nP2^xj^x$DH~ zqw+5^MsXPCoYlyz|Zd3f~jG@F!*AO0vV`TTPE{4&9omQNfW7dhBf^+k>g z#AQeyzr?d~(k{-eDpMw0usLGU6JWjPDMx&Y{aLA;>vz=3@w^5x*m+RlKK3sLXQ1;sv-R9|%lMekpynl=J;g1I& zr&pi6v+tCoa{eC-df2Y~=&lgVZHGd>kx`|0WE`BFB zgG}X&d7I0wJ3$lANBK^f zWn4IL_`iV74gbx%=1ND;E#u8O#jW^1bgk62H@CLAtx%nuaEpJkjkgroY-R_{<%z4O8ry6V%@ybYmwjH*Z;qLbo;%%)zwYa$K)EzzuztYu4cej zVg1PSgk_k4YRZm~#sAO9KI2i6k(*v&pyUvG6jFLJSzTMk>%QtnBzvc;_V8D{))|aCB)X&tu*hJXq0nQf%TkM+GgKO@Z4Q^`Et(d zr~l7Ao)WcTmdp`l_V*@XAwJK#7yYbwDKdJ9H`!?SdyQJM{OW4AoPA+`a@M@PlT7c_zME>09J@3p@vMAqpIf~k zN2H)oUc{%GO)`soXNgKJPuZb$-RRl}uRh;3ldBT!*T?nrXgbN=>)x3x^xjZE`cT+s z&Qq9s6IRr*{HtSLQw9~5uixRpR9;k~TI?K{Z|A7-cHYjP4+XM5#5hmTQkxPee=ljX+W9Sl zyT5#W^4Ij$*^`NFPvrld2o#%@%lj=OFmYke?}NK0bWAzc`+9>@3|DXPI*o7t-_B*9 z6MFRPasE(7S4WqP3p+|SB)W=JAC9}Al9lx4;)=iz`R={C8(kN-t=M>7<6?qi;DM&t zH8&W%T|_1>3u1Zr_j&c1J$Gtc?CZS1mr-KpSxrOpfVj+frO60sA_(ktSOovB}4qn;u! z7DZ<3d}PVmKI^m4eVb6Uo$*NHUtQ`78`o5Xd7*A72ep_WE9wFsg2t9A*jHB~#2_*- z@~H5Hh%g)Nr6Q=Q36ZP{n1oJi?P7k=NZ)y;l2jPARv0&^>6}@*b zYaXuUs~=fZriq^S(!??>2llJhoQ5NtxZWq2qHf_vj0i5MU=ljrmA-TeE?O-x!^@bLpF()2t7h->WzSyR92*Z=fBzdUT_i)U5J zpf#B9*I!)hem#1oca&pzZ0S_lf&+}(3LYL(U7K~(z5+x4+(+qn!Wi@5|-$*ZG=xf87hZqigeA>+*L&cl(xZ{B(4W zaoU*~50k%aJT9l5Eo^*0-t?r+&$|E5X6L_|8Xl+lQZ{O`QTNX03)|(2(u$v*`S_&N z@YwntkGPx-CL<@GDQ*r)k(qm@?3%~d5c&H^eE)}H`+q+c^GcbVuqt_x09xrg zx8~EyW3@YT4mPpQlYbe#H7m9H&BpfHPbbxPPWt^bL@V|C{rdf~RWBA^+n#@aO_F4( z)z>S*Z$X>)`(&+mEx&Wt{CZ@|90l?`}yqK-|zROAI_F>S8RWL|Iah?m%q6_{`_#5|Lu~=ew#|K zMIQewXHl>~)wag&@0Z};51RQe{Y>9;}Q{5!A5*WcZCw=5d85g&9V8>qQlBKLmJ=f3BKw{y4O1T~_2K0fQH z1nmPayPa#EeS6zl&~0*|hhoKbqn;=RPuY1ZYqjNm&>e`M+q4t2Bp&YhaJ2d9&*$^M ze-fx#Z0MG89CUHna*gHw^X<<&h=i;i8DODw)A%X z{=YW;5qVFV%tL>Fdwcou{EsJgcUDX6Ze+Oys!JdJ49enkaW%l$F7QlAMba*kvR3qY5n~*T0YN$6xW!Dy6B#tUez|i*I%6FK*-}`y}^l( zrtNyr#2u7qG?ObXYb9u@`Fegyqa&Yrg(LsVu}J-wd(SU?L?o5vpt|UxML~&0bGhOa zR~k5ed#v#8N3Hg{9Z6apIdx~&*VH_aR=c~>K+w0<;P923>GS7i-Pn-$>XNtq*WWwk zj;sy&@Xx#TWR%tUGtEvlO$yVqE-mrYYPq${$sV97?%)ndRW|+x*F|B#&_U3){T@WA#>@zruix&+5ejk*CM@G;>V7RerxV z*iqnf$%kIIxjW1|dR9Jo`>3+y-5txh`4Rr7*XM6Ksdi54pCiNP;>0Am%^$Z-^ydiw zT>M3}R?H=Geg2Gq<(H2&EBI8{UFrYEzEJtgHe|O98S8j4jR^K*pTk!iE+Z2?l z?>Q=T9IgC!W#Y${qlKqG3$uvpPfu6#`4ikOTQ=jl`!5BSWuHCdL~iRl_V}_ks%-uL z@AvNr54+2bHlGW{Kd(h(hAQ@rs$u8t6ZhUsoBgv;rh1EEN6JbC6U*-k6MlX^x+BTw zQ%-B?)>Ti0_Zx)0D8J|G7~s!pc;oYeHyH&BW9$;e_7ns=GWdYb@xIK~A5(9CA-;!s z9qYyu>p$l8h_Tq#vmYz>|1|et^@M-w{kq%l7>Tw><}=@KUhytc_H`f~^;owhubDCG+y0IcE&#O?)(G-&?k(GJ-|9-1jbxVD6j+(5U%dT-#;G|K6%+x-e13bALy9+?uI!W*;9Ugec=22da~`J z2r(zkzrVI#k9&Q6vBl^9`ag&Ff9BpOcu^zsWM{sjoln%v1IjwC$%jt*Z+XD`Wb)=8 zwztz2?GAdMx-HbIt9B5yt3xX%?ZHjgiAoi(mTcyKUGdZQAoG#)hLLG9Ecycf`%ZK{ zXgbky)Kj-f_^*iWGub_hA8Cp!32YD$Hu%(YNcR5!KhN!}BM(aVu3x$RUe)RS!OJr? z+H-ZLUa`D?qbo^L_^Cx(^3T8pS|(*l(t@dz#O6pBXWG}~^vjeFxXGlh_p z%}KviD^4%TPxqOaE|WgfiRpY$?yD)i?uO^ruMN zJZYE587Ir#KD2zUuK#`e{;|_~lLFmDPIG;=G#9IqpQLvCclYOu|9+mYuZlf%E9T=A z?p;?}zZ*=e*`MB(x<}j7yLK__`DAn~rg$M0U@e)DKY z>XL`|+1?$lsQ*~k^|-U<=i{Ic9p0?|iT=$2UjKwn%e2=a+CvVWEK=?NCr;`-Amq8A z^7FGeeKB+Wl$Hk@CQHm_Z0T%lm)<1FkT@l=DbX>(z-eAYjr`*o^K-=1*6n*NmmP4_ z;M@*o^@klddoHYHm#?|7?RK7Z@^hza5z1HEC+xQW`_lhq(N1%pRkkh$a-SvDw$)VB zHb3vUTlIP^Xq}~0>49Z_b6?G$xxeggY54sQ4Q0Y=o)!ro&TV>-IANyA^YUBK9sEyQ zJXf;v^TliHRUECxhlK~5FFHSy@Ne1A+HdvS zq-Cy9RqNANvuF4l&R5mkbg?Pp z^}-1)+{rfa5qf=fhJU!~9X>c8GgEwYF#Ga+#$O!CIRdMsdnc6Y{5+SeBN!&V-tgZ! z%jYuk{x;fssySlMr+u{b*im6}NPPY7ce{REy&wN`p6k7d5&OO;T5Yyr@6qi!tKTH> z?6`dWpN;iF{!Yg~N9K5c+I#5tWLcBNSIho<%4dAfbLeq$EyquuxXN#bxb=@DeX84* zclXxeca_JB`Tw62Xp+2d-*U9=|L@P=jkC`rI>v0Rm}6cXi`>aw0ctv%s#tAYB9QP_ z@}K+sSn0@a)e5sEtB<)fcII+;Z+yV`P*_i`-A84{5u=@)atib07P56enq7bLvv$S# zAEDQHl55p^&db?WRan+3Jr4g6viZaG`s9m$&a{4x+^%Km*f+U)6NlpT&>|_Tk`=8V z6rFn#_9~Y#oK63bnAE=G$giM|v<{y&o5R+K9&R^Nl=;})aL~o5#qyVw&Cw~rJo3NT zAGYt2ultcGZBwx!w&z zo}j+&x6^C>Y@W)#{Z`Z@cg^#4pY}zxt2m!~`s($JeQNW!ShmP4%RgJgwqru%b`6o^ zTb6Vl|9CSo*Yt?dJ;f#NQ=Z07Is0hylp3+g$L|EMIRCgpf9rYU*TTPh%2nUz^gN&c zJ%Pjhtk1m9)glW$C)hlzUbt-n+v%&*9;m){3R7Er=Dq#%Nq@^Z&Tf6s`QmTe3&}lC zS8@Ei`KzT~Ug`Opov+p)b*3Hkm_pNE?F@RkheL;r$%pGE=VaG2kvUdfav`m)>uw58 zcD*Qg+CZ&3(O38They`;oF#;LdX65N$&*weydl86d(-BK%1cRAEX#KsFrF-HqwC}m zV3hf5My%XNzFlv(-M%C&acOga6?cmI(M?}`Bl&J@ox~}hB)^DX__|YEbVW;m-o1*sUU z=Ua^=E|}}gm@jhrgTldX*5vXKovMo$rU~rIO5`<*UobnnLTyuamI%8=_^LwtuMRU@ zrW|^3X2+Q=D%oN(#}|F)JFdU?i;#Tk_E|l$S`*hOch5>zTyw_$^w-tvel3mp+WqrL z`obyc_V>8mkI8kPEtWZyboVv8z2uTBhxZ2VF#Qf0TD7bt#VU)XbD zjYZ&MqYgJ8ha0*EZ3#v5?jGl`bmDO;;Lg7C!>=H*cf}W%?vjf$Bqr)B$)-M9+t$vi z78FCpgSAKV zI^Ni{n@c^Clxy>Jmf*=&t?alVnLg(slk6SCvV(^?gj=n5|1s=LVZVAyVxHBO=_mCb zZfm)g_AZJ;nZ@$d(*GIeZ+71+4#JN?te;ui0D{Ntgdf0X5|L+=j%v37W&dWR!XZ&}?&xgOu1xy~Q= z9BsCG7k0YR#r{(YyU)KJ4dHsZ-c^ey>D}Kw>oxMJxQ+8UJ#;R6L@eSI_|@ScT$cQ0 z!zp1ui-R8+4jgXZ|4;pT@t`))qFdY zI*KQ&`4*j5YFX;DSgwLQr7Ogz8Dqx^z&ywRR}UNbQa**Eic6+doM|Xi7}3^Vt%Ud>8_`j z*T>s)@Ak1;y`g!*`sFV1s(Y_%^q*8(B>G7HZ-0f@-sBk^j~I_xh5Lw{?C(@o3drRx zWIXS5Of2{O8)>zrpmY1$Z54kUY%z4Oo!RsFE#v=#ihH&|qVvNU1G5$SPF&|%Yd~8>qe0b=hwZSQaF5%L+P z9RELm*?+Xe#f4>B0#ooZpTdh=`dn(6Gmpi;6}&Fs^}};rwCH7}A0H-b&oNroJ-_Au z1iRpduIsN~85j3%b9(wy*Kv3yVtAYy;eFKW@i6-b6CEA(;3sJU7DK%qz+yB_^0c2 z&qo`v-+JAZ$Imi*?bW|G|7WC+?5T^-Z_ZnJX4i)v#k#4FF1CC0{OEgeg1@a?DoOGE zoHM?BS+~WGiN0SlYoGSV2v?RfHSFq<8x(opugH0StZ4u0$xmNJAjWF7Ivb8`@_KbP zb%!p8>mSv*TNi$?Q~QkM%ChFu=ABWqW~OwddKX8BlnbulZ1mZ< zMy>M2yj3g${T%Us9(C*6?2$hBW8d$0#r(TBCLiC$9(UFH3(DEXkqQe~|4na=i(|Xh zvD|gOU9HWVmaSRSL=WF?a$OT?-)*qSOZ3zW|3kr?Cu7p*mQI`cF4Wp}0T<)7N6I2m zVRlS=j3dAI_D1|z%p4cp;w4-+KW6&I8dWWIK>@_5{?f(44cG7gwR&^z=9RqN zHU6`$^BaBVnjIHw*vY6ak|Nu z{cYRBzw0;h^Y6W1Z}IHT6wAxG2ZEnVEQ*Sa(5lcrJHv3X-llawZ1(?prTuuhj9JbT zmg?`1^Ve1{H`{jgSa#I=d8==`-MuCC*SP-RA%%H=V@@4bJ|=DN-BkPg?e=f;|NmL; zw>n5Z^-3o5l$}UTDDa^qI*y>@L>%WXTos~jko}Lp?9%7(U#<7QT3mQ{D|5rwsHKay z=G;02a#f)skFfRA*6cUGS&RQzTwf2mwGgzZFM3D8!q|$3tuIrGpPkvL=-hV0@VJby z%k=-N^d7!?y?%dQGaK(F>AW2WLB|qQKb;zW>HC!@57utKw<*})_9|#(an_xESMDH_pL77S+|zihHd^_cmKGa^p3e- z-)x#y`tHIpxyq`hhppRofDTvQesQt8_?lzl@imD(y|W_r85Q-uo;780HF``WL@IzH zzBMkc>$b(0$rsIX@9DhWT%~VaeL4Pl&dHs7`?nNcw%_`Ef7NNZITn}dE-$UWwxvQr zamv~qkGj77d_Mp7tn76!U+(+)OnUdXTiI*#@9+C|Ogewb`?+?tyFjNYmK~E!j{uD$ zzq+!r>~87x$n|l1*FmtbSMXyYQdC*~8B> z6KglQUR&)Qoqgj#&JAPXzrW+z->00NmMwEhcfcx|dnndVWu@HTi7+?fF{2E#I`aoj$p! z(R4%T?6o=kwMM6G&wb0ezdY)e`uv(pdv^*5fEF5lFH@@Fy|||K_qS`i%ky7fT-Gbc}{Puq~1g5|0crGZHSFzN0rqR(|+hGm^(!sk@B6)O`|LlUvw6QiTI}=Y?e_cI9v*HF7w$=``@Y!LtSTuZ+gV!Tno{-C zx9i{Lf8Udt-@^KDI{%>?$LF70@u@a3;&jf5z4^D+{;xUyj5TrX`?T!pe@Fi#87$#|taY+kW3+;AM3# zcgMpv%io;mt#8!*d^-KxpU>x`_t*Wc`D6R-M)JM<9_O6DU$5&&w5k7iuYcrT&SR^Y z&vrhaSN#5D-rZe4Gmktut+)FOXx`xW$K&#Q``_(&%(wWzMDXf$yH+hfZJPI?sQT5) zP|^L8FByI)(L@4d-q-Q?#h0vGS;>65kom3qwnk;(Um6L0J)&Gu(6*XjEYnpm?7 ztE`jgMsDhX>jw>W#@57Xlb3zcvTh9DC;7ZG@5-{^gL`&wi@JV!kKNbiHJRo&Q-sAc zXH>{nJZQYOEjRjha=-1L^tW5Do7EZdIx_Sdxl9!Hx49_b^MU7d>YB5zGt?f1nt`US zcqi&iFYK+_^ZA_hOO+?>8VwIhpU*9?x_jR8xlFwC+o#jxzm;%sbC`h^q`ckx{hnTe z;=4o+dk$H5xymJ=S%W&gpRZ@8&)Yc9w)&Rp^q5CY{7H&!2R=V&=D%h4`%SX?{F+VN zk;3YJKJ6=%&M4jsPRVhe z$xf2**0#*J)LtW-QyKCXH`(j@>~xR(WPO}lOlOnp!^yJ7#=ZXxcTu`8qulU#QFi22*HVC(yRzi%Cr&d>St zcTwSE1qQZ>f^r+|-|cwJb8ynfh!s60i4PU7@96IKbK7Q`?O`wVU6F-{B{NFnAvzXBpz3pK?kI3P zDDy$@@U!P0-R?Z|j9MI&*lNDtE!XpN;a`)(`XKf55n=xupxM<5VbIN;dJ(DK-3?6_ z8pC<)O-);bZPsk?oUFFfT>6mQy@HndPt6V6Z|CinjEj;`x}(@G^JwA14&RE~0rN9< zzuDAX`r?A(+qGinKUcn3*uINhbY9LACFFqs_Tc$dRRxt*|56rt8N-pL3~EpP#N?7g%;+ z-Q2e;7^QDbWdFX&`B(YIGw;_VmeoZZelzLv_RUkH!uY4}{rPP6-u@TsRhFMADz0_U zxm|qT_AYn7VWYcJ>G6Bj?`_2;B*Qn{PH5)6bo0q8b(bI(BfG`RMGgu6Jr=R_{SNbQ z<@<~-wTf0AxN+#WZl06F&K}2}PcI&at&O^wHaqv3lX|kyY16zN+m16BoZI!eIqYcQ`@J)(ce`*AJkRI90GN;8gr`e4xPeJML* z@7HUeO}7g;81YV2mQtL@;q-;^&PR*I_c~k+S}T{y*5Bj!eU{O7jk~%NgY*xnR9`9c zO>Mnmm9i0=b$-q@X-V58c|dpiyIC{ma`(@1+2GvLnSDLfd&Xmy9!~3Cx7!~rTwW;K zm{s;}bLZdY^jGBbV_~%lJ~w@vbAn~o`ShmO6%tey|`!9kvjSKt*`HGQ*N)D7!6(&>+I3|H6u1w=kROJ^|CHY zM8hHuI=_jC?=Ei9e`aJ85pl&{>XAT`pj^nzBuTk=4rvaCn|l@~$+g-E_I?O)DsT=+ zDEH%GWD9(};V|FoX{@hjfo_X**3A@t*mqQ-GvlW&Ma-VQ8*S~8X5Ll#6WNS4AG-g*~Qc9(`vnf1Lwr)_xY#*|JVH`Zm|u)!z&g7lW>W;x1`fkS0~?ctp|u z*PLHUXIz{ETtvE+v~%4Zl5z~z?GUpS+bQOHH0T%Sv6i!W`+h##c;id@KBG&WUKR`Z zBe?tR+}AAq`{#oD^0{SETerUW)H~bh=%Kk6yqq*2PUU&Kq=sd)L|1o#c<)DfTRqF~ zhxzR*{-=D7>;C>C7`<(i<>Zh!!*t=Y>Q}u7CdU50&E-4mr{47D_}w?_y#Ah#)(UGX zj*2Xyn*B>qU@vuETPVc4lBi7e7ikpu7Qe2=o&sBfv^|rd z`uYSH{<;;`^9vO#-zmn3=5GVt@?iT?fJrdGpyH7t=!6sg`A4)l1$Cyki_OcZCOtv~k&_z2Cm2{H}WSCM!~| z@QC0&{|euW-+UJ5zM0`Qmy^GhalYqb*)20axE|w(iioe%x&+^kk5o>AWAA2r>VYn>c>l&SPDt?yJQr8}_UZ2AN$QU$9{mg2moDBa_+!!a)P+W+vFKUFOYwq& zPe6THvc^-rrJ{{hY6eCfDa-qI9$R+qZ)N(PGmpY^w{42O`&{I9;@SU|M^l!qJX_8p ze9cYiiFTFCRki(2-ydx>srZm^KhQ9^=I~+8^Rspc)EMa>^8MU8Rqe7`|3@Jwha}x~ z863?OS4!XAx#|BfutojaQStbgRz}4x4#}euZ=DvL-jcm;=P`jRMU~Sg{yQ~0eyjQY z|Ho#v9{uMW`gS|}*G=!{-iqi>^R?M+e$01c$OpUEcZ*G}U!8fFcy`mvZQuQ5b01uc zP7w?LQXcVn@|)sY4FaH^)y{I!nX2oLpDErt_4UtRorjGiGZ+}y=6Sj}hHRYnhW(dR z|G_6alTLMHcKuB`Yi+j0;>UyL)psYY*1dVmckArpIR}Dui+LVLy8m9>u5@oQN1JEi z)cQ?3%x_zq3Y_AH7^wz#mOC6gS)N3O3F)cE#jpq*oOi#xr^y zVd6%{1It#IZCt$j?PJ9mrJ?pMT`w#{!c&jbaM~Z{UY&n`U*z5^0)9rWZ58>xEk^Io zs(n*%d+_k^qW2XHf=nIefoZprT8&Pf6tVcQUQEt>X?kW?X-+af?|*}ifbKQk?bj4ziYLyk`|@ntdB6X+J15zAnMQn`eA*~d z<#Osa(@NcV`_!(a7WZeHYEqx3VY4$Ykj?_~{8`BTZDtdc+`+Bt&y}qu8rl4N0 z{;UgEZgCWKFaD>6Rxc#HR9D!T^YXp(RtJ`8mQ2ES^98S27-wJK*4mypui)P0Z@xDS zC-*W$++UOYJM6TKuqo209dw*vfenkww5jcjiv+=49K=8vjJtw?X{Y$(l?}&Ma)KIO zNJ|Y7+yE}d&eWwBf})TH(qQ^QCN_4dDQsM`Xm@xo&PAlH4M#QwWoROwHULS75YoXF zw21WL-POksv)&LH7&*nsAt_RG%akzm@&M-1MW98bFW!Ydh6;d3sgT)TiV7Roh(vjz zZNY;3IN%~^O>xQhRfPzj!zICtr2-Qo!nkyoqV25%1pzoXR%9>ci6i!=4Z z6;L9e0|6E;-Ga-PqP`AEk*?+IrEsn(9!(B|C^<+?pA?blx?mrt&wRVPY3JwVt_)eV zuR9F;!gz0nMmAolh;A|6HKnhweGQt;=GZcUD^Pz$sK-hcfm0Im)<$jJ)W-XiB~r_N zsW>=M!&5hi(debHA>*RbY{TR>#aUO|6TbZydGqSap%5Qe1_lNOPgg&ebxsLQ0G|$G ARsaA1 literal 0 HcmV?d00001 diff --git a/doc/user/project/issues/index.md b/doc/user/project/issues/index.md index d71273ba970..200b3a642a1 100644 --- a/doc/user/project/issues/index.md +++ b/doc/user/project/issues/index.md @@ -155,3 +155,7 @@ Read through the [API documentation](../../../api/issues.md). ### Bulk editing issues Find out about [bulk editing issues](../../project/bulk_editing.md). + +### Similar issues + +Find out about [similar issues](similar_issues.md). diff --git a/doc/user/project/issues/similar_issues.md b/doc/user/project/issues/similar_issues.md new file mode 100644 index 00000000000..e90ecd88ec6 --- /dev/null +++ b/doc/user/project/issues/similar_issues.md @@ -0,0 +1,16 @@ +# Similar issues + +> [Introduced][ce-22866] in GitLab 11.6. + +Similar issues suggests issues that are similar when new issues are being created. +This features requires [GraphQL] to be enabled. + +![Similar issues](img/similar_issues.png) + +You can see the similar issues when typing in the title in the new issue form. +This searches both titles and descriptions across all issues the user has access +to in the current project. It then displays the first 5 issues sorted by most +recently updated. + +[GraphQL]: ../../../api/graphql/index.md +[ce-22866]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/22866 -- GitLab From 4619cbd253ad8b1d90d12d1b7f9cf15d70b3631d Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Mon, 10 Dec 2018 21:47:43 +0000 Subject: [PATCH 03/13] Merge branch 'sh-json-serialize-broadcast-messages' into 'master' Avoid caching BroadcastMessage as an ActiveRecord object Closes #55034 See merge request gitlab-org/gitlab-ce!23662 (cherry picked from commit ec76f4fd905c04706447dffee4f8061a2b8d4e1e) cde78f7f Avoid caching BroadcastMessage as an ActiveRecord object --- app/models/broadcast_message.rb | 42 +++++++++++++++++-- .../sh-json-serialize-broadcast-messages.yml | 5 +++ spec/models/broadcast_message_spec.rb | 37 +++++++++++++++- 3 files changed, 80 insertions(+), 4 deletions(-) create mode 100644 changelogs/unreleased/sh-json-serialize-broadcast-messages.yml diff --git a/app/models/broadcast_message.rb b/app/models/broadcast_message.rb index baf8adb318b..277f7c2717c 100644 --- a/app/models/broadcast_message.rb +++ b/app/models/broadcast_message.rb @@ -16,14 +16,20 @@ class BroadcastMessage < ActiveRecord::Base default_value_for :color, '#E75E40' default_value_for :font, '#FFFFFF' - CACHE_KEY = 'broadcast_message_current'.freeze + CACHE_KEY = 'broadcast_message_current_json'.freeze + LEGACY_CACHE_KEY = 'broadcast_message_current'.freeze after_commit :flush_redis_cache def self.current - messages = Rails.cache.fetch(CACHE_KEY, expires_in: cache_expires_in) { current_and_future_messages.to_a } + raw_messages = Rails.cache.fetch(CACHE_KEY, expires_in: cache_expires_in) do + remove_legacy_cache_key + current_and_future_messages.to_json + end - return messages if messages.empty? + messages = decode_messages(raw_messages) + + return [] unless messages&.present? now_or_future = messages.select(&:now_or_future?) @@ -34,6 +40,27 @@ class BroadcastMessage < ActiveRecord::Base now_or_future.select(&:now?) end + def self.decode_messages(raw_messages) + return unless raw_messages&.present? + + message_list = ActiveSupport::JSON.decode(raw_messages) + + return unless message_list.is_a?(Array) + + valid_attr = BroadcastMessage.attribute_names + + message_list.map do |raw| + BroadcastMessage.new(raw) if valid_cache_entry?(raw, valid_attr) + end.compact + rescue ActiveSupport::JSON.parse_error + end + + def self.valid_cache_entry?(raw, valid_attr) + return false unless raw.is_a?(Hash) + + (raw.keys - valid_attr).empty? + end + def self.current_and_future_messages where('ends_at > :now', now: Time.zone.now).order_id_asc end @@ -42,6 +69,14 @@ class BroadcastMessage < ActiveRecord::Base nil end + # This can be removed in GitLab 12.0+ + # The old cache key had an indefinite lifetime, and in an HA + # environment a one-shot migration would not work because the cache + # would be repopulated by a node that has not been upgraded. + def self.remove_legacy_cache_key + Rails.cache.delete(LEGACY_CACHE_KEY) + end + def active? started? && !ended? end @@ -68,5 +103,6 @@ class BroadcastMessage < ActiveRecord::Base def flush_redis_cache Rails.cache.delete(CACHE_KEY) + self.class.remove_legacy_cache_key end end diff --git a/changelogs/unreleased/sh-json-serialize-broadcast-messages.yml b/changelogs/unreleased/sh-json-serialize-broadcast-messages.yml new file mode 100644 index 00000000000..e8bee64f780 --- /dev/null +++ b/changelogs/unreleased/sh-json-serialize-broadcast-messages.yml @@ -0,0 +1,5 @@ +--- +title: Avoid caching BroadcastMessage as an ActiveRecord object +merge_request: 23662 +author: +type: fixed diff --git a/spec/models/broadcast_message_spec.rb b/spec/models/broadcast_message_spec.rb index 5326f9cb8c0..d6e5b557870 100644 --- a/spec/models/broadcast_message_spec.rb +++ b/spec/models/broadcast_message_spec.rb @@ -58,6 +58,12 @@ describe BroadcastMessage do end end + it 'does not create new records' do + create(:broadcast_message) + + expect { described_class.current }.not_to change { described_class.count } + end + it 'includes messages that need to be displayed in the future' do create(:broadcast_message) @@ -77,9 +83,37 @@ describe BroadcastMessage do it 'does not clear the cache if only a future message should be displayed' do create(:broadcast_message, :future) - expect(Rails.cache).not_to receive(:delete) + expect(Rails.cache).not_to receive(:delete).with(described_class::CACHE_KEY) expect(described_class.current.length).to eq(0) end + + it 'clears the legacy cache key' do + create(:broadcast_message, :future) + + expect(Rails.cache).to receive(:delete).with(described_class::LEGACY_CACHE_KEY) + expect(described_class.current.length).to eq(0) + end + + it 'gracefully handles bad cache entry' do + allow(described_class).to receive(:current_and_future_messages).and_return('{') + + expect(described_class.current).to be_empty + end + + it 'gracefully handles an empty hash' do + allow(described_class).to receive(:current_and_future_messages).and_return('{}') + + expect(described_class.current).to be_empty + end + + it 'gracefully handles unknown attributes' do + message = create(:broadcast_message) + + allow(described_class).to receive(:current_and_future_messages) + .and_return([{ bad_attr: 1 }, message]) + + expect(described_class.current).to eq([message]) + end end describe '#active?' do @@ -143,6 +177,7 @@ describe BroadcastMessage do message = create(:broadcast_message) expect(Rails.cache).to receive(:delete).with(described_class::CACHE_KEY) + expect(Rails.cache).to receive(:delete).with(described_class::LEGACY_CACHE_KEY) message.flush_redis_cache end -- GitLab From b1ac474dc753d61e48e38e68cd7f5613ae6dda8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Mon, 10 Dec 2018 12:03:01 +0000 Subject: [PATCH 04/13] Merge branch 'sh-ignore-arrays-url-sanitizer' into 'master' Only allow strings in URL::Sanitizer.valid? Closes #55079 See merge request gitlab-org/gitlab-ce!23675 (cherry picked from commit 5c5a5992c0602f14c7f4f43b5fc2756662fafb3c) 401be1d1 Only allow strings in URL::Sanitizer.valid? --- changelogs/unreleased/sh-ignore-arrays-url-sanitizer.yml | 5 +++++ lib/gitlab/url_sanitizer.rb | 1 + spec/lib/gitlab/url_sanitizer_spec.rb | 1 + 3 files changed, 7 insertions(+) create mode 100644 changelogs/unreleased/sh-ignore-arrays-url-sanitizer.yml diff --git a/changelogs/unreleased/sh-ignore-arrays-url-sanitizer.yml b/changelogs/unreleased/sh-ignore-arrays-url-sanitizer.yml new file mode 100644 index 00000000000..c010bd1f540 --- /dev/null +++ b/changelogs/unreleased/sh-ignore-arrays-url-sanitizer.yml @@ -0,0 +1,5 @@ +--- +title: Only allow strings in URL::Sanitizer.valid? +merge_request: 23675 +author: +type: fixed diff --git a/lib/gitlab/url_sanitizer.rb b/lib/gitlab/url_sanitizer.rb index 035268bc4f2..880712de5fe 100644 --- a/lib/gitlab/url_sanitizer.rb +++ b/lib/gitlab/url_sanitizer.rb @@ -14,6 +14,7 @@ module Gitlab def self.valid?(url) return false unless url.present? + return false unless url.is_a?(String) uri = Addressable::URI.parse(url.strip) diff --git a/spec/lib/gitlab/url_sanitizer_spec.rb b/spec/lib/gitlab/url_sanitizer_spec.rb index b41a81a8167..6e98a999766 100644 --- a/spec/lib/gitlab/url_sanitizer_spec.rb +++ b/spec/lib/gitlab/url_sanitizer_spec.rb @@ -41,6 +41,7 @@ describe Gitlab::UrlSanitizer do false | '123://invalid:url' false | 'valid@project:url.git' false | 'valid:pass@project:url.git' + false | %w(test array) true | 'ssh://example.com' true | 'ssh://:@example.com' true | 'ssh://foo@example.com' -- GitLab From 8a4ae2639bb0536dae0c1d62c779bd7f9c4048fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Trzci=C5=84ski?= Date: Mon, 10 Dec 2018 14:14:38 +0000 Subject: [PATCH 05/13] Merge branch '55090-fix-group-clusters-no-project-namespace' into 'master' Resolve "Project Namespace field should be removed from Group Cluster, Add existing" Closes #55090 See merge request gitlab-org/gitlab-ce!23679 (cherry picked from commit 2d85d362c626f7c4afdc3e8f7123672b3a6363c0) 6cbc982c Add failing feature spec 22289352 Set cluster_type for a new cluster 01dc3c96 Refactor to re-use similar block ecda32ea Extract Clusters::BuildService --- .../clusters/clusters_controller.rb | 12 +- app/services/clusters/build_service.rb | 21 +++ spec/features/groups/clusters/user_spec.rb | 126 ++++++++++++++++++ spec/services/clusters/build_service_spec.rb | 25 ++++ 4 files changed, 178 insertions(+), 6 deletions(-) create mode 100644 app/services/clusters/build_service.rb create mode 100644 spec/features/groups/clusters/user_spec.rb create mode 100644 spec/services/clusters/build_service_spec.rb diff --git a/app/controllers/clusters/clusters_controller.rb b/app/controllers/clusters/clusters_controller.rb index 2e9c77ae55c..9aa8b758539 100644 --- a/app/controllers/clusters/clusters_controller.rb +++ b/app/controllers/clusters/clusters_controller.rb @@ -181,15 +181,15 @@ class Clusters::ClustersController < Clusters::BaseController end def gcp_cluster - @gcp_cluster = ::Clusters::Cluster.new.tap do |cluster| - cluster.build_provider_gcp - end.present(current_user: current_user) + cluster = Clusters::BuildService.new(clusterable.subject).execute + cluster.build_provider_gcp + @gcp_cluster = cluster.present(current_user: current_user) end def user_cluster - @user_cluster = ::Clusters::Cluster.new.tap do |cluster| - cluster.build_platform_kubernetes - end.present(current_user: current_user) + cluster = Clusters::BuildService.new(clusterable.subject).execute + cluster.build_platform_kubernetes + @user_cluster = cluster.present(current_user: current_user) end def validate_gcp_token diff --git a/app/services/clusters/build_service.rb b/app/services/clusters/build_service.rb new file mode 100644 index 00000000000..8de73831164 --- /dev/null +++ b/app/services/clusters/build_service.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +module Clusters + class BuildService + def initialize(subject) + @subject = subject + end + + def execute + ::Clusters::Cluster.new.tap do |cluster| + case @subject + when ::Project + cluster.cluster_type = :project_type + when ::Group + cluster.cluster_type = :group_type + else + raise NotImplementedError + end + end + end + end +end diff --git a/spec/features/groups/clusters/user_spec.rb b/spec/features/groups/clusters/user_spec.rb new file mode 100644 index 00000000000..2410cd92e3f --- /dev/null +++ b/spec/features/groups/clusters/user_spec.rb @@ -0,0 +1,126 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'User Cluster', :js do + include GoogleApi::CloudPlatformHelpers + + let(:group) { create(:group) } + let(:user) { create(:user) } + + before do + group.add_maintainer(user) + gitlab_sign_in(user) + + allow(Groups::ClustersController).to receive(:STATUS_POLLING_INTERVAL) { 100 } + allow_any_instance_of(Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService).to receive(:execute) + end + + context 'when user does not have a cluster and visits cluster index page' do + before do + visit group_clusters_path(group) + + click_link 'Add Kubernetes cluster' + click_link 'Add existing cluster' + end + + context 'when user filled form with valid parameters' do + shared_examples 'valid cluster user form' do + it 'user sees a cluster details page' do + subject + + expect(page).to have_content('Kubernetes cluster integration') + expect(page.find_field('cluster[name]').value).to eq('dev-cluster') + expect(page.find_field('cluster[platform_kubernetes_attributes][api_url]').value) + .to have_content('http://example.com') + expect(page.find_field('cluster[platform_kubernetes_attributes][token]').value) + .to have_content('my-token') + end + end + + before do + fill_in 'cluster_name', with: 'dev-cluster' + fill_in 'cluster_platform_kubernetes_attributes_api_url', with: 'http://example.com' + fill_in 'cluster_platform_kubernetes_attributes_token', with: 'my-token' + end + + subject { click_button 'Add Kubernetes cluster' } + + it_behaves_like 'valid cluster user form' + + context 'RBAC is enabled for the cluster' do + before do + check 'cluster_platform_kubernetes_attributes_authorization_type' + end + + it_behaves_like 'valid cluster user form' + + it 'user sees a cluster details page with RBAC enabled' do + subject + + expect(page.find_field('cluster[platform_kubernetes_attributes][authorization_type]', disabled: true)).to be_checked + end + end + end + + context 'when user filled form with invalid parameters' do + before do + click_button 'Add Kubernetes cluster' + end + + it 'user sees a validation error' do + expect(page).to have_css('#error_explanation') + end + end + end + + context 'when user does have a cluster and visits cluster page' do + let(:cluster) { create(:cluster, :provided_by_user, cluster_type: :group_type, groups: [group]) } + + before do + visit group_cluster_path(group, cluster) + end + + it 'user sees a cluster details page' do + expect(page).to have_button('Save changes') + end + + context 'when user disables the cluster' do + before do + page.find(:css, '.js-cluster-enable-toggle-area .js-project-feature-toggle').click + page.within('#cluster-integration') { click_button 'Save changes' } + end + + it 'user sees the successful message' do + expect(page).to have_content('Kubernetes cluster was successfully updated.') + end + end + + context 'when user changes cluster parameters' do + before do + fill_in 'cluster_name', with: 'my-dev-cluster' + fill_in 'cluster_platform_kubernetes_attributes_token', with: 'new-token' + page.within('#js-cluster-details') { click_button 'Save changes' } + end + + it 'user sees the successful message' do + expect(page).to have_content('Kubernetes cluster was successfully updated.') + expect(cluster.reload.name).to eq('my-dev-cluster') + expect(cluster.reload.platform_kubernetes.token).to eq('new-token') + end + end + + context 'when user destroy the cluster' do + before do + page.accept_confirm do + click_link 'Remove integration' + end + end + + it 'user sees creation form with the successful message' do + expect(page).to have_content('Kubernetes cluster integration was successfully removed.') + expect(page).to have_link('Add Kubernetes cluster') + end + end + end +end diff --git a/spec/services/clusters/build_service_spec.rb b/spec/services/clusters/build_service_spec.rb new file mode 100644 index 00000000000..da0cb42b3a1 --- /dev/null +++ b/spec/services/clusters/build_service_spec.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Clusters::BuildService do + describe '#execute' do + subject { described_class.new(cluster_subject).execute } + + describe 'when cluster subject is a project' do + let(:cluster_subject) { build(:project) } + + it 'sets the cluster_type to project_type' do + is_expected.to be_project_type + end + end + + describe 'when cluster subject is a group' do + let(:cluster_subject) { build(:group) } + + it 'sets the cluster_type to group_type' do + is_expected.to be_group_type + end + end + end +end -- GitLab From 7fba1cce1643627d6ecf627149afb565e8f8f40e Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Mon, 10 Dec 2018 14:37:42 +0000 Subject: [PATCH 06/13] Merge branch '55104-frozenerror-can-t-modify-frozen-string' into 'master' Fix a frozen string error in app/mailers/notify.rb Closes #55104 See merge request gitlab-org/gitlab-ce!23683 (cherry picked from commit 80eebd8e33c5f2f26bc0fdd233d9d92c51edd242) d78272a1 Fix a frozen string error in app/mailers/notify.rb --- app/mailers/notify.rb | 2 +- .../55104-frozenerror-can-t-modify-frozen-string.yml | 5 +++++ spec/mailers/notify_spec.rb | 4 ++-- 3 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 changelogs/unreleased/55104-frozenerror-can-t-modify-frozen-string.yml diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb index 662f3e00047..88ad4c3e893 100644 --- a/app/mailers/notify.rb +++ b/app/mailers/notify.rb @@ -166,7 +166,7 @@ class Notify < BaseMailer headers['In-Reply-To'] = message_id(model) headers['References'] = [message_id(model)] - headers[:subject]&.prepend('Re: ') + headers[:subject] = "Re: #{headers[:subject]}" if headers[:subject] mail_thread(model, headers) end diff --git a/changelogs/unreleased/55104-frozenerror-can-t-modify-frozen-string.yml b/changelogs/unreleased/55104-frozenerror-can-t-modify-frozen-string.yml new file mode 100644 index 00000000000..994859b1d1d --- /dev/null +++ b/changelogs/unreleased/55104-frozenerror-can-t-modify-frozen-string.yml @@ -0,0 +1,5 @@ +--- +title: Fix a frozen string error in app/mailers/notify.rb +merge_request: 23683 +author: +type: fixed diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb index 150c00e4bfe..1d17aec0ded 100644 --- a/spec/mailers/notify_spec.rb +++ b/spec/mailers/notify_spec.rb @@ -28,8 +28,8 @@ describe Notify do end def have_referable_subject(referable, reply: false) - prefix = referable.project ? "#{referable.project.name} | " : '' - prefix.prepend('Re: ') if reply + prefix = (referable.project ? "#{referable.project.name} | " : '').freeze + prefix = "Re: #{prefix}" if reply suffix = "#{referable.title} (#{referable.to_reference})" -- GitLab From e309bf894cbee4570a2e477daa64606990fff361 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Mon, 10 Dec 2018 16:47:15 +0000 Subject: [PATCH 07/13] Merge branch '55116-runtimeerror-can-t-modify-frozen-string' into 'master' Fix a frozen string error in lib/gitlab/utils.rb Closes #55116 See merge request gitlab-org/gitlab-ce!23690 (cherry picked from commit e1064f16a8230396f16b175108ac54cdfefe212f) f233c3bc Fix a frozen string error in lib/gitlab/utils.rb --- .../55116-runtimeerror-can-t-modify-frozen-string.yml | 5 +++++ lib/gitlab/utils.rb | 2 +- spec/lib/gitlab/utils_spec.rb | 6 ++++++ 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/55116-runtimeerror-can-t-modify-frozen-string.yml diff --git a/changelogs/unreleased/55116-runtimeerror-can-t-modify-frozen-string.yml b/changelogs/unreleased/55116-runtimeerror-can-t-modify-frozen-string.yml new file mode 100644 index 00000000000..a98e70465b2 --- /dev/null +++ b/changelogs/unreleased/55116-runtimeerror-can-t-modify-frozen-string.yml @@ -0,0 +1,5 @@ +--- +title: Fix a frozen string error in lib/gitlab/utils.rb +merge_request: 23690 +author: +type: fixed diff --git a/lib/gitlab/utils.rb b/lib/gitlab/utils.rb index 26fc56227a2..a81cee0d6d2 100644 --- a/lib/gitlab/utils.rb +++ b/lib/gitlab/utils.rb @@ -60,7 +60,7 @@ module Gitlab # Converts newlines into HTML line break elements def nlbr(str) - ActionView::Base.full_sanitizer.sanitize(str, tags: []).gsub(/\r?\n/, '
').html_safe + ActionView::Base.full_sanitizer.sanitize(+str, tags: []).gsub(/\r?\n/, '
').html_safe end def remove_line_breaks(str) diff --git a/spec/lib/gitlab/utils_spec.rb b/spec/lib/gitlab/utils_spec.rb index 47a5fd0bdb4..f5a4b7e2ebf 100644 --- a/spec/lib/gitlab/utils_spec.rb +++ b/spec/lib/gitlab/utils_spec.rb @@ -44,6 +44,12 @@ describe Gitlab::Utils do end end + describe '.nlbr' do + it 'replaces new lines with
' do + expect(described_class.nlbr("hello\nworld".freeze)).to eq("hello
world") + end + end + describe '.remove_line_breaks' do using RSpec::Parameterized::TableSyntax -- GitLab From fcba3d2b6312f6e5fe8a4834314d702a026ef2c7 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Mon, 10 Dec 2018 23:17:07 +0000 Subject: [PATCH 08/13] Merge branch '11-6-update-gitignore' into 'master' Update the .gitignore See merge request gitlab-org/gitlab-ce!23706 (cherry picked from commit 185f8a5da6b4bd6090aa41e5f39ad0381200ee84) bc1b5ff3 Update the .gitignore --- vendor/gitignore/CMake.gitignore | 1 + vendor/gitignore/Drupal.gitignore | 77 ++++++++++++---------- vendor/gitignore/Global/Emacs.gitignore | 4 ++ vendor/gitignore/Global/PuTTY.gitignore | 2 + vendor/gitignore/Global/Virtuoso.gitignore | 18 +++++ vendor/gitignore/Global/Xcode.gitignore | 74 +++------------------ vendor/gitignore/Node.gitignore | 5 +- vendor/gitignore/Python.gitignore | 1 + vendor/gitignore/Smalltalk.gitignore | 9 +++ vendor/gitignore/TeX.gitignore | 4 ++ vendor/gitignore/Unity.gitignore | 4 ++ vendor/gitignore/VisualStudio.gitignore | 4 ++ 12 files changed, 102 insertions(+), 101 deletions(-) create mode 100644 vendor/gitignore/Global/PuTTY.gitignore create mode 100644 vendor/gitignore/Global/Virtuoso.gitignore diff --git a/vendor/gitignore/CMake.gitignore b/vendor/gitignore/CMake.gitignore index 9ea395f15ee..7e25564f9ec 100644 --- a/vendor/gitignore/CMake.gitignore +++ b/vendor/gitignore/CMake.gitignore @@ -1,3 +1,4 @@ +CMakeLists.txt.user CMakeCache.txt CMakeFiles CMakeScripts diff --git a/vendor/gitignore/Drupal.gitignore b/vendor/gitignore/Drupal.gitignore index 072b683190f..50d3eef8a33 100644 --- a/vendor/gitignore/Drupal.gitignore +++ b/vendor/gitignore/Drupal.gitignore @@ -1,39 +1,46 @@ -# Ignore configuration files that may contain sensitive information. -sites/*/*settings*.php -sites/example.sites.php +# gitignore template for Drupal 8 projects +# +# earlier versions of Drupal are tracked in `community/Python/` -# Ignore paths that contain generated content. -files/ -sites/*/files -sites/*/private -sites/*/translations +# Ignore configuration files that may contain sensitive information +/sites/*/*settings*.php +/sites/*/*services*.yml -# Ignore default text files -robots.txt -/CHANGELOG.txt -/COPYRIGHT.txt -/INSTALL*.txt +# Ignore paths that may contain user-generated content +/sites/*/files +/sites/*/public +/sites/*/private +/sites/*/files-public +/sites/*/files-private + +# Ignore paths that may contain temporary files +/sites/*/translations +/sites/*/tmp +/sites/*/cache + +# Ignore drupal core (if not versioning drupal sources) +/core +/modules/README.txt +/profiles/README.txt +/sites/README.txt +/sites/example.sites.php +/sites/example.settings.local.php +/sites/development.services.yml +/themes/README.txt +/vendor +/.csslintrc +/.editorconfig +/.eslintignore +/.eslintrc.json +/.gitattributes +/.htaccess +/autoload.php +/composer.json +/composer.lock +/example.gitignore +/index.php /LICENSE.txt -/MAINTAINERS.txt -/UPGRADE.txt /README.txt -sites/README.txt -sites/all/libraries/README.txt -sites/all/modules/README.txt -sites/all/themes/README.txt - -# Ignore everything but the "sites" folder ( for non core developer ) -.htaccess -web.config -authorize.php -cron.php -index.php -install.php -update.php -xmlrpc.php -/includes -/misc -/modules -/profiles -/scripts -/themes +/robots.txt +/update.php +/web.config diff --git a/vendor/gitignore/Global/Emacs.gitignore b/vendor/gitignore/Global/Emacs.gitignore index 3ac7904dcd2..d40e86599b5 100644 --- a/vendor/gitignore/Global/Emacs.gitignore +++ b/vendor/gitignore/Global/Emacs.gitignore @@ -43,3 +43,7 @@ flycheck_*.el # directory configuration .dir-locals.el + +# network security +/network-security.data + diff --git a/vendor/gitignore/Global/PuTTY.gitignore b/vendor/gitignore/Global/PuTTY.gitignore new file mode 100644 index 00000000000..c37466b1c79 --- /dev/null +++ b/vendor/gitignore/Global/PuTTY.gitignore @@ -0,0 +1,2 @@ +# Private key +*.ppk diff --git a/vendor/gitignore/Global/Virtuoso.gitignore b/vendor/gitignore/Global/Virtuoso.gitignore new file mode 100644 index 00000000000..2de03673a6c --- /dev/null +++ b/vendor/gitignore/Global/Virtuoso.gitignore @@ -0,0 +1,18 @@ +# Gitignore for Cadence Virtuoso +################################################################ + +# Log files +*.log +panic*.log.* + +# OpenAccess database lock files +*.cdslck* + +# Run directories for layout vs. schematic and design rule check +lvsRunDir/* +drcRunDir/* + +# Abstract generation tool +abstract.log* +abstract.record* + diff --git a/vendor/gitignore/Global/Xcode.gitignore b/vendor/gitignore/Global/Xcode.gitignore index b01314d3a64..cd0c7d3e45a 100644 --- a/vendor/gitignore/Global/Xcode.gitignore +++ b/vendor/gitignore/Global/Xcode.gitignore @@ -2,11 +2,17 @@ # # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore -## Build generated +## User settings +xcuserdata/ + +## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) +*.xcscmblueprint +*.xccheckout + +## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) build/ DerivedData/ - -## Various settings +*.moved-aside *.pbxuser !default.pbxuser *.mode1v3 @@ -15,65 +21,3 @@ DerivedData/ !default.mode2v3 *.perspectivev3 !default.perspectivev3 -xcuserdata/ - -## Other -*.moved-aside -*.xccheckout -*.xcscmblueprint - -## Obj-C/Swift specific -*.hmap -*.ipa -*.dSYM.zip -*.dSYM - -## Playgrounds -timeline.xctimeline -playground.xcworkspace - -# Swift Package Manager -# -# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. -# Packages/ -# Package.pins -# Package.resolved -.build/ - -# CocoaPods -# -# We recommend against adding the Pods directory to your .gitignore. However -# you should judge for yourself, the pros and cons are mentioned at: -# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control -# -# Pods/ -# -# Add this line if you want to avoid checking in source code from the Xcode workspace -# *.xcworkspace - -# Carthage -# -# Add this line if you want to avoid checking in source code from Carthage dependencies. -# Carthage/Checkouts - -Carthage/Build - -# fastlane -# -# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the -# screenshots whenever they are needed. -# For more information about the recommended setup visit: -# https://docs.fastlane.tools/best-practices/source-control/#source-control - -fastlane/report.xml -fastlane/Preview.html -fastlane/screenshots/**/*.png -fastlane/test_output - -# Code Injection -# -# After new code Injection tools there's a generated folder /iOSInjectionProject -# https://github.com/johnno1962/injectionforxcode - -iOSInjectionProject/ - diff --git a/vendor/gitignore/Node.gitignore b/vendor/gitignore/Node.gitignore index e1da6ae8ea5..ebfe43954dc 100644 --- a/vendor/gitignore/Node.gitignore +++ b/vendor/gitignore/Node.gitignore @@ -70,7 +70,10 @@ typings/ .vuepress/dist # Serverless directories -.serverless +.serverless/ # FuseBox cache .fusebox/ + +#DynamoDB Local files +.dynamodb/ diff --git a/vendor/gitignore/Python.gitignore b/vendor/gitignore/Python.gitignore index 510c73d0fdb..11614af2870 100644 --- a/vendor/gitignore/Python.gitignore +++ b/vendor/gitignore/Python.gitignore @@ -20,6 +20,7 @@ parts/ sdist/ var/ wheels/ +share/python-wheels/ *.egg-info/ .installed.cfg *.egg diff --git a/vendor/gitignore/Smalltalk.gitignore b/vendor/gitignore/Smalltalk.gitignore index 943995e1172..178d87af45b 100644 --- a/vendor/gitignore/Smalltalk.gitignore +++ b/vendor/gitignore/Smalltalk.gitignore @@ -1,8 +1,11 @@ # changes file *.changes +*.chg # system image *.image +*.img7 +*.img # Pharo Smalltalk Debug log file PharoDebug.log @@ -10,6 +13,12 @@ PharoDebug.log # Squeak Smalltalk Debug log file SqueakDebug.log +# Dolphin Smalltalk source file +*.sml + +# Dolphin Smalltalk error file +*.errors + # Monticello package cache /package-cache diff --git a/vendor/gitignore/TeX.gitignore b/vendor/gitignore/TeX.gitignore index 753f2b954ff..edd1f60b726 100644 --- a/vendor/gitignore/TeX.gitignore +++ b/vendor/gitignore/TeX.gitignore @@ -205,6 +205,10 @@ pythontex-files-*/ # todonotes *.tdo +# vhistory +*.hst +*.ver + # easy-todo *.lod diff --git a/vendor/gitignore/Unity.gitignore b/vendor/gitignore/Unity.gitignore index 833e6d4291c..93c9ce52191 100644 --- a/vendor/gitignore/Unity.gitignore +++ b/vendor/gitignore/Unity.gitignore @@ -35,3 +35,7 @@ sysinfo.txt # Builds *.apk *.unitypackage + +# Crashlytics generated file +Assets/StreamingAssets/crashlytics-build.properties + diff --git a/vendor/gitignore/VisualStudio.gitignore b/vendor/gitignore/VisualStudio.gitignore index 4d13c54854e..4ba92b04afb 100644 --- a/vendor/gitignore/VisualStudio.gitignore +++ b/vendor/gitignore/VisualStudio.gitignore @@ -20,6 +20,8 @@ [Rr]eleases/ x64/ x86/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ bld/ [Bb]in/ [Oo]bj/ @@ -229,6 +231,8 @@ orleans.codegen.cs # Since there are multiple workflows, uncomment next line to ignore bower_components # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) #bower_components/ +# ASP.NET Core default setup: bower directory is configured as wwwroot/lib/ and bower restore is true +**/wwwroot/lib/ # RIA/Silverlight projects Generated_Code/ -- GitLab From 70bd0e09d84e888df950b220a25fbef474c61b04 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Mon, 10 Dec 2018 22:40:37 +0000 Subject: [PATCH 09/13] Merge branch '11-6-update-license' into 'master' Update License info for 11.6 feature freeze See merge request gitlab-org/gitlab-ce!23707 (cherry picked from commit 5eb4a228a71e8eefc919e808a27b6b93d8a610df) e3a8b1c6 Update License info for 11.6 feature freeze --- vendor/licenses.csv | 154 ++++++++++++++++++++++++++++---------------- 1 file changed, 98 insertions(+), 56 deletions(-) diff --git a/vendor/licenses.csv b/vendor/licenses.csv index f6fd1efaa83..d706d76358a 100644 --- a/vendor/licenses.csv +++ b/vendor/licenses.csv @@ -67,10 +67,15 @@ @babel/template,7.1.2,MIT @babel/traverse,7.1.0,MIT @babel/types,7.1.2,MIT -@gitlab/svgs,1.35.0,MIT -@gitlab/ui,1.11.0,MIT +@gitlab/csslab,1.8.0,MIT +@gitlab/svgs,1.41.0,MIT +@gitlab/ui,1.15.0,MIT @sindresorhus/is,0.7.0,MIT +@types/async,2.0.50,MIT @types/jquery,2.0.48,MIT +@types/node,10.12.9,MIT +@types/semver,5.5.0,MIT +@types/zen-observable,0.8.0,MIT @vue/component-compiler-utils,2.2.0,MIT @webassemblyjs/ast,1.7.6,MIT @webassemblyjs/floating-point-hex-parser,1.7.6,MIT @@ -98,13 +103,14 @@ accepts,1.3.5,MIT ace-rails-ap,4.1.2,MIT acorn,5.7.3,MIT acorn-dynamic-import,3.0.0,MIT -actionmailer,4.2.10,MIT -actionpack,4.2.10,MIT -actionview,4.2.10,MIT -activejob,4.2.10,MIT -activemodel,4.2.10,MIT -activerecord,4.2.10,MIT -activesupport,4.2.10,MIT +actioncable,5.0.7,MIT +actionmailer,5.0.7,MIT +actionpack,5.0.7,MIT +actionview,5.0.7,MIT +activejob,5.0.7,MIT +activemodel,5.0.7,MIT +activerecord,5.0.7,MIT +activesupport,5.0.7,MIT acts-as-taggable-on,5.0.0,MIT addressable,2.5.2,Apache 2.0 aes_key_wrap,1.0.1,MIT @@ -119,24 +125,35 @@ ansi-regex,3.0.0,MIT ansi-styles,2.2.1,MIT ansi-styles,3.2.1,MIT anymatch,2.0.0,ISC +apollo-boost,0.1.20,MIT +apollo-cache,1.1.20,MIT +apollo-cache-inmemory,1.3.9,MIT +apollo-client,2.4.5,MIT +apollo-link,1.2.3,MIT +apollo-link-dedup,1.0.10,MIT +apollo-link-error,1.1.1,MIT +apollo-link-http,1.5.5,MIT +apollo-link-http-common,0.2.5,MIT +apollo-link-state,0.4.2,MIT +apollo-utilities,1.0.25,MIT aproba,1.2.0,ISC are-we-there-yet,1.1.4,ISC -arel,6.0.4,MIT +arel,7.1.4,MIT arr-diff,4.0.0,MIT arr-flatten,1.1.0,MIT arr-union,3.1.0,MIT array-flatten,1.1.1,MIT array-uniq,1.0.3,MIT array-unique,0.3.2,MIT -asana,0.6.0,MIT -asciidoctor,1.5.6.2,MIT +asana,0.8.1,MIT +asciidoctor,1.5.8,MIT asciidoctor-plantuml,0.0.8,MIT asn1.js,4.10.1,MIT assert,1.4.1,MIT assign-symbols,1.0.0,MIT async-each,1.0.1,MIT async-limiter,1.0.0,MIT -atob,2.0.3,(MIT OR Apache-2.0) +atob,2.1.2,(MIT OR Apache-2.0) atomic,1.1.99,Apache 2.0 attr_encrypted,3.1.0,MIT attr_required,1.0.0,MIT @@ -147,12 +164,13 @@ babel-code-frame,6.26.0,MIT babel-loader,8.0.4,MIT babel-polyfill,6.23.0,MIT babel-runtime,6.26.0,MIT +babel-standalone,6.26.0,MIT babosa,1.0.2,MIT balanced-match,1.0.0,MIT base,0.11.2,MIT base32,0.3.2,MIT base64-js,1.2.3,MIT -batch-loader,1.2.1,MIT +batch-loader,1.2.2,MIT bcrypt,3.1.12,MIT bcrypt_pbkdf,1.0.0,MIT bfj,6.1.1,MIT @@ -163,7 +181,7 @@ bindata,2.4.3,ruby bluebird,3.5.1,MIT bn.js,4.11.8,MIT body-parser,1.18.2,MIT -bootstrap,4.1.1,MIT +bootstrap,4.1.3,MIT bootstrap-vue,2.0.0-rc.11,MIT bootstrap_form,2.7.0,MIT brace-expansion,1.1.11,MIT @@ -216,7 +234,7 @@ clipboard,1.7.1,MIT cliui,4.0.0,ISC clone-response,1.0.2,MIT code-point-at,1.1.0,MIT -codesandbox-api,0.0.18,MIT +codesandbox-api,0.0.20,MIT codesandbox-import-util-types,1.2.11,LGPL codesandbox-import-utils,1.2.11,LGPL coercible,1.0.0,MIT @@ -224,14 +242,15 @@ collection-visit,1.0.0,MIT color-convert,1.9.3,MIT color-name,1.1.3,MIT commander,2.13.0,MIT -commander,2.18.0,MIT +commander,2.19.0,MIT commondir,1.0.1,MIT commonmarker,0.17.13,MIT component-emitter,1.2.1,MIT compression-webpack-plugin,2.0.0,MIT concat-map,0.0.1,MIT concat-stream,1.6.2,MIT -concurrent-ruby-ext,1.0.5,MIT +concurrent-ruby-ext,1.1.3,MIT +config-chain,1.1.12,MIT connection_pool,2.2.2,MIT console-browserify,1.1.0,MIT console-control-strings,1.1.0,ISC @@ -244,6 +263,7 @@ cookie,0.3.1,MIT cookie-signature,1.0.6,MIT copy-concurrently,1.0.5,ISC copy-descriptor,0.1.1,MIT +copy-to-clipboard,3.0.8,MIT core-js,2.3.0,MIT core-js,2.5.7,MIT core-util-is,1.0.2,MIT @@ -262,7 +282,6 @@ css-selector-tokenizer,0.7.0,MIT css_parser,1.5.0,MIT cssesc,0.1.0,MIT cyclist,0.2.2,MIT* -d3,4.12.2,New BSD d3,4.13.0,New BSD d3-array,1.2.1,New BSD d3-axis,1.0.8,New BSD @@ -275,7 +294,6 @@ d3-drag,1.2.1,New BSD d3-dsv,1.0.8,New BSD d3-ease,1.0.3,New BSD d3-force,1.1.0,New BSD -d3-format,1.2.1,New BSD d3-format,1.2.2,New BSD d3-geo,1.9.1,New BSD d3-hierarchy,1.1.5,New BSD @@ -287,7 +305,6 @@ d3-queue,3.0.7,New BSD d3-random,1.1.0,New BSD d3-request,1.0.6,New BSD d3-scale,1.0.7,New BSD -d3-selection,1.2.0,New BSD d3-selection,1.3.0,New BSD d3-shape,1.2.0,New BSD d3-time,1.0.8,New BSD @@ -302,7 +319,7 @@ date-now,0.1.4,MIT dateformat,3.0.3,MIT de-indent,1.0.2,MIT debug,2.6.9,MIT -debug,3.2.5,MIT +debug,3.2.6,MIT debugger-ruby_core_source,1.3.8,MIT decamelize,2.0.0,MIT deckar01-task_list,2.0.0,MIT @@ -310,8 +327,7 @@ declarative,0.0.10,MIT declarative-option,0.1.0,MIT decode-uri-component,0.2.0,MIT decompress-response,3.3.0,MIT -deep-extend,0.4.2,MIT -default_value_for,3.0.2,MIT +deep-extend,0.6.0,MIT define-properties,1.1.3,MIT define-property,0.2.5,MIT define-property,1.0.0,MIT @@ -330,6 +346,7 @@ devise-two-factor,3.0.0,MIT diff,3.5.0,New BSD diffie-hellman,5.0.2,MIT diffy,3.1.0,MIT +discordrb-webhooks-blackst0ne,3.3.0,MIT document-register-element,1.3.0,MIT dom-serializer,0.1.0,MIT domain-browser,1.1.7,MIT @@ -345,8 +362,10 @@ dropzone,4.2.0,MIT duplexer,0.1.1,MIT duplexer3,0.1.4,New BSD duplexify,3.5.3,MIT +echarts,4.2.0-rc.2,Apache 2.0 ed25519,1.2.4,MIT editions,1.3.4,MIT +editorconfig,0.15.2,MIT ee-first,1.1.1,MIT ejs,2.6.1,Apache 2.0 electron-to-chromium,1.3.73,ISC @@ -368,7 +387,7 @@ es-to-primitive,1.1.1,MIT es6-promise,3.0.2,MIT escape-html,1.0.3,MIT escape-string-regexp,1.0.5,MIT -escape_utils,1.1.1,MIT +escape_utils,1.2.1,MIT escaper,2.5.3,MIT eslint-scope,4.0.0,Simplified BSD esrecurse,4.2.1,Simplified BSD @@ -447,9 +466,10 @@ get-value,2.0.6,MIT get_process_mem,0.2.0,MIT gettext_i18n_rails,1.8.0,MIT gettext_i18n_rails_js,1.3.0,MIT -gitaly-proto,0.123.0,MIT +gitaly-proto,1.3.0,MIT github-markup,1.7.0,MIT -gitlab-markup,1.6.4,MIT +gitlab-default_value_for,3.1.1,MIT +gitlab-markup,1.6.5,MIT gitlab-sidekiq-fetcher,0.3.0,LGPL gitlab_omniauth-ldap,2.0.4,MIT glob,7.1.3,ISC @@ -464,7 +484,7 @@ google-protobuf,3.6.1,New BSD googleapis-common-protos-types,1.0.2,Apache 2.0 googleauth,0.6.6,Apache 2.0 got,8.3.0,MIT -gpgme,2.0.13,LGPL-2.1+ +gpgme,2.0.18,LGPL-2.1+ graceful-fs,4.1.11,ISC grape,1.1.0,MIT grape-entity,0.7.1,MIT @@ -473,6 +493,9 @@ grape_logging,1.7.0,MIT graphiql-rails,1.4.10,MIT graphlibrary,2.2.0,MIT graphql,1.8.1,MIT +graphql,14.0.2,MIT +graphql-anywhere,4.1.22,MIT +graphql-tag,2.10.0,MIT grpc,1.15.0,Apache 2.0 gzip-size,5.0.0,MIT hamlit,2.8.8,MIT @@ -496,6 +519,7 @@ hashie,3.5.7,MIT hashie-forbidden_attributes,0.1.1,MIT he,1.1.1,MIT health_check,2.6.0,MIT +highlight.js,9.13.1,New BSD hipchat,1.5.2,MIT hmac-drbg,1.0.1,MIT hoopy,0.1.4,MIT @@ -503,16 +527,16 @@ html-pipeline,2.8.4,MIT html2text,0.2.0,MIT htmlentities,4.3.4,MIT htmlparser2,3.9.2,MIT -http,2.2.2,MIT +http,3.3.0,MIT http-cache-semantics,3.8.1,Simplified BSD http-cookie,1.0.3,MIT http-errors,1.6.2,MIT -http-form_data,1.0.3,MIT +http-form_data,2.1.1,MIT http_parser.rb,0.6.0,MIT httparty,0.13.7,MIT httpclient,2.8.3,ruby https-browserify,1.0.0,MIT -i18n,0.9.5,MIT +i18n,1.1.1,MIT icalendar,2.4.1,ruby ice_nine,0.11.2,MIT iconv-lite,0.4.19,MIT @@ -523,6 +547,7 @@ ieee754,1.1.11,New BSD iferr,0.1.5,MIT ignore-walk,3.0.1,ISC immediate,3.0.6,MIT +immutable-tuple,0.4.9,MIT import-local,1.0.0,MIT imports-loader,0.8.0,MIT imurmurhash,0.1.4,MIT @@ -578,12 +603,14 @@ isobject,2.1.0,MIT isobject,3.0.1,MIT istextorbinary,2.2.1,MIT isurl,1.0.0,MIT +iterall,1.2.2,MIT jed,1.1.1,MIT jira-ruby,1.4.1,MIT jquery,3.3.1,MIT jquery-atwho-rails,1.3.2,MIT jquery-ujs,1.2.2,MIT jquery.waitforimages,2.2.0,MIT +js-beautify,1.8.8,MIT js-cookie,2.1.3,MIT js-levenshtein,1.1.4,MIT js-tokens,3.0.2,MIT @@ -611,7 +638,7 @@ kind-of,3.2.2,MIT kind-of,4.0.0,MIT kind-of,5.1.0,MIT kind-of,6.0.2,MIT -kubeclient,3.1.0,MIT +kubeclient,4.0.0,MIT lazy-cache,2.0.2,MIT lcid,2.0.0,MIT licensee,8.9.2,MIT @@ -631,7 +658,7 @@ lodash.isequal,4.5.0,MIT lodash.mergewith,4.6.0,MIT lodash.startcase,4.4.0,MIT lograge,0.10.0,MIT -loofah,2.2.2,MIT +loofah,2.2.3,MIT loose-envify,1.4.0,MIT lowercase-keys,1.0.0,MIT lru-cache,4.1.3,ISC @@ -653,17 +680,17 @@ memory-fs,0.4.1,MIT merge-descriptors,1.0.1,MIT merge-source-map,1.1.0,MIT mermaid,8.0.0-rc.8,MIT -method_source,0.9.0,MIT +method_source,0.9.2,MIT methods,1.1.2,MIT micromatch,3.1.10,MIT miller-rabin,4.0.1,MIT mime,1.4.1,MIT mime,2.3.1,MIT -mime-db,1.33.0,MIT -mime-types,2.1.18,MIT -mime-types,3.1,MIT -mime-types-data,3.2016.0521,MIT -mimemagic,0.3.0,MIT +mime-db,1.37.0,MIT +mime-types,2.1.21,MIT +mime-types,3.2.2,MIT +mime-types-data,3.2018.0812,MIT +mimemagic,0.3.2,MIT mimic-fn,1.1.0,MIT mimic-response,1.0.0,MIT mini_magick,4.8.0,MIT @@ -695,20 +722,22 @@ mustermann,1.0.3,MIT mustermann-grape,1.0.0,MIT mute-stream,0.0.7,ISC mysql2,0.4.10,MIT +nakayoshi_fork,0.0.4,MIT nan,2.10.0,MIT nanomatch,1.2.9,MIT -needle,2.2.1,MIT +needle,2.2.4,MIT negotiator,0.6.1,MIT neo-async,2.5.0,MIT net-ldap,0.16.0,MIT net-ssh,5.0.1,MIT netrc,0.11.0,MIT nice-try,1.0.4,MIT +nio4r,2.3.1,MIT node-fetch,1.6.3,MIT node-libs-browser,2.1.0,MIT -node-pre-gyp,0.10.0,New BSD +node-pre-gyp,0.10.3,New BSD node-releases,1.0.0-alpha.12,CC-BY-4.0 -nokogiri,1.8.4,MIT +nokogiri,1.8.5,MIT nokogumbo,1.5.0,Apache 2.0 nopt,4.0.1,ISC normalize-path,2.1.1,MIT @@ -752,6 +781,7 @@ onetime,2.0.1,MIT opencollective,1.0.3,MIT opener,1.5.1,(WTFPL OR MIT) opn,4.0.2,MIT +optimism,0.6.8,MIT org-ruby,0.9.12,MIT orm_adapter,0.5.0,MIT os,1.0.0,MIT @@ -818,6 +848,7 @@ process-nextick-args,1.0.7,MIT process-nextick-args,2.0.0,MIT prometheus-client-mmap,0.9.4,Apache 2.0 promise-inflight,1.0.1,ISC +proto-list,1.2.4,ISC proxy-addr,2.0.4,MIT prr,1.0.1,MIT pseudomap,1.0.2,ISC @@ -835,20 +866,20 @@ qs,6.5.1,New BSD query-string,5.1.1,MIT querystring,0.2.0,MIT querystring-es3,0.2.1,MIT -rack,1.6.10,MIT +rack,2.0.6,MIT rack-accept,0.4.5,MIT rack-attack,4.4.1,MIT rack-cors,1.0.2,MIT rack-oauth2,1.2.3,MIT -rack-protection,2.0.3,MIT +rack-protection,2.0.4,MIT rack-proxy,0.6.0,MIT rack-test,0.6.3,MIT -rails,4.2.10,MIT +rails,5.0.7,MIT rails-deprecated_sanitizer,1.0.3,MIT -rails-dom-testing,1.0.9,MIT +rails-dom-testing,2.0.3,MIT rails-html-sanitizer,1.0.4,MIT -rails-i18n,4.0.9,MIT -railties,4.2.10,MIT +rails-i18n,5.1.1,MIT +railties,5.0.7,MIT rainbow,3.0.0,MIT raindrops,0.18.0,LGPL-2.1+ rake,12.3.1,MIT @@ -862,7 +893,7 @@ raw-loader,0.5.1,MIT rb-fsevent,0.10.2,MIT rb-inotify,0.9.10,MIT rbtrace,0.4.10,MIT -rc,1.2.5,(BSD-2-Clause OR MIT OR Apache-2.0) +rc,1.2.8,(BSD-2-Clause OR MIT OR Apache-2.0) rdoc,6.0.4,ruby re2,1.1.1,New BSD readable-stream,2.0.6,MIT @@ -877,7 +908,7 @@ redis-activesupport,5.0.4,MIT redis-namespace,1.6.0,MIT redis-rack,2.0.4,MIT redis-rails,5.0.2,MIT -redis-store,1.4.1,MIT +redis-store,1.6.0,MIT regenerate,1.4.0,MIT regenerate-unicode-properties,7.0.0,MIT regenerator-runtime,0.10.5,MIT @@ -920,7 +951,7 @@ ruby-fogbugz,0.2.1,MIT ruby-prof,0.17.0,Simplified BSD ruby-progressbar,1.9.0,MIT ruby-saml,1.7.2,MIT -ruby_parser,3.9.0,MIT +ruby_parser,3.11.0,MIT rubyntlm,0.6.2,MIT rubypants,0.2.0,BSD rufus-scheduler,3.4.0,MIT @@ -949,9 +980,9 @@ seed-fu,2.3.7,MIT select,1.1.2,MIT select2,3.5.2-browserify,Apache* select2-rails,3.5.9.3,MIT -semver,5.5.1,ISC +semver,5.6.0,ISC send,0.16.2,MIT -sentry-raven,2.7.2,Apache 2.0 +sentry-raven,2.7.4,Apache 2.0 serialize-javascript,1.4.0,New BSD serve-static,1.13.2,MIT set-blocking,2.0.0,ISC @@ -963,18 +994,19 @@ setimmediate,1.0.5,MIT setprototypeof,1.0.3,ISC setprototypeof,1.1.0,ISC settingslogic,2.0.9,MIT -sexp_processor,4.9.0,MIT +sexp_processor,4.11.0,MIT sha.js,2.4.10,MIT sha1,1.1.1,New BSD shebang-command,1.2.0,MIT shebang-regex,1.0.0,MIT -sidekiq,5.2.1,LGPL +sidekiq,5.2.3,LGPL sidekiq-cron,0.6.0,MIT +sigmund,1.0.1,ISC signal-exit,3.0.2,ISC signet,0.11.0,Apache 2.0 slack-notifier,1.5.1,MIT slugify,1.3.1,MIT -smooshpack,0.0.48,LGPL +smooshpack,0.0.53,LGPL snapdragon,0.8.1,MIT snapdragon-node,2.1.1,MIT snapdragon-util,3.0.1,MIT @@ -1018,6 +1050,7 @@ style-loader,0.23.0,MIT supports-color,2.0.0,MIT supports-color,5.5.0,MIT svg4everybody,2.1.9,CC0-1.0 +symbol-observable,1.2.0,MIT sys-filesystem,1.1.6,Artistic 2.0 tapable,1.1.0,MIT tar,4.4.4,ISC @@ -1029,6 +1062,7 @@ thread_safe,0.3.6,Apache 2.0 three,0.84.0,MIT three-orbit-controls,82.1.0,MIT three-stl-loader,1.0.4,MIT +throttle-debounce,2.0.1,MIT through,2.3.8,MIT through2,2.0.3,MIT tilt,2.0.8,MIT @@ -1043,6 +1077,7 @@ to-fast-properties,2.0.0,MIT to-object-path,0.3.0,MIT to-regex,3.0.2,MIT to-regex-range,2.1.1,MIT +toggle-selection,1.0.6,MIT toml-rb,1.0.0,MIT trim-right,1.0.1,MIT trollop,2.1.3,MIT @@ -1079,6 +1114,7 @@ urix,0.1.0,MIT url,0.11.0,MIT url-loader,1.1.1,MIT url-parse-lax,3.0.0,MIT +url-search-params-polyfill,5.0.0,MIT url-to-options,1.0.1,MIT use,2.0.2,MIT util,0.10.3,MIT @@ -1094,6 +1130,7 @@ visibilityjs,1.2.4,MIT vm-browserify,0.0.4,MIT vmstat,2.3.0,MIT vue,2.5.17,MIT +vue-apollo,3.0.0-beta.25,ISC vue-functional-data-merge,2.0.6,MIT vue-hot-reload-api,2.3.0,MIT vue-loader,15.4.2,MIT @@ -1112,6 +1149,8 @@ webpack-cli,3.1.0,MIT webpack-rails,0.9.11,MIT webpack-sources,1.3.0,MIT webpack-stats-plugin,0.2.1,MIT +websocket-driver,0.6.5,MIT +websocket-extensions,0.1.3,MIT which,1.3.0,ISC which-module,2.0.0,ISC wide-align,1.1.2,ISC @@ -1131,3 +1170,6 @@ yallist,2.1.2,ISC yallist,3.0.2,ISC yargs,12.0.2,MIT yargs-parser,10.1.0,ISC +zen-observable,0.8.11,MIT +zen-observable-ts,0.8.10,MIT +zrender,4.0.5,New BSD -- GitLab From 8e245c303bf86de9704248c7daed8f306fd5c1c7 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 11 Dec 2018 08:17:56 +0000 Subject: [PATCH 10/13] Merge branch '55138-fix-mr-discussions-count' into 'master' Fix MR discussion counts being off Closes #55138 See merge request gitlab-org/gitlab-ce!23710 (cherry picked from commit 97ba7735eaefa0e749295b722434e1d3826bbbc2) 958aaebd Fix MR discussion counts being off --- .../javascripts/notes/stores/mutations.js | 2 +- .../55138-fix-mr-discussions-count.yml | 5 ++ .../javascripts/notes/stores/mutation_spec.js | 71 ++++++++++++------- 3 files changed, 50 insertions(+), 28 deletions(-) create mode 100644 changelogs/unreleased/55138-fix-mr-discussions-count.yml diff --git a/app/assets/javascripts/notes/stores/mutations.js b/app/assets/javascripts/notes/stores/mutations.js index bea396e5bb6..dfce698e56f 100644 --- a/app/assets/javascripts/notes/stores/mutations.js +++ b/app/assets/javascripts/notes/stores/mutations.js @@ -245,7 +245,7 @@ export default { discussion => !discussion.individual_note && discussion.resolvable && - discussion.notes.some(note => !note.resolved), + discussion.notes.some(note => note.resolvable && !note.resolved), ).length; state.hasUnresolvedDiscussions = state.unresolvedDiscussionsCount > 1; }, diff --git a/changelogs/unreleased/55138-fix-mr-discussions-count.yml b/changelogs/unreleased/55138-fix-mr-discussions-count.yml new file mode 100644 index 00000000000..667e9b971d8 --- /dev/null +++ b/changelogs/unreleased/55138-fix-mr-discussions-count.yml @@ -0,0 +1,5 @@ +--- +title: Fix MR resolved discussion counts being too low +merge_request: 23710 +author: +type: fixed diff --git a/spec/javascripts/notes/stores/mutation_spec.js b/spec/javascripts/notes/stores/mutation_spec.js index 52cdc16353a..3fbae82f16c 100644 --- a/spec/javascripts/notes/stores/mutation_spec.js +++ b/spec/javascripts/notes/stores/mutation_spec.js @@ -9,6 +9,11 @@ import { individualNote, } from '../mock_data'; +const RESOLVED_NOTE = { resolvable: true, resolved: true }; +const UNRESOLVED_NOTE = { resolvable: true, resolved: false }; +const SYSTEM_NOTE = { resolvable: false, resolved: false }; +const WEIRD_NOTE = { resolvable: false, resolved: true }; + describe('Notes Store mutations', () => { describe('ADD_NEW_NOTE', () => { let state; @@ -449,49 +454,61 @@ describe('Notes Store mutations', () => { }); describe('UPDATE_RESOLVABLE_DISCUSSIONS_COUNTS', () => { - it('updates resolvableDiscussionsCount', () => { - const state = { - discussions: [ - { individual_note: false, resolvable: true, notes: [] }, - { individual_note: true, resolvable: true, notes: [] }, - { individual_note: false, resolvable: false, notes: [] }, - ], - resolvableDiscussionsCount: 0, - }; - - mutations.UPDATE_RESOLVABLE_DISCUSSIONS_COUNTS(state); - - expect(state.resolvableDiscussionsCount).toBe(1); - }); - - it('updates unresolvedDiscussionsCount', () => { + it('with unresolvable discussions, updates state', () => { const state = { discussions: [ - { individual_note: false, resolvable: true, notes: [{ resolved: false }] }, - { individual_note: true, resolvable: true, notes: [{ resolved: false }] }, - { individual_note: false, resolvable: false, notes: [{ resolved: false }] }, + { individual_note: false, resolvable: true, notes: [UNRESOLVED_NOTE] }, + { individual_note: true, resolvable: true, notes: [UNRESOLVED_NOTE] }, + { individual_note: false, resolvable: false, notes: [UNRESOLVED_NOTE] }, ], - unresolvedDiscussionsCount: 0, }; mutations.UPDATE_RESOLVABLE_DISCUSSIONS_COUNTS(state); - expect(state.unresolvedDiscussionsCount).toBe(1); + expect(state).toEqual( + jasmine.objectContaining({ + resolvableDiscussionsCount: 1, + unresolvedDiscussionsCount: 1, + hasUnresolvedDiscussions: false, + }), + ); }); - it('updates hasUnresolvedDiscussions', () => { + it('with resolvable discussions, updates state', () => { const state = { discussions: [ - { individual_note: false, resolvable: true, notes: [{ resolved: false }] }, - { individual_note: false, resolvable: true, notes: [{ resolved: false }] }, - { individual_note: false, resolvable: false, notes: [{ resolved: false }] }, + { + individual_note: false, + resolvable: true, + notes: [RESOLVED_NOTE, SYSTEM_NOTE, RESOLVED_NOTE], + }, + { + individual_note: false, + resolvable: true, + notes: [RESOLVED_NOTE, SYSTEM_NOTE, WEIRD_NOTE], + }, + { + individual_note: false, + resolvable: true, + notes: [SYSTEM_NOTE, RESOLVED_NOTE, WEIRD_NOTE, UNRESOLVED_NOTE], + }, + { + individual_note: false, + resolvable: true, + notes: [UNRESOLVED_NOTE], + }, ], - hasUnresolvedDiscussions: 0, }; mutations.UPDATE_RESOLVABLE_DISCUSSIONS_COUNTS(state); - expect(state.hasUnresolvedDiscussions).toBe(true); + expect(state).toEqual( + jasmine.objectContaining({ + resolvableDiscussionsCount: 4, + unresolvedDiscussionsCount: 2, + hasUnresolvedDiscussions: true, + }), + ); }); }); }); -- GitLab From 5637c566f97f9afa697e95beddfbf7fc32f8ed0a Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Tue, 11 Dec 2018 08:58:46 +0000 Subject: [PATCH 11/13] Merge branch 'sh-revert-mr-22911' into 'master' Revert "Merge branch '28682-can-merge-branch-before-build-is-started' into 'master'" See merge request gitlab-org/gitlab-ce!23715 (cherry picked from commit 85f430cb3cde4ff8c4d24c1b2a426670e38dd44f) 1bd7f7cb Revert "Merge branch '28682-can-merge-branch-before-build-is-started' into 'master'" --- app/models/merge_request.rb | 1 + .../28682-can-merge-branch-before-build-is-started.yml | 5 ----- spec/models/merge_request_spec.rb | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) delete mode 100644 changelogs/unreleased/28682-can-merge-branch-before-build-is-started.yml diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 861211ffc0a..77e48ce11e8 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -978,6 +978,7 @@ class MergeRequest < ActiveRecord::Base def mergeable_ci_state? return true unless project.only_allow_merge_if_pipeline_succeeds? + return true unless head_pipeline actual_head_pipeline&.success? || actual_head_pipeline&.skipped? end diff --git a/changelogs/unreleased/28682-can-merge-branch-before-build-is-started.yml b/changelogs/unreleased/28682-can-merge-branch-before-build-is-started.yml deleted file mode 100644 index 5ffd93e098f..00000000000 --- a/changelogs/unreleased/28682-can-merge-branch-before-build-is-started.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Strictly require a pipeline to merge. -merge_request: 22911 -author: -type: changed diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 9b60054e14a..c3152d2021b 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -1885,7 +1885,7 @@ describe MergeRequest do allow(subject).to receive(:head_pipeline) { nil } end - it { expect(subject.mergeable_ci_state?).to be_falsey } + it { expect(subject.mergeable_ci_state?).to be_truthy } end end -- GitLab From 4abe49f13cac4b57750f8dc53a5a9db28214380d Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Tue, 11 Dec 2018 20:38:59 +0000 Subject: [PATCH 12/13] Merge branch '55183-frozenerror-can-t-modify-frozen-string-in-app-mailers-notify-rb' into 'master' Fix a potential frozen string error in app/mailers/notify.rb Closes #55183 See merge request gitlab-org/gitlab-ce!23728 --- app/mailers/notify.rb | 4 ++-- ...t-modify-frozen-string-in-app-mailers-notify-rb.yml | 5 +++++ spec/mailers/notify_spec.rb | 10 +--------- spec/support/helpers/email_helpers.rb | 9 +++++++++ 4 files changed, 17 insertions(+), 11 deletions(-) create mode 100644 changelogs/unreleased/55183-frozenerror-can-t-modify-frozen-string-in-app-mailers-notify-rb.yml diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb index 88ad4c3e893..6d86b60c50c 100644 --- a/app/mailers/notify.rb +++ b/app/mailers/notify.rb @@ -128,7 +128,7 @@ class Notify < BaseMailer address.display_name = reply_display_name(model) end - fallback_reply_message_id = "".freeze + fallback_reply_message_id = "" headers['References'] ||= [] headers['References'].unshift(fallback_reply_message_id) @@ -178,7 +178,7 @@ class Notify < BaseMailer headers['X-GitLab-Discussion-ID'] = note.discussion.id if note.part_of_discussion? - headers[:subject]&.prepend('Re: ') + headers[:subject] = "Re: #{headers[:subject]}" if headers[:subject] mail_thread(model, headers) end diff --git a/changelogs/unreleased/55183-frozenerror-can-t-modify-frozen-string-in-app-mailers-notify-rb.yml b/changelogs/unreleased/55183-frozenerror-can-t-modify-frozen-string-in-app-mailers-notify-rb.yml new file mode 100644 index 00000000000..685a8309c72 --- /dev/null +++ b/changelogs/unreleased/55183-frozenerror-can-t-modify-frozen-string-in-app-mailers-notify-rb.yml @@ -0,0 +1,5 @@ +--- +title: Fix a potential frozen string error in app/mailers/notify.rb +merge_request: 23728 +author: +type: fixed diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb index 1d17aec0ded..f6e5c9d33ac 100644 --- a/spec/mailers/notify_spec.rb +++ b/spec/mailers/notify_spec.rb @@ -4,6 +4,7 @@ require 'email_spec' describe Notify do include EmailSpec::Helpers include EmailSpec::Matchers + include EmailHelpers include RepoHelpers include_context 'gitlab email notification' @@ -27,15 +28,6 @@ describe Notify do description: 'My awesome description!') end - def have_referable_subject(referable, reply: false) - prefix = (referable.project ? "#{referable.project.name} | " : '').freeze - prefix = "Re: #{prefix}" if reply - - suffix = "#{referable.title} (#{referable.to_reference})" - - have_subject [prefix, suffix].compact.join - end - context 'for a project' do shared_examples 'an assignee email' do it 'is sent to the assignee as the author' do diff --git a/spec/support/helpers/email_helpers.rb b/spec/support/helpers/email_helpers.rb index 1fb8252459f..ad6e1064499 100644 --- a/spec/support/helpers/email_helpers.rb +++ b/spec/support/helpers/email_helpers.rb @@ -34,4 +34,13 @@ module EmailHelpers def find_email_for(user) ActionMailer::Base.deliveries.find { |d| d.to.include?(user.notification_email) } end + + def have_referable_subject(referable, include_project: true, reply: false) + prefix = (include_project && referable.project ? "#{referable.project.name} | " : '').freeze + prefix = "Re: #{prefix}" if reply + + suffix = "#{referable.title} (#{referable.to_reference})" + + have_subject [prefix, suffix].compact.join + end end -- GitLab From 63acce291a7c588da2252f980aa660cbf5f7b65c Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Tue, 11 Dec 2018 22:05:11 +0000 Subject: [PATCH 13/13] Merge branch 'sh-fix-diff-check-issue-55137-ce' into 'master' [CE] Fix DiffCheck failing due to invalid string argument See merge request gitlab-org/gitlab-ce!23741 --- lib/gitlab/checks/diff_check.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/gitlab/checks/diff_check.rb b/lib/gitlab/checks/diff_check.rb index 49d361fcef7..8ee345ab45a 100644 --- a/lib/gitlab/checks/diff_check.rb +++ b/lib/gitlab/checks/diff_check.rb @@ -11,6 +11,7 @@ module Gitlab }.freeze def validate! + return if deletion? || newrev.nil? return unless should_run_diff_validations? return if commits.empty? return unless uses_raw_delta_validations? @@ -28,7 +29,7 @@ module Gitlab private def should_run_diff_validations? - newrev && oldrev && !deletion? && validate_lfs_file_locks? + validate_lfs_file_locks? end def validate_lfs_file_locks? -- GitLab