diff options
Diffstat (limited to 'tests')
335 files changed, 17240 insertions, 5582 deletions
diff --git a/tests/TestsAutoLoader.php b/tests/TestsAutoLoader.php index 2e8fed44..def23dad 100644 --- a/tests/TestsAutoLoader.php +++ b/tests/TestsAutoLoader.php @@ -44,18 +44,18 @@ $wgAutoloadClasses += array( 'ResourceLoaderTestCase' => "$testDir/phpunit/ResourceLoaderTestCase.php", 'ResourceLoaderTestModule' => "$testDir/phpunit/ResourceLoaderTestCase.php", 'ResourceLoaderFileModuleTestModule' => "$testDir/phpunit/ResourceLoaderTestCase.php", - 'ResourceLoaderWikiModuleTestModule' => "$testDir/phpunit/ResourceLoaderTestCase.php", 'TestUser' => "$testDir/phpunit/includes/TestUser.php", 'LessFileCompilationTest' => "$testDir/phpunit/LessFileCompilationTest.php", # tests/phpunit/includes - 'BlockTest' => "$testDir/phpunit/includes/BlockTest.php", - 'RevisionStorageTest' => "$testDir/phpunit/includes/RevisionStorageTest.php", - 'WikiPageTest' => "$testDir/phpunit/includes/WikiPageTest.php", + 'TestingAccessWrapper' => "$testDir/phpunit/includes/TestingAccessWrapper.php", # tests/phpunit/includes/api 'ApiFormatTestBase' => "$testDir/phpunit/includes/api/format/ApiFormatTestBase.php", + 'ApiQueryTestBase' => "$testDir/phpunit/includes/api/query/ApiQueryTestBase.php", + 'ApiQueryContinueTestBase' => "$testDir/phpunit/includes/api/query/ApiQueryContinueTestBase.php", 'ApiTestCase' => "$testDir/phpunit/includes/api/ApiTestCase.php", + 'ApiTestCaseUpload' => "$testDir/phpunit/includes/api/ApiTestCaseUpload.php", 'ApiTestContext' => "$testDir/phpunit/includes/api/ApiTestContext.php", 'MockApi' => "$testDir/phpunit/includes/api/MockApi.php", 'MockApiQueryBase' => "$testDir/phpunit/includes/api/MockApiQueryBase.php", @@ -79,9 +79,16 @@ $wgAutoloadClasses += array( 'PageORMTableForTesting' => "$testDir/phpunit/includes/db/ORMTableTest.php", 'DatabaseTestHelper' => "$testDir/phpunit/includes/db/DatabaseTestHelper.php", - # tests/phpunit/includes/passwords + # tests/phpunit/includes/diff + 'FakeDiffOp' => "$testDir/phpunit/includes/diff/FakeDiffOp.php", + + # tests/phpunit/includes/password 'PasswordTestCase' => "$testDir/phpunit/includes/password/PasswordTestCase.php", + # tests/phpunit/includes/resourceloader + 'ResourceLoaderImageModuleTest' => "$testDir/phpunit/includes/resourceloader/ResourceLoaderImageModuleTest.php", + 'ResourceLoaderImageModuleTestable' => "$testDir/phpunit/includes/resourceloader/ResourceLoaderImageModuleTest.php", + # tests/phpunit/languages 'LanguageClassesTestCase' => "$testDir/phpunit/languages/LanguageClassesTestCase.php", @@ -112,4 +119,7 @@ $wgAutoloadClasses += array( # tests/phpunit/includes/site 'SiteTest' => "$testDir/phpunit/includes/site/SiteTest.php", 'TestSites' => "$testDir/phpunit/includes/site/TestSites.php", + + # tests/phpunit/includes/specialpage + 'SpecialPageTestHelper' => "$testDir/phpunit/includes/specialpage/SpecialPageTestHelper.php", ); diff --git a/tests/browser/Gemfile.lock b/tests/browser/Gemfile.lock deleted file mode 100644 index 1ea4eb55..00000000 --- a/tests/browser/Gemfile.lock +++ /dev/null @@ -1,82 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - builder (3.2.2) - childprocess (0.5.3) - ffi (~> 1.0, >= 1.0.11) - cucumber (1.3.16) - builder (>= 2.1.2) - diff-lcs (>= 1.1.3) - gherkin (~> 2.12) - multi_json (>= 1.7.5, < 2.0) - multi_test (>= 0.1.1) - data_magic (0.19) - faker (>= 1.1.2) - yml_reader (>= 0.3) - diff-lcs (1.2.5) - domain_name (0.5.20) - unf (>= 0.0.5, < 1.0.0) - faker (1.4.3) - i18n (~> 0.5) - faraday (0.9.0) - multipart-post (>= 1.2, < 3) - faraday-cookie_jar (0.0.6) - faraday (>= 0.7.4) - http-cookie (~> 1.0.0) - ffi (1.9.3) - gherkin (2.12.2) - multi_json (~> 1.3) - headless (1.0.2) - http-cookie (1.0.2) - domain_name (~> 0.5) - i18n (0.6.11) - json (1.8.1) - mediawiki_api (0.2.1) - faraday (~> 0.9, >= 0.9.0) - faraday-cookie_jar (~> 0.0, >= 0.0.6) - mediawiki_selenium (0.3.2) - cucumber (~> 1.3, >= 1.3.10) - headless (~> 1.0, >= 1.0.1) - json (~> 1.8, >= 1.8.1) - mediawiki_api (~> 0.2, >= 0.2.1) - page-object (~> 1.0) - rest-client (~> 1.6, >= 1.6.7) - rspec-expectations (~> 2.14, >= 2.14.4) - syntax (~> 1.2, >= 1.2.0) - mime-types (2.3) - multi_json (1.10.1) - multi_test (0.1.1) - multipart-post (2.0.0) - netrc (0.7.7) - page-object (1.0.2) - page_navigation (>= 0.9) - selenium-webdriver (>= 2.42.0) - watir-webdriver (>= 0.6.9) - page_navigation (0.9) - data_magic (>= 0.14) - rest-client (1.7.2) - mime-types (>= 1.16, < 3.0) - netrc (~> 0.7) - rspec-expectations (2.99.2) - diff-lcs (>= 1.1.3, < 2.0) - rubyzip (1.1.6) - selenium-webdriver (2.42.0) - childprocess (>= 0.5.0) - multi_json (~> 1.0) - rubyzip (~> 1.0) - websocket (~> 1.0.4) - syntax (1.2.0) - unf (0.1.4) - unf_ext - unf_ext (0.0.6) - watir-webdriver (0.6.10) - selenium-webdriver (>= 2.18.0) - websocket (1.0.7) - yml_reader (0.3) - -PLATFORMS - ruby - -DEPENDENCIES - mediawiki_api - mediawiki_selenium diff --git a/tests/browser/environment_variables b/tests/browser/environment_variables deleted file mode 100644 index 25c45775..00000000 --- a/tests/browser/environment_variables +++ /dev/null @@ -1,5 +0,0 @@ -export MEDIAWIKI_URL=http://localhost/wiki/ -export MEDIAWIKI_API_URL=http://localhost/w/api.php -export MEDIAWIKI_USER=Selenium_user -export MEDIAWIKI_PASSWORD=Selenium_password -export BROWSER=firefox diff --git a/tests/browser/environments.yml b/tests/browser/environments.yml new file mode 100644 index 00000000..8f8381ed --- /dev/null +++ b/tests/browser/environments.yml @@ -0,0 +1,35 @@ +# Customize this configuration as necessary to provide defaults for various +# test environments. +# +# The set of defaults to use is determined by the MEDIAWIKI_ENVIRONMENT +# environment variable. +# +# export MEDIAWIKI_ENVIRONMENT=mw-vagrant-host +# bundle exec cucumber +# +# Additional variables set by the environment will override the corresponding +# defaults defined here. +# +# export MEDIAWIKI_ENVIRONMENT=mw-vagrant-host +# export MEDIAWIKI_USER=Selenium_user2 +# bundle exec cucumber +# +mw-vagrant-host: + mediawiki_url: http://127.0.0.1:8080/wiki/ + mediawiki_user: Selenium_user + mediawiki_password: vagrant + +mw-vagrant-guest: + mediawiki_url: http://127.0.0.1/wiki/ + mediawiki_user: Selenium_user + mediawiki_password: vagrant + +beta: + mediawiki_url: http://en.wikipedia.beta.wmflabs.org/wiki/ + mediawiki_user: Selenium_user + # mediawiki_password: SET THIS IN THE ENVIRONMENT! + +test2: + mediawiki_url: http://test2.wikipedia.org/wiki/ + mediawiki_user: Selenium_user + # mediawiki_password: SET THIS IN THE ENVIRONMENT! diff --git a/tests/browser/features/file.feature b/tests/browser/features/file.feature index 0bd36ed6..35a6675d 100644 --- a/tests/browser/features/file.feature +++ b/tests/browser/features/file.feature @@ -1,14 +1,3 @@ -# -# This file is subject to the license terms in the LICENSE file found in the -# qa-browsertests top-level directory and at -# https://git.wikimedia.org/blob/qa%2Fbrowsertests/HEAD/LICENSE. No part of -# qa-browsertests, including this file, may be copied, modified, propagated, or -# distributed except according to the terms contained in the LICENSE file. -# -# Copyright 2012-2014 by the Mediawiki developers. See the CREDITS file in the -# qa-browsertests top-level directory and at -# https://git.wikimedia.org/blob/qa%2Fbrowsertests/HEAD/CREDITS -# @chrome @clean @firefox @internet_explorer_6 @internet_explorer_7 @internet_explorer_8 @internet_explorer_9 @internet_explorer_10 @phantomjs Feature: File diff --git a/tests/browser/features/login.feature b/tests/browser/features/login.feature index c34d23d3..2cb63564 100644 --- a/tests/browser/features/login.feature +++ b/tests/browser/features/login.feature @@ -1,14 +1,3 @@ -# -# This file is subject to the license terms in the LICENSE file found in the -# qa-browsertests top-level directory and at -# https://git.wikimedia.org/blob/qa%2Fbrowsertests/HEAD/LICENSE. No part of -# qa-browsertests, including this file, may be copied, modified, propagated, or -# distributed except according to the terms contained in the LICENSE file. -# -# Copyright 2012-2014 by the Mediawiki developers. See the CREDITS file in the -# qa-browsertests top-level directory and at -# https://git.wikimedia.org/blob/qa%2Fbrowsertests/HEAD/CREDITS -# @chrome @clean @firefox @internet_explorer_6 @internet_explorer_7 @internet_explorer_8 @internet_explorer_9 @internet_explorer_10 @phantomjs Feature: Log in diff --git a/tests/browser/features/preferences.feature b/tests/browser/features/preferences.feature index 9e3abfde..9fed9cf4 100644 --- a/tests/browser/features/preferences.feature +++ b/tests/browser/features/preferences.feature @@ -1,14 +1,3 @@ -# -# This file is subject to the license terms in the LICENSE file found in the -# qa-browsertests top-level directory and at -# https://git.wikimedia.org/blob/qa%2Fbrowsertests/HEAD/LICENSE. No part of -# qa-browsertests, including this file, may be copied, modified, propagated, or -# distributed except according to the terms contained in the LICENSE file. -# -# Copyright 2012-2014 by the Mediawiki developers. See the CREDITS file in the -# qa-browsertests top-level directory and at -# https://git.wikimedia.org/blob/qa%2Fbrowsertests/HEAD/CREDITS -# @chrome @clean @firefox @internet_explorer_6 @internet_explorer_7 @internet_explorer_8 @internet_explorer_9 @internet_explorer_10 @login @phantomjs Feature: Preferences diff --git a/tests/browser/features/step_definitions/create_account_steps.rb b/tests/browser/features/step_definitions/create_account_steps.rb index 7fa29843..03bff66f 100644 --- a/tests/browser/features/step_definitions/create_account_steps.rb +++ b/tests/browser/features/step_definitions/create_account_steps.rb @@ -10,9 +10,9 @@ # https://git.wikimedia.org/blob/qa%2Fbrowsertests/HEAD/CREDITS # Given(/^I go to Create account page at (.+)$/) do |path| - visit(CreateAccountPage, :using_params => {:page_title => path}) + visit(CreateAccountPage, using_params: { page_title: path }) end Then(/^form has Create account button$/) do - on(CreateAccountPage).create_account_element.should exist + expect(on(CreateAccountPage).create_account_element).to exist end diff --git a/tests/browser/features/step_definitions/create_and_follow_wiki_link_steps.rb b/tests/browser/features/step_definitions/create_and_follow_wiki_link_steps.rb index ba41f7fb..504d3454 100644 --- a/tests/browser/features/step_definitions/create_and_follow_wiki_link_steps.rb +++ b/tests/browser/features/step_definitions/create_and_follow_wiki_link_steps.rb @@ -1,28 +1,26 @@ Given(/^I go to the "(.+)" page with content "(.+)"$/) do |page_title, page_content| @wikitext = page_content - on(APIPage).create page_title, page_content + api.create_page page_title, page_content step "I am on the #{page_title} page" end Given(/^I am on the (.+) page$/) do |article| article = article.gsub(/ /, '_') - visit(ZtargetPage, :using_params => {:article_name => article}) + visit(ZtargetPage, using_params: { article_name: article }) end Given(/^I create page "(.*?)" with content "(.*?)"$/) do |page_title, page_content| - on(APIPage).create page_title, page_content + api.create_page page_title, page_content end - When(/^I click the Link Target link$/) do on(ZtargetPage).link_target_page_link end Then(/^I should be on the Link Target Test Page$/) do - @browser.url.should match /Link_Target_Test_Page/ + expect(@browser.url).to match /Link_Target_Test_Page/ end Then(/^the page content should contain "(.*?)"$/) do |content| - on(ZtargetPage).page_content.should match content + expect(on(ZtargetPage).page_content).to match content end - diff --git a/tests/browser/features/step_definitions/edit_page_steps.rb b/tests/browser/features/step_definitions/edit_page_steps.rb index 5ab02bec..0e0aeb17 100644 --- a/tests/browser/features/step_definitions/edit_page_steps.rb +++ b/tests/browser/features/step_definitions/edit_page_steps.rb @@ -19,6 +19,5 @@ When(/^I save the edit$/) do end Then(/^the edited page content should contain "(.*?)"$/) do |content| - on(MainPage).page_content.should match(content + @random_string) + expect(on(MainPage).page_content).to match(content + @random_string) end - diff --git a/tests/browser/features/step_definitions/file_steps.rb b/tests/browser/features/step_definitions/file_steps.rb index a2ed1bfc..a80ca504 100644 --- a/tests/browser/features/step_definitions/file_steps.rb +++ b/tests/browser/features/step_definitions/file_steps.rb @@ -10,9 +10,9 @@ # https://git.wikimedia.org/blob/qa%2Fbrowsertests/HEAD/CREDITS # Given(/^I am at file that does not exist$/) do - visit(FileDoesNotExistPage, using_params: {page_name: @random_string}) + visit(FileDoesNotExistPage, using_params: { page_name: @random_string }) end Then(/^page should show that no such file exists$/) do - on(FileDoesNotExistPage).file_does_not_exist_message_element.should be_visible + expect(on(FileDoesNotExistPage).file_does_not_exist_message_element).to be_visible end diff --git a/tests/browser/features/step_definitions/login_steps.rb b/tests/browser/features/step_definitions/login_steps.rb index b654b2d3..bff5bddd 100644 --- a/tests/browser/features/step_definitions/login_steps.rb +++ b/tests/browser/features/step_definitions/login_steps.rb @@ -14,52 +14,52 @@ Given(/^I am at Log in page$/) do end When(/^I log in with incorrect password$/) do - on(LoginPage).login_with(ENV["MEDIAWIKI_USER"], "incorrect password", false) + on(LoginPage).login_with(user, 'incorrect password', false) end When(/^I log in with incorrect username$/) do - on(LoginPage).login_with("incorrect username", ENV["MEDIAWIKI_PASSWORD"], false) + on(LoginPage).login_with('incorrect username', password, false) end When(/^I log in without entering credentials$/) do - on(LoginPage).login_with("", "", false) + on(LoginPage).login_with('', '', false) end When(/^I log in without entering password$/) do - on(LoginPage).login_with(ENV["MEDIAWIKI_USER"], "", false) + on(LoginPage).login_with(user, '', false) end Then(/^error box should be visible$/) do - on(LoginErrorPage).error_box_element.should be_visible + expect(on(LoginErrorPage).error_box_element).to be_visible end Then(/^error box should not be visible$/) do - on(LoginErrorPage).error_box_element.should_not be_visible + expect(on(LoginErrorPage).error_box_element).not_to be_visible end Then(/^feedback should be (.+)$/) do |feedback| on(LoginPage) do |page| page.feedback_element.when_present.click - page.feedback.should match Regexp.escape(feedback) + expect(page.feedback).to match Regexp.escape(feedback) end end Then(/^Log in element should be there$/) do - on(LoginPage).login_element.should exist + expect(on(LoginPage).login_element).to exist end Then(/^main page should open$/) do - @browser.url.should == on(MainPage).class.url + expect(@browser.url).to eq on(MainPage).class.url end Then(/^Password element should be there$/) do - on(LoginPage).password_element.should exist + expect(on(LoginPage).password_element).to exist end Then(/^there should be a link to (.+)$/) do |text| - on(LoginPage).username_displayed_element.when_present.text.should == text + expect(on(LoginPage).username_displayed_element.when_present.text).to eq text end Then(/^Username element should be there$/) do - on(LoginPage).username_element.should exist + expect(on(LoginPage).username_element).to exist end diff --git a/tests/browser/features/step_definitions/main_page_links_steps.rb b/tests/browser/features/step_definitions/main_page_links_steps.rb index c76fd2ba..7f588c05 100644 --- a/tests/browser/features/step_definitions/main_page_links_steps.rb +++ b/tests/browser/features/step_definitions/main_page_links_steps.rb @@ -3,45 +3,45 @@ Given(/^I open the main wiki URL$/) do end Then(/^I should see a link for View History$/) do - on(MainPage).view_history_link_element.should be_visible + expect(on(MainPage).view_history_link_element).to be_visible end Then(/^I should see a link for Edit$/) do - on(MainPage).edit_link_element.should be_visible + expect(on(MainPage).edit_link_element).to be_visible end Then(/^I should see a link for Recent changes$/) do - on(MainPage).recent_changes_link_element.should be_visible + expect(on(MainPage).recent_changes_link_element).to be_visible end Then(/^I should see a link for Random page$/) do - on(MainPage).random_page_link_element.should be_visible + expect(on(MainPage).random_page_link_element).to be_visible end Then(/^I should see a link for Help$/) do - on(MainPage).help_link_element.should be_visible + expect(on(MainPage).help_link_element).to be_visible end Then(/^I should see a link for What links here$/) do - on(MainPage).what_links_here_link_element.should be_visible + expect(on(MainPage).what_links_here_link_element).to be_visible end Then(/^I should see a link for Related changes$/) do - on(MainPage).related_changes_link_element.should be_visible + expect(on(MainPage).related_changes_link_element).to be_visible end Then(/^I should see a link for Special pages$/) do - on(MainPage).special_pages_link_element.should be_visible + expect(on(MainPage).special_pages_link_element).to be_visible end Then(/^I should see a link for Printable version$/) do - on(MainPage).printable_version_link_element.should be_visible + expect(on(MainPage).printable_version_link_element).to be_visible end Then(/^I should see a link for Permanent link$/) do - on(MainPage).permanent_link_link_element.should be_visible + expect(on(MainPage).permanent_link_link_element).to be_visible end Then(/^I should see a link for Page information$/) do - on(MainPage).page_information_link_element.should be_visible + expect(on(MainPage).page_information_link_element).to be_visible end diff --git a/tests/browser/features/step_definitions/preferences_appearance_steps.rb b/tests/browser/features/step_definitions/preferences_appearance_steps.rb index 0046af69..133eec3b 100644 --- a/tests/browser/features/step_definitions/preferences_appearance_steps.rb +++ b/tests/browser/features/step_definitions/preferences_appearance_steps.rb @@ -18,68 +18,66 @@ When(/^I navigate to Preferences$/) do end Then(/^I can click Save$/) do - on(PreferencesPage).save_button_element.should exist + expect(on(PreferencesPage).save_button_element).to exist end Then(/^I can restore default settings$/) do - on(PreferencesAppearancePage).restore_default_link_element.should exist + expect(on(PreferencesAppearancePage).restore_default_link_element).to exist end Then(/^I can see local time$/) do - on(PreferencesAppearancePage).local_time_span_element.should exist + expect(on(PreferencesAppearancePage).local_time_span_element).to exist end Then(/^I can see time offset section$/) do - on(PreferencesAppearancePage).time_offset_table_element.should be_visible + expect(on(PreferencesAppearancePage).time_offset_table_element).to be_visible end Then(/^I can select date format$/) do on(PreferencesAppearancePage) do |page| - page.no_preference_radio_element.should exist - page.mo_day_year_radio_element.should exist - page.day_mo_year_radio_element.should exist - page.year_mo_day_radio_element.should exist - page.iso_8601_radio_element.should exist + expect(page.no_preference_radio_element).to exist + expect(page.mo_day_year_radio_element).to exist + expect(page.day_mo_year_radio_element).to exist + expect(page.year_mo_day_radio_element).to exist + expect(page.iso_8601_radio_element).to exist end end Then(/^I can select image size$/) do - on(PreferencesAppearancePage).size_select_element.should exist + expect(on(PreferencesAppearancePage).size_select_element).to exist end Then(/^I can select my time zone$/) do on(PreferencesAppearancePage) do |page| - page.time_offset_select_element.should exist - page.other_offset_element.should exist + expect(page.time_offset_select_element).to exist + expect(page.other_offset_element).to exist end end Then(/^I can select skins$/) do on(PreferencesAppearancePage) do |page| - page.cologne_blue_element.should exist - page.modern_element.should exist - page.monobook_element.should exist - page.vector_element.should exist + expect(page.cologne_blue_element).to exist + expect(page.modern_element).to exist + expect(page.monobook_element).to exist + expect(page.vector_element).to exist end end Then(/^I can select Threshold for stub link$/) do - on(PreferencesAppearancePage).threshold_select_element.should exist + expect(on(PreferencesAppearancePage).threshold_select_element).to exist end Then(/^I can select thumbnail size$/) do - on(PreferencesAppearancePage).thumb_select_element.should exist + expect(on(PreferencesAppearancePage).thumb_select_element).to exist end Then(/^I can select underline preferences$/) do - on(PreferencesAppearancePage).underline_select_element.should exist + expect(on(PreferencesAppearancePage).underline_select_element).to exist end Then(/^I have advanced options checkboxes$/) do on(PreferencesAppearancePage) do |page| - page.hidden_categories_check_element.should exist - page.auto_number_check_element.should exist + expect(page.hidden_categories_check_element).to exist + expect(page.auto_number_check_element).to exist end end - - diff --git a/tests/browser/features/step_definitions/preferences_editing_steps.rb b/tests/browser/features/step_definitions/preferences_editing_steps.rb index ad29a745..0a98e889 100644 --- a/tests/browser/features/step_definitions/preferences_editing_steps.rb +++ b/tests/browser/features/step_definitions/preferences_editing_steps.rb @@ -14,41 +14,41 @@ When(/^I click Editing$/) do end Then(/^I can select edit area font style$/) do - on(PreferencesEditingPage).edit_area_font_style_select_element.when_present.should exist + expect(on(PreferencesEditingPage).edit_area_font_style_select_element.when_present).to exist end Then(/^I can select live preview$/) do - on(PreferencesEditingPage).live_preview_check_element.when_present.should exist + expect(on(PreferencesEditingPage).live_preview_check_element.when_present).to exist end Then(/^I can select section editing by double clicking$/) do - on(PreferencesEditingPage).edit_section_double_click_check_element.when_present.should exist + expect(on(PreferencesEditingPage).edit_section_double_click_check_element.when_present).to exist end Then(/^I can select section editing by right clicking$/) do - on(PreferencesEditingPage).edit_section_right_click_check_element.when_present.should exist + expect(on(PreferencesEditingPage).edit_section_right_click_check_element.when_present).to exist end Then(/^I can select section editing via edit links$/) do - on(PreferencesEditingPage).edit_section_edit_link_element.when_present.should exist + expect(on(PreferencesEditingPage).edit_section_edit_link_element.when_present).to exist end Then(/^I can select show edit toolbar$/) do - on(PreferencesEditingPage).show_edit_toolbar_check_element.when_present.should exist + expect(on(PreferencesEditingPage).show_edit_toolbar_check_element.when_present).to exist end Then(/^I can select show preview before edit box$/) do - on(PreferencesEditingPage).preview_on_top_check_element.when_present.should exist + expect(on(PreferencesEditingPage).preview_on_top_check_element.when_present).to exist end Then(/^I can select show preview on first edit$/) do - on(PreferencesEditingPage).preview_on_first_check_element.when_present.should exist + expect(on(PreferencesEditingPage).preview_on_first_check_element.when_present).to exist end Then(/^I can select to prompt me when entering a blank edit summary$/) do - on(PreferencesEditingPage).forced_edit_summary_check_element.when_present.should exist + expect(on(PreferencesEditingPage).forced_edit_summary_check_element.when_present).to exist end Then(/^I can select to warn me when I leave an edit page with unsaved changes$/) do - on(PreferencesEditingPage).unsaved_changes_check_element.when_present.should exist + expect(on(PreferencesEditingPage).unsaved_changes_check_element.when_present).to exist end diff --git a/tests/browser/features/step_definitions/preferences_user_profile_steps.rb b/tests/browser/features/step_definitions/preferences_user_profile_steps.rb index 529af66d..9c65db83 100644 --- a/tests/browser/features/step_definitions/preferences_user_profile_steps.rb +++ b/tests/browser/features/step_definitions/preferences_user_profile_steps.rb @@ -15,29 +15,28 @@ end Then(/^I can change my gender$/) do on(PreferencesUserProfilePage) do |page| - page.gender_undefined_radio_element.should exist - page.gender_male_radio_element.should exist - page.gender_female_radio_element.should exist + expect(page.gender_undefined_radio_element).to exist + expect(page.gender_male_radio_element).to exist + expect(page.gender_female_radio_element).to exist end end Then(/^I can change my language$/) do - on(PreferencesUserProfilePage).lang_select_element.should exist + expect(on(PreferencesUserProfilePage).lang_select_element).to exist end Then(/^I can change my signature$/) do - on(PreferencesUserProfilePage).signature_field_element.should exist + expect(on(PreferencesUserProfilePage).signature_field_element).to exist end Then(/^I can see my Basic informations$/) do - on(PreferencesUserProfilePage).basic_info_table_element.should exist + expect(on(PreferencesUserProfilePage).basic_info_table_element).to exist end Then(/^I can see my email$/) do - on(PreferencesUserProfilePage).email_table_element.should exist + expect(on(PreferencesUserProfilePage).email_table_element).to exist end Then(/^I can see my signature$/) do - on(PreferencesUserProfilePage).signature_table_element.should exist + expect(on(PreferencesUserProfilePage).signature_table_element).to exist end - diff --git a/tests/browser/features/step_definitions/view_history_steps.rb b/tests/browser/features/step_definitions/view_history_steps.rb index 1ecc0085..d9b93817 100644 --- a/tests/browser/features/step_definitions/view_history_steps.rb +++ b/tests/browser/features/step_definitions/view_history_steps.rb @@ -3,6 +3,5 @@ When(/^I click View History$/) do end Then(/^I should see a link to a previous version of the page$/) do - on(ViewHistoryPage).old_version_link_element.should be_visible + expect(on(ViewHistoryPage).old_version_link_element).to be_visible end - diff --git a/tests/browser/features/support/env.rb b/tests/browser/features/support/env.rb index 7c122366..5eff4ce5 100644 --- a/tests/browser/features/support/env.rb +++ b/tests/browser/features/support/env.rb @@ -1,2 +1,4 @@ -require "mediawiki_api" -require "mediawiki_selenium" +require 'mediawiki_selenium' + +require 'mediawiki_selenium/support' +require 'mediawiki_selenium/step_definitions' diff --git a/tests/browser/features/support/modules/url_module.rb b/tests/browser/features/support/modules/url_module.rb deleted file mode 100644 index 6c329e87..00000000 --- a/tests/browser/features/support/modules/url_module.rb +++ /dev/null @@ -1,10 +0,0 @@ -module URL - def self.url(name) - if ENV["MEDIAWIKI_URL"] - mediawiki_url = ENV["MEDIAWIKI_URL"] - else - mediawiki_url = "http://127.0.0.1:80/w/index.php" - end - "#{mediawiki_url}#{name}" - end -end diff --git a/tests/browser/features/support/pages/create_account_page.rb b/tests/browser/features/support/pages/create_account_page.rb index 380bccbc..98b893a6 100644 --- a/tests/browser/features/support/pages/create_account_page.rb +++ b/tests/browser/features/support/pages/create_account_page.rb @@ -12,8 +12,7 @@ class CreateAccountPage include PageObject - include URL - page_url URL.url("<%=params[:page_title]%>") + page_url '<%=params[:page_title]%>' - button(:create_account, id: "wpCreateaccount") + button(:create_account, id: 'wpCreateaccount') end diff --git a/tests/browser/features/support/pages/edit_page.rb b/tests/browser/features/support/pages/edit_page.rb index b619c342..b0f6bffe 100644 --- a/tests/browser/features/support/pages/edit_page.rb +++ b/tests/browser/features/support/pages/edit_page.rb @@ -1,8 +1,8 @@ class EditPage include PageObject - text_area(:edit_page_content, id: "wpTextbox1") - button(:preview_button, id: "wpPreview") - button(:show_changes_button, id: "wpDiff") - button(:save_button, id: "wpSave") -end
\ No newline at end of file + text_area(:edit_page_content, id: 'wpTextbox1') + button(:preview_button, id: 'wpPreview') + button(:show_changes_button, id: 'wpDiff') + button(:save_button, id: 'wpSave') +end diff --git a/tests/browser/features/support/pages/file_does_not_exist_page.rb b/tests/browser/features/support/pages/file_does_not_exist_page.rb index c8491f3b..90762d22 100644 --- a/tests/browser/features/support/pages/file_does_not_exist_page.rb +++ b/tests/browser/features/support/pages/file_does_not_exist_page.rb @@ -12,8 +12,7 @@ class FileDoesNotExistPage include PageObject - include URL - page_url URL.url("File:<%=params[:page_name]%>") + page_url 'File:<%=params[:page_name]%>' - div(:file_does_not_exist_message, id: "mw-imagepage-nofile") + div(:file_does_not_exist_message, id: 'mw-imagepage-nofile') end diff --git a/tests/browser/features/support/pages/login_error_page.rb b/tests/browser/features/support/pages/login_error_page.rb index 4fc9ca7f..9a1805f3 100644 --- a/tests/browser/features/support/pages/login_error_page.rb +++ b/tests/browser/features/support/pages/login_error_page.rb @@ -1,5 +1,5 @@ class LoginErrorPage include PageObject - div(:error_box, class: "errorbox") -end
\ No newline at end of file + div(:error_box, class: 'errorbox') +end diff --git a/tests/browser/features/support/pages/main_page.rb b/tests/browser/features/support/pages/main_page.rb index 7d96c2b2..6d76b01c 100644 --- a/tests/browser/features/support/pages/main_page.rb +++ b/tests/browser/features/support/pages/main_page.rb @@ -1,19 +1,18 @@ class MainPage include PageObject - include URL - page_url URL.url("") + page_url '' a(:edit_link, href: /action=edit/) - li(:help_link, id: "n-help") - div(:page_content, id: "content") - li(:page_information_link, id: "t-info") - li(:permanent_link_link, id: "t-permalink") + li(:help_link, id: 'n-help') + div(:page_content, id: 'content') + li(:page_information_link, id: 't-info') + li(:permanent_link_link, id: 't-permalink') a(:printable_version_link, href: /printable=yes/) - li(:random_page_link, id: "n-randompage") - li(:recent_changes_link, id: "n-recentchanges") - li(:related_changes_link, id: "t-recentchangeslinked") - li(:special_pages_link, id: "t-specialpages") + li(:random_page_link, id: 'n-randompage') + li(:recent_changes_link, id: 'n-recentchanges') + li(:related_changes_link, id: 't-recentchangeslinked') + li(:special_pages_link, id: 't-specialpages') a(:view_history_link, href: /action=history/) - li(:what_links_here_link, id: "t-whatlinkshere") -end
\ No newline at end of file + li(:what_links_here_link, id: 't-whatlinkshere') +end diff --git a/tests/browser/features/support/pages/preferences_appearance_page.rb b/tests/browser/features/support/pages/preferences_appearance_page.rb index c24e3862..83c3952f 100644 --- a/tests/browser/features/support/pages/preferences_appearance_page.rb +++ b/tests/browser/features/support/pages/preferences_appearance_page.rb @@ -12,30 +12,28 @@ class PreferencesAppearancePage include PageObject - include URL - page_url URL.url("Special:Preferences#mw-prefsection-rendering") + page_url 'Special:Preferences#mw-prefsection-rendering' - checkbox(:auto_number_check, id: "mw-input-wpnumberheadings") - radio_button(:cologne_blue, id: "mw-input-wpskin-cologneblue") - radio_button(:day_mo_year_radio, id: "mw-input-wpdate-dmy") - checkbox(:dont_show_aft_check, id: "mw-input-wparticlefeedback-disable") - checkbox(:exclude_from_experiments_check, id: "mw-input-wpvector-noexperiments") - checkbox(:hidden_categories_check, id: "mw-input-wpshowhiddencats") - radio_button(:iso_8601_radio, id: "mw-input-wpdate-ISO_8601") - span(:local_time_span, id: "wpLocalTime") - radio_button(:mo_day_year_radio, id: "mw-input-wpdate-mdy") - radio_button(:modern, id: "mw-input-wpskin-modern") - radio_button(:monobook, id: "mw-input-wpskin-monobook") - radio_button(:no_preference_radio, id: "mw-input-wpdate-default") - text_field(:other_offset, id: "mw-input-wptimecorrection-other") + checkbox(:auto_number_check, id: 'mw-input-wpnumberheadings') + radio_button(:cologne_blue, id: 'mw-input-wpskin-cologneblue') + radio_button(:day_mo_year_radio, id: 'mw-input-wpdate-dmy') + checkbox(:dont_show_aft_check, id: 'mw-input-wparticlefeedback-disable') + checkbox(:exclude_from_experiments_check, id: 'mw-input-wpvector-noexperiments') + checkbox(:hidden_categories_check, id: 'mw-input-wpshowhiddencats') + radio_button(:iso_8601_radio, id: 'mw-input-wpdate-ISO_8601') + span(:local_time_span, id: 'wpLocalTime') + radio_button(:mo_day_year_radio, id: 'mw-input-wpdate-mdy') + radio_button(:modern, id: 'mw-input-wpskin-modern') + radio_button(:monobook, id: 'mw-input-wpskin-monobook') + radio_button(:no_preference_radio, id: 'mw-input-wpdate-default') + text_field(:other_offset, id: 'mw-input-wptimecorrection-other') a(:restore_default_link, href: /reset/) - select_list(:size_select, id: "mw-input-wpimagesize") - select_list(:threshold_select, id: "mw-input-wpstubthreshold") - select_list(:time_offset_select, id: "mw-input-wptimecorrection") - table(:time_offset_table, id: "mw-htmlform-timeoffset") - select_list(:thumb_select, id: "mw-input-wpthumbsize") - select_list(:underline_select, id: "mw-input-wpunderline") - radio_button(:vector, id: "mw-input-wpskin-vector") - radio_button(:year_mo_day_radio, id: "mw-input-wpdate-ymd") + select_list(:size_select, id: 'mw-input-wpimagesize') + select_list(:threshold_select, id: 'mw-input-wpstubthreshold') + select_list(:time_offset_select, id: 'mw-input-wptimecorrection') + table(:time_offset_table, id: 'mw-htmlform-timeoffset') + select_list(:thumb_select, id: 'mw-input-wpthumbsize') + select_list(:underline_select, id: 'mw-input-wpunderline') + radio_button(:vector, id: 'mw-input-wpskin-vector') + radio_button(:year_mo_day_radio, id: 'mw-input-wpdate-ymd') end - diff --git a/tests/browser/features/support/pages/preferences_editing_page.rb b/tests/browser/features/support/pages/preferences_editing_page.rb index aed9c41d..25c384f7 100644 --- a/tests/browser/features/support/pages/preferences_editing_page.rb +++ b/tests/browser/features/support/pages/preferences_editing_page.rb @@ -12,17 +12,16 @@ class PreferencesEditingPage include PageObject - include URL - page_url URL.url("Special:Preferences#mw-prefsection-rendering") + page_url 'Special:Preferences#mw-prefsection-rendering' - select_list(:edit_area_font_style_select, id: "mw-input-wpeditfont") - checkbox(:edit_section_double_click_check, id: "mw-input-wpeditondblclick") - checkbox(:edit_section_edit_link, id: "mw-input-wpeditsectiononrightclick") - checkbox(:edit_section_right_click_check, id: "mw-input-wpeditsectiononrightclick") - checkbox(:forced_edit_summary_check, id: "mw-input-wpforceeditsummary") - checkbox(:live_preview_check, id: "mw-input-wpuselivepreview") - checkbox(:preview_on_first_check, id: "mw-input-wppreviewonfirst") - checkbox(:preview_on_top_check, id: "mw-input-wppreviewontop") - checkbox(:show_edit_toolbar_check, id: "mw-input-wpshowtoolbar") - checkbox(:unsaved_changes_check, id: "mw-input-wpuseeditwarning") + select_list(:edit_area_font_style_select, id: 'mw-input-wpeditfont') + checkbox(:edit_section_double_click_check, id: 'mw-input-wpeditondblclick') + checkbox(:edit_section_edit_link, id: 'mw-input-wpeditsectiononrightclick') + checkbox(:edit_section_right_click_check, id: 'mw-input-wpeditsectiononrightclick') + checkbox(:forced_edit_summary_check, id: 'mw-input-wpforceeditsummary') + checkbox(:live_preview_check, id: 'mw-input-wpuselivepreview') + checkbox(:preview_on_first_check, id: 'mw-input-wppreviewonfirst') + checkbox(:preview_on_top_check, id: 'mw-input-wppreviewontop') + checkbox(:show_edit_toolbar_check, id: 'mw-input-wpshowtoolbar') + checkbox(:unsaved_changes_check, id: 'mw-input-wpuseeditwarning') end diff --git a/tests/browser/features/support/pages/preferences_page.rb b/tests/browser/features/support/pages/preferences_page.rb index 919ba27f..b305ee2c 100644 --- a/tests/browser/features/support/pages/preferences_page.rb +++ b/tests/browser/features/support/pages/preferences_page.rb @@ -12,11 +12,10 @@ class PreferencesPage include PageObject - include URL - page_url URL.url("Special:Preferences") + page_url 'Special:Preferences' - a(:appearance_link, id: "preftab-rendering") - a(:editing_link, id: "preftab-editing") - a(:user_profile_link, id: "preftab-personal") - button(:save_button, id: "prefcontrol") + a(:appearance_link, id: 'preftab-rendering') + a(:editing_link, id: 'preftab-editing') + a(:user_profile_link, id: 'preftab-personal') + button(:save_button, id: 'prefcontrol') end diff --git a/tests/browser/features/support/pages/preferences_user_profile_page.rb b/tests/browser/features/support/pages/preferences_user_profile_page.rb index 28e10b97..9e95eb5a 100644 --- a/tests/browser/features/support/pages/preferences_user_profile_page.rb +++ b/tests/browser/features/support/pages/preferences_user_profile_page.rb @@ -12,17 +12,16 @@ class PreferencesUserProfilePage include PageObject - include URL - page_url URL.url("Special:Preferences#mw-prefsection-personal") + page_url 'Special:Preferences#mw-prefsection-personal' - table(:basic_info_table, id: "mw-htmlform-info") - link(:change_password_link, text: "Change password") - table(:email_table, id: "mw-htmlform-email") - radio_button(:gender_female_radio, id: "mw-input-wpgender-male") - radio_button(:gender_male_radio, id: "mw-input-wpgender-female") - radio_button(:gender_undefined_radio, id: "mw-input-wpgender-unknown") - select_list(:lang_select, id: "mw-input-wplanguage") - checkbox(:remember_password_check, id: "mw-input-wprememberpassword") - text_field(:signature_field, id: "mw-input-wpnickname") - table(:signature_table, id: "mw-htmlform-signature") + table(:basic_info_table, id: 'mw-htmlform-info') + link(:change_password_link, text: 'Change password') + table(:email_table, id: 'mw-htmlform-email') + radio_button(:gender_female_radio, id: 'mw-input-wpgender-male') + radio_button(:gender_male_radio, id: 'mw-input-wpgender-female') + radio_button(:gender_undefined_radio, id: 'mw-input-wpgender-unknown') + select_list(:lang_select, id: 'mw-input-wplanguage') + checkbox(:remember_password_check, id: 'mw-input-wprememberpassword') + text_field(:signature_field, id: 'mw-input-wpnickname') + table(:signature_table, id: 'mw-htmlform-signature') end diff --git a/tests/browser/features/support/pages/view_history_page.rb b/tests/browser/features/support/pages/view_history_page.rb index 66895986..bb9c5862 100644 --- a/tests/browser/features/support/pages/view_history_page.rb +++ b/tests/browser/features/support/pages/view_history_page.rb @@ -3,5 +3,4 @@ class ViewHistoryPage a(:view_history_link, href: /action=history/) a(:old_version_link, href: /oldid=/) - -end
\ No newline at end of file +end diff --git a/tests/browser/features/support/pages/ztargetpage.rb b/tests/browser/features/support/pages/ztargetpage.rb index c1f46eca..da789e5e 100644 --- a/tests/browser/features/support/pages/ztargetpage.rb +++ b/tests/browser/features/support/pages/ztargetpage.rb @@ -1,7 +1,7 @@ class ZtargetPage < MainPage - include URL - page_url URL.url("<%=params[:article_name]%>") include PageObject - a(:link_target_page_link, text: "link to the test target page") -end
\ No newline at end of file + page_url '<%=params[:article_name]%>' + + a(:link_target_page_link, text: 'link to the test target page') +end diff --git a/tests/parser/ParserTestResult.php b/tests/parser/ParserTestResult.php index 7d9415a2..a7b36721 100644 --- a/tests/parser/ParserTestResult.php +++ b/tests/parser/ParserTestResult.php @@ -1,10 +1,9 @@ <?php /** + * @file + * * @copyright Copyright © 2013, Antoine Musso * @copyright Copyright © 2013, Wikimedia Foundation Inc. - * @license GNU GPL v2 - * - * @file */ /** diff --git a/tests/parser/parserTest.inc b/tests/parser/parserTest.inc index a9df6832..1cffa20c 100644 --- a/tests/parser/parserTest.inc +++ b/tests/parser/parserTest.inc @@ -559,7 +559,7 @@ class ParserTest { $parser->setTransparentTagHook( $tag, $callback ); } - wfRunHooks( 'ParserTestParser', array( &$parser ) ); + Hooks::run( 'ParserTestParser', array( &$parser ) ); return $parser; } @@ -593,6 +593,14 @@ class ParserTest { } } + if ( isset( $opts['tidy'] ) ) { + if ( !$this->tidySupport->isEnabled() ) { + return $this->showSkipped(); + } else { + $options->setTidy( true ); + } + } + if ( isset( $opts['title'] ) ) { $titleText = $opts['title']; } else { @@ -624,10 +632,6 @@ class ParserTest { $output->setTOCEnabled( !isset( $opts['notoc'] ) ); $out = $output->getText(); if ( isset( $opts['tidy'] ) ) { - if ( !$this->tidySupport->isEnabled() ) { - return $this->showSkipped(); - } - $out = MWTidy::tidy( $out ); $out = preg_replace( '/\s+$/', '', $out ); } @@ -639,6 +643,14 @@ class ParserTest { $out = "$title\n$out"; } + if ( isset( $opts['showindicators'] ) ) { + $indicators = ''; + foreach ( $output->getIndicators() as $id => $content ) { + $indicators .= "$id=$content\n"; + } + $out = $indicators . $out; + } + if ( isset( $opts['ill'] ) ) { $out = implode( ' ', $output->getLanguageLinks() ); } elseif ( isset( $opts['cat'] ) ) { @@ -877,10 +889,7 @@ class ParserTest { 'wgDisableLangConversion' => false, 'wgDisableTitleConversion' => false, // Tidy options. - // We always set 'wgUseTidy' to false when parsing, but certain - // test-running modes still use tidy if available, so ensure - // that the tidy-related options are all set to their defaults. - 'wgUseTidy' => false, + 'wgUseTidy' => isset( $opts['tidy'] ), 'wgAlwaysUseTidy' => false, 'wgDebugTidy' => false, 'wgTidyConf' => $IP . '/includes/tidy.conf', @@ -901,7 +910,7 @@ class ParserTest { $this->savedGlobals = array(); /** @since 1.20 */ - wfRunHooks( 'ParserTestGlobals', array( &$settings ) ); + Hooks::run( 'ParserTestGlobals', array( &$settings ) ); foreach ( $settings as $var => $val ) { if ( array_key_exists( $var, $GLOBALS ) ) { @@ -941,7 +950,7 @@ class ParserTest { $tables = array( 'user', 'user_properties', 'user_former_groups', 'page', 'page_restrictions', 'protected_titles', 'revision', 'text', 'pagelinks', 'imagelinks', 'categorylinks', 'templatelinks', 'externallinks', 'langlinks', 'iwlinks', - 'site_stats', 'hitcounter', 'ipblocks', 'image', 'oldimage', + 'site_stats', 'ipblocks', 'image', 'oldimage', 'recentchanges', 'watchlist', 'interwiki', 'logging', 'querycache', 'objectcache', 'job', 'l10n_cache', 'redirect', 'querycachetwo', 'archive', 'user_groups', 'page_props', 'category', 'msg_resource', 'msg_resource_links' @@ -954,7 +963,7 @@ class ParserTest { // Allow extensions to add to the list of tables to duplicate; // may be necessary if they hook into page save or other code // which will require them while running tests. - wfRunHooks( 'ParserTestTables', array( &$tables ) ); + Hooks::run( 'ParserTestTables', array( &$tables ) ); return $tables; } @@ -1493,8 +1502,10 @@ class ParserTest { * Insert a temporary test article * @param string $name The title, including any prefix * @param string $text The article text - * @param int $line The input line number, for reporting errors - * @param bool $ignoreDuplicate Whether to silently ignore duplicate pages + * @param int|string $line The input line number, for reporting errors + * @param bool|string $ignoreDuplicate Whether to silently ignore duplicate pages + * @throws Exception + * @throws MWException */ public static function addArticle( $name, $text, $line = 'unknown', $ignoreDuplicate = '' ) { global $wgCapitalLinks; diff --git a/tests/parser/parserTests.txt b/tests/parser/parserTests.txt index f915922f..e9653529 100644 --- a/tests/parser/parserTests.txt +++ b/tests/parser/parserTests.txt @@ -16,7 +16,7 @@ # cat add category links # ill add inter-language links # subpage enable subpages (disabled by default) -# noxml don't check for XML well formdness +# noxml don't check for XML well-formedness # title=[[XXX]] run test using article title XXX # language=XXX set content language to XXX for this test # variant=XXX set the variant of language for this test (eg zh-tw) @@ -26,6 +26,7 @@ # php php-only test (not run by the parsoid parser unless # the test includes an html/parsoid section) # showtitle make the first line the title +# showindicators make the first lines the page status indicators # comment run through Linker::formatComment() instead of main parser # local format section links in edit comment text as local links # notoc disable table of contents @@ -69,6 +70,12 @@ Template:pipe | !! endarticle +!! article +Template:= +!! text +<nowiki>=</nowiki> +!! endarticle + !!article MediaWiki:bad image list !!text @@ -112,22 +119,50 @@ Template:echo_with_div !! endarticle !! article -Template:attr_str +Template:table_attribs !! text -{{{1}}}="{{{2}}}" +<noinclude> +|</noinclude>style="color:red;"|Foo !! endarticle !! article -Template:table_attribs +Template:table_attribs_2 +!! text +<noinclude> +|</noinclude>style="color:red;"|Foo +|Bar||Baz +!! endarticle + +!! article +Template:table_attribs_3 +!! text +<noinclude> +|</noinclude>style{{=}}"background:#f9f9f9;"|Foo +!! endarticle + +!! article +Template:table_attribs_4 +!! text +| style="background-color:#DC241f;" width="10px" | +!! endarticle + +!! article +Template:table_attribs_5 !! text <noinclude> -|</noinclude>style="color: red"| Foo +|</noinclude>style="color:red;"||Bar +!! endarticle + +!! article +Template:table_header_cells +!! text +{{table_attribs}}!!style='color:red;'|''Bar''||style='color:brown;'|''Foo'' and Baz !! endarticle !! article Template:table_cells !! text -{{table_attribs}} || Bar || Baz +{{table_attribs}}||style='color:red;'|''Bar''||style='color:brown;'|''Foo'' and Baz !! endarticle !! article @@ -137,6 +172,22 @@ Template:image_attribs [[File:foobar.jpg|</noinclude>right|Caption text<noinclude>]]</noinclude> !! endarticle +## See T48811 for details +!! article +Template:mixed_attr_content_template +!! text +style="color:red;" title="T48811" +|- +|foo +!! endarticle + +!! article +Template:definition_list +!! text +one +::two +!! endarticle + !! article A?b !! text @@ -155,6 +206,39 @@ Template:OpenTable {| !!endarticle +!!article +Template:EmptyLITest +!!text +*a +* +* +*b +!!endarticle + +!!article +Template:EmptyTRTest +!!text +{| +|- +|- +|foo +|- +|- +|bar +|} +!!endarticle + +!!article +Template:EmptyTRWithHTMLAttrTest +!!text +<table> +<tr align="center"></tr> +<tr><td>foo</td></tr> +<tr align="center"></tr> +<tr><td>bar</td></tr> +</table> +!!endarticle + ### ### Basic tests ### @@ -505,11 +589,8 @@ Italics and bold: 2-quote opening sequence: (2,2) </p> !!end - !! test Italics and bold: 2-quote opening sequence: (2,3) -!! options -parsoid=wt2html !! wikitext ''foo''' !! html/* @@ -517,18 +598,6 @@ parsoid=wt2html </p> !!end - -# same html as previous, but wikitext adjusted to match parsoid html2wt -!! test -Italics and bold: 2-quote opening sequence: (2,3) w/ nowiki -!! wikitext -''<nowiki>foo'</nowiki>'' -!! html -<p><i>foo'</i> -</p> -!! end - - !! test Italics and bold: 2-quote opening sequence: (2,4) !! options @@ -540,18 +609,16 @@ parsoid=wt2html </p> !!end - # same html as previous, but wikitext adjusted to match parsoid html2wt !! test Italics and bold: 2-quote opening sequence: (2,4) w/ nowiki !! wikitext -''<nowiki>foo''</nowiki>'' +''foo<nowiki>''</nowiki>'' !! html <p><i>foo''</i> </p> !! end - # The PHP parser strips the empty tags out for giggles; parsoid doesn't. !! test Italics and bold: 2-quote opening sequence: (2,5) @@ -589,12 +656,11 @@ Italics and bold: 2-quote opening sequence: (2,5+3) w/ nowiki Italics and bold: 3-quote opening sequence: (3,2) !! wikitext '''foo'' -!! html +!! html/* <p>'<i>foo</i> </p> !!end - !! test Italics and bold: 3-quote opening sequence: (3,3) !! wikitext @@ -604,11 +670,8 @@ Italics and bold: 3-quote opening sequence: (3,3) </p> !!end - !! test Italics and bold: 3-quote opening sequence: (3,4) -!! options -parsoid=wt2html !! wikitext '''foo'''' !! html/* @@ -616,18 +679,6 @@ parsoid=wt2html </p> !!end - -# same html as previous, but wikitext adjusted to match parsoid html2wt -!! test -Italics and bold: 3-quote opening sequence: (3,4) w/ nowiki -!! wikitext -'''<nowiki>foo'</nowiki>''' -!! html -<p><b>foo'</b> -</p> -!! end - - # The PHP parser strips the empty tags out for giggles; parsoid doesn't. !! test Italics and bold: 3-quote opening sequence: (3,5) @@ -672,7 +723,6 @@ parsoid=wt2html </p> !!end - # same html as previous, but wikitext adjusted to match parsoid html2wt !! test Italics and bold: 4-quote opening sequence: (4,2) w/ nowiki @@ -683,17 +733,15 @@ Italics and bold: 4-quote opening sequence: (4,2) w/ nowiki </p> !! end - !! test Italics and bold: 4-quote opening sequence: (4,3) !! wikitext ''''foo''' -!! html +!! html/* <p>'<b>foo</b> </p> !!end - !! test Italics and bold: 4-quote opening sequence: (4,4) !! options @@ -705,18 +753,16 @@ parsoid=wt2html </p> !!end - # same html as previous, but wikitext adjusted to match parsoid html2wt !! test Italics and bold: 4-quote opening sequence: (4,4) w/ nowiki !! wikitext -''''<nowiki>foo'</nowiki>''' +'<nowiki/>'''foo'''' !! html <p>'<b>foo'</b> </p> !! end - # The PHP parser strips the empty tags out for giggles; parsoid doesn't. !! test Italics and bold: 4-quote opening sequence: (4,5) @@ -736,7 +782,7 @@ parsoid=wt2html !! test Italics and bold: 4-quote opening sequence: (4,5+2) w/ nowiki !! wikitext -''''foo'''''<nowiki/>'' +'<nowiki/>'''foo'''''<nowiki/>'' !! html/php <p>'<b>foo</b> </p> @@ -761,7 +807,6 @@ parsoid=wt2html </p> !!end - # same html as previous, but wikitext adjusted to match parsoid html2wt # skipping wt2html and html2html because it wants to put <i> before <b> !! test @@ -786,7 +831,6 @@ parsoid=wt2html </p> !!end - # same html as previous, but wikitext adjusted to match parsoid html2wt !! test Italics and bold: 5-quote opening sequence: (5,3+2) @@ -797,7 +841,6 @@ Italics and bold: 5-quote opening sequence: (5,3+2) </p> !! end - !! test Italics and bold: 5-quote opening sequence: (5,4) !! options @@ -809,18 +852,6 @@ parsoid=wt2html </p> !!end - -# same html as previous, but wikitext adjusted to match parsoid html2wt -!! test -Italics and bold: 5-quote opening sequence: (5,4+2) w/ nowiki -!! wikitext -'''''<nowiki>foo'</nowiki>''''' -!! html -<p><i><b>foo'</b></i> -</p> -!! end - - !! test Italics and bold: 5-quote opening sequence: (5,5) !! wikitext @@ -830,6 +861,15 @@ Italics and bold: 5-quote opening sequence: (5,5) </p> !!end +!! test +Italics and bold: 5-quote opening sequence: (5,6) +!! wikitext +'''''foo'''''' +!! html/* +<p><i><b>foo'</b></i> +</p> +!! end + ### ### multiple quote sequences in a line ### @@ -849,7 +889,7 @@ parsoid=wt2html !! test Italics and bold: multiple quote sequences: (2,4,2+3) w/ nowiki !! wikitext -''<nowiki>foo'</nowiki>'''bar''''' +''foo'<nowiki/>'''bar''''' !! html <p><i>foo'<b>bar</b></i> </p> @@ -872,7 +912,7 @@ parsoid=wt2html !! test Italics and bold: multiple quote sequences: (2,4,3+2) w/ nowiki !! wikitext -''<nowiki>foo'</nowiki>'''bar''''' +''foo'<nowiki/>'''bar''''' !! html <p><i>foo'<b>bar</b></i> </p> @@ -895,7 +935,7 @@ parsoid=wt2html !! test Italics and bold: multiple quote sequences: (2,4,4+2) w/ nowiki !! wikitext -''<nowiki>foo'</nowiki>'''<nowiki>bar'</nowiki>''''' +''foo'<nowiki/>'''bar'<nowiki/>''''' !! html <p><i>foo'<b>bar'</b></i> </p> @@ -997,14 +1037,11 @@ parsoid=wt2html # same html as previous, but wikitext adjusted to match parsoid html2wt -# add 'parsoid' option to use 'parsoid' normalization of the placeholder !! test Italics and bold: other quote tests: (3,2,3+2+2,2) -!! options -parsoid !! wikitext '''this is about ''foo'''''<nowiki/>''s family'' -!! html/* +!! html <p><b>this is about <i>foo</i></b><i>s family</i> </p> !! end @@ -1012,10 +1049,9 @@ parsoid !! test Italics and bold: other quote tests: (3,2,3,3) -!! options !! wikitext '''this is about ''foo'''s family''' -!! html +!! html/* <p>'<i>this is about </i>foo<b>s family</b> </p> !!end @@ -1035,9 +1071,11 @@ Italics and bold: other quote tests: (3,(2,2),3) Italicized possessive !! wikitext The ''[[Main Page]]'''s talk page. -!! html +!! html/php <p>The <i><a href="/wiki/Main_Page" title="Main Page">Main Page</a>'</i>s talk page. </p> +!! html/parsoid +<p>The <i><a rel="mw:WikiLink" href="Main_Page" title="Main Page">Main Page</a>'</i>s talk page.</p> !! end !! test @@ -1201,38 +1239,84 @@ Ruby markup (W3C-style) </p> !! end -# There is a tidy bug here: http://sourceforge.net/p/tidy/bugs/946/ +# The next two test different paths in the sanitizer. !! test Non-word characters don't terminate tag names (bug 17663, 40670, 52022) !! wikitext -<b→> doesn't work! </b→> +<blockquote|>a</blockquote> + +<b→> doesn't terminate </b→> -<bä> doesn't work! </bä> +<bä> doesn't terminate </bä> -<boo> works fine </boo> +<boo> doesn't terminate </boo> -<s.foo>s.foo</s.foo> +<s.foo> doesn't terminate </s.foo> <sub-ID#1> !! html -<p><b→> doesn't work! </b→> -</p><p><bä> doesn't work! </bä> -</p><p><boo> works fine </boo> -</p><p><s.foo>s.foo</s.foo> +<p><blockquote|>a</blockquote> +</p><p><b→> doesn't terminate </b→> +</p><p><bä> doesn't terminate </bä> +</p><p><boo> doesn't terminate </boo> +</p><p><s.foo> doesn't terminate </s.foo> </p><p><sub-ID#1> </p> !! end +# There is a tidy bug here: http://sourceforge.net/p/tidy/bugs/946/ +# If the non-word-character tag made it through the sanitizer, tidy +# would munge it up. +!! test +Non-word characters don't terminate tag names + tidy +!! wikitext +<blockquote|>a</blockquote> + +<b→> doesn't terminate </b→> + +<bä> doesn't terminate </bä> + +<boo> doesn't terminate </boo> + +<s.foo> doesn't terminate </s.foo> + +<sub-ID#1> +!! html+tidy +<p><blockquote|>a</p> +<p><b→> doesn't terminate </b→></p> +<p><bä> doesn't terminate </bä></p> +<p><boo> doesn't terminate </boo></p> +<p><s.foo> doesn't terminate </s.foo></p> +<p><sub-ID#1></p> +!! end + +### +### See tests/parser/parserTestsParserHook.php for the <tåg> extension) +### This checks that HTML5 tags (with non-word characters in the tag +### name) make it safely through the parser -- the Sanitizer will +### munge them later, as it should. +### +!! test +Non-word characters are valid in extension tags (T19663) +!! wikitext +<tåg>tåg</tåg> +!! html +<pre> +'tåg' +array ( +) +</pre> + +!! end + !! test Isolated close tags should be treated as literal text (bug 52760) !! wikitext </b> <s.foo>s</s> -!! html -<p></b> -</p><p><s.foo>s</s> -</p> +!! html+tidy +<p><s.foo>s</p> !! end ### @@ -1328,18 +1412,75 @@ parsoid !! wikitext {{echo|–}} !! html -<p><span typeof="mw:Transclusion mw:Entity" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"&ndash;"}},"i":0}}]}'>–</span> -</p> +<p><span typeof="mw:Transclusion mw:Entity" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"&ndash;"}},"i":0}}]}'>–</span></p> !! end !! test Properly escape nowiki when combined with other wiki markup !! options parsoid=html2wt +!! html +<p>* </nowiki> tag</p> !! wikitext <nowiki>* </nowiki></nowiki> tag +!! end + +!! test +T71950: 1. Put nowiki as close to cause as possible, even with non-quote escapable chars +!! options +parsoid=html2wt !! html -<p>* </nowiki> tag</p> +<p>This text: L'<a rel="mw:WikiLink" href="./Foo">Foo</a> +This text: L''<a rel="mw:WikiLink" href="./Foo">Foo</a> +This text: L'''<a rel="mw:WikiLink" href="./Foo">Foo</a>''</p> +!! wikitext +This text: L'[[Foo]] +This text: L<nowiki>''</nowiki>[[Foo]] +This text: L<nowiki>'''</nowiki>[[Foo]]<nowiki>''</nowiki> +!! end + +# This test fails because wikitext whitespace is not normalized before comparing. +!! test +T71950: 2. Put nowiki as close to cause as possible, after ' :' +!! options +parsoid=html2wt +!! html +<p>This text : L''<a rel="mw:WikiLink" href="./Foo">Foo</a> +</p> +!! wikitext +This text : L<nowiki>''</nowiki>[[Foo]] +!! end + +# This test and the next one are html2wt only as they test that incorrect wikitext +# passed in template arguments gets escaped or wrapped in nowikis where required. +!! test +T71482: Use {{!}} instead of nowiki for single pipe in template argument +!! options +parsoid=html2wt +!! html/parsoid +<p><span typeof="mw:Transclusion" data-mw="{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo|bar"}},"i":0}}]}" about="#mwt1"></span> +<span typeof="mw:Transclusion" data-mw="{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo|bar |[["}},"i":0}}]}" about="#mwt2"></p> +!! wikitext +{{echo|foo{{!}}bar}} +{{echo|<nowiki>foo|bar |[[</nowiki>}} +!! end + +!! test +T53961: Output correct nowikis in template arguments +!! options +parsoid=html2wt +!! html/parsoid +<p><span typeof="mw:Transclusion" data-mw="{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"a [ b"}},"i":0}}]}" about="#mwt1"></span> +<span typeof="mw:Transclusion" data-mw="{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"a }} b"}},"i":0}}]}" about="#mwt2"></span> +<span typeof="mw:Transclusion" data-mw="{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"a [[ b"}},"i":0}}]}" about="#mwt3"></span> +<span typeof="mw:Transclusion" data-mw="{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"a | {{ ]]"}},"i":0}}]}" about="#mwt4"></span> +<span typeof="mw:Transclusion" data-mw="{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"a }"}},"i":0}}]}" about="#mwt5"></span></p> +!! wikitext +{{echo|a [ b}} +{{echo|a <nowiki>}}</nowiki> b}} +{{echo|<nowiki>a [[ b</nowiki>}} +{{echo|a {{!}} <nowiki>{{ ]]</nowiki>}} +{{echo|a <nowiki>}</nowiki>}} !! end ### @@ -1488,6 +1629,19 @@ Comment semantics: unclosed comment at end !! end +# Bug 58184: document parsoid's behaviour +!! test +Suppress comment closing tag in lenient browsers +!! options +parsoid=wt2html,html2html +!! wikitext +<!-- Browsers--!> think this is closed --> +!! html/php + +!! html/parsoid +<!-- Browsers--¡> think this is closed --> +!! end + !! test Comment in template title !! wikitext @@ -1649,6 +1803,11 @@ x <div>foo</div> z <p>z</p> !! end +# Tidy strips out the empty <div> tags. Parsoid doesn't. +# So, we have a separate section for Parsoid. We don't want +# to mimic this stripping behavior in Parsoid. It affects +# editing experience and also requires us to maintain additional +# info for RT-ing. !! test Empty lines between lines with block tags !! wikitext @@ -1687,10 +1846,22 @@ b <p>d</p> <p><br /></p> <div>e</div> +!! html/parsoid +<div data-parsoid='{"stx":"html"}'></div> + +<p><br /></p> +<div data-parsoid='{"stx":"html"}'></div><p>a</p> + +<p>b</p> +<div data-parsoid='{"stx":"html"}'>a</div><p>b</p> + +<div data-parsoid='{"stx":"html"}'>b</div><p>d</p> + +<p><br /></p> +<div data-parsoid='{"stx":"html"}'>e</div> !! end ## PHP parser emits output which is broken -## XXX The parsoid output doesn't match the tidy output. !! test Unclosed HTML p-tags should be handled properly !! wikitext @@ -1700,15 +1871,42 @@ a b !! html/php+tidy <div> -<p>foo</div></p> +<p>foo</p> +</div> <p>a</p> -b</div> +<p>b</p> !! html/parsoid <div data-parsoid='{"stx":"html"}'><p data-parsoid='{"stx":"html", "autoInsertedEnd":true}'>foo</p></div> <p>a</p> <p>b</p> !! end +## SSS FIXME: I can come up with other scenarios where this doesn't work because +## of eager output of buffered tokens in the p-wrapper. But, I'm going to ignore +## them for now. +!! test +1. P-wrapping should leave sol-transparent tags outside p-tags where possible +!! options +parsoid=wt2html +!! wikitext +a [[Category:A1]] [[Category:A2]] +[[Category:A3]] +[[Category:A4]] +!! html/parsoid +<p>a</p> +<link href="Category:A1"/> <link href="Category:A2"/> <link href="Category:A3"/> <link href="Category:A4"/> +!! end + +!! test +2. P-wrapping should leave sol-transparent tags outside p-tags where possible +!! options +parsoid=wt2html +!! wikitext +[[Category:A1]]a +!! html/parsoid +<link href="Category:A1"/><p>a</p> +!! end + ### ### Preformatted text ### @@ -1966,8 +2164,11 @@ Entities inside <pre> </p> !! end +# Parsoid doesn't strip empty tags, like Tidy does. !! test Empty pre; pre inside other HTML tags (bug 54946) +!! options +parsoid=wt2html,wt2wt !! wikitext a @@ -1975,7 +2176,7 @@ a foo </pre></div> <pre></pre> -!! html +!! html/php <p>a </p> <div><pre> @@ -1983,12 +2184,18 @@ foo </pre></div> <pre></pre> -!! html+tidy +!! html/php+tidy <p>a</p> <div> <pre> foo </pre></div> +!! html/parsoid +<p>a</p> + +<div><pre>foo +</pre></div> +<pre></pre> !! end !! test @@ -2156,10 +2363,11 @@ parsoid=wt2html <table><pre></pre></table> !! html/parsoid -<span typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"<pre <pre>x</pre>"}},"i":0}}]}'><pre </span> -<pre>x</pre> +<pre about="#mwt1" typeof="mw:Transclusion" data-parsoid='{"a":{"<pre":null},"sa":{"<pre":""},"stx":"html","pi":[[{"k":"1","spc":["","","",""]}]]}' data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"<pre <pre>x</pre>"}},"i":0}}]}'>x</pre> + + +<p><pre </p> -<span><pre </span> <table></table> !! end @@ -2335,6 +2543,41 @@ Templates: Handle comments in the target <p typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo"}},"i":0}}]}'>foo</p> !!end +!! test +Templates: Handle comments in parameter names (bug 67657) +!! wikitext +{{echo|1 +<!-- should be ignored --> +=foo}} + +{{echo| +<!-- should be ignored --> +1 = foo}} + +{{echo|1<!-- should be ignored --> = foo}} + +{{echo|<!-- should be ignored -->1 = foo}} +!!html/parsoid +<p typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo","key":{"wt":"1\n<!-- should be ignored -->"}}},"i":0}}]}'>foo</p> + +<p typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo","key":{"wt":"<!-- should be ignored -->\n1"}}},"i":0}}]}'>foo</p> + +<p typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo","key":{"wt":"1<!-- should be ignored -->"}}},"i":0}}]}'>foo</p> + +<p typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo","key":{"wt":"<!-- should be ignored -->1"}}},"i":0}}]}'>foo</p> +!!end + +!! test +Templates: Other wikitext in parameter names (bug 67657) +!! wikitext +{{echo|''1''=foo}} +!!html/parsoid +<p typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"''1''":{"wt":"foo"}},"i":0}}]}'>{{{1}}}</p> +!!html/php +<p>{{{1}}} +</p> +!!end + #-------------------------------------------------------------------- # Transclusion parameter escaping tests #-------------------------------------------------------------------- @@ -2431,6 +2674,18 @@ parsoid <p about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"a : b"}},"i":0}}]}'>a<span typeof="mw:Placeholder" data-parsoid='{"isDisplayHack":true}'> </span>: b</p> !! end +## Bug T73412 +!! test +Templates: Preserve blank parameter names +!! wikitext +{{echo|=foo}} +!! html/php +<p>{{{1}}} +</p> +!! html/parsoid +<p about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"":{"wt":"foo"}},"i":0}}]}'>{{{1}}}</p> +!! end + ### ### Parsoid-centric tests for testing RT edge cases for pre ### @@ -2559,12 +2814,8 @@ c !! html/parsoid <pre>a</pre> - -<table> - -<tbody> -<tr> -<td> b</td></tr> + <table> + <tbody><tr><td> b</td></tr> </tbody></table> !!end @@ -2613,6 +2864,12 @@ a c <blockquote> foo </blockquote> <pre><span> foo </span> </pre> +!! html/parsoid + <p>a </p><p data-parsoid='{"stx":"html"}'> foo </p> + <p>b </p><div data-parsoid='{"stx":"html"}'> foo </div> + <p>c </p><blockquote data-parsoid='{"stx":"html"}'> foo </blockquote> +<pre><span> foo </span> +</pre> !! html+tidy <p>a</p> <p>foo</p> @@ -2637,6 +2894,9 @@ a </pre> b <div> foo </div> +!! html/parsoid +<pre>a <span data-parsoid='{"stx":"html"}'>foo</span></pre> + b <div data-parsoid='{"stx":"html"}'> foo </div> !! html+tidy <pre> a <span>foo</span> @@ -2718,7 +2978,7 @@ File:foobar.jpg !! html a <ul class="gallery mw-gallery-traditional"> <li class="gallerybox" style="width: 155px"><div style="width: 155px"> - <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" width="120" height="14" /></a></div></div> + <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" width="120" height="14" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/240px-Foobar.jpg 2x" /></a></div></div> <div class="gallerytext"> </div> </div></li> @@ -2730,7 +2990,7 @@ File:foobar.jpg <li class="gallerybox" style="width: 155px"> <div style="width: 155px"> <div class="thumb" style="width: 150px;"> -<div style="margin:68px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" width="120" height="14" /></a></div> +<div style="margin:68px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" width="120" height="14" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/240px-Foobar.jpg 2x" /></a></div> </div> <div class="gallerytext"></div> </div> @@ -2878,8 +3138,7 @@ parsoid=wt2html,wt2wt {{echo| [[Category:foo]]}} <!-- No pre-wrapping --> !! html <link rel="mw:PageProp/Category" href="./Category:Foo"> <!-- No pre-wrapping --> -<span about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":" [[Category:foo]]"}},"i":0}}]}'> </span> -<link rel="mw:PageProp/Category" href="./Category:Foo" about="#mwt1"> <!-- No pre-wrapping --> +<span about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":" [[Category:foo]]"}},"i":0}}]}'> </span><link rel="mw:PageProp/Category" href="./Category:Foo" about="#mwt1"> <!-- No pre-wrapping --> !! end !! test @@ -2892,7 +3151,6 @@ parsoid=wt2html,wt2wt !! html <pre> <link rel="mw:PageProp/Category" href="./Category:Foo"> a - <link rel="mw:PageProp/Category" href="./Category:Foo"> <span about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"b"}},"i":0}}]}'>b</span></pre> !! end @@ -3110,10 +3368,12 @@ Definition list with wikilink containing colon Definition list with news link containing colon !! wikitext ; news:alt.wikipedia.rox: This isn't even a real newsgroup! -!! html +!! html/php <dl><dt> <a rel="nofollow" class="external free" href="news:alt.wikipedia.rox">news:alt.wikipedia.rox</a></dt> <dd> This isn't even a real newsgroup!</dd></dl> +!! html/parsoid +<dl><dt> <a rel="mw:ExtLink" href="news:alt.wikipedia.rox" data-parsoid='{"stx":"url"}'>news:alt.wikipedia.rox</a></dt><dd data-parsoid='{"stx":"row"}'> This isn't even a real newsgroup!</dd></dl> !! end !! test @@ -3803,7 +4063,7 @@ Definition Lists: Weird Ones: Test 1 <dl> <dt> <dl> -<dt> foo<span typeof="mw:Placeholder" data-parsoid='{"src":" "}'> </span></dt> +<dt> foo<span typeof="mw:Placeholder"> </span></dt> <dd data-parsoid='{"stx":"row"}'> bar (who uses this?)</dd> </dl></dt> </dl></dd> @@ -3815,6 +4075,122 @@ Definition Lists: Weird Ones: Test 1 </ul> !! end +!! test +Definition Lists: colons occurring in tags +!! wikitext +;a:b +;'''a:b''' +;<i>a:b</i> +;<span>a:b</span> +;<div>a:b</div> +;<div>a +:b</div> +;{{echo|a:b}} +;{{echo|''a:b''}} +;;;''a:b'' +!! html+tidy +<dl> +<dt>a</dt> +<dd>b</dd> +<dt><b>a:b</b></dt> +<dt><i>a:b</i></dt> +<dt><span>a:b</span></dt> +<dd> +<div>a:b</div> +</dd> +<dd> +<div>a +<dl> +<dd>b</dd> +</dl> +</div> +</dd> +<dt>a</dt> +<dd>b</dd> +<dt><i>a:b</i></dt> +</dl> +<dl> +<dd> +<dl> +<dd> +<dl> +<dt><i>a:b</i></dt> +</dl> +</dd> +</dl> +</dd> +</dl> +!! end + +!! test +Definition Lists: colons and tables 1 +!! wikitext +:{| +| x +|} +:{| +| y +|} +!! html +<dl><dd><table> +<tr> +<td> x +</td></tr></table></dd></dl> +<dl><dd><table> +<tr> +<td> y +</td></tr></table></dd></dl> + +!! end + +# Parsoid's output (as documented below) differs from php's in this case. +# This is probably a bug. If we fixup parsoid to match php's output, the +# above test should pass and the below test case can be removed. It is +# unclear which output is more desirable. + +!! test +Definition Lists: colons and tables 2 +!! wikitext +:{| +| x +|} +:{| +| y +|} +!! html/parsoid +<dl><dd><table> +<tr> +<td> x +</td></tr></table></dd> +<dd><table> +<tr> +<td> y +</td></tr></table></dd></dl> +!! end + +!! test +Definition Lists: template interaction +!! wikitext +::{{definition_list}} + +:one +::{{definition_list}} +:::two +:::three +::four +!! html/parsoid +<dl><dd><dl data-parsoid='{}'><dd about="#mwt1" typeof="mw:Transclusion" data-parsoid='{"pi":[[]]}' data-mw='{"parts":[":",{"template":{"target":{"wt":"definition_list","href":"./Template:Definition_list"},"params":{},"i":0}}]}'>one</dd><span about="#mwt1"> +</span><dd about="#mwt1">two</dd></dl></dd></dl> + +<dl><dd data-parsoid='{}'>one +<dl><dd about="#mwt2" typeof="mw:Transclusion" data-parsoid='{"pi":[[]]}' data-mw='{"parts":["::",{"template":{"target":{"wt":"definition_list","href":"./Template:Definition_list"},"params":{},"i":0}},"\n:::two\n:::three"]}'>one</dd><span about="#mwt2"> +</span><dd about="#mwt2">two +<dl><dd>two</dd> +<dd>three</dd></dl></dd> +<dd data-parsoid='{}'>four</dd></dl></dd></dl> +!! end + + ### ### External links ### @@ -4004,8 +4380,79 @@ External links: with no contents </p> !! html/parsoid <p><a rel="mw:ExtLink" href="http://en.wikipedia.org/wiki/Foo"></a></p> -<p><a rel="mw:ExtLink" href="http://en.wikipedia.org/wiki/Foo">Bar</a></p> -<p><a rel="mw:ExtLink" href="http://en.wikipedia.org/wiki/Foo"><span>Bar</span></a></p> +<p><a rel="mw:ExtLink" href="http://en.wikipedia.org/wiki/Foo" title="wikipedia:Foo">Bar</a></p> +<p><a rel="mw:ExtLink" href="http://en.wikipedia.org/wiki/Foo" title="wikipedia:Foo"><span>Bar</span></a></p> +!! end + +!! test +External links: Free with trailing punctuation +!! wikitext +http://example.com, +http://example.com; +http://example.com\ +http://example.com. +http://example.com: +http://example.com! +http://example.com? +http://example.com) +http://example.com/url_with_(brackets) +(http://example.com/url_without_brackets) +http://example.com/url_with_entity +http://example.com/url_with_entity  +http://example.com/url_with_entity  +http://example.com/url_with_entity< +http://example.com/url_with_entity< +http://example.com/url_with_entity< +!! html/php +<p><a rel="nofollow" class="external free" href="http://example.com">http://example.com</a>, +<a rel="nofollow" class="external free" href="http://example.com">http://example.com</a>; +<a rel="nofollow" class="external free" href="http://example.com">http://example.com</a>\ +<a rel="nofollow" class="external free" href="http://example.com">http://example.com</a>. +<a rel="nofollow" class="external free" href="http://example.com">http://example.com</a>: +<a rel="nofollow" class="external free" href="http://example.com">http://example.com</a>! +<a rel="nofollow" class="external free" href="http://example.com">http://example.com</a>? +<a rel="nofollow" class="external free" href="http://example.com">http://example.com</a>) +<a rel="nofollow" class="external free" href="http://example.com/url_with_(brackets)">http://example.com/url_with_(brackets)</a> +(<a rel="nofollow" class="external free" href="http://example.com/url_without_brackets">http://example.com/url_without_brackets</a>) +<a rel="nofollow" class="external free" href="http://example.com/url_with_entity ">http://example.com/url_with_entity </a> +<a rel="nofollow" class="external free" href="http://example.com/url_with_entity ">http://example.com/url_with_entity </a> +<a rel="nofollow" class="external free" href="http://example.com/url_with_entity ">http://example.com/url_with_entity </a> +<a rel="nofollow" class="external free" href="http://example.com/url_with_entity">http://example.com/url_with_entity</a>< +<a rel="nofollow" class="external free" href="http://example.com/url_with_entity%3C">http://example.com/url_with_entity%3C</a> +<a rel="nofollow" class="external free" href="http://example.com/url_with_entity%3C">http://example.com/url_with_entity%3C</a> +</p> +!! html/parsoid +<p><a rel="mw:ExtLink" href="http://example.com">http://example.com</a>, +<a rel="mw:ExtLink" href="http://example.com">http://example.com</a>; +<a rel="mw:ExtLink" href="http://example.com">http://example.com</a>\ +<a rel="mw:ExtLink" href="http://example.com">http://example.com</a>. +<a rel="mw:ExtLink" href="http://example.com">http://example.com</a>: +<a rel="mw:ExtLink" href="http://example.com">http://example.com</a>! +<a rel="mw:ExtLink" href="http://example.com">http://example.com</a>? +<a rel="mw:ExtLink" href="http://example.com">http://example.com</a>) +<a rel="mw:ExtLink" href="http://example.com/url_with_(brackets)">http://example.com/url_with_(brackets)</a> +(<a rel="mw:ExtLink" href="http://example.com/url_without_brackets">http://example.com/url_without_brackets</a>) +<a rel="mw:ExtLink" href="http://example.com/url_with_entity ">http://example.com/url_with_entity </a> +<a rel="mw:ExtLink" href="http://example.com/url_with_entity ">http://example.com/url_with_entity </a> +<a rel="mw:ExtLink" href="http://example.com/url_with_entity ">http://example.com/url_with_entity </a> +<a rel="mw:ExtLink" href="http://example.com/url_with_entity">http://example.com/url_with_entity</a><span typeof="mw:Entity"><</span> +<a rel="mw:ExtLink" href="http://example.com/url_with_entity<">http://example.com/url_with_entity<</a> +<a rel="mw:ExtLink" href="http://example.com/url_with_entity<">http://example.com/url_with_entity<</a></p> +!! end + +!! test +External links: No preceding word characters allowed (bug 65278) +!! wikitext +NOPEhttp://example.com +N0http://example.com +ok:http://example.com +ok-http://example.com +!! html +<p>NOPEhttp://example.com +N0http://example.com +ok:<a rel="nofollow" class="external free" href="http://example.com">http://example.com</a> +ok-<a rel="nofollow" class="external free" href="http://example.com">http://example.com</a> +</p> !! end !! test @@ -4095,10 +4542,12 @@ URL in text: [http://example.com http://example.com] External links: Clickable images !! wikitext ja-style clickable images: [http://example.com http://meta.wikimedia.org/upload/f/f1/Ncwikicol.png] -!! html +!! html/php <p>ja-style clickable images: <a rel="nofollow" class="external text" href="http://example.com"><img src="http://meta.wikimedia.org/upload/f/f1/Ncwikicol.png" alt="Ncwikicol.png" /></a> </p> -!!end +!! html/parsoid +<p>ja-style clickable images: <a rel="mw:ExtLink" href="http://example.com"><img src="http://meta.wikimedia.org/upload/f/f1/Ncwikicol.png" alt="Ncwikicol.png" data-parsoid='{"type":"extlink"}'/></a></p> +!! end !! test External links: raw ampersand @@ -4288,10 +4737,12 @@ http://www.example.com/<hello> BUG 289: literal ">"-token in URL-tail !! wikitext http://www.example.com/<b>html</b> -!! html +!! html/php <p><a rel="nofollow" class="external free" href="http://www.example.com/">http://www.example.com/</a><b>html</b> </p> -!!end +!! html/parsoid +<p><a rel="mw:ExtLink" href="http://www.example.com/" data-parsoid='{"stx":"url"}'>http://www.example.com/</a><b data-parsoid='{"stx":"html"}'>html</b></p> +!! end !! test BUG 289: ">"-token in bracketed URL @@ -4410,7 +4861,7 @@ http://www.example.com/?title=AT%26T <p><a rel="mw:ExtLink" href="http://www.example.com/?title=AT%26T">http://www.example.com/?title=AT%26T</a></p> !! end -# According to http://dev.w3.org/html5/spec/Overview.html#parsing-urls a plain +# According to http://www.w3.org/TR/2011/WD-html5-20110525/Overview.html#parsing-urls a plain # % is actually legal in HTML5. Any change in output would need testing though. !! test Bug 4781, 5267: %25 in URL @@ -4751,7 +5202,7 @@ Parenthesis in external links, w/ transclusion or comment </p><p>(<a rel="nofollow" class="external free" href="http://example.com">http://example.com</a>) </p> !! html/parsoid -<p>(<a data-mw='{"attribs":[[{"txt":"href"},{"html":"http://example.com/<span about=\"#mwt1\" typeof=\"mw:Transclusion\" data-mw=\"{&quot;parts&quot;:[{&quot;template&quot;:{&quot;target&quot;:{&quot;wt&quot;:&quot;echo&quot;,&quot;href&quot;:&quot;./Template:Echo&quot;},&quot;params&quot;:{&quot;1&quot;:{&quot;wt&quot;:&quot;hi&quot;}},&quot;i&quot;:0}}]}\" data-parsoid=\"{&quot;pi&quot;:[[{&quot;k&quot;:&quot;1&quot;,&quot;spc&quot;:[&quot;&quot;,&quot;&quot;,&quot;&quot;,&quot;&quot;]}]],&quot;dsr&quot;:[20,31,null,null]}\">hi</span>"}]]}' typeof="mw:ExpandedAttrs" about="#mwt2" rel="mw:ExtLink" href="http://example.com/hi" data-parsoid='{"stx":"url","a":{"href":"http://example.com/hi"},"sa":{"href":"http://example.com/{{echo|hi}}"}}'>http://example.com/hi</a>)</p> +<p>(<a typeof="mw:ExpandedAttrs" about="#mwt2" rel="mw:ExtLink" href="http://example.com/hi" data-parsoid='{"stx":"url","a":{"href":"http://example.com/hi"},"sa":{"href":"http://example.com/{{echo|hi}}"}}' data-mw='{"attribs":[[{"txt":"href"},{"html":"http://example.com/<span about=\"#mwt1\" typeof=\"mw:Transclusion\" data-parsoid=\"{&quot;pi&quot;:[[{&quot;k&quot;:&quot;1&quot;,&quot;spc&quot;:[&quot;&quot;,&quot;&quot;,&quot;&quot;,&quot;&quot;]}]],&quot;dsr&quot;:[20,31,null,null]}\" data-mw=\"{&quot;parts&quot;:[{&quot;template&quot;:{&quot;target&quot;:{&quot;wt&quot;:&quot;echo&quot;,&quot;href&quot;:&quot;./Template:Echo&quot;},&quot;params&quot;:{&quot;1&quot;:{&quot;wt&quot;:&quot;hi&quot;}},&quot;i&quot;:0}}]}\">hi</span>"}]]}'>http://example.com/hi</a>)</p> <p>(<a rel="mw:ExtLink" href="http://example.com" data-parsoid='{"stx":"url","a":{"href":"http://example.com"},"sa":{"href":"http://example.com<!-- hi -->"}}'>http://example.com</a>)</p> !! end @@ -5129,8 +5580,8 @@ Accept "!!" in table data </td></tr></table> !! html/parsoid -<table data-parsoid='{}'> -<tbody data-parsoid='{}'><tr data-parsoid='{"autoInsertedEnd":true,"autoInsertedStart":true}'><td data-parsoid='{"autoInsertedEnd":true}'> Foo!! </td><td data-parsoid='{"stx_v":"row","autoInsertedEnd":true}'></td></tr> +<table> +<tbody><tr data-parsoid='{"autoInsertedEnd":true,"autoInsertedStart":true}'><td data-parsoid='{"autoInsertedEnd":true}'> Foo!! </td><td data-parsoid='{"stx_v":"row","autoInsertedEnd":true}'></td></tr> </tbody></table> !! end @@ -5295,7 +5746,6 @@ Invalid attributes in table cell (bug 1830) !! end - # The "|}" to close the table is missing from the input, so parsoid's # *2wt modes will fail. !! test @@ -5320,6 +5770,25 @@ parsoid=wt2html,html2html <td><a rel="mw:ExtLink" href="ftp://|x||"></a>" onmouseover="alert(document.cookie)">test</td></tr></tbody></table> !! end +# FIXME: The php output is broken. +!! test +! and || in td attributes should not be parsed as <th>/<td> +!! wikitext +{| +| style="color: red !important;" data-contrived="put this here ||" | foo +|} +!! html/php +<table> +<tr> +<td> style="color: red !important;" data-contrived="put this here </td> +<td> foo +</td></tr></table> + +!! html/parsoid +<table> +<tbody><tr><td style="color: red !important;" data-contrived="put this here ||" data-parsoid='{"autoInsertedEnd":true}'> foo</td></tr> +</tbody></table> +!! end !! test Indented table markup mixed with indented pre content (proposed in bug 6200) @@ -5344,50 +5813,83 @@ Indented table markup mixed with indented pre content (proposed in bug 6200) !! end !! test -Template-generated table cell attributes and cell content +1. Template-generated table cell attributes and cell content !! wikitext {| |{{table_attribs}} | {{table_attribs}} +|| {{table_attribs_5}} +| <!--foo--> <!--bar--> <!--baz--> {{table_attribs}} +|align=center {{table_attribs}} +| <!--foo--> align=center <!--bar--> {{table_attribs}} |} !! html <table> <tr> -<td style="color: red"> Foo +<td style="color:red;">Foo </td> -<td style="color: red"> Foo +<td style="color:red;">Foo +</td> +<td> style="color:red;"</td> +<td>Bar +</td> +<td style="color:red;">Foo +</td> +<td align="center" style="color:red;">Foo +</td> +<td align="center" style="color:red;">Foo </td></tr></table> !! end !! test -Template-generated table cell attributes and cell content (2) +2. Template-generated table cell attributes and cell content !! wikitext {| -|align=center {{table_attribs}} +|{{table_attribs_2}} |} -!! html +!! html/php <table> <tr> -<td align="center" style="color: red"> Foo +<td style="color:red;">Foo +</td> +<td>Bar</td> +<td>Baz </td></tr></table> +!! html/parsoid +<table> +<tbody><tr><td about="#mwt1" typeof="mw:Transclusion" style="color:red;" data-mw='{"parts":["|",{"template":{"target":{"wt":"table_attribs_2","href":"./Template:Table_attribs_2"},"params":{},"i":0}}]}'>Foo</td> +<td about="#mwt1">Bar</td><td about="#mwt1">Baz</td></tr> +</tbody></table> !! end !! test -Template-generated table cell attributes and cell content (3) +3. Template-generated table cell attributes and cell content !! wikitext {| +!align=center {{table_header_cells}} +|- |align=center {{table_cells}} |} -!! html +!! html/php <table> <tr> -<td align="center" style="color: red"> Foo </td> -<td> Bar </td> -<td> Baz +<th align="center" style="color:red;">Foo</th> +<th style="color:red;"><i>Bar</i></th> +<th style="color:brown;"><i>Foo</i> and Baz +</th></tr> +<tr> +<td align="center" style="color:red;">Foo</td> +<td style="color:red;"><i>Bar</i></td> +<td style="color:brown;"><i>Foo</i> and Baz </td></tr></table> +!! html/parsoid +<table> +<tbody><tr><th align="center" style="color:red;" typeof="mw:Transclusion" about="#mwt1" data-mw='{"parts":["!align=center ",{"template":{"target":{"wt":"table_header_cells","href":"./Template:Table_header_cells"},"params":{},"i":0}}]}'>Foo</th><th about="#mwt1" style="color:red;"><i about="#mwt1">Bar</i></th><th about="#mwt1" style="color:brown;"><i about="#mwt1">Foo</i> and Baz</th></tr><tr> +<td align="center" style="color:red;" typeof="mw:Transclusion" about="#mwt1" data-mw='{"parts":["|align=center ",{"template":{"target":{"wt":"table_cells","href":"./Template:Table_cells"},"params":{},"i":0}}]}'>Foo</td><td about="#mwt1" style="color:red;"><i about="#mwt1">Bar</i></td><td about="#mwt1" style="color:brown;"><i about="#mwt1">Foo</i> and Baz</td></tr> +</tbody></table> !! end !! test @@ -5450,7 +5952,7 @@ Wikitext table with a lot of comments <!-- c0 --> | foo <!-- c1 --> -|- <!-- c2 --> +|-<!-- c2 --> <!-- c3 --> |<!-- c4 --> <!-- c5 --> @@ -5467,6 +5969,26 @@ Wikitext table with a lot of comments !! end !! test +Wikitext table comments represented in parsoid dom +!! wikitext +{|<!--c1--><!--c2--> +|-<!--c3--> +| x +|} +!! html/php+tidy +<table> +<tr> +<td>x</td> +</tr> +</table> +!! html/parsoid +<table><!--c1--><!--c2--> +<tbody><tr data-parsoid='{"startTagSrc":"|-","autoInsertedEnd":true}'><!--c3--> +<td data-parsoid='{"autoInsertedEnd":true}'> x</td></tr> +</tbody></table> +!! end + +!! test Wikitext table with double-line table cell !! wikitext {| @@ -5548,6 +6070,68 @@ Build table with {{!}} !! end +!! test +Build table with pipe as data +!! wikitext +{| class="wikitable" +! header +! second header +|- style="color:red;" +| data || style="color:red;" | second data +|- +| style="color:red;" | data with | || style="color:red;" | second data with | +|- +|| data with | ||| second data with | +|} +!! html +<table class="wikitable"> +<tr> +<th> header +</th> +<th> second header +</th></tr> +<tr style="color:red;"> +<td> data </td> +<td style="color:red;"> second data +</td></tr> +<tr> +<td style="color:red;"> data with | </td> +<td style="color:red;"> second data with | +</td></tr> +<tr> +<td> data with | </td> +<td> second data with | +</td></tr></table> + +!! end + +!! test +Build table with wikilink +!! wikitext +{| class="wikitable" +! header || second header +|- style="color:red;" +| data [[Main Page|linktext]] || second data [[Main Page|linktext]] +|- +| data || second data [[Main Page|link|text with pipe]] +|} +!! html +<table class="wikitable"> +<tr> +<th> header </th> +<th> second header +</th></tr> +<tr style="color:red;"> +<td> data <a href="/wiki/Main_Page" title="Main Page">linktext</a> </td> +<td> second data <a href="/wiki/Main_Page" title="Main Page">linktext</a> +</td></tr> +<tr> +<td> data </td> +<td> second data <a href="/wiki/Main_Page" title="Main Page">link|text with pipe</a> +</td></tr></table> + +!! end + # The expected HTML structure in this test is debatable. The PHP parser does # not parse this kind of table at all. The main focus for Parsoid is on # round-tripping, so this output is ok for now. TODO: revisit! @@ -5574,7 +6158,7 @@ Wikitext table with html-syntax row !! test Implicit <td> after a |- !! options -parsoid=wt2html,wt2wt +parsoid=wt2html,html2html !! wikitext {| |- @@ -5598,7 +6182,7 @@ a !! test <pre> tags should be recognized in an explicit <td> context, but not in an implicit <td> context !! options -parsoid=wt2html,wt2wt +parsoid=wt2html,html2html !! wikitext {| |- @@ -5638,10 +6222,11 @@ a !! end # PHP + Tidy strips the list out of the table; Parsoid wraps it. +# Parsoid generates the missing <td>, so wt2wt won't succeed. !! test Lists should be recognized in an implicit <td> context !! options -parsoid=wt2html,wt2wt +parsoid=wt2html,html2html !! wikitext {| |- @@ -5668,6 +6253,28 @@ parsoid=wt2html,wt2wt !! end !! test +Table cells not properly parsed in an implicit-td context +!! wikitext +{| +|- +{{table_attribs_4}} || a || b +|} +!! html/php+tidy +<table> +<tr> +<td style="background-color:#DC241f;" width="10px"></td> +<td>a</td> +<td>b</td> +</tr> +</table> +!! html/parsoid +<table> +<tbody><tr data-parsoid='{"startTagSrc":"|-","autoInsertedEnd":true}'> +<td style="background-color:#DC241f;" width="10px" about="#mwt1" typeof="mw:Transclusion" data-parsoid='{"autoInsertedEnd":true,"pi":[[]]}' data-mw='{"parts":["",{"template":{"target":{"wt":"table_attribs_4","href":"./Template:Table_attribs_4"},"params":{},"i":0}}," "]}'> </td><td data-parsoid='{"stx_v":"row","autoInsertedEnd":true}'> a </td><td data-parsoid='{"stx_v":"row","autoInsertedEnd":true}'> b</td></tr> +</tbody></table> +!! end + +!! test Parsoid: Round-trip tables directly followed by content (bug 51219) !! options parsoid=wt2html,wt2wt @@ -5679,20 +6286,30 @@ parsoid=wt2html,wt2wt {| |baz |}<b>quux</b> -!! html -<table><tbody> +!! html+tidy +<table> <tr> -<td>foo</td></tr></tbody></table> bar +<td>foo</td> +</tr> +</table> +<p>bar</p> <table> -<tbody> <tr> -<td>baz</td></tr></tbody></table><b>quux</b> +<td>baz</td> +</tr> +</table> +<p><b>quux</b></p> !! end !! test Parsoid: Default to a newline after tables in new content (bug 51219) !! options parsoid=html2wt +!! html +<table><tbody> +<tr><td>foo</td></tr></tbody></table> bar +<table><tbody> +<tr><td>baz</td></tr></tbody></table><b>quux</b> !! wikitext {| |foo @@ -5702,23 +6319,18 @@ parsoid=html2wt |baz |} '''quux''' -!! html -<table><tbody> -<tr><td>foo</td></tr></tbody></table> bar -<table><tbody> -<tr><td>baz</td></tr></tbody></table><b>quux</b> !! end !! test Parsoid: newline inducing block nodes don't suppress <nowiki> !! options parsoid=html2wt +!! html + a<h1>foo</h1> !! wikitext <nowiki> </nowiki>a = foo = -!! html - a<h1>foo</h1> !! end !! test @@ -5823,6 +6435,27 @@ parsoid=html2wt |} !! end +!!test +Testing serialization after deletion of table cells +!!options +parsoid={ + "modes": ["wt2wt", "selser"], + "changes": [ + ["#x", "remove"] + ] +} +!!wikitext +{| +!h1 !!h2 !!h3 +| id="x" |c1 {{!}}{{!}}{{!}}c2 |||c3 +|} +!! wikitext/edited +{| +!h1 !!h2 !!h3 +|c2 |||c3 +|} +!!end + ### ### Internal links ### @@ -5953,9 +6586,11 @@ Bug 43661: Piped links with identical prefixes Link with HTML entity in suffix / tail !! wikitext [[Main Page]]", [[Main Page]]a -!! html +!! html/php <p><a href="/wiki/Main_Page" title="Main Page">Main Page</a>", <a href="/wiki/Main_Page" title="Main Page">Main Page</a>a </p> +!! html/parsoid +<p><a rel="mw:WikiLink" href="./Main_Page" title="Main Page">Main Page</a><span typeof="mw:Entity" data-parsoid='{"src":"&quot;","srcContent":"\""}'>"</span>, <a rel="mw:WikiLink" href="./Main_Page" title="Main Page">Main Page</a><span typeof="mw:Entity" data-parsoid='{"src":"&#97;","srcContent":"a"}'>a</span></p> !! end !! test @@ -5990,10 +6625,13 @@ Piped link with extlink-like text !! wikitext [[Main Page|[bar]]] [[Main Page|This is a [bar]]] -!! html +!! html/php <p><a href="/wiki/Main_Page" title="Main Page">[bar]</a> <a href="/wiki/Main_Page" title="Main Page">This is a [bar]</a> </p> +!! html/parsoid +<p><a rel="mw:WikiLink" href="./Main_Page" title="Main Page" data-parsoid='{"stx":"piped"}'>[bar]</a> +<a rel="mw:WikiLink" href="./Main_Page" title="Main Page" data-parsoid='{"stx":"piped"}'>This is a [bar]</a></p> !! end !! test @@ -6058,11 +6696,10 @@ Namespace takes precedence over interwiki link (bug 51680) Link to namespace preferred over interwiki with correct rel attribute !! options parsoid=html2wt,html2html +!! html +<p><a rel="mw:WikiLink" href="./MemoryAlpha:AlphaTest" title="MemoryAlpha:AlphaTest">MemoryAlpha:AlphaTest</a></p> !! wikitext [[MemoryAlpha:AlphaTest]] -!! html -<p><a rel="mw:WikiLink" href="./MemoryAlpha:AlphaTest" title="MemoryAlpha:AlphaTest">MemoryAlpha:AlphaTest</a> -</p> !! end !! test @@ -6213,7 +6850,7 @@ Link containing double-single-quotes '' in text embedded in italics (bug 4598 sa !! test Link with double quotes in title part (literal) and alternate part (interpreted) !! wikitext -[[File:Denys Savchenko ''Pentecoste''.jpg]] +[[File:Denys_Savchenko_''Pentecoste''.jpg]] [[''Pentecoste'']] @@ -6227,7 +6864,7 @@ Link with double quotes in title part (literal) and alternate part (interpreted) </p><p><a href="/index.php?title=%27%27Pentecoste%27%27&action=edit&redlink=1" class="new" title="''Pentecoste'' (page does not exist)"><i>Pentecoste</i></a> </p> !! html/parsoid -<meta typeof="mw:Placeholder"/> +<p><span class="mw-default-size" typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}]}'><a href="./File:Denys_Savchenko_''Pentecoste''.jpg"><img resource="./File:Denys_Savchenko_''Pentecoste''.jpg" src="./Special:FilePath/Denys_Savchenko_''Pentecoste''.jpg" height="220" width="220"/></a></span></p> <p><a rel="mw:WikiLink" href="''Pentecoste''" title="''Pentecoste''">''Pentecoste''</a></p> <p><a rel="mw:WikiLink" href="''Pentecoste''" title="''Pentecoste''">Pentecoste</a></p> <p><a rel="mw:WikiLink" href="''Pentecoste''" title="''Pentecoste''"><i>Pentecoste</i></a></p> @@ -6237,15 +6874,20 @@ Link with double quotes in title part (literal) and alternate part (interpreted) Broken image links with HTML captions (bug 39700) !! wikitext [[File:Nonexistent|<script></script>]] -[[File:Nonexistent|100px|<script></script>]] +[[File:Nonexistent|100x100px|<script></script>]] [[File:Nonexistent|<]] [[File:Nonexistent|a<i>b</i>c]] -!! html +!! html/php <p><a href="/index.php?title=Special:Upload&wpDestFile=Nonexistent" class="new" title="File:Nonexistent"><script></script></a> <a href="/index.php?title=Special:Upload&wpDestFile=Nonexistent" class="new" title="File:Nonexistent"><script></script></a> <a href="/index.php?title=Special:Upload&wpDestFile=Nonexistent" class="new" title="File:Nonexistent"><</a> <a href="/index.php?title=Special:Upload&wpDestFile=Nonexistent" class="new" title="File:Nonexistent">abc</a> </p> +!! html/parsoid +<p><span class="mw-default-size" typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}],"caption":"<script></script>"}'><a href="./File:Nonexistent"><img resource="./File:Nonexistent" src="./Special:FilePath/Nonexistent" height="220" width="220"/></a></span> +<span typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}],"caption":"<script></script>"}'><a href="./File:Nonexistent" data-parsoid='{"a":{"href":"./File:Nonexistent"},"sa":{}}'><img resource="./File:Nonexistent" src="./Special:FilePath/Nonexistent" height="100" width="100"/></a></span> +<span class="mw-default-size" typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}],"caption":"&lt;"}'><a href="./File:Nonexistent"><img resource="./File:Nonexistent" src="./Special:FilePath/Nonexistent" height="220" width="220"/></a></span> +<span class="mw-default-size" typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}],"caption":"a<i>b</i>c"}'><a href="./File:Nonexistent"><img resource="./File:Nonexistent" src="./Special:FilePath/Nonexistent" height="220" width="220"/></a></span></p> !! end !! test @@ -6483,7 +7125,7 @@ title=[[User:test/123]] <p><a href="#a">b</a> </p> !! html/parsoid -<p data-parsoid='{}'><a rel="mw:WikiLink" href="../User:Test/123#a" data-parsoid='{"stx":"piped","a":{"href":"../User:Test/123#a"},"sa":{"href":"#a"}}'>b</a></p> +<p><a rel="mw:WikiLink" href="../User:Test/123#a" data-parsoid='{"stx":"piped","a":{"href":"../User:Test/123#a"},"sa":{"href":"#a"}}'>b</a></p> !! end !! test @@ -6503,7 +7145,7 @@ parsoid !! wikitext {{echo|Some [[Fool]]}}s !! html -<p data-parsoid='{}'><span about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"Some [[Fool]]"}},"i":0}},"s"]}' data-parsoid='{"pi":[[{"k":"1","spc":["","","",""]}]]}'>Some </span><a rel="mw:WikiLink" href="./Fool" title="Fool" about="#mwt1" data-parsoid='{"stx":"simple","a":{"href":"./Fool"},"sa":{"href":"Fool"},"tail":"s"}'>Fools</a></p> +<p><span about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"Some [[Fool]]"}},"i":0}},"s"]}' data-parsoid='{"pi":[[{"k":"1","spc":["","","",""]}]]}'>Some </span><a rel="mw:WikiLink" href="./Fool" title="Fool" about="#mwt1" data-parsoid='{"stx":"simple","a":{"href":"./Fool"},"sa":{"href":"Fool"},"tail":"s"}'>Fools</a></p> !! end !! test @@ -6513,7 +7155,7 @@ parsoid !! wikitext {{echo|Some [[Fool]]s are '''bold and foolish'''}} !! html -<p about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"Some [[Fool]]s are '''bold and foolish'''"}},"i":0}}]}' data-parsoid='{"pi":[[{"k":"1","spc":["","","",""]}]]}'>Some <a rel="mw:WikiLink" href="./Fool" title="Fool" data-parsoid='{"stx":"simple","a":{"href":"./Fool"},"sa":{"href":"Fool"},"tail":"s"}'>Fools</a> are <b data-parsoid="{}">bold and foolish</b></p> +<p about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"Some [[Fool]]s are '''bold and foolish'''"}},"i":0}}]}' data-parsoid='{"pi":[[{"k":"1","spc":["","","",""]}]]}'>Some <a rel="mw:WikiLink" href="./Fool" title="Fool" data-parsoid='{"stx":"simple","a":{"href":"./Fool"},"sa":{"href":"Fool"},"tail":"s"}'>Fools</a> are <b>bold and foolish</b></p> !! end !! article @@ -6562,10 +7204,10 @@ mótmælenda[[söfnuður|söfnuðir]]xxx Parsoid link trail escaping !! options parsoid=html2wt,html2html -!! wikitext -[[apple]]<nowiki/>s !! html <p><a rel="mw:WikiLink" href="Apple" title="Apple">apple</a>s</p> +!! wikitext +[[apple]]<nowiki/>s !! end !! test @@ -6573,10 +7215,10 @@ Parsoid link prefix escaping !! options language=is parsoid=html2wt,html2html -!! wikitext -Aðrir mótmælenda<nowiki/>[[söfnuður]] !! html <p>Aðrir mótmælenda<a rel="mw:WikiLink" href="Söfnuður" title="Söfnuður">söfnuður</a></p> +!! wikitext +Aðrir mótmælenda<nowiki/>[[söfnuður]] !! end !! test @@ -6624,20 +7266,28 @@ Link with angle bracket after anchor !! test Inline interwiki link +!! options +parsoid=wt2html,wt2wt,html2html !! wikitext [[MeatBall:SoftSecurity]] -!! html +!! html/php <p><a href="http://www.usemod.com/cgi-bin/mb.pl?SoftSecurity" class="extiw" title="meatball:SoftSecurity">MeatBall:SoftSecurity</a> </p> +!! html/parsoid +<p><a rel="mw:ExtLink" href="http://www.usemod.com/cgi-bin/mb.pl?SoftSecurity" title="meatball:SoftSecurity">MeatBall:SoftSecurity</a></p> !! end !! test Inline interwiki link with empty title (bug 2372) +!! options +parsoid=wt2html,wt2wt,html2html !! wikitext [[MeatBall:]] -!! html +!! html/php <p><a href="http://www.usemod.com/cgi-bin/mb.pl" class="extiw" title="meatball:">MeatBall:</a> </p> +!! html/parsoid +<p><a rel="mw:ExtLink" href="http://www.usemod.com/cgi-bin/mb.pl?" title="meatball:">MeatBall:</a></p> !! end !! test @@ -6666,6 +7316,10 @@ Interwiki link with fragment (bug 2130) !! end # Ideally the wikipedia: prefix here should be proto-relative too +# [CSA]: this is kind of a bogus test, as the PHP parser test doesn't +# define the 'en' prefix, and originally the test used 'wikipedia', +# which isn't a localinterwiki prefix hence the links to the 'en:Foo' +# article. !! test Different interwiki prefixes mapping to the same URL !! wikitext @@ -6683,19 +7337,19 @@ Different interwiki prefixes mapping to the same URL [[ wikiPEdia :Foo]] !! html/parsoid -<p><a rel="mw:ExtLink" href="//en.wikipedia.org/wiki/Foo" data-parsoid='{"stx":"simple","a":{"href":"//en.wikipedia.org/wiki/Foo"},"sa":{"href":":en:Foo"},"isIW":true}'>en:Foo</a></p> +<p><a rel="mw:ExtLink" href="//en.wikipedia.org/wiki/Foo" data-parsoid='{"stx":"simple","a":{"href":"//en.wikipedia.org/wiki/Foo"},"sa":{"href":":en:Foo"},"isIW":true}' title="en:Foo">en:Foo</a></p> -<p><a rel="mw:ExtLink" href="//en.wikipedia.org/wiki/Foo" data-parsoid='{"stx":"piped","a":{"href":"//en.wikipedia.org/wiki/Foo"},"sa":{"href":":en:Foo"},"isIW":true}'>Foo</a></p> +<p><a rel="mw:ExtLink" href="//en.wikipedia.org/wiki/Foo" data-parsoid='{"stx":"piped","a":{"href":"//en.wikipedia.org/wiki/Foo"},"sa":{"href":":en:Foo"},"isIW":true}' title="en:Foo">Foo</a></p> -<p><a rel="mw:ExtLink" href="http://en.wikipedia.org/wiki/Foo" data-parsoid='{"stx":"simple","a":{"href":"http://en.wikipedia.org/wiki/Foo"},"sa":{"href":"wikipedia:Foo"},"isIW":true}'>wikipedia:Foo</a></p> +<p><a rel="mw:ExtLink" href="http://en.wikipedia.org/wiki/Foo" data-parsoid='{"stx":"simple","a":{"href":"http://en.wikipedia.org/wiki/Foo"},"sa":{"href":"wikipedia:Foo"},"isIW":true}' title="wikipedia:Foo">wikipedia:Foo</a></p> -<p><a rel="mw:ExtLink" href="http://en.wikipedia.org/wiki/Foo" data-parsoid='{"stx":"piped","a":{"href":"http://en.wikipedia.org/wiki/Foo"},"sa":{"href":":wikipedia:Foo"},"isIW":true}'>Foo</a></p> +<p><a rel="mw:ExtLink" href="http://en.wikipedia.org/wiki/Foo" data-parsoid='{"stx":"piped","a":{"href":"http://en.wikipedia.org/wiki/Foo"},"sa":{"href":":wikipedia:Foo"},"isIW":true}' title="wikipedia:Foo">Foo</a></p> -<p><a rel="mw:ExtLink" href="http://en.wikipedia.org/wiki/en:Foo" data-parsoid='{"stx":"simple","a":{"href":"http://en.wikipedia.org/wiki/en:Foo"},"sa":{"href":"wikipedia:en:Foo"},"isIW":true}'>wikipedia:en:Foo</a></p> +<p><a rel="mw:ExtLink" href="http://en.wikipedia.org/wiki/en:Foo" data-parsoid='{"stx":"simple","a":{"href":"http://en.wikipedia.org/wiki/en:Foo"},"sa":{"href":"wikipedia:en:Foo"},"isIW":true}' title="wikipedia:en:Foo">wikipedia:en:Foo</a></p> -<p><a rel="mw:ExtLink" href="http://en.wikipedia.org/wiki/en:Foo" data-parsoid='{"stx":"simple","a":{"href":"http://en.wikipedia.org/wiki/en:Foo"},"sa":{"href":":wikipedia:en:Foo"},"isIW":true}'>wikipedia:en:Foo</a></p> +<p><a rel="mw:ExtLink" href="http://en.wikipedia.org/wiki/en:Foo" data-parsoid='{"stx":"simple","a":{"href":"http://en.wikipedia.org/wiki/en:Foo"},"sa":{"href":":wikipedia:en:Foo"},"isIW":true}' title="wikipedia:en:Foo">wikipedia:en:Foo</a></p> -<p><a rel="mw:ExtLink" href="http://en.wikipedia.org/wiki/Foo" data-parsoid='{"stx":"simple","a":{"href":"http://en.wikipedia.org/wiki/Foo"},"sa":{"href":" wikiPEdia :Foo"},"isIW":true}'> wikiPEdia :Foo</a></p> +<p><a rel="mw:ExtLink" href="http://en.wikipedia.org/wiki/Foo" data-parsoid='{"stx":"simple","a":{"href":"http://en.wikipedia.org/wiki/Foo"},"sa":{"href":" wikiPEdia :Foo"},"isIW":true}' title="wikipedia:Foo"> wikiPEdia :Foo</a></p> !! end !! test @@ -6707,60 +7361,97 @@ Interwiki links that cannot be represented in wiki syntax [http://de.wikipedia.org/wiki/Foo?action=history has query] [http://de.wikipedia.org/wiki/#foo is just fragment] +!! html/php +<p><a href="http://www.usemod.com/cgi-bin/mb.pl?ok" class="extiw" title="meatball:ok">meatball:ok</a> +<a href="http://www.usemod.com/cgi-bin/mb.pl?ok#foo" class="extiw" title="meatball:ok">ok with fragment</a> +<a href="http://www.usemod.com/cgi-bin/mb.pl?ok_as_well%3F" class="extiw" title="meatball:ok as well?">ok ending with ? mark</a> +<a rel="nofollow" class="external text" href="http://de.wikipedia.org/wiki/Foo?action=history">has query</a> +<a rel="nofollow" class="external text" href="http://de.wikipedia.org/wiki/#foo">is just fragment</a> +</p> !! html/parsoid -<p><a rel="mw:ExtLink" href="http://www.usemod.com/cgi-bin/mb.pl?ok">meatball:ok</a> -<a rel="mw:ExtLink" href="http://www.usemod.com/cgi-bin/mb.pl?ok#foo">ok with fragment</a> -<a rel="mw:ExtLink" href="http://www.usemod.com/cgi-bin/mb.pl?ok_as_well?">ok ending with ? mark</a> +<p><a rel="mw:ExtLink" href="http://www.usemod.com/cgi-bin/mb.pl?ok" title="meatball:ok">meatball:ok</a> +<a rel="mw:ExtLink" href="http://www.usemod.com/cgi-bin/mb.pl?ok#foo" title="meatball:ok">ok with fragment</a> +<a rel="mw:ExtLink" href="http://www.usemod.com/cgi-bin/mb.pl?ok_as_well?" title="meatball:ok as well?">ok ending with ? mark</a> <a rel="mw:ExtLink" href="http://de.wikipedia.org/wiki/Foo?action=history">has query</a> <a rel="mw:ExtLink" href="http://de.wikipedia.org/wiki/#foo">is just fragment</a></p> !! end !! test Interwiki links: trail -!! options -parsoid !! wikitext [[wikipedia:Foo|Ba]]r -!! html -<p data-parsoid='{}'><a rel="mw:ExtLink" href="http://en.wikipedia.org/wiki/Foo" data-parsoid='{"stx":"piped","a":{"href":"http://en.wikipedia.org/wiki/Foo"},"sa":{"href":"wikipedia:Foo"},"isIW":true,"tail":"r"}'>Bar</a></p> +!! html/php +<p><a href="http://en.wikipedia.org/wiki/Foo" class="extiw" title="wikipedia:Foo">Bar</a> +</p> +!! html/parsoid +<p><a rel="mw:ExtLink" href="http://en.wikipedia.org/wiki/Foo" data-parsoid='{"stx":"piped","a":{"href":"http://en.wikipedia.org/wiki/Foo"},"sa":{"href":"wikipedia:Foo"},"isIW":true,"tail":"r"}' title="wikipedia:Foo">Bar</a></p> !! end !! test Local interwiki link +!! options +parsoid=wt2html,wt2wt,html2html !! wikitext [[local:Template:Foo]] -!! html +!! html/php <p><a href="/wiki/Template:Foo" title="Template:Foo">local:Template:Foo</a> </p> +!! html/parsoid +<p><a rel="mw:WikiLink" href="./Template:Foo" title="Template:Foo">local:Template:Foo</a></p> !! end +# Parsoid does not mark self-links, by design. !! test Local interwiki link: self-link to current page !! options title=[[Main Page]] +parsoid=wt2html,wt2wt,html2html !! wikitext [[local:Main Page]] -!! html +!! html/php <p><strong class="selflink">local:Main Page</strong> </p> +!! html/parsoid +<p><a rel="mw:WikiLink" href="./Main_Page" title="Main Page">local:Main Page</a></p> !! end !! test Local interwiki link: prefix only (bug 64167) +!! options +parsoid=wt2html,wt2wt,html2html !! wikitext [[local:]] -!! html +!! html/php <p><a href="/wiki/Main_Page" title="Main Page">local:</a> </p> +!! html/parsoid +<p><a rel="mw:WikiLink" href="./Main_Page" title="Main Page">local:</a></p> !! end !! test Local interwiki link: with additional interwiki prefix (bug 61357) +!! options +parsoid=wt2html,wt2wt,html2html !! wikitext [[local:meatball:Hello]] -!! html +!! html/php <p><a href="http://www.usemod.com/cgi-bin/mb.pl?Hello" class="extiw" title="meatball:Hello">local:meatball:Hello</a> </p> +!! html/parsoid +<p><a rel="mw:ExtLink" href="http://www.usemod.com/cgi-bin/mb.pl?Hello" title="meatball:Hello">local:meatball:Hello</a></p> +!! end + +!! test +Multiple local interwiki link prefixes +!! wikitext +[[local:local:local:local:mi:local:Foo]] +!! options +parsoid=wt2html,wt2wt,html2html +!! html/php +<p><a href="/wiki/Foo" title="Foo">local:local:local:local:mi:local:Foo</a> +</p> +!! html/parsoid +<p><a rel="mw:WikiLink" href="./Foo" title="Foo">local:local:local:local:mi:local:Foo</a></p> !! end ### @@ -6770,6 +7461,8 @@ Local interwiki link: with additional interwiki prefix (bug 61357) !! test Interlanguage link +!! options +parsoid=wt2html,wt2wt,html2html !! wikitext Blah blah blah [[zh:Chinese]] @@ -6777,12 +7470,14 @@ Blah blah blah <p>Blah blah blah </p> !! html/parsoid -<p>Blah blah blah -<link rel="mw:PageProp/Language" href="//zh.wikipedia.org/wiki/Chinese"/></p> +<p>Blah blah blah</p> +<link rel="mw:PageProp/Language" href="http://zh.wikipedia.org/wiki/Chinese"/> !! end !! test Interlanguage link with spacing +!! options +parsoid=wt2html,wt2wt,html2html !! wikitext Blah blah blah [[ zh : Chinese ]] @@ -6790,12 +7485,14 @@ Blah blah blah <p>Blah blah blah </p> !! html/parsoid -<p>Blah blah blah -<link rel="mw:PageProp/Language" href="//zh.wikipedia.org/wiki/Chinese"/></p> +<p>Blah blah blah</p> +<link rel="mw:PageProp/Language" href="http://zh.wikipedia.org/wiki/Chinese"/> !! end !! test Double interlanguage link +!! options +parsoid=wt2html,wt2wt,html2html !! wikitext Blah blah blah [[es:Spanish]] @@ -6804,24 +7501,30 @@ Blah blah blah <p>Blah blah blah </p> !! html/parsoid -<p>Blah blah blah -<link rel="mw:PageProp/Language" href="//es.wikipedia.org/wiki/Spanish"/> -<link rel="mw:PageProp/Language" href="//zh.wikipedia.org/wiki/Chinese"/></p> +<p>Blah blah blah</p> +<link rel="mw:PageProp/Language" href="http://es.wikipedia.org/wiki/Spanish"/> +<link rel="mw:PageProp/Language" href="http://zh.wikipedia.org/wiki/Chinese"/> !! end !! test Interlanguage link variations +!! options +parsoid=wt2html,wt2wt,html2html !! wikitext Blah blah blah [[ es :Spanish]] [[ ZH :Chinese]] +[[es:Foo_bar]] +[[es:Foo bar]] !! html/php <p>Blah blah blah </p> !! html/parsoid -<p>Blah blah blah -<link rel="mw:PageProp/Language" href="//es.wikipedia.org/wiki/Spanish" data-parsoid='{"stx":"simple","a":{"href":"//es.wikipedia.org/wiki/Spanish"},"sa":{"href":" es :Spanish"}}'/> -<link rel="mw:PageProp/Language" href="//zh.wikipedia.org/wiki/Chinese" data-parsoid='{"stx":"simple","a":{"href":"//zh.wikipedia.org/wiki/Chinese"},"sa":{"href":" ZH :Chinese"}}'/> +<p>Blah blah blah</p> +<link rel="mw:PageProp/Language" href="http://es.wikipedia.org/wiki/Spanish" /> +<link rel="mw:PageProp/Language" href="http://zh.wikipedia.org/wiki/Chinese" /> +<link rel="mw:PageProp/Language" href="http://es.wikipedia.org/wiki/Foo_bar" /> +<link rel="mw:PageProp/Language" href="http://es.wikipedia.org/wiki/Foo_bar" /> !! end !! test @@ -6835,8 +7538,8 @@ Blah blah blah <p>Blah blah blah </p> !! html/parsoid -<p>Blah blah blah -<link rel="mw:PageProp/Language" href="//zh.wikipedia.org/wiki/Chinese"/></p> +<p>Blah blah blah</p> +<link rel="mw:PageProp/Language" href="http://zh.wikipedia.org/wiki/Chinese"/> !! end !! test @@ -6851,9 +7554,9 @@ Blah blah blah <p>Blah blah blah </p> !! html/parsoid -<p>Blah blah blah -<link rel="mw:PageProp/Language" href="//es.wikipedia.org/wiki/Spanish"/> -<link rel="mw:PageProp/Language" href="//zh.wikipedia.org/wiki/Chinese"/></p> +<p>Blah blah blah</p> +<link rel="mw:PageProp/Language" href="http://es.wikipedia.org/wiki/Spanish"/> +<link rel="mw:PageProp/Language" href="http://zh.wikipedia.org/wiki/Chinese"/> !! end !! test @@ -6865,8 +7568,8 @@ Blah blah blah <p>Blah blah blah </p> !! html/parsoid -<p>Blah blah blah -<link rel="mw:PageProp/Language" title="Multilingual" href="//wikisource.org/wiki/Article"/></p> +<p>Blah blah blah</p> +<link rel="mw:PageProp/Language" title="Multilingual" href="http://wikisource.org/wiki/Article"/> !! end !! test @@ -6884,84 +7587,119 @@ language=ln Parsoid bug 53221: Wikilinks should be properly entity-escaped !! options parsoid=html2wt +!! html +<p>He&nbsp;llo <a href="Foo" rel="mw:WikiLink">He&nbsp;llo</a></p> +<p>He&nbsp;llo <a href="He&nbsp;llo" rel="mw:WikiLink">He&nbsp;llo</a></p> !! wikitext He&nbsp;llo [[Foo|He&nbsp;llo]] He&nbsp;llo [[He&nbsp;llo]] -!! html -<p>He&nbsp;llo <a href="Foo" rel="mw:WikiLink">He&nbsp;llo</a></p> -<p>He&nbsp;llo <a href="He&nbsp;llo" rel="mw:WikiLink">He&nbsp;llo</a></p> !! end !! test Parsoid: handle constructor well -!! options -parsoid !! wikitext [[constructor]] [[constructor:foo]] -!! html +!! html/php +<p><a href="/index.php?title=Constructor&action=edit&redlink=1" class="new" title="Constructor (page does not exist)">constructor</a> +</p><p><a href="/index.php?title=Constructor:foo&action=edit&redlink=1" class="new" title="Constructor:foo (page does not exist)">constructor:foo</a> +</p> +!! html/parsoid <p><a rel="mw:WikiLink" href="./Constructor" title="Constructor" data-parsoid="{"stx":"simple","a":{"href":"./Constructor"},"sa":{"href":"constructor"}}">constructor</a></p> <p><a rel="mw:WikiLink" href="./Foo" title="Foo" data-parsoid="{"stx":"simple","a":{"href":"./Foo"},"sa":{"href":"constructor:foo"}}">constructor:foo</a></p> !! end +!! article +ko: +!! text +Test. +!! endarticle + +# Note that `ko` isn't a known interlanguage prefix !! test Parsoid: recognize interlanguage links without a target page !! options -parsoid +ill !! wikitext +[[es:]] + [[ko:]] -!! html -<p><link rel="mw:PageProp/Language" href="http://ko.wikipedia.org/wiki/"></p> +!! html/php +es: +!! html/parsoid +<link rel="mw:PageProp/Language" href="http://es.wikipedia.org/wiki/"/> + +<p><a rel="mw:WikiLink" href="./Ko:" title="Ko:">ko:</a></p> !! end +# Note that `ko` isn't a known interwiki prefix !! test Parsoid: recognize interwiki links without a target page !! options -parsoid +parsoid=wt2html,wt2wt,html2html !! wikitext +[[:es:]] + [[:ko:]] -!! html -<p><a rel="mw:ExtLink" href="//ko.wikipedia.org/wiki/">ko:</a></p> +!! html/php +<p><a href="http://es.wikipedia.org/wiki/" class="extiw" title="es:">es:</a> +</p><p><a href="/wiki/Ko:" title="Ko:">ko:</a> +</p> +!! html/parsoid +<p><a rel="mw:ExtLink" href="http://es.wikipedia.org/wiki/" title="es:">es:</a></p> +<p><a rel="mw:WikiLink" href="./Ko:" title="Ko:">ko:</a></p> !! end !! test -Parsoid: Bug #45209, handle interwiki links pointing to the current wiki as plain wiki links -!! options -parsoid +Handle interwiki links pointing to the current wiki as plain wiki links (bug 45209) !! wikitext -[[en:Foo]] -!! html -<p><a rel="mw:WikiLink" href="./Foo" title="Foo" data-parsoid='{"stx":"simple","a":{"href":"./Foo"},"sa":{"href":"en:Foo"}}'>Foo</a></p> +[[mi:Foo]] +!! html/php +<p><a href="/wiki/Foo" title="Foo">mi:Foo</a> +</p> +!! html/parsoid +<p><a rel="mw:WikiLink" href="./Foo" title="Foo" data-parsoid='{"stx":"simple","a":{"href":"./Foo"},"sa":{"href":"mi:Foo"}}'>mi:Foo</a></p> !! end !! test Interlanguage link with preceding local interwiki link (bug 68085) +!! options +parsoid=wt2html,wt2wt,html2html !! wikitext Blah blah blah [[local:es:Spanish]] -!! html +!! html/php <p>Blah blah blah <a href="http://es.wikipedia.org/wiki/Spanish" class="extiw" title="es:Spanish">local:es:Spanish</a> </p> +!! html/parsoid +<p>Blah blah blah +<a rel="mw:ExtLink" href="http://es.wikipedia.org/wiki/Spanish" title="es:Spanish">local:es:Spanish</a></p> !! end !! test Looks like an interlanguage link, but is actually a local interwiki +!! options +parsoid=wt2html,wt2wt,html2html !! wikitext Blah blah blah [[mi:Template:Foo]] -!! html +!! html/php <p>Blah blah blah <a href="/wiki/Template:Foo" title="Template:Foo">mi:Template:Foo</a> </p> +!! html/parsoid +<p>Blah blah blah +<a rel="mw:WikiLink" href="Template:Foo" title="Template:Foo">mi:Template:Foo</a></p> !! end ### ### Redirects, Parsoid-only ### + !! test 1. Simple redirect to page !! options @@ -6972,17 +7710,20 @@ parsoid <link rel="mw:PageProp/redirect" href="./Main_Page"> !! end -# Only wt2html and html2html since "Main_Page" will serialize to "Main Page" !! test 2. Other redirect variants -!! options -parsoid=wt2html,wt2wt !! wikitext #REDIRECT [[Main_Page]] +!! html/parsoid +<link rel="mw:PageProp/redirect" href="./Main_Page" data-parsoid='{"src":"#REDIRECT ","a":{"href":"./Main_Page"},"sa":{"href":"Main_Page"}}'/> +!! end + +!! test +3. Other redirect variants +!! wikitext #REDIRECT [[<nowiki>[[Bar]]</nowiki>]] -!! html -<link rel="mw:PageProp/redirect" href="./Main_Page"> -<link rel="mw:PageProp/redirect" href="./%5B%5BBar%5D%5D"> +!! html/parsoid +<link rel="mw:PageProp/redirect" href="./%5B%5BBar%5D%5D" data-parsoid='{"src":"#REDIRECT ","a":{"href":"./%5B%5BBar%5D%5D"},"sa":{"href":"<nowiki>[[Bar]]</nowiki>"}}'/> !! end !! test @@ -7039,7 +7780,7 @@ parsoid=wt2html !! test Redirect to category !! options -parsoid=wt2html +parsoid=wt2wt,wt2html !! wikitext #REDIRECT [[Category:Foo]] !! html @@ -7059,11 +7800,11 @@ parsoid=wt2html !! test Redirect to category page !! options -parsoid=wt2html,html2html +parsoid !! wikitext #REDIRECT [[:Category:Foo]] !! html -<p><a rel="mw:WikiLink" href="Category:Foo" title="Category:Foo">Category:Foo</a></p> +<link rel="mw:PageProp/redirect" href="Category:Foo" title="Category:Foo"/> !! end !! test @@ -7093,7 +7834,7 @@ parsoid !! wikitext #REDIRECT [[en:File:Wiki.png]] !! html -<link rel="mw:PageProp/redirect" href="File:Wiki.png"> +<link rel="mw:PageProp/redirect" href="./File:Wiki.png"> !! end !! test @@ -7103,7 +7844,7 @@ parsoid !! wikitext #REDIRECT [[meatball:File:Wiki.png]] !! html -<link rel="mw:PageProp/redirect" href="File:Wiki.png"> +<link rel="mw:PageProp/redirect" href="./File:Wiki.png"> !! end !! test @@ -7118,14 +7859,26 @@ language=is !! end !! test +Redirect syntax under text isn't considered a redirect +!! wikitext +some text +#redirect [[Main Page]] +!! html/parsoid +<p>some text</p> +<ol data-parsoid='{}'><li data-parsoid='{}'>redirect <a rel="mw:WikiLink" href="./Main_Page" title="Main Page" data-parsoid='{"stx":"simple","a":{"href":"./Main_Page"},"sa":{"href":"Main Page"}}'>Main Page</a></li></ol> +!! end + +# FIXME: Should hoist the redirect to the top of the page and ensure there +# is only one. +!! test New redirect !! options parsoid=html2wt +!! html +<p>Foo<link rel="mw:PageProp/redirect" href="./Foo"></p> !! wikitext Foo #REDIRECT [[Foo]] -!! html -<p>Foo<link rel="mw:PageProp/redirect" href="./Foo"></p> !! end ## @@ -7151,9 +7904,6 @@ Broken br tag sanitization !! end # TODO: Fix html2html mode (bug 51055)! -# This </br> handling was added as part of bug 50831; but it -# differs from how PHP+tidy handles this. We should investigate -# this. !! test Parsoid: Broken br tag recognition !! options @@ -7162,12 +7912,9 @@ parsoid=wt2html </br> <br/ > -!! html/php+tidy -<p></br></p> +!! html+tidy +<p><br /></p> <p><br /></p> -!! html/parsoid -<p><br></p> -<p><br/></p> !! end !! test @@ -7192,6 +7939,8 @@ Failing to transform badly formed HTML into correct XHTML </p> !!end +## FIXME: Is Parsoid's acceptance of self-closing html-tags +## a feature or a bug? See https://phabricator.wikimedia.org/T76962 !! test Handling html with a div self-closing tag !! wikitext @@ -7201,7 +7950,7 @@ Handling html with a div self-closing tag <div title=bar /> <div title=bar/> <div title=bar/ > -!! html +!! html/php <p><div title /> <div title/> </p> @@ -7212,6 +7961,13 @@ Handling html with a div self-closing tag <div title="bar/"></div> </div> +!! html/parsoid +<div title="" data-parsoid='{"stx":"html","selfClose":true}'></div> +<div title="" data-parsoid='{"stx":"html","selfClose":true}'></div> +<div title="" data-parsoid='{"stx":"html","selfClose":true,"brokenHTMLTag":true}'></div> +<div title="bar" data-parsoid='{"stx":"html","selfClose":true}'></div> +<div title="bar" data-parsoid='{"stx":"html","selfClose":true}'></div> +<div title="bar/" data-parsoid='{"stx":"html","autoInsertedEnd":true}'></div> !! end !! test @@ -7234,7 +7990,7 @@ Handling html with a br self-closing tag !! html/parsoid <p><br title="" /> <br title="" /> -<br /> +<br title="" /> <br title="bar" /> <br title="bar" /> <br title="bar/" /> @@ -7248,11 +8004,12 @@ Horizontal ruler (should it add that extra space?) <hr > foo <hr > bar -!! html +!! html+tidy <hr /> <hr /> -foo <hr /> bar - +<p>foo</p> +<hr /> +<p>bar</p> !! end !! test @@ -7462,6 +8219,16 @@ Nested lists 8 (multiple nesting transitions) !! end !! test +Nested lists 9 (extension interaction) +!! options +parsoid +!! wikitext +*<references /> +!! html/parsoid +<ul><li data-parsoid='{}'><ol class="references" typeof="mw:Extension/references" about="#mwt2" data-parsoid='{}' data-mw='{"name":"references","attrs":{}}'></ol></li></ul> +!! end + +!! test 1. Lists with start-of-line-transparent tokens before bullets: Comments !! wikitext *foo @@ -7718,6 +8485,8 @@ Unbalanced closing non-block tags don't break a list !! test Unclosed formatting tags that straddle lists are closed and reopened (php parser relies on Tidy to fix up) +!! options +parsoid=wt2html,wt2wt,html2html !! wikitext # <s> a # b </s> @@ -7727,19 +8496,13 @@ Unclosed formatting tags that straddle lists are closed and reopened <li><s>b</s></li> </ol> !! html/parsoid -<ol> -<li> <s> a </s> -</li> -<li> <s> b </s> -</li> -</ol> +<ol><li> <s> a</s></li> +<li><s> b </s></li></ol> !! end -# Parsoid fails this test, but it might be tricky to support properly. # See bug 68395. !!test -List embedded in a non-block tag -(Ugly Parsoid output -- worth fixing; PHP parser relies on Tidy) +1. List embedded in a formatting tag !! wikitext <small> * foo @@ -7756,6 +8519,49 @@ List embedded in a non-block tag </small> !!end +## Ugly Parsoid output here +## Not sure what the right output is. +!!test +2. List embedded in a formatting tag +!! wikitext +<small> +*a +*b</small> +!! html/php+tidy +<ul> +<li><small>a</small></li> +<li><small>b</small></li> +</ul> +!! html/parsoid +<small></small> +<ul><small> +<li>a</li> +</small> +<li><small>b</small></li> +</ul> +!!end + +# Ugly Parsoid and PHP parser output here +# Not sure if we want to make this a test! +# +## !!test +## 3. Unclosed formatting tags in list elements +## !! wikitext +## *<small>a +## *<small>b +## !! html/php+tidy +## <ul> +## <li><small>a</small></li> +## <li><small><small>b</small></small></li> +## </ul> +## !! html/parsoid +## <ul> +## <li><small>a</small></li> +## <small> +## <li><small>b</small></li> +## </small></ul> +## !!end + # This is a bug in the PHP parser + tidy combination. # (The </tr> tag gets parsed as text and html-escaped by PHP, # and then fostered out of the table by tidy.) @@ -7769,14 +8575,7 @@ parsoid=wt2html,wt2wt <td>foo</td> </tr> </table> -!! html/php+tidy -<p></tr></p> -<table> -<tr> -<td>foo</td> -</tr> -</table> -!! html/parsoid +!! html+tidy <table> <tr> <td>foo</td> @@ -8360,6 +9159,23 @@ Aoeu </p> !! end +# From plwiki:PLOS_ONE +!! test +Parsoid: Page property magic word with magic word contents +!! wikitext +{{DISPLAYTITLE:''{{PAGENAME}}''}} +!! html/parsoid +<meta property="mw:PageProp/displaytitle" content="Main Page" about="#mwt2" typeof="mw:ExpandedAttrs" data-mw='{"attribs":[[{"txt":"content"},{"html":"<i data-parsoid=\"{&quot;dsr&quot;:[15,31,2,2]}\"><span about=\"#mwt1\" typeof=\"mw:Transclusion\" data-parsoid=\"{&quot;pi&quot;:[[]],&quot;dsr&quot;:[17,29,null,null]}\" data-mw=\"{&quot;parts&quot;:[{&quot;template&quot;:{&quot;target&quot;:{&quot;wt&quot;:&quot;PAGENAME&quot;,&quot;function&quot;:&quot;pagename&quot;},&quot;params&quot;:{},&quot;i&quot;:0}}]}\">Main Page</span></i>"}]]}'/> +!! end + +!! test +Parsoid: Template-generated DISPLAYTITLE +!! wikitext +{{{{echo|DISPLAYTITLE}}:Foo}} +!! html/parsoid +<meta property="mw:PageProp/displaytitle" content="Foo" about="#mwt1" typeof="mw:Transclusion" data-parsoid='{"dsr":[0,29,null,null],"pi":[[]]}' data-mw='{"parts":[{"template":{"target":{"wt":"{{echo|DISPLAYTITLE}}:Foo"},"params":{},"i":0}}]}'/> +!! end + !! test Namespace 1 {{ns:1}} !! wikitext @@ -8490,10 +9306,10 @@ hi+world%3F%21 Magic Word: prioritize type info over data-parsoid !! options parsoid=html2wt +!! html +<meta property="mw:PageProp/forcetoc" data-parsoid='{"magicSrc":"__NOTOC__"}'/> !! wikitext __FORCETOC__ -!! html -<meta property="mw:PageProp/forcetoc" data-parsoid='{"src":"__NOTOC__","magicSrc":"__NOTOC__"}'/> !! end !! test @@ -8516,7 +9332,7 @@ language=de !! wikitext __NOEDITSECTION__ !! html -<meta property="mw:PageProp/noeditsection" data-parsoid='{"src":"__NOEDITSECTION__","magicSrc":"__NOEDITSECTION__"}'/> +<meta property="mw:PageProp/noeditsection" data-parsoid='{"magicSrc":"__NOEDITSECTION__"}'/> !! end ### @@ -8541,6 +9357,28 @@ RFC 822 !! end !! test +Magic links: RFC (bug 65278) +!! wikitext +This is RFC 822 but thisRFC 822 is not RFC 822linked. +!! html +<p>This is <a class="external mw-magiclink-rfc" rel="nofollow" href="//tools.ietf.org/html/rfc822">RFC 822</a> but thisRFC 822 is not RFC 822linked. +</p> +!! end + +!! test +Magic links: RFC (w/ non-newline whitespace, bug 28950/29025) +!! wikitext +RFC      822 +RFC +822 +!! html +<p><a class="external mw-magiclink-rfc" rel="nofollow" href="//tools.ietf.org/html/rfc822">RFC 822</a> +RFC +822 +</p> +!! end + +!! test Magic links: ISBN (bug 1937) !! wikitext ISBN 0-306-40615-2 @@ -8550,6 +9388,34 @@ ISBN 0-306-40615-2 !! end !! test +Magic links: ISBN (bug 65278) +!! wikitext +This is ISBN 978-0-316-09811-3 but thisISBN 978-0-316-09811-3 is not ISBN 978-0-316-09811-3linked. +!! html/php +<p>This is <a href="/wiki/Special:BookSources/9780316098113" class="internal mw-magiclink-isbn">ISBN 978-0-316-09811-3</a> but thisISBN 978-0-316-09811-3 is not ISBN 978-0-316-09811-3linked. +</p> +!! html/parsoid +<p>This is <a href="./Special:BookSources/9780316098113" rel="mw:ExtLink">ISBN 978-0-316-09811-3</a> but thisISBN 978-0-316-09811-3 is not ISBN 978-0-316-09811-3linked.</p> +!! end + +!! test +Magic links: ISBN (w/ non-newline whitespace, bug 28950/29025) +!! wikitext +ISBN      978 0 316 09811 3 +ISBN +9780316098113 +ISBN 978 +0316098113 +!! html +<p><a href="/wiki/Special:BookSources/9780316098113" class="internal mw-magiclink-isbn">ISBN 978 0 316 09811 3</a> +ISBN +9780316098113 +ISBN 978 +0316098113 +</p> +!! end + +!! test Magic links: PMID incorrectly converts space to underscore !! wikitext PMID 1234 @@ -8558,6 +9424,28 @@ PMID 1234 </p> !! end +!! test +Magic links: PMID (bug 65278) +!! wikitext +This is PMID 1234 but thisPMID 1234 is not PMID 1234linked. +!! html +<p>This is <a class="external mw-magiclink-pmid" rel="nofollow" href="//www.ncbi.nlm.nih.gov/pubmed/1234?dopt=Abstract">PMID 1234</a> but thisPMID 1234 is not PMID 1234linked. +</p> +!! end + +!! test +Magic links: PMID (w/ non-newline whitespace, bug 28950/29025) +!! wikitext +PMID      1234 +PMID +1234 +!! html +<p><a class="external mw-magiclink-pmid" rel="nofollow" href="//www.ncbi.nlm.nih.gov/pubmed/1234?dopt=Abstract">PMID 1234</a> +PMID +1234 +</p> +!! end + ### ### Templates #### @@ -8783,8 +9671,7 @@ Template with complex template as argument !! test Template with thumb image (with link in description) !! wikitext -{{paramtest| - param =[[Image:noimage.png|thumb|[[no link|link]] [[no link|caption]]]]}} +{{paramtest|param =[[Image:noimage.png|thumb|[[no link|link]] [[no link|caption]]]]}} !! html/php This is a test template with parameter <div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/index.php?title=Special:Upload&wpDestFile=Noimage.png" class="new" title="File:Noimage.png">File:Noimage.png</a> <div class="thumbcaption"><a href="/index.php?title=No_link&action=edit&redlink=1" class="new" title="No link (page does not exist)">link</a> <a href="/index.php?title=No_link&action=edit&redlink=1" class="new" title="No link (page does not exist)">caption</a></div></div></div> @@ -8795,6 +9682,8 @@ This is a test template with parameter <div class="thumb tright"><div class="thu <div class="thumbcaption"><a href="/index.php?title=No_link&action=edit&redlink=1" class="new" title="No link (page does not exist)">link</a> <a href="/index.php?title=No_link&action=edit&redlink=1" class="new" title="No link (page does not exist)">caption</a></div> </div> </div> +!! html/parsoid +<p about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"paramtest","href":"./Template:Paramtest"},"params":{"param":{"wt":"[[Image:noimage.png|thumb|[[no link|link]] [[no link|caption]]]]"}},"i":0}}]}'>This is a test template with parameter </p><figure class="mw-default-size" typeof="mw:Error mw:Image/Thumb" about="#mwt1" data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}]}'><a href="./File:Noimage.png" ><img resource="./File:Noimage.png" src="./Special:FilePath/Noimage.png" height="220" width="220"/></a><figcaption><a rel="mw:WikiLink" href="./No_link" title="No link">link</a> <a rel="mw:WikiLink" href="./No_link" title="No link">caption</a></figcaption></figure> !! end !! article @@ -8853,15 +9742,6 @@ Template parameter as link source </p> !! end -!!test -Template-generated attribute string (k='v') -!! wikitext -<span {{attr_str|id|v1}}>bar</span> -!! html -<p><span id="v1">bar</span> -</p> -!!end - !!article Template:paramtest2 !! text @@ -9237,19 +10117,15 @@ some <h3><span class="mw-headline" id="here">here</span></h3> !! html/parsoid -<!-- comment --><meta typeof="mw:Includes/NoInclude" data-parsoid='{"src":"<noinclude>"}'/><!-- comment --><meta typeof="mw:Includes/NoInclude/End" data-parsoid='{"src":"</noinclude>"}'/><!-- comment --> -<h2 data-parsoid='{}'> hu </h2> +<!-- comment --><meta typeof="mw:Includes/NoInclude" data-parsoid='{"src":"<noinclude>"}'/><!-- comment --><meta typeof="mw:Includes/NoInclude/End" data-parsoid='{"src":"</noinclude>"}'/><!-- comment --><h2> hu </h2> <meta typeof="mw:Includes/NoInclude" data-parsoid='{"src":"<noinclude>"}'/> +<p>some</p> +<meta typeof="mw:Includes/NoInclude/End" data-parsoid='{"src":"</noinclude>"}'/><ul><li> stuff</li> +<li> here</li></ul> -<p data-parsoid='{}'>some</p> -<meta typeof="mw:Includes/NoInclude/End" data-parsoid='{"src":"</noinclude>"}'/> -<ul data-parsoid='{}'> -<li data-parsoid='{}'> stuff</li> - -<li data-parsoid='{}'> here</li></ul> +<meta typeof="mw:Includes/IncludeOnly" data-parsoid='{"src":"<includeonly>can have stuff</includeonly>"}'/><meta typeof="mw:Includes/IncludeOnly/End" data-parsoid='{"src":""}'/><h3> here </h3> -<h3 data-parsoid='{}'> here </h3> !! end # TODO: test with DOM fragment reuse! @@ -9270,25 +10146,17 @@ c}}d b}} !! html -a<span about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"b -<table></table>c"}},"i":0}}]}'>b</span> -<table about="#mwt1"></table><span about="#mwt1">c</span>d +<p about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":["a",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"b<table></table>c"}},"i":0}},"d"]}' data-parsoid='{"pi":[[{"k":"1","spc":["","","",""]}]]}'>ab</p><table about="#mwt1" data-parsoid='{"stx":"html"}'></table><p about="#mwt1">cd</p> +<p about="#mwt2" typeof="mw:Transclusion" data-mw='{"parts":["a",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"b\n<table></table>\nc"}},"i":0}},"d"]}' data-parsoid='{"pi":[[{"k":"1","spc":["","","",""]}]]}'>ab</p><span about="#mwt2"> +</span><table about="#mwt2" data-parsoid='{"stx":"html"}'></table><span about="#mwt2"> +</span><p about="#mwt2">cd</p> -<p about="#mwt2" typeof="mw:Transclusion" data-mw='{"parts":["a",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"b\n<table></table>\nc"}},"i":0}},"d"]}'>ab</p><span about="#mwt2"> -</span> -<table about="#mwt2"></table><span about="#mwt2"> -</span> -<p about="#mwt2">cd</p> - +<p about="#mwt3" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"a\n\n<table></table>\n\nb"}},"i":0}}]}' data-parsoid='{"pi":[[{"k":"1","spc":["","","",""]}]]}'>a</p><span about="#mwt3"> -<p about="#mwt3" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"a\n\n<table></table>\n\nb"}},"i":0}}]}'>a</p><span about="#mwt3"> - -</span> -<table about="#mwt3"></table><span about="#mwt3"> +</span><table about="#mwt3" data-parsoid='{"stx":"html"}'></table><span about="#mwt3"> -</span> -<p about="#mwt3">b</p> +</span><p about="#mwt3">b</p> !! end !! test @@ -9405,11 +10273,9 @@ parsoid=wt2html,wt2wt |foo |} !!html/parsoid -<span typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":""}},"i":0}}]}'></span> -<table width="100%"> -<tbody> -<tr> -<td>foo</td></tr></tbody></table> +<span typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":""}},"i":0}}]}'></span><table width="100%"> +<tbody><tr><td>foo</td></tr> +</tbody></table> !!end !!test @@ -9421,7 +10287,7 @@ parsoid=wt2html,wt2wt |c |} !!html/parsoid -<meta typeof="mw:Includes/IncludeOnly" data-parsoid='{"src":"<includeonly>a</includeonly>"'/><meta typeof="mw:Includes/IncludeOnly/End" data-parsoid='{"src":""}'/><table about="#mwt2" typeof="mw:ExpandedAttrs" data-mw='{"attribs":[[{"txt":"{{{b}}}","html":"<span about=\"#mwt1\" typeof=\"mw:Param\" data-parsoid=\"{&quot;dsr&quot;:[31,38,null,null],&quot;src&quot;:&quot;{{{b}}}&quot;}\">{{{b}}}</span>"},{"html":""}]]}' data-parsoid='{"a":{"{{{b}}}":null},"sa":{"{{{b}}}":""}}'> +<meta typeof="mw:Includes/IncludeOnly"/><meta typeof="mw:Includes/IncludeOnly/End"/><table about="#mwt2" typeof="mw:ExpandedAttrs" data-mw='{"attribs":[[{"txt":"{{{b}}}","html":"<span about=\"#mwt1\" typeof=\"mw:Param\" data-parsoid=\"{&quot;dsr&quot;:[31,38,null,null],&quot;src&quot;:&quot;{{{b}}}&quot;}\">{{{b}}}</span>"},{"html":""}]]}' data-parsoid='{"a":{"{{{b}}}":null},"sa":{"{{{b}}}":""}}'> <tbody><tr><td>c</td></tr> </tbody></table> @@ -9592,7 +10458,7 @@ Templates: Correctly encapsulate templates producing </p> tag without a correspo b</p>}} !! html/parsoid <p about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"a\nb</p>"}},"i":0}}]}'>a -b</p><p></p> +b</p> !!end !!test @@ -9718,6 +10584,9 @@ Templates: HTML Tag: 6. Generation of end piece of HTML attr value !!end +# SSS FIXME: While it is great we added support for all this, +# do we want to make this part of the spec? Maybe we want to +# deprecate this kind of usage in the future? !!test Templates: HTML Tag: 7. Generation of partial attribute key string !! wikitext @@ -9727,6 +10596,79 @@ Templates: HTML Tag: 7. Generation of partial attribute key string !!end +!! test +Templates: HTML Tag: 8. Template-generated attribute (k=v) +!! wikitext +<div {{echo|1=id="v1"}}>bar</div> +!! html +<div id="v1">bar</div> + +!!end + +!! test +Templates: HTML Tag: 9. Multiple template-generated attributes +!! wikitext +<div {{echo|1=id="v1" title="foo"}}>bar</div> +!! html +<div id="v1" title="foo">bar</div> + +!!end + +!! test +Templates: Support for templates generating attributes and content +!! wikitext +{| {{mixed_attr_content_template}} +|- +|bar +|} +!! html/php +<table style="color:red;" title="T48811"> + +<tr> +<td>foo +</td></tr> +<tr> +<td>bar +</td></tr></table> + +!! html/parsoid +<table style="color:red;" title="T48811" about="#mwt1" typeof="mw:Transclusion mw:ExpandedAttrs" data-mw='{"parts":["{| ",{"template":{"target":{"wt":"mixed_attr_content_template","href":"./Template:Mixed_attr_content_template"},"params":{},"i":0}},"\n|-\n|bar\n|}"]}'> +<tbody><tr> +<td>foo</td></tr> +<tr> +<td>bar</td></tr> +</tbody></table> +!!end + +!! test +1. Entities and nowikis inside templated attributes should be handled correctly +!! wikitext +<div {{echo|style{{=}}"background:#f9f9f9;"}}>foo</div> +!! html/php +<div style="background:#f9f9f9;">foo</div> + +!! html/parsoid +<div style="background:#f9f9f9;" about="#mwt3" typeof="mw:ExpandedAttrs" data-parsoid='{"stx":"html"}' data-mw='{"attribs":[[{"txt":"style","html":"<span about=\"#mwt1\" typeof=\"mw:Transclusion\" data-parsoid=\"{&quot;pi&quot;:[[{&quot;k&quot;:&quot;1&quot;,&quot;spc&quot;:[&quot;&quot;,&quot;&quot;,&quot;&quot;,&quot;&quot;]}]],&quot;dsr&quot;:[5,49,null,null]}\" data-mw=\"{&quot;parts&quot;:[{&quot;template&quot;:{&quot;target&quot;:{&quot;wt&quot;:&quot;echo&quot;,&quot;href&quot;:&quot;./Template:Echo&quot;},&quot;params&quot;:{&quot;1&quot;:{&quot;wt&quot;:&quot;style{{=}}\\&quot;background:&amp;#35;f9f9f9;\\&quot;&quot;}},&quot;i&quot;:0}}]}\">style</span><span typeof=\"mw:Nowiki\" about=\"#mwt1\" data-parsoid=\"{}\">=</span><span about=\"#mwt1\" data-parsoid=\"{}\">\"background:</span><span typeof=\"mw:Entity\" about=\"#mwt1\" data-parsoid=\"{&quot;src&quot;:&quot;&amp;#35;&quot;,&quot;srcContent&quot;:&quot;#&quot;}\">#</span><span about=\"#mwt1\" data-parsoid=\"{}\">f9f9f9;\"</span>"},{"html":""}]]}'>foo</div> +!! end + +!! test +2. Entities and nowikis inside templated attributes should be handled correctly +!! wikitext +{| +|{{table_attribs_3}} +|} +!! html/php +<table> +<tr> +<td style="background:#f9f9f9;">Foo +</td></tr></table> + +!! html/parsoid +<table> +<tbody><tr data-parsoid='{"autoInsertedEnd":true,"autoInsertedStart":true}'><td style="background:#f9f9f9;" typeof="mw:Transclusion" about="#mwt1" data-parsoid='{"autoInsertedEnd":true,"pi":[[]]}' data-mw='{"parts":["|",{"template":{"target":{"wt":"table_attribs_3","href":"./Template:Table_attribs_3"},"params":{},"i":0}}]}'>Foo</td></tr> +</tbody></table> +!! end + !!test Templates: HTML Tables: 1. Generating start of a HTML table !! wikitext @@ -10700,26 +11642,26 @@ parsoid=wt2html Parsoid: Escape nowiki with trailing space in tags !! options parsoid=html2wt +!! html +<p><nowiki > foo </nowiki ></p> +<p>a<nowiki />b</p> +<p>c<nowiki/ >d</p> !! wikitext <nowiki > foo </nowiki > a<nowiki />b c<nowiki/ >d -!! html -<p><nowiki > foo </nowiki ></p> -<p>a<nowiki />b</p> -<p>c<nowiki/ >d</p> !! end !! test Parsoid: Escape weird noWikI capitalizations !! options parsoid=html2wt -!! wikitext -<noWikI > foo </NoWikI > !! html <p><noWikI > foo </NoWikI ></p> +!! wikitext +<noWikI > foo </NoWikI > !! end ### @@ -10841,8 +11783,7 @@ parsoid=wt2html,wt2wt,html2html <p><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> </p> !! html/parsoid -<p><span class="mw-default-size" typeof="mw:Image"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"></a></span> -</p> +<p><span class="mw-default-size" typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></span></p> !! end !! test @@ -10853,8 +11794,7 @@ Simple image (using File: namespace, now canonical) <p><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> </p> !! html/parsoid -<p><span class="mw-default-size" typeof="mw:Image"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"></a></span> -</p> +<p><span class="mw-default-size" typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></span></p> !! end !! test @@ -10865,7 +11805,7 @@ Right-aligned image <div class="floatright"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a></div> !! html/parsoid -<figure class="mw-default-size mw-halign-right" typeof="mw:Image"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"></a></figure> +<figure class="mw-default-size mw-halign-right" typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></figure> !! end !! test @@ -10876,7 +11816,7 @@ Image with caption <div class="floatright"><a href="/wiki/File:Foobar.jpg" class="image" title="Caption text"><img alt="Caption text" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a></div> !! html/parsoid -<figure class="mw-default-size mw-halign-right" typeof="mw:Image"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"></a><figcaption>Caption text</figcaption></figure> +<figure class="mw-default-size mw-halign-right" typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a><figcaption>Caption text</figcaption></figure> !! end !! test @@ -10887,7 +11827,7 @@ Image with caption, bug 53312 #1 <div class="floatright"><a href="/wiki/File:Foobar.jpg" class="image" title="Caption page stuff"><img alt="Caption page stuff" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a></div> !! html/parsoid -<figure class="mw-default-size mw-halign-right" typeof="mw:Image"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"></a><figcaption>Caption page stuff</figcaption></figure> +<figure class="mw-default-size mw-halign-right" typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a><figcaption>Caption page stuff</figcaption></figure> !! end !! test @@ -10898,7 +11838,7 @@ Image with caption, bug 53312 #2 <div class="floatright"><a href="/wiki/File:Foobar.jpg" class="image" title="Caption page="><img alt="Caption page=" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a></div> !! html/parsoid -<figure class="mw-default-size mw-halign-right" typeof="mw:Image"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"></a><figcaption>Caption page=</figcaption></figure> +<figure class="mw-default-size mw-halign-right" typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a><figcaption>Caption page=</figcaption></figure> !! end !! test @@ -10909,7 +11849,7 @@ Image with caption, bug 53312 #3 <div class="floatright"><a href="/wiki/File:Foobar.jpg" class="image" title="Caption page=stuff"><img alt="Caption page=stuff" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a></div> !! html/parsoid -<figure class="mw-default-size mw-halign-right" typeof="mw:Image"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"></a><figcaption>Caption page=stuff</figcaption></figure> +<figure class="mw-default-size mw-halign-right" typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a><figcaption>Caption page=stuff</figcaption></figure> !! end !! test @@ -10925,13 +11865,22 @@ thumbsize=220 <div class="thumb tright"><div class="thumbinner" style="width:222px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" width="220" height="25" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/330px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/440px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"></a></div>Caption <a href="/index.php?title=Link1&action=edit&redlink=1" class="new" title="Link1 (page does not exist)">Link1</a> [[]] <a href="/index.php?title=Link2&action=edit&redlink=1" class="new" title="Link2 (page does not exist)">Link2</a></div></div></div> !! html/parsoid -<figure class="mw-default-size" typeof="mw:Image/Thumb" data-parsoid='{"optList":[{"ck":"thumbnail","ak":"thumb"},{"ck":"caption","ak":"Caption [[Link1]]\n[[]]\n[[Link2]]\n"}],"dsr":[0,59,2,2]}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"},"dsr":[2,null,null,null]}'><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" height="25" width="220" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"25","width":"220"},"sa":{"resource":"File:Foobar.jpg"}}'/></a><figcaption data-parsoid='{"dsr":[null,57,null,null]}'>Caption <a rel="mw:WikiLink" href="./Link1" title="Link1" data-parsoid='{"stx":"simple","a":{"href":"./Link1"},"sa":{"href":"Link1"},"dsr":[32,41,2,2]}'>Link1</a> +<figure class="mw-default-size" typeof="mw:Image/Thumb" data-parsoid='{"optList":[{"ck":"thumbnail","ak":"thumb"},{"ck":"caption","ak":"Caption [[Link1]]\n[[]]\n[[Link2]]\n"}]}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"}}'><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"25","width":"220"},"sa":{"resource":"File:Foobar.jpg"}}'/></a><figcaption>Caption <a rel="mw:WikiLink" href="./Link1" title="Link1" data-parsoid='{"stx":"simple","a":{"href":"./Link1"},"sa":{"href":"Link1"}}'>Link1</a> [[]] -<a rel="mw:WikiLink" href="./Link2" title="Link2" data-parsoid='{"stx":"simple","a":{"href":"./Link2"},"sa":{"href":"Link2"},"dsr":[47,56,2,2]}'>Link2</a> +<a rel="mw:WikiLink" href="./Link2" title="Link2" data-parsoid='{"stx":"simple","a":{"href":"./Link2"},"sa":{"href":"Link2"}}'>Link2</a> </figcaption></figure> !! end !! test +Titles in unlinked images (T23454) +!! wikitext +[[File:Foobar.jpg|link=|stuff]] +!! html/php +<p><img alt="stuff" src="http://example.com/images/3/3a/Foobar.jpg" title="stuff" width="1941" height="220" /> +</p> +!! end + +!! test Link with empty target !! wikitext [[]] @@ -10941,6 +11890,17 @@ Link with empty target !! end !! test +Image with link trail +!! wikitext +Linktrails should not work for images: [[File:Foobar.jpg]]s +!! html/php +<p>Linktrails should not work for images: <a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a>s +</p> +!! html/parsoid +<p>Linktrails should not work for images: <span class="mw-default-size" typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></span>s</p> +!! end + +!! test Image with empty attribute !! options parsoid=wt2html,wt2wt,html2html @@ -10950,7 +11910,7 @@ parsoid=wt2html,wt2wt,html2html <div class="floatright"><a href="/wiki/File:Foobar.jpg" class="image" title="Caption text"><img alt="Caption text" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a></div> !! html/parsoid -<figure class="mw-default-size mw-halign-right" typeof="mw:Image"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"></a><figcaption>Caption text</figcaption></figure> +<figure class="mw-default-size mw-halign-right" typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a><figcaption>Caption text</figcaption></figure> !! end !! test @@ -10961,7 +11921,7 @@ parsoid=wt2html,wt2wt,html2html <div class="thumb tright"><div class="thumbinner" style="width:139px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/137px-Foobar.jpg" width="137" height="16" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/206px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/274px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"></a></div>This is a caption</div></div></div> !! html/parsoid -<figure typeof="mw:Image/Thumb mw:ExpandedAttrs" data-mw='{"attribs":[["thumbnail",{"html":"thumb"}],["width",{"html":"<span about=\"#mwt1\" typeof=\"mw:Transclusion\" data-mw=\"{&quot;parts&quot;:[{&quot;template&quot;:{&quot;target&quot;:{&quot;wt&quot;:&quot;echo&quot;,&quot;href&quot;:&quot;./Template:Echo&quot;},&quot;params&quot;:{&quot;1&quot;:{&quot;wt&quot;:&quot;137px&quot;}},&quot;i&quot;:0}}]}\" data-parsoid=\"{&quot;pi&quot;:[[{&quot;k&quot;:&quot;1&quot;,&quot;spc&quot;:[&quot;&quot;,&quot;&quot;,&quot;&quot;,&quot;&quot;]}]],&quot;dsr&quot;:[24,38,null,null]}\">137px</span>"}]]}'><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="16" width="137"/></a><figcaption>This is a caption</figcaption></figure> +<figure typeof="mw:Image/Thumb mw:ExpandedAttrs" about="#mwt2" data-mw='{"attribs":[["thumbnail",{"html":"thumb"}],["width",{"html":"<span about=\"#mwt1\" typeof=\"mw:Transclusion\" data-parsoid=\"{&quot;pi&quot;:[[{&quot;k&quot;:&quot;1&quot;,&quot;spc&quot;:[&quot;&quot;,&quot;&quot;,&quot;&quot;,&quot;&quot;]}]],&quot;dsr&quot;:[24,38,null,null]}\" data-mw=\"{&quot;parts&quot;:[{&quot;template&quot;:{&quot;target&quot;:{&quot;wt&quot;:&quot;echo&quot;,&quot;href&quot;:&quot;./Template:Echo&quot;},&quot;params&quot;:{&quot;1&quot;:{&quot;wt&quot;:&quot;137px&quot;}},&quot;i&quot;:0}}]}\">137px</span>"}]]}'><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="16" width="137"/></a><figcaption>This is a caption</figcaption></figure> !! end !! test @@ -10972,7 +11932,7 @@ parsoid=wt2html,wt2wt,html2html <div class="thumb tright"><div class="thumbinner" style="width:139px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/137px-Foobar.jpg" width="137" height="16" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/206px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/274px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"></a></div>This is a caption</div></div></div> !! html/parsoid -<figure typeof="mw:Image/Thumb mw:ExpandedAttrs" data-mw='{"attribs":[["thumbnail",{"html":"<span about=\"#mwt1\" typeof=\"mw:Transclusion\" data-mw=\"{&quot;parts&quot;:[{&quot;template&quot;:{&quot;target&quot;:{&quot;wt&quot;:&quot;echo&quot;,&quot;href&quot;:&quot;./Template:Echo&quot;},&quot;params&quot;:{&quot;1&quot;:{&quot;wt&quot;:&quot;thumb&quot;}},&quot;i&quot;:0}}]}\" data-parsoid=\"{&quot;pi&quot;:[[{&quot;k&quot;:&quot;1&quot;,&quot;spc&quot;:[&quot;&quot;,&quot;&quot;,&quot;&quot;,&quot;&quot;]}]],&quot;dsr&quot;:[18,32,null,null]}\">thumb</span>"}],["width",{"html":"<span about=\"#mwt2\" typeof=\"mw:Transclusion\" data-mw=\"{&quot;parts&quot;:[{&quot;template&quot;:{&quot;target&quot;:{&quot;wt&quot;:&quot;echo&quot;,&quot;href&quot;:&quot;./Template:Echo&quot;},&quot;params&quot;:{&quot;1&quot;:{&quot;wt&quot;:&quot;137px&quot;}},&quot;i&quot;:0}}]}\" data-parsoid=\"{&quot;pi&quot;:[[{&quot;k&quot;:&quot;1&quot;,&quot;spc&quot;:[&quot;&quot;,&quot;&quot;,&quot;&quot;,&quot;&quot;]}]],&quot;dsr&quot;:[33,47,null,null]}\">137px</span>"}]]}'><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="16" width="137"/></a><figcaption>This is a caption</figcaption></figure> +<figure typeof="mw:Image/Thumb mw:ExpandedAttrs" about="#mwt3" data-mw='{"attribs":[["thumbnail",{"html":"<span about=\"#mwt1\" typeof=\"mw:Transclusion\" data-parsoid=\"{&quot;pi&quot;:[[{&quot;k&quot;:&quot;1&quot;,&quot;spc&quot;:[&quot;&quot;,&quot;&quot;,&quot;&quot;,&quot;&quot;]}]],&quot;dsr&quot;:[18,32,null,null]}\" data-mw=\"{&quot;parts&quot;:[{&quot;template&quot;:{&quot;target&quot;:{&quot;wt&quot;:&quot;echo&quot;,&quot;href&quot;:&quot;./Template:Echo&quot;},&quot;params&quot;:{&quot;1&quot;:{&quot;wt&quot;:&quot;thumb&quot;}},&quot;i&quot;:0}}]}\">thumb</span>"}],["width",{"html":"<span about=\"#mwt2\" typeof=\"mw:Transclusion\" data-parsoid=\"{&quot;pi&quot;:[[{&quot;k&quot;:&quot;1&quot;,&quot;spc&quot;:[&quot;&quot;,&quot;&quot;,&quot;&quot;,&quot;&quot;]}]],&quot;dsr&quot;:[33,47,null,null]}\" data-mw=\"{&quot;parts&quot;:[{&quot;template&quot;:{&quot;target&quot;:{&quot;wt&quot;:&quot;echo&quot;,&quot;href&quot;:&quot;./Template:Echo&quot;},&quot;params&quot;:{&quot;1&quot;:{&quot;wt&quot;:&quot;137px&quot;}},&quot;i&quot;:0}}]}\">137px</span>"}]]}'><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="16" width="137"/></a><figcaption>This is a caption</figcaption></figure> !! end !! test @@ -10983,7 +11943,7 @@ parsoid=wt2html,wt2wt,html2html <p><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/thumb/3/3a/Foobar.jpg/50px-Foobar.jpg" width="50" height="6" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/75px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/100px-Foobar.jpg 2x" /></a> </p> !! html/parsoid -<p><span typeof="mw:Image mw:ExpandedAttrs" about="#mwt2" data-mw='{"attribs":[["width",{"html":"<span about=\"#mwt1\" typeof=\"mw:Transclusion\" data-mw=\"{&quot;parts&quot;:[{&quot;template&quot;:{&quot;target&quot;:{&quot;wt&quot;:&quot;echo&quot;,&quot;href&quot;:&quot;./Template:Echo&quot;},&quot;params&quot;:{&quot;1&quot;:{&quot;wt&quot;:&quot;50px&quot;}},&quot;i&quot;:0}}]}\" data-parsoid=\"{&quot;pi&quot;:[[{&quot;k&quot;:&quot;1&quot;,&quot;spc&quot;:[&quot;&quot;,&quot;&quot;,&quot;&quot;,&quot;&quot;]}]],&quot;dsr&quot;:[18,31,null,null]}\">50px</span>"}]]}' data-parsoid='{"optList":[{"ck":"width","ak":"{{echo|50px}}"}]}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"}}'><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/50px-Foobar.jpg" height="6" width="50" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"6","width":"50"},"sa":{"resource":"File:Foobar.jpg"}}'/></a></span></p> +<p><span typeof="mw:Image mw:ExpandedAttrs" about="#mwt2" data-parsoid='{"optList":[{"ck":"width","ak":"{{echo|50px}}"}]}' data-mw='{"attribs":[["width",{"html":"<span about=\"#mwt1\" typeof=\"mw:Transclusion\" data-parsoid=\"{&quot;pi&quot;:[[{&quot;k&quot;:&quot;1&quot;,&quot;spc&quot;:[&quot;&quot;,&quot;&quot;,&quot;&quot;,&quot;&quot;]}]],&quot;dsr&quot;:[18,31,null,null]}\" data-mw=\"{&quot;parts&quot;:[{&quot;template&quot;:{&quot;target&quot;:{&quot;wt&quot;:&quot;echo&quot;,&quot;href&quot;:&quot;./Template:Echo&quot;},&quot;params&quot;:{&quot;1&quot;:{&quot;wt&quot;:&quot;50px&quot;}},&quot;i&quot;:0}}]}\">50px</span>"}]]}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"},"sa":{}}'><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/50px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="6" width="50"/></a></span></p> !! end ## Parsoid does not provide editing support for images where templates produce multiple image attributes. @@ -10996,10 +11956,9 @@ Image with multiple attributes from the same template <div class="floatright"><a href="/wiki/File:Foobar.jpg" class="image" title="Caption text"><img alt="Caption text" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a></div> !! html/parsoid -<figure class="mw-default-size mw-halign-right" typeof="mw:Image mw:Placeholder"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"></a><figcaption>Caption text</figcaption></figure> +<figure class="mw-default-size mw-halign-right" typeof="mw:Image mw:Placeholder"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a><figcaption>Caption text</figcaption></figure> !! end -# Parsoid's output here is broken (incorrect p-wrapping); see bug 64901. !! test Image with link tails !! options @@ -11028,9 +11987,9 @@ thumbsize=220 </div> <p>456</p> !! html/parsoid -<p>123<span class="mw-default-size" typeof="mw:Image"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"></a></span>456</p> -123<figure class="mw-default-size mw-halign-right" typeof="mw:Image"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"></a></figure>456 -123<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" height="25" width="220"></a></figure>456 +<p>123<span class="mw-default-size" typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></span>456</p> +<p>123</p><figure class="mw-default-size mw-halign-right" typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></figure><p>456</p> +<p>123</p><figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a></figure><p>456</p> !! end !! test @@ -11041,7 +12000,7 @@ Image with multiple captions -- only last one is accepted <div class="floatright"><a href="/wiki/File:Foobar.jpg" class="image" title="Caption3 - accepted"><img alt="Caption3 - accepted" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a></div> !! html/parsoid -<figure class="mw-default-size mw-halign-right" typeof="mw:Image"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"></a><figcaption>Caption3 - accepted</figcaption></figure> +<figure class="mw-default-size mw-halign-right" typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a><figcaption>Caption3 - accepted</figcaption></figure> !! end !! test @@ -11052,7 +12011,7 @@ Image with multiple widths -- use last <p><a href="/wiki/File:Foobar.jpg" class="image" title="caption"><img alt="caption" src="http://example.com/images/thumb/3/3a/Foobar.jpg/300px-Foobar.jpg" width="300" height="34" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/450px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/600px-Foobar.jpg 2x" /></a> </p> !! html/parsoid -<p><span typeof="mw:Image" data-mw='{"caption":"caption"}'><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="34" width="300"/></a></span></p> +<p><span typeof="mw:Image" data-mw='{"caption":"caption"}'><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="34" width="300"/></a></span></p> !! end !! test @@ -11068,8 +12027,8 @@ thumbsize=220 <p><a href="/wiki/File:Foobar.jpg" class="image" title="caption"><img alt="caption" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" style="vertical-align: middle" /></a> </p> !! html/parsoid -<figure class="mw-default-size mw-halign-left" typeof="mw:Image/Thumb"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="25" width="220"/></a><figcaption>caption</figcaption></figure> -<p><span class="mw-default-size mw-valign-middle" typeof="mw:Image" data-mw='{"caption":"caption"}'><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"/></a></span></p> +<figure class="mw-default-size mw-halign-left" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption>caption</figcaption></figure> +<p><span class="mw-default-size mw-valign-middle" typeof="mw:Image" data-mw='{"caption":"caption"}'><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></span></p> !! end !! test @@ -11084,9 +12043,9 @@ Image with width attribute at different positions <div class="floatright"><a href="/wiki/File:Foobar.jpg" class="image" title="Caption"><img alt="Caption" src="http://example.com/images/thumb/3/3a/Foobar.jpg/200px-Foobar.jpg" width="200" height="23" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/300px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/400px-Foobar.jpg 2x" /></a></div> !! html/parsoid -<figure class="mw-halign-right" typeof="mw:Image"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/200px-Foobar.jpg" height="23" width="200"></a><figcaption>Caption</figcaption></figure> -<figure class="mw-halign-right" typeof="mw:Image"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/200px-Foobar.jpg" height="23" width="200"></a><figcaption>Caption</figcaption></figure> -<figure class="mw-halign-right" typeof="mw:Image"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/200px-Foobar.jpg" height="23" width="200"></a><figcaption>Caption</figcaption></figure> +<figure class="mw-halign-right" typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="23" width="200"/></a><figcaption>Caption</figcaption></figure> +<figure class="mw-halign-right" typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="23" width="200"/></a><figcaption>Caption</figcaption></figure> +<figure class="mw-halign-right" typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="23" width="200"/></a><figcaption>Caption</figcaption></figure> !! end # a sad bit of backward-compatibility @@ -11102,7 +12061,7 @@ parsoid=wt2html,wt2wt,html2html <a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/thumb/3/3a/Foobar.jpg/177px-Foobar.jpg" width="177" height="20" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/265px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/353px-Foobar.jpg 2x" /></a> </p> !! html/parsoid -<p><span typeof="mw:Image"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="2" width="20"/></a></span><span typeof="mw:Image"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="20" width="177"/></a></span></p> +<p><span typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="2" width="20"/></a></span> <span typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="20" width="177"/></a></span></p> !! end !! test @@ -11113,7 +12072,7 @@ Image with link parameter, wiki target <p><a href="/wiki/Main_Page" title="Main Page"><img alt="Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> </p> !! html/parsoid -<p><span class="mw-default-size" typeof="mw:Image"><a href="Main_Page"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"></a></span></p> +<p><span class="mw-default-size" typeof="mw:Image"><a href="Main_Page"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></span></p> !! end # parsoid bug 49293 (part 1) @@ -11125,7 +12084,7 @@ Image with link parameter, URL target <p><a href="http://example.com/" rel="nofollow"><img alt="Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> </p> !! html/parsoid -<p><span class="mw-default-size" typeof="mw:Image"><a href="http://example.com/"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"></a></span></p> +<p><span class="mw-default-size" typeof="mw:Image"><a href="http://example.com/"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></span></p> !! end # parsoid bug 49293 (part 2) @@ -11137,7 +12096,7 @@ Image with link parameter, protocol-less URL target <p><a href="//example.com/" rel="nofollow"><img alt="Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> </p> !! html/parsoid -<p><span class="mw-default-size" typeof="mw:Image"><a href="//example.com/"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"></a></span></p> +<p><span class="mw-default-size" typeof="mw:Image"><a href="//example.com/"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></span></p> !! end !! test @@ -11192,7 +12151,7 @@ Image with empty link parameter <p><img alt="Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /> </p> !! html/parsoid -<p><span class="mw-default-size" typeof="mw:Image"><span><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"></span></span></p> +<p><span class="mw-default-size" typeof="mw:Image"><span><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></span></span></p> !! end !! test @@ -11203,7 +12162,7 @@ Image with link parameter (wiki target) and unnamed parameter <p><a href="/wiki/Main_Page" title="Title"><img alt="Title" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> </p> !! html/parsoid -<p><span class="mw-default-size" typeof="mw:Image" data-mw='{"caption":"Title"}'><a href="Main_Page"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"></a></span></p> +<p><span class="mw-default-size" typeof="mw:Image" data-mw='{"caption":"Title"}'><a href="Main_Page"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></span></p> !! end !! test @@ -11214,7 +12173,7 @@ Image with link parameter (URL target) and unnamed parameter <p><a href="http://example.com/" title="Title" rel="nofollow"><img alt="Title" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> </p> !! html/parsoid -<p><span class="mw-default-size" typeof="mw:Image" data-mw='{"caption":"Title"}'><a href="http://example.com/"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"></a></span></p> +<p><span class="mw-default-size" typeof="mw:Image" data-mw='{"caption":"Title"}'><a href="http://example.com/"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></span></p> !! end !! test @@ -11228,7 +12187,7 @@ parsoid=wt2html,wt2wt,html2html <div class="thumb tright"><div class="thumbinner" style="width:222px;"><a href="http://example.com/"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" width="220" height="25" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/330px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/440px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"></a></div>Title</div></div></div> !! html/parsoid -<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="http://example.com/"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="25" width="220"/></a><figcaption>Title</figcaption></figure> +<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="http://example.com/"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption>Title</figcaption></figure> !! end !! test @@ -11241,7 +12200,7 @@ thumbsize=220 <div class="thumb tright"><div class="thumbinner" style="width:137px;"><a href="/wiki/File:Foobar.jpg"><img alt="" src="http://example.com/images/e/ea/Thumb.png" width="135" height="135" class="thumbimage" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"></a></div>Title</div></div></div> !! html/parsoid -<figure class="mw-default-size" typeof="mw:Image/Thumb" data-mw='{"thumb":"Thumb.png"}'><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/e/ea/Thumb.png" height="135" width="135"/></a><figcaption>Title</figcaption></figure> +<figure class="mw-default-size" typeof="mw:Image/Thumb" data-mw='{"thumb":"Thumb.png"}'><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/e/ea/Thumb.png" data-file-width="135" data-file-height="135" data-file-type="bitmap" height="135" width="135"/></a><figcaption>Title</figcaption></figure> !! end !! test @@ -11255,7 +12214,7 @@ parsoid=wt2html,wt2wt,html2html <div class="thumb tright"><div class="thumbinner" style="width:137px;"><a href="/wiki/Main_Page" title="Main Page"><img alt="" src="http://example.com/images/e/ea/Thumb.png" width="135" height="135" class="thumbimage" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"></a></div>Title</div></div></div> !! html/parsoid -<figure class="mw-default-size" typeof="mw:Image/Thumb" data-mw='{"thumb":"Thumb.png"}'><a href="Main_Page"><img resource="./File:Foobar.jpg" src="//example.com/images/e/ea/Thumb.png" height="135" width="135"/></a><figcaption>Title</figcaption></figure> +<figure class="mw-default-size" typeof="mw:Image/Thumb" data-mw='{"thumb":"Thumb.png"}'><a href="Main_Page"><img resource="./File:Foobar.jpg" src="//example.com/images/e/ea/Thumb.png" data-file-width="135" data-file-height="135" data-file-type="bitmap" height="135" width="135"/></a><figcaption>Title</figcaption></figure> !! end !! test @@ -11269,7 +12228,7 @@ parsoid=wt2html,wt2wt,html2html <div class="thumb tright"><div class="thumbinner" style="width:137px;"><a href="http://example.com"><img alt="" src="http://example.com/images/e/ea/Thumb.png" width="135" height="135" class="thumbimage" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"></a></div>Title</div></div></div> !! html/parsoid -<figure class="mw-default-size" typeof="mw:Image/Thumb" data-mw='{"thumb":"Thumb.png"}'><a href="http://example.com"><img resource="./File:Foobar.jpg" src="//example.com/images/e/ea/Thumb.png" height="135" width="135"/></a><figcaption>Title</figcaption></figure> +<figure class="mw-default-size" typeof="mw:Image/Thumb" data-mw='{"thumb":"Thumb.png"}'><a href="http://example.com"><img resource="./File:Foobar.jpg" src="//example.com/images/e/ea/Thumb.png" data-file-width="135" data-file-height="135" data-file-type="bitmap" height="135" width="135"/></a><figcaption>Title</figcaption></figure> !! end !! test @@ -11283,7 +12242,7 @@ parsoid=wt2html,wt2wt,html2html <div class="thumb tright"><div class="thumbinner" style="width:137px;"><img alt="" src="http://example.com/images/e/ea/Thumb.png" width="135" height="135" class="thumbimage" /> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"></a></div>Title</div></div></div> !! html/parsoid -<figure class="mw-default-size" typeof="mw:Image/Thumb" data-mw='{"thumb":"Thumb.png"}'><span><img resource="./File:Foobar.jpg" src="//example.com/images/e/ea/Thumb.png" height="135" width="135"/></span><figcaption>Title</figcaption></figure> +<figure class="mw-default-size" typeof="mw:Image/Thumb" data-mw='{"thumb":"Thumb.png"}'><span><img resource="./File:Foobar.jpg" src="//example.com/images/e/ea/Thumb.png" data-file-width="135" data-file-height="135" data-file-type="bitmap" height="135" width="135"/></span><figcaption>Title</figcaption></figure> !! end !! test @@ -11297,7 +12256,7 @@ parsoid=wt2html,wt2wt,html2html <div class="thumb tright"><div class="thumbinner" style="width:137px;"><a href="/wiki/Main_Page" title="Main Page"><img alt="alttext" src="http://example.com/images/e/ea/Thumb.png" width="135" height="135" class="thumbimage" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"></a></div>Title</div></div></div> !! html/parsoid -<figure class="mw-default-size" typeof="mw:Image/Thumb" data-mw='{"thumb":"Thumb.png"}'><a href="Main_Page"><img alt="alttext" resource="./File:Foobar.jpg" src="//example.com/images/e/ea/Thumb.png" height="135" width="135"/></a><figcaption>Title</figcaption></figure> +<figure class="mw-default-size" typeof="mw:Image/Thumb" data-mw='{"thumb":"Thumb.png"}'><a href="Main_Page"><img alt="alttext" resource="./File:Foobar.jpg" src="//example.com/images/e/ea/Thumb.png" data-file-width="135" data-file-height="135" data-file-type="bitmap" height="135" width="135"/></a><figcaption>Title</figcaption></figure> !! end !! test @@ -11310,7 +12269,7 @@ parsoid=wt2html,wt2wt,html2html <div class="thumb tleft"><div class="thumbinner" style="width:1943px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" class="thumbimage" /></a> <div class="thumbcaption">This is a test image <a href="/wiki/Main_Page" title="Main Page">Main Page</a></div></div></div> !! html/parsoid -<figure class="mw-default-size mw-halign-left" typeof="mw:Image/Frame"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"/></a><figcaption>This is a test image <a rel="mw:WikiLink" href="Main_Page" title="Main Page">Main Page</a></figcaption></figure> +<figure class="mw-default-size mw-halign-left" typeof="mw:Image/Frame"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a><figcaption>This is a test image <a rel="mw:WikiLink" href="Main_Page" title="Main Page">Main Page</a></figcaption></figure> !! end !! test @@ -11323,7 +12282,7 @@ parsoid=wt2html,wt2wt,html2html <div class="thumb tleft"><div class="thumbinner" style="width:1943px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Altitude" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" class="thumbimage" /></a> <div class="thumbcaption">This is a test image <a href="/wiki/Main_Page" title="Main Page">Main Page</a></div></div></div> !! html/parsoid -<figure class="mw-default-size mw-halign-left" typeof="mw:Image/Frame"><a href="File:Foobar.jpg"><img alt="Altitude" resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"/></a><figcaption>This is a test image <a rel="mw:WikiLink" href="Main_Page" title="Main Page">Main Page</a></figcaption></figure> +<figure class="mw-default-size mw-halign-left" typeof="mw:Image/Frame"><a href="./File:Foobar.jpg"><img alt="Altitude" resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a><figcaption>This is a test image <a rel="mw:WikiLink" href="Main_Page" title="Main Page">Main Page</a></figcaption></figure> !! end !! test @@ -11339,8 +12298,19 @@ parsoid=wt2html,wt2wt,html2html </p><p><a href="/wiki/File:Foobar.jpg" class="image"><img alt="testing bold in alt" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> </p> !! html/parsoid -<p><span class="mw-default-size" typeof="mw:Image" data-mw="{"caption":"testing '''bold''' in alt"}"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"/></a></span></p> -<p><span class="mw-default-size" typeof="mw:Image"><a href="File:Foobar.jpg"><img alt="testing bold in alt" resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"/></a></span></p> +<p><span class="mw-default-size" typeof="mw:Image" data-mw="{"caption":"testing '''bold''' in alt"}"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></span></p> +<p><span class="mw-default-size" typeof="mw:Image"><a href="./File:Foobar.jpg"><img alt="testing bold in alt" resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></span></p> +!! end + +!! test +Alt image option should handle most kinds of wikitext without barfing +!! wikitext +[[Image:Foobar.jpg|thumb|This is the image caption|alt=This is a [[link]] and a {{echo|''bold template''}}.]] +!! html/php +<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="This is a link and a bold template." src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/270px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/360px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"></a></div>This is the image caption</div></div></div> + +!! html/parsoid +<figure class="mw-default-size" typeof="mw:Image/Thumb mw:ExpandedAttrs" about="#mwt2" data-parsoid='{"optList":[{"ck":"thumbnail","ak":"thumb"},{"ck":"caption","ak":"This is the image caption"},{"ck":"alt","ak":"alt=This is a [[link]] and a {{echo|''bold template''}}."}]}' data-mw='{"attribs":[["thumbnail",{"html":"thumb"}],["alt",{"html":"alt=This is a <a rel=\"mw:WikiLink\" href=\"./Link\" title=\"Link\" data-parsoid=\"{&quot;stx&quot;:&quot;simple&quot;,&quot;a&quot;:{&quot;href&quot;:&quot;./Link&quot;},&quot;sa&quot;:{&quot;href&quot;:&quot;link&quot;},&quot;dsr&quot;:[65,73,2,2]}\">link</a> and a <i about=\"#mwt1\" typeof=\"mw:Transclusion\" data-parsoid=\"{&quot;dsr&quot;:[80,106,null,null],&quot;pi&quot;:[[{&quot;k&quot;:&quot;1&quot;,&quot;spc&quot;:[&quot;&quot;,&quot;&quot;,&quot;&quot;,&quot;&quot;]}]]}\" data-mw=\"{&quot;parts&quot;:[{&quot;template&quot;:{&quot;target&quot;:{&quot;wt&quot;:&quot;echo&quot;,&quot;href&quot;:&quot;./Template:Echo&quot;},&quot;params&quot;:{&quot;1&quot;:{&quot;wt&quot;:&quot;''bold template''&quot;}},&quot;i&quot;:0}}]}\">bold template</i>."}]]}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"},"sa":{}}'><img alt="This is a link and a bold template." resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220" data-parsoid='{"a":{"alt":"This is a link and a bold template.","resource":"./File:Foobar.jpg","height":"25","width":"220"},"sa":{"alt":"alt=This is a [[link]] and a {{echo|''bold template''}}.","resource":"Image:Foobar.jpg"}}'/></a><figcaption>This is the image caption</figcaption></figure> !! end ################### @@ -11364,9 +12334,9 @@ parsoid=wt2html,wt2wt,html2html </p><p><a href="/wiki/File:Foobar.jpg" class="image" title="caption"><img alt="caption" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/270px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/360px-Foobar.jpg 2x" /></a> </p> !! html/parsoid -<p><span class="mw-default-size" typeof="mw:Image/Frameless" data-mw='{"caption":"caption"}'><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="25" width="220"/></a></span></p> -<p><span class="mw-default-size" typeof="mw:Image/Frameless" data-mw='{"caption":"caption"}'><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="25" width="220"/></a></span></p> -<p><span class="mw-default-size" typeof="mw:Image/Frameless" data-mw='{"caption":"caption"}'><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="25" width="220"/></a></span></p> +<p><span class="mw-default-size" typeof="mw:Image/Frameless" data-mw='{"caption":"caption"}'><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a></span></p> +<p><span class="mw-default-size" typeof="mw:Image/Frameless" data-mw='{"caption":"caption"}'><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a></span></p> +<p><span class="mw-default-size" typeof="mw:Image/Frameless" data-mw='{"caption":"caption"}'><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a></span></p> !! end !! test @@ -11383,7 +12353,9 @@ parsoid=wt2html,wt2wt,html2html <div class="thumb tright"><div class="thumbinner" style="width:1943px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" class="thumbimage" /></a> <div class="thumbcaption">caption</div></div></div> !! html/parsoid -<figure class="mw-default-size" typeof="mw:Image/Frame"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"/></a><figcaption>caption</figcaption></figure><figure class="mw-default-size" typeof="mw:Image/Frame"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"/></a><figcaption>caption</figcaption></figure><figure class="mw-default-size" typeof="mw:Image/Frame"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"/></a><figcaption>caption</figcaption></figure> +<figure class="mw-default-size" typeof="mw:Image/Frame"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a><figcaption>caption</figcaption></figure> +<figure class="mw-default-size" typeof="mw:Image/Frame"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a><figcaption>caption</figcaption></figure> +<figure class="mw-default-size" typeof="mw:Image/Frame"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a><figcaption>caption</figcaption></figure> !! end !! test @@ -11400,7 +12372,9 @@ parsoid=wt2html,wt2wt,html2html <div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/270px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/360px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"></a></div>caption</div></div></div> !! html/parsoid -<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="25" width="220"/></a><figcaption>caption</figcaption></figure><figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="25" width="220"/></a><figcaption>caption</figcaption></figure><figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="25" width="220"/></a><figcaption>caption</figcaption></figure> +<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption>caption</figcaption></figure> +<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption>caption</figcaption></figure> +<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption>caption</figcaption></figure> !! end ################### @@ -11427,8 +12401,8 @@ parsoid=wt2html,wt2wt,html2html </p><p><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="2000" height="227" class="thumbborder" /></a> </p> !! html/parsoid -<p><span typeof="mw:Image"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="227" width="2000"/></a></span></p> -<p><span class="mw-image-border" typeof="mw:Image"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="227" width="2000"/></a></span></p> +<p><span typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="227" width="2000"/></a></span></p> +<p><span class="mw-image-border" typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="227" width="2000"/></a></span></p> !! end !! test @@ -11444,8 +12418,8 @@ parsoid=wt2html,wt2wt,html2html </p><p><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/thumb/3/3a/Foobar.jpg/1000px-Foobar.jpg" width="1000" height="113" class="thumbborder" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/1500px-Foobar.jpg 1.5x, http://example.com/images/3/3a/Foobar.jpg 2x" /></a> </p> !! html/parsoid -<p><span typeof="mw:Image"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="113" width="1000"/></a></span></p> -<p><span class="mw-image-border" typeof="mw:Image"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="113" width="1000"/></a></span></p> +<p><span typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="113" width="1000"/></a></span></p> +<p><span class="mw-image-border" typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="113" width="1000"/></a></span></p> !! end !! test @@ -11458,7 +12432,7 @@ parsoid=wt2html,wt2wt,html2html <div class="thumb tright"><div class="thumbinner" style="width:52px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/thumb/3/3a/Foobar.jpg/50px-Foobar.jpg" width="50" height="6" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/75px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/100px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"></a></div></div></div></div> !! html/parsoid -<figure typeof="mw:Image/Thumb"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="6" width="50"/></a></figure> +<figure typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="6" width="50"/></a></figure> !! end !! test @@ -11474,8 +12448,8 @@ parsoid=wt2html,wt2wt,html2html <div class="thumb tright"><div class="thumbinner" style="width:2002px;"><a href="/wiki/File:Foobar.svg" class="image"><img alt="Foobar.svg" src="http://example.com/images/thumb/f/ff/Foobar.svg/2000px-Foobar.svg.png" width="2000" height="1500" class="thumbimage" srcset="http://example.com/images/thumb/f/ff/Foobar.svg/3000px-Foobar.svg.png 1.5x, http://example.com/images/thumb/f/ff/Foobar.svg/4000px-Foobar.svg.png 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.svg" class="internal" title="Enlarge"></a></div></div></div></div> !! html/parsoid -<figure typeof="mw:Image/Thumb"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"/></a></figure> -<figure typeof="mw:Image/Thumb"><a href="File:Foobar.svg"><img resource="./File:Foobar.svg" src="//example.com/images/f/ff/Foobar.svg" height="1500" width="2000"/></a></figure> +<figure typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></figure> +<figure typeof="mw:Image/Thumb"><a href="./File:Foobar.svg"><img resource="./File:Foobar.svg" src="//example.com/images/f/ff/Foobar.svg" data-file-width="240" data-file-height="180" data-file-type="drawing" height="1500" width="2000"/></a></figure> !! end !! test @@ -11488,7 +12462,7 @@ parsoid=wt2html,wt2wt,html2html <p><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/thumb/3/3a/Foobar.jpg/50px-Foobar.jpg" width="50" height="6" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/75px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/100px-Foobar.jpg 2x" /></a> </p> !! html/parsoid -<p><span typeof="mw:Image/Frameless"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="6" width="50"/></a></span></p> +<p><span typeof="mw:Image/Frameless"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="6" width="50"/></a></span></p> !! end !! test @@ -11504,8 +12478,8 @@ parsoid=wt2html,wt2wt,html2html </p><p><a href="/wiki/File:Foobar.svg" class="image"><img alt="Foobar.svg" src="http://example.com/images/thumb/f/ff/Foobar.svg/2000px-Foobar.svg.png" width="2000" height="1500" srcset="http://example.com/images/thumb/f/ff/Foobar.svg/3000px-Foobar.svg.png 1.5x, http://example.com/images/thumb/f/ff/Foobar.svg/4000px-Foobar.svg.png 2x" /></a> </p> !! html/parsoid -<p><span typeof="mw:Image/Frameless"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"/></a></span></p> -<p><span typeof="mw:Image/Frameless"><a href="File:Foobar.svg"><img resource="./File:Foobar.svg" src="//example.com/images/f/ff/Foobar.svg" height="1500" width="2000"/></a></span></p> +<p><span typeof="mw:Image/Frameless"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></span></p> +<p><span typeof="mw:Image/Frameless"><a href="./File:Foobar.svg"><img resource="./File:Foobar.svg" src="//example.com/images/f/ff/Foobar.svg" data-file-width="240" data-file-height="180" data-file-type="drawing" height="1500" width="2000"/></a></span></p> !! end !! test @@ -11527,7 +12501,10 @@ parsoid=wt2html,wt2wt,html2html <div class="thumb tright"><div class="thumbinner" style="width:1943px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" class="thumbimage" /></a> <div class="thumbcaption"></div></div></div> !! html/parsoid -<figure class="mw-default-size" typeof="mw:Image/Frame"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"/></a></figure><figure typeof="mw:Image/Frame"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"/></a></figure><figure typeof="mw:Image/Frame"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"/></a></figure><figure typeof="mw:Image/Frame"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"/></a></figure> +<figure class="mw-default-size" typeof="mw:Image/Frame"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></figure> +<figure typeof="mw:Image/Frame"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></figure> +<figure typeof="mw:Image/Frame"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></figure> +<figure typeof="mw:Image/Frame"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></figure> !! end ################### @@ -11560,7 +12537,7 @@ Frameless image caption with a free URL <p><a href="/wiki/File:Foobar.jpg" class="image" title="http://example.com"><img alt="http://example.com" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> </p> !! html/parsoid -<p><span class="mw-default-size" typeof="mw:Image" data-mw='{"caption":"http://example.com"}'><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"/></a></span></p> +<p><span class="mw-default-size" typeof="mw:Image" data-mw='{"caption":"http://example.com"}'><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></span></p> !! end !! test @@ -11573,7 +12550,7 @@ thumbsize=220 <div class="thumb tright"><div class="thumbinner" style="width:222px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" width="220" height="25" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/330px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/440px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"></a></div><a rel="nofollow" class="external free" href="http://example.com">http://example.com</a></div></div></div> !! html/parsoid -<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="25" width="220"/></a><figcaption><a rel="mw:ExtLink" href="http://example.com">http://example.com</a></figcaption></figure> +<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption><a rel="mw:ExtLink" href="http://example.com">http://example.com</a></figcaption></figure> !! end !! test @@ -11587,7 +12564,7 @@ parsoid=wt2html,wt2wt,html2html <div class="thumb tright"><div class="thumbinner" style="width:222px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Alteration" src="http://example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" width="220" height="25" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/330px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/440px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"></a></div><a rel="nofollow" class="external free" href="http://example.com">http://example.com</a></div></div></div> !! html/parsoid -<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="File:Foobar.jpg"><img alt="Alteration" resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="25" width="220"/></a><figcaption><a rel="mw:ExtLink" href="http://example.com">http://example.com</a></figcaption></figure> +<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img alt="Alteration" resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption><a rel="mw:ExtLink" href="http://example.com">http://example.com</a></figcaption></figure> !! end !! test @@ -11599,7 +12576,7 @@ SVG thumbnails with no language set <div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.svg" class="image"><img alt="" src="http://example.com/images/thumb/f/ff/Foobar.svg/180px-Foobar.svg.png" width="180" height="135" class="thumbimage" srcset="http://example.com/images/thumb/f/ff/Foobar.svg/270px-Foobar.svg.png 1.5x, http://example.com/images/thumb/f/ff/Foobar.svg/360px-Foobar.svg.png 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.svg" class="internal" title="Enlarge"></a></div>caption</div></div></div> !! html/parsoid -<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="File:Foobar.svg"><img resource="./File:Foobar.svg" src="//example.com/images/f/ff/Foobar.svg" height="165" width="220"/></a><figcaption>caption</figcaption></figure> +<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="./File:Foobar.svg"><img resource="./File:Foobar.svg" src="//example.com/images/f/ff/Foobar.svg" data-file-width="240" data-file-height="180" data-file-type="drawing" height="165" width="220"/></a><figcaption>caption</figcaption></figure> !! end !! test @@ -11612,7 +12589,7 @@ parsoid=wt2html,wt2wt,html2html <div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/index.php?title=File:Foobar.svg&lang=de" class="image"><img alt="" src="http://example.com/images/thumb/f/ff/Foobar.svg/langde-180px-Foobar.svg.png" width="180" height="135" class="thumbimage" srcset="http://example.com/images/thumb/f/ff/Foobar.svg/langde-270px-Foobar.svg.png 1.5x, http://example.com/images/thumb/f/ff/Foobar.svg/langde-360px-Foobar.svg.png 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.svg" class="internal" title="Enlarge"></a></div>caption</div></div></div> !! html/parsoid -<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="File:Foobar.svg"><img resource="./File:Foobar.svg" src="//example.com/images/f/ff/Foobar.svg" lang="de" height="165" width="220"/></a><figcaption>caption</figcaption></figure> +<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="./File:Foobar.svg"><img resource="./File:Foobar.svg" src="//example.com/images/f/ff/Foobar.svg" lang="de" data-file-width="240" data-file-height="180" data-file-type="drawing" height="165" width="220"/></a><figcaption>caption</figcaption></figure> !! end !! test @@ -11625,7 +12602,7 @@ parsoid=wt2html,wt2wt,html2html <div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.svg" class="image"><img alt="" src="http://example.com/images/thumb/f/ff/Foobar.svg/180px-Foobar.svg.png" width="180" height="135" class="thumbimage" srcset="http://example.com/images/thumb/f/ff/Foobar.svg/270px-Foobar.svg.png 1.5x, http://example.com/images/thumb/f/ff/Foobar.svg/360px-Foobar.svg.png 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.svg" class="internal" title="Enlarge"></a></div>lang=invalid.language.code</div></div></div> !! html/parsoid -<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="File:Foobar.svg"><img resource="./File:Foobar.svg" src="//example.com/images/f/ff/Foobar.svg" height="165" width="220"/></a><figcaption>lang=invalid.language.code</figcaption></figure> +<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="./File:Foobar.svg"><img resource="./File:Foobar.svg" src="//example.com/images/f/ff/Foobar.svg" data-file-width="240" data-file-height="180" data-file-type="drawing" height="165" width="220"/></a><figcaption>lang=invalid.language.code</figcaption></figure> !! end !! test @@ -11636,7 +12613,7 @@ BUG 1887: A ISBN with a thumbnail <div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/270px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/360px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"></a></div><a href="/wiki/Special:BookSources/1235467890" class="internal mw-magiclink-isbn">ISBN 1235467890</a></div></div></div> !! html/parsoid -<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="25" width="220"/></a><figcaption><a href="Special:BookSources/1235467890" rel="mw:ExtLink">ISBN 1235467890</a></figcaption></figure> +<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption><a href="Special:BookSources/1235467890" rel="mw:ExtLink">ISBN 1235467890</a></figcaption></figure> !! end !! test @@ -11647,7 +12624,7 @@ BUG 1887: A RFC with a thumbnail <div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/270px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/360px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"></a></div>This is <a class="external mw-magiclink-rfc" rel="nofollow" href="//tools.ietf.org/html/rfc12354">RFC 12354</a></div></div></div> !! html/parsoid -<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="25" width="220"/></a><figcaption>This is <a href="//tools.ietf.org/html/rfc12354" rel="mw:ExtLink">RFC 12354</a></figcaption></figure> +<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption>This is <a href="//tools.ietf.org/html/rfc12354" rel="mw:ExtLink">RFC 12354</a></figcaption></figure> !! end !! test @@ -11658,7 +12635,7 @@ BUG 1887: A mailto link with a thumbnail <div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/270px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/360px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"></a></div>Please <a rel="nofollow" class="external free" href="mailto:nobody@example.com">mailto:nobody@example.com</a></div></div></div> !! html/parsoid -<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="25" width="220"/></a><figcaption>Please <a rel="mw:ExtLink" href="mailto:nobody@example.com">mailto:nobody@example.com</a></figcaption></figure> +<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption>Please <a rel="mw:ExtLink" href="mailto:nobody@example.com">mailto:nobody@example.com</a></figcaption></figure> !! end # Pending resolution to bug 368 @@ -11670,7 +12647,7 @@ BUG 648: Frameless image caption with a link <p><a href="/wiki/File:Foobar.jpg" class="image" title="text with a link in it"><img alt="text with a link in it" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> </p> !! html/parsoid -<p><span class="mw-default-size" typeof="mw:Image" data-mw='{"caption":"text with a [[link]] in it"}'><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"/></a></span></p> +<p><span class="mw-default-size" typeof="mw:Image" data-mw='{"caption":"text with a [[link]] in it"}'><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></span></p> !! end !! test @@ -11681,7 +12658,7 @@ BUG 648: Frameless image caption with a link (suffix) <p><a href="/wiki/File:Foobar.jpg" class="image" title="text with a linkfoo in it"><img alt="text with a linkfoo in it" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> </p> !! html/parsoid -<p><span class="mw-default-size" typeof="mw:Image" data-mw='{"caption":"text with a [[link]]foo in it"}'><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"/></a></span></p> +<p><span class="mw-default-size" typeof="mw:Image" data-mw='{"caption":"text with a [[link]]foo in it"}'><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></span></p> !! end !! test @@ -11692,7 +12669,7 @@ BUG 648: Frameless image caption with an interwiki link <p><a href="/wiki/File:Foobar.jpg" class="image" title="text with a MeatBall:Link in it"><img alt="text with a MeatBall:Link in it" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> </p> !! html/parsoid -<p><span class="mw-default-size" typeof="mw:Image" data-mw='{"caption":"text with a [[MeatBall:Link]] in it"}'><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"/></a></span></p> +<p><span class="mw-default-size" typeof="mw:Image" data-mw='{"caption":"text with a [[MeatBall:Link]] in it"}'><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></span></p> !! end !! test @@ -11703,7 +12680,7 @@ BUG 648: Frameless image caption with a piped interwiki link <p><a href="/wiki/File:Foobar.jpg" class="image" title="text with a link in it"><img alt="text with a link in it" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> </p> !! html/parsoid -<p><span class="mw-default-size" typeof="mw:Image" data-mw='{"caption":"text with a [[MeatBall:Link|link]] in it"}'><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"/></a></span></p> +<p><span class="mw-default-size" typeof="mw:Image" data-mw='{"caption":"text with a [[MeatBall:Link|link]] in it"}'><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></span></p> !! end !! test @@ -11714,7 +12691,7 @@ Escape HTML special chars in image alt text <p><a href="/wiki/File:Foobar.jpg" class="image" title="& < > ""><img alt="& < > "" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> </p> !! html/parsoid -<p><span class="mw-default-size" typeof="mw:Image" data-mw='{"caption":"& < > \""}'><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"/></a></span></p> +<p><span class="mw-default-size" typeof="mw:Image" data-mw='{"caption":"& < > \""}'><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></span></p> !! end !! test @@ -11725,7 +12702,7 @@ BUG 499: Alt text should have Ӓ, not &1234; <p><a href="/wiki/File:Foobar.jpg" class="image" title="♀"><img alt="♀" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> </p> !! html/parsoid -<p><span class="mw-default-size" typeof="mw:Image" data-mw='{"caption":"&#9792;"}'><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"/></a></span></p> +<p><span class="mw-default-size" typeof="mw:Image" data-mw='{"caption":"&#9792;"}'><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></span></p> !! end !! test @@ -11749,7 +12726,7 @@ Image caption containing another image <div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/270px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/360px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"></a></div>This is a caption with another <a href="/wiki/File:Thumb.png" class="image" title="image"><img alt="image" src="http://example.com/images/e/ea/Thumb.png" width="135" height="135" /></a> inside it!</div></div></div> !! html/parsoid -<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="25" width="220"/></a><figcaption>This is a caption with another <span class="mw-default-size" typeof="mw:Image" data-mw='{"caption":"image"}'><a href="File:Thumb.png"><img resource="./File:Thumb.png" src="//example.com/images/e/ea/Thumb.png" height="135" width="135"/></a></span> inside it!</figcaption></figure> +<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption>This is a caption with another <span class="mw-default-size" typeof="mw:Image" data-mw='{"caption":"image"}'><a href="./File:Thumb.png"><img resource="./File:Thumb.png" src="//example.com/images/e/ea/Thumb.png" data-file-width="135" data-file-height="135" data-file-type="bitmap" height="135" width="135"/></a></span> inside it!</figcaption></figure> !! end !! test @@ -11761,7 +12738,7 @@ Image: caption containing a newline <p><a href="/wiki/File:Foobar.jpg" class="image" title="This *is some text"><img alt="This *is some text" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> </p> !! html/parsoid -<p><span class="mw-default-size" typeof="mw:Image" data-mw='{"caption":"This\n*is some text"}'><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"/></a></span></p> +<p><span class="mw-default-size" typeof="mw:Image" data-mw='{"caption":"This\n*is some text"}'><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></span></p> !!end !!test @@ -11773,7 +12750,7 @@ Image: caption containing leading space <div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/270px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/360px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"></a></div>bar</div></div></div> !! html/parsoid -<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="25" width="220"/></a><figcaption> bar</figcaption></figure> +<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption> bar</figcaption></figure> !!end !! test @@ -11792,7 +12769,7 @@ and some more text.]] <div class="thumb tright"><div class="thumbinner" style="width:202px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/200px-Foobar.jpg" width="200" height="23" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/300px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/400px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"></a></div>This is an example image thumbnail caption with a table <table> <tr> <th> Foo </th> <th> Bar </th></tr> <tr> <td> Foo1 </td> <td> Bar1 </td></tr></table> and some more text.</div></div></div> !! html/parsoid -<figure typeof="mw:Image/Thumb"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="23" width="200"/></a><figcaption>This is an example image thumbnail caption with a table +<figure typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="23" width="200"/></a><figcaption>This is an example image thumbnail caption with a table <table> <tbody> <tr><th>Foo </th><th>Bar</th></tr> @@ -11809,7 +12786,7 @@ Bug 3090: External links other than http: in image captions <div class="thumb tright"><div class="thumbinner" style="width:202px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/200px-Foobar.jpg" width="200" height="23" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/300px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/400px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"></a></div>This caption has <a rel="nofollow" class="external text" href="irc://example.net">irc</a> and <a rel="nofollow" class="external text" href="https://example.com">Secure</a> ext links in it.</div></div></div> !! html/parsoid -<figure typeof="mw:Image/Thumb"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="23" width="200"/></a><figcaption>This caption has <a rel="mw:ExtLink" href="irc://example.net">irc</a> and <a rel="mw:ExtLink" href="https://example.com">Secure</a> ext links in it.</figcaption></figure> +<figure typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="23" width="200"/></a><figcaption>This caption has <a rel="mw:ExtLink" href="irc://example.net">irc</a> and <a rel="mw:ExtLink" href="https://example.com">Secure</a> ext links in it.</figcaption></figure> !! end !! test @@ -11822,7 +12799,7 @@ parsoid=wt2html,wt2wt,html2html <p><a href="/wiki/File:Foobar.jpg" class="image" title="a"><img alt="a" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" class="b" /></a> </p> !! html/parsoid -<p><span class="mw-default-size b" typeof="mw:Image" data-mw='{"caption":"a"}'><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"/></a></span></p> +<p><span class="mw-default-size b" typeof="mw:Image" data-mw='{"caption":"a"}'><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></span></p> !! end !! test @@ -11836,7 +12813,7 @@ language=es <div class="floatleft"><a href="/wiki/Foo" title="caption"><img alt="caption" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a></div> !! html/parsoid -<figure class="mw-default-size mw-halign-left" typeof="mw:Image"><a href="./Foo"><img resource="./Archivo:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"/></a><figcaption>caption</figcaption></figure> +<figure class="mw-default-size mw-halign-left" typeof="mw:Image"><a href="./Foo"><img resource="./Archivo:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a><figcaption>caption</figcaption></figure> !! end !! test @@ -11851,7 +12828,7 @@ language=es <div class="thumb tleft"><div class="thumbinner" style="width:222px;"><a href="/wiki/Foo" title="Foo"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" width="220" height="25" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/330px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/440px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/Archivo:Foobar.jpg" class="internal" title="Aumentar"></a></div>caption</div></div></div> !! html/parsoid -<figure class="mw-default-size mw-halign-left" typeof="mw:Image/Thumb"><a href="./Foo"><img resource="./Archivo:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="25" width="220"/></a><figcaption>caption</figcaption></figure> +<figure class="mw-default-size mw-halign-left" typeof="mw:Image/Thumb"><a href="./Foo"><img resource="./Archivo:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption>caption</figcaption></figure> !! end !! test @@ -11865,7 +12842,7 @@ parsoid=wt2html,wt2wt,html2html <p><a href="/wiki/File:Foobar.jpg" class="image" title="caption"><img alt="caption" src="http://example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" width="220" height="25" class="extra thumbborder" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/330px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/440px-Foobar.jpg 2x" /></a> </p> !! html/parsoid -<p><span class="mw-default-size mw-image-border extra" typeof="mw:Image/Frameless" data-mw='{"caption":"caption"}'><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="25" width="220"/></a></span></p> +<p><span class="mw-default-size mw-image-border extra" typeof="mw:Image/Frameless" data-mw='{"caption":"caption"}'><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a></span></p> !! end # Note that 'right' is the default alignment, despite the misspelled 'righ' below @@ -11886,7 +12863,9 @@ parsoid=wt2html,wt2wt,html2html <div class="thumb tleft"><div class="thumbinner" style="width:222px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" width="220" height="25" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/330px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/440px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"></a></div>caption</div></div></div> !! html/parsoid -<figure class="mw-default-size mw-halign-left" typeof="mw:Image/Thumb"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="25" width="220"/></a><figcaption>caption</figcaption></figure><figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="25" width="220"/></a><figcaption>caption</figcaption></figure><figure class="mw-default-size mw-halign-left" typeof="mw:Image/Thumb"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="25" width="220"/></a><figcaption>caption</figcaption></figure> +<figure class="mw-default-size mw-halign-left" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption>caption</figcaption></figure> +<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption>caption</figcaption></figure> +<figure class="mw-default-size mw-halign-left" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption>caption</figcaption></figure> !! end !! article @@ -11895,11 +12874,13 @@ File:Barfoo.jpg #REDIRECT [[File:Barfoo.jpg]] !! endarticle +# FIXME: Parsoid should run this test -- but we'd need to teach the +# mockAPI about the redirected Barfoo.jpg image. !! test Redirected image !! wikitext [[Image:Barfoo.jpg]] -!! html +!! html/php <p><a href="/wiki/File:Barfoo.jpg" title="File:Barfoo.jpg">File:Barfoo.jpg</a> </p> !! end @@ -11909,10 +12890,12 @@ Missing image with uploads disabled !! options wgEnableUploads=0 !! wikitext -[[Image:Foobaz.jpg]] -!! html +[[File:Foobaz.jpg]] +!! html/php <p><a href="/wiki/File:Foobaz.jpg" title="File:Foobaz.jpg">File:Foobaz.jpg</a> </p> +!! html/parsoid +<p><span class="mw-default-size" typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}]}'><a href="./File:Foobaz.jpg"><img resource="./File:Foobaz.jpg" src="./Special:FilePath/Foobaz.jpg" height="220" width="220"/></a></span></p> !! end # Parsoid-specific testing for images @@ -11927,12 +12910,7 @@ Parsoid-specific image handling - simple image with size and middle alignment !! wikitext [[File:Foobar.jpg|middle|50px]] !! html/parsoid -<p><span class="mw-valign-middle" typeof="mw:Image"> -<a href="File:Foobar.jpg"> -<img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/50px-Foobar.jpg" height="6" width="50"> -</a> -</span> -</p> +<p><span class="mw-valign-middle" typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="6" width="50"/></a></span></p> !! end !! test @@ -11943,12 +12921,7 @@ parsoid=wt2wt,wt2html,html2html !! wikitext [[Image:Foobar.jpg|middle|50px]] !! html/parsoid -<p><span class="mw-valign-middle" typeof="mw:Image"> -<a href="File:Foobar.jpg"> -<img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/50px-Foobar.jpg" height="6" width="50"> -</a> -</span> -</p> +<p><span class="mw-valign-middle" typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="6" width="50"/></a></span></p> !! end !! test @@ -11957,7 +12930,7 @@ Parsoid-specific image handling - simple image with size and middle alignment !! wikitext [[File:Foobar.jpg|50px|middle]] !! html/parsoid -<p><span class="mw-valign-middle" typeof="mw:Image" data-parsoid='{"optList":[{"ck":"width","ak":"50px"},{"ck":"middle","ak":"middle"}]}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"}}'><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/50px-Foobar.jpg" height="6" width="50" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"6","width":"50"},"sa":{"resource":"File:Foobar.jpg"}}'/></a></span></p> +<p><span class="mw-valign-middle" typeof="mw:Image" data-parsoid='{"optList":[{"ck":"width","ak":"50px"},{"ck":"middle","ak":"middle"}]}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"}}'><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="6" width="50" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"6","width":"50"},"sa":{"resource":"File:Foobar.jpg"}}'/></a></span></p> !! end !! test @@ -11968,12 +12941,7 @@ parsoid=wt2html,wt2wt,html2html !! wikitext [[Image:Foobar.jpg|50px|middle]] !! html/parsoid -<p><span class="mw-valign-middle" typeof="mw:Image"> -<a href="File:Foobar.jpg"> -<img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/50px-Foobar.jpg" height="6" width="50"> -</a> -</span> -</p> +<p><span class="mw-valign-middle" typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="6" width="50"/></a></span></p> !! end !! test @@ -11981,7 +12949,7 @@ Parsoid-specific image handling - simple image with both sizes, a baseline align !! wikitext [[File:Foobar.jpg|500x10px|baseline|caption]] !! html/parsoid -<p><span class="mw-valign-baseline" typeof="mw:Image" data-mw='{"caption":"caption"}' data-parsoid='{"optList":[{"ck":"width","ak":"500x10px"},{"ck":"baseline","ak":"baseline"},{"ck":"caption","ak":"caption"}],"size":"500x10"}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"}}'><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/89px-Foobar.jpg" height="10" width="89" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"10","width":"89"},"sa":{"resource":"File:Foobar.jpg"}}'/></a></span></p> +<p><span class="mw-valign-baseline" typeof="mw:Image" data-mw='{"caption":"caption"}' data-parsoid='{"optList":[{"ck":"width","ak":"500x10px"},{"ck":"baseline","ak":"baseline"},{"ck":"caption","ak":"caption"}],"size":"500x10"}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"}}'><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/89px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="10" width="89" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"10","width":"89"},"sa":{"resource":"File:Foobar.jpg"}}'/></a></span></p> !! end !! test @@ -11989,7 +12957,7 @@ Parsoid-specific image handling - simple image with border and size spec !! wikitext [[File:Foobar.jpg|50px|border|caption]] !! html/parsoid -<p><span class="mw-image-border" typeof="mw:Image" data-mw='{"caption":"caption"}' data-parsoid='{"optList":[{"ck":"width","ak":"50px"},{"ck":"border","ak":"border"},{"ck":"caption","ak":"caption"}]}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"}}'><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/50px-Foobar.jpg" height="6" width="50" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"6","width":"50"},"sa":{"resource":"File:Foobar.jpg"}}'/></a></span></p> +<p><span class="mw-image-border" typeof="mw:Image" data-mw='{"caption":"caption"}' data-parsoid='{"optList":[{"ck":"width","ak":"50px"},{"ck":"border","ak":"border"},{"ck":"caption","ak":"caption"}]}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"}}'><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/50px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="6" width="50" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"6","width":"50"},"sa":{"resource":"File:Foobar.jpg"}}'/></a></span></p> !! end !! test @@ -11997,12 +12965,7 @@ Parsoid-specific image handling - thumbnail with halign, valign, and caption !! wikitext [[File:Foobar.jpg|left|baseline|thumb|caption content]] !! html/parsoid -<figure class="mw-default-size mw-halign-left mw-valign-baseline" typeof="mw:Image/Thumb"> -<a href="File:Foobar.jpg"> -<img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" height="25" width="220" /> -</a> -<figcaption>caption content</figcaption> -</figure> +<figure class="mw-default-size mw-halign-left mw-valign-baseline" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption>caption content</figcaption></figure> !! end !! test @@ -12011,7 +12974,7 @@ Parsoid-specific image handling - thumbnail with halign, valign, and caption !! wikitext [[File:Foobar.jpg|thumb|left|baseline|caption content]] !! html/parsoid -<figure class="mw-default-size mw-halign-left mw-valign-baseline" typeof="mw:Image/Thumb" data-parsoid='{"optList":[{"ck":"thumbnail","ak":"thumb"},{"ck":"left","ak":"left"},{"ck":"baseline","ak":"baseline"},{"ck":"caption","ak":"caption content"}]}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"}}'><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" height="25" width="220" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"25","width":"220"},"sa":{"resource":"File:Foobar.jpg"}}'/></a><figcaption>caption content</figcaption></figure> +<figure class="mw-default-size mw-halign-left mw-valign-baseline" typeof="mw:Image/Thumb" data-parsoid='{"optList":[{"ck":"thumbnail","ak":"thumb"},{"ck":"left","ak":"left"},{"ck":"baseline","ak":"baseline"},{"ck":"caption","ak":"caption content"}]}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"}}'><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"25","width":"220"},"sa":{"resource":"File:Foobar.jpg"}}'/></a><figcaption>caption content</figcaption></figure> !! end !! test @@ -12019,12 +12982,7 @@ Parsoid-specific image handling - thumbnail with specific size, halign, valign, !! wikitext [[Image:Foobar.jpg|right|middle|thumb|50x50px|caption]] !! html/parsoid -<figure class="mw-halign-right mw-valign-middle" typeof="mw:Image/Thumb"> -<a href="File:Foobar.jpg"> -<img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/50px-Foobar.jpg" height="6" width="50" /> -</a> -<figcaption>caption</figcaption> -</figure> +<figure class="mw-halign-right mw-valign-middle" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="6" width="50"/></a><figcaption>caption</figcaption></figure> !! end !! test @@ -12033,7 +12991,7 @@ valign, and caption (existing content) !! wikitext [[File:Foobar.jpg|thumb|50x50px|right|middle|caption]] !! html/parsoid -<figure class="mw-halign-right mw-valign-middle" typeof="mw:Image/Thumb" data-parsoid='{"optList":[{"ck":"thumbnail","ak":"thumb"},{"ck":"width","ak":"50x50px"},{"ck":"right","ak":"right"},{"ck":"middle","ak":"middle"},{"ck":"caption","ak":"caption"}],"size":"50x50"}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"}}'><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/50px-Foobar.jpg" height="6" width="50" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"6","width":"50"},"sa":{"resource":"File:Foobar.jpg"}}'/></a><figcaption>caption</figcaption></figure> +<figure class="mw-halign-right mw-valign-middle" typeof="mw:Image/Thumb" data-parsoid='{"optList":[{"ck":"thumbnail","ak":"thumb"},{"ck":"width","ak":"50x50px"},{"ck":"right","ak":"right"},{"ck":"middle","ak":"middle"},{"ck":"caption","ak":"caption"}],"size":"50x50"}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"}}'><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/50px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="6" width="50" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"6","width":"50"},"sa":{"resource":"File:Foobar.jpg"}}'/></a><figcaption>caption</figcaption></figure> !! end !! test @@ -12044,12 +13002,7 @@ parsoid=wt2html,wt2wt,html2html !! wikitext [[File:Foobar.jpg|frame|500x50px|caption]] !! html/parsoid -<figure typeof="mw:Image/Frame"> -<a href="File:Foobar.jpg"> -<img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941" /> -</a> -<figcaption>caption</figcaption> -</figure> +<figure typeof="mw:Image/Frame"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a><figcaption>caption</figcaption></figure> !! end !! test @@ -12060,12 +13013,7 @@ parsoid=wt2html,wt2wt,html2html !! wikitext [[File:Foobar.jpg|left|baseline|frame|500x50px|caption]] !! html/parsoid -<figure class="mw-halign-left mw-valign-baseline" typeof="mw:Image/Frame"> -<a href="File:Foobar.jpg"> -<img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941" /> -</a> -<figcaption>caption</figcaption> -</figure> +<figure class="mw-halign-left mw-valign-baseline" typeof="mw:Image/Frame"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a><figcaption>caption</figcaption></figure> !! end !! test @@ -12073,7 +13021,7 @@ Parsoid-specific image handling - frameless image with specific size, border, an !! wikitext [[File:Foobar.jpg|frameless|442x50px|border|caption]] !! html/parsoid -<p><span class="mw-image-border" typeof="mw:Image/Frameless" data-mw='{"caption":"caption"}' data-parsoid='{"optList":[{"ck":"frameless","ak":"frameless"},{"ck":"width","ak":"442x50px"},{"ck":"border","ak":"border"},{"ck":"caption","ak":"caption"}],"size":"442x50"}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"}}'><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/442px-Foobar.jpg" height="50" width="442" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"50","width":"442"},"sa":{"resource":"File:Foobar.jpg"}}'/></a></span></p> +<p><span class="mw-image-border" typeof="mw:Image/Frameless" data-mw='{"caption":"caption"}' data-parsoid='{"optList":[{"ck":"frameless","ak":"frameless"},{"ck":"width","ak":"442x50px"},{"ck":"border","ak":"border"},{"ck":"caption","ak":"caption"}],"size":"442x50"}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"}}'><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/442px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="50" width="442" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"50","width":"442"},"sa":{"resource":"File:Foobar.jpg"}}'/></a></span></p> !! end !! test @@ -12081,10 +13029,7 @@ Parsoid-specific image handling - simple image with a formatted caption !! wikitext [[File:Foobar.jpg|<table><tr><td>a</td><td>b</td></tr><tr><td>c</td></tr></table>]] !! html/parsoid -<p><span class="mw-default-size" typeof="mw:Image" data-mw='{"caption":"<table><tr><td>a</td><td>b</td></tr><tr><td>c</td></tr></table>"}'> -<a href="File:Foobar.jpg"> -<img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"> -</a></span></p> +<p><span class="mw-default-size" typeof="mw:Image" data-mw='{"caption":"<table><tr><td>a</td><td>b</td></tr><tr><td>c</td></tr></table>"}'><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></span></p> !! end !! test @@ -12092,7 +13037,7 @@ Parsoid-specific image handling - caption with a template in it !! wikitext [[File:Foobar.jpg|thumb|200x23px|This caption has a {{echo|transclusion}} in it.]] !! html/parsoid -<figure typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/200px-Foobar.jpg" height="23" width="200"></a><figcaption>This caption has a <span about="#mwt1" typeof="mw:Transclusion" data-mw="{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"transclusion"}},"i":0}}]}">transclusion</span> in it.</figcaption></figure> +<figure typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/200px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="23" width="200"></a><figcaption>This caption has a <span about="#mwt1" typeof="mw:Transclusion" data-mw="{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"transclusion"}},"i":0}}]}">transclusion</span> in it.</figcaption></figure> !! end !! test @@ -12105,7 +13050,7 @@ foo bar !! html/parsoid <p>foo</p> -<figure typeof="mw:Image/Thumb"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="23" width="200"></a><figcaption>This caption has a <center>unbalanced tag in it.</center></figcaption></figure> +<figure typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="23" width="200"/></a><figcaption>This caption has a <center>unbalanced tag in it.</center></figcaption></figure> <p>bar</p> !! end @@ -12116,7 +13061,7 @@ parsoid=wt2html,wt2wt !! wikitext [[File:Foobar.jpg|thumb|]] !! html/parsoid -<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="25" width="220"/></a><figcaption></figcaption></figure> +<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption></figcaption></figure> !! end # empty captions don't get serialized unless we're in the "round trip" case @@ -12126,9 +13071,10 @@ Parsoid-specific image handling - empty caption (2) parsoid=html2wt !! html/parsoid <figure class="mw-default-size" typeof="mw:Image/Thumb"> - <a href="File:Foobar.jpg"> + <a href="./File:Foobar.jpg"> <img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" + data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/> </a> <figcaption></figcaption> @@ -12142,7 +13088,7 @@ Parsoid-specific image handling - whitespace caption !! wikitext [[File:Foobar.jpg|thumb| ]] !! html/parsoid -<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="25" width="220"/></a><figcaption> </figcaption></figure> +<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption> </figcaption></figure> !! end !! test @@ -12153,7 +13099,7 @@ foo bar !! html/parsoid <p>foo -<span class="mw-default-size" typeof="mw:Image" data-mw='{"caption":"caption"}'><a href="./File:Foobar.svg"><img resource="./File:Foobar.svg" src="//example.com/images/f/ff/Foobar.svg" lang="de" height="180" width="240"/></a></span> +<span class="mw-default-size" typeof="mw:Image" data-mw='{"caption":"caption"}'><a href="./File:Foobar.svg"><img resource="./File:Foobar.svg" src="//example.com/images/f/ff/Foobar.svg" lang="de" data-file-width="240" data-file-height="180" data-file-type="drawing" height="180" width="240"/></a></span> bar</p> !! end @@ -12189,7 +13135,12 @@ subpage title=[[Subpage test]] </p> !! end -# TODO: make this PHP-parser compatible! +!! article +Subpage test/1/2/subpage +!! text +blah +!! endarticle + !! test Relative subpage noslash link !! options @@ -12199,8 +13150,12 @@ subpage title=[[Subpage test/1/2/3/4]] [[../../subpage/]] [[../../subpage]] -!! html -<p><a rel="mw:WikiLink" href="Subpage_test/1/2/subpage/" title="Subpage test/1/2/subpage/">subpage</a></p> +!! html/php +<p><a href="/wiki/Subpage_test/1/2/subpage" title="Subpage test/1/2/subpage">subpage</a> +</p><p><a href="/wiki/Subpage_test/1/2/subpage" title="Subpage test/1/2/subpage">Subpage test/1/2/subpage</a> +</p> +!! html/parsoid +<p><a rel="mw:WikiLink" href="Subpage_test/1/2/subpage" title="Subpage test/1/2/subpage">subpage</a></p> <p><a rel="mw:WikiLink" href="Subpage_test/1/2/subpage" title="Subpage test/1/2/subpage">Subpage_test/1/2/subpage</a></p> !! end @@ -12273,8 +13228,28 @@ Render invalid page names as plain text (bug 51090) [[foo<bar]] </p> !!html/parsoid -<p>[[./../foo|bar]][[foo�|bar]][[foo/.|bar]][[foo/..|bar]][[foo~~~bar]][[foo>bar]][[foo[bar]][[.]][[..]][[foo././bar]]</p> -<p>[[<span typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"./../foo"}},"i":0}}]}'>./../foo</span>|bar]][[<span typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo/."}},"i":0}}]}'>foo/.</span>|bar]][[<span typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo/.."}},"i":0}}]}'>foo/..</span>|bar]][[<span typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo~~~~bar"}},"i":0}}]}'>foo~~~~bar</span>]][[<span typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo>bar"}},"i":0}}]}'>foo>bar</span>]][[<span typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo././bar"}},"i":0}}]}'>foo././bar</span>]][[<span typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo{bar"}},"i":0}}]}'>foo{bar</span>]][[<span typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo}bar"}},"i":0}}]}'>foo}bar</span>]][[<span typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo[bar"}},"i":0}}]}'>foo[bar</span>]][[<span typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo]bar"}},"i":0}}]}'>foo]bar</span>]][[<span typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo<bar"}},"i":0}}]}'>foo<bar</span>]]</p> +<p>[[./../foo|bar]] +[[foo�|bar]] +[[foo/.|bar]] +[[foo/..|bar]] +[[foo~~~bar]] +[[foo>bar]] +[[foo[bar]] +[[.]] +[[..]] +[[foo././bar]]</p> + +<p>[[<span typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"./../foo"}},"i":0}}]}'>./../foo</span>|bar]] +[[<span typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo/."}},"i":0}}]}'>foo/.</span>|bar]] +[[<span typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo/.."}},"i":0}}]}'>foo/..</span>|bar]] +[[<span typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo~~~~bar"}},"i":0}}]}'>foo~~~~bar</span>]] +[[<span typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo>bar"}},"i":0}}]}'>foo>bar</span>]] +[[<span typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo././bar"}},"i":0}}]}'>foo././bar</span>]] +[[<span typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo{bar"}},"i":0}}]}'>foo{bar</span>]] +[[<span typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo}bar"}},"i":0}}]}'>foo}bar</span>]] +[[<span typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo[bar"}},"i":0}}]}'>foo[bar</span>]] +[[<span typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo]bar"}},"i":0}}]}'>foo]bar</span>]] +[[<span typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo<bar"}},"i":0}}]}'>foo<bar</span>]]</p> !!end !! test @@ -12496,8 +13471,8 @@ parsoid [[:File:Foo.png|Bar]] !! html <p> -<a rel="mw:WikiLink" href="File:Foo.png" title="File:Foo.png">File:Foo.png</a> -<a rel="mw:WikiLink" href="File:Foo.png" title="File:Foo.png">Bar</a> +<a rel="mw:WikiLink" href="./File:Foo.png" title="File:Foo.png">File:Foo.png</a> +<a rel="mw:WikiLink" href="./File:Foo.png" title="File:Foo.png">Bar</a> </p> !! end @@ -12514,15 +13489,31 @@ parsoid !! end !! test -Parsoid: Defaultsort +Normalize hrefs properly before testing for invalid link targets (bug 70894) !! options -parsoid +parsoid=html2wt +!! html +<link rel="mw:PageProp/Category" href="./Category:Toxine_bactérienne"/> +!! wikitext +[[Category:Toxine bactérienne]] +!! end + +!! test +Parsoid: Defaultsort !! wikitext {{DEFAULTSORT:Foo}} -!! html +!! html/parsoid <meta property="mw:PageProp/categorydefaultsort" content="Foo"/> !! end +!! test +Parsoid: Defaultsort (template-generated) +!! wikitext +{{{{echo|DEFAULTSORT}}:Foo}} +!! html/parsoid +<meta property="mw:PageProp/categorydefaultsort" content="Foo" about="#mwt1" typeof="mw:Transclusion" data-parsoid='{"dsr":[0,28,null,null],"pi":[[]]}' data-mw='{"parts":[{"template":{"target":{"wt":"{{echo|DEFAULTSORT}}:Foo"},"params":{},"i":0}}]}'/> +!! end + ### ### Inter-language links ### @@ -12537,9 +13528,9 @@ ill !! html/php es:Alimento fr:Nourriture zh:食品 !! html/parsoid -<p><link rel="mw:PageProp/Language" href="//es.wikipedia.org/wiki/Alimento"/> -<link rel="mw:PageProp/Language" href="//fr.wikipedia.org/wiki/Nourriture"/> -<link rel="mw:PageProp/Language" href="//zh.wikipedia.org/wiki/食品"/></p> +<link rel="mw:PageProp/Language" href="http://es.wikipedia.org/wiki/Alimento"/> +<link rel="mw:PageProp/Language" href="http://fr.wikipedia.org/wiki/Nourriture"/> +<link rel="mw:PageProp/Language" href="http://zh.wikipedia.org/wiki/食品"/> !! end !! test @@ -12554,10 +13545,10 @@ ill !! html/php es:1 fr:1 !! html/parsoid -<p><link rel="mw:PageProp/Language" href="//es.wikipedia.org/wiki/1"/> -<link rel="mw:PageProp/Language" href="//es.wikipedia.org/wiki/2"/> -<link rel="mw:PageProp/Language" href="//fr.wikipedia.org/wiki/1"/> -<link rel="mw:PageProp/Language" href="//fr.wikipedia.org/wiki/2"/></p> +<link rel="mw:PageProp/Language" href="http://es.wikipedia.org/wiki/1"/> +<link rel="mw:PageProp/Language" href="http://es.wikipedia.org/wiki/2"/> +<link rel="mw:PageProp/Language" href="http://fr.wikipedia.org/wiki/1"/> +<link rel="mw:PageProp/Language" href="http://fr.wikipedia.org/wiki/2"/> !! end ### @@ -12631,6 +13622,31 @@ Some text !! end +!! test +TOC anchors don't collide +!! wikitext +__FORCETOC__ +== Headline 2 == +== Headline == +== Headline 2 == +== Headline == +!! html +<div id="toc" class="toc"><div id="toctitle"><h2>Contents</h2></div> +<ul> +<li class="toclevel-1 tocsection-1"><a href="#Headline_2"><span class="tocnumber">1</span> <span class="toctext">Headline 2</span></a></li> +<li class="toclevel-1 tocsection-2"><a href="#Headline"><span class="tocnumber">2</span> <span class="toctext">Headline</span></a></li> +<li class="toclevel-1 tocsection-3"><a href="#Headline_2_2"><span class="tocnumber">3</span> <span class="toctext">Headline 2</span></a></li> +<li class="toclevel-1 tocsection-4"><a href="#Headline_3"><span class="tocnumber">4</span> <span class="toctext">Headline</span></a></li> +</ul> +</div> + +<h2><span class="mw-headline" id="Headline_2">Headline 2</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&action=edit&section=1" title="Edit section: Headline 2">edit</a><span class="mw-editsection-bracket">]</span></span></h2> +<h2><span class="mw-headline" id="Headline">Headline</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&action=edit&section=2" title="Edit section: Headline">edit</a><span class="mw-editsection-bracket">]</span></span></h2> +<h2><span class="mw-headline" id="Headline_2_2">Headline 2</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&action=edit&section=3" title="Edit section: Headline 2">edit</a><span class="mw-editsection-bracket">]</span></span></h2> +<h2><span class="mw-headline" id="Headline_3">Headline</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&action=edit&section=4" title="Edit section: Headline">edit</a><span class="mw-editsection-bracket">]</span></span></h2> + +!! end + # perl -e 'print "="x$_," Level $_ heading","="x$_,"\n" for 1..10' !! test Handling of sections up to level 6 and beyond @@ -12690,7 +13706,7 @@ Handling of sections up to level 6 and beyond !! end !! test -TOC regression (bug 9764) +TOC regression (T11764) !! wikitext == title 1 == === title 1.1 === @@ -12862,7 +13878,7 @@ Link inside a section heading !! end !! test -TOC regression (bug 12077) +TOC regression (T14077) !! wikitext __TOC__ == title 1 == @@ -12889,10 +13905,12 @@ __TOC__ !! test BUG 1219 URL next to image (good) !! wikitext -http://example.com [[Image:foobar.jpg]] -!! html +http://example.com [[File:Foobar.jpg]] +!! html/php <p><a rel="nofollow" class="external free" href="http://example.com">http://example.com</a> <a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> </p> +!! html/parsoid +<p><a rel="mw:ExtLink" href="http://example.com">http://example.com</a> <span class="mw-default-size" typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></span></p> !!end !! test @@ -13115,10 +14133,12 @@ c3--> !! test BUG 1219 URL next to image (broken) !! wikitext -http://example.com[[Image:foobar.jpg]] -!! html +http://example.com[[File:Foobar.jpg]] +!! html/php <p><a rel="nofollow" class="external free" href="http://example.com">http://example.com</a><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> </p> +!! html/parsoid +<p><a rel="mw:ExtLink" href="http://example.com">http://example.com</a><span class="mw-default-size" typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a></span></p> !!end !! test @@ -13237,15 +14257,14 @@ parsoid </tbody></table> !! end -# The PHP parser escapes the opening brace to { for some reason, so -# disabled this test for it. !! test div with braces in attribute value -!! options -parsoid !! wikitext <div title="{}">Foo</div> -!! html +!! html/php +<div title="{}">Foo</div> + +!! html/parsoid <div title="{}">Foo</div> !! end @@ -13254,17 +14273,19 @@ parsoid # 'div with empty attribute value, space before equals'), but strips the # attribute completely if the space is missing. We hope that not much content # depends on this, so are implementing the behavior below in Parsoid for -# consistencies' sake. Disabled for the PHP parser. +# consistencies' sake. # FIXME: fix this behavior in the PHP parser? !! test div with empty attribute value, no space before equals !! options -parsoid +parsoid=wt2html,html2html !! wikitext <div class=>HTML rocks</div> -!! html -<div class="">HTML rocks</div> +!! html/php +<div>HTML rocks</div> +!! html/parsoid +<div class="">HTML rocks</div> !! end !! test @@ -13482,16 +14503,17 @@ Media link with text !! end # FIXME: this is still bad HTML tag nesting +# FIXME: doBlockLevels won't wrap this in a paragraph because it contains a div !! test Media link with nasty text -fixme: doBlockLevels won't wrap this in a paragraph because it contains a div !! wikitext [[Media:Foobar.jpg|Safe Link<div style=display:none>" onmouseover="alert(document.cookie)" onfoo="</div>]] !! html <a href="http://example.com/images/3/3a/Foobar.jpg" class="internal" title="Foobar.jpg">Safe Link<div style="display:none">" onmouseover="alert(document.cookie)" onfoo="</div></a> !! html+tidy -<p><a href="http://example.com/images/3/3a/Foobar.jpg" class="internal" title="Foobar.jpg">Safe Link<div style="display:none">" onmouseover="alert(document.cookie)" onfoo="</div></a></p> +<p><a href="http://example.com/images/3/3a/Foobar.jpg" class="internal" title="Foobar.jpg">Safe Link</a></p> +<div style="display:none">" onmouseover="alert(document.cookie)" onfoo="</div> !! end !! test @@ -13506,19 +14528,23 @@ Media link to nonexistent file (bug 1702) !! test Image link to nonexistent file (bug 1850 - good) !! wikitext -[[Image:No such.jpg]] -!! html +[[File:No_such.jpg]] +!! html/php <p><a href="/index.php?title=Special:Upload&wpDestFile=No_such.jpg" class="new" title="File:No such.jpg">File:No such.jpg</a> </p> +!! html/parsoid +<p><span class="mw-default-size" typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}]}'><a href="./File:No_such.jpg"><img resource="./File:No_such.jpg" src="./Special:FilePath/No_such.jpg" height="220" width="220"/></a></span></p> !! end !! test :Image link to nonexistent file (bug 1850 - bad) !! wikitext [[:Image:No such.jpg]] -!! html +!! html/php <p><a href="/index.php?title=File:No_such.jpg&action=edit&redlink=1" class="new" title="File:No such.jpg (page does not exist)">Image:No such.jpg</a> </p> +!! html/parsoid +<p><a rel="mw:WikiLink" href="./File:No_such.jpg" title="File:No such.jpg">Image:No such.jpg</a></p> !! end @@ -13685,7 +14711,7 @@ Bug 2304: HTML attribute safety (dangerous template; 2309) <div title=""></div> !! html/parsoid -<div title='" onmouseover="alert(document.cookie)' about="#mwt2" typeof="mw:ExpandedAttrs" data-mw='{"attribs":[[{"txt":"title"},{"html":"<span about=\"#mwt1\" typeof=\"mw:Transclusion\" data-mw=\"{&quot;parts&quot;:[{&quot;template&quot;:{&quot;target&quot;:{&quot;wt&quot;:&quot;dangerous attribute&quot;,&quot;href&quot;:&quot;./Template:Dangerous_attribute&quot;},&quot;params&quot;:{},&quot;i&quot;:0}}]}\" data-parsoid=\"{&quot;pi&quot;:[[]],&quot;dsr&quot;:[12,35,null,null]}\">\" onmouseover=\"alert(document.cookie)</span>"}]]}' data-parsoid='{"stx":"html","a":{"title":"\" onmouseover=\"alert(document.cookie)"},"sa":{"title":"{{dangerous attribute}}"}}'></div> +<div title='" onmouseover="alert(document.cookie)' about="#mwt2" typeof="mw:ExpandedAttrs" data-parsoid='{"stx":"html","a":{"title":"\" onmouseover=\"alert(document.cookie)"},"sa":{"title":"{{dangerous attribute}}"}}' data-mw='{"attribs":[[{"txt":"title"},{"html":"<span about=\"#mwt1\" typeof=\"mw:Transclusion\" data-parsoid=\"{&quot;pi&quot;:[[]],&quot;dsr&quot;:[12,35,null,null]}\" data-mw=\"{&quot;parts&quot;:[{&quot;template&quot;:{&quot;target&quot;:{&quot;wt&quot;:&quot;dangerous attribute&quot;,&quot;href&quot;:&quot;./Template:Dangerous_attribute&quot;},&quot;params&quot;:{},&quot;i&quot;:0}}]}\">\" onmouseover=\"alert(document.cookie)</span>"}]]}'></div> !! end !! test @@ -14005,9 +15031,12 @@ Expansion of multi-line templates in attribute values (bug 6255 sanity check) !! wikitext <div style="background: #00FF00">-</div> -!! html +!! html/php <div style="background: #00FF00">-</div> +!! html/parsoid +<div style="background: +#00FF00">-</div> !! end !! test @@ -14245,6 +15274,10 @@ Nested template calls ### ### Sanitizer ### + +# HTML+Tidy effectively strips out the empty tags completely +# But since Parsoid doesn't it wraps the <s></s> tags in p-tags +# which Tidy would have done for the PHP parser had there been content inside it. !! test Sanitizer: Closing of open tags !! wikitext @@ -14252,6 +15285,8 @@ Sanitizer: Closing of open tags !! html <s></s><table></table> +!! html/parsoid +<p><s></s></p><table></table> !! end !! test @@ -14290,16 +15325,19 @@ Sanitizer: Escaping of spaces, multibyte characters, colons & other stuff in id= </p> !! end +# In HTML5, the restrictions are that id must contain at least one character, +# and must not contain any space characters. !! test Sanitizer: Validating the contents of the id attribute (bug 4515) !! options disabled !! wikitext -<br id=9 /> +<br id="" /><br id="a space" /> !! html -Something, but definitely not <br id="9" />... +Something ... !! end +# In HTML5, id must be unique amongst all the ids in the element's home subtree. !! test Sanitizer: Validating id attribute uniqueness (bug 4515, bug 6301) !! options @@ -14397,7 +15435,6 @@ Punctuation: CSS ! important (bug 11874; with space after) !!end - !! test HTML bullet list, closed tags (bug 5497) !! wikitext @@ -14405,29 +15442,36 @@ HTML bullet list, closed tags (bug 5497) <li>One</li> <li>Two</li> </ul> -!! html +!! html/php <ul> <li>One</li> <li>Two</li> </ul> +!! html/parsoid +<ul data-parsoid='{"stx":"html"}'> +<li data-parsoid='{"stx":"html"}'>One</li> +<li data-parsoid='{"stx":"html"}'>Two</li> +</ul> + !! end !! test HTML bullet list, unclosed tags (bug 5497) -!! options -disabled !! wikitext <ul> <li>One <li>Two </ul> -!! html +!! html/php+tidy <ul> -<li>One -</li> -<li>Two -</li> +<li>One</li> +<li>Two</li> +</ul> +!! html/parsoid +<ul data-parsoid='{"stx":"html"}'> +<li data-parsoid='{"stx":"html","autoInsertedEnd":true}'>One</li> +<li data-parsoid='{"stx":"html","autoInsertedEnd":true}'>Two</li> </ul> !! end @@ -14439,29 +15483,37 @@ HTML ordered list, closed tags (bug 5497) <li>One</li> <li>Two</li> </ol> -!! html +!! html/php <ol> <li>One</li> <li>Two</li> </ol> +!! html/parsoid +<ol data-parsoid='{"stx":"html"}'> +<li data-parsoid='{"stx":"html"}'>One</li> +<li data-parsoid='{"stx":"html"}'>Two</li> +</ol> + !! end !! test HTML ordered list, unclosed tags (bug 5497) !! options -disabled !! wikitext <ol> <li>One <li>Two </ol> -!! html +!! html/php+tidy <ol> -<li>One -</li> -<li>Two -</li> +<li>One</li> +<li>Two</li> +</ol> +!! html/parsoid +<ol data-parsoid='{"stx":"html"}'> +<li data-parsoid='{"stx":"html","autoInsertedEnd":true}'>One</li> +<li data-parsoid='{"stx":"html","autoInsertedEnd":true}'>Two</li> </ol> !! end @@ -14493,8 +15545,6 @@ HTML nested bullet list, closed tags (bug 5497) !! test HTML nested bullet list, open tags (bug 5497) -!! options -disabled !! wikitext <ul> <li>One @@ -14504,7 +15554,17 @@ disabled <li>Sub-two </ul> </ul> -!! html +!! html/php+tidy +<ul> +<li>One</li> +<li>Two: +<ul> +<li>Sub-one</li> +<li>Sub-two</li> +</ul> +</li> +</ul> +!! html/parsoid <ul> <li>One </li> @@ -14547,8 +15607,6 @@ HTML nested ordered list, closed tags (bug 5497) !! test HTML nested ordered list, open tags (bug 5497) -!! options -disabled !! wikitext <ol> <li>One @@ -14558,7 +15616,17 @@ disabled <li>Sub-two </ol> </ol> -!! html +!! html/php +<ol> +<li>One +<li>Two: +<ol> +<li>Sub-one +<li>Sub-two +</ol> +</ol> + +!! html/parsoid <ol> <li>One </li> @@ -14659,6 +15727,7 @@ http://<div id="toc" class="toc"><div id="toctitle"><h2>Contents</h2></div> <li class="toclevel-1 tocsection-1"><a href="#onmouseover.3D"><span class="tocnumber">1</span> <span class="toctext">onmouseover=</span></a></li> </ul> </div> +<p></p> !! end !! test @@ -14798,32 +15867,38 @@ Fuzz testing: Parser25 (bug 6055) Fuzz testing: URL adjacent extension (with space, clean) !! wikitext http://example.com <nowiki>junk</nowiki> -!! html +!! html/php <p><a rel="nofollow" class="external free" href="http://example.com">http://example.com</a> junk </p> -!!end +!! html/parsoid +<p><a rel="mw:ExtLink" href="http://example.com" data-parsoid='{"stx":"url"}'>http://example.com</a> <span typeof="mw:Nowiki">junk</span></p> +!! end !!test Fuzz testing: URL adjacent extension (no space, dirty; nowiki) !! wikitext http://example.com<nowiki>junk</nowiki> -!! html +!! html/php <p><a rel="nofollow" class="external free" href="http://example.com">http://example.com</a>junk </p> -!!end +!! html/parsoid +<p><a rel="mw:ExtLink" href="http://example.com" data-parsoid='{"stx":"url"}'>http://example.com</a><span typeof="mw:Nowiki">junk</span></p> +!! end !!test Fuzz testing: URL adjacent extension (no space, dirty; pre) !! wikitext http://example.com<pre>junk</pre> -!! html +!! html/php <a rel="nofollow" class="external free" href="http://example.com">http://example.com</a><pre>junk</pre> -!! html+tidy +!! html/php+tidy <p><a rel="nofollow" class="external free" href="http://example.com">http://example.com</a></p> <pre> junk </pre> +!! html/parsoid +<p><a rel="mw:ExtLink" href="http://example.com" data-parsoid='{"stx":"url"}'>http://example.com</a></p><pre data-parsoid='{"stx":"html"}'>junk</pre> !!end !!test @@ -14834,7 +15909,7 @@ Fuzz testing: image with bogus manual thumbnail <div class="thumb tright"><div class="thumbinner" style="width:182px;">Error creating thumbnail: <div class="thumbcaption"></div></div></div> !! html/parsoid -<meta typeof="mw:Placeholder" data-parsoid='{"src":"[[Image:foobar.jpg|thumbnail= ]]","optList":[{"ck":"manualthumb","ak":"thumbnail= "}],"dsr":[0,32,null,null]}'/> +<figure class="mw-default-size" typeof="mw:Error mw:Image/Thumb" data-parsoid='{"optList":[{"ck":"manualthumb","ak":"thumbnail= "}],"dsr":[0,32,2,2]}' data-mw='{"errors":[{"key":"missing-thumbnail","message":"This thumbnail does not exist.","params":{"name":""}}],"thumb":""}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"},"sa":{},"dsr":[2,30,null,null]}'><img resource="./File:Foobar.jpg" src="./Special:FilePath/" height="220" width="220" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"220","width":"220"},"sa":{"resource":"Image:foobar.jpg"}}'/></a></figure> !!end !! test @@ -14912,15 +15987,19 @@ New wiki paragraph </p> !! end +# FIXME: The current php output is documented +# and desired output is the parsoid target. !! test Inline HTML vs wiki block nesting -!! options -disabled !! wikitext <b>Bold paragraph New wiki paragraph -!! html +!! html/php +<p><b>Bold paragraph +</p><p>New wiki paragraph</b> +</p> +!! html/parsoid <p><b>Bold paragraph</b> </p><p>New wiki paragraph </p> @@ -15913,6 +16992,17 @@ Special:Search page linking. !! end !! test +{{!}} is a magic word +!! wikitext +{{!}} is a magic word there and {{!}} is still a magic word here +!! html/php +<p>| is a magic word there and | is still a magic word here +</p> +!! html/parsoid +<p><span about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"!","href":"./Template:!"},"params":{},"i":0}}]}' data-parsoid='{"pi":[[]]}'>|</span> is a magic word there and <span about="#mwt2" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"!","href":"./Template:!"},"params":{},"i":0}}]}' data-parsoid='{"pi":[[]]}'>|</span> is still a magic word here</p> +!! end + +!! test Say the magic word !! options title=[[Parser test]] @@ -16025,8 +17115,8 @@ image4 |300px| centre Gallery (with options) !! wikitext <gallery widths='70px' heights='40px' perrow='2' caption='Foo [[Main Page]]' > -File:Nonexistant.jpg|caption -File:Nonexistant.jpg +File:Nonexistent.jpg|caption +File:Nonexistent.jpg image:foobar.jpg|some '''caption''' [[Main Page]] image:foobar.jpg image:foobar.jpg|Blabla|alt=This is a foo-bar.|blabla. @@ -16035,31 +17125,31 @@ image:foobar.jpg|Blabla|alt=This is a foo-bar.|blabla. <ul class="gallery mw-gallery-traditional" style="max-width: 226px;_width: 226px;"> <li class='gallerycaption'>Foo <a href="/wiki/Main_Page" title="Main Page">Main Page</a></li> <li class="gallerybox" style="width: 105px"><div style="width: 105px"> - <div class="thumb" style="height: 70px;">Nonexistant.jpg</div> + <div class="thumb" style="height: 70px;">Nonexistent.jpg</div> <div class="gallerytext"> <p>caption </p> </div> </div></li> <li class="gallerybox" style="width: 105px"><div style="width: 105px"> - <div class="thumb" style="height: 70px;">Nonexistant.jpg</div> + <div class="thumb" style="height: 70px;">Nonexistent.jpg</div> <div class="gallerytext"> </div> </div></li> <li class="gallerybox" style="width: 105px"><div style="width: 105px"> - <div class="thumb" style="width: 100px;"><div style="margin:31px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/70px-Foobar.jpg" width="70" height="8" /></a></div></div> + <div class="thumb" style="width: 100px;"><div style="margin:31px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/70px-Foobar.jpg" width="70" height="8" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/105px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/140px-Foobar.jpg 2x" /></a></div></div> <div class="gallerytext"> <p>some <b>caption</b> <a href="/wiki/Main_Page" title="Main Page">Main Page</a> </p> </div> </div></li> <li class="gallerybox" style="width: 105px"><div style="width: 105px"> - <div class="thumb" style="width: 100px;"><div style="margin:31px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/thumb/3/3a/Foobar.jpg/70px-Foobar.jpg" width="70" height="8" /></a></div></div> + <div class="thumb" style="width: 100px;"><div style="margin:31px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/thumb/3/3a/Foobar.jpg/70px-Foobar.jpg" width="70" height="8" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/105px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/140px-Foobar.jpg 2x" /></a></div></div> <div class="gallerytext"> </div> </div></li> <li class="gallerybox" style="width: 105px"><div style="width: 105px"> - <div class="thumb" style="width: 100px;"><div style="margin:31px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="This is a foo-bar." src="http://example.com/images/thumb/3/3a/Foobar.jpg/70px-Foobar.jpg" width="70" height="8" /></a></div></div> + <div class="thumb" style="width: 100px;"><div style="margin:31px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="This is a foo-bar." src="http://example.com/images/thumb/3/3a/Foobar.jpg/70px-Foobar.jpg" width="70" height="8" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/105px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/140px-Foobar.jpg 2x" /></a></div></div> <div class="gallerytext"> <p>Blabla|blabla. </p> @@ -16080,17 +17170,17 @@ image:foobar.jpg|link=Main Page#section|caption !! html <ul class="gallery mw-gallery-traditional"> <li class="gallerybox" style="width: 155px"><div style="width: 155px"> - <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/Main_Page"><img alt="Foobar.jpg" src="http://example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" width="120" height="14" /></a></div></div> + <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/Main_Page"><img alt="Foobar.jpg" src="http://example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" width="120" height="14" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/240px-Foobar.jpg 2x" /></a></div></div> <div class="gallerytext"> </div> </div></li> <li class="gallerybox" style="width: 155px"><div style="width: 155px"> - <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/Main_Page#section"><img alt="Foobar.jpg" src="http://example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" width="120" height="14" /></a></div></div> + <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/Main_Page#section"><img alt="Foobar.jpg" src="http://example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" width="120" height="14" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/240px-Foobar.jpg 2x" /></a></div></div> <div class="gallerytext"> </div> </div></li> <li class="gallerybox" style="width: 155px"><div style="width: 155px"> - <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/Main_Page#section"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" width="120" height="14" /></a></div></div> + <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/Main_Page#section"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" width="120" height="14" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/240px-Foobar.jpg 2x" /></a></div></div> <div class="gallerytext"> <p>caption </p> @@ -16110,14 +17200,14 @@ File:foobar.jpg|{{Test|unamedParam|alt=param}}|alt=galleryalt !! html <ul class="gallery mw-gallery-traditional"> <li class="gallerybox" style="width: 155px"><div style="width: 155px"> - <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="galleryalt" src="http://example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" width="120" height="14" /></a></div></div> + <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="galleryalt" src="http://example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" width="120" height="14" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/240px-Foobar.jpg 2x" /></a></div></div> <div class="gallerytext"> <p><a href="/wiki/File:Foobar.jpg" class="image" title="desc"><img alt="inneralt" src="http://example.com/images/thumb/3/3a/Foobar.jpg/20px-Foobar.jpg" width="20" height="2" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/30px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/40px-Foobar.jpg 2x" /></a> </p> </div> </div></li> <li class="gallerybox" style="width: 155px"><div style="width: 155px"> - <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="galleryalt" src="http://example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" width="120" height="14" /></a></div></div> + <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="galleryalt" src="http://example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" width="120" height="14" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/240px-Foobar.jpg 2x" /></a></div></div> <div class="gallerytext"> <p>This is a test template </p> @@ -16131,30 +17221,30 @@ File:foobar.jpg|{{Test|unamedParam|alt=param}}|alt=galleryalt gallery (with showfilename option) !! wikitext <gallery showfilename> -File:Nonexistant.jpg|caption -File:Nonexistant.jpg +File:Nonexistent.jpg|caption +File:Nonexistent.jpg image:foobar.jpg|some '''caption''' [[Main Page]] File:Foobar.jpg </gallery> !! html <ul class="gallery mw-gallery-traditional"> <li class="gallerybox" style="width: 155px"><div style="width: 155px"> - <div class="thumb" style="height: 150px;">Nonexistant.jpg</div> + <div class="thumb" style="height: 150px;">Nonexistent.jpg</div> <div class="gallerytext"> -<p><a href="/wiki/File:Nonexistant.jpg" title="File:Nonexistant.jpg">Nonexistant.jpg</a><br /> +<p><a href="/wiki/File:Nonexistent.jpg" title="File:Nonexistent.jpg">Nonexistent.jpg</a><br /> caption </p> </div> </div></li> <li class="gallerybox" style="width: 155px"><div style="width: 155px"> - <div class="thumb" style="height: 150px;">Nonexistant.jpg</div> + <div class="thumb" style="height: 150px;">Nonexistent.jpg</div> <div class="gallerytext"> -<p><a href="/wiki/File:Nonexistant.jpg" title="File:Nonexistant.jpg">Nonexistant.jpg</a><br /> +<p><a href="/wiki/File:Nonexistent.jpg" title="File:Nonexistent.jpg">Nonexistent.jpg</a><br /> </p> </div> </div></li> <li class="gallerybox" style="width: 155px"><div style="width: 155px"> - <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" width="120" height="14" /></a></div></div> + <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" width="120" height="14" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/240px-Foobar.jpg 2x" /></a></div></div> <div class="gallerytext"> <p><a href="/wiki/File:Foobar.jpg" title="File:Foobar.jpg">Foobar.jpg</a><br /> some <b>caption</b> <a href="/wiki/Main_Page" title="Main Page">Main Page</a> @@ -16162,7 +17252,7 @@ some <b>caption</b> <a href="/wiki/Main_Page" title="Main Page">Main Page</a> </div> </div></li> <li class="gallerybox" style="width: 155px"><div style="width: 155px"> - <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" width="120" height="14" /></a></div></div> + <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" width="120" height="14" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/240px-Foobar.jpg 2x" /></a></div></div> <div class="gallerytext"> <p><a href="/wiki/File:Foobar.jpg" title="File:Foobar.jpg">Foobar.jpg</a><br /> </p> @@ -16176,30 +17266,30 @@ some <b>caption</b> <a href="/wiki/Main_Page" title="Main Page">Main Page</a> Gallery (with namespace-less filenames) !! wikitext <gallery> -File:Nonexistant.jpg -Nonexistant.jpg +File:Nonexistent.jpg +Nonexistent.jpg image:foobar.jpg foobar.jpg </gallery> !! html <ul class="gallery mw-gallery-traditional"> <li class="gallerybox" style="width: 155px"><div style="width: 155px"> - <div class="thumb" style="height: 150px;">Nonexistant.jpg</div> + <div class="thumb" style="height: 150px;">Nonexistent.jpg</div> <div class="gallerytext"> </div> </div></li> <li class="gallerybox" style="width: 155px"><div style="width: 155px"> - <div class="thumb" style="height: 150px;">Nonexistant.jpg</div> + <div class="thumb" style="height: 150px;">Nonexistent.jpg</div> <div class="gallerytext"> </div> </div></li> <li class="gallerybox" style="width: 155px"><div style="width: 155px"> - <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" width="120" height="14" /></a></div></div> + <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" width="120" height="14" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/240px-Foobar.jpg 2x" /></a></div></div> <div class="gallerytext"> </div> </div></li> <li class="gallerybox" style="width: 155px"><div style="width: 155px"> - <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" width="120" height="14" /></a></div></div> + <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" width="120" height="14" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/240px-Foobar.jpg 2x" /></a></div></div> <div class="gallerytext"> </div> </div></li> @@ -16267,6 +17357,8 @@ ISBN 978-0-1234-56 789 </p> !! html+tidy <p><a href="/wiki/Special:BookSources/9780123456" class="internal mw-magiclink-isbn">ISBN 978-0-1234-56</a> 789</p> +!! html/parsoid +<p><a href="./Special:BookSources/9780123456" rel="mw:ExtLink" data-parsoid='{"stx":"magiclink"}'>ISBN 978-0-1234-56</a><span typeof="mw:Entity" data-parsoid='{"src":"&#x20;","srcContent":" "}'> </span>789</p> !! end !! test @@ -16282,24 +17374,37 @@ ISBN Double ISBN !! wikitext ISBN ISBN 1234567890 -!! html +!! html/php <p>ISBN <a href="/wiki/Special:BookSources/1234567890" class="internal mw-magiclink-isbn">ISBN 1234567890</a> </p> +!! html/parsoid +<p>ISBN <a href="./Special:BookSources/1234567890" rel="mw:ExtLink" data-parsoid='{"stx":"magiclink"}'>ISBN 1234567890</a></p> !! end !! test ISBN with an X !! wikitext ISBN 3-462-04561-X -!! html +ISBN 080442957X +ISBN 978080442957X +!! html/php <p><a href="/wiki/Special:BookSources/346204561X" class="internal mw-magiclink-isbn">ISBN 3-462-04561-X</a> +<a href="/wiki/Special:BookSources/080442957X" class="internal mw-magiclink-isbn">ISBN 080442957X</a> +<a href="/wiki/Special:BookSources/978080442957X" class="internal mw-magiclink-isbn">ISBN 978080442957X</a> </p> +!! html/parsoid +<p><a href="./Special:BookSources/346204561X" rel="mw:ExtLink" data-parsoid='{"stx":"magiclink"}'>ISBN 3-462-04561-X</a> +<a href="./Special:BookSources/080442957X" rel="mw:ExtLink" data-parsoid='{"stx":"magiclink"}'>ISBN 080442957X</a> +<a href="./Special:BookSources/978080442957X" rel="mw:ExtLink" data-parsoid='{"stx":"magiclink"}'>ISBN 978080442957X</a></p> !! end !! test ISBN with empty prefix (parsoid test) !! wikitext ISBN 1234567890 +!! html/php +<p><a href="/wiki/Special:BookSources/1234567890" class="internal mw-magiclink-isbn">ISBN 1234567890</a> +</p> !! html/parsoid <p><a href="Special:BookSources/1234567890" rel="mw:ExtLink">ISBN 1234567890</a></p> !! end @@ -16308,9 +17413,11 @@ ISBN 1234567890 Bug 22905: <abbr> followed by ISBN followed by </a> !! wikitext <abbr>(fr)</abbr> ISBN 2753300917 [http://www.example.com example.com] -!! html +!! html/php <p><abbr>(fr)</abbr> <a href="/wiki/Special:BookSources/2753300917" class="internal mw-magiclink-isbn">ISBN 2753300917</a> <a rel="nofollow" class="external text" href="http://www.example.com">example.com</a> </p> +!! html/parsoid +<p><abbr data-parsoid='{"stx":"html"}'>(fr)</abbr> <a href="./Special:BookSources/2753300917" rel="mw:ExtLink" data-parsoid='{"stx":"magiclink"}'>ISBN 2753300917</a> <a rel="mw:ExtLink" href="http://www.example.com">example.com</a></p> !! end !! test @@ -16402,9 +17509,11 @@ Image with page parameter djvu !! wikitext [[File:LoremIpsum.djvu|page=2]] -!! html +!! html/php <p><a href="/index.php?title=File:LoremIpsum.djvu&page=2" class="image"><img alt="LoremIpsum.djvu" src="http://example.com/images/thumb/5/5f/LoremIpsum.djvu/page2-2480px-LoremIpsum.djvu.jpg" width="2480" height="3508" srcset="http://example.com/images/thumb/5/5f/LoremIpsum.djvu/page2-3720px-LoremIpsum.djvu.jpg 1.5x, http://example.com/images/thumb/5/5f/LoremIpsum.djvu/page2-4960px-LoremIpsum.djvu.jpg 2x" /></a> </p> +!! html/parsoid +<p><span class="mw-default-size" typeof="mw:Image" data-parsoid='{"optList":[{"ck":"page","ak":"page=2"}]}'><a href="./File:LoremIpsum.djvu" data-parsoid='{"a":{"href":"./File:LoremIpsum.djvu"},"sa":{}}'><img resource="./File:LoremIpsum.djvu" src="//example.com/images/5/5f/LoremIpsum.djvu" data-file-width="2480" data-file-height="3508" data-file-type="bitmap" height="3508" width="2480" data-parsoid='{"a":{"resource":"./File:LoremIpsum.djvu","height":"3508","width":"2480"},"sa":{"resource":"File:LoremIpsum.djvu"}}'/></a></span></p> !! end !! test @@ -16416,35 +17525,16 @@ Another italics / bold test </pre> !!end -# Note the results may be incorrect, as parserTest output included this: -# XML error: Mismatched tag at byte 6120: -# ...<dd> </dt></dl> </dd... +# FIXME: The php output seems broken. It's interleaving some open/close tags. !! test dt/dd/dl test -!! options -disabled !! wikitext :;;;:: -!! html -<dl> -<dd><dl> -<dt><dl> -<dt><dl> -<dt><dl> -<dd><dl> -<dd> -</dd> -</dl> -</dd> -</dl> -</dt> -</dl> -</dt> -</dl> -</dt> -</dl> -</dd> -</dl> +!! html/php +<dl><dd><dl><dt><dl><dt><dl><dt><dl><dd><dl><dd></dt></dl></dd></dl></dd></dl></dd></dl></dd></dl></dd></dl> + +!! html/parsoid +<dl><dd><dl><dt><dl><dt><dl><dt><dl><dd><dl><dd></dd></dl></dd></dl></dt></dl></dt></dl></dt></dl></dd></dl> !!end @@ -16458,7 +17548,7 @@ Images with the "|" character in the comment <div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/270px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/360px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"></a></div>An <a rel="nofollow" class="external text" href="http://test/?param1=%7Cleft%7C&param2=%7Cx">external</a> URL</div></div></div> !! html/parsoid -<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="25" width="220"/></a><figcaption>An <a rel="mw:ExtLink" href="http://test/?param1=|left|&param2=|x">external</a> URL</figcaption></figure> +<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption>An <a rel="mw:ExtLink" href="http://test/?param1=|left|&param2=|x">external</a> URL</figcaption></figure> !! end !! test @@ -16538,7 +17628,7 @@ subpage title=[[Subpage test/L1/L2/L3]] !! wikitext [[../../////]] !! html -<p><a href="/index.php?title=Subpage_test/L1////&action=edit&redlink=1" class="new" title="Subpage test/L1//// (page does not exist)">///</a> +<p><a href="/index.php?title=Subpage_test/L1&action=edit&redlink=1" class="new" title="Subpage test/L1 (page does not exist)">Subpage test/L1</a> </p> !! end @@ -16587,7 +17677,7 @@ Definition list code coverage ; title : def ; title : def ;title: def -!! html +!! html/php <dl><dt> title  </dt> <dd> def</dd> <dt> title </dt> @@ -16595,6 +17685,10 @@ Definition list code coverage <dt>title</dt> <dd> def</dd></dl> +!! html/parsoid +<dl><dt> title <span typeof="mw:Placeholder"> </span></dt><dd> def</dd> +<dt> title<span typeof="mw:Placeholder"> </span></dt><dd> def</dd> +<dt>title</dt><dd> def</dd></dl> !! end !! test @@ -17051,7 +18145,7 @@ language=sr variant=sr-ec !! wikitext == -{Naslov}- == !! html -<h2><span class="mw-headline" id="-.7BNaslov.7D-">Naslov</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&action=edit&section=1" title="Уредите одељак „Naslov“">уреди</a><span class="mw-editsection-bracket">]</span></span></h2> +<h2><span class="mw-headline" id="-.7BNaslov.7D-">Naslov</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&action=edit&section=1" title="Уреди одељак „Naslov“">уреди</a><span class="mw-editsection-bracket">]</span></span></h2> !! end @@ -17277,45 +18371,51 @@ language=sr variant=sr-ec </p> !! end -# This test is currently broken in the PHP parser (bug 52661) +# FIXME: This test is currently broken in the PHP parser (bug 52661) !! test Don't break image parsing if language converter markup is in the caption. !! options language=sr -disabled !! wikitext [[File:Foobar.jpg|-{R|caption}-]] -!! html +!! html/parsoid <p><a href="/wiki/File:Foobar.jpg" class="image" title="caption"><img alt="caption" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> </p> !! end -# This test is currently broken in the PHP parser (bug 52661) +# FIXME: This test is currently broken in the PHP parser (bug 52661) !! test Don't break list handling if language converter markup is in the item. !! options language=zh variant=zh-cn -disabled !! wikitext ;-{zh-cn:AAA;zh-tw:BBB}- -!! html +!! html/php +<dl><dt><span class="error">在手动语言转换规则中检测到错误</span></dd></dl> + +!! html/parsoid <dl><dt>AAA </dt></dl> - !! end -# This test is currently broken in the PHP parser (bug 52661) +# FIXME: This test is currently broken in the PHP parser (bug 52661) !! test Don't break table handling if language converter markup is in the cell. !! options language=sr variant=sr-ec -disabled !! wikitext {| |- | -{R|B}- |} -!! html +!! html/php +<table> + +<tr> +<td>Б}- +</td></tr></table> + +!! html/parsoid <table> <tr> @@ -17534,12 +18634,13 @@ Line two !! test Nesting tags, paragraphs on lines which begin with <div> -!! options -disabled !! wikitext <div></div><strong>A B</strong> -!! html +!! html/php+tidy +<p><strong>A</strong></p> +<p><strong>B</strong></p> +!! html/parsoid <div></div> <p><strong>A B</strong> @@ -17941,27 +19042,35 @@ comment <a href="/index.php?title=ABC3D%25_%2B%2B&action=edit&redlink=1" class="new" title="ABC3D% ++ (page does not exist)">ABC3D% ++</a> <a href="/index.php?title=ABC3D%25_%2B%2B&action=edit&redlink=1" class="new" title="ABC3D% ++ (page does not exist)">+%20</a> !! end +# Parsoid doesn't support this yet: see bug 73581 +# but it *should* omit the 'src' attribute if the image is bad. +# PHP side of tests was disabled in +# mediawiki/core:6bd31e7d95161a6e88fa86df60871051da997c3c +# because of issues in the PHP parserTests infrastructure +# (but the output below is indeed what the PHP side emits) !! test Bad images - basic functionality -!! options -disabled !! wikitext [[File:Bad.jpg]] -!! html +!! DISABLED/html/php +!! html/parsoid +<p><span class="mw-default-size" typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"bad-image","message":"This image is blacklisted in this context."}]}'><a href="./File:Bad.jpg"><img resource="./File:Bad.jpg" height="220" width="220"/></a></span></p> !! end !! test Bad images - bug 16039: text after bad image disappears -!! options -disabled !! wikitext Foo bar [[File:Bad.jpg]] Bar foo -!! html +!! DISABLED/html/php <p>Foo bar </p><p>Bar foo </p> +!! html/parsoid +<p>Foo bar +<span class="mw-default-size" typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"bad-image","message":"This image is blacklisted in this context."}]}'><a href="./File:Bad.jpg"><img resource="./File:Bad.jpg" height="220" width="220"/></a></span> +Bar foo</p> !! end !! test @@ -18097,6 +19206,82 @@ this is not the the title !! end !! test +Page status indicators: Empty name is invalid +!! options +showindicators +!! wikitext +<indicator name=" "></indicator> +<indicator></indicator> +!! html +<p><span class="error"><strong>Error:</strong> Page status indicators' <code>name</code> attribute must not be empty.</span> +<span class="error"><strong>Error:</strong> Page status indicators' <code>name</code> attribute must not be empty.</span> +</p> +!! end + +!! test +Page status indicators: Weird syntaxes that are okay +!! options +showindicators +!! wikitext +<indicator name="empty" /> +<indicator name></indicator> +!! html +empty= +name= +<p><br /> +</p> +!! end + +!! test +Page status indicators: Torture test +!! options +showindicators +!! wikitext +<indicator name="01">hello world</indicator> +<indicator name="02">[[Main Page]]</indicator> +<indicator name="03">[[File:Foobar.jpg|25px|link=]]</indicator> +<indicator name="04">[[File:Foobar.jpg|25px]]</indicator> +<indicator name="05">* foo +* bar</indicator> +<indicator name="06"><nowiki>foo</nowiki></indicator> +<indicator name="07"> Preformatted</indicator> +<indicator name="08"><div>Broken tag</indicator> +<indicator name="09">{| class=wikitable +| cell +|}</indicator> +<indicator name="10">Two + +paragraphs</indicator> +!! html +01=hello world +02=<a href="/wiki/Main_Page" title="Main Page">Main Page</a> +03=<img alt="Foobar.jpg" src="http://example.com/images/thumb/3/3a/Foobar.jpg/25px-Foobar.jpg" width="25" height="3" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/38px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/50px-Foobar.jpg 2x" /> +04=<a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/thumb/3/3a/Foobar.jpg/25px-Foobar.jpg" width="25" height="3" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/38px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/50px-Foobar.jpg 2x" /></a> +05=<ul><li> foo</li> +<li> bar</li></ul> + +06=foo +07=<pre>Preformatted +</pre> +08=<div>Broken tag</div> + +09=<table class="wikitable"> +<tr> +<td> cell +</td></tr></table> + +10=<p>Two +</p><p>paragraphs +</p> +<p><br /> +</p><p><br /> +</p><p><br /> +</p><p><br /> +</p><p><br /> +</p> +!! end + +!! test preload: check <noinclude> and <includeonly> !! options preload @@ -18138,18 +19323,22 @@ preload !! test Play a bit with r67090 and bug 3158 -!! options -disabled !! wikitext <div style="width:50% !important"> </div> <div style="width:50% !important"> </div> <div style="width:50% !important"> </div> <div style="border : solid;"> </div> -!! html -<div style="width:50% !important"> </div> -<div style="width:50% !important"> </div> -<div style="width:50% !important"> </div> -<div style="border : solid;"> </div> +!! html/php +<div style="width:50% !important"> </div> +<div style="width:50% !important"> </div> +<div style="width:50% !important"> </div> +<div style="border : solid;"> </div> + +!! html/parsoid +<div style="width:50% !important" data-parsoid='{"stx":"html"}'><span typeof="mw:Entity" data-parsoid='{"srcContent":" "}'> </span></div> +<div style="width:50% !important" data-parsoid='{"stx":"html","a":{"style":"width:50% !important"},"sa":{"style":"width:50%&nbsp;!important"}}'><span typeof="mw:Entity" data-parsoid='{"srcContent":" "}'> </span></div> +<div style="width:50% !important" data-parsoid='{"stx":"html","a":{"style":"width:50% !important"},"sa":{"style":"width:50%&#160;!important"}}'><span typeof="mw:Entity" data-parsoid='{"srcContent":" "}'> </span></div> +<div style="border : solid;" data-parsoid='{"stx":"html"}'><span typeof="mw:Entity" data-parsoid='{"srcContent":" "}'> </span></div> !! end @@ -18170,14 +19359,16 @@ percent-encoding and + signs in internal links (Bug 26410) !! wikitext [[User:+%]] [[Page+title%]] [[%+]] [[%+|%20]] [[%+ ]] [[%+r]] -[[%]] [[+]] [[image:%+abc%39|foo|[[bar]]]] +[[%]] [[+]] [[File:%+abc%39|foo|[[bar]]]] [[%33%45]] [[%33%45+]] -!! html +!! html/php <p><a href="/index.php?title=User:%2B%25&action=edit&redlink=1" class="new" title="User:+% (page does not exist)">User:+%</a> <a href="/index.php?title=Page%2Btitle%25&action=edit&redlink=1" class="new" title="Page+title% (page does not exist)">Page+title%</a> <a href="/index.php?title=%25%2B&action=edit&redlink=1" class="new" title="%+ (page does not exist)">%+</a> <a href="/index.php?title=%25%2B&action=edit&redlink=1" class="new" title="%+ (page does not exist)">%20</a> <a href="/index.php?title=%25%2B&action=edit&redlink=1" class="new" title="%+ (page does not exist)">%+ </a> <a href="/index.php?title=%25%2Br&action=edit&redlink=1" class="new" title="%+r (page does not exist)">%+r</a> <a href="/index.php?title=%25&action=edit&redlink=1" class="new" title="% (page does not exist)">%</a> <a href="/index.php?title=%2B&action=edit&redlink=1" class="new" title="+ (page does not exist)">+</a> <a href="/index.php?title=Special:Upload&wpDestFile=%25%2Babc9" class="new" title="File:%+abc9">bar</a> <a href="/index.php?title=3E&action=edit&redlink=1" class="new" title="3E (page does not exist)">3E</a> <a href="/index.php?title=3E%2B&action=edit&redlink=1" class="new" title="3E+ (page does not exist)">3E+</a> </p> +!! html/parsoid +<p><a rel="mw:WikiLink" href="User:+%" title="User:+%">User:+%</a> <a rel="mw:WikiLink" href="Page+title%" title="Page+title%">Page+title%</a> <a rel="mw:WikiLink" href="%+" title="%+">%+</a> <a rel="mw:WikiLink" href="%+" title="%+">%20</a> <a rel="mw:WikiLink" href="%+" title="%+">%+ </a> <a rel="mw:WikiLink" href="%+r" title="%+r">%+r</a> <a rel="mw:WikiLink" href="%" title="%">%</a> <a rel="mw:WikiLink" href="+" title="+">+</a> <span class="mw-default-size" typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}],"caption":"[[bar]]"}'><a href="./File:%+abc9"><img resource="./File:%25+abc9" src="./Special:FilePath/%+abc9" height="220" width="220"/></a></span> <a rel="mw:WikiLink" href="3E" title="3E">3E</a> <a rel="mw:WikiLink" href="3E+" title="3E+">3E+</a></p> !! end !! test @@ -18185,13 +19376,15 @@ Special characters in embedded file links (bug 27679) !! wikitext [[File:Contains & ampersand.jpg]] [[File:Does not exist.jpg|Title with & ampersand]] -!! html +!! html/php <p><a href="/index.php?title=Special:Upload&wpDestFile=Contains_%26_ampersand.jpg" class="new" title="File:Contains & ampersand.jpg">File:Contains & ampersand.jpg</a> <a href="/index.php?title=Special:Upload&wpDestFile=Does_not_exist.jpg" class="new" title="File:Does not exist.jpg">Title with & ampersand</a> </p> +!! html/parsoid +<p><span class="mw-default-size" typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}]}'><a href="./File:Contains_&_ampersand.jpg"><img resource="./File:Contains_&_ampersand.jpg" src="./Special:FilePath/Contains_&_ampersand.jpg" height="220" width="220"/></a></span> +<span class="mw-default-size" typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}],"caption":"Title with & ampersand"}'><a href="./File:Does_not_exist.jpg"><img resource="./File:Does_not_exist.jpg" src="./Special:FilePath/Does_not_exist.jpg" height="220" width="220"/></a></span></p> !! end - !! test Confirm that 'apos' named character reference doesn't make it to output (not legal in HTML 4) !! wikitext @@ -18383,6 +19576,7 @@ __TOC__ <h2><span class="mw-headline" id="Quote"><blockquote>Quote</blockquote></span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Main_Page&action=edit&section=1" title="Edit section: Quote">edit</a><span class="mw-editsection-bracket">]</span></span></h2> !! html+tidy +<p></p> <div id="toc" class="toc"> <div id="toctitle"> <h2>Contents</h2> @@ -18391,6 +19585,7 @@ __TOC__ <li class="toclevel-1 tocsection-1"><a href="#Quote"><span class="tocnumber">1</span> <span class="toctext">Quote</span></a></li> </ul> </div> +<p></p> <h2><span class="mw-headline" id="Quote"></span></h2> <blockquote> <p><span class="mw-headline" id="Quote">Quote</span></p> @@ -18439,6 +19634,7 @@ __TOC__ <h2><span class="mw-headline" id="Foo_Bar_2"><i>Foo</i> <blockquote>Bar</blockquote></span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&action=edit&section=2" title="Edit section: Foo Bar">edit</a><span class="mw-editsection-bracket">]</span></span></h2> !! html+tidy +<p></p> <div id="toc" class="toc"> <div id="toctitle"> <h2>Contents</h2> @@ -18448,6 +19644,7 @@ __TOC__ <li class="toclevel-1 tocsection-2"><a href="#Foo_Bar_2"><span class="tocnumber">2</span> <span class="toctext"><i>Foo</i> Bar</span></a></li> </ul> </div> +<p></p> <h2><span class="mw-headline" id="Foo_Bar"><i>Foo</i> <b>Bar</b></span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&action=edit&section=1" title="Edit section: Foo Bar">edit</a><span class="mw-editsection-bracket">]</span></span></h2> <h2><span class="mw-headline" id="Foo_Bar_2"><i>Foo</i></span></h2> <blockquote> @@ -18508,6 +19705,53 @@ __TOC__ !! end +!! test +Bug 72884: bdi element in ToC +!! wikitext +__TOC__ +== <bdi>test</bdi> == +!! html +<div id="toc" class="toc"><div id="toctitle"><h2>Contents</h2></div> +<ul> +<li class="toclevel-1 tocsection-1"><a href="#test"><span class="tocnumber">1</span> <span class="toctext"><bdi>test</bdi></span></a></li> +</ul> +</div> + +<h2><span class="mw-headline" id="test"><bdi>test</bdi></span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&action=edit&section=1" title="Edit section: test">edit</a><span class="mw-editsection-bracket">]</span></span></h2> + +!! end + +# Note that the html output does not have the <p></p>, but the +# html+tidy output *does*. This is because the empty <p></p> is +# removed by the sanitizer, but only when tidy is *not* enabled (!). +!! test +Empty <p> tag in TOC, removed by Sanitizer (T92892) +!! wikitext +__TOC__ +== x == +!! html +<div id="toc" class="toc"><div id="toctitle"><h2>Contents</h2></div> +<ul> +<li class="toclevel-1 tocsection-1"><a href="#x"><span class="tocnumber">1</span> <span class="toctext">x</span></a></li> +</ul> +</div> + +<h2><span class="mw-headline" id="x">x</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&action=edit&section=1" title="Edit section: x">edit</a><span class="mw-editsection-bracket">]</span></span></h2> + +!! html+tidy +<p></p> +<div id="toc" class="toc"> +<div id="toctitle"> +<h2>Contents</h2> +</div> +<ul> +<li class="toclevel-1 tocsection-1"><a href="#x"><span class="tocnumber">1</span> <span class="toctext">x</span></a></li> +</ul> +</div> +<p></p> +<h2><span class="mw-headline" id="x">x</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&action=edit&section=1" title="Edit section: x">edit</a><span class="mw-editsection-bracket">]</span></span></h2> +!! end + !! article MediaWiki:Bug32057 !! text @@ -18677,7 +19921,7 @@ File:foobar.jpg|caption|alt=galleryalt|link=InterWikiLink !! html <ul class="gallery mw-gallery-traditional"> <li class="gallerybox" style="width: 155px"><div style="width: 155px"> - <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/InterWikiLink"><img alt="galleryalt" src="http://example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" width="120" height="14" /></a></div></div> + <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/InterWikiLink"><img alt="galleryalt" src="http://example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" width="120" height="14" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/240px-Foobar.jpg 2x" /></a></div></div> <div class="gallerytext"> <p>caption </p> @@ -18696,7 +19940,7 @@ File:foobar.jpg|caption|alt=galleryalt|link=http://www.example.org !! html <ul class="gallery mw-gallery-traditional"> <li class="gallerybox" style="width: 155px"><div style="width: 155px"> - <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="http://www.example.org"><img alt="galleryalt" src="http://example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" width="120" height="14" /></a></div></div> + <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="http://www.example.org"><img alt="galleryalt" src="http://example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" width="120" height="14" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/240px-Foobar.jpg 2x" /></a></div></div> <div class="gallerytext"> <p>caption </p> @@ -18715,7 +19959,7 @@ File:foobar.jpg|caption|alt=galleryalt|link=" onclick="alert('malicious javascri !! html <ul class="gallery mw-gallery-traditional"> <li class="gallerybox" style="width: 155px"><div style="width: 155px"> - <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/%22_onclick%3D%22alert(%27malicious_javascript_code!%27);"><img alt="galleryalt" src="http://example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" width="120" height="14" /></a></div></div> + <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/%22_onclick%3D%22alert(%27malicious_javascript_code!%27);"><img alt="galleryalt" src="http://example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" width="120" height="14" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/240px-Foobar.jpg 2x" /></a></div></div> <div class="gallerytext"> <p>caption </p> @@ -18734,7 +19978,7 @@ File:foobar.jpg|link=< !! html <ul class="gallery mw-gallery-traditional"> <li class="gallerybox" style="width: 155px"><div style="width: 155px"> - <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" width="120" height="14" /></a></div></div> + <div class="thumb" style="width: 150px;"><div style="margin:68px auto;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg" width="120" height="14" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/240px-Foobar.jpg 2x" /></a></div></div> <div class="gallerytext"> </div> </div></li> @@ -18858,13 +20102,13 @@ parsoid=wt2html,wt2wt #### Parsoid-specific functionality tests #### ----------------------------------------------------------------- -# Bug 63642: Formatting elt fixup is cleaned up. +# Bug 63642/66749: Formatting elt fixup around images is cleaned up. # We know wt2wt will fail, but we expect selser to pass. # Due to the nature of our testing, wt2wt and selser tests will enter the # blacklist and we'll catch selser regressions based on changes to the # blacklist entries for selser tests. !! test -Bad treebuilder fixup of formatting elt is cleaned up +1. Bad treebuilder fixup of formatting elt is cleaned up !! options parsoid=wt2html,wt2wt !! wikitext @@ -18877,12 +20121,28 @@ parsoid=wt2html,wt2wt !! html/parsoid <table> <tbody><tr><td> -<p><small></small></p> -<figure class="mw-default-size mw-halign-right" typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"></a><figcaption><small>Test</small></figcaption></figure> -<p></p></td></tr> +<small> +<figure class="mw-default-size mw-halign-right" typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="220" width="1941"/></a><figcaption>Test</figcaption></figure> +</small> +</td></tr> </tbody></table> !! end +!! test +2. Bad treebuilder fixup of formatting elt is cleaned up +!! options +parsoid=wt2html,wt2wt +!! wikitext +'''foo[[File:Foobar.jpg|thumb|caption]]bar''' + +<small>[[Image:Foobar.jpg|right|300px]]</small> +!! html/parsoid +<p><b>foo</b></p> +<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption><b>caption</b></figcaption></figure> +<p><b>bar</b></p> +<small><figure class="mw-halign-right" typeof="mw:Image"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="34" width="300"/></a></figure></small> +!! end + #### ---------------------------------------------------------------- #### Parsoid-only testing of Parsoid's impl of <ref> and <references> #### tags. Parsoid's output for these tags differs from that of the @@ -18897,10 +20157,16 @@ parsoid A <ref>foo</ref> B <ref name="x">foo</ref> C <ref name="y" /> +<references /> !! html -<p>A <span about="#mwt1" class="reference" data-mw='{"name":"ref","body":{"html":"foo"},"attrs":{}}' id="cite_ref-1-0" rel="dc:references" typeof="mw:Extension/ref"><a href="#cite_note-1">[1]</a></span> -B <span about="#mwt2" class="reference" data-mw='{"name":"ref","body":{"html":"foo"},"attrs":{"name":"x"}}' id="cite_ref-x-2-0" rel="dc:references" typeof="mw:Extension/ref"><a href="#cite_note-x-2">[2]</a></span> -C <span about="#mwt3" class="reference" data-mw='{"name":"ref","attrs":{"name":"y"}}' id="cite_ref-y-3-0" rel="dc:references" typeof="mw:Extension/ref"><a href="#cite_note-y-3">[3]</a></span></p> +<p>A <span about="#mwt2" class="reference" id="cite_ref-1" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-1"},"attrs":{}}'><a href="#cite_note-1">[1]</a></span> +B <span about="#mwt4" class="reference" id="cite_ref-x_2-0" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-x-2"},"attrs":{"name":"x"}}'><a href="#cite_note-x-2">[2]</a></span> +C <span about="#mwt6" class="reference" id="cite_ref-y_3-0" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","attrs":{"name":"y"}}'><a href="#cite_note-y-3">[3]</a></span></p> +<ol class="references" typeof="mw:Extension/references" about="#mwt8" data-mw='{"name":"references","attrs":{}}'> +<li about="#cite_note-1" id="cite_note-1"><span rel="mw:referencedBy"><a href="#cite_ref-1">↑</a></span> <span id="mw-reference-text-cite_note-1" class="mw-reference-text">foo</span></li> +<li about="#cite_note-x-2" id="cite_note-x-2"><span rel="mw:referencedBy"><a href="#cite_ref-x_2-0">↑</a></span> <span id="mw-reference-text-cite_note-x-2" class="mw-reference-text">foo</span></li> +<li about="#cite_note-y-3" id="cite_note-y-3"><span rel="mw:referencedBy"><a href="#cite_ref-y_3-0">↑</a></span> <span id="mw-reference-text-cite_note-y-3" class="mw-reference-text"></span></li> +</ol> !!end !!test @@ -18910,9 +20176,13 @@ parsoid !! wikitext A <ref name="x">foo</ref> B <ref name="x" /> +<references /> !! html -<p>A <span about="#mwt1" class="reference" data-mw='{"name":"ref","body":{"html":"foo"},"attrs":{"name":"x"}}' id="cite_ref-x-1-0" rel="dc:references" typeof="mw:Extension/ref"><a href="#cite_note-x-1">[1]</a></span> -B <span about="#mwt2" class="reference" data-mw='{"name":"ref","attrs":{"name":"x"}}' id="cite_ref-x-1-1" rel="dc:references" typeof="mw:Extension/ref"><a href="#cite_note-x-1">[1]</a></span></p> +<p>A <span about="#mwt2" class="reference" id="cite_ref-x_1-0" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-x-1"},"attrs":{"name":"x"}}'><a href="#cite_note-x-1">[1]</a></span> +B <span about="#mwt4" class="reference" id="cite_ref-x_1-1" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","attrs":{"name":"x"}}'><a href="#cite_note-x-1">[1]</a></span></p> +<ol class="references" typeof="mw:Extension/references" about="#mwt6" data-mw='{"name":"references","attrs":{}}'> +<li about="#cite_note-x-1" id="cite_note-x-1"><span rel="mw:referencedBy">↑ <a href="#cite_ref-x_1-0">1.0</a> <a href="#cite_ref-x_1-1">1.1</a></span> <span id="mw-reference-text-cite_note-x-1" class="mw-reference-text">foo</span></li> +</ol> !!end !!test @@ -18923,21 +20193,29 @@ parsoid A <ref name="x">foo</ref> B <ref name=" x " /> C <ref name= x /> +<references /> !! html -<p>A <span about="#mwt1" class="reference" data-mw='{"name":"ref","body":{"html":"foo"},"attrs":{"name":"x"}}' id="cite_ref-x-1-0" rel="dc:references" typeof="mw:Extension/ref"><a href="#cite_note-x-1">[1]</a></span> -B <span about="#mwt2" class="reference" data-mw='{"name":"ref","attrs":{"name":"x"}}' id="cite_ref-x-1-1" rel="dc:references" typeof="mw:Extension/ref"><a href="#cite_note-x-1">[1]</a></span> -C <span about="#mwt3" class="reference" data-mw='{"name":"ref","attrs":{"name":"x"}}' id="cite_ref-x-1-2" rel="dc:references" typeof="mw:Extension/ref"><a href="#cite_note-x-1">[1]</a></span></p> +<p>A <span about="#mwt2" class="reference" id="cite_ref-x_1-0" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-x-1"},"attrs":{"name":"x"}}'><a href="#cite_note-x-1">[1]</a></span> +B <span about="#mwt4" class="reference" id="cite_ref-x_1-1" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","attrs":{"name":"x"}}'><a href="#cite_note-x-1">[1]</a></span> +C <span about="#mwt6" class="reference" id="cite_ref-x_1-2" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","attrs":{"name":"x"}}'><a href="#cite_note-x-1">[1]</a></span></p> +<ol class="references" typeof="mw:Extension/references" about="#mwt8" data-mw='{"name":"references","attrs":{}}'> +<li about="#cite_note-x-1" id="cite_note-x-1"><span rel="mw:referencedBy">↑ <a href="#cite_ref-x_1-0">1.0</a> <a href="#cite_ref-x_1-1">1.1</a> <a href="#cite_ref-x_1-2">1.2</a></span> <span id="mw-reference-text-cite_note-x-1" class="mw-reference-text">foo</span></li> +</ol> !!end +# NOTE: constructor is a predefined property in JS and constructor as a ref-name can clash with it if not handled properly) !!test Ref: 4. 'constructor' should be accepted as a valid ref-name -(NOTE: constructor is a predefined property in JS and constructor as a ref-name can clash with it if not handled properly) !!options parsoid !! wikitext A <ref name="constructor">foo</ref> +<references /> !! html -<p>A <span about="#mwt1" class="reference" data-mw='{"name":"ref","body":{"html":"foo"},"attrs":{"name":"constructor"}}' id="cite_ref-constructor-1-0" rel="dc:references" typeof="mw:Extension/ref"><a href="#cite_note-constructor-1">[1]</a></span></p> +<p>A <span about="#mwt2" class="reference" id="cite_ref-constructor_1-0" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-constructor-1"},"attrs":{"name":"constructor"}}'><a href="#cite_note-constructor-1">[1]</a></span></p> +<ol class="references" typeof="mw:Extension/references" about="#mwt4" data-mw='{"name":"references","attrs":{}}'> +<li about="#cite_note-constructor-1" id="cite_note-constructor-1"><span rel="mw:referencedBy"><a href="#cite_ref-constructor_1-0">↑</a></span> <span id="mw-reference-text-cite_note-constructor-1" class="mw-reference-text">foo</span></li> +</ol> !!end !!test @@ -18951,11 +20229,11 @@ A <ref> <references /> !! html -<p>A <span about="#mwt2" class="reference" data-mw='{"name":"ref","body":{"html":"This is a <b data-parsoid='{\"dsr\":[19,40,3,3]}'><a rel=\"mw:WikiLink\" href=\"./Bolded_link\" title=\"Bolded link\" data-parsoid='{\"stx\":\"simple\",\"a\":{\"href\":\"./Bolded_link\"},\"sa\":{\"href\":\"bolded link\"},\"dsr\":[22,37,2,2]}'>bolded link</a></b> and this is a <span about=\"#mwt3\" typeof=\"mw:Transclusion\" data-mw='{\"parts\":[{\"template\":{\"target\":{\"wt\":\"echo\",\"href\":\"./Template:Echo\"},\"params\":{\"1\":{\"wt\":\"transclusion\"}},\"i\":0}}]}' data-parsoid='{\"pi\":[[{\"k\":\"1\",\"spc\":[\"\",\"\",\"\",\"\"]}]],\"dsr\":[55,76,null,null]}'>transclusion</span>\n"},"attrs":{}}' id="cite_ref-1-0" rel="dc:references" typeof="mw:Extension/ref"><a href="#cite_note-1">[1]</a></span></p> +<p>A <span about="#mwt2" class="reference" id="cite_ref-1" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-1"},"attrs":{}}'><a href="#cite_note-1">[1]</a></span></p> -<ol class="references" typeof="mw:Extension/references" about="#mwt4" data-mw='{"name":"references","attrs":{}}'> -<li about="#cite_note-1" id="cite_note-1"><span rel="mw:referencedBy"><a href="#cite_ref-1-0">↑</a></span> This is a <b><a rel="mw:WikiLink" href="./Bolded_link" title="Bolded link">bolded link</a></b> and this is a <span about="#mwt3" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"transclusion"}},"i":0}}]}'>transclusion</span> -</li> +<ol class="references" typeof="mw:Extension/references" about="#mwt5" data-mw='{"name":"references","attrs":{}}'> +<li about="#cite_note-1" id="cite_note-1"><span rel="mw:referencedBy"><a href="#cite_ref-1">↑</a></span> <span id="mw-reference-text-cite_note-1" class="mw-reference-text">This is a <b><a rel="mw:WikiLink" href="Bolded_link" title="Bolded link">bolded link</a></b> and this is a <span about="#mwt3" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"transclusion"}},"i":0}}]}'>transclusion</span> +</span></li> </ol> !!end @@ -18972,13 +20250,13 @@ A <ref> <references /> !! html -<p>A <span about="#mwt1" class="reference" data-mw='{"name":"ref","body":{"html":"foo\n bar\n baz\n"},"attrs":{}}' id="cite_ref-1-0" rel="dc:references" typeof="mw:Extension/ref"><a href="#cite_note-1">[1]</a></span></p> +<p>A <span about="#mwt2" class="reference" id="cite_ref-1" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-1"},"attrs":{}}'><a href="#cite_note-1">[1]</a></span></p> -<ol class="references" typeof="mw:Extension/references" about="#mwt3" data-mw='{"name":"references","attrs":{}}'> -<li about="#cite_note-1" id="cite_note-1"><span rel="mw:referencedBy"><a href="#cite_ref-1-0">↑</a></span> foo +<ol class="references" typeof="mw:Extension/references" about="#mwt4" data-mw='{"name":"references","attrs":{}}'> +<li about="#cite_note-1" id="cite_note-1"><span rel="mw:referencedBy"><a href="#cite_ref-1">↑</a></span> <span id="mw-reference-text-cite_note-1" class="mw-reference-text">foo bar baz -</li> +</span></li> </ol> !!end @@ -19002,10 +20280,10 @@ booz <references /> !! html -<p>A <span about="#mwt1" class="reference" data-mw='{"name":"ref","body":{"html":"foo\n\nbar\n\n\nbaz\n\n\n\nbooz\n"},"attrs":{}}' id="cite_ref-1-0" rel="dc:references" typeof="mw:Extension/ref"><a href="#cite_note-1">[1]</a></span></p> +<p>A <span about="#mwt2" class="reference" id="cite_ref-1" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-1"},"attrs":{}}'><a href="#cite_note-1">[1]</a></span></p> -<ol about="#mwt2" class="references" typeof="mw:Extension/references" data-mw='{"name":"references","attrs":{}}'> -<li about="#cite_note-1" id="cite_note-1"><span rel="mw:referencedBy"><a href="#cite_ref-1-0">↑</a></span> foo +<ol class="references" typeof="mw:Extension/references" about="#mwt4" data-mw='{"name":"references","attrs":{}}'> +<li about="#cite_note-1" id="cite_note-1"><span rel="mw:referencedBy"><a href="#cite_ref-1">↑</a></span> <span id="mw-reference-text-cite_note-1" class="mw-reference-text">foo bar @@ -19015,7 +20293,7 @@ baz booz -</li> +</span></li> </ol> !!end @@ -19028,9 +20306,9 @@ A <ref> foo {{echo|</ref> B C}} <references /> !! html -<p>A <span class="reference" data-mw="{"name":"ref","body":{"html":"foo <span typeof=\"mw:Nowiki\" data-parsoid='{\"src\":\"{{\",\"dsr\":[12,14,0,0]}'>{{</span>echo|"},"attrs":{}}" id="cite_ref-1-0" rel="dc:references" typeof="mw:Extension/ref"><a href="#cite_note-1">[1]</a></span> B C<span typeof="mw:Nowiki">}}</span></p> -<ol class="references" typeof="mw:Extension/references" data-mw="{"name":"references","attrs":{}}"> -<li id="cite_note-1"><span rel="mw:referencedBy"><a href="#cite_ref-1-0">↑</a></span> foo <span typeof="mw:Nowiki">{{</span>echo|</li> +<p>A <span about="#mwt2" class="reference" id="cite_ref-1" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-1"},"attrs":{}}'><a href="#cite_note-1">[1]</a></span> B C<span typeof="mw:Nowiki">}}</span></p> +<ol class="references" typeof="mw:Extension/references" about="#mwt4" data-mw='{"name":"references","attrs":{}}'> +<li about="#cite_note-1" id="cite_note-1"><span rel="mw:referencedBy"><a href="#cite_ref-1">↑</a></span> <span id="mw-reference-text-cite_note-1" class="mw-reference-text">foo <span typeof="mw:Nowiki" data-parsoid='{"src":"{{","dsr":[12,14,0,0]}'>{{</span>echo|</span></li> </ol> !!end @@ -19042,9 +20320,9 @@ parsoid A <ref> foo <!--</ref> B C <references /> !! html -<p>A <span class="reference" data-mw='{"name":"ref","body":{"html":"foo <!---->"},"attrs":{}}' id="cite_ref-1-0" rel="dc:references" typeof="mw:Extension/ref"><a href="#cite_note-1">[1]</a></span> B C</p> -<ol class="references" typeof="mw:Extension/references" data-mw='{"name":"references","attrs":{}}'> -<li id="cite_note-1"><span rel="mw:referencedBy"><a href="#cite_ref-1-0">↑</a></span> foo </li> +<p>A <span about="#mwt2" class="reference" id="cite_ref-1" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-1"},"attrs":{}}'><a href="#cite_note-1">[1]</a></span> B C</p> +<ol class="references" typeof="mw:Extension/references" about="#mwt4" data-mw='{"name":"references","attrs":{}}'> +<li about="#cite_note-1" id="cite_note-1"><span rel="mw:referencedBy"><a href="#cite_ref-1">↑</a></span> <span id="mw-reference-text-cite_note-1" class="mw-reference-text">foo <!----></span></li> </ol> !!end @@ -19057,11 +20335,11 @@ A <ref> <b> foo </ref> B C <references /> !! html -<p>A <span about="#mwt2" class="reference" data-mw='{"name":"ref","body":{"html":"<b data-parsoid='{\"stx\":\"html\",\"autoInsertedEnd\":true,\"dsr\":[8,16,3,0]}'> foo </b>"},"attrs":{}}' id="cite_ref-1-0" rel="dc:references" typeof="mw:Extension/ref" data-parsoid='{"src":"<ref> <b> foo </ref>"}'><a href="#cite_note-1">[1]</a></span> B C</p> +<p>A <span about="#mwt2" class="reference" id="cite_ref-1" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-1"},"attrs":{}}'><a href="#cite_note-1">[1]</a></span> B C</p> -<ol class="references" typeof="mw:Extension/references" about="#mwt4" data-parsoid='{"src":"<references />"}' data-mw='{"name":"references","attrs":{}}'> -<li about="#cite_note-1" id="cite_note-1" data-parsoid="{}"><span rel="mw:referencedBy"><a href="#cite_ref-1-0">↑</a></span> <b data-parsoid='{"stx":"html","autoInsertedEnd":true}'> foo </b></li> +<ol class="references" typeof="mw:Extension/references" about="#mwt4" data-mw='{"name":"references","attrs":{}}'> +<li about="#cite_note-1" id="cite_note-1"><span rel="mw:referencedBy"><a href="#cite_ref-1">↑</a></span> <span id="mw-reference-text-cite_note-1" class="mw-reference-text"><b data-parsoid='{"stx":"html","autoInsertedEnd":true}'> foo </b></span></li> </ol> !!end @@ -19072,9 +20350,14 @@ parsoid !! wikitext A <ref>foo</ref> B C <ref>bar</ref> D +<references /> !! html -<p>A <span about="#mwt2" class="reference" data-mw='{"name":"ref","body":{"html":"foo"},"attrs":{}}' id="cite_ref-1-0" rel="dc:references" typeof="mw:Extension/ref" data-parsoid='{"src":"<ref>foo</ref>"}'><a href="#cite_note-1">[1]</a></span> B -C <span about="#mwt4" class="reference" data-mw='{"name":"ref","body":{"html":"bar"},"attrs":{}}' id="cite_ref-2-0" rel="dc:references" typeof="mw:Extension/ref" data-parsoid='{"src":"<ref>bar</ref>"}'><a href="#cite_note-2">[2]</a></span> D</p> +<p>A <span about="#mwt2" class="reference" id="cite_ref-1" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-1"},"attrs":{}}'><a href="#cite_note-1">[1]</a></span> B +C <span about="#mwt4" class="reference" id="cite_ref-2" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-2"},"attrs":{}}'><a href="#cite_note-2">[2]</a></span> D</p> +<ol class="references" typeof="mw:Extension/references" about="#mwt6" data-mw='{"name":"references","attrs":{}}'> +<li about="#cite_note-1" id="cite_note-1"><span rel="mw:referencedBy"><a href="#cite_ref-1">↑</a></span> <span id="mw-reference-text-cite_note-1" class="mw-reference-text">foo</span></li> +<li about="#cite_note-2" id="cite_note-2"><span rel="mw:referencedBy"><a href="#cite_ref-2">↑</a></span> <span id="mw-reference-text-cite_note-2" class="mw-reference-text">bar</span></li> +</ol> !!end !!test @@ -19088,15 +20371,18 @@ b<!--the newline at the end of this line stays inside the p-tag--> <ref /> <ref /> c +<references /> !! html <p><!--the newline at the end of this line moves out of the p-tag-->a</p> -<p>b<!--the newline at the end of this line stays inside the p-tag--> <span about="#mwt1" class="reference" data-mw='{"name":"ref","attrs":{}}' id="cite_ref-1-0" rel="dc:references" typeof="mw:Extension/ref"><a href="#cite_note-1">[1]</a></span> -<span about="#mwt2" class="reference" data-mw='{"name":"ref","attrs":{}}' id="cite_ref-2-0" rel="dc:references" typeof="mw:Extension/ref"><a href="#cite_note-2">[2]</a></span></p> - +<p>b<!--the newline at the end of this line stays inside the p-tag--> <span about="#mwt2" class="reference" id="cite_ref-1" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","attrs":{}}'><a href="#cite_note-1">[1]</a></span> +<span about="#mwt4" class="reference" id="cite_ref-2" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","attrs":{}}'><a href="#cite_note-2">[2]</a></span></p> <p>c</p> +<ol class="references" typeof="mw:Extension/references" about="#mwt6" data-mw='{"name":"references","attrs":{}}'> +<li about="#cite_note-1" id="cite_note-1"><span rel="mw:referencedBy"><a href="#cite_ref-1">↑</a></span> <span id="mw-reference-text-cite_note-1" class="mw-reference-text"></span></li> +<li about="#cite_note-2" id="cite_note-2"><span rel="mw:referencedBy"><a href="#cite_ref-2">↑</a></span> <span id="mw-reference-text-cite_note-2" class="mw-reference-text"></span></li></ol> !!end !!test @@ -19107,9 +20393,15 @@ parsoid <ref>foo</ref> A <ref>bar </ref> B +<references /> !! html -<p><span about="#mwt1" class="reference" data-mw='{"name":"ref","body":{"html":"foo"},"attrs":{}}' id="cite_ref-1-0" rel="dc:references" typeof="mw:Extension/ref"><a href="#cite_note-1">[1]</a></span> A -<span about="#mwt2" class="reference" data-mw='{"name":"ref","body":{"html":"bar\n"},"attrs":{}}' id="cite_ref-2-0" rel="dc:references" typeof="mw:Extension/ref"><a href="#cite_note-2">[2]</a></span> B</p> +<p><span about="#mwt2" class="reference" id="cite_ref-1" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-1"},"attrs":{}}'><a href="#cite_note-1">[1]</a></span> A +<span about="#mwt4" class="reference" id="cite_ref-2" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-2"},"attrs":{}}'><a href="#cite_note-2">[2]</a></span> B</p> +<ol class="references" typeof="mw:Extension/references" about="#mwt6" data-mw='{"name":"references","attrs":{}}'> +<li about="#cite_note-1" id="cite_note-1"><span rel="mw:referencedBy"><a href="#cite_ref-1">↑</a></span> <span id="mw-reference-text-cite_note-1" class="mw-reference-text">foo</span></li> +<li about="#cite_note-2" id="cite_note-2"><span rel="mw:referencedBy"><a href="#cite_ref-2">↑</a></span> <span id="mw-reference-text-cite_note-2" class="mw-reference-text">bar +</span></li> +</ol> !!end !!test @@ -19121,10 +20413,10 @@ parsoid <references /> !! html -<p><span about="#mwt2" class="reference" data-mw='{"name":"ref","body":{"html":"foo &lt;ref>bar&lt;/ref> baz"},"attrs":{}}' id="cite_ref-1-0" rel="dc:references" typeof="mw:Extension/ref" data-parsoid='{"src":"<ref>foo <ref>bar</ref> baz</ref>"}'><a href="#cite_note-1">[1]</a></span></p> - -<ol class="references" typeof="mw:Extension/references" about="#mwt5" data-parsoid='{"src":"<references />"}' data-mw='{"name":"references","attrs":{}}'> -<li about="#cite_note-1" id="cite_note-1" data-parsoid="{}"><span rel="mw:referencedBy"><a href="#cite_ref-1-0">↑</a></span> foo <ref>bar</ref> baz</li> +<p><span about="#mwt2" class="reference" id="cite_ref-1" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-1"},"attrs":{}}'><a href="#cite_note-1">[1]</a></span> +</p> +<ol class="references" typeof="mw:Extension/references" about="#mwt5" data-mw='{"name":"references","attrs":{}}'> +<li about="#cite_note-1" id="cite_note-1"><span rel="mw:referencedBy"><a href="#cite_ref-1">↑</a></span> <span id="mw-reference-text-cite_note-1" class="mw-reference-text">foo <ref>bar</ref> baz</span></li> </ol> !!end @@ -19138,10 +20430,10 @@ B1 <ref name="b" /> B2 <ref name="b">bar</ref> <references /> !! html -<p>A1 <span about="#mwt3" class="reference" data-mw='{"name":"ref","body":{"html":"foo"},"attrs":{"name":"a"}}' id="cite_ref-a-1-0" rel="dc:references" typeof="mw:Extension/ref"><a href="#cite_note-a-1">[1]</a></span> A2 <span about="#mwt4" class="reference" data-mw='{"name":"ref","attrs":{"name":"a"}}' id="cite_ref-a-1-1" rel="dc:references" typeof="mw:Extension/ref"><a href="#cite_note-a-1">[1]</a></span> -B1 <span about="#mwt7" class="reference" data-mw='{"name":"ref","attrs":{"name":"b"}}' id="cite_ref-b-2-0" rel="dc:references" typeof="mw:Extension/ref"><a href="#cite_note-b-2">[2]</a></span> B2 <span about="#mwt8" class="reference" data-mw='{"name":"ref","body":{"html":"bar"},"attrs":{"name":"b"}}' id="cite_ref-b-2-1" rel="dc:references" typeof="mw:Extension/ref"><a href="#cite_note-b-2">[2]</a></span></p> +<p>A1 <span about="#mwt3" class="reference" id="cite_ref-a_1-0" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-a-1"},"attrs":{"name":"a"}}'><a href="#cite_note-a-1">[1]</a></span> A2 <span about="#mwt4" class="reference" id="cite_ref-a_1-1" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","attrs":{"name":"a"}}'><a href="#cite_note-a-1">[1]</a></span> +B1 <span about="#mwt7" class="reference" id="cite_ref-b_2-0" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","attrs":{"name":"b"}}'><a href="#cite_note-b-2">[2]</a></span> B2 <span about="#mwt8" class="reference" id="cite_ref-b_2-1" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-b-2"},"attrs":{"name":"b"}}'><a href="#cite_note-b-2">[2]</a></span></p> -<ol about="#mwt10" class="references" typeof="mw:Extension/references" data-mw='{"name":"references","attrs":{}}'><li about="#cite_note-a-1" id="cite_note-a-1"><span rel="mw:referencedBy">↑ <a href="#cite_ref-a-1-0">1.0</a> <a href="#cite_ref-a-1-1">1.1</a></span> foo</li><li about="#cite_note-b-2" id="cite_note-b-2"><span rel="mw:referencedBy">↑ <a href="#cite_ref-b-2-0">2.0</a> <a href="#cite_ref-b-2-1">2.1</a></span> bar</li> +<ol class="references" typeof="mw:Extension/references" about="#mwt10" data-mw='{"name":"references","attrs":{}}'><li about="#cite_note-a-1" id="cite_note-a-1"><span rel="mw:referencedBy">↑ <a href="#cite_ref-a_1-0">1.0</a> <a href="#cite_ref-a_1-1">1.1</a></span> <span id="mw-reference-text-cite_note-a-1" class="mw-reference-text">foo</span></li><li about="#cite_note-b-2" id="cite_note-b-2"><span rel="mw:referencedBy">↑ <a href="#cite_ref-b_2-0">2.0</a> <a href="#cite_ref-b_2-1">2.1</a></span> <span id="mw-reference-text-cite_note-b-2" class="mw-reference-text">bar</span></li> </ol> !!end @@ -19155,10 +20447,78 @@ A <ref >foo</ref > <references /> !! html -<p>A <span class="reference" data-mw='{"name":"ref","body":{"html":"foo"},"attrs":{}}' id="cite_ref-1-0" rel="dc:references" typeof="mw:Extension/ref"><a href="#cite_note-1">[1]</a></span></p> +<p>A <span about="#mwt2" class="reference" id="cite_ref-1" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-1"},"attrs":{}}'><a href="#cite_note-1">[1]</a></span></p> +<ol class="references" typeof="mw:Extension/references" about="#mwt4" data-mw='{"name":"references","attrs":{}}'> +<li about="#cite_note-1" id="cite_note-1"><span rel="mw:referencedBy"><a href="#cite_ref-1">↑</a></span> <span id="mw-reference-text-cite_note-1" class="mw-reference-text">foo</span></li></ol> +!!end + +!!test +Ref: 17. Generate valid HTML5 id/about attributes +!!options +parsoid +!!wikitext +<ref name="a b">foo</ref> + +<references /> +!!html +<p><span class="reference" id="cite_ref-a_b_1-0" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-a_b-1"},"attrs":{"name":"a b"}}'><a href="#cite_note-a_b-1">[1]</a></span> +</p> + +<ol class="references" typeof="mw:Extension/references" about="#mwt4" data-mw='{"name":"references","attrs":{}}'> +<li about="#cite_note-a_b-1" id="cite_note-a_b-1"><span rel="mw:referencedBy"><a href="#cite_ref-a_b_1-0">↑</a></span> <span id="mw-reference-text-cite_note-a_b-1" class="mw-reference-text">foo</span></li> +</ol> +!!end + +!!test +Ref: 18. T58916: Extension attributes should be parsed as plain text +!!options +parsoid +!!wikitext +<ref name="{{echo|a}}">foo</ref> + +<references /> +!!html +<p><span class="reference" id="cite_ref-.7B.7Becho.7Ca.7D.7D_1-0" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-.7B.7Becho.7Ca.7D.7D-1"},"attrs":{"name":"{{echo|a}}"}}'><a href="#cite_note-.7B.7Becho.7Ca.7D.7D-1">[1]</a></span> +</p> + +<ol class="references" typeof="mw:Extension/references" about="#mwt4" data-mw='{"name":"references","attrs":{}}'> +<li about="#cite_note-.7B.7Becho.7Ca.7D.7D-1" id="cite_note-.7B.7Becho.7Ca.7D.7D-1"><span rel="mw:referencedBy"><a href="#cite_ref-.7B.7Becho.7Ca.7D.7D_1-0">↑</a></span> <span id="mw-reference-text-cite_note-.7B.7Becho.7Ca.7D.7D-1" class="mw-reference-text">foo</span></li> +</ol> +!!end + +!!test +Ref: 19. ref-tags with identical name encodings should get identical indexes +!!options +parsoid +!! wikitext +1 <ref name="a & b">foo</ref> 2 <ref name="a & b" /> + +<references /> +!! html +<p>1 <span about="#mwt3" class="reference" id="cite_ref-a_.26_b_1-0" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-a_.26_b-1"},"attrs":{"name":"a & b"}}'><a href="#cite_note-a_.26_b-1">[1]</a></span> 2 <span about="#mwt4" class="reference" id="cite_ref-a_.26_b_1-1" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","attrs":{"name":"a &amp; b"}}'><a href="#cite_note-a_.26_b-1">[1]</a></span> +</p> +<ol class="references" typeof="mw:Extension/references" about="#mwt6" data-mw='{"name":"references","attrs":{}}'> +<li about="#cite_note-a_.26_b-1" id="cite_note-a_.26_b-1"><span rel="mw:referencedBy">↑ <a href="#cite_ref-a_.26_b_1-0">1.0</a> <a href="#cite_ref-a_.26_b_1-1">1.1</a></span> <span id="mw-reference-text-cite_note-a_.26_b-1" class="mw-reference-text">foo</span></li> +</ol> +!!end -<ol class="references" typeof="mw:Extension/references" data-mw='{"name":"references","attrs":{}}'> -<li id="cite_note-1"><span rel="mw:referencedBy"><a href="#cite_ref-1-0">↑</a></span> foo</li></ol> +!!test +Ref: 20. ref-tags with identical names but different content should keep it +!!options +parsoid +!! wikitext +A <ref name="foo">Foo one</ref> +B <ref name="foo">Foo two</ref> +C <ref name="foo" /> + +<references /> +!! html +<p>A <span about="#mwt2" class="reference" id="cite_ref-foo_1-0" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-foo-1"},"attrs":{"name":"foo"}}'><a href="#cite_note-foo-1">[1]</a></span> +B <span about="#mwt4" class="reference" id="cite_ref-foo_1-1" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"html":"Foo two"},"attrs":{"name":"foo"}}'><a href="#cite_note-foo-1">[1]</a></span> +C <span about="#mwt6" class="reference" id="cite_ref-foo_1-2" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","attrs":{"name":"foo"}}'><a href="#cite_note-foo-1">[1]</a></span></p> + +<ol class="references" typeof="mw:Extension/references" about="#mwt8" data-mw='{"name":"references","attrs":{}}'><li about="#cite_note-foo-1" id="cite_note-foo-1"><span rel="mw:referencedBy">↑ <a href="#cite_ref-foo_1-0">1.0</a> <a href="#cite_ref-foo_1-1">1.1</a> <a href="#cite_ref-foo_1-2">1.2</a></span> <span id="mw-reference-text-cite_note-foo-1" class="mw-reference-text">Foo one</span></li> +</ol> !!end !!test @@ -19168,7 +20528,7 @@ parsoid !! wikitext <references /> !! html -<ol about="#mwt2" class="references" typeof="mw:Extension/references" data-mw='{"name":"references","attrs":{}}'></ol> +<ol class="references" typeof="mw:Extension/references" about="#mwt2" data-mw='{"name":"references","attrs":{}}'></ol> !!end !!test @@ -19178,13 +20538,24 @@ parsoid !! wikitext A <ref group="a">foo</ref> B <ref group="b">bar</ref> +C <ref>baz</ref> <references group="a" /> +<references /> +<references group="b" /> !! html -<p>A <span about="#mwt2" class="reference" data-mw='{"name":"ref","body":{"html":"foo"},"attrs":{"group":"a"}}' id="cite_ref-1-0" rel="dc:references" typeof="mw:Extension/ref"><a href="#cite_note-1">[a 1]</a></span> -B <span about="#mwt4" class="reference" data-mw='{"name":"ref","body":{"html":"bar"},"attrs":{"group":"b"}}' id="cite_ref-2-0" rel="dc:references" typeof="mw:Extension/ref"><a href="#cite_note-2">[b 1]</a></span></p> +<p>A <span about="#mwt2" class="reference" id="cite_ref-1" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-1"},"attrs":{"group":"a"}}'><a href="#cite_note-1">[a 1]</a></span> +B <span about="#mwt4" class="reference" id="cite_ref-2" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-2"},"attrs":{"group":"b"}}'><a href="#cite_note-2">[b 1]</a></span> +C <span class="reference" id="cite_ref-3" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-3"},"attrs":{}}'><a href="#cite_note-3">[1]</a></span></p> -<ol about="#mwt6" class="references" typeof="mw:Extension/references" data-mw='{"name":"references","attrs":{"group":"a"}}'><li about="#cite_note-1" id="cite_note-1"><span rel="mw:referencedBy"><a href="#cite_ref-1-0">↑</a></span> foo</li> +<ol class="references" typeof="mw:Extension/references" about="#mwt8" data-mw='{"name":"references","attrs":{"group":"a"}}'> +<li about="#cite_note-1" id="cite_note-1"><span rel="mw:referencedBy"><a href="#cite_ref-1">↑</a></span> <span id="mw-reference-text-cite_note-1" class="mw-reference-text">foo</span></li> +</ol> +<ol class="references" typeof="mw:Extension/references" about="#mwt10" data-mw='{"name":"references","attrs":{}}'> +<li about="#cite_note-3" id="cite_note-3"><span rel="mw:referencedBy"><a href="#cite_ref-3">↑</a></span> <span id="mw-reference-text-cite_note-3" class="mw-reference-text">baz</span></li> +</ol> +<ol class="references" typeof="mw:Extension/references" about="#mwt12" data-mw='{"name":"references","attrs":{"group":"b"}}'> +<li about="#cite_note-2" id="cite_note-2"><span rel="mw:referencedBy"><a href="#cite_ref-2">↑</a></span> <span id="mw-reference-text-cite_note-2" class="mw-reference-text">bar</span></li> </ol> !!end @@ -19201,14 +20572,15 @@ B <ref>bar</ref> <references /> !! html -<p>A <span about="#mwt2" class="reference" data-mw='{"name":"ref","body":{"html":"foo"},"attrs":{}}' id="cite_ref-1-0" rel="dc:references" typeof="mw:Extension/ref"><a href="#cite_note-1">[1]</a></span></p> +<p>A <span about="#mwt2" class="reference" id="cite_ref-1" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-1"},"attrs":{}}'><a href="#cite_note-1">[1]</a></span></p> -<ol about="#mwt4" class="references" typeof="mw:Extension/references" data-mw='{"name":"references","attrs":{}}'><li about="#cite_note-1" id="cite_note-1"><span rel="mw:referencedBy"><a href="#cite_ref-1-0">↑</a></span> foo</li> +<ol class="references" typeof="mw:Extension/references" about="#mwt4" data-mw='{"name":"references","attrs":{}}'><li about="#cite_note-1" id="cite_note-1"><span rel="mw:referencedBy"><a href="#cite_ref-1">↑</a></span> <span id="mw-reference-text-cite_note-1" class="mw-reference-text">foo</span></li> </ol> -<p>B <span about="#mwt6" class="reference" data-mw='{"name":"ref","body":{"html":"bar"},"attrs":{}}' id="cite_ref-2-0" rel="dc:references" typeof="mw:Extension/ref"><a href="#cite_note-2">[1]</a></span></p> +<p>B <span about="#mwt6" class="reference" id="cite_ref-2" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-2"},"attrs":{}}'><a href="#cite_note-2">[1]</a></span></p> -<ol about="#mwt8" class="references" typeof="mw:Extension/references" data-mw='{"name":"references","attrs":{}}'><li about="#cite_note-2" id="cite_note-2"><span rel="mw:referencedBy"><a href="#cite_ref-2-0">↑</a></span> bar</li> +<ol class="references" typeof="mw:Extension/references" about="#mwt8" data-mw='{"name":"references","attrs":{}}'> +<li about="#cite_note-2" id="cite_note-2"><span rel="mw:referencedBy"><a href="#cite_ref-2">↑</a></span> <span id="mw-reference-text-cite_note-2" class="mw-reference-text">bar</span></li> </ol> !!end @@ -19226,15 +20598,15 @@ C <ref>cfoo</ref> <references /> !! html -<p>A <span about="#mwt2" class="reference" data-mw='{"name":"ref","body":{"html":"afoo"},"attrs":{"group":"a"}}' id="cite_ref-1-0" rel="dc:references" typeof="mw:Extension/ref"><a href="#cite_note-1">[a 1]</a></span> -B <span about="#mwt4" class="reference" data-mw='{"name":"ref","body":{"html":"bfoo"},"attrs":{}}' id="cite_ref-2-0" rel="dc:references" typeof="mw:Extension/ref" data-parsoid='{"src":"<ref>bfoo</ref>"}'><a href="#cite_note-2">[1]</a></span></p> +<p>A <span about="#mwt2" class="reference" id="cite_ref-1" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-1"},"attrs":{"group":"a"}}'><a href="#cite_note-1">[a 1]</a></span> +B <span about="#mwt4" class="reference" id="cite_ref-2" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-2"},"attrs":{}}'><a href="#cite_note-2">[1]</a></span></p> -<ol about="#mwt6" class="references" typeof="mw:Extension/references" data-mw='{"name":"references","attrs":{"group":"a"}}'><li about="#cite_note-1" id="cite_note-1"><span rel="mw:referencedBy"><a href="#cite_ref-1-0">↑</a></span> afoo</li> +<ol class="references" typeof="mw:Extension/references" about="#mwt6" data-mw='{"name":"references","attrs":{"group":"a"}}'><li about="#cite_note-1" id="cite_note-1"><span rel="mw:referencedBy"><a href="#cite_ref-1">↑</a></span> <span id="mw-reference-text-cite_note-1" class="mw-reference-text">afoo</span></li> </ol> -<p>C <span about="#mwt8" class="reference" data-mw='{"name":"ref","body":{"html":"cfoo"},"attrs":{}}' id="cite_ref-3-0" rel="dc:references" typeof="mw:Extension/ref"><a href="#cite_note-3">[2]</a></span></p> +<p>C <span about="#mwt8" class="reference" id="cite_ref-3" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-3"},"attrs":{}}'><a href="#cite_note-3">[2]</a></span></p> -<ol about="#mwt10" class="references" typeof="mw:Extension/references" data-mw='{"name":"references","attrs":{}}'><li about="#cite_note-2" id="cite_note-2"><span rel="mw:referencedBy"><a href="#cite_ref-2-0">↑</a></span> bfoo</li><li about="#cite_note-3" id="cite_note-3"><span rel="mw:referencedBy"><a href="#cite_ref-3-0">↑</a></span> cfoo</li> +<ol class="references" typeof="mw:Extension/references" about="#mwt10" data-mw='{"name":"references","attrs":{}}'><li about="#cite_note-2" id="cite_note-2"><span rel="mw:referencedBy"><a href="#cite_ref-2">↑</a></span> <span id="mw-reference-text-cite_note-2" class="mw-reference-text">bfoo</span></li><li about="#cite_note-3" id="cite_note-3"><span rel="mw:referencedBy"><a href="#cite_ref-3">↑</a></span> <span id="mw-reference-text-cite_note-3" class="mw-reference-text">cfoo</span></li> </ol> !!end @@ -19251,13 +20623,11 @@ B <ref name="b">bar</ref> This should just get lost. </references> !! html -<p>A <span about="#mwt2" class="reference" data-mw='{"name":"ref","attrs":{"name":"a"}}' id="cite_ref-a-1-0" rel="dc:references" typeof="mw:Extension/ref" data-parsoid='{"src":"<ref name=\"a\" />"}'><a href="#cite_note-a-1">[1]</a></span> -B <span about="#mwt4" class="reference" data-mw='{"name":"ref","body":{"html":"bar"},"attrs":{"name":"b"}}' id="cite_ref-b-2-0" rel="dc:references" typeof="mw:Extension/ref" data-parsoid='{"src":"<ref name=\"b\">bar</ref>"}'><a href="#cite_note-b-2">[2]</a></span></p> +<p>A <span about="#mwt2" class="reference" id="cite_ref-a_1-0" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","attrs":{"name":"a"}}'><a href="#cite_note-a-1">[1]</a></span> +B <span about="#mwt4" class="reference" id="cite_ref-b_2-0" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-b-2"},"attrs":{"name":"b"}}'><a href="#cite_note-b-2">[2]</a></span></p> -<ol class="references" typeof="mw:Extension/references" about="#mwt6" data-parsoid='{"src":"<references>\n<ref name=\"a\">foo</ref>\nThis should just get lost.\n</references>"}' data-mw='{"name":"references","body":{"extsrc":"<ref name=\"a\">foo</ref>\nThis should just get lost.","html":"\n<span about=\"#mwt8\" class=\"reference\" data-mw='{\"name\":\"ref\",\"body\":{\"html\":\"foo\"},\"attrs\":{\"name\":\"a\"}}' rel=\"dc:references\" typeof=\"mw:Extension/ref\"><a href=\"#cite_note-a-1\">[1]</a></span>\n"},"attrs":{}}'> -<li about="#cite_note-a-1" id="cite_note-a-1" data-parsoid="{}"><span rel="mw:referencedBy"><a href="#cite_ref-a-1-0">↑</a></span> foo</li> -<li about="#cite_note-b-2" id="cite_note-b-2" data-parsoid="{}"><span rel="mw:referencedBy"><a href="#cite_ref-b-2-0">↑</a></span> bar</li> +<ol class="references" typeof="mw:Extension/references" about="#mwt6" data-mw='{"name":"references","body":{"extsrc":"<ref name=\"a\">foo</ref>\nThis should just get lost.","html":"\n<span about=\"#mwt8\" class=\"reference\" rel=\"dc:references\" typeof=\"mw:Extension/ref\" data-parsoid='{\"dsr\":[59,82,14,6]}' data-mw='{\"name\":\"ref\",\"body\":{\"id\":\"mw-reference-text-cite_note-a-1\"},\"attrs\":{\"name\":\"a\"}}'><a href=\"#cite_note-a-1\">[1]</a></span>\n"},"attrs":{}}'><li about="#cite_note-a-1" id="cite_note-a-1"><span rel="mw:referencedBy"><a href="#cite_ref-a_1-0">↑</a></span> <span id="mw-reference-text-cite_note-a-1" class="mw-reference-text">foo</span></li><li about="#cite_note-b-2" id="cite_note-b-2"><span rel="mw:referencedBy"><a href="#cite_ref-b_2-0">↑</a></span> <span id="mw-reference-text-cite_note-b-2" class="mw-reference-text">bar</span></li> </ol> !!end @@ -19268,7 +20638,8 @@ parsoid !! wikitext <ref>Foo</ref> {{echo|<references />}} !! html -<span about="#mwt3" class="reference" data-mw='{"name":"ref","body":{"html":"Foo"},"attrs":{}}' id="cite_ref-1-0" rel="dc:references" typeof="mw:Extension/ref"><a href="#cite_note-1">[1]</a></span> <ol class="references" typeof="mw:Extension/references mw:Transclusion" about="#mwt4" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"<references />"}},"i":0}}]}'><li about="#cite_note-1" id="cite_note-1"><span rel="mw:referencedBy"><a href="#cite_ref-1-0">↑</a></span> Foo</li></ol> +<p><span about="#mwt3" class="reference" id="cite_ref-1" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-1"},"attrs":{}}'><a href="#cite_note-1">[1]</a></span></p> <ol class="references" typeof="mw:Extension/references mw:Transclusion" about="#mwt4" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"<references />"}},"i":0}}]}'><li about="#cite_note-1" id="cite_note-1"><span rel="mw:referencedBy"><a href="#cite_ref-1">↑</a></span> <span id="mw-reference-text-cite_note-1" class="mw-reference-text">Foo</span></li> +</ol> !!end !! test @@ -19285,22 +20656,81 @@ B <ref group="X" name="b" /> <ref name="b">foo</ref> </references> !! html -<p>A <span about="#mwt2" class="reference" data-mw='{"name":"ref","body":{"html":"foo bar for a"},"attrs":{}}' id="cite_ref-1-0" rel="dc:references" typeof="mw:Extension/ref" data-parsoid='{"src":"<ref>foo bar for a</ref>"}'><a href="#cite_note-1" data-parsoid="{}">[1]</a></span> -B <span about="#mwt4" class="reference" data-mw='{"name":"ref","attrs":{"group":"X","name":"b"}}' id="cite_ref-b-2-0" rel="dc:references" typeof="mw:Extension/ref" data-parsoid='{"src":"<ref group=\"X\" name=\"b\" />"}'><a href="#cite_note-b-2" data-parsoid="{}">[X 1]</a></span></p> +<p>A <span about="#mwt2" class="reference" id="cite_ref-1" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-1"},"attrs":{}}'><a href="#cite_note-1">[1]</a></span> +B <span about="#mwt4" class="reference" id="cite_ref-b_2-0" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","attrs":{"group":"X","name":"b"}}'><a href="#cite_note-b-2">[X 1]</a></span> +</p> -<ol class="references" typeof="mw:Extension/references" about="#mwt6" data-parsoid='{"src":"<references />"}' data-mw='{"name":"references","attrs":{}}'><li about="#cite_note-1" id="cite_note-1" data-parsoid="{}"><span rel="mw:referencedBy" data-parsoid="{}"><a href="#cite_ref-1-0" data-parsoid="{}">↑</a></span> foo bar for a</li></ol> +<ol class="references" typeof="mw:Extension/references" about="#mwt6" data-mw='{"name":"references","attrs":{}}'> +<li about="#cite_note-1" id="cite_note-1"><span rel="mw:referencedBy"><a href="#cite_ref-1">↑</a></span> <span id="mw-reference-text-cite_note-1" class="mw-reference-text">foo bar for a</span></li> +</ol> -<ol class="references" typeof="mw:Extension/references" about="#mwt8" data-parsoid='{"src":"<references group=\"X\">\n<ref name=\"b\">foo</ref>\n</references>","group":"X"}' data-mw='{"name":"references","body":{"extsrc":"<ref name=\"b\">foo</ref>","html":"\n<span about=\"#mwt10\" class=\"reference\" data-mw='{\"name\":\"ref\",\"body\":{\"html\":\"foo\"},\"attrs\":{\"name\":\"b\"}}' rel=\"dc:references\" typeof=\"mw:Extension/ref\"><a href=\"#cite_note-b-2\">[X 1]</a></span>\n"},"attrs":{"group":"X"}}'><li about="#cite_note-b-2" id="cite_note-b-2" data-parsoid="{}"><span rel="mw:referencedBy" data-parsoid="{}"><a href="#cite_ref-b-2-0" data-parsoid="{}">↑</a></span> foo</li></ol> +<ol class="references" typeof="mw:Extension/references" about="#mwt8" data-mw='{"name":"references","body":{"extsrc":"<ref name=\"b\">foo</ref>","html":"\n<span about=\"#mwt10\" class=\"reference\" rel=\"dc:references\" typeof=\"mw:Extension/ref\" data-parsoid='{\"dsr\":[96,119,14,6]}' data-mw='{\"name\":\"ref\",\"body\":{\"id\":\"mw-reference-text-cite_note-b-2\"},\"attrs\":{\"name\":\"b\"}}'><a href=\"#cite_note-b-2\">[X 1]</a></span>\n"},"attrs":{"group":"X"}}'> +<li about="#cite_note-b-2" id="cite_note-b-2"><span rel="mw:referencedBy"><a href="#cite_ref-b_2-0">↑</a></span> <span id="mw-reference-text-cite_note-b-2" class="mw-reference-text">foo</span></li> +</ol> !! end !! test +References: 8. T88019: Remove <meta>s from templates inside <ref> that's itself inside a template +!! options +parsoid +!! wikitext +X{{echo|<ref>foo {{echo|<b>bar</b>}} and {{echo|baz}} boo</ref>}} +<references /> +!! html +<p>X<span about="#mwt2" class="reference" id="cite_ref-1" rel="dc:references" typeof="mw:Transclusion mw:Extension/ref" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"<ref>foo {{echo|<b>bar</b>}} and {{echo|baz}} boo</ref>"}},"i":0}}]}'><a href="#cite_note-1">[1]</a></span></p> +<ol class="references" typeof="mw:Extension/references" about="#mwt7" data-mw='{"name":"references","attrs":{}}'><li about="#cite_note-1" id="cite_note-1"><span rel="mw:referencedBy"><a href="#cite_ref-1">↑</a></span> <span id="mw-reference-text-cite_note-1" class="mw-reference-text">foo <b data-parsoid='{"stx":"html"}'>bar</b> and baz boo</span></li> +</ol> +!!end + +# This test only works in wt2html now as the <references /> are always generated +# unless selser is active. Once T72722 is fixed, we should add a changes test +# here to ensure that unrelated changes don't add the new <references /> in +# wt2wt. +!! test +References: 9. Generate missing references list at the end +!! options +parsoid +!! wikitext +A <ref>foo</ref> +B <ref group="inexistent">bar</ref> +!! html +<p>A <span class="reference" id="cite_ref-1" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-1"},"attrs":{}}'><a href="#cite_note-1">[1]</a></span> B <span class="reference" id="cite_ref-2" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-2"},"attrs":{"group":"inexistent"}}'><a href="#cite_note-2">[inexistent 1]</a></span></p> +<ol class="references" typeof="mw:Extension/references" about="#mwt5" data-mw='{"name":"references","attrs":{}}'> +<li about="#cite_note-1" id="cite_note-1"><span rel="mw:referencedBy"><a href="#cite_ref-1">↑</a></span> <span id="mw-reference-text-cite_note-1" class="mw-reference-text">foo</span></li> +</ol> +<ol class="references" typeof="mw:Extension/references" about="#mwt6" data-mw='{"name":"references","attrs":{"group":"inexistent"}}'> +<li about="#cite_note-2" id="cite_note-2"><span rel="mw:referencedBy"><a href="#cite_ref-2">↑</a></span> <span id="mw-reference-text-cite_note-2" class="mw-reference-text">bar</span></li> +</ol> +!! end + +!! test +References: 10. New <references/> shouldn't be added for unrelated edits. +!! options +parsoid={ + "modes": ["selser"], + "changes": [["#x", "remove"]], + "selser": "noauto" +} +!! wikitext +Unrelated text<span id="x"> that's going to disappear</span>. +A <ref>foo</ref> +!! wikitext/edited +Unrelated text. +A <ref>foo</ref> +!!end + +!! test Entities in ref name !! options parsoid !! wikitext <ref name="test & me">hi</ref> +<references /> !! html -<p data-parsoid='{}'><span about="#mwt2" class="reference" data-mw='{"name":"ref","body":{"html":"hi"},"attrs":{"name":"test & me"}}' id="cite_ref-test & me-1-0" rel="dc:references" typeof="mw:Extension/ref" data-parsoid='{"src":"<ref name=\"test &amp; me\">hi</ref>"}'><a href="#cite_note-test & me-1" data-parsoid="{}">[1]</a></span></p> +<p><span about="#mwt2" class="reference" id="cite_ref-test_.26_me_1-0" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-test_.26_me-1"},"attrs":{"name":"test &amp; me"}}'><a href="#cite_note-test_.26_me-1">[1]</a></span></p> +<ol class="references" typeof="mw:Extension/references" about="#mwt4" data-mw='{"name":"references","attrs":{}}'> +<li about="#cite_note-test_.26_me-1" id="cite_note-test_.26_me-1"><span rel="mw:referencedBy"><a href="#cite_ref-test_.26_me_1-0">↑</a></span> <span id="mw-reference-text-cite_note-test_.26_me-1" class="mw-reference-text">hi</span></li> +</ol> !! end # This test is wt2html only because we're permitting the serializer to produce @@ -19314,11 +20744,9 @@ a<ref>foo</ref> <references> !! html -<p data-parsoid='{}'>a<span about="#mwt2" class="reference" data-mw='{"name":"ref","body":{"html":"foo"},"attrs":{}}' id="cite_ref-1-0" rel="dc:references" typeof="mw:Extension/ref" data-parsoid='{"src":"<ref>foo</ref>"}'><a href="#cite_note-1" data-parsoid="{}">[1]</a></span></p> - - -<ol class="references" typeof="mw:Extension/references" about="#mwt4" data-parsoid='{"src":"<references>"}' data-mw='{"name":"references","attrs":{}}'> -<li about="#cite_note-1" id="cite_note-1" data-parsoid="{}"><span rel="mw:referencedBy" data-parsoid="{}"><a href="#cite_ref-1-0" data-parsoid="{}">↑</a></span> foo</li></ol> +<p>a<span about="#mwt2" class="reference" id="cite_ref-1" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-1"},"attrs":{}}'><a href="#cite_note-1">[1]</a></span></p> +<ol class="references" typeof="mw:Extension/references" about="#mwt4" data-mw='{"name":"references","attrs":{}}'> +<li about="#cite_note-1" id="cite_note-1"><span rel="mw:referencedBy"><a href="#cite_ref-1">↑</a></span> <span id="mw-reference-text-cite_note-1" class="mw-reference-text">foo</span></li></ol> !! end !! test @@ -19333,6 +20761,85 @@ foo<ol class="references" typeof="mw:Extension/references" about="#mwt2" data-mw !! end #### ---------------------------------------------------------------- +#### Parsoid-only testing of Parsoid's impl of LST +#### Not implemented yet, see +#### https://www.mediawiki.org/wiki/Parsoid/HTML_based_LST +#### ---------------------------------------------------------------- + +!!test +LST Sections: 1. Simple section start and end +!! wikitext +<section begin="2011-05-16" /> +<section end="2014-04-10 (MW 1.23wmf22)" /> +!! html/parsoid +<p><meta typeof="mw:Extension/LabeledSectionTransclusion/begin" content="2011-05-16"/> +<meta typeof="mw:Extension/LabeledSectionTransclusion/end" content="2014-04-10 (MW 1.23wmf22)"/></p> +!! end + +#--------- Test stripping of empty nodes in template content ---------- +!!test +Empty LI and TR nodes should be stripped from template content +!!wikitext +{{EmptyLITest}} +{{EmptyTRTest}} +!!html/parsoid +<ul about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"EmptyLITest","href":"./Template:EmptyLITest"},"params":{},"i":0}}]}'> +<li>a</li> +<li>b</li> +</ul> +<table about="#mwt2" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"EmptyTRTest","href":"./Template:EmptyTRTest"},"params":{},"i":0}}]}'> +<tbody> +<tr> +<td>foo</td> +</tr> +<tr> +<td>bar</td> +</tr> +</tbody> +</table> +!!end + +!!test +Empty LI and TR nodes should not be stripped from top-level content +!!wikitext +* a +* +* b +{| +|- +|- +|foo +|} +!!html/parsoid +<ul> +<li> a</li> +<li></li> +<li> b</li> +</ul> +<table> +<tbody> +<tr></tr> +<tr> +<td>foo</td> +</tr> +</tbody> +</table> +!!end + +!!test +Empty TR nodes should not be stripped if they have any attributes set +!!wikitext +{{EmptyTRWithHTMLAttrTest}} +!!html/parsoid +<table about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"EmptyTRWithHTMLAttrTest","href":"./Template:EmptyTRWithHTMLAttrTest"},"params":{},"i":0}}]}'> +<tr align="center"></tr> +<tr><td>foo</td></tr> +<tr align="center"></tr> +<tr><td>bar</td></tr> +</table> +!!end + +#### ---------------------------------------------------------------- #### The following section of tests are primarily to test #### wikitext escaping capabilities of Parsoid. Given that #### escaping can be done any number of ways, the wikitext (input) @@ -19376,11 +20883,22 @@ parsoid <p>=foo<i>a</i><span typeof="mw:Nowiki">=</span></p> !!end +# New headings and existing headings are handled differently !! test Headings: 1. Nested inside html -(New headings and existing headings are handled differently) !! options parsoid=html2wt +!! html +<h1>=foo=</h1> +<h2>=foo=</h2> +<h3>=foo=</h3> + +<h1 data-parsoid=''>=foo=</h1> +<h2 data-parsoid=''>=foo=</h2> +<h3 data-parsoid=''>=foo=</h3> +<h4 data-parsoid=''>=foo=</h4> +<h5 data-parsoid=''>=foo=</h5> +<h6 data-parsoid=''>=foo=</h6> !! wikitext = =foo= = @@ -19395,23 +20913,16 @@ parsoid=html2wt =====<nowiki>=foo=</nowiki>===== ======<nowiki>=foo=</nowiki>====== -!! html -<h1>=foo=</h1> -<h2>=foo=</h2> -<h3>=foo=</h3> - -<h1 data-parsoid='{}'>=foo=</h1> -<h2 data-parsoid='{}'>=foo=</h2> -<h3 data-parsoid='{}'>=foo=</h3> -<h4 data-parsoid='{}'>=foo=</h4> -<h5 data-parsoid='{}'>=foo=</h5> -<h6 data-parsoid='{}'>=foo=</h6> !!end !! test Headings: 2. Outside heading nest on a single line <h1>foo</h1>*bar !! options parsoid=html2wt +!! html +<h1>foo</h1>*bar +<h1>foo</h1>=bar +<h1>foo</h1>=bar= !! wikitext = foo = <nowiki>*</nowiki>bar @@ -19421,26 +20932,20 @@ parsoid=html2wt = foo = <nowiki>=bar=</nowiki> -!! html -<h1>foo</h1>*bar -<h1>foo</h1>=bar -<h1>foo</h1>=bar= !!end !! test Headings: 3. Nested inside html with wikitext split by html tags !! options -parsoid=html2wt +parsoid=html2wt,wt2wt !! wikitext = ='''bold'''<nowiki>foo=</nowiki> = -!! html -<h1>=<b>bold</b><span typeof="mw:Nowiki">foo=</span></h1> +!! html/parsoid +<h1>=<b>bold</b>foo=</h1> !!end !! test Headings: 4a. No escaping needed (testing just h1 and h2) -!! options -parsoid=html2wt !! wikitext = =foo = @@ -19454,33 +20959,33 @@ parsoid=html2wt == foo= == -= ''=''foo= = += = = -= <nowiki>=</nowiki> = -!! html += ''=''foo= = +!! html/parsoid <h1>=foo</h1> <h1>foo=</h1> <h1> =foo= </h1> <h1>=foo= bar</h1> <h2>=foo</h2> <h2>foo=</h2> +<h1>=</h1> <h1><i>=</i>foo=</h1> -<h1><span typeof="mw:Nowiki">=</span></h1> !!end !! test Headings: 4b. No escaping needed (inside p-tags) !! options parsoid=html2wt -!! wikitext -=== -=foo= x -=foo= <s></s> !! html <p>=== =foo= x =foo= <s></s> </p> +!! wikitext +=== +=foo= x +=foo= <s></s> !!end !! test @@ -19584,12 +21089,30 @@ parsoid Headings: 6d. Heading chars in SOL context (No escaping needed) !! options parsoid=html2wt -!! wikitext -=a=<div>b</div> !! html =a=<div>b</div> +!! wikitext +=a=<div>b</div> !!end +!! test +Headings: 7. Insert a newline between new content and headings +!! options +parsoid=html2wt +!! html +<h2>NEW</h2> +<p>new</p> +<h2 data-parsoid='{"dsr":[0,5,2,2]}'>A</h2> +<p data-parsoid='{"dsr":[6,7,0,0]}'>a</p> +!! wikitext +== NEW == +new + +==A== +a + +!! end + #### --------------- Lists --------------- #### 0. Outside nests (*foo, etc.) #### 1. Nested inside html <ul><li>*foo</li></ul> @@ -19714,33 +21237,36 @@ Lists: 5. No unnecessary escapes !! wikitext * bar <span><nowiki>[[foo]]</nowiki></span> -*=bar <span><nowiki>[[foo]]</nowiki></span> +* =bar <span><nowiki>[[foo]]</nowiki></span> -*[[bar <span><nowiki>[[foo]]</nowiki></span> +* [[bar <span><nowiki>[[foo]]</nowiki></span> -*]]bar <span><nowiki>[[foo]]</nowiki></span> +* ]]bar <span><nowiki>[[foo]]</nowiki></span> -*=bar <span>foo]]</span>= +* =bar <span>foo]]</span>= * <s></s>: a + +* ''* foo'' !! html <ul><li> bar <span>[[foo]]</span></li></ul> -<ul><li>=bar <span>[[foo]]</span></li></ul> -<ul><li>[[bar <span>[[foo]]</span></li></ul> -<ul><li>]]bar <span>[[foo]]</span></li></ul> -<ul><li>=bar <span>foo]]</span>=</li></ul> +<ul><li> =bar <span>[[foo]]</span></li></ul> +<ul><li> [[bar <span>[[foo]]</span></li></ul> +<ul><li> ]]bar <span>[[foo]]</span></li></ul> +<ul><li> =bar <span>foo]]</span>=</li></ul> <ul><li> <s></s>: a</li></ul> +<ul><li> <i>* foo</i></li></ul> !!end !! test Lists: 6. Escape bullets in SOL position !! options -parsoid -!! wikitext -<!--cmt--><nowiki>*foo</nowiki> +parsoid=html2wt !! html -<p><!--cmt--><span typeof="mw:Nowiki">*foo</span></p> +<p><!--cmt-->*foo</p> +!! wikitext +<!--cmt--><nowiki>*</nowiki>foo !!end !! test @@ -19754,22 +21280,33 @@ a </p> !!end +!! test +Lists: 8. Escape colons only if not present in tags +!! options +parsoid=html2wt +!! html +<dl><dt>a:b<i>c:d</i></dt></dl> +!! wikitext +; <nowiki>a:b</nowiki>''c:d'' +!! end + #### --------------- HRs --------------- #### 1. Single line #### ----------------------------------- !! test HRs: 1. Single line -!! options -parsoid !! wikitext ----<nowiki>----</nowiki> ----=foo= ----*foo -!! html -<hr><span typeof="mw:Nowiki">----</span> -<hr>=foo= -<hr>*foo +!! html+tidy +<hr /> +<p>----</p> +<hr /> +<p>=foo=</p> +<hr /> +<p>*foo</p> !! end #### --------------- Tables --------------- @@ -19833,127 +21370,196 @@ Tables: 1d. No escaping needed Tables: 2a. Nested in td !! options parsoid=html2wt +!! html/parsoid +<table><tbody><tr> +<td>foo|bar</td></tr> +<tr><td>x<div>a|b</div></td> +</tbody></table> !! wikitext {| |<nowiki>foo|bar</nowiki> |- |x<div><nowiki>a|b</nowiki></div> |} -!! html -<table><tbody><tr> -<td>foo|bar</td></tr> -<tr><td>x<div>a|b</div></td> -</tbody></table> +!! html/php+tidy +<table> +<tr> +<td>foo|bar</td> +</tr> +<tr> +<td>x +<div>a|b</div> +</td> +</tr> +</table> !! end !! test Tables: 2b. Nested in td !! options -parsoid +parsoid=html2wt +!! html/parsoid +<table><tbody><tr> +<td>foo||bar</td> +<td>a<i>b||c</i></td> +<td>a<i><div>b||c</div></i></td> +</tr></tbody></table> !! wikitext {| |<nowiki>foo||bar</nowiki> -|''it''<nowiki>foo||bar</nowiki> +|a''<nowiki>b||c</nowiki>'' +|a''<div><nowiki>b||c</nowiki></div>'' |} -!! html -<table><tbody><tr> -<td><span typeof="mw:Nowiki">foo||bar</span></td> -<td><i>it</i><span typeof="mw:Nowiki">foo||bar</span></td></tr></tbody></table> +!! html/php +<table> +<tr> +<td>foo||bar +</td> +<td>a<i>b||c</i> +</td> +<td>a<i><div>b||c</div></i> +</td></tr></table> + !! end !! test Tables: 2c. Nested in td -- no escaping needed -!! options -parsoid !! wikitext {| + |foo!!bar |} -!! html -<table><tbody><tr><td>foo!!bar -</td></tr></tbody></table> +!! html/* +<table> + +<tr> +<td>foo!!bar +</td></tr></table> !! end !! test Tables: 3a. Nested in th -!! options -parsoid !! wikitext {| + !foo!bar |} -!! html -<table><tbody><tr><th>foo!bar -</th></tr></tbody></table> +!! html/* +<table> + +<tr> +<th>foo!bar +</th></tr></table> !! end !! test Tables: 3b. Nested in th !! options -parsoid +parsoid=html2wt +!! html/parsoid +<table><tbody> +<tr><th>foo!!bar</th> +<th><i>foo|bar</i></th> +<th><i>foo!!bar</i></th> +<th><i><span>foo!!bar</span></i></th> +</tr></tbody></table> !! wikitext {| !<nowiki>foo!!bar</nowiki> +!''<nowiki>foo|bar</nowiki>'' +!''<nowiki>foo!!bar</nowiki>'' +!''<span><nowiki>foo!!bar</nowiki></span>'' |} -!! html +!! html/php <table> -<tbody><tr><th><span typeof="mw:Nowiki">foo!!bar</span></th></tr> -</tbody></table> +<tr> +<th>foo!!bar +</th> +<th><i>foo|bar</i> +</th> +<th><i>foo!!bar</i> +</th> +<th><i><span>foo!!bar</span></i> +</th></tr></table> + !! end !! test -Tables: 3c. Nested in th -- no escaping needed +Tables: 3c. Nested in th !! options -parsoid +parsoid=html2wt +!! html/parsoid +<table><tbody> +<tr><th>foo||bar</th> +<th><span typeof="mw:Nowiki">foo||bar</span></th> +</tr></tbody></table> !! wikitext {| !<nowiki>foo||bar</nowiki> +!<nowiki>foo||bar</nowiki> |} -!! html -<table><tbody><tr> -<th><span typeof="mw:Nowiki">foo||bar</span></th></tr></tbody></table> +!! html/php +<table> +<tr> +<th>foo||bar +</th> +<th>foo||bar +</th></tr></table> + !! end !! test Tables: 4a. Escape - !! options -parsoid +parsoid=html2wt +!! html/* +<table> + +<tr> +<th>-bar +</th></tr> +<tr> +<td>-bar +</td></tr></table> + !! wikitext {| + !-bar + |- |<nowiki>-bar</nowiki> |} -!! html -<table><tbody> -<tr><th>-bar</th></tr> -<tr> -<td><span typeof="mw:Nowiki">-bar</span></td></tr></tbody></table> !! end !! test Tables: 4b. Escape + !! options -parsoid +parsoid=html2wt +!! html/* +<table> + +<tr> +<th>+bar +</th></tr> +<tr> +<td>+bar +</td></tr></table> + !! wikitext {| + !+bar + |- |<nowiki>+bar</nowiki> |} -!! html -<table><tbody> -<tr><th>+bar</th></tr> -<tr> -<td><span typeof="mw:Nowiki">+bar</span></td></tr></tbody></table> !! end !! test Tables: 4c. No escaping needed -!! options -parsoid !! wikitext {| |foo-bar @@ -19970,7 +21576,31 @@ bar|baz |x <div>a|b</div> |} -!! html +!! html/php +<table> +<tr> +<td>foo-bar +</td> +<td>foo+bar +</td></tr> +<tr> +<td><i>foo</i>-bar +</td> +<td><i>foo</i>+bar +</td></tr> +<tr> +<td>foo +<p>bar|baz ++bar +-bar +</p> +</td></tr> +<tr> +<td>x +<div>a|b</div> +</td></tr></table> + +!! html/parsoid <table><tbody> <tr><td>foo-bar</td><td>foo+bar</td></tr> <tr><td><i>foo</i>-bar</td><td><i>foo</i>+bar</td></tr> @@ -19985,15 +21615,23 @@ bar|baz !! test Tables: 4d. No escaping needed -!! options -parsoid !! wikitext {| |[[Foo]]-bar ||+1 ||-2 |} -!! html +!! html/php +<table> +<tr> +<td><a href="/wiki/Foo" title="Foo">Foo</a>-bar +</td> +<td>+1 +</td> +<td>-2 +</td></tr></table> + +!! html/parsoid <table> <tbody><tr><td><a rel="mw:WikiLink" href="./Foo" title="Foo">Foo</a>-bar</td> <td data-parsoid='{"startTagSrc":"|","attrSepSrc":"|"}'>+1</td> @@ -20026,23 +21664,39 @@ parsoid=wt2html #### 5. Extlinks: No escapes needed #### -------------------------------------- !! test -Links 1. Quote marks in link text -!! options -parsoid +Links 1. WikiLinks: No escapes needed !! wikitext -[[Foo|Foo<nowiki>''boo''</nowiki>]] -!! html -<a rel="mw:WikiLink" href="Foo">Foo''boo''</a> +[[Foo|Foo''boo'']] +[[Foo|[Foobar]]] +[[Foo|x [Foobar] x]] +!! html/php +<p><a href="/wiki/Foo" title="Foo">Foo<i>boo</i></a> +<a href="/wiki/Foo" title="Foo">[Foobar]</a> +<a href="/wiki/Foo" title="Foo">x [Foobar] x</a> +</p> +!! html/parsoid +<p><a rel="mw:WikiLink" href="Foo" title="Foo">Foo<i>boo</i></a> +<a rel="mw:WikiLink" href="Foo" title="Foo">[Foobar]</a> +<a rel="mw:WikiLink" href="Foo" title="Foo">x [Foobar] x</a></p> !! end !! test Links 2. WikiLinks: Escapes needed !! options -parsoid +parsoid=html2wt +!! html/parsoid +<a href="Foo" rel="mw:WikiLink">Foobar]</a> +<a href="Foo" rel="mw:WikiLink">x [http://google.com g] x</a> +<a href="Foo" rel="mw:WikiLink">[[Bar]]</a> +<a href="Foo" rel="mw:WikiLink">x [[Bar]] x</a> +<a href="Foo" rel="mw:WikiLink">|Bar</a> +<a href="Foo" rel="mw:WikiLink">]]bar</a> +<a href="Foo" rel="mw:WikiLink">[[bar</a> +<a href="Foo" rel="mw:WikiLink">x [[ y</a> +<a href="Foo" rel="mw:WikiLink">x ]] y</a> +<a href="Foo" rel="mw:WikiLink">x ]] y [[ z</a> !! wikitext -[[Foo|[Foobar]]] [[Foo|<nowiki>Foobar]</nowiki>]] -[[Foo|x [Foobar] x]] [[Foo|x <nowiki>[http://google.com g]</nowiki> x]] [[Foo|<nowiki>[[Bar]]</nowiki>]] [[Foo|<nowiki>x [[Bar]] x</nowiki>]] @@ -20052,37 +21706,43 @@ parsoid [[Foo|<nowiki>x [[ y</nowiki>]] [[Foo|<nowiki>x ]] y</nowiki>]] [[Foo|<nowiki>x ]] y [[ z</nowiki>]] -!! html -<a href="Foo" rel="mw:WikiLink">[Foobar]</a> -<a href="Foo" rel="mw:WikiLink">Foobar]</a> -<a href="Foo" rel="mw:WikiLink">x [Foobar] x</a> -<a href="Foo" rel="mw:WikiLink">x [http://google.com g] x</a> -<a href="Foo" rel="mw:WikiLink">[[Bar]]</a> -<a href="Foo" rel="mw:WikiLink">x [[Bar]] x</a> -<a href="Foo" rel="mw:WikiLink">|Bar</a> -<a href="Foo" rel="mw:WikiLink">]]bar</a> -<a href="Foo" rel="mw:WikiLink">[[bar</a> -<a href="Foo" rel="mw:WikiLink">x [[ y</a> -<a href="Foo" rel="mw:WikiLink">x ]] y</a> -<a href="Foo" rel="mw:WikiLink">x ]] y [[ z</a> +!! html/php +<p><a href="/wiki/Foo" title="Foo">Foobar]</a> +<a href="/wiki/Foo" title="Foo">x [http://google.com g] x</a> +<a href="/wiki/Foo" title="Foo">[[Bar]]</a> +<a href="/wiki/Foo" title="Foo">x [[Bar]] x</a> +<a href="/wiki/Foo" title="Foo">|Bar</a> +<a href="/wiki/Foo" title="Foo">]]bar</a> +<a href="/wiki/Foo" title="Foo">[[bar</a> +<a href="/wiki/Foo" title="Foo">x [[ y</a> +<a href="/wiki/Foo" title="Foo">x ]] y</a> +<a href="/wiki/Foo" title="Foo">x ]] y [[ z</a> +</p> !! end !! test Links 3. WikiLinks: No escapes needed -!! options -parsoid !! wikitext [[Foo|[Foobar]] [[Foo|foo|bar]] -!! html -<a href="Foo" rel="mw:WikiLink">[Foobar</a> -<a href="Foo" rel="mw:WikiLink">foo|bar</a> +!! html/php +<p><a href="/wiki/Foo" title="Foo">[Foobar</a> +<a href="/wiki/Foo" title="Foo">foo|bar</a> +</p> +!! html/parsoid +<p><a rel="mw:WikiLink" href="Foo">[Foobar</a> +<a rel="mw:WikiLink" href="Foo" title="Foo">foo|bar</a></p> !! end !! test Links 4. ExtLinks: Escapes needed !! options -parsoid +parsoid=html2wt +!! html/parsoid +<p><a rel="mw:ExtLink" href="http://google.com">[google]</a> +<a rel="mw:ExtLink" href="http://google.com">google]</a></p> +<p>[http://google.com]</p> +<p>[http://google.com google]</p> !! wikitext [http://google.com <nowiki>[google]</nowiki>] [http://google.com <nowiki>google]</nowiki>] @@ -20091,21 +21751,23 @@ parsoid <nowiki>[http://google.com google]</nowiki> -!! html -<p><a href="http://google.com" rel="mw:ExtLink">[google]</a> -<a href="http://google.com" rel="mw:ExtLink">google]</a></p> -<p>[http://google.com]</p> -<p>[http://google.com google]</p> +!! html/php +<p><a rel="nofollow" class="external text" href="http://google.com">[google]</a> +<a rel="nofollow" class="external text" href="http://google.com">google]</a> +</p><p>[http://google.com] +</p><p>[http://google.com google] +</p> !! end !! test Links 5. ExtLinks: No escapes needed -!! options -parsoid !! wikitext [http://google.com [google] -!! html -<a href="http://google.com" rel="mw:ExtLink">[google</a> +!! html/php +<p><a rel="nofollow" class="external text" href="http://google.com">[google</a> +</p> +!! html/parsoid +<p><a rel="mw:ExtLink" href="http://google.com">[google</a></p> !! end !! test @@ -20162,61 +21824,90 @@ y (http://example.com) foo http://example.com, http://example.com, foo +!! html/php +<p>x +<a rel="nofollow" class="external free" href="http://example.com">http://example.com</a> +y +"<a rel="nofollow" class="external free" href="http://example.com">http://example.com</a>" +(<a rel="nofollow" class="external free" href="http://example.com">http://example.com</a>) +(<a rel="nofollow" class="external free" href="http://example.com">http://example.com</a>) foo +<a rel="nofollow" class="external free" href="http://example.com">http://example.com</a>, +<a rel="nofollow" class="external free" href="http://example.com">http://example.com</a>, foo +</p> !! end -## Parsoid currently fails wt2html on this one! !! test Links 7b. Don't add spurious <nowiki/>s between text-nodes and url-links (bug 64300) !! html/parsoid -<p><a rel="mw:ExtLink" href="http://example.com" data-parsoid='{"stx":"url"}'>http://example.com</a>.,;:!?</p> +<p><a rel="mw:ExtLink" href="http://example.com" data-parsoid='{"stx":"url"}'>http://example.com</a>.,;:!?\ +-<a rel="mw:ExtLink" href="http://example.com">http://example.com</a>:</p> !! wikitext -http://example.com.,;:!? +http://example.com.,;:!?\ +-http://example.com: +!! html/php +<p><a rel="nofollow" class="external free" href="http://example.com">http://example.com</a>.,;:!?\ +-<a rel="nofollow" class="external free" href="http://example.com">http://example.com</a>: +</p> !! end !! test Links 8. Add <nowiki/>s between text-nodes and RFC-links when required (bug 64300) !! html/parsoid -<p><a href="//tools.ietf.org/html/rfc123" rel="mw:ExtLink" data-parsoid='{"stx":"magiclink"}'>RFC 123</a>4</p> +<p><a href="//tools.ietf.org/html/rfc123" rel="mw:ExtLink" data-parsoid='{"stx":"magiclink"}'>RFC 123</a>4 +<a href="//tools.ietf.org/html/rfc123" rel="mw:ExtLink" data-parsoid='{"stx":"magiclink"}'>RFC 123</a>y +X<a href="//tools.ietf.org/html/rfc123" rel="mw:ExtLink" data-parsoid='{"stx":"magiclink"}'>RFC 123</a>y</p> !! wikitext RFC 123<nowiki/>4 +RFC 123<nowiki/>y +X<nowiki/>RFC 123<nowiki/>y !! end !! test Links 9. Don't add spurious <nowiki/>s between text-nodes and RFC-links (bug 64300) !! html/parsoid -<p>x<a href="//tools.ietf.org/html/rfc123" rel="mw:ExtLink" data-parsoid='{"stx":"magiclink"}'>RFC 123</a>y -X<a href="//tools.ietf.org/html/rfc123" rel="mw:ExtLink" data-parsoid='{"stx":"magiclink"}'>RFC 123</a>y -<a href="//tools.ietf.org/html/rfc123" rel="mw:ExtLink" data-parsoid='{"stx":"magiclink"}'>RFC 123</a>?foo +<p><a href="//tools.ietf.org/html/rfc123" rel="mw:ExtLink" data-parsoid='{"stx":"magiclink"}'>RFC 123</a>?foo <a href="//tools.ietf.org/html/rfc123" rel="mw:ExtLink" data-parsoid='{"stx":"magiclink"}'>RFC 123</a>&foo +-<a href="//tools.ietf.org/html/rfc123" rel="mw:ExtLink" data-parsoid='{"stx":"magiclink"}'>RFC 123</a>- </p> !! wikitext -xRFC 123y -XRFC 123y RFC 123?foo RFC 123&foo +-RFC 123- +!! html/php +<p><a class="external mw-magiclink-rfc" rel="nofollow" href="//tools.ietf.org/html/rfc123">RFC 123</a>?foo +<a class="external mw-magiclink-rfc" rel="nofollow" href="//tools.ietf.org/html/rfc123">RFC 123</a>&foo +-<a class="external mw-magiclink-rfc" rel="nofollow" href="//tools.ietf.org/html/rfc123">RFC 123</a>- +</p> !! end !! test Links 10. Add <nowiki/>s between text-nodes and PMID-links when required (bug 64300) !! html/parsoid <p><a href="//www.ncbi.nlm.nih.gov/pubmed/123?dopt=Abstract" rel="mw:ExtLink" data-parsoid='{"stx":"magiclink"}'>PMID 123</a>4 +<a href="//www.ncbi.nlm.nih.gov/pubmed/123?dopt=Abstract" rel="mw:ExtLink" data-parsoid='{"stx":"magiclink"}'>PMID 123</a>y +X<a href="//www.ncbi.nlm.nih.gov/pubmed/123?dopt=Abstract" rel="mw:ExtLink" data-parsoid='{"stx":"magiclink"}'>PMID 123</a>y !! wikitext PMID 123<nowiki/>4 +PMID 123<nowiki/>y +X<nowiki/>PMID 123<nowiki/>y !! end !! test Links 11. Don't add spurious <nowiki/>s between text-nodes and PMID-links (bug 64300) !! html/parsoid -<p>x<a href="//www.ncbi.nlm.nih.gov/pubmed/123?dopt=Abstract" rel="mw:ExtLink" data-parsoid='{"stx":"magiclink"}'>PMID 123</a>y -X<a href="//www.ncbi.nlm.nih.gov/pubmed/123?dopt=Abstract" rel="mw:ExtLink" data-parsoid='{"stx":"magiclink"}'>PMID 123</a>y -<a href="//www.ncbi.nlm.nih.gov/pubmed/123?dopt=Abstract" rel="mw:ExtLink" data-parsoid='{"stx":"magiclink"}'>PMID 123</a>?foo +<p><a href="//www.ncbi.nlm.nih.gov/pubmed/123?dopt=Abstract" rel="mw:ExtLink" data-parsoid='{"stx":"magiclink"}'>PMID 123</a>?foo <a href="//www.ncbi.nlm.nih.gov/pubmed/123?dopt=Abstract" rel="mw:ExtLink" data-parsoid='{"stx":"magiclink"}'>PMID 123</a>&foo +-<a href="//www.ncbi.nlm.nih.gov/pubmed/123?dopt=Abstract" rel="mw:ExtLink" data-parsoid='{"stx":"magiclink"}'>PMID 123</a>- </p> !! wikitext -xPMID 123y -XPMID 123y PMID 123?foo PMID 123&foo +-PMID 123- +!! html/php +<p><a class="external mw-magiclink-pmid" rel="nofollow" href="//www.ncbi.nlm.nih.gov/pubmed/123?dopt=Abstract">PMID 123</a>?foo +<a class="external mw-magiclink-pmid" rel="nofollow" href="//www.ncbi.nlm.nih.gov/pubmed/123?dopt=Abstract">PMID 123</a>&foo +-<a class="external mw-magiclink-pmid" rel="nofollow" href="//www.ncbi.nlm.nih.gov/pubmed/123?dopt=Abstract">PMID 123</a>- +</p> !! end !! test @@ -20224,20 +21915,47 @@ Links 12. Add <nowiki/>s between text-nodes and ISBN-links when required (bug 64 !! html/parsoid <p><a href="./Special:BookSources/1234567890" rel="mw:ExtLink" data-parsoid='{"stx":"magiclink"}'>ISBN 1234567890</a>1 <a href="./Special:BookSources/1234567890" rel="mw:ExtLink" data-parsoid='{"stx":"magiclink"}'>ISBN 1234567890</a>x -<a href="./Special:BookSources/1234567890" rel="mw:ExtLink" data-parsoid='{"stx":"magiclink"}'>ISBN 1234567890</a>b +a<a href="./Special:BookSources/1234567890" rel="mw:ExtLink" data-parsoid='{"stx":"magiclink"}'>ISBN 1234567890</a>b </p> !! wikitext ISBN 1234567890<nowiki/>1 ISBN 1234567890<nowiki/>x -ISBN 1234567890<nowiki/>b +a<nowiki/>ISBN 1234567890<nowiki/>b !! end !! test -Links 12. Don't add spurious <nowiki/>s between text-nodes and ISBN-links (bug 64300) +Links 13. Don't add spurious <nowiki/>s between text-nodes and ISBN-links (bug 64300) !! html/parsoid -<p><a href="./Special:BookSources/1234567890" rel="mw:ExtLink" data-parsoid='{"stx":"magiclink"}'>ISBN 1234567890</a>'s +<p>-<a href="./Special:BookSources/1234567890" rel="mw:ExtLink" data-parsoid='{"stx":"magiclink"}'>ISBN 1234567890</a>'s +!! wikitext +-ISBN 1234567890's +!! html/php +<p>-<a href="/wiki/Special:BookSources/1234567890" class="internal mw-magiclink-isbn">ISBN 1234567890</a>'s +</p> +!! end + +!! test +Links 14. Protect link-like plain text. (Parsoid bug T78425) +!! options +parsoid=html2wt +!! html/* +<p>this is not a link: http://example.com +</p> +!! wikitext +this is not a link: <nowiki>http://example.com</nowiki> +!! end + +!! test +Links 15. Link trails can't become link prefixes. +!! options +language=is !! wikitext -ISBN 1234567890's +[[Söfnuður]]-[[00]] +!! html/php +<p><a href="/wiki/S%C3%B6fnu%C3%B0ur" title="Söfnuður">Söfnuður-</a><a href="/wiki/00" title="00">00</a> +</p> +!! html/parsoid +<p><a rel="mw:WikiLink" href="Söfnuður" title="Söfnuður" data-parsoid='{"stx":"simple","tail":"-"}'>Söfnuður-</a><a rel="mw:WikiLink" href="00" title="00">00</a></p> !! end #### --------------- Quotes --------------- @@ -20247,28 +21965,31 @@ ISBN 1234567890's #### 4. No escaping needed #### -------------------------------------- !! test -1. Quotes inside <b> and <i> +1a. Quotes inside <b> and <i> !! options parsoid=html2wt,wt2wt !! wikitext -''<nowiki>'foo'</nowiki>'' +''<nowiki/>'foo''' ''<nowiki>''foo''</nowiki>'' ''<nowiki>'''foo'''</nowiki>'' ''foo''<nowiki/>'s -'''<nowiki>'foo'</nowiki>''' +'''<nowiki/>'foo'''' '''<nowiki>''foo''</nowiki>''' '''<nowiki>'''foo'''</nowiki>''' -'''<nowiki>foo'</nowiki>''<nowiki>bar'</nowiki>''baz''' +'''foo'<nowiki/>''bar'<nowiki/>''baz''' '''foo'''<nowiki/>'s '''foo'' ''foo''<nowiki/>' -'<nowiki/>''foo''<nowiki/>' +''foo'''<nowiki/>' +'''foo''<nowiki/>' ''''foo''' '''foo'''<nowiki/>' -'<nowiki/>'''foo'''<nowiki/>' +''''foo'''<nowiki/>' ''fools'<span> errand</span>'' ''<span>fool</span>'s errand'' -!! html +'<nowiki/>''foo'' bar '''baz'' +a|!*#-:;+-~[]{}b'''x'' +!! html/* <p><i>'foo'</i> <i>''foo''</i> <i>'''foo'''</i> @@ -20280,12 +22001,42 @@ parsoid=html2wt,wt2wt <b>foo</b>'s '<i>foo</i> <i>foo</i>' +<i>foo'</i>' '<i>foo</i>' '<b>foo</b> <b>foo</b>' -'<b>foo</b>'</p> +'<b>foo</b>' <i>fools'<span> errand</span></i> <i><span>fool</span>'s errand</i> +'<i>foo</i> bar '<i>baz</i> +a|!*#-:;+-~[]{}b'<i>x</i> +</p> +!! end + +!! test +1b. Quotes inside <b> and <i> with other tags on same line +!! options +parsoid=html2wt,wt2wt +!! wikitext +'''a'' foo ''[[bar]]'' +''a''' foo ''[[bar]]'' +''a''' foo '''{{echo|[[bar]]}}''' +[[foo]] x'''[[bar]]'' +'''foo'' <ref>test</ref> +'''foo'' <div title="name">test</div> +'''foo'' and <br> bar +<references /> +!! html +'<i>a</i> foo <i><a rel="mw:WikiLink" href="Bar" title="Bar">bar</a></i> +<i>a'</i> foo <i><a rel="mw:WikiLink" href="Bar" title="Bar">bar</a></i> +<i>a'</i> foo <b><a rel="mw:WikiLink" href="Bar" title="Bar" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"[[bar]]"}},"i":0}}]}'>bar</a></b> +<a rel="mw:WikiLink" href="Foo" title="Foo">foo</a> x'<i><a href="Bar" rel="mw:WikiLink" title="Bar">bar</a></i> +'<i>foo</i> <span class="reference" id="cite_ref-1-0" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-1"},"attrs":{}}'><a href="#cite_note-1">[1]</a></span> +'<i>foo</i> <div title="name">test</div> +'<i>foo</i> and <br data-parsoid='{"stx":"html","noClose":true}'/> bar +<ol class="references" typeof="mw:Extension/references" about="#mwt5" data-mw='{"name":"references","attrs":{}}'> +<li about="#cite_note-1" id="cite_note-1"><span rel="mw:referencedBy"><a href="#cite_ref-1">↑</a></span> <span id="mw-reference-text-cite_note-1" class="mw-reference-text" data-parsoid="{}">test</span></li> +</ol> !! end !! test @@ -20300,10 +22051,10 @@ parsoid=html2wt,wt2wt </p> !! end +# FIXME: Escaping one or both of [[ and ]] is also acceptable -- +# this is one of the shortcomings of this format !! test 3. Link fragments inside <i> and <b> -(FIXME: Escaping one or both of [[ and ]] is also acceptable -- - this is one of the shortcomings of this format) !! wikitext ''[[foo''<nowiki>]]</nowiki> @@ -20319,9 +22070,11 @@ parsoid=html2wt,wt2wt !! wikitext '<span>''bar''</span>' '<span>'''bar'''</span>' +'a:b'foo !! html <p>'<span><i>bar</i></span>' '<span><b>bar</b></span>' +'a:b'foo </p> !! end @@ -20397,8 +22150,13 @@ parsoid !! wikitext foo <ref>''a'' b</ref> +<references /> !! html -<p>foo <span about="#mwt2" class="reference" data-mw='{"name":"ref","body":{"html":"<i data-parsoid='{\"dsr\":[9,14,2,2]}'>a</i>\n b"},"attrs":{}}' id="cite_ref-1-0" rel="dc:references" typeof="mw:Extension/ref"><a href="#cite_note-1">[1]</a></span></p> +<p>foo <span about="#mwt2" class="reference" id="cite_ref-1" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"id":"mw-reference-text-cite_note-1"},"attrs":{}}'><a href="#cite_note-1">[1]</a></span></p> +<ol class="references" typeof="mw:Extension/references" about="#mwt4" data-mw='{"name":"references","attrs":{}}'> +<li about="#cite_note-1" id="cite_note-1"><span rel="mw:referencedBy"><a href="#cite_ref-1">↑</a></span> <span id="mw-reference-text-cite_note-1" class="mw-reference-text"><i data-parsoid='{"dsr":[9,14,2,2]}'>a</i> + b</span></li> +</ol> !! end !! test @@ -20426,9 +22184,8 @@ parsoid parsoid !! wikitext [[File:Foobar.jpg|thumb|caption]] -!! html !! html/parsoid - <figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="25" width="220"/></a><figcaption>caption</figcaption></figure> + <figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220"/></a><figcaption>caption</figcaption></figure> !! end !! test @@ -20446,22 +22203,22 @@ parsoid=html2wt 1. Valid behavior switches should be escaped !! options parsoid=html2wt -!! wikitext -<nowiki>__TOC__</nowiki> -''<nowiki>__TOC__</nowiki>'' !! html __TOC__ <i>__TOC__</i> +!! wikitext +<nowiki>__TOC__</nowiki> +''<nowiki>__TOC__</nowiki>'' !! end !! test 2. Invalid behavior switches should not be escaped !! options parsoid=html2wt -!! wikitext +!! html __TOO__ __|__ -!! html +!! wikitext __TOO__ __|__ !! end @@ -20485,12 +22242,14 @@ parsoid !! test 2. other tags !! wikitext -<nowiki><div>foo</div> -<div style="color:red">foo</div></nowiki> +* <nowiki><div>foo</div></nowiki> +* <nowiki><div style="color:red">foo</div></nowiki> +* <nowiki><td></nowiki> !! html -<p><div>foo</div> -<div style="color:red">foo</div> -</p> +<ul><li> <div>foo</div></li> +<li> <div style="color:red">foo</div></li> +<li> <td></li></ul> + !! end !! test @@ -20570,18 +22329,6 @@ a>b </p> !! end - -# This was a bug in the PHP parser (see bug 17663 and its dups, -# https://bugzilla.wikimedia.org/show_bug.cgi?id=17663) -!! test -Tag names followed by punctuation should not be recognized as tags -!! wikitext -<s.ome> text -!! html -<p><s.ome> text -</p> -!! end - !! test HTML tag with necessary entities in attributes !! wikitext @@ -20650,7 +22397,7 @@ Table with broken attribute value quoting on consecutive lines | title="Hello world|Foo | style="color:red|Bar |} -!! html +!! html/php <table> <tr> <td>Foo @@ -20658,18 +22405,7 @@ Table with broken attribute value quoting on consecutive lines <td>Bar </td></tr></table> -!! end - -!! test -Parsoid-only: Table with broken attribute value quoting on consecutive lines -!! options -parsoid -!! wikitext -{| -| title="Hello world|Foo -| style="color:red|Bar -|} -!! html +!! html/parsoid <table><tbody> <tr> <td title="Hello world">Foo @@ -20783,9 +22519,9 @@ RT-ed inter-element separators should be valid separators !!end +# Parsoid-only since PHP parser relies on Tidy for correct output !!test Trailing newlines in a deep dom-subtree that ends a wikitext line should be migrated out -(Parsoid-only since PHP parser relies on Tidy for correct output) !!options parsoid !! wikitext @@ -20798,6 +22534,14 @@ bar |<small>foo<small> |} !! html +<table> +<tbody><tr data-parsoid='{"autoInsertedEnd":true,"autoInsertedStart":true}'><td data-parsoid='{"autoInsertedEnd":true}'><small data-parsoid='{"stx":"html","autoInsertedEnd":true}'>foo +<p>bar</p></small></td></tr> +</tbody></table> + +<table> +<tbody><tr data-parsoid='{"autoInsertedEnd":true,"autoInsertedStart":true}'><td data-parsoid='{"autoInsertedEnd":true}'><small data-parsoid='{"stx":"html","autoInsertedEnd":true}'>foo<small data-parsoid='{"stx":"html","autoInsertedEnd":true}'></small></small></td></tr> +</tbody></table> !!end !!test @@ -20838,6 +22582,29 @@ Indented table with an empty td !!end +## We have some newline diffs RT-ing this edge case +## and it is not important enough -- we seem to be emitting +## at most 2 newlines after a </tr> and this is unrelated to +## the issue from T85627 that this is testing. +!!test +Indented table with blank lines in between (T85627) +!! options +parsoid=wt2html +!! wikitext + {| + |foo + + + |} +!! html +<table> + +<tr> +<td>foo +</td></tr></table> + +!!end + !!test Indented block & table !! wikitext @@ -20874,15 +22641,15 @@ Indent and comment before table row </td></tr></table> !! html/parsoid -<table data-parsoid='{}'> - <!--hi--><tbody data-parsoid='{}'><tr data-parsoid='{"startTagSrc":"|-","autoInsertedEnd":true}'> +<table> + <!--hi--><tbody><tr data-parsoid='{"startTagSrc":"|-","autoInsertedEnd":true}'> <td data-parsoid='{"autoInsertedEnd":true}'> there</td></tr> </tbody></table> !! end +# Parsoid-specific since PHP parser doesn't handle this mixed tbl-wikitext !!test Empty TR followed by a template-generated TR -(Parsoid-specific since PHP parser doesn't handle this mixed tbl-wikitext) !!options parsoid !! wikitext @@ -20925,32 +22692,29 @@ parsoid !!test Multi-line image caption generated by templates with/without trailing newlines -!!options -parsoid !! wikitext -[[File:foo.jpg|thumb|300px|foo\n{{echo|A}}\n{{echo|B}}\n{{echo|C}}]] -[[File:foo.jpg|thumb|300px|foo\n{{echo|A}}\n{{echo|B}}\n{{echo|C}}\n\n]] -!! html -<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/index.php?title=Special:Upload&wpDestFile=Foo.jpg" class="new" title="File:Foo.jpg">File:Foo.jpg</a> <div class="thumbcaption">foo\nA\nB\nC</div></div></div> -<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/index.php?title=Special:Upload&wpDestFile=Foo.jpg" class="new" title="File:Foo.jpg">File:Foo.jpg</a> <div class="thumbcaption">foo\nA\nB\nC\n\n</div></div></div> - +[[File:Foobar.jpg|thumb|300x300px|foo\n{{echo|A}}\n{{echo|B}}\n{{echo|C}}]] +[[File:Foobar.jpg|thumb|300x300px|foo\n{{echo|A}}\n{{echo|B}}\n{{echo|C}}\n\n]] +!! html/parsoid +<figure typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/300px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="34" width="300"/></a><figcaption>foo\n<span about="#mwt9" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"A"}},"i":0}}]}'>A</span>\n<span about="#mwt10" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"B"}},"i":0}}]}'>B</span>\n<span about="#mwt11" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"C"}},"i":0}}]}'>C</span></figcaption></figure> +<figure typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/300px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="34" width="300"/></a><figcaption>foo\n<span about="#mwt12" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"A"}},"i":0}}]}'>A</span>\n<span about="#mwt13" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"B"}},"i":0}}]}'>B</span>\n<span about="#mwt14" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"C"}},"i":0}}]}'>C</span>\n\n</figcaption></figure> !!end !! test New element inserted (without intervening newlines) after an old sol-transparent node should serialize correctly !! options parsoid=html2wt +!! html +<meta typeof="mw:Includes/IncludeOnly" data-parsoid='{"src":"<includeonly>foo</includeonly>"}'/><meta typeof="mw:Includes/IncludeOnly/End" data-parsoid='{"src":""}'/><p>new para</p> + +<link rel="mw:PageProp/Category" href="./Category:Foo" data-parsoid='{}'/><h1>new heading</h1> !! wikitext <includeonly>foo</includeonly> new para -[[./Category:Foo]] +[[Category:Foo]] = new heading = -!! html -<meta typeof="mw:Includes/IncludeOnly" data-parsoid='{"src":"<includeonly>foo</includeonly>"}'/><meta typeof="mw:Includes/IncludeOnly/End" data-parsoid='{"src":""}'/><p>new para</p> - -<link rel="mw:PageProp/Category" href="./Category:Foo" data-parsoid=''/><h1>new heading</h1> !! end ## PHP emits broken html for this, and since this is primarily @@ -20993,20 +22757,20 @@ plain text !!end !!test -1. Ensure fostered text content is wrapped in spans +1. Ensure fostered text content is wrapped in element nodes !!options parsoid=wt2html !! wikitext <table>hi</table><table>ho</table> !! html -<span>hi</span> +<p>hi</p> <table></table> -<span>ho</span> +<p>ho</p> <table></table> !!end !!test -2. Ensure fostered text content is wrapped in spans (traps regressions around fostered marker on the span getting lost) +2. Ensure fostered text content is wrapped in element nodes (traps regressions around fostered marker on the element getting lost) !!options parsoid=wt2html,wt2wt !! wikitext @@ -21015,11 +22779,9 @@ parsoid=wt2html,wt2wt <td> a </table> !! html -<span> || ||</span> -<table> -<tbody> -<tr> -<td> a</td></tr> +<p> || || +</p><table> +<tbody><tr><td> a</td></tr> </tbody></table> !!end @@ -21030,14 +22792,7 @@ parsoid=wt2html,wt2wt !! wikitext {{echo|<table>foo<tr><td>bar</td></tr></table>}} !! html -<span typeof="mw:Transclusion" data-mw="{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":" -<table>foo -<tr> -<td>bar</td></tr></table>"}},"i":0}}]}">foo</span> -<table> -<tbody> -<tr> -<td>bar</td></tr></tbody></table> +<span typeof="mw:Transclusion" data-mw="{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"<table>foo<tr><td>bar</td></tr></table>"}},"i":0}}]}">foo</span><table><tbody><tr><td>bar</td></tr></tbody></table> !!end !!test @@ -21047,14 +22802,13 @@ parsoid=wt2wt,wt2html !! wikitext <table>{{echo|foo<tr><td>bar</td></tr>}}</table> !! html -<span typeof="mw:Transclusion" data-mw="{"parts":[" -<table>",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo -<tr> -<td>bar</td></tr>"}},"i":0}},"</table>"]}">foo</span> -<table> +<p typeof="mw:Transclusion" data-mw="{"parts":["<table>",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo<tr><td>bar</td></tr>"}},"i":0}},"</table>"]}">foo</p><table> <tbody> <tr> -<td>bar</td></tr></tbody></table> +<td>bar</td> +</tr> +</tbody> +</table> !!end !!test @@ -21064,15 +22818,14 @@ parsoid=wt2wt,wt2html !! wikitext <table><div>{{echo|foo}}</div><tr><td>bar</td></tr></table> !! html -<div typeof="mw:Transclusion" data-mw="{"parts":[" -<table> -<div>",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo"}},"i":0}},"</div> -<tr> -<td>bar</td></tr></table>"]}">foo</div> +<div typeof="mw:Transclusion" data-mw="{"parts":["<table><div>",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo"}},"i":0}},"</div><tr><td>bar</td></tr></table>"]}">foo</div> <table> <tbody> <tr> -<td>bar</td></tr></tbody></table> +<td>bar</td> +</tr> +</tbody> +</table> !!end !!test @@ -21082,17 +22835,16 @@ parsoid=wt2wt,wt2html !! wikitext <table><div><p>{{echo|foo</p></div><tr><td>}}bar</td></tr></table> !! html -<div typeof="mw:Transclusion" data-mw="{"parts":[" -<table> -<div> -<p>",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo</p></div> -<tr> -<td>"}},"i":0}},"bar</td></tr></table>"]}"> -<p>foo</p></div> +<div typeof="mw:Transclusion" data-mw="{"parts":["<table><div><p>",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo</p></div><tr><td>"}},"i":0}},"bar</td></tr></table>"]}"> +<p>foo</p> +</div> <table> <tbody> <tr> -<td>bar</td></tr></tbody></table> +<td>bar</td> +</tr> +</tbody> +</table> !!end !!test @@ -21102,17 +22854,16 @@ parsoid=wt2wt,wt2html !! wikitext <table><div><p>{{echo|foo</p></div><tr><td>}}bar</td></tr></table> !! html -<div typeof="mw:Transclusion" data-mw="{"parts":[" -<table> -<div> -<p>",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo</p></div> -<tr> -<td>"}},"i":0}},"bar</td></tr></table>"]}"> -<p>foo</p></div> +<div typeof="mw:Transclusion" data-mw="{"parts":["<table><div><p>",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo</p></div><tr><td>"}},"i":0}},"bar</td></tr></table>"]}"> +<p>foo</p> +</div> <table> <tbody> <tr> -<td>bar</td></tr></tbody></table> +<td>bar</td> +</tr> +</tbody> +</table> !!end !!test @@ -21122,18 +22873,18 @@ parsoid=wt2wt,wt2html !! wikitext <table><tr><td><div><p>{{echo|foo</p></div></td>foo}}</tr></table> !! html -<span typeof="mw:Transclusion" data-mw="{"parts":[" -<table> -<tr> -<td> -<div> -<p>",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo</p></div></td>foo"}},"i":0}},"</tr></table>"]}">foo</span> +<p typeof="mw:Transclusion" data-mw="{"parts":["<table><tr><td><div><p>",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo</p></div></td>foo"}},"i":0}},"</tr></table>"]}">foo</p> <table> <tbody> <tr> <td> <div> -<p>foo</p></div></td></tr></tbody></table> +<p>foo</p> +</div> +</td> +</tr> +</tbody> +</table> !!end !!test @@ -21143,18 +22894,18 @@ parsoid=wt2wt,wt2html !! wikitext <table><tr><td><div><p>{{echo|foo</p></div></td>foo</tr></table>}}<p>ok</p> !! html -<span typeof="mw:Transclusion" data-mw="{"parts":[" -<table> -<tr> -<td> -<div> -<p>",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo</p></div></td>foo</tr></table>"}},"i":0}}]}">foo</span> +<p typeof="mw:Transclusion" data-mw="{"parts":["<table><tr><td><div><p>",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo</p></div></td>foo</tr></table>"}},"i":0}}]}">foo</p> <table> <tbody> <tr> <td> <div> -<p>foo</p></div></td></tr></tbody></table> +<p>foo</p> +</div> +</td> +</tr> +</tbody> +</table> <p>ok</p> !!end @@ -21165,14 +22916,14 @@ parsoid=wt2wt,wt2html !! wikitext <table>{{echo|<p>foo</p>}}<td>bar</td></table> !! html -<p typeof="mw:Transclusion" data-mw="{"parts":[" -<table>",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":" -<p>foo</p>"}},"i":0}}," -<td>bar</td></table>"]}">foo</p> +<p typeof="mw:Transclusion" data-mw="{"parts":["<table>",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"<p>foo</p>"}},"i":0}},"<td>bar</td></table>"]}">foo</p> <table> <tbody> <tr> -<td>bar</td></tr></tbody></table> +<td>bar</td> +</tr> +</tbody> +</table> !!end !!test @@ -21186,11 +22937,13 @@ parsoid=wt2wt,wt2html |b |} !! html -<p typeof="mw:Transclusion" data-mw="{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"a\n"}},"i":0}}]}">a</p><span typeof="mw:Transclusion" data-mw="{"parts":["{|",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"style":{"wt":"'color:red'"}},"i":0}},"\n|-\n|b\n|}"]}">{{{1}}}</span> -<table> +<p typeof="mw:Transclusion" data-mw="{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"a\n"}},"i":0}}]}">a</p><p typeof="mw:Transclusion" data-mw="{"parts":["{|",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"style":{"wt":"'color:red'"}},"i":0}},"\n|-\n|b\n|}"]}">{{{1}}}</p><table> <tbody> <tr> -<td>b</td></tr></tbody></table> +<td>b</td> +</tr> +</tbody> +</table> !!end !!test @@ -21200,8 +22953,7 @@ parsoid=wt2wt,wt2html !! wikitext <table>{{echo|hi</table>hello}} !! html -<span about="#mwt2" typeof="mw:Transclusion" data-mw='{"parts":["<table>",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"hi</table>hello"}},"i":0}}]}' data-parsoid='{"fostered":true,"autoInsertedEnd":true,"autoInsertedStart":true,"pi":[[{"k":"1","spc":["","","",""]}]]}'>hi</span> -<table about="#mwt2" data-parsoid='{"stx":"html"}'></table><span about="#mwt2" data-parsoid="{}">hello</span> +<p about="#mwt2" typeof="mw:Transclusion" data-mw='{"parts":["<table>",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"hi</table>hello"}},"i":0}}]}' data-parsoid='{"fostered":true,"autoInsertedEnd":true,"autoInsertedStart":true,"pi":[[{"k":"1","spc":["","","",""]}]]}'>hi</p><table about="#mwt2" data-parsoid='{"stx":"html"}'></table><p about="#mwt2">hello</p> !!end !!test @@ -21216,7 +22968,7 @@ parsoid=wt2html,wt2wt </div> |} !! html -<div about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"OpenTable","href":"./Template:OpenTable"},"params":{},"i":0}},"\n<div>"]}' data-parsoid='{"stx":"html","autoInsertedEnd":true,"pi":[[]]}'></div><span about="#mwt1" data-parsoid="{}"> +<div about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"OpenTable","href":"./Template:OpenTable"},"params":{},"i":0}},"\n<div>"]}' data-parsoid='{"stx":"html","autoInsertedEnd":true,"pi":[[]]}'></div><span about="#mwt1"> </span> <table about="#mwt1" data-parsoid='{"autoInsertedEnd":true}'></table> @@ -21234,7 +22986,7 @@ Properly encapsulate empty-content transclusions in fosterable positions }} </table> !! html/parsoid -<table about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":["<table>\n",{"template":{"target":{"wt":"#if:","function":"#if"},"params":{"1":{"wt":"\n<td>foo</td>\n"}},"i":0}},"\n</table>"]}' data-parsoid='{"stx":"html","pi":[[{"k":"1","spc":["","","",""]}]],"src":"<table>\n{{#if:|\n<td>foo</td>\n}}\n</table>"}'> +<table about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":["<table>\n",{"template":{"target":{"wt":"#if:","function":"#if"},"params":{"1":{"wt":"\n<td>foo</td>\n"}},"i":0}},"\n</table>"]}' data-parsoid='{"stx":"html","pi":[[{"k":"1","spc":["","","",""]}]]}'> </table> !! end @@ -21243,12 +22995,23 @@ Properly encapsulate empty-content transclusions in fosterable positions Support <object> element with .data attribute !!options parsoid=html2wt -!! wikitext -<object data="test.swf"></object> !! html <object data="test.swf"></object> +!! wikitext +<object data="test.swf"></object> !!end +!! test +Don't block XML namespace declaration +!! wikitext +<span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">MediaWiki</span> +!! html/php +<p><span>MediaWiki</span> +</p> +!! html/parsoid +<p><span xmlns:dct="http://purl.org/dc/terms/" data-x-property="dct:title" data-parsoid='{"stx":"html"}'>MediaWiki</span></p> +!! end + # ----------------------------------------------------------------- # The following section of tests are primarily to spec requirements # around serialization of new/edited content. @@ -21256,15 +23019,101 @@ parsoid=html2wt # All these tests are marked Parsoid html2wt and html2html only # ---------------------------------------------------------------- +# 'mi' is a localinterwiki prefix as well as a language !! test Serialize interwiki links pointing to the current wiki as plain wiki links (bug 65869) !! options parsoid=html2wt -language=es +!! html +<p><a rel="mw:ExtLink" href="http://mi.wikipedia.org/wiki/Foo">Foo</a></p> !! wikitext [[Foo]] +!! end + +# See T93839 +!! test +New wikilinks should be serialized properly +!! options +parsoid=html2wt !! html -<p><a rel="mw:ExtLink" href="http://es.wikipedia.org/wiki/Foo">Foo</a></p> +<a rel="mw:WikiLink" href="./Foo" title="Foo" data-parsoid='{}'>Foo</a> +<a rel="mw:WikiLink" href="./Foo" title="Foo">Foo</a> +!! wikitext +[[Foo]] +[[Foo]] +!! end + +!! test +New wiki links (href variations) +!! options +parsoid=html2wt +!! html +<a rel="mw:WikiLink" href="./Foo_bar">Foo_bar</a> +<a rel="mw:WikiLink" href="Foo_bar">Foo_bar</a> +<a rel="mw:WikiLink" href="Foo bar">Foo_bar</a> +<a rel="mw:WikiLink" href="./Toxine_bact%C3%A9rienne">Toxine bactérienne</a> +!! wikitext +[[Foo_bar]] +[[Foo_bar]] +[[Foo_bar]] +[[Toxine bactérienne]] +!! end + +!! test +New wiki links (content string variations) +!! options +parsoid=html2wt +!! html +<a rel="mw:WikiLink" href="./Foo_bar">Foo_bar</a> +<a rel="mw:WikiLink" href="./Foo_bar">Foo bar</a> +<a rel="mw:WikiLink" href="./Foo_bar">./Foo_bar</a> +!! wikitext +[[Foo_bar]] +[[Foo bar]] +[[Foo_bar|./Foo_bar]] +!! end + +!! test +New category links (href variations) +!! options +parsoid=html2wt +!! html +<link rel="mw:PageProp/Category" href="./Category:Toxine_bactérienne" /> +<link rel="mw:PageProp/Category" href="./Category:Toxine_bact%C3%A9rienne" /> +<link rel="mw:PageProp/Category" href="Category:Toxine_bact%C3%A9rienne" /> +!! wikitext +[[Category:Toxine bactérienne]] +[[Category:Toxine bactérienne]] +[[Category:Toxine bactérienne]] +!! end + +!! test +New sol transparent links don't need indent-pre nowiki protection +!! options +parsoid=html2wt +language=de +!! html + <link rel="mw:PageProp/redirect" href="./Main_Page"> +<!-- this is good --> <link rel="mw:PageProp/Category" href="./Category:Good" /> +<!-- this is great --> <link rel="mw:PageProp/Category" href="./Kategorie:Great" /> +!! wikitext + #WEITERLEITUNG [[Main Page]] +<!-- this is good --> [[Category:Good]] +<!-- this is great --> [[Kategorie:Great]] +!! end + +!! test +New interlanguage links (href variations) +!! options +parsoid=html2wt +!! html +<link rel="mw:PageProp/Language" href="http://es.wikipedia.org/wiki/Toxine bactérienne" /> +<link rel="mw:PageProp/Language" href="http://es.wikipedia.org/wiki/Toxine_bactérienne" /> +<link rel="mw:PageProp/Language" href="http://es.wikipedia.org/wiki/Toxine_bact%C3%A9rienne" /> +!! wikitext +[[es:Toxine bactérienne]] +[[es:Toxine_bactérienne]] +[[es:Toxine_bactérienne]] !! end !! test @@ -21401,7 +23250,7 @@ parsoid !! wikitext [[File:Foobar.jpg|thumb|alt=|bar]] !! html -<figure class="mw-default-size" typeof="mw:Image/Thumb" data-parsoid='{"optList":[{"ck":"thumbnail","ak":"thumb"},{"ck":"alt","ak":"alt="},{"ck":"caption","ak":"bar"}]}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"}}'><img alt="" resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" height="25" width="220" data-parsoid='{"a":{"alt":"","resource":"./File:Foobar.jpg","height":"25","width":"220"},"sa":{"alt":"alt=","resource":"File:Foobar.jpg"}}'/></a><figcaption>bar</figcaption></figure> +<figure class="mw-default-size" typeof="mw:Image/Thumb" data-parsoid='{"optList":[{"ck":"thumbnail","ak":"thumb"},{"ck":"alt","ak":"alt="},{"ck":"caption","ak":"bar"}]}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"}}'><img alt="" resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/220px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="25" width="220" data-parsoid='{"a":{"alt":"","resource":"./File:Foobar.jpg","height":"25","width":"220"},"sa":{"alt":"alt=","resource":"File:Foobar.jpg"}}'/></a><figcaption>bar</figcaption></figure> !! end #!! test @@ -21409,37 +23258,34 @@ parsoid #!! options #parsoid=html2wt #language=ar -#!! input +#!! html +#<figure class="mw-default-size mw-halign-right" typeof="mw:Image/Thumb"><a href="Imagen:Foobar.jpg"><img resource="./Imagen:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="20" width="180"/></a></figure> +#!! wikitext #[[Imagen:Foobar.jpg|derecha|miniaturadeimagen]] -#!! result -#<figure class="mw-default-size mw-halign-right" typeof="mw:Image/Thumb"><a href="Imagen:Foobar.jpg"><img resource="./Imagen:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="20" width="180"/></a></figure> #!! end !! test Image: Block level image should have \n before and after -!! options -parsoid !! wikitext 123 [[File:Foobar.jpg|right|thumb|150x150px]] 456 -!! html -<p>123</p><figure typeof="mw:Image/Thumb" class="mw-halign-right"><a href="./File:Foobar.png"><img src="http://192.168.142.128/mw/images/thumb/b/bc/Foobar.png/131px-Foobar.png" width="131" height="150" resource="./File:Foobar.png" data-parsoid='{"a":{"resource":"./File:Foobar.png","width":"131"},"sa":{"resource":"File:Foobar.png","width":"150"}}'></a></figure><p>456</p> +!! html/parsoid +<p>123</p> +<figure class="mw-halign-right" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="17" width="150"/></a></figure> +<p>456</p> !!end !! test -Image: New block level image should have \n before and after (existing -content) -!! options -parsoid +Image: New block level image should have \n before and after (existing content) !! wikitext 123 [[File:Foobar.jpg|right|thumb|150x150px]] 456 -!! html -<p data-parsoid='{"dsr":[0,3,0,0]}'>123</p> -<figure class="mw-halign-right" typeof="mw:Image/Thumb" data-parsoid='{"optList":[{"ck":"right","ak":"right"},{"ck":"thumbnail","ak":"thumb"},{"ck":"width","ak":"150x150px"}],"dsr":[4,45,2,2]}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"},"dsr":[6,43,null,null]}'><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/150px-Foobar.jpg" height="17" width="150" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"17","width":"150"},"sa":{"resource":"File:Foobar.jpg"}}'/></a></figure> -<p data-parsoid='{"dsr":[46,49,0,0]}'>456</p> +!! html/parsoid +<p>123</p> +<figure class="mw-halign-right" typeof="mw:Image/Thumb" data-parsoid='{"optList":[{"ck":"right","ak":"right"},{"ck":"thumbnail","ak":"thumb"},{"ck":"width","ak":"150x150px"}]}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"}}'><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/150px-Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="17" width="150" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"17","width":"150"},"sa":{"resource":"File:Foobar.jpg"}}'/></a></figure> +<p>456</p> !!end !! test @@ -21451,7 +23297,9 @@ parsoid [[File:Foobar.jpg|thumb|upright=0.5|caption]] [[File:Foobar.jpg|thumb|500x500px|upright=0.5|caption]] !! html -<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="19" width="170"/></a><figcaption>caption</figcaption></figure><figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="12" width="110"/></a><figcaption>caption</figcaption></figure><figure typeof="mw:Image/Thumb"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="57" width="500"/></a><figcaption>caption</figcaption></figure> +<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="19" width="170"/></a><figcaption>caption</figcaption></figure> +<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="12" width="110"/></a><figcaption>caption</figcaption></figure> +<figure typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="57" width="500"/></a><figcaption>caption</figcaption></figure> !!end !! test @@ -21461,7 +23309,7 @@ parsoid !! wikitext [[File:Foobar.jpg|500x500px|upright=0.5|caption]] !! html -<p><span typeof="mw:Image" data-mw='{"caption":"caption"}'><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="57" width="500"/></a></span></p> +<p><span typeof="mw:Image" data-mw='{"caption":"caption"}'><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" data-file-width="1941" data-file-height="220" data-file-type="bitmap" height="57" width="500"/></a></span></p> !!end !! test @@ -21470,7 +23318,7 @@ Image: from basic HTML (1) parsoid=html2wt !! html/parsoid <span typeof="mw:Image"> - <img src="File:Foobar.jpg" width=100 height=100 alt="Alt"> + <img src="./File:Foobar.jpg" width=100 height=100 alt="Alt"> </span> !! wikitext [[File:Foobar.jpg|link=|alt=Alt|100x100px]] @@ -21481,7 +23329,7 @@ Image: from basic HTML (2) !! options parsoid=html2wt !! html/parsoid -<img src="File:Foobar.jpg" width=100 height=100 alt="Alt"> +<img src="./File:Foobar.jpg" width=100 height=100 alt="Alt"> !! wikitext [[File:Foobar.jpg|link=|alt=Alt|100x100px]] !! end @@ -21491,7 +23339,7 @@ Image: from basic HTML (3) !! options parsoid=html2wt !! html/parsoid -<a href="Main"><img src="File:Foobar.jpg" width=100 height=100 alt="Alt"></a> +<a href="Main"><img src="./File:Foobar.jpg" width=100 height=100 alt="Alt"></a> !! wikitext [[File:Foobar.jpg|link=Main|alt=Alt|100x100px]] !! end @@ -21501,7 +23349,7 @@ Image: from basic HTML (4) !! options parsoid=html2wt !! html/parsoid -<img src="File:Foobar.jpg"> +<img src="./File:Foobar.jpg"> !! wikitext [[File:Foobar.jpg|link=]] !! end @@ -21510,28 +23358,41 @@ parsoid=html2wt Lists: Serialize correctly even when list content is wrapped in p-tags (like VE does) !! options parsoid=html2wt -!! wikitext -* foo !! html <ul> <li><p>foo</p></li> </ul> +!! wikitext +* foo !! end !! test Lists: Serialize correctly even when list tags has unneeded whitespace between tags !! options parsoid=html2wt -!! wikitext -* foo !! html <ul> <li>foo</li></ul> +!! wikitext +* foo !! end !! test Don't strip leading whitespace when handling indent-pre suppressing tags !! options parsoid=html2wt +!! html +<table> + <tr><td> indented row</td></tr> +</table> +<blockquote><p> + <b>This is very bold of you!</b> +</p> +<table><tr><td> + indented cell (no pre-wrapping!) +</td></tr></table> +</blockquote> +<p>foo</p> + <div>bar</div> !! wikitext {| | indented row @@ -21546,19 +23407,6 @@ parsoid=html2wt </blockquote> foo <div>bar</div> -!! html -<table> - <tr><td> indented row</td></tr> -</table> -<blockquote><p> - <b>This is very bold of you!</b> -</p> -<table><tr><td> - indented cell (no pre-wrapping!) -</td></tr></table> -</blockquote> -<p>foo</p> - <div>bar</div> !! end !! test @@ -21597,33 +23445,38 @@ foo Lists: Add space after bullets !! options parsoid=html2wt -!! wikitext -* foo -* bar -* <span> baz</span> !! html <ul> <li>foo</li> <li> bar</li> <li><span> baz</span></li> </ul> +!! wikitext +* foo +* bar +* <span> baz</span> !! end !! test Lists: Dont insert newlines in a serialized list item. !! options parsoid=html2wt +!! html +<ul><li>a<br>b</li><li>c</li></ul> !! wikitext * a<br>b * c -!! html -<ul><li>a<br>b</li><li>c</li></ul> !! end !! test Headings: Add space before/after == (Bug 51744) !! options parsoid=html2wt +!! html +<h2>foo</h2> +<h2> bar</h2> +<h2>baz </h2> +<h2><span> baz</span></h2> !! wikitext == foo == @@ -21632,25 +23485,32 @@ parsoid=html2wt == baz == == <span> baz</span> == -!! html -<h2>foo</h2> -<h2> bar</h2> -<h2>baz </h2> -<h2><span> baz</span></h2> !! end !! test -Parsoid: Serialize positional parameters with = in them as named parameter +Headings: Force metas to serialize before/after !! options parsoid=html2wt +!! html +<h2>hello there<link href="Category:A1" rel="mw:PageProp/Category" /></h2> +<h2><link href="Category:A2" rel="mw:PageProp/Category" />hi pal</h2> + +<h2><!--foo--> <link href="Category:A3" rel="mw:PageProp/Category" /> how goes it</h2> !! wikitext -{{echo|1 = f=oo}} +== hello there == +[[Category:A1]] -{{echo|1 = f=oo|2 = bar}} +[[Category:A2]] +== hi pal == -<!--Orig params with data-parsoid has heuristics for handling = chars--> -<!--FIXME: But maybe the heuristic needs fixing to apply to new params as well--> -{{echo|<nowiki>f=oo</nowiki>|bar}} +<!--foo--> [[Category:A3]] +== how goes it == +!! end + +!! test +Parsoid: Serialize positional parameters with = in them as named parameter +!! options +parsoid=html2wt !! html <p about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"f=oo"}},"i":0}}]}'>foo</p> @@ -21661,12 +23521,37 @@ data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"}, <!--Orig params with data-parsoid has heuristics for handling = chars--> <!--FIXME: But maybe the heuristic needs fixing to apply to new params as well--> <p data-parsoid='{"pi":[[{"k":"1","spc":["","","",""]},{"k":"2","spc":["","","",""]}]]}' about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"f=oo"},"2":{"wt":"bar"}},"i":0}}]}'>foo</p> +!! wikitext +{{echo|1 = f=oo}} + +{{echo|1 = f=oo|2 = bar}} + +<!--Orig params with data-parsoid has heuristics for handling = chars--> +<!--FIXME: But maybe the heuristic needs fixing to apply to new params as well--> +{{echo|<nowiki>f=oo</nowiki>|bar}} +!! end + +!! test +Parsoid: Serialize positional parameters with = in extlink as named parameter +!! options +parsoid=html2wt +!! html +<p><a rel="mw:ExtLink" href="http://stuff?is=ok" about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"http://stuff?is=ok"}},"i":0}}]}'>http://stuff?is=ok</a></p> +!! wikitext +{{echo|1 = http://stuff?is=ok}} !! end !! test Parsoid: Correctly serialize block-node children when they are a combination of text and p-nodes !! options parsoid=html2wt +!! html +<div>a<p>b</p></div> +<div>a +<p>b</p></div> +<div> +a +<p>b</p></div> !! wikitext <div>a b @@ -21679,23 +23564,32 @@ a b </div> -!! html -<div>a<p>b</p></div> -<div>a -<p>b</p></div> -<div> -a -<p>b</p></div> !! end !! test Substrings resembling wikitext in hrefs should not get nowiki escapes !! options parsoid=html2wt +!! html +<a rel="mw:WikiLink" href="./Foo''bar''baz">Foo''bar''baz</a> !! wikitext [[Foo''bar''baz]] +!! end + +!! test +Enforce single-line context in the serializer +!! options +parsoid=html2wt !! html -<a rel="mw:WikiLink" href="./Foo''bar''baz">Foo''bar''baz</a> +<h2>testing +123</h2> + +<ul><li>asd +sdf</li></ul> +!! wikitext +== testing 123 == + +* asd sdf !! end #----------------------------- @@ -21706,6 +23600,15 @@ parsoid=html2wt 1. I/B quote minimization: wikitext-only tags should be combined !! options parsoid=html2wt +!! html +<p><i>A</i><i>B</i></p> +<p><b>A</b><b>B</b></p> +<p><i>A</i><b><i>B</i></b></p> +<p><b>A</b><i><b>B</b></i></p> +<p><b>A</b><i><b>B</b><b>C</b></i><b>D</b></p> +<p><i><b>A</b></i><i><b>B</b></i></p> +<p><i><b>A</b></i><b><i>B</i></b></p> +<p><b><i>A</i></b><i><b>B</b></i></p> !! wikitext ''AB'' @@ -21722,57 +23625,78 @@ parsoid=html2wt '''''AB''''' '''''AB''''' -!! html -<p><i>A</i><i>B</i></p> -<p><b>A</b><b>B</b></p> -<p><i>A</i><b><i>B</i></b></p> -<p><b>A</b><i><b>B</b></i></p> -<p><b>A</b><i><b>B</b><b>C</b></i><b>D</b></p> -<p><i><b>A</b></i><i><b>B</b></i></p> -<p><i><b>A</b></i><b><i>B</i></b></p> -<p><b><i>A</i></b><i><b>B</b></i></p> !! end !! test 2. I/B quote minimization: wikitext and html tags should not be combined !! options parsoid=html2wt -!! wikitext -''A''<i>B</i> - -''A'''''<i>B</i>''' !! html <p><i>A</i><i data-parsoid='{"stx":"html"}'>B</i></p> <p><i>A</i><b><i data-parsoid='{"stx":"html"}'>B</i></b></p> +!! wikitext +''A''<i>B</i> + +''A''<nowiki/>'''<i>B</i>''' !! end !! test 3. I/B quote minimization: templated content stops minimization !! options parsoid=html2wt +!! html +<p><i>A</i><i about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"''B''"}},"i":0}}]}'>B</i> +<p><i>A</i><b about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"'''''B'''''"}},"i":0}}]}'><i>B</i></b> !! wikitext ''A''{{echo|''B''}} ''A''{{echo|'''''B'''''}} -!! html -<p><i>A</i><i about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"''B''"}},"i":0}}]}'>B</i> -<p><i>A</i><b about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"'''''B'''''"}},"i":0}}]}'><i>B</i></b> !! end !! test 4. I/B quote minimization: new content should be mimimized with adjacent old content !! options parsoid=html2wt +!! html +<p><i>A</i><i>B</i></p> +<p><b>A</b><b>B</b></p> +<p><i>A</i><b><i>B</i></b></p> !! wikitext ''AB'' '''AB''' ''A'''B''''' -!! html -<p><i>A</i><i data-parsoid='{}'>B</i></p> -<p><b data-parsoid='{}'>A</b><b>B</b></p> -<p><i>A</i><b data-parsoid='{}'><i data-parsoid='{}'>B</i></b></p> +!! end + +!! test +5a. Merge adjacent quote nodes if they've been edited +!! options +parsoid={ + "modes": ["wt2wt", "selser"], + "changes": [ + ["p", "contents", "remove", ":contains('b')"] + ] +} +!! wikitext +''a''b''c'' +!! wikitext/edited +''ac'' +!! end + +!! test +5b. Merge adjacent quote nodes if they've been edited +!! options +parsoid={ + "modes": ["wt2wt", "selser"], + "changes": [ + ["#x", "remove"] + ] +} +!! wikitext +''a''<span id="x">b</span>''c'' +!! wikitext/edited +''ac'' !! end #------------------------------------ @@ -21796,16 +23720,6 @@ parsoid=html2wt Magic words !! options parsoid=html2wt -!! wikitext -__TOC__ -__NOTOC__ -__FORCETOC__ -__INDEX__ -__NOINDEX__ -__NOGALLERY__ -__NOEDITSECTION__ -__NOTITLECONVERT__ -__NOCONTENTCONVERT__ !! html <meta property='mw:PageProp/toc' /> <meta property='mw:PageProp/notoc' /> @@ -21817,12 +23731,34 @@ __NOCONTENTCONVERT__ <meta property='mw:PageProp/notitleconvert' /> <meta property='mw:PageProp/nocontentconvert' /> <meta property='mw:PageProp/unknownproperty' /> +!! wikitext +__TOC__ +__NOTOC__ +__FORCETOC__ +__INDEX__ +__NOINDEX__ +__NOGALLERY__ +__NOEDITSECTION__ +__NOTITLECONVERT__ +__NOCONTENTCONVERT__ !! end !! test Consecutive <pre>s should not get merged !! options parsoid=html2wt,html2html +!! html +<pre>a</pre><pre>b</pre> + +<pre>c +</pre><pre> +d</pre> + +<pre>e + +</pre><pre> + +f</pre> !! wikitext a @@ -21837,58 +23773,209 @@ parsoid=html2wt,html2html f -!! html -<pre>a</pre><pre>b</pre> - -<pre>c -</pre><pre> -d</pre> - -<pre>e - -</pre><pre> - -f</pre> !! end !! test Edited ISBN links not serializable as ISBN links should serialize as wikilinks !! options parsoid=html2wt -!! wikitext -[[Special:BookSources/1234567890|ISBN 1234567895]] !! html <a rel="mw:ExtLink" href="./Special:BookSources/1234567890">ISBN 1234567895</a> +!! wikitext +[[Special:BookSources/1234567890|ISBN 1234567895]] !! end !! test Edited RFC links not serializable as RFC links should serialize as extlinks !! options parsoid=html2wt -!! wikitext -[//tools.ietf.org/html/rfc123 New RFC] !! html <a href="//tools.ietf.org/html/rfc123" rel="mw:ExtLink">New RFC</a> +!! wikitext +[//tools.ietf.org/html/rfc123 New RFC] !! end !! test Edited PMID links not serializable as PMID links should serialize as extlinks !! options parsoid=html2wt -!! wikitext -[//www.ncbi.nlm.nih.gov/pubmed/123?dopt=Abstract New PMID] !! html <a href="//www.ncbi.nlm.nih.gov/pubmed/123?dopt=Abstract" rel="mw:ExtLink">New PMID</a> +!! wikitext +[//www.ncbi.nlm.nih.gov/pubmed/123?dopt=Abstract New PMID] +!! end + +!! test +WTS of autolinks with trailing/surrounding context +!! options +parsoid=html2wt +!! html/parsoid +<p><a href="http://cscott.net">http://cscott.net</a><b>foo</b></p> +<p><a href="http://cscott.net">http://cscott.net</a><b data-parsoid='{"stx":"html"}'>foo</b></p> +<p><b><a href="http://cscott.net">http://cscott.net</a></b></p> +<p><b><a href="http://cscott.net">http://cscott.net</a> </b></p> +<p><b><a href="http://cscott.net">http://cscott.net</a>x</b></p> +<p><a href="http://cscott.net">http://cscott.net</a>x</p> +!! wikitext +http://cscott.net<nowiki/>'''foo''' + +http://cscott.net<b>foo</b> + +'''http://cscott.net<nowiki/>''' + +'''http://cscott.net ''' + +'''http://cscott.net<nowiki/>x''' + +http://cscott.net<nowiki/>x +!! end + +!! test +WTS of autolinks with nowikis (round-trip) +!! wikitext +x<nowiki/>http://cscott.net<nowiki/>x +!! html/parsoid +<p>x<a rel="mw:ExtLink" href="http://cscott.net">http://cscott.net</a>x</p> +!! end + +# this is the "easy" test because it leaves in place all the +# data-parsoid information indicating this is an autolink +!! test +WTS of autolinks with escapes (editing) +!! options +parsoid={ + "modes": ["wt2wt"], + "changes": [ + [ "meta", "remove" ] + ] +} +!! wikitext +x<nowiki/>http://cscott.net<nowiki/>x +!! wikitext/edited +x<nowiki/>http://cscott.net<nowiki/>x !! end !! test Edited Redirect link should emit a non-piped wikitext link !! options parsoid=html2wt +!! html +<link rel="mw:PageProp/redirect" href="Bar" data-parsoid='{"a":{"href":"./Foo"},"sa":{"href":"Foo"}}'> !! wikitext #REDIRECT [[Bar]] +!! end + +!! test +T75121: Infer extension name from typeOf if data-mw is not present +!! options +parsoid=html2wt +!! html +<div typeOf="mw:Extension/foo"></div> +!! wikitext +<foo /> +!! end + +# Note that the <p> wrapping isn't present in PHP parser output +# The important thing for this test is that P-wrapping doesn't +# interfere with the <nowiki> protection for leading - in <td> +# (which isn't necessary for <th>). +!! test +T88318: p-wrapped dash in table. +!! options +parsoid=html2wt,wt2wt +!! html/parsoid +<table><tbody> +<tr><th><p>-</p></th><th><p>- </p></th></tr> +<tr><td><p>-</p></td><td><p>- </p></td></tr> +<tr><td><small>-</small></td><td><br/><p>-</p></td><td><br/>-</td></tr> +</tbody></table> +!! wikitext +{| +!- +!- +|- +|<nowiki>-</nowiki> +|<nowiki>- </nowiki> +|- +|<small>-</small> +|<br> +- +|<br> +- +|} +!! html/php+tidy +<table> +<tr> +<th>-</th> +<th>-</th> +</tr> +<tr> +<td>-</td> +<td>-</td> +</tr> +<tr> +<td><small>-</small></td> +<td><br /> +<p>-</p> +</td> +<td><br /> +<p>-</p> +</td> +</tr> +</table> +!! end + +!! test +HTML id attribute with Parsoid-like element ids should not be serialized to wikitext +!! options +parsoid=html2wt +!! html +<table id='mwAb'> +<td id='mwAc'>foo</td> +<td id='serialize-this'>bar</td> +</table> +!! wikitext +{| +|foo +| id="serialize-this" |bar +|} +!! end + +!! test +Parsoid-like element ids should not be serialized to wikitext unless shadowed +!! options +parsoid=html2wt !! html -<link rel="mw:PageProp/redirect" href="Bar" data-parsoid='{"src":"#REDIRECT ","a":{"href":"./Foo"},"sa":{"href":"Foo"}}'> +<div id="mwAQ" data-parsoid='{"stx":"html","a":{"id":"mwAQ"},"sa":{"id":"hello"}}'>ok</div> +!! wikitext +<div id="hello">ok</div> +!! end + +!! test +WTS change modes +!! options +parsoid={ + "modes": ["wt2wt"], + "changes": [ + [ "#xyz", "before", "<b>before</b> stuff " ], + [ "#xyz", "after", " stuff <i>after</i>" ], + [ "#xyz", "html", "x <b>y</b> z" ] + ] +} +!! wikitext +<span id="xyz">hello</span> +!! wikitext/edited +'''before''' stuff <span id="xyz">x '''y''' z</span> stuff ''after'' +!! end + +!! test +Never serialize a-tag as html, regardless of what data-parsoid has to say +!! options +parsoid=html2wt +!! html +<a rel="mw:WikiLink" href="./Foo" title="Foo" data-parsoid='{"stx":"html"}'>Foo</a> +!! wikitext +[[Foo]] !! end # ----------------------------------------------------------------- @@ -21896,6 +23983,53 @@ parsoid=html2wt # of new content # ----------------------------------------------------------------- +# ----------------------------------------------------------------- +# The following section of tests are primarily to spec behavior of +# the selective serializer. All these tests have manual selser +# changes. The automated selser changes for all tests handle the +# wide variation of changes, but these tests here capture specs +# deterministically. +# ---------------------------------------------------------------- + +## T90517 +!! test +1. Selser: New comments should not be lost +!! options +parsoid={ + "modes": ["selser"], + "changes": [ + [ "#a", "after", "<!--c1-->" ], + [ "#b", "before", "<!--c2-->" ] + ] +} +!! wikitext +<span id="a">a</span> + +<span id="b">b</span> +!! wikitext/edited +<span id="a">a</span><!--c1--> + +<!--c2--><span id="b">b</span> +!! end + +## T89383 +!! test +2. Selser: Check for validity of DSR before using it +!! options +parsoid={ + "modes": ["selser"], + "changes": [ + [ "#a", "before", "<meta property='mw:PageProp/displaytitle' content='foo'>" ] + ] +} +!! wikitext +<span id="a">a</span> +!! wikitext/edited +{{DISPLAYTITLE:foo}} +<span id="a">a</span> +!! end + + TODO: more images more tables diff --git a/tests/parser/parserTestsParserHook.php b/tests/parser/parserTestsParserHook.php index c8b3e897..221fc79a 100644 --- a/tests/parser/parserTestsParserHook.php +++ b/tests/parser/parserTestsParserHook.php @@ -29,6 +29,7 @@ class ParserTestParserHook { static function setup( &$parser ) { $parser->setHook( 'tag', array( __CLASS__, 'dumpHook' ) ); + $parser->setHook( 'tåg', array( __CLASS__, 'dumpHook' ) ); $parser->setHook( 'statictag', array( __CLASS__, 'staticTagHook' ) ); return true; } diff --git a/tests/parser/preprocess/All_system_messages.expected b/tests/parser/preprocess/All_system_messages.expected index 078d8f0d..2ee805e0 100644 --- a/tests/parser/preprocess/All_system_messages.expected +++ b/tests/parser/preprocess/All_system_messages.expected @@ -2207,13 +2207,6 @@ Log in </td><td> <template lineStart="1"><title>int:Login</title></template> </td></tr><tr><td> -[http://tl.wiktionary.org/w/wiki.phtml?title=MediaWiki:Loginend&action=edit loginend]<br> -[[MediaWiki_talk:Loginend|Talk]] -</td><td> -&amp;nbsp; -</td><td> -<template lineStart="1"><title>int:Loginend</title></template> -</td></tr><tr><td> [http://tl.wiktionary.org/w/wiki.phtml?title=MediaWiki:Loginerror&action=edit loginerror]<br> [[MediaWiki_talk:Loginerror|Talk]] </td><td> diff --git a/tests/parser/preprocess/All_system_messages.txt b/tests/parser/preprocess/All_system_messages.txt index 3c30da94..4a30f56f 100644 --- a/tests/parser/preprocess/All_system_messages.txt +++ b/tests/parser/preprocess/All_system_messages.txt @@ -2207,13 +2207,6 @@ Log in </td><td> {{int:Login}} </td></tr><tr><td> -[http://tl.wiktionary.org/w/wiki.phtml?title=MediaWiki:Loginend&action=edit loginend]<br> -[[MediaWiki_talk:Loginend|Talk]] -</td><td> -&nbsp; -</td><td> -{{int:Loginend}} -</td></tr><tr><td> [http://tl.wiktionary.org/w/wiki.phtml?title=MediaWiki:Loginerror&action=edit loginerror]<br> [[MediaWiki_talk:Loginerror|Talk]] </td><td> diff --git a/tests/parserTests.php b/tests/parserTests.php index 9965c438..5d21319b 100644 --- a/tests/parserTests.php +++ b/tests/parserTests.php @@ -70,10 +70,6 @@ if ( $wgDBtype == 'sqlite' ) { } } -# There is a convention that the parser should never -# refer to $wgTitle directly, but instead use the title -# passed to it. -$wgTitle = Title::newFromText( 'Parser test script do not use' ); $tester = new ParserTest( $options ); if ( isset( $options['file'] ) ) { diff --git a/tests/phpunit/LessFileCompilationTest.php b/tests/phpunit/LessFileCompilationTest.php index 71e0f4b2..df4690a4 100644 --- a/tests/phpunit/LessFileCompilationTest.php +++ b/tests/phpunit/LessFileCompilationTest.php @@ -38,7 +38,7 @@ class LessFileCompilationTest extends ResourceLoaderTestCase { "$thisString must refer to a readable file" ); - $rlContext = static::getResourceLoaderContext(); + $rlContext = $this->getResourceLoaderContext(); // Bleh $method = new ReflectionMethod( $this->module, 'getLessCompiler' ); diff --git a/tests/phpunit/Makefile b/tests/phpunit/Makefile index c3e2a303..a33b86a3 100644 --- a/tests/phpunit/Makefile +++ b/tests/phpunit/Makefile @@ -1,4 +1,4 @@ -.PHONY: help test phpunit install coverage warning destructive parser noparser safe databaseless list-groups +.PHONY: help test phpunit coverage warning destructive parser noparser safe databaseless list-groups .DEFAULT: warning SHELL = /bin/sh @@ -35,9 +35,6 @@ destructive: phpunit phpunit: ${PU} -install: - ./install-phpunit.sh - tap: ${PU} --tap @@ -83,7 +80,7 @@ help: # You will need the Xdebug PHP extension for the later. # [no]parser Skip or only run Parser tests # - # list-groups List availabe Tests groups. + # list-groups List available Tests groups. # # Options: # CONFIG_FILE Path to a PHPUnit configuration file (default: suite.xml) diff --git a/tests/phpunit/MediaWikiTestCase.php b/tests/phpunit/MediaWikiTestCase.php index 995853ea..72cac051 100644 --- a/tests/phpunit/MediaWikiTestCase.php +++ b/tests/phpunit/MediaWikiTestCase.php @@ -104,7 +104,6 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase { ObjectCache::$instances[CACHE_DB] = new HashBagOStuff; $needsResetDB = false; - $logName = get_class( $this ) . '::' . $this->getName( false ); if ( $this->needsDB() ) { // set up a DB connection for this test to use @@ -117,34 +116,22 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase { $this->checkDbIsSupported(); if ( !self::$dbSetup ) { - wfProfileIn( $logName . ' (clone-db)' ); - // switch to a temporary clone of the database self::setupTestDB( $this->db, $this->dbPrefix() ); if ( ( $this->db->getType() == 'oracle' || !self::$useTemporaryTables ) && self::$reuseDB ) { $this->resetDB(); } - - wfProfileOut( $logName . ' (clone-db)' ); } - - wfProfileIn( $logName . ' (prepare-db)' ); $this->addCoreDBData(); $this->addDBData(); - wfProfileOut( $logName . ' (prepare-db)' ); - $needsResetDB = true; } - wfProfileIn( $logName ); parent::run( $result ); - wfProfileOut( $logName ); if ( $needsResetDB ) { - wfProfileIn( $logName . ' (reset-db)' ); $this->resetDB(); - wfProfileOut( $logName . ' (reset-db)' ); } } @@ -198,7 +185,6 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase { } protected function setUp() { - wfProfileIn( __METHOD__ ); parent::setUp(); $this->called['setUp'] = true; @@ -223,12 +209,15 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase { $this->db->ignoreErrors( false ); } - wfProfileOut( __METHOD__ ); + DeferredUpdates::clearPendingUpdates(); + } - protected function tearDown() { - wfProfileIn( __METHOD__ ); + protected function addTmpFiles( $files ) { + $this->tmpFiles = array_merge( $this->tmpFiles, (array)$files ); + } + protected function tearDown() { $this->called['tearDown'] = true; // Cleaning up temporary files foreach ( $this->tmpFiles as $fileName ) { @@ -271,7 +260,6 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase { } parent::tearDown(); - wfProfileOut( __METHOD__ ); } /** @@ -429,6 +417,35 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase { } /** + * Insert a new page. + * + * Should be called from addDBData(). + * + * @since 1.25 + * @param string $pageName Page name + * @param string $text Page's content + * @return array Title object and page id + */ + protected function insertPage( $pageName, $text = 'Sample page for unit test.' ) { + $title = Title::newFromText( $pageName, 0 ); + + $user = User::newFromName( 'UTSysop' ); + $comment = __METHOD__ . ': Sample page for unit test.'; + + // Avoid memory leak...? + // LinkCache::singleton()->clear(); + // Maybe. But doing this absolutely breaks $title->isRedirect() when called during unit tests.... + + $page = WikiPage::factory( $title ); + $page->doEditContent( ContentHandler::makeContent( $text, $title ), $comment, 0, false, $user ); + + return array( + 'title' => $title, + 'id' => $page->getId(), + ); + } + + /** * Stub. If a test needs to add additional data to the database, it should * implement this method and do so * @@ -453,7 +470,6 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase { 'page_namespace' => 0, 'page_title' => ' ', 'page_restrictions' => null, - 'page_counter' => 0, 'page_is_redirect' => 0, 'page_is_new' => 0, 'page_random' => 0, @@ -464,7 +480,7 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase { User::resetIdByNameCache(); - //Make sysop user + // Make sysop user $user = User::newFromName( 'UTSysop' ); if ( $user->idForName() == 0 ) { @@ -476,7 +492,7 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase { $user->saveSettings(); } - //Make 1 page with 1 revision + // Make 1 page with 1 revision $page = WikiPage::factory( Title::newFromText( 'UTPage' ) ); if ( $page->getId() == 0 ) { $page->doEditContent( @@ -484,7 +500,8 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase { 'UTPageSummary', EDIT_NEW, false, - User::newFromName( 'UTSysop' ) ); + $user + ); } } @@ -603,7 +620,7 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase { if ( isset( $compatibility[$func] ) ) { return call_user_func_array( array( $this, $compatibility[$func] ), $args ); } else { - throw new MWException( "Called non-existant $func method on " + throw new MWException( "Called non-existent $func method on " . get_class( $this ) ); } } @@ -614,7 +631,7 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase { * @param string $msg */ private function assertEmpty2( $value, $msg ) { - return $this->assertTrue( $value == '', $msg ); + $this->assertTrue( $value == '', $msg ); } private static function unprefixTable( $tableName ) { @@ -630,7 +647,7 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase { /** * @since 1.18 * - * @param DataBaseBase $db + * @param DatabaseBase $db * * @return array */ @@ -753,7 +770,7 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase { /** * Utility method taking an array of elements and wrapping - * each element in it's own array. Useful for data providers + * each element in its own array. Useful for data providers * that only return a single argument. * * @since 1.20 @@ -1120,9 +1137,23 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase { } /** + * @param array $matcher + * @param string $actual + * @param bool $isHtml + * + * @return bool + */ + private static function tagMatch( $matcher, $actual, $isHtml = true ) { + $dom = PHPUnit_Util_XML::load( $actual, $isHtml ); + $tags = PHPUnit_Util_XML::findNodes( $dom, $matcher, $isHtml ); + return count( $tags ) > 0 && $tags[0] instanceof DOMNode; + } + + /** * Note: we are overriding this method to remove the deprecated error * @see https://bugzilla.wikimedia.org/show_bug.cgi?id=69505 * @see https://github.com/sebastianbergmann/phpunit/issues/1292 + * @deprecated * * @param array $matcher * @param string $actual @@ -1132,10 +1163,21 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase { public static function assertTag( $matcher, $actual, $message = '', $isHtml = true ) { //trigger_error(__METHOD__ . ' is deprecated', E_USER_DEPRECATED); - $dom = PHPUnit_Util_XML::load( $actual, $isHtml ); - $tags = PHPUnit_Util_XML::findNodes( $dom, $matcher, $isHtml ); - $matched = count( $tags ) > 0 && $tags[0] instanceof DOMNode; + self::assertTrue( self::tagMatch( $matcher, $actual, $isHtml ), $message ); + } + + /** + * @see MediaWikiTestCase::assertTag + * @deprecated + * + * @param array $matcher + * @param string $actual + * @param string $message + * @param bool $isHtml + */ + public static function assertNotTag( $matcher, $actual, $message = '', $isHtml = true ) { + //trigger_error(__METHOD__ . ' is deprecated', E_USER_DEPRECATED); - self::assertTrue( $matched, $message ); + self::assertFalse( self::tagMatch( $matcher, $actual, $isHtml ), $message ); } } diff --git a/tests/phpunit/ResourceLoaderTestCase.php b/tests/phpunit/ResourceLoaderTestCase.php index f5f302e0..deecb31e 100644 --- a/tests/phpunit/ResourceLoaderTestCase.php +++ b/tests/phpunit/ResourceLoaderTestCase.php @@ -1,7 +1,12 @@ <?php abstract class ResourceLoaderTestCase extends MediaWikiTestCase { - protected static function getResourceLoaderContext( $lang = 'en' ) { + /** + * @param string $lang + * @param string $dir + * @return ResourceLoaderContext + */ + protected function getResourceLoaderContext( $lang = 'en', $dir = 'ltr' ) { $resourceLoader = new ResourceLoader(); $request = new FauxRequest( array( 'lang' => $lang, @@ -10,7 +15,14 @@ abstract class ResourceLoaderTestCase extends MediaWikiTestCase { 'skin' => 'vector', 'target' => 'test', ) ); - return new ResourceLoaderContext( $resourceLoader, $request ); + $ctx = $this->getMockBuilder( 'ResourceLoaderContext' ) + ->setConstructorArgs( array( $resourceLoader, $request ) ) + ->setMethods( array( 'getDirection' ) ) + ->getMock(); + $ctx->expects( $this->any() )->method( 'getDirection' )->will( + $this->returnValue( $dir ) + ); + return $ctx; } protected function setUp() { @@ -86,10 +98,3 @@ class ResourceLoaderTestModule extends ResourceLoaderModule { class ResourceLoaderFileModuleTestModule extends ResourceLoaderFileModule { } - -class ResourceLoaderWikiModuleTestModule extends ResourceLoaderWikiModule { - // Override expected via PHPUnit mocks and stubs - protected function getPages( ResourceLoaderContext $context ) { - return array(); - } -} diff --git a/tests/phpunit/bootstrap.php b/tests/phpunit/bootstrap.php index 121aade9..a5c8ef61 100644 --- a/tests/phpunit/bootstrap.php +++ b/tests/phpunit/bootstrap.php @@ -15,14 +15,7 @@ EOF; } class MediaWikiPHPUnitBootstrap { - - public function __construct() { - wfProfileIn( __CLASS__ ); - } - public function __destruct() { - wfProfileOut( __CLASS__ ); - // Return to real wiki db, so profiling data is preserved MediaWikiTestCase::teardownTestDB(); diff --git a/tests/phpunit/data/composer/composer.json b/tests/phpunit/data/composer/composer.json new file mode 100644 index 00000000..bcd196f4 --- /dev/null +++ b/tests/phpunit/data/composer/composer.json @@ -0,0 +1,48 @@ +{ + "name": "mediawiki/core", + "description": "Free software wiki application developed by the Wikimedia Foundation and others", + "keywords": ["mediawiki", "wiki"], + "homepage": "https://www.mediawiki.org/", + "authors": [ + { + "name": "MediaWiki Community", + "homepage": "https://www.mediawiki.org/wiki/Special:Version/Credits" + } + ], + "license": "GPL-2.0", + "support": { + "issues": "https://bugzilla.wikimedia.org/", + "irc": "irc://irc.freenode.net/mediawiki", + "wiki": "https://www.mediawiki.org/" + }, + "require": { + "leafo/lessphp": "0.5.0", + "php": ">=5.3.3", + "psr/log": "1.0.0", + "cssjanus/cssjanus": "1.1.1", + "cdb/cdb": "1.0.0" + }, + "require-dev": { + "phpunit/phpunit": "*" + }, + "suggest": { + "ext-fileinfo": "*", + "ext-mbstring": "*", + "ext-wikidiff2": "*", + "ext-apc": "*", + "monolog/monolog": "*" + }, + "autoload": { + "psr-0": { + "ComposerHookHandler": "includes/composer" + } + }, + "scripts": { + "pre-update-cmd": "ComposerHookHandler::onPreUpdate", + "pre-install-cmd": "ComposerHookHandler::onPreInstall" + }, + "config": { + "prepend-autoloader": false, + "optimize-autoloader": true + } +} diff --git a/tests/phpunit/data/composer/composer.lock b/tests/phpunit/data/composer/composer.lock new file mode 100644 index 00000000..cae6a478 --- /dev/null +++ b/tests/phpunit/data/composer/composer.lock @@ -0,0 +1,1195 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "hash": "a3bb80b0ac4c4a31e52574d48c032923", + "packages": [ + { + "name": "composer/installers", + "version": "v1.0.19", + "source": { + "type": "git", + "url": "https://github.com/composer/installers.git", + "reference": "89d77bfbee79e16653f7162c86e602cc188471db" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/installers/zipball/89d77bfbee79e16653f7162c86e602cc188471db", + "reference": "89d77bfbee79e16653f7162c86e602cc188471db", + "shasum": "" + }, + "replace": { + "roundcube/plugin-installer": "*", + "shama/baton": "*" + }, + "require-dev": { + "composer/composer": "1.0.*@dev", + "phpunit/phpunit": "4.1.*" + }, + "type": "composer-installer", + "extra": { + "class": "Composer\\Installers\\Installer", + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-0": { + "Composer\\Installers\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kyle Robinson Young", + "email": "kyle@dontkry.com", + "homepage": "https://github.com/shama" + } + ], + "description": "A multi-framework Composer library installer", + "homepage": "http://composer.github.com/installers/", + "keywords": [ + "Craft", + "Dolibarr", + "Hurad", + "MODX Evo", + "OXID", + "Thelia", + "WolfCMS", + "agl", + "annotatecms", + "bitrix", + "cakephp", + "chef", + "codeigniter", + "concrete5", + "croogo", + "dokuwiki", + "drupal", + "elgg", + "fuelphp", + "grav", + "installer", + "joomla", + "kohana", + "laravel", + "lithium", + "magento", + "mako", + "mediawiki", + "modulework", + "moodle", + "phpbb", + "piwik", + "ppi", + "puppet", + "roundcube", + "shopware", + "silverstripe", + "symfony", + "typo3", + "wordpress", + "zend", + "zikula" + ], + "time": "2014-11-29 01:29:17" + }, + { + "name": "cssjanus/cssjanus", + "version": "v1.1.1", + "source": { + "type": "git", + "url": "https://github.com/cssjanus/php-cssjanus.git", + "reference": "62a9c32e6e140de09082b40a6e99d868ad14d4e0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cssjanus/php-cssjanus/zipball/62a9c32e6e140de09082b40a6e99d868ad14d4e0", + "reference": "62a9c32e6e140de09082b40a6e99d868ad14d4e0", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "jakub-onderka/php-parallel-lint": "0.8.*", + "phpunit/phpunit": "3.7.*", + "squizlabs/php_codesniffer": "1.*" + }, + "type": "library", + "autoload": { + "psr-0": { + "": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "Convert CSS stylesheets between left-to-right and right-to-left.", + "time": "2014-11-14 20:00:50" + }, + { + "name": "leafo/lessphp", + "version": "v0.5.0", + "source": { + "type": "git", + "url": "https://github.com/leafo/lessphp.git", + "reference": "0f5a7f5545d2bcf4e9fad9a228c8ad89cc9aa283" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/leafo/lessphp/zipball/0f5a7f5545d2bcf4e9fad9a228c8ad89cc9aa283", + "reference": "0f5a7f5545d2bcf4e9fad9a228c8ad89cc9aa283", + "shasum": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.4.x-dev" + } + }, + "autoload": { + "classmap": [ + "lessc.inc.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT", + "GPL-3.0" + ], + "authors": [ + { + "name": "Leaf Corcoran", + "email": "leafot@gmail.com", + "homepage": "http://leafo.net" + } + ], + "description": "lessphp is a compiler for LESS written in PHP.", + "homepage": "http://leafo.net/lessphp/", + "time": "2014-11-24 18:39:20" + }, + { + "name": "mediawiki/translate", + "version": "2014.12", + "source": { + "type": "git", + "url": "https://github.com/wikimedia/mediawiki-extensions-Translate.git", + "reference": "2bc100763f3150380412faceea258c7378ce7ea0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/wikimedia/mediawiki-extensions-Translate/zipball/2bc100763f3150380412faceea258c7378ce7ea0", + "reference": "2bc100763f3150380412faceea258c7378ce7ea0", + "shasum": "" + }, + "require": { + "composer/installers": ">=1.0.1", + "mediawiki/universal-language-selector": "*", + "php": ">=5.3.0" + }, + "suggest": { + "mediawiki/babel": "Users can easily indicate their language proficiency on their user page", + "mediawiki/translation-notifications": "Manage communication with translators", + "mustangostang/spyc": "More recent version of the bundled spyc library" + }, + "type": "mediawiki-extension", + "autoload": { + "files": [ + "Translate.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-2.0+" + ], + "authors": [ + { + "name": "Niklas Laxström", + "email": "niklas.laxstrom@gmail.com", + "role": "Lead nitpicker" + }, + { + "name": "Siebrand Mazeland", + "email": "s.mazeland@xs4all.nl", + "role": "Developer" + } + ], + "description": "The only standard solution to translate any kind of text with an avant-garde web interface within MediaWiki, including your documentation and software", + "homepage": "https://www.mediawiki.org/wiki/Extension:Translate", + "keywords": [ + "g11n", + "i18n", + "internationalization", + "l10n", + "localization", + "m17n", + "mediawiki", + "translatewiki.net", + "translation" + ], + "time": "2014-12-30 15:21:24" + }, + { + "name": "mediawiki/universal-language-selector", + "version": "2014.12", + "source": { + "type": "git", + "url": "https://github.com/wikimedia/mediawiki-extensions-UniversalLanguageSelector.git", + "reference": "f730b0f47e2828001c1e03ec40d4681bfb0bff2d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/wikimedia/mediawiki-extensions-UniversalLanguageSelector/zipball/f730b0f47e2828001c1e03ec40d4681bfb0bff2d", + "reference": "f730b0f47e2828001c1e03ec40d4681bfb0bff2d", + "shasum": "" + }, + "require": { + "composer/installers": ">=1.0.1", + "php": ">=5.3.0" + }, + "suggest": { + "mediawiki/cldr": "Language names in all languages" + }, + "type": "mediawiki-extension", + "autoload": { + "files": [ + "UniversalLanguageSelector.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-2.0+", + "MIT" + ], + "description": "The primary aim is to allow users to select a language and configure its support in an easy way. Main features are language selection, input methods and web fonts.", + "homepage": "https://www.mediawiki.org/wiki/Extension:UniversalLanguageSelector", + "keywords": [ + "Input methods", + "Language selection", + "Web fonts", + "mediawiki" + ], + "time": "2014-12-30 15:21:25" + }, + { + "name": "oojs/oojs-ui", + "version": "v0.6.0", + "source": { + "type": "git", + "url": "https://github.com/wikimedia/oojs-ui.git", + "reference": "50fa12637ad377f00bdbf1913406a3bfe9c1689e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/wikimedia/oojs-ui/zipball/50fa12637ad377f00bdbf1913406a3bfe9c1689e", + "reference": "50fa12637ad377f00bdbf1913406a3bfe9c1689e", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "php/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "homepage": "https://www.mediawiki.org/wiki/OOjs_UI", + "time": "2014-12-16 20:50:05" + }, + { + "name": "psr/log", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b", + "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b", + "shasum": "" + }, + "type": "library", + "autoload": { + "psr-0": { + "Psr\\Log\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "time": "2012-12-21 11:40:51" + }, + { + "name": "wikimedia/cdb", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/wikimedia/cdb.git", + "reference": "3b7d5366c88eccf2517ebac57c59eb557c82f46c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/wikimedia/cdb/zipball/3b7d5366c88eccf2517ebac57c59eb557c82f46c", + "reference": "3b7d5366c88eccf2517ebac57c59eb557c82f46c", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "*" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-2.0" + ], + "authors": [ + { + "name": "Tim Starling", + "email": "tstarling@wikimedia.org" + }, + { + "name": "Chad Horohoe", + "email": "chad@wikimedia.org" + } + ], + "description": "Constant Database (CDB) wrapper library for PHP. Provides pure-PHP fallback when dba_* functions are absent.", + "homepage": "https://www.mediawiki.org/wiki/CDB", + "time": "2014-12-08 19:26:44" + } + ], + "packages-dev": [ + { + "name": "doctrine/instantiator", + "version": "1.0.4", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "f976e5de371104877ebc89bd8fecb0019ed9c119" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/f976e5de371104877ebc89bd8fecb0019ed9c119", + "reference": "f976e5de371104877ebc89bd8fecb0019ed9c119", + "shasum": "" + }, + "require": { + "php": ">=5.3,<8.0-DEV" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "ext-pdo": "*", + "ext-phar": "*", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "2.0.*@ALPHA" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Instantiator\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "http://ocramius.github.com/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://github.com/doctrine/instantiator", + "keywords": [ + "constructor", + "instantiate" + ], + "time": "2014-10-13 12:58:55" + }, + { + "name": "phpunit/php-code-coverage", + "version": "2.0.14", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "ca158276c1200cc27f5409a5e338486bc0b4fc94" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ca158276c1200cc27f5409a5e338486bc0b4fc94", + "reference": "ca158276c1200cc27f5409a5e338486bc0b4fc94", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "phpunit/php-file-iterator": "~1.3", + "phpunit/php-text-template": "~1.2", + "phpunit/php-token-stream": "~1.3", + "sebastian/environment": "~1.0", + "sebastian/version": "~1.0" + }, + "require-dev": { + "ext-xdebug": ">=2.1.4", + "phpunit/phpunit": "~4.1" + }, + "suggest": { + "ext-dom": "*", + "ext-xdebug": ">=2.2.1", + "ext-xmlwriter": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "time": "2014-12-26 13:28:33" + }, + { + "name": "phpunit/php-file-iterator", + "version": "1.3.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/acd690379117b042d1c8af1fafd61bde001bf6bb", + "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "File/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "time": "2013-10-10 15:34:57" + }, + { + "name": "phpunit/php-text-template", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/206dfefc0ffe9cebf65c413e3d0e809c82fbf00a", + "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "Text/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "time": "2014-01-30 17:20:04" + }, + { + "name": "phpunit/php-timer", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/19689d4354b295ee3d8c54b4f42c3efb69cbc17c", + "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "PHP/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "time": "2013-08-02 07:42:54" + }, + { + "name": "phpunit/php-token-stream", + "version": "1.3.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "f8d5d08c56de5cfd592b3340424a81733259a876" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/f8d5d08c56de5cfd592b3340424a81733259a876", + "reference": "f8d5d08c56de5cfd592b3340424a81733259a876", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "time": "2014-08-31 06:12:13" + }, + { + "name": "phpunit/phpunit", + "version": "4.4.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "6a5e49a86ce5e33b8d0657abe145057fc513543a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/6a5e49a86ce5e33b8d0657abe145057fc513543a", + "reference": "6a5e49a86ce5e33b8d0657abe145057fc513543a", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-spl": "*", + "php": ">=5.3.3", + "phpunit/php-code-coverage": "~2.0", + "phpunit/php-file-iterator": "~1.3.2", + "phpunit/php-text-template": "~1.2", + "phpunit/php-timer": "~1.0.2", + "phpunit/phpunit-mock-objects": "~2.3", + "sebastian/comparator": "~1.0", + "sebastian/diff": "~1.1", + "sebastian/environment": "~1.1", + "sebastian/exporter": "~1.0", + "sebastian/global-state": "~1.0", + "sebastian/version": "~1.0", + "symfony/yaml": "~2.0" + }, + "suggest": { + "phpunit/php-invoker": "~1.1" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "time": "2014-12-28 07:57:05" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "2.3.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "c63d2367247365f688544f0d500af90a11a44c65" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/c63d2367247365f688544f0d500af90a11a44c65", + "reference": "c63d2367247365f688544f0d500af90a11a44c65", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "~1.0,>=1.0.1", + "php": ">=5.3.3", + "phpunit/php-text-template": "~1.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.3" + }, + "suggest": { + "ext-soap": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "keywords": [ + "mock", + "xunit" + ], + "time": "2014-10-03 05:12:11" + }, + { + "name": "sebastian/comparator", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "c484a80f97573ab934e37826dba0135a3301b26a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/c484a80f97573ab934e37826dba0135a3301b26a", + "reference": "c484a80f97573ab934e37826dba0135a3301b26a", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/diff": "~1.1", + "sebastian/exporter": "~1.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "http://www.github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "time": "2014-11-16 21:32:38" + }, + { + "name": "sebastian/diff", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "5843509fed39dee4b356a306401e9dd1a931fec7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/5843509fed39dee4b356a306401e9dd1a931fec7", + "reference": "5843509fed39dee4b356a306401e9dd1a931fec7", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Diff implementation", + "homepage": "http://www.github.com/sebastianbergmann/diff", + "keywords": [ + "diff" + ], + "time": "2014-08-15 10:29:00" + }, + { + "name": "sebastian/environment", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "6e6c71d918088c251b181ba8b3088af4ac336dd7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/6e6c71d918088c251b181ba8b3088af4ac336dd7", + "reference": "6e6c71d918088c251b181ba8b3088af4ac336dd7", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "time": "2014-10-25 08:00:45" + }, + { + "name": "sebastian/exporter", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "c7d59948d6e82818e1bdff7cadb6c34710eb7dc0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/c7d59948d6e82818e1bdff7cadb6c34710eb7dc0", + "reference": "c7d59948d6e82818e1bdff7cadb6c34710eb7dc0", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "time": "2014-09-10 00:51:36" + }, + { + "name": "sebastian/global-state", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "c7428acdb62ece0a45e6306f1ae85e1c05b09c01" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/c7428acdb62ece0a45e6306f1ae85e1c05b09c01", + "reference": "c7428acdb62ece0a45e6306f1ae85e1c05b09c01", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "time": "2014-10-06 09:23:50" + }, + { + "name": "sebastian/version", + "version": "1.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "a77d9123f8e809db3fbdea15038c27a95da4058b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/a77d9123f8e809db3fbdea15038c27a95da4058b", + "reference": "a77d9123f8e809db3fbdea15038c27a95da4058b", + "shasum": "" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "time": "2014-12-15 14:25:24" + }, + { + "name": "symfony/yaml", + "version": "v2.6.1", + "target-dir": "Symfony/Component/Yaml", + "source": { + "type": "git", + "url": "https://github.com/symfony/Yaml.git", + "reference": "3346fc090a3eb6b53d408db2903b241af51dcb20" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Yaml/zipball/3346fc090a3eb6b53d408db2903b241af51dcb20", + "reference": "3346fc090a3eb6b53d408db2903b241af51dcb20", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Yaml\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony Yaml Component", + "homepage": "http://symfony.com", + "time": "2014-12-02 20:19:20" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "platform": { + "php": ">=5.3.3" + }, + "platform-dev": [] +} diff --git a/tests/phpunit/data/composer/new-composer.json b/tests/phpunit/data/composer/new-composer.json new file mode 100644 index 00000000..0634c2dd --- /dev/null +++ b/tests/phpunit/data/composer/new-composer.json @@ -0,0 +1,48 @@ +{ + "name": "mediawiki/core", + "description": "Free software wiki application developed by the Wikimedia Foundation and others", + "keywords": ["mediawiki", "wiki"], + "homepage": "https://www.mediawiki.org/", + "authors": [ + { + "name": "MediaWiki Community", + "homepage": "https://www.mediawiki.org/wiki/Special:Version/Credits" + } + ], + "license": "GPL-2.0", + "support": { + "issues": "https://bugzilla.wikimedia.org/", + "irc": "irc://irc.freenode.net/mediawiki", + "wiki": "https://www.mediawiki.org/" + }, + "require": { + "leafo/lessphp": "0.5.0", + "php": ">=5.3.3", + "psr/log": "1.0.0", + "cssjanus/cssjanus": "1.1.1", + "wikimedia/cdb": "1.0.1" + }, + "require-dev": { + "phpunit/phpunit": "*" + }, + "suggest": { + "ext-fileinfo": "*", + "ext-mbstring": "*", + "ext-wikidiff2": "*", + "ext-apc": "*", + "monolog/monolog": "*" + }, + "autoload": { + "psr-0": { + "ComposerHookHandler": "includes/composer" + } + }, + "scripts": { + "pre-update-cmd": "ComposerHookHandler::onPreUpdate", + "pre-install-cmd": "ComposerHookHandler::onPreInstall" + }, + "config": { + "prepend-autoloader": false, + "optimize-autoloader": true + } +} diff --git a/tests/phpunit/data/cssmin/circle.svg b/tests/phpunit/data/cssmin/circle.svg new file mode 100644 index 00000000..6b7d1afd --- /dev/null +++ b/tests/phpunit/data/cssmin/circle.svg @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg xmlns="http://www.w3.org/2000/svg" width="8" height="8"> +<circle cx="4" cy="4" r="2"/> +</svg> diff --git a/tests/phpunit/data/gitinfo/info-testValidJsonData.json b/tests/phpunit/data/gitinfo/info-testValidJsonData.json index e955a2b6..8cf21bda 100644 --- a/tests/phpunit/data/gitinfo/info-testValidJsonData.json +++ b/tests/phpunit/data/gitinfo/info-testValidJsonData.json @@ -1 +1,7 @@ -{
"head": "refs/heads/master",
"headSHA1": "0123456789abcdef0123456789abcdef01234567",
"headCommitDate": "1070884800",
"branch": "master",
"remoteURL": "https://gerrit.wikimedia.org/r/mediawiki/core"
}
\ No newline at end of file +{ + "head": "refs/heads/master", + "headSHA1": "0123456789abcdef0123456789abcdef01234567", + "headCommitDate": "1070884800", + "branch": "master", + "remoteURL": "https://gerrit.wikimedia.org/r/mediawiki/core" +} diff --git a/tests/phpunit/data/helpers/WellProtectedClass.php b/tests/phpunit/data/helpers/WellProtectedClass.php new file mode 100644 index 00000000..99c7f642 --- /dev/null +++ b/tests/phpunit/data/helpers/WellProtectedClass.php @@ -0,0 +1,21 @@ +<?php + +class WellProtectedClass { + protected $property; + + public function __construct() { + $this->property = 1; + } + + protected function incrementPropertyValue() { + $this->property++; + } + + public function getProperty() { + return $this->property; + } + + protected function whatSecondArg( $a, $b = false ) { + return $b; + } +} diff --git a/tests/phpunit/data/media/Soccer_ball_animated.svg b/tests/phpunit/data/media/Soccer_ball_animated.svg index 6bd82fc4..183e43d8 100644 --- a/tests/phpunit/data/media/Soccer_ball_animated.svg +++ b/tests/phpunit/data/media/Soccer_ball_animated.svg @@ -1,55 +1,55 @@ -<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE svg>
-<svg width="150" height="150" viewBox="-105 -105 210 210" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
- <defs>
- <clipPath id="ball">
- <circle r="100" stroke-width="0"/>
- </clipPath>
- <radialGradient id="shadow1" cx=".4" cy=".3" r=".8">
- <stop offset="0" stop-color="white" stop-opacity="1"/>
- <stop offset=".4" stop-color="white" stop-opacity="1"/>
- <stop offset=".8" stop-color="#EEEEEE" stop-opacity="1"/>
- </radialGradient>
- <radialGradient id="shadow2" cx=".5" cy=".5" r=".5">
- <stop offset="0" stop-color="white" stop-opacity="0"/>
- <stop offset=".8" stop-color="white" stop-opacity="0"/>
- <stop offset=".99" stop-color="black" stop-opacity=".3"/>
- <stop offset="1" stop-color="black" stop-opacity="1"/>
- </radialGradient>
- <g id="black_stuff" stroke-linejoin="round" clip-path="url(#ball)">
- <g fill="black">
- <path d="M 6,-32 Q 26,-28 46,-19 Q 57,-35 64,-47 Q 50,-68 37,-76 Q 17,-75 1,-68 Q 4,-51 6,-32"/>
- <path d="M -26,-2 Q -45,-8 -62,-11 Q -74,5 -76,22 Q -69,40 -50,54 Q -32,47 -17,39 Q -23,15 -26,-2"/>
- <path d="M -95,22 Q -102,12 -102,-8 V 80 H -85 Q -95,45 -95,22"/>
- <path d="M 55,24 Q 41,41 24,52 Q 28,65 31,79 Q 55,78 68,67 Q 78,50 80,35 Q 65,28 55,24"/>
- <path d="M 0,120 L -3,95 Q -25,93 -42,82 Q -50,84 -60,81"/>
- <path d="M -90,-48 Q -80,-52 -68,-49 Q -52,-71 -35,-77 Q -35,-100 -40,-100 H -100"/>
- <path d="M 100,-55 L 87,-37 Q 98,-10 97,5 L 100,6"/>
- </g>
- <g fill="none">
- <path d="M 6,-32 Q -18,-12 -26,-2
- M 46,-19 Q 54,5 55,24
- M 64,-47 Q 77,-44 87,-37
- M 37,-76 Q 39,-90 36,-100
- M 1,-68 Q -13,-77 -35,-77
- M -62,-11 Q -67,-25 -68,-49
- M -76,22 Q -85,24 -95,22
- M -50,54 Q -49,70 -42,82
- M -17,39 Q 0,48 24,52
- M 31,79 Q 20,92 -3,95
- M 68,67 L 80,80
- M 80,35 Q 90,25 97,5
- "/>
- </g>
- </g>
- </defs>
- <circle r="100" fill="white" stroke="none"/>
- <circle r="100" fill="url(#shadow1)" stroke="none"/>
- <g><animateTransform attributeName="transform" attributeType="XML" type="rotate" from="0" to="360" begin="0s" dur="3s" repeatCount="indefinite"/>
- <use xlink:href="#black_stuff" stroke="#EEE" stroke-width="7"/>
- <use xlink:href="#black_stuff" stroke="#DDD" stroke-width="4"/>
- <use xlink:href="#black_stuff" stroke="#999" stroke-width="2"/>
- <use xlink:href="#black_stuff" stroke="black" stroke-width="1"/>
- </g>
- <circle r="100" fill="url(#shadow2)" stroke="none"/>
-</svg>
+<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE svg> +<svg width="150" height="150" viewBox="-105 -105 210 210" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> + <defs> + <clipPath id="ball"> + <circle r="100" stroke-width="0"/> + </clipPath> + <radialGradient id="shadow1" cx=".4" cy=".3" r=".8"> + <stop offset="0" stop-color="white" stop-opacity="1"/> + <stop offset=".4" stop-color="white" stop-opacity="1"/> + <stop offset=".8" stop-color="#EEEEEE" stop-opacity="1"/> + </radialGradient> + <radialGradient id="shadow2" cx=".5" cy=".5" r=".5"> + <stop offset="0" stop-color="white" stop-opacity="0"/> + <stop offset=".8" stop-color="white" stop-opacity="0"/> + <stop offset=".99" stop-color="black" stop-opacity=".3"/> + <stop offset="1" stop-color="black" stop-opacity="1"/> + </radialGradient> + <g id="black_stuff" stroke-linejoin="round" clip-path="url(#ball)"> + <g fill="black"> + <path d="M 6,-32 Q 26,-28 46,-19 Q 57,-35 64,-47 Q 50,-68 37,-76 Q 17,-75 1,-68 Q 4,-51 6,-32"/> + <path d="M -26,-2 Q -45,-8 -62,-11 Q -74,5 -76,22 Q -69,40 -50,54 Q -32,47 -17,39 Q -23,15 -26,-2"/> + <path d="M -95,22 Q -102,12 -102,-8 V 80 H -85 Q -95,45 -95,22"/> + <path d="M 55,24 Q 41,41 24,52 Q 28,65 31,79 Q 55,78 68,67 Q 78,50 80,35 Q 65,28 55,24"/> + <path d="M 0,120 L -3,95 Q -25,93 -42,82 Q -50,84 -60,81"/> + <path d="M -90,-48 Q -80,-52 -68,-49 Q -52,-71 -35,-77 Q -35,-100 -40,-100 H -100"/> + <path d="M 100,-55 L 87,-37 Q 98,-10 97,5 L 100,6"/> + </g> + <g fill="none"> + <path d="M 6,-32 Q -18,-12 -26,-2 + M 46,-19 Q 54,5 55,24 + M 64,-47 Q 77,-44 87,-37 + M 37,-76 Q 39,-90 36,-100 + M 1,-68 Q -13,-77 -35,-77 + M -62,-11 Q -67,-25 -68,-49 + M -76,22 Q -85,24 -95,22 + M -50,54 Q -49,70 -42,82 + M -17,39 Q 0,48 24,52 + M 31,79 Q 20,92 -3,95 + M 68,67 L 80,80 + M 80,35 Q 90,25 97,5 + "/> + </g> + </g> + </defs> + <circle r="100" fill="white" stroke="none"/> + <circle r="100" fill="url(#shadow1)" stroke="none"/> + <g><animateTransform attributeName="transform" attributeType="XML" type="rotate" from="0" to="360" begin="0s" dur="3s" repeatCount="indefinite"/> + <use xlink:href="#black_stuff" stroke="#EEE" stroke-width="7"/> + <use xlink:href="#black_stuff" stroke="#DDD" stroke-width="4"/> + <use xlink:href="#black_stuff" stroke="#999" stroke-width="2"/> + <use xlink:href="#black_stuff" stroke="black" stroke-width="1"/> + </g> + <circle r="100" fill="url(#shadow2)" stroke="none"/> +</svg> diff --git a/tests/phpunit/data/media/Tux.svg b/tests/phpunit/data/media/Tux.svg index 39561078..e48b7353 100644 --- a/tests/phpunit/data/media/Tux.svg +++ b/tests/phpunit/data/media/Tux.svg @@ -1,902 +1,902 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="100%" width="100%" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" viewBox="0 0 349.46883 405.12272">
- <title>Tux</title>
- <desc>For more information see: http://commons.wikimedia.org/wiki/Image:Tux.svg</desc>
- <radialGradient id="ag" gradientUnits="userSpaceOnUse" cy="-551.04" cx="274.822" gradientTransform="matrix(.5671 0 0 -.2835 81.263 201.645)" r="165.384">
- <stop stop-opacity=".502" offset="0"/>
- <stop stop-opacity="0" offset="1"/>
- </radialGradient>
- <path fill="url(#ag)" d="m330.892 357.885c0 25.898-41.989 46.893-93.785 46.893-51.795 0-93.784-20.994-93.784-46.893s41.989-46.893 93.784-46.893c51.795 0.001 93.785 20.995 93.785 46.893z"/>
- <radialGradient id="ak" gradientUnits="userSpaceOnUse" cy="-551.042" cx="268.794" gradientTransform="matrix(.5823 0 0 -.2835 -61.6052 201.14)" r="165.383">
- <stop stop-opacity=".502" offset="0"/>
- <stop stop-opacity="0" offset="1"/>
- </radialGradient>
- <path fill="url(#ak)" d="m191.223 357.381c0 25.897-43.117 46.892-96.306 46.892-53.188 0-96.305-20.994-96.305-46.892s43.117-46.893 96.305-46.893c53.188 0.001 96.306 20.995 96.306 46.893z"/>
- <g transform="translate(8.99996 9.00046)">
- <path d="m292.327 256.606c-4.752 19.584-28.872 60.48-41.688 78.48-12.815 18.072-11.231 34.344-34.92 28.008-23.616-6.336-30.24-5.184-54.647-3.744-24.265 1.439-19.009-0.721-34.2 6.12-15.12 6.84-65.88-82.944-69.984-99.647-4.031-16.705-5.976-14.689 4.536-32.761 10.513-18.071 12.024-35.928 25.92-57.816 13.896-21.96 29.952-33.12 28.8-49.896-4.535-62.28-8.136-93.384 19.513-107.784 26.352-13.68 48.384-5.544 57.096-0.864 3.744 2.016 11.376 5.904 17.064 12.744 5.688 6.696 10.8 16.848 13.68 29.664 5.904 25.704-2.448 17.208 4.248 46.656 6.624 29.375 20.088 43.775 36.504 67.031 16.414 23.257 33.55 61.633 28.078 83.809z"/>
- <g transform="translate(-12.4048,10.0005)">
- <path fill="#666" d="m148.47 94.049c4.319-1.728 3.592-1.958 6.472-8.222 2.304-4.824 4.328-6.898 4.256-14.242 0-7.2-2.232-9.648-5.616-14.328-3.24-4.464-8.424-4.68-11.664-4.104-1.872 0.288-4.319 2.664-5.976 6.192-1.08 2.376-1.944 5.4-2.017 8.568-0.216 8.496 0.505 11.736 2.448 17.496 2.305 6.769 7.921 10.297 12.097 8.64z"/>
- <path fill="#6d6d6d" d="m148.47 94.023c4.293-1.717 3.563-1.954 6.425-8.178 2.289-4.793 4.312-6.861 4.271-14.164 0.027-7.152-2.162-9.702-5.488-14.201-3.296-4.345-8.376-4.509-11.593-3.953-1.916 0.283-4.354 2.569-6.038 5.968-1.159 2.31-2.016 5.353-2.087 8.535-0.212 8.438 0.547 11.691 2.46 17.417 2.268 6.731 7.901 10.221 12.05 8.576z"/>
- <path fill="#757575" d="m148.471 93.996c4.264-1.706 3.533-1.95 6.377-8.133 2.273-4.762 4.296-6.823 4.288-14.085 0.053-7.105-2.093-9.756-5.363-14.075-3.35-4.225-8.327-4.338-11.52-3.801-1.961 0.278-4.389 2.474-6.099 5.744-1.242 2.245-2.089 5.305-2.16 8.501-0.207 8.38 0.591 11.647 2.473 17.34 2.231 6.691 7.881 10.144 12.004 8.509z"/>
- <path fill="#7c7c7c" d="m148.471 93.969c4.235-1.694 3.506-1.946 6.329-8.089 2.26-4.731 4.28-6.786 4.304-14.006 0.081-7.058-2.021-9.811-5.236-13.948-3.403-4.105-8.278-4.167-11.446-3.649-2.006 0.273-4.424 2.379-6.16 5.519-1.322 2.179-2.161 5.257-2.232 8.468-0.202 8.323 0.636 11.603 2.486 17.261 2.191 6.654 7.859 10.068 11.955 8.444z"/>
- <path fill="#848484" d="m148.471 93.943c4.209-1.684 3.477-1.942 6.282-8.045 2.245-4.7 4.266-6.749 4.319-13.928 0.107-7.01-1.95-9.864-5.109-13.821-3.458-3.985-8.23-3.996-11.375-3.498-2.049 0.268-4.458 2.284-6.222 5.295-1.403 2.114-2.233 5.21-2.303 8.435-0.198 8.265 0.679 11.559 2.498 17.183 2.156 6.615 7.842 9.992 11.91 8.379z"/>
- <path fill="#8c8c8c" d="m148.471 93.916c4.181-1.672 3.448-1.938 6.235-8 2.23-4.668 4.249-6.711 4.335-13.85 0.134-6.962-1.88-9.918-4.982-13.695-3.513-3.865-8.183-3.825-11.303-3.347-2.094 0.263-4.492 2.189-6.283 5.07-1.484 2.049-2.306 5.163-2.375 8.401-0.193 8.207 0.723 11.515 2.511 17.105 2.118 6.58 7.821 9.919 11.862 8.316z"/>
- <path fill="#939393" d="m148.472 93.889c4.152-1.661 3.419-1.934 6.188-7.956 2.215-4.638 4.233-6.674 4.35-13.771 0.161-6.915-1.809-9.972-4.854-13.568-3.567-3.746-8.134-3.654-11.23-3.195-2.138 0.259-4.527 2.094-6.345 4.847-1.564 1.983-2.378 5.115-2.447 8.368-0.188 8.149 0.767 11.47 2.523 17.026 2.079 6.54 7.8 9.841 11.815 8.249z"/>
- <path fill="#9b9b9b" d="m148.472 93.863c4.125-1.65 3.391-1.93 6.141-7.912 2.2-4.607 4.217-6.637 4.366-13.693 0.188-6.868-1.739-10.026-4.729-13.441-3.621-3.626-8.085-3.484-11.157-3.044-2.183 0.253-4.562 1.999-6.406 4.622-1.646 1.918-2.45 5.068-2.52 8.335-0.185 8.091 0.811 11.426 2.535 16.948 2.044 6.502 7.782 9.766 11.77 8.185z"/>
- <path fill="#a3a3a3" d="m148.472 93.836c4.097-1.639 3.361-1.926 6.094-7.867 2.185-4.576 4.201-6.599 4.382-13.614 0.214-6.82-1.669-10.081-4.603-13.315-3.676-3.506-8.036-3.313-11.084-2.893-2.229 0.249-4.598 1.904-6.47 4.398-1.726 1.852-2.521 5.021-2.591 8.301-0.18 8.034 0.854 11.382 2.548 16.87 2.008 6.465 7.763 9.691 11.724 8.12z"/>
- <path fill="#aaa" d="m148.472 93.809c4.069-1.628 3.334-1.922 6.047-7.823 2.17-4.544 4.185-6.562 4.396-13.536 0.242-6.772-1.597-10.134-4.475-13.188-3.73-3.387-7.989-3.142-11.013-2.741-2.271 0.243-4.632 1.809-6.53 4.173-1.808 1.787-2.594 4.974-2.662 8.268-0.176 7.976 0.897 11.337 2.56 16.792 1.97 6.427 7.743 9.615 11.677 8.055z"/>
- <path fill="#b2b2b2" d="m148.473 93.782c4.041-1.617 3.304-1.918 5.999-7.778 2.154-4.514 4.169-6.524 4.412-13.458 0.269-6.725-1.526-10.188-4.349-13.062-3.784-3.267-7.939-2.971-10.939-2.589-2.316 0.238-4.666 1.714-6.592 3.949-1.888 1.721-2.667 4.926-2.734 8.234-0.171 7.918 0.941 11.293 2.572 16.713 1.933 6.391 7.723 9.541 11.631 7.991z"/>
- <path fill="#bababa" d="m148.473 93.756c4.014-1.606 3.275-1.914 5.951-7.734 2.141-4.482 4.153-6.487 4.43-13.379 0.295-6.678-1.457-10.243-4.223-12.935-3.839-3.147-7.892-2.8-10.867-2.438-2.36 0.233-4.701 1.619-6.653 3.725-1.969 1.656-2.739 4.879-2.806 8.201-0.167 7.86 0.984 11.249 2.585 16.636 1.895 6.35 7.702 9.462 11.583 7.924z"/>
- <path fill="#c1c1c1" d="m148.473 93.729c3.985-1.595 3.247-1.91 5.904-7.69 2.125-4.451 4.138-6.45 4.445-13.3 0.321-6.63-1.387-10.297-4.096-12.808-3.894-3.028-7.844-2.629-10.795-2.287-2.405 0.229-4.735 1.524-6.716 3.5-2.049 1.59-2.811 4.831-2.878 8.167-0.161 7.802 1.029 11.205 2.599 16.557 1.859 6.314 7.683 9.389 11.537 7.861z"/>
- <path fill="#c9c9c9" d="m148.473 93.702c3.958-1.583 3.219-1.906 5.857-7.646 2.11-4.42 4.121-6.412 4.46-13.222 0.35-6.583-1.315-10.351-3.969-12.682-3.947-2.908-7.794-2.458-10.722-2.135-2.45 0.224-4.771 1.429-6.777 3.276-2.13 1.525-2.883 4.784-2.95 8.135-0.157 7.745 1.073 11.16 2.611 16.479 1.821 6.276 7.663 9.313 11.49 7.795z"/>
- <path fill="#d1d1d1" d="m148.474 93.676c3.93-1.573 3.188-1.902 5.809-7.601 2.097-4.389 4.107-6.375 4.477-13.144 0.375-6.535-1.245-10.404-3.842-12.555-4.002-2.788-7.747-2.287-10.65-1.984-2.493 0.219-4.805 1.334-6.837 3.052-2.213 1.459-2.957 4.736-3.022 8.101-0.153 7.687 1.116 11.116 2.623 16.401 1.782 6.237 7.642 9.237 11.442 7.73z"/>
- <path fill="#d8d8d8" d="m148.474 93.649c3.901-1.562 3.16-1.898 5.762-7.557 2.082-4.358 4.091-6.338 4.493-13.065 0.401-6.487-1.176-10.458-3.716-12.428-4.057-2.668-7.698-2.116-10.578-1.832-2.538 0.214-4.839 1.239-6.899 2.827-2.292 1.394-3.029 4.689-3.094 8.068-0.148 7.629 1.16 11.072 2.636 16.322 1.746 6.2 7.623 9.161 11.396 7.665z"/>
- <path fill="#e0e0e0" d="m148.474 93.622c3.875-1.55 3.132-1.894 5.715-7.512 2.066-4.327 4.075-6.3 4.508-12.987 0.429-6.44-1.104-10.513-3.588-12.302-4.111-2.549-7.65-1.945-10.506-1.681-2.582 0.209-4.874 1.144-6.961 2.604-2.373 1.328-3.102 4.642-3.165 8.034-0.145 7.571 1.204 11.027 2.647 16.244 1.709 6.162 7.604 9.086 11.35 7.6z"/>
- <path fill="#e8e8e8" d="m148.474 93.596c3.847-1.54 3.104-1.89 5.668-7.468 2.052-4.296 4.059-6.263 4.523-12.908 0.456-6.393-1.034-10.567-3.462-12.175-4.165-2.429-7.601-1.774-10.433-1.529-2.627 0.204-4.908 1.049-7.023 2.379-2.453 1.263-3.173 4.594-3.236 8.001-0.141 7.514 1.247 10.983 2.659 16.166 1.673 6.123 7.585 9.008 11.304 7.534z"/>
- <path fill="#efefef" d="m148.475 93.569c3.817-1.528 3.073-1.886 5.62-7.424 2.036-4.265 4.043-6.226 4.539-12.83 0.482-6.345-0.964-10.621-3.336-12.048-4.219-2.31-7.552-1.604-10.359-1.378-2.672 0.199-4.943 0.954-7.084 2.155-2.535 1.197-3.246 4.546-3.311 7.967-0.135 7.456 1.292 10.939 2.673 16.087 1.636 6.087 7.565 8.935 11.258 7.471z"/>
- <path fill="#f7f7f7" d="m148.475 93.542c3.791-1.517 3.046-1.882 5.572-7.379 2.022-4.234 4.027-6.188 4.556-12.751 0.51-6.297-0.894-10.675-3.208-11.921-4.274-2.19-7.505-1.433-10.289-1.227-2.715 0.194-4.978 0.859-7.146 1.93-2.614 1.132-3.317 4.5-3.381 7.935-0.131 7.398 1.335 10.895 2.686 16.009 1.597 6.047 7.544 8.858 11.21 7.404z"/>
- <path fill="#fff" d="m148.475 93.516c3.763-1.506 3.017-1.878 5.525-7.335 2.007-4.203 4.012-6.151 4.571-12.673 0.536-6.25-0.823-10.729-3.082-11.795-4.328-2.07-7.456-1.262-10.216-1.075-2.76 0.189-5.012 0.764-7.207 1.706-2.696 1.066-3.39 4.452-3.453 7.901-0.126 7.34 1.379 10.85 2.698 15.931 1.561 6.01 7.525 8.782 11.164 7.34z"/>
- </g>
- <path d="m132.033 74.7465c2.16 0 4.896 1.44 6.191 3.384 1.368 1.944 2.376 4.68 2.376 7.776 0 4.608-0.504 9.72-3.239 11.304-0.864 0.504-2.736 0.936-3.816 0.936-2.448 0-2.664-1.584-4.968-3.96-0.792-0.864-3.168-5.04-3.168-8.496 0-2.16-0.504-5.256 1.368-7.992 1.296-2.016 2.952-2.952 5.256-2.952z"/>
- <g transform="translate(-12.4048,10.0005)">
- <path d="m143.862 68.608c0.844-1.305 4.222-0.69 5.45 1.996 1.229 2.687 0.998 8.522 0.153 8.829-2.226 0.691-1.535-2.534-3.454-5.451-1.919-2.762-2.994-4.067-2.149-5.374z"/>
- <path fill="#070707" d="m143.916 68.664c0.833-1.289 4.169-0.681 5.381 1.971 1.215 2.653 0.985 8.414 0.152 8.717-2.198 0.682-1.516-2.502-3.411-5.382-1.895-2.728-2.956-4.017-2.122-5.306z"/>
- <path fill="#0f0f0f" d="m143.97 68.719c0.822-1.272 4.114-0.673 5.312 1.945 1.198 2.619 0.973 8.306 0.15 8.605-2.169 0.673-1.497-2.47-3.367-5.313-1.871-2.692-2.918-3.964-2.095-5.237z"/>
- <path fill="#161616" d="m144.024 68.774c0.812-1.255 4.062-0.664 5.243 1.92 1.182 2.585 0.96 8.198 0.147 8.493-2.141 0.665-1.477-2.438-3.323-5.244-1.846-2.657-2.88-3.913-2.067-5.169z"/>
- <path fill="#1e1e1e" d="m144.078 68.829c0.801-1.239 4.008-0.655 5.174 1.895 1.167 2.551 0.947 8.09 0.146 8.381-2.113 0.656-1.458-2.405-3.28-5.174-1.821-2.623-2.842-3.863-2.04-5.102z"/>
- <path fill="#262626" d="m144.132 68.884c0.791-1.222 3.955-0.646 5.105 1.87 1.151 2.517 0.935 7.982 0.144 8.27-2.085 0.647-1.438-2.374-3.235-5.105-1.798-2.589-2.805-3.812-2.014-5.035z"/>
- <path fill="#2d2d2d" d="m144.186 68.939c0.779-1.206 3.9-0.638 5.036 1.844 1.135 2.483 0.922 7.874 0.142 8.158-2.057 0.639-1.419-2.341-3.192-5.037-1.773-2.552-2.766-3.758-1.986-4.965z"/>
- <path fill="#353535" d="m144.24 68.994c0.769-1.189 3.848-0.629 4.967 1.819 1.12 2.449 0.909 7.766 0.141 8.046-2.028 0.629-1.399-2.31-3.148-4.967-1.75-2.518-2.73-3.708-1.96-4.898z"/>
- <path fill="#3d3d3d" d="m144.294 69.049c0.76-1.172 3.794-0.621 4.898 1.793 1.104 2.415 0.896 7.658 0.138 7.934-2 0.621-1.38-2.277-3.104-4.898-1.725-2.482-2.691-3.655-1.932-4.829z"/>
- <path fill="#444" d="m144.348 69.104c0.748-1.156 3.74-0.612 4.829 1.768 1.088 2.38 0.884 7.55 0.136 7.822-1.973 0.612-1.36-2.245-3.062-4.829-1.699-2.448-2.651-3.604-1.903-4.761z"/>
- <path fill="#4c4c4c" d="m144.402 69.16c0.737-1.14 3.687-0.603 4.76 1.743 1.073 2.347 0.871 7.442 0.134 7.71-1.943 0.604-1.341-2.213-3.017-4.76-1.676-2.414-2.614-3.554-1.877-4.693z"/>
- <path fill="#545454" d="m144.456 69.215c0.727-1.123 3.634-0.595 4.691 1.717 1.057 2.313 0.857 7.334 0.132 7.598-1.916 0.595-1.321-2.181-2.973-4.691-1.652-2.378-2.577-3.501-1.85-4.624z"/>
- <path fill="#5b5b5b" d="m144.51 69.27c0.717-1.106 3.58-0.585 4.622 1.692 1.041 2.278 0.847 7.226 0.131 7.486-1.888 0.586-1.303-2.149-2.93-4.622-1.628-2.343-2.539-3.45-1.823-4.556z"/>
- <path fill="#636363" d="m144.564 69.325c0.705-1.09 3.526-0.577 4.553 1.667 1.026 2.245 0.833 7.118 0.128 7.375-1.858 0.577-1.282-2.117-2.885-4.553-1.604-2.309-2.501-3.399-1.796-4.489z"/>
- <path fill="#6b6b6b" d="m144.618 69.38c0.694-1.073 3.473-0.568 4.483 1.642 1.011 2.21 0.82 7.01 0.127 7.263-1.831 0.568-1.264-2.084-2.842-4.484-1.578-2.274-2.462-3.347-1.768-4.421z"/>
- <path fill="#727272" d="m144.672 69.435c0.685-1.057 3.42-0.56 4.414 1.617 0.995 2.176 0.81 6.902 0.125 7.15-1.803 0.56-1.243-2.053-2.798-4.415-1.554-2.238-2.425-3.295-1.741-4.352z"/>
- <path fill="#7a7a7a" d="m144.726 69.49c0.673-1.041 3.365-0.551 4.345 1.591 0.979 2.143 0.796 6.794 0.123 7.039-1.775 0.551-1.224-2.021-2.754-4.346-1.53-2.203-2.387-3.244-1.714-4.284z"/>
- <path fill="#828282" d="m144.78 69.545c0.662-1.023 3.313-0.542 4.276 1.566 0.964 2.108 0.782 6.686 0.121 6.926-1.746 0.542-1.204-1.988-2.711-4.276-1.505-2.167-2.348-3.192-1.686-4.216z"/>
- <path fill="#898989" d="m144.834 69.6c0.652-1.007 3.259-0.533 4.207 1.541s0.771 6.578 0.119 6.815c-1.718 0.534-1.185-1.956-2.666-4.207-1.482-2.134-2.311-3.142-1.66-4.149z"/>
- <path fill="#919191" d="m144.888 69.655c0.641-0.99 3.206-0.524 4.138 1.516 0.933 2.04 0.758 6.47 0.117 6.703-1.69 0.525-1.165-1.924-2.623-4.138-1.457-2.098-2.273-3.09-1.632-4.081z"/>
- <path fill="#999" d="m144.942 69.71c0.63-0.974 3.152-0.516 4.069 1.49s0.744 6.362 0.114 6.591c-1.662 0.516-1.146-1.892-2.579-4.069-1.432-2.062-2.234-3.037-1.604-4.012z"/>
- </g>
- <g transform="translate(-12.4048,10.0005)">
- <path fill="#666" d="m193.11 94.985c10.8-1.152 14.616-5.328 16.56-12.6 1.729-6.48 1.801-13.68-3.023-22.104-4.536-8.063-7.128-9.36-13.681-9.864-10.079-0.864-14.832 6.192-17.063 11.232-2.376 5.472-1.872 4.68-1.729 11.592 0.145 7.272 4.245 9.299 6.766 13.835 2.519 4.465 10.946 7.982 12.17 7.909z"/>
- <path fill="#6d6d6d" d="m193.115 94.944c10.759-1.131 14.618-5.354 16.515-12.569 1.701-6.525 1.785-13.686-3.002-21.912-4.434-7.797-7.038-9.081-13.512-9.581-10.049-0.861-14.941 5.873-17.181 10.874-2.304 5.28-1.878 4.718-1.726 11.539 0.16 7.268 4.268 9.223 6.784 13.76 2.521 4.475 10.898 7.962 12.122 7.889z"/>
- <path fill="#757575" d="m193.12 94.902c10.718-1.11 14.62-5.379 16.469-12.538 1.676-6.57 1.771-13.692-2.979-21.721-4.331-7.53-6.947-8.801-13.344-9.297-10.018-0.858-15.05 5.553-17.298 10.516-2.229 5.087-1.885 4.757-1.722 11.487 0.176 7.264 4.289 9.146 6.803 13.686 2.52 4.485 10.848 7.942 12.071 7.867z"/>
- <path fill="#7c7c7c" d="m193.126 94.861c10.675-1.09 14.621-5.405 16.423-12.507 1.648-6.616 1.756-13.698-2.958-21.529-4.229-7.263-6.856-8.522-13.176-9.014-9.985-0.854-15.158 5.234-17.414 10.158-2.156 4.895-1.891 4.795-1.719 11.434 0.193 7.26 4.31 9.07 6.822 13.611 2.52 4.495 10.798 7.922 12.022 7.847z"/>
- <path fill="#848484" d="m193.131 94.82c10.635-1.069 14.623-5.431 16.377-12.476 1.622-6.661 1.741-13.704-2.936-21.337-4.126-6.996-6.767-8.242-13.008-8.73-9.955-0.852-15.267 4.915-17.53 9.8-2.084 4.703-1.896 4.833-1.716 11.38 0.209 7.256 4.332 8.995 6.841 13.537 2.52 4.505 10.748 7.902 11.972 7.826z"/>
- <path fill="#8c8c8c" d="m193.136 94.778c10.593-1.048 14.625-5.457 16.331-12.445 1.596-6.706 1.726-13.709-2.913-21.145-4.025-6.729-6.678-7.963-12.841-8.447-9.924-0.848-15.375 4.595-17.647 9.441-2.01 4.51-1.903 4.872-1.712 11.328 0.225 7.251 4.354 8.918 6.858 13.462 2.521 4.517 10.7 7.883 11.924 7.806z"/>
- <path fill="#939393" d="m193.141 94.737c10.552-1.027 14.627-5.482 16.286-12.414 1.568-6.751 1.711-13.715-2.893-20.954-3.922-6.462-6.586-7.683-12.672-8.163-9.892-0.845-15.483 4.276-17.764 9.083-1.938 4.318-1.909 4.91-1.709 11.275 0.24 7.247 4.375 8.842 6.878 13.387 2.521 4.528 10.651 7.863 11.874 7.786z"/>
- <path fill="#9b9b9b" d="m193.146 94.695c10.51-1.007 14.63-5.508 16.241-12.382 1.542-6.796 1.694-13.721-2.87-20.762-3.82-6.195-6.496-7.404-12.504-7.879-9.861-0.842-15.592 3.956-17.882 8.725-1.863 4.126-1.915 4.949-1.706 11.223 0.258 7.243 4.397 8.766 6.897 13.313 2.521 4.535 10.601 7.841 11.824 7.762z"/>
- <path fill="#a3a3a3" d="m193.151 94.654c10.469-0.986 14.632-5.534 16.196-12.351 1.515-6.842 1.68-13.727-2.85-20.57-3.717-5.928-6.405-7.125-12.335-7.596-9.83-0.839-15.7 3.637-17.998 8.367-1.791 3.933-1.922 4.987-1.703 11.169 0.273 7.239 4.419 8.689 6.916 13.238 2.521 4.547 10.551 7.822 11.774 7.743z"/>
- <path fill="#aaa" d="m193.157 94.612c10.427-0.965 14.633-5.56 16.149-12.32 1.488-6.887 1.666-13.733-2.826-20.379-3.615-5.661-6.316-6.845-12.168-7.313-9.799-0.835-15.809 3.317-18.114 8.009-1.718 3.741-1.928 5.025-1.7 11.117 0.29 7.235 4.44 8.613 6.936 13.163 2.519 4.558 10.499 7.804 11.723 7.723z"/>
- <path fill="#b2b2b2" d="m193.162 94.571c10.386-0.944 14.635-5.585 16.104-12.289 1.462-6.932 1.649-13.739-2.806-20.188-3.512-5.394-6.225-6.565-11.999-7.029-9.768-0.833-15.917 2.998-18.23 7.651-1.646 3.549-1.935 5.064-1.697 11.064 0.306 7.231 4.462 8.537 6.954 13.088 2.52 4.569 10.451 7.784 11.674 7.703z"/>
- <path fill="#bababa" d="m193.167 94.529c10.345-0.923 14.638-5.611 16.059-12.258 1.436-6.977 1.636-13.744-2.782-19.995-3.41-5.127-6.135-6.286-11.832-6.746-9.736-0.829-16.025 2.679-18.347 7.293-1.572 3.356-1.941 5.103-1.694 11.011 0.322 7.227 4.484 8.461 6.973 13.014 2.519 4.579 10.4 7.764 11.623 7.681z"/>
- <path fill="#c1c1c1" d="m193.172 94.488c10.304-0.903 14.64-5.637 16.014-12.227 1.409-7.022 1.62-13.75-2.762-19.804-3.308-4.86-6.044-6.006-11.662-6.462-9.705-0.826-16.135 2.359-18.466 6.935-1.498 3.164-1.945 5.141-1.689 10.958 0.338 7.223 4.506 8.385 6.991 12.939 2.519 4.59 10.351 7.744 11.574 7.661z"/>
- <path fill="#c9c9c9" d="m193.177 94.447c10.262-0.882 14.641-5.663 15.967-12.196 1.383-7.068 1.605-13.756-2.738-19.612-3.206-4.593-5.954-5.727-11.496-6.179-9.673-0.823-16.242 2.04-18.581 6.577-1.425 2.972-1.952 5.179-1.687 10.906 0.354 7.219 4.526 8.308 7.01 12.865 2.52 4.598 10.302 7.723 11.525 7.639z"/>
- <path fill="#d1d1d1" d="m193.182 94.405c10.221-0.861 14.643-5.688 15.922-12.165 1.355-7.113 1.591-13.762-2.717-19.42-3.104-4.326-5.864-5.448-11.327-5.895-9.644-0.82-16.352 1.721-18.698 6.219-1.353 2.779-1.959 5.217-1.684 10.853 0.369 7.214 4.549 8.232 7.028 12.79 2.521 4.609 10.254 7.703 11.476 7.618z"/>
- <path fill="#d8d8d8" d="m193.187 94.364c10.179-0.841 14.645-5.714 15.876-12.133 1.33-7.158 1.576-13.768-2.694-19.229-3.001-4.059-5.773-5.168-11.16-5.612-9.61-0.817-16.459 1.401-18.813 5.861-1.279 2.586-1.965 5.256-1.682 10.8 0.387 7.21 4.571 8.156 7.049 12.715 2.519 4.619 10.202 7.684 11.424 7.598z"/>
- <path fill="#e0e0e0" d="m193.193 94.322c10.137-0.82 14.646-5.74 15.83-12.103 1.303-7.203 1.561-13.773-2.673-19.037-2.898-3.792-5.684-4.889-10.991-5.328-9.58-0.813-16.568 1.082-18.931 5.502-1.206 2.395-1.972 5.294-1.679 10.747 0.403 7.207 4.592 8.08 7.067 12.641 2.521 4.631 10.154 7.666 11.377 7.578z"/>
- <path fill="#e8e8e8" d="m193.198 94.281c10.096-0.799 14.648-5.766 15.785-12.071 1.275-7.249 1.545-13.779-2.651-18.845-2.796-3.525-5.593-4.609-10.823-5.044-9.549-0.81-16.677 0.762-19.048 5.145-1.133 2.202-1.978 5.333-1.675 10.694 0.419 7.202 4.614 8.003 7.086 12.566 2.52 4.638 10.103 7.643 11.326 7.555z"/>
- <path fill="#efefef" d="m193.203 94.239c10.055-0.778 14.65-5.792 15.739-12.04 1.25-7.293 1.531-13.785-2.629-18.653-2.694-3.258-5.502-4.33-10.655-4.761-9.517-0.807-16.785 0.443-19.165 4.786-1.059 2.01-1.983 5.372-1.671 10.642 0.435 7.198 4.636 7.928 7.104 12.492 2.52 4.649 10.055 7.624 11.277 7.534z"/>
- <path fill="#f7f7f7" d="m193.208 94.198c10.014-0.757 14.652-5.817 15.694-12.009 1.223-7.339 1.516-13.792-2.607-18.462-2.592-2.991-5.413-4.05-10.486-4.478-9.487-0.804-16.895 0.124-19.282 4.428-0.986 1.817-1.989 5.41-1.668 10.589 0.451 7.194 4.657 7.851 7.123 12.417 2.519 4.661 10.004 7.605 11.226 7.515z"/>
- <path fill="#fff" d="m193.213 94.156c9.973-0.737 14.654-5.843 15.648-11.978 1.197-7.384 1.501-13.797-2.585-18.27-2.489-2.724-5.322-3.771-10.319-4.194-9.455-0.801-17.002-0.196-19.397 4.07-0.913 1.625-1.996 5.448-1.665 10.536 0.467 7.19 4.679 7.775 7.142 12.342 2.519 4.671 9.954 7.586 11.176 7.494z"/>
- </g>
- <path d="m179.841 74.4585c5.4 0 8.568 4.824 9.648 11.016 0.432 2.808-0.216 6.048-1.944 8.28-1.944 2.592-5.4 4.176-8.208 4.176-2.664 0-5.688 0.432-7.271-1.728-1.584-2.232-1.944-7.2-1.944-10.728 0-3.96 1.152-6.768 3.168-9 1.511-1.657 4.247-2.016 6.551-2.016z"/>
- <g transform="translate(-12.4048,10.0005)">
- <path d="m192.591 66.68c0.98-0.653 2.612 0 4.489 2.122 2.039 2.285 2.938 4.08 0.489 5.385-1.877 0.98-2.448-1.958-3.59-3.182-1.795-1.959-3.346-3.02-1.388-4.325z"/>
- <path fill="#070707" d="m192.631 66.738c0.96-0.649 2.573 0 4.423 2.09 2.009 2.251 2.864 4.02 0.481 5.305-1.837 0.977-2.403-1.929-3.525-3.135-1.768-1.925-3.296-2.965-1.379-4.26z"/>
- <path fill="#0f0f0f" d="m192.671 66.797c0.939-0.645 2.534 0 4.356 2.059 1.978 2.217 2.792 3.958 0.474 5.225-1.798 0.974-2.357-1.9-3.46-3.087-1.742-1.895-3.247-2.913-1.37-4.197z"/>
- <path fill="#161616" d="m192.711 66.855c0.919-0.641 2.495 0 4.289 2.027 1.948 2.184 2.721 3.898 0.467 5.146-1.759 0.971-2.313-1.871-3.396-3.041-1.715-1.861-3.197-2.858-1.36-4.132z"/>
- <path fill="#1e1e1e" d="m192.751 66.914c0.899-0.637 2.457 0 4.223 1.996 1.918 2.149 2.647 3.838 0.46 5.065-1.72 0.968-2.269-1.842-3.331-2.993-1.689-1.83-3.148-2.805-1.352-4.068z"/>
- <path fill="#262626" d="m192.791 66.973c0.878-0.633 2.418 0 4.155 1.964 1.888 2.116 2.576 3.777 0.453 4.986-1.68 0.965-2.224-1.813-3.267-2.946-1.661-1.798-3.097-2.752-1.341-4.004z"/>
- <path fill="#2d2d2d" d="m192.831 67.031c0.858-0.629 2.379 0 4.089 1.933 1.857 2.082 2.503 3.717 0.445 4.906-1.641 0.961-2.178-1.784-3.201-2.898-1.636-1.767-3.048-2.7-1.333-3.941z"/>
- <path fill="#353535" d="m192.87 67.09c0.838-0.625 2.341 0 4.023 1.902 1.827 2.047 2.431 3.656 0.438 4.826-1.601 0.958-2.133-1.755-3.137-2.852-1.608-1.735-2.998-2.646-1.324-3.876z"/>
- <path fill="#3d3d3d" d="m192.91 67.148c0.818-0.621 2.302 0 3.956 1.87 1.797 2.014 2.359 3.596 0.431 4.746-1.562 0.956-2.088-1.726-3.071-2.804-1.583-1.702-2.95-2.592-1.316-3.812z"/>
- <path fill="#444" d="m192.95 67.207c0.798-0.617 2.263 0 3.889 1.839 1.768 1.98 2.287 3.535 0.425 4.666-1.523 0.952-2.043-1.697-3.008-2.757-1.556-1.671-2.899-2.539-1.306-3.748z"/>
- <path fill="#4c4c4c" d="m192.99 67.266c0.777-0.614 2.224 0 3.823 1.807 1.735 1.946 2.214 3.474 0.416 4.586-1.483 0.949-1.998-1.667-2.942-2.709-1.529-1.639-2.85-2.486-1.297-3.684z"/>
- <path fill="#545454" d="m193.03 67.325c0.757-0.61 2.185 0 3.756 1.775 1.706 1.912 2.143 3.414 0.409 4.506-1.444 0.946-1.953-1.639-2.878-2.663-1.502-1.606-2.799-2.431-1.287-3.618z"/>
- <path fill="#5b5b5b" d="m193.07 67.383c0.736-0.605 2.146 0 3.688 1.744 1.677 1.878 2.07 3.353 0.402 4.426-1.405 0.943-1.908-1.609-2.813-2.615-1.475-1.575-2.749-2.378-1.277-3.555z"/>
- <path fill="#636363" d="m193.11 67.442c0.716-0.602 2.106 0 3.622 1.712 1.646 1.844 1.998 3.293 0.395 4.347-1.364 0.94-1.862-1.581-2.748-2.568-1.449-1.543-2.701-2.326-1.269-3.491z"/>
- <path fill="#6b6b6b" d="m193.15 67.5c0.696-0.598 2.069 0 3.556 1.681 1.615 1.811 1.925 3.232 0.387 4.267-1.325 0.937-1.818-1.552-2.683-2.521-1.423-1.511-2.651-2.272-1.26-3.427z"/>
- <path fill="#727272" d="m193.19 67.559c0.675-0.594 2.03 0 3.489 1.649 1.585 1.777 1.853 3.172 0.38 4.187-1.287 0.935-1.774-1.522-2.619-2.473-1.396-1.48-2.601-2.219-1.25-3.363z"/>
- <path fill="#7a7a7a" d="m193.23 67.618c0.654-0.59 1.991 0 3.422 1.618 1.555 1.743 1.781 3.111 0.373 4.107-1.247 0.931-1.729-1.494-2.554-2.426-1.369-1.448-2.551-2.166-1.241-3.299z"/>
- <path fill="#828282" d="m193.269 67.677c0.635-0.586 1.953 0 3.355 1.586 1.525 1.708 1.709 3.05 0.366 4.026-1.208 0.928-1.684-1.464-2.489-2.378-1.342-1.416-2.501-2.112-1.232-3.234z"/>
- <path fill="#898989" d="m193.309 67.735c0.614-0.582 1.914 0 3.29 1.555 1.493 1.675 1.636 2.99 0.357 3.947-1.169 0.925-1.639-1.435-2.424-2.332-1.316-1.384-2.452-2.058-1.223-3.17z"/>
- <path fill="#919191" d="m193.349 67.794c0.595-0.578 1.875 0 3.223 1.523 1.464 1.641 1.564 2.93 0.351 3.867-1.129 0.922-1.594-1.406-2.359-2.284-1.29-1.352-2.403-2.005-1.215-3.106z"/>
- <path fill="#999" d="m193.389 67.853c0.573-0.574 1.836 0 3.155 1.492 1.435 1.607 1.492 2.869 0.345 3.787-1.091 0.919-1.55-1.377-2.295-2.237-1.263-1.32-2.353-1.953-1.205-3.042z"/>
- </g>
- <g transform="translate(-12.4048,10.0005)">
- <path d="m165.498 69.906c1.693-0.654 3.012-0.69 5.63 1.036 3.166 2.088 1.705 5.245-0.779 4.601-2.146-0.556-2.417-0.681-4.391-1.086-3.101-0.648-3.641-3.322-0.46-4.551z"/>
- <path fill="#050505" d="m165.564 70.033c1.658-0.629 2.973-0.656 5.555 1.026 3.066 2.009 1.654 5.012-0.805 4.38-2.131-0.547-2.345-0.656-4.284-1.052-3.055-0.634-3.587-3.173-0.466-4.354z"/>
- <path fill="#0a0a0a" d="m165.63 70.16c1.623-0.604 2.935-0.622 5.481 1.015 2.965 1.93 1.602 4.779-0.83 4.159-2.119-0.539-2.274-0.63-4.179-1.018-3.009-0.618-3.533-3.022-0.472-4.156z"/>
- <path fill="#0f0f0f" d="m165.696 70.287c1.587-0.579 2.895-0.587 5.406 1.005 2.864 1.851 1.551 4.546-0.855 3.938-2.105-0.53-2.203-0.605-4.073-0.983-2.963-0.604-3.48-2.873-0.478-3.96z"/>
- <path fill="#141414" d="m165.761 70.413c1.553-0.553 2.856-0.553 5.331 0.995 2.766 1.772 1.5 4.313-0.88 3.717-2.092-0.521-2.131-0.58-3.967-0.949-2.916-0.588-3.425-2.723-0.484-3.763z"/>
- <path fill="#191919" d="m165.827 70.54c1.519-0.528 2.818-0.519 5.258 0.984 2.664 1.693 1.448 4.079-0.905 3.497-2.079-0.513-2.06-0.554-3.861-0.915-2.873-0.573-3.373-2.573-0.492-3.566z"/>
- <path fill="#1e1e1e" d="m165.893 70.667c1.482-0.503 2.778-0.484 5.183 0.974 2.564 1.614 1.397 3.846-0.93 3.276-2.067-0.504-1.989-0.529-3.756-0.88-2.826-0.559-3.319-2.425-0.497-3.37z"/>
- <path fill="#232323" d="m165.959 70.793c1.447-0.478 2.74-0.45 5.108 0.964 2.464 1.535 1.345 3.613-0.955 3.055-2.053-0.496-1.917-0.503-3.651-0.846-2.779-0.543-3.264-2.274-0.502-3.173z"/>
- <path fill="#282828" d="m166.025 70.92c1.412-0.453 2.701-0.416 5.034 0.954 2.362 1.456 1.293 3.38-0.981 2.834-2.04-0.487-1.845-0.478-3.545-0.812-2.733-0.528-3.21-2.125-0.508-2.976z"/>
- <path fill="#2d2d2d" d="m166.09 71.047c1.378-0.428 2.663-0.382 4.96 0.943 2.264 1.377 1.242 3.146-1.006 2.613-2.026-0.478-1.773-0.453-3.438-0.777-2.688-0.513-3.158-1.974-0.516-2.779z"/>
- <path fill="#333" d="m166.156 71.173c1.343-0.402 2.624-0.347 4.885 0.933 2.163 1.298 1.191 2.914-1.029 2.392-2.015-0.47-1.703-0.428-3.334-0.743-2.642-0.498-3.104-1.824-0.522-2.582z"/>
- <path fill="#383838" d="m166.222 71.3c1.307-0.377 2.585-0.313 4.81 0.922 2.063 1.219 1.14 2.681-1.055 2.171-2.001-0.461-1.631-0.402-3.229-0.708-2.594-0.483-3.048-1.674-0.526-2.385z"/>
- <path fill="#3d3d3d" d="m166.288 71.427c1.272-0.352 2.546-0.279 4.736 0.913 1.962 1.14 1.088 2.447-1.081 1.95-1.988-0.452-1.56-0.377-3.122-0.674-2.55-0.469-2.995-1.526-0.533-2.189z"/>
- <path fill="#424242" d="m166.354 71.554c1.236-0.327 2.507-0.245 4.661 0.902 1.861 1.061 1.037 2.214-1.106 1.729-1.974-0.444-1.488-0.352-3.016-0.64-2.504-0.453-2.942-1.375-0.539-1.991z"/>
- <path fill="#474747" d="m166.419 71.68c1.203-0.302 2.469-0.21 4.587 0.892 1.762 0.982 0.986 1.98-1.13 1.508-1.962-0.435-1.417-0.326-2.911-0.606-2.458-0.437-2.888-1.224-0.546-1.794z"/>
- <path fill="#4c4c4c" d="m166.485 71.807c1.167-0.276 2.429-0.176 4.513 0.882 1.66 0.903 0.935 1.748-1.156 1.288-1.948-0.426-1.345-0.301-2.805-0.572-2.412-0.423-2.834-1.076-0.552-1.598z"/>
- <path fill="#515151" d="m166.551 71.934c1.133-0.251 2.391-0.142 4.438 0.871 1.56 0.824 0.883 1.515-1.181 1.067-1.936-0.417-1.274-0.275-2.699-0.537-2.366-0.408-2.781-0.926-0.558-1.401z"/>
- <path fill="#565656" d="m166.617 72.061c1.097-0.227 2.351-0.108 4.363 0.861 1.46 0.745 0.831 1.281-1.206 0.846-1.922-0.409-1.202-0.25-2.594-0.503-2.319-0.393-2.726-0.777-0.563-1.204z"/>
- <path fill="#5b5b5b" d="m166.683 72.187c1.062-0.201 2.312-0.073 4.289 0.851 1.358 0.666 0.778 1.048-1.231 0.625-1.91-0.4-1.131-0.225-2.489-0.469-2.274-0.377-2.672-0.626-0.569-1.007z"/>
- <path fill="#606060" d="m166.748 72.314c1.027-0.176 2.274-0.04 4.215 0.84 1.26 0.587 0.729 0.815-1.256 0.404-1.896-0.392-1.06-0.2-2.383-0.435-2.228-0.361-2.619-0.475-0.576-0.809z"/>
- <path fill="#666" d="m166.814 72.44c0.992-0.151 2.234-0.005 4.14 0.83 1.159 0.508 0.677 0.582-1.281 0.183-1.883-0.383-0.987-0.174-2.276-0.4-2.183-0.346-2.566-0.325-0.583-0.613z"/>
- </g>
- <g transform="translate(-12.4048,10.0005)">
- <path fill="#666" d="m159.99 128.249c-9.36 0.36-24.192-25.848-24.552-14.976-0.288 9.216 0.216 9.072 0.216 18 0 5.976-2.736 6.408-8.64 15.408-3.024 4.752-5.4 9.864-7.272 15.048-1.152 3.096-2.232 6.336-3.096 9.504-0.36 1.584-1.008 3.24-1.368 4.824-2.952 10.872-13.464 24.264-15.912 35.136-2.448 10.8-5.328 17.712-4.968 32.185 0.36 14.472 0.504 10.295 4.896 13.896 4.32 3.601 8.784 6.983 15.624 13.032 7.2 6.264 22.177 17.208 24.192 20.592 2.16 3.456 2.088 11.232 0.792 13.752-1.296 2.448-12.6 3.816-12.528 3.816-0.071 0 9.864 13.68 11.809 15.623 1.872 1.873 9.936 10.873 42.768 4.752 18.504-3.455 32.832-13.823 43.2-23.832 13.392-13.031 6.624-16.775 8.352-23.327 2.521-9.433 10.729-12.96 12.601-23.616 0.216-1.512 0.72-2.664 2.088-4.896 2.088-3.168 1.584-9.432 1.584-15.191 0-14.977-1.729-30.24-5.185-41.472-3.168-10.512-8.208-17.856-12.527-27.36-8.641-18.936-8.208-27.432-15.912-39.528-8.784-13.968-4.464-23.256-16.128-22.68-14.546 0.79-26.282 20.734-40.034 21.31z"/>
- <path fill="#6d6d6d" d="m159.973 129.334c-9.281 0.353-23.746-25.511-24.242-15.179-0.316 8.755 0.1 8.678 0.03 17.247-0.15 5.87-2.953 6.637-8.727 15.481-3.013 4.763-5.273 9.812-6.993 14.877-0.968 3.253-1.56 6.422-2.43 9.526-0.415 1.642-1.497 3.187-2.185 5.042-3.254 10.78-13.545 24.182-15.961 34.877-2.466 10.81-5.37 17.694-4.961 32.141 0.366 14 0.395 10.177 4.773 13.816 4.283 3.616 8.839 7.069 15.662 13.103 7.183 6.248 22.237 17.216 24.243 20.588 2.149 3.444 2.131 11.317 0.844 13.823-1.284 2.439-12.579 3.875-12.508 3.875-0.071 0 9.815 13.566 11.757 15.508 1.87 1.87 9.902 10.809 42.678 4.704 18.524-3.455 33.124-13.753 43.078-23.856 12.789-12.762 6.107-16.773 7.826-23.291 2.513-9.416 11.277-12.961 13.143-23.602 0.216-1.508 0.754-2.654 2.113-4.876 2.096-3.202 1.561-9.447 1.582-15.185 0.067-15.027-1.705-30.234-5.159-41.434-3.171-10.483-8.204-17.817-12.515-27.305-8.624-18.906-8.221-27.415-15.933-39.474-8.586-13.613-4.601-22.583-16.011-21.99-14.374 0.826-26.375 21.016-40.104 21.584z"/>
- <path fill="#757575" d="m159.955 130.419c-9.201 0.346-23.299-25.175-23.931-15.383-0.344 8.295-0.017 8.284-0.156 16.494-0.301 5.764-3.17 6.867-8.812 15.555-3.002 4.774-5.148 9.76-6.714 14.706-0.784 3.41-0.889 6.508-1.764 9.548-0.471 1.699-1.986 3.133-3.003 5.259-3.554 10.688-13.624 24.1-16.009 34.619-2.483 10.82-5.411 17.678-4.954 32.097 0.373 13.528 0.285 10.058 4.651 13.739 4.244 3.632 8.893 7.154 15.699 13.171 7.167 6.233 22.299 17.224 24.294 20.585 2.142 3.432 2.175 11.404 0.896 13.896-1.271 2.428-12.558 3.932-12.486 3.932-0.071 0 9.768 13.453 11.705 15.392 1.867 1.867 9.867 10.744 42.588 4.655 18.545-3.453 33.415-13.682 42.956-23.879 12.187-12.492 5.591-16.771 7.3-23.258 2.507-9.398 11.826-12.959 13.687-23.586 0.215-1.5 0.788-2.643 2.138-4.854 2.104-3.235 1.538-9.462 1.58-15.178 0.133-15.076-1.681-30.228-5.135-41.394-3.173-10.455-8.199-17.779-12.501-27.25-8.609-18.877-8.234-27.399-15.952-39.42-8.389-13.258-4.739-21.911-15.895-21.301-14.21 0.859-26.474 21.295-40.182 21.855z"/>
- <path fill="#7c7c7c" d="m159.938 131.504c-9.122 0.338-22.854-24.838-23.622-15.586-0.37 7.833-0.131 7.89-0.341 15.741-0.452 5.657-3.388 7.096-8.899 15.628-2.99 4.785-5.021 9.708-6.433 14.535-0.602 3.566-0.218 6.594-1.099 9.57-0.526 1.756-2.475 3.08-3.82 5.477-3.854 10.596-13.703 24.016-16.057 34.361-2.501 10.829-5.453 17.66-4.948 32.052 0.38 13.059 0.177 9.939 4.529 13.66 4.208 3.648 8.948 7.239 15.739 13.242 7.149 6.217 22.358 17.232 24.345 20.581 2.13 3.42 2.216 11.489 0.946 13.968-1.259 2.417-12.538 3.99-12.466 3.99-0.072 0 9.718 13.34 11.653 15.275 1.865 1.864 9.833 10.681 42.498 4.607 18.565-3.453 33.706-13.609 42.834-23.902 11.583-12.223 5.074-16.771 6.774-23.223 2.499-9.382 12.375-12.959 14.229-23.57 0.215-1.496 0.821-2.633 2.162-4.834 2.111-3.271 1.516-9.478 1.578-15.173 0.199-15.125-1.657-30.221-5.109-41.354-3.177-10.427-8.196-17.741-12.488-27.195-8.594-18.848-8.247-27.383-15.972-39.366-8.192-12.903-4.877-21.239-15.779-20.612-14.041 0.894-26.569 21.576-40.254 22.128z"/>
- <path fill="#848484" d="m159.921 132.589c-9.043 0.331-22.406-24.502-23.312-15.79-0.398 7.373-0.247 7.496-0.527 14.988-0.602 5.551-3.604 7.326-8.984 15.702-2.98 4.796-4.896 9.656-6.154 14.364-0.417 3.723 0.455 6.679-0.432 9.592-0.582 1.813-2.964 3.026-4.639 5.694-4.153 10.504-13.782 23.936-16.104 34.104-2.519 10.838-5.495 17.643-4.941 32.008 0.387 12.586 0.067 9.819 4.407 13.582 4.171 3.664 9.002 7.324 15.777 13.311 7.132 6.201 22.419 17.24 24.396 20.576 2.12 3.41 2.259 11.578 0.998 14.041-1.247 2.408-12.517 4.049-12.446 4.049-0.07 0 9.67 13.227 11.604 15.16 1.861 1.861 9.798 10.615 42.409 4.558 18.584-3.45 33.996-13.538 42.711-23.926 10.979-11.952 4.557-16.769 6.248-23.187 2.491-9.367 12.924-12.959 14.771-23.557 0.215-1.49 0.856-2.622 2.188-4.813 2.118-3.305 1.491-9.494 1.575-15.166 0.267-15.174-1.635-30.215-5.086-41.314-3.179-10.399-8.19-17.703-12.473-27.141-8.579-18.818-8.262-27.366-15.994-39.312-7.993-12.547-5.013-20.565-15.661-19.922-13.876 0.927-26.669 21.855-40.331 22.399z"/>
- <path fill="#8c8c8c" d="m159.903 133.674c-8.963 0.323-21.961-24.165-23.001-15.994-0.426 6.912-0.363 7.102-0.713 14.236-0.753 5.445-3.821 7.554-9.071 15.775-2.969 4.807-4.768 9.604-5.875 14.192-0.232 3.881 1.128 6.766 0.234 9.615-0.638 1.87-3.452 2.972-5.455 5.911-4.455 10.413-13.862 23.853-16.153 33.845-2.537 10.849-5.537 17.625-4.935 31.963 0.393 12.115-0.042 9.701 4.285 13.505 4.133 3.68 9.057 7.409 15.814 13.38 7.116 6.188 22.48 17.248 24.447 20.574 2.109 3.398 2.301 11.662 1.049 14.113-1.235 2.396-12.496 4.104-12.425 4.104-0.071 0 9.622 13.114 11.552 15.045 1.86 1.858 9.763 10.552 42.319 4.509 18.604-3.449 34.288-13.467 42.589-23.949 10.377-11.682 4.04-16.766 5.721-23.15 2.486-9.35 13.474-12.959 15.316-23.542 0.214-1.483 0.89-2.611 2.213-4.793 2.126-3.339 1.468-9.507 1.573-15.158 0.333-15.224-1.611-30.208-5.062-41.276-3.181-10.37-8.186-17.664-12.459-27.085-8.563-18.789-8.275-27.35-16.014-39.258-7.796-12.192-5.151-19.893-15.545-19.233-13.707 0.961-26.763 22.134-40.404 22.671z"/>
- <path fill="#939393" d="m159.886 134.759c-8.885 0.316-21.516-23.829-22.691-16.197-0.454 6.451-0.479 6.708-0.899 13.482-0.903 5.339-4.038 7.784-9.157 15.849-2.957 4.818-4.642 9.552-5.595 14.021-0.05 4.037 1.799 6.852 0.9 9.637-0.693 1.928-3.941 2.919-6.273 6.129-4.756 10.32-13.941 23.77-16.201 33.587-2.555 10.858-5.579 17.608-4.928 31.92 0.399 11.644-0.151 9.581 4.162 13.424 4.096 3.697 9.111 7.494 15.854 13.451 7.099 6.17 22.541 17.256 24.498 20.569 2.1 3.387 2.344 11.75 1.101 14.186-1.223 2.387-12.476 4.163-12.404 4.163-0.071 0 9.573 13.001 11.5 14.929 1.857 1.856 9.729 10.488 42.229 4.461 18.625-3.449 34.579-13.396 42.467-23.973 9.774-11.412 3.523-16.764 5.195-23.115 2.479-9.334 14.022-12.959 15.858-23.527 0.214-1.479 0.924-2.601 2.238-4.772 2.134-3.373 1.445-9.522 1.571-15.151 0.399-15.273-1.587-30.201-5.036-41.237-3.185-10.342-8.184-17.625-12.446-27.03-8.548-18.76-8.288-27.333-16.034-39.204-7.598-11.837-5.289-19.221-15.428-18.544-13.543 0.994-26.863 22.413-40.481 22.942z"/>
- <path fill="#9b9b9b" d="m159.868 135.844c-8.805 0.308-21.068-23.492-22.381-16.401-0.481 5.991-0.594 6.314-1.085 12.73-1.053 5.232-4.253 8.013-9.243 15.922-2.946 4.829-4.515 9.5-5.314 13.85 0.133 4.194 2.471 6.937 1.565 9.658-0.749 1.986-4.43 2.866-7.091 6.347-5.056 10.229-14.021 23.689-16.249 33.329-2.572 10.868-5.621 17.591-4.921 31.876 0.405 11.172-0.261 9.463 4.04 13.346 4.058 3.713 9.166 7.58 15.892 13.521 7.082 6.155 22.601 17.265 24.548 20.567 2.092 3.373 2.388 11.834 1.152 14.256-1.21 2.377-12.454 4.222-12.383 4.222-0.071 0 9.523 12.888 11.45 14.813 1.854 1.854 9.692 10.424 42.138 4.412 18.645-3.447 34.871-13.324 42.345-23.996 9.171-11.143 3.007-16.762 4.669-23.08 2.472-9.317 14.572-12.959 16.401-23.514 0.214-1.473 0.958-2.588 2.265-4.75 2.142-3.408 1.421-9.539 1.568-15.145 0.466-15.324-1.564-30.196-5.012-41.198-3.187-10.313-8.179-17.587-12.433-26.976-8.533-18.73-8.301-27.316-16.054-39.149-7.401-11.482-5.426-18.548-15.313-17.855-13.373 1.029-26.958 22.694-40.554 23.215z"/>
- <path fill="#a3a3a3" d="m159.851 136.929c-8.727 0.301-20.622-23.156-22.071-16.604-0.509 5.529-0.71 5.919-1.271 11.976-1.203 5.126-4.47 8.243-9.328 15.996-2.936 4.84-4.39 9.448-5.036 13.679 0.316 4.351 3.143 7.023 2.231 9.68-0.804 2.043-4.919 2.812-7.908 6.563-5.356 10.137-14.101 23.607-16.298 33.072-2.589 10.877-5.661 17.574-4.913 31.832 0.412 10.699-0.37 9.342 3.918 13.268 4.021 3.729 9.221 7.664 15.93 13.59 7.064 6.139 22.661 17.271 24.599 20.563 2.081 3.363 2.43 11.922 1.204 14.33-1.198 2.365-12.434 4.278-12.363 4.278-0.07 0 9.477 12.774 11.399 14.697 1.851 1.851 9.659 10.36 42.048 4.364 18.666-3.447 35.162-13.254 42.223-24.021 8.568-10.873 2.49-16.761 4.144-23.045 2.464-9.301 15.121-12.958 16.943-23.498 0.215-1.467 0.992-2.579 2.29-4.729 2.148-3.441 1.398-9.553 1.566-15.139 0.532-15.373-1.541-30.189-4.987-41.158-3.188-10.285-8.174-17.549-12.419-26.921-8.518-18.701-8.313-27.3-16.073-39.096-7.204-11.126-5.564-17.875-15.196-17.165-13.21 1.064-27.058 22.975-40.632 23.488z"/>
- <path fill="#aaa" d="m159.834 138.014c-8.646 0.293-20.176-22.819-21.761-16.808-0.536 5.069-0.826 5.526-1.457 11.224-1.354 5.02-4.687 8.472-9.416 16.069-2.924 4.851-4.262 9.396-4.756 13.508 0.501 4.507 3.814 7.109 2.897 9.702-0.858 2.1-5.406 2.759-8.725 6.782-5.657 10.045-14.181 23.524-16.347 32.812-2.606 10.888-5.703 17.557-4.906 31.787 0.418 10.229-0.479 9.225 3.795 13.189 3.984 3.745 9.275 7.749 15.968 13.66 7.048 6.124 22.723 17.279 24.651 20.559 2.07 3.352 2.472 12.008 1.255 14.402-1.186 2.355-12.414 4.337-12.343 4.337-0.071 0 9.428 12.66 11.348 14.581 1.85 1.848 9.624 10.297 41.958 4.314 18.687-3.444 35.453-13.18 42.102-24.043 7.965-10.602 1.973-16.758 3.616-23.01 2.457-9.283 15.67-12.957 17.487-23.482 0.214-1.461 1.026-2.568 2.315-4.709 2.155-3.477 1.375-9.568 1.563-15.131 0.6-15.424-1.518-30.184-4.963-41.119-3.192-10.257-8.17-17.511-12.405-26.866-8.502-18.672-8.328-27.284-16.095-39.042-7.005-10.771-5.701-17.203-15.078-16.476-13.04 1.098-27.152 23.255-40.703 23.76z"/>
- <path fill="#b2b2b2" d="m159.816 139.099c-8.567 0.286-19.729-22.483-21.45-17.012-0.563 4.608-0.942 5.132-1.643 10.471-1.506 4.914-4.904 8.701-9.502 16.143-2.913 4.862-4.137 9.344-4.477 13.336 0.685 4.665 4.486 7.195 3.564 9.725-0.915 2.157-5.897 2.705-9.543 6.999-5.958 9.953-14.262 23.443-16.396 32.554-2.624 10.898-5.745 17.54-4.9 31.744 0.426 9.757-0.588 9.105 3.674 13.111 3.945 3.761 9.33 7.834 16.006 13.729 7.032 6.109 22.783 17.288 24.702 20.557 2.06 3.338 2.515 12.094 1.306 14.473-1.173 2.346-12.392 4.395-12.321 4.395-0.07 0 9.379 12.549 11.296 14.465 1.847 1.848 9.591 10.234 41.868 4.268 18.706-3.444 35.745-13.11 41.979-24.066 7.361-10.332 1.456-16.757 3.091-22.974 2.45-9.269 16.219-12.958 18.03-23.47 0.213-1.455 1.06-2.557 2.34-4.688 2.164-3.509 1.352-9.583 1.562-15.124 0.665-15.473-1.494-30.177-4.938-41.08-3.195-10.228-8.166-17.472-12.393-26.811-8.486-18.642-8.341-27.267-16.114-38.987-6.809-10.416-5.838-16.531-14.962-15.787-12.873 1.129-27.25 23.531-40.779 24.029z"/>
- <path fill="#bababa" d="m159.799 140.184c-8.487 0.279-19.282-22.146-21.141-17.215-0.591 4.147-1.057 4.737-1.828 9.717-1.656 4.808-5.121 8.931-9.588 16.217-2.902 4.873-4.01 9.292-4.197 13.165 0.868 4.822 5.158 7.281 4.23 9.747-0.971 2.215-6.385 2.651-10.361 7.216-6.258 9.861-14.339 23.36-16.442 32.297-2.643 10.906-5.787 17.521-4.894 31.699 0.432 9.285-0.697 8.986 3.552 13.032 3.908 3.776 9.384 7.919 16.043 13.799 7.016 6.093 22.845 17.296 24.753 20.552 2.051 3.328 2.559 12.18 1.358 14.547-1.161 2.334-12.372 4.451-12.301 4.451-0.071 0 9.33 12.436 11.245 14.35 1.844 1.844 9.555 10.17 41.777 4.219 18.727-3.443 36.036-13.039 41.857-24.09 6.759-10.063 0.939-16.756 2.565-22.939 2.442-9.25 16.768-12.957 18.572-23.453 0.213-1.451 1.095-2.547 2.365-4.668 2.171-3.543 1.329-9.599 1.56-15.117 0.732-15.522-1.471-30.172-4.913-41.042-3.197-10.2-8.161-17.433-12.379-26.756-8.471-18.612-8.354-27.25-16.135-38.933-6.609-10.061-5.976-15.858-14.845-15.098-12.706 1.165-27.347 23.813-40.853 24.303z"/>
- <path fill="#c1c1c1" d="m159.781 141.269c-8.408 0.271-18.837-21.81-20.83-17.419-0.619 3.687-1.173 4.344-2.014 8.965-1.808 4.701-5.338 9.16-9.674 16.29-2.892 4.884-3.885 9.24-3.918 12.994 1.052 4.978 5.829 7.367 4.896 9.769-1.026 2.272-6.874 2.598-11.178 7.434-6.56 9.769-14.419 23.277-16.491 32.039-2.66 10.916-5.829 17.504-4.887 31.656 0.438 8.813-0.807 8.867 3.43 12.953 3.87 3.793 9.438 8.004 16.082 13.868 6.997 6.077 22.904 17.304 24.803 20.55 2.041 3.314 2.601 12.266 1.409 14.617-1.149 2.324-12.351 4.51-12.28 4.51-0.07 0 9.282 12.321 11.194 14.233 1.841 1.842 9.521 10.106 41.688 4.17 18.746-3.44 36.326-12.967 41.734-24.112 6.156-9.793 0.423-16.754 2.038-22.904 2.438-9.235 17.318-12.957 19.117-23.438 0.212-1.444 1.128-2.536 2.39-4.647 2.18-3.578 1.306-9.613 1.558-15.11 0.799-15.571-1.447-30.165-4.889-41.002-3.2-10.172-8.156-17.395-12.364-26.701-8.456-18.583-8.367-27.234-16.155-38.88-6.413-9.705-6.114-15.185-14.729-14.408-12.541 1.197-27.445 24.091-40.93 24.573z"/>
- <path fill="#c9c9c9" d="m159.764 142.354c-8.329 0.264-18.392-21.473-20.521-17.622-0.646 3.225-1.289 3.949-2.2 8.211-1.957 4.596-5.555 9.39-9.761 16.364-2.879 4.895-3.757 9.188-3.638 12.823 1.235 5.135 6.502 7.453 5.562 9.791-1.081 2.329-7.362 2.544-11.995 7.651-6.859 9.677-14.499 23.195-16.54 31.78-2.677 10.927-5.87 17.488-4.879 31.611 0.444 8.344-0.916 8.748 3.307 12.875 3.834 3.81 9.492 8.09 16.121 13.939 6.98 6.061 22.965 17.311 24.854 20.545 2.031 3.303 2.643 12.352 1.461 14.69-1.137 2.313-12.33 4.567-12.26 4.567-0.07 0 9.233 12.209 11.143 14.117 1.839 1.84 9.486 10.043 41.599 4.122 18.767-3.44 36.618-12.896 41.612-24.137 5.554-9.522-0.094-16.751 1.513-22.868 2.43-9.219 17.866-12.957 19.659-23.424 0.213-1.439 1.162-2.525 2.415-4.627 2.188-3.612 1.282-9.629 1.556-15.104 0.865-15.621-1.424-30.158-4.864-40.962-3.202-10.144-8.153-17.357-12.351-26.646-8.441-18.554-8.381-27.218-16.176-38.826-6.216-9.35-6.251-14.513-14.612-13.719-12.374 1.235-27.543 24.375-41.005 24.849z"/>
- <path fill="#d1d1d1" d="m159.747 143.439c-8.25 0.256-17.944-21.137-20.21-17.826-0.675 2.765-1.406 3.555-2.386 7.459-2.108 4.489-5.772 9.619-9.847 16.437-2.869 4.906-3.631 9.136-3.358 12.652 1.419 5.292 7.174 7.538 6.228 9.812-1.137 2.387-7.852 2.491-12.813 7.869-7.161 9.586-14.579 23.114-16.588 31.522-2.695 10.938-5.912 17.471-4.873 31.568 0.451 7.871-1.025 8.629 3.185 12.797 3.796 3.824 9.547 8.174 16.158 14.008 6.964 6.047 23.026 17.32 24.905 20.541 2.021 3.292 2.686 12.439 1.513 14.764-1.125 2.303-12.31 4.625-12.239 4.625-0.07 0 9.186 12.094 11.092 14.002 1.836 1.836 9.45 9.978 41.509 4.072 18.786-3.439 36.909-12.824 41.49-24.16 4.948-9.252-0.611-16.748 0.985-22.832 2.423-9.203 18.415-12.957 20.203-23.41 0.212-1.434 1.196-2.514 2.44-4.605 2.193-3.646 1.259-9.645 1.553-15.098 0.932-15.67-1.4-30.151-4.84-40.922-3.205-10.115-8.148-17.319-12.336-26.592-8.427-18.524-8.396-27.201-16.197-38.771-6.017-8.995-6.388-13.84-14.495-13.03-12.207 1.266-27.64 24.652-41.079 25.118z"/>
- <path fill="#d8d8d8" d="m159.729 144.524c-8.17 0.249-17.498-20.8-19.9-18.03-0.702 2.304-1.521 3.162-2.571 6.706-2.259 4.383-5.988 9.848-9.933 16.511-2.858 4.917-3.504 9.084-3.079 12.48 1.604 5.449 7.846 7.625 6.895 9.835-1.193 2.444-8.342 2.438-13.631 8.087-7.461 9.493-14.658 23.031-16.637 31.262-2.712 10.947-5.953 17.455-4.865 31.524 0.458 7.399-1.135 8.511 3.063 12.718 3.758 3.842 9.601 8.26 16.196 14.078 6.946 6.031 23.087 17.328 24.956 20.538 2.011 3.28 2.729 12.524 1.563 14.835-1.112 2.293-12.289 4.684-12.218 4.684-0.071 0 9.136 11.981 11.04 13.886 1.834 1.834 9.417 9.913 41.419 4.024 18.807-3.438 37.2-12.752 41.368-24.184 4.346-8.982-1.128-16.747 0.46-22.798 2.416-9.187 18.964-12.956 20.746-23.394 0.211-1.429 1.229-2.504 2.465-4.586 2.202-3.681 1.236-9.658 1.551-15.091 0.998-15.72-1.377-30.146-4.814-40.884-3.208-10.086-8.145-17.28-12.323-26.536-8.411-18.495-8.408-27.185-16.217-38.717-5.82-8.64-6.526-13.168-14.38-12.341-12.04 1.303-27.736 24.934-41.154 25.393z"/>
- <path fill="#e0e0e0" d="m159.712 145.609c-8.091 0.241-17.052-20.464-19.59-18.233-0.729 1.843-1.637 2.767-2.757 5.953-2.409 4.276-6.206 10.077-10.02 16.584-2.847 4.928-3.378 9.032-2.8 12.309 1.787 5.606 8.519 7.711 7.561 9.857-1.248 2.502-8.829 2.384-14.448 8.304-7.761 9.402-14.738 22.95-16.684 31.006-2.731 10.955-5.996 17.436-4.859 31.48 0.464 6.928-1.244 8.389 2.939 12.639 3.722 3.857 9.656 8.344 16.234 14.148 6.932 6.014 23.148 17.336 25.008 20.533 2 3.268 2.771 12.611 1.615 14.907-1.1 2.282-12.268 4.741-12.198 4.741-0.069 0 9.089 11.867 10.989 13.77 1.831 1.831 9.382 9.85 41.329 3.977 18.827-3.438 37.492-12.683 41.246-24.207 3.743-8.715-1.646-16.746-0.066-22.762 2.409-9.171 19.514-12.957 21.289-23.381 0.211-1.422 1.265-2.494 2.49-4.564 2.21-3.715 1.213-9.674 1.549-15.084 1.065-15.77-1.354-30.139-4.791-40.844-3.21-10.058-8.14-17.241-12.309-26.481-8.396-18.466-8.421-27.168-16.237-38.664-5.622-8.284-6.663-12.495-14.262-11.651-11.872 1.335-27.833 25.212-41.228 25.663z"/>
- <path fill="#e8e8e8" d="m159.694 146.694c-8.012 0.234-16.605-20.127-19.279-18.437-0.757 1.383-1.753 2.373-2.943 5.2-2.56 4.171-6.423 10.307-10.105 16.658-2.835 4.939-3.251 8.979-2.52 12.138 1.97 5.763 9.189 7.796 8.226 9.879-1.303 2.559-9.318 2.33-15.265 8.521-8.063 9.31-14.818 22.867-16.733 30.748-2.748 10.967-6.037 17.419-4.853 31.436 0.472 6.457-1.353 8.271 2.818 12.562 3.685 3.873 9.711 8.429 16.273 14.218 6.913 6 23.207 17.344 25.058 20.529 1.991 3.257 2.814 12.697 1.666 14.98-1.087 2.271-12.247 4.799-12.177 4.799-0.07 0 9.04 11.755 10.938 13.654 1.829 1.828 9.349 9.785 41.239 3.926 18.847-3.435 37.783-12.609 41.124-24.229 3.14-8.444-2.161-16.743-0.592-22.728 2.401-9.152 20.062-12.955 21.831-23.364 0.211-1.417 1.298-2.483 2.516-4.544 2.217-3.748 1.19-9.689 1.547-15.076 1.132-15.82-1.331-30.133-4.766-40.806-3.213-10.03-8.136-17.203-12.296-26.427-8.38-18.436-8.435-27.151-16.257-38.609-5.425-7.929-6.802-11.822-14.146-10.962-11.706 1.368-27.931 25.491-41.304 25.934z"/>
- <path fill="#efefef" d="m159.677 147.779c-7.934 0.226-16.16-19.791-18.97-18.64-0.785 0.921-1.869 1.979-3.13 4.447-2.71 4.064-6.639 10.536-10.19 16.731-2.824 4.95-3.125 8.928-2.24 11.967 2.152 5.919 9.86 7.882 8.892 9.901-1.358 2.616-9.808 2.277-16.083 8.739-8.363 9.218-14.896 22.784-16.781 30.489-2.766 10.977-6.079 17.402-4.846 31.393 0.478 5.984-1.462 8.152 2.696 12.482 3.646 3.889 9.765 8.514 16.311 14.287 6.896 5.983 23.269 17.352 25.109 20.526 1.98 3.245 2.855 12.782 1.718 15.052-1.076 2.262-12.227 4.857-12.156 4.857-0.07 0 8.991 11.641 10.887 13.537 1.826 1.826 9.313 9.723 41.148 3.879 18.868-3.434 38.074-12.538 41.002-24.254 2.537-8.174-2.678-16.741-1.119-22.69 2.396-9.138 20.612-12.957 22.375-23.351 0.212-1.412 1.332-2.473 2.541-4.523 2.226-3.783 1.166-9.704 1.545-15.07 1.197-15.869-1.307-30.125-4.741-40.766-3.215-10.002-8.131-17.165-12.282-26.372-8.365-18.407-8.447-27.135-16.277-38.555-5.228-7.574-6.938-11.15-14.029-10.272-11.541 1.402-28.029 25.771-41.38 26.206z"/>
- <path fill="#f7f7f7" d="m159.66 148.864c-7.854 0.219-15.714-19.454-18.66-18.844-0.812 0.461-1.983 1.585-3.314 3.694-2.86 3.958-6.856 10.766-10.278 16.805-2.813 4.961-2.998 8.876-1.96 11.796 2.337 6.076 10.533 7.968 9.558 9.923-1.415 2.673-10.296 2.223-16.899 8.956-8.664 9.126-14.978 22.702-16.83 30.23-2.783 10.986-6.121 17.386-4.839 31.349 0.484 5.515-1.571 8.033 2.573 12.403 3.609 3.906 9.82 8.6 16.35 14.357 6.88 5.969 23.329 17.36 25.16 20.523 1.971 3.232 2.898 12.869 1.77 15.124-1.063 2.252-12.206 4.915-12.136 4.915-0.07 0 8.942 11.527 10.835 13.422 1.824 1.822 9.279 9.658 41.059 3.83 18.889-3.434 38.366-12.467 40.881-24.278 1.934-7.903-3.195-16.739-1.646-22.655 2.388-9.121 21.161-12.955 22.918-23.336 0.211-1.404 1.366-2.461 2.566-4.502 2.232-3.816 1.143-9.719 1.542-15.063 1.265-15.92-1.283-30.12-4.717-40.727-3.219-9.974-8.128-17.127-12.269-26.317-8.349-18.378-8.461-27.119-16.298-38.501-5.029-7.219-7.075-10.478-13.912-9.584-11.373 1.438-28.126 26.053-41.454 26.48z"/>
- <path fill="#fff" d="m159.642 149.949c-7.774 0.211-15.268-19.118-18.35-19.048-0.84 0-2.1 1.191-3.501 2.941-3.011 3.852-7.072 10.995-10.363 16.878-2.803 4.972-2.872 8.824-1.682 11.625 2.521 6.233 11.205 8.054 10.225 9.945-1.471 2.731-10.785 2.17-17.719 9.174-8.964 9.034-15.056 22.621-16.877 29.973-2.801 10.995-6.163 17.368-4.832 31.304 0.49 5.043-1.681 7.914 2.451 12.325 3.571 3.923 9.874 8.685 16.387 14.427 6.863 5.953 23.391 17.368 25.211 20.521 1.962 3.221 2.942 12.954 1.821 15.196-1.051 2.24-12.185 4.972-12.115 4.972-0.069 0 8.895 11.416 10.784 13.307 1.821 1.82 9.244 9.595 40.97 3.781 18.907-3.431 38.656-12.396 40.758-24.302 1.331-7.633-3.712-16.736-2.171-22.619 2.381-9.104 21.71-12.956 23.461-23.321 0.21-1.399 1.399-2.45 2.591-4.481 2.24-3.852 1.12-9.734 1.54-15.057 1.331-15.968-1.26-30.113-4.692-40.688-3.221-9.945-8.123-17.088-12.255-26.262-8.334-18.348-8.474-27.102-16.318-38.447-4.832-6.863-7.213-9.805-13.796-8.894-11.205 1.469-28.222 26.33-41.528 26.75z"/>
- </g>
- <path fill="#995900" d="m152.553 88.8575c5.256-0.648 12.456 0.648 15.769 3.096 3.096 2.304 5.256 3.528 8.063 4.464 9.433 3.096 21.816 4.536 21.24 13.032-0.648 10.151-3.6 14.688-12.024 17.351-6.768 2.088-18.863 13.824-28.224 13.824-4.176 0-10.008 0.216-13.392-1.008-3.24-1.152-7.776-6.624-13.104-11.016-5.328-4.32-10.296-8.928-10.439-14.976-0.217-6.407 3.96-8.496 9.863-13.607 3.097-2.736 8.712-7.272 12.601-9.288 3.599-1.799 5.903-1.439 9.647-1.872z"/>
- <g transform="translate(-12.4048,10.0005)">
- <path fill="#9e5f00" d="m165.068 78.951c5.225-0.644 12.384 0.645 15.677 3.079 3.078 2.29 5.227 3.51 8.018 4.438 9.375 3.078 21.729 4.529 21.159 12.973-0.641 10.09-3.669 14.581-12.041 17.223-6.723 2.073-18.768 13.589-28.07 13.64-4.21 0.032-9.926 0.234-13.287-0.977-3.215-1.142-7.737-6.608-13.031-10.969-5.291-4.292-10.26-8.774-10.317-14.765-0.153-6.252 3.912-8.411 9.773-13.488 3.071-2.71 8.594-7.303 12.463-9.333 3.563-1.803 5.933-1.392 9.656-1.821z"/>
- <path fill="#a36400" d="m165.177 79.044c5.195-0.641 12.313 0.64 15.587 3.06 3.06 2.278 5.194 3.494 7.971 4.413 9.317 3.06 21.641 4.522 21.078 12.914-0.634 10.027-3.737 14.474-12.058 17.094-6.678 2.057-18.673 13.352-27.919 13.454-4.241 0.064-9.842 0.252-13.18-0.945-3.19-1.133-7.7-6.592-12.96-10.921-5.254-4.264-10.222-8.622-10.192-14.555-0.093-6.099 3.863-8.329 9.681-13.369 3.048-2.685 8.478-7.335 12.328-9.379 3.526-1.804 5.963-1.338 9.664-1.766z"/>
- <path fill="#a86a00" d="m165.287 79.138c5.165-0.637 12.241 0.637 15.496 3.043 3.042 2.264 5.165 3.476 7.924 4.387 9.26 3.042 21.556 4.515 20.998 12.854-0.627 9.968-3.805 14.368-12.074 16.967-6.633 2.042-18.576 13.117-27.766 13.27-4.276 0.096-9.759 0.27-13.075-0.914-3.165-1.123-7.661-6.577-12.887-10.874-5.217-4.236-10.187-8.468-10.069-14.345-0.03-5.943 3.815-8.244 9.589-13.249 3.023-2.66 8.36-7.366 12.191-9.424 3.49-1.808 5.993-1.291 9.673-1.715z"/>
- <path fill="#ad7000" d="m165.396 79.23c5.135-0.633 12.17 0.633 15.404 3.025 3.025 2.251 5.137 3.46 7.88 4.361 9.201 3.025 21.467 4.508 20.917 12.796-0.62 9.905-3.874 14.26-12.093 16.837-6.586 2.027-18.479 12.882-27.611 13.086-4.311 0.127-9.677 0.287-12.971-0.883-3.14-1.113-7.622-6.561-12.814-10.826-5.18-4.208-10.148-8.315-9.945-14.135 0.031-5.789 3.768-8.16 9.497-13.129 2.999-2.635 8.244-7.398 12.055-9.47 3.454-1.808 6.023-1.24 9.681-1.662z"/>
- <path fill="#b27600" d="m165.506 79.325c5.105-0.63 12.099 0.629 15.314 3.007 3.007 2.237 5.104 3.442 7.832 4.335 9.145 3.007 21.38 4.501 20.837 12.737-0.614 9.844-3.943 14.154-12.109 16.709-6.541 2.011-18.385 12.645-27.46 12.9-4.342 0.16-9.592 0.306-12.862-0.851-3.115-1.103-7.584-6.545-12.743-10.779-5.144-4.18-10.112-8.162-9.821-13.924 0.092-5.634 3.718-8.076 9.405-13.009 2.975-2.609 8.126-7.429 11.919-9.514 3.416-1.812 6.052-1.192 9.688-1.611z"/>
- <path fill="#b77b00" d="m165.615 79.417c5.075-0.626 12.026 0.626 15.224 2.989 2.989 2.225 5.075 3.425 7.786 4.31 9.087 2.989 21.292 4.494 20.756 12.678-0.606 9.781-4.012 14.046-12.126 16.581-6.496 1.997-18.289 12.41-27.307 12.716-4.376 0.191-9.51 0.323-12.758-0.82-3.09-1.094-7.546-6.53-12.671-10.732-5.106-4.152-10.074-8.008-9.697-13.713 0.155-5.479 3.67-7.992 9.313-12.889 2.951-2.585 8.011-7.461 11.783-9.56 3.38-1.814 6.083-1.143 9.697-1.56z"/>
- <path fill="#bc8100" d="m165.725 79.511c5.044-0.622 11.954 0.622 15.133 2.972 2.971 2.211 5.045 3.408 7.739 4.284 9.029 2.971 21.205 4.487 20.675 12.619-0.6 9.719-4.079 13.939-12.143 16.451-6.45 1.982-18.192 12.175-27.153 12.532-4.41 0.223-9.428 0.341-12.653-0.789-3.065-1.084-7.507-6.514-12.598-10.684-5.069-4.124-10.038-7.855-9.574-13.504 0.217-5.324 3.622-7.908 9.222-12.77 2.926-2.559 7.894-7.492 11.646-9.605 3.344-1.816 6.113-1.092 9.706-1.506z"/>
- <path fill="#c18700" d="m165.834 79.604c5.015-0.618 11.883 0.619 15.043 2.954 2.953 2.198 5.015 3.391 7.693 4.259 8.972 2.953 21.118 4.48 20.594 12.559-0.593 9.66-4.147 13.833-12.159 16.324-6.405 1.967-18.098 11.94-27.002 12.347-4.441 0.255-9.343 0.359-12.546-0.757-3.04-1.074-7.469-6.498-12.526-10.637-5.032-4.096-10-7.701-9.45-13.293 0.278-5.169 3.574-7.823 9.13-12.649 2.903-2.534 7.776-7.524 11.511-9.651 3.306-1.821 6.141-1.044 9.712-1.456z"/>
- <path fill="#c68d00" d="m165.944 79.697c4.984-0.615 11.811 0.614 14.952 2.936 2.935 2.184 4.983 3.374 7.646 4.233 8.915 2.935 21.031 4.473 20.515 12.5-0.586 9.597-4.218 13.726-12.177 16.195-6.36 1.951-18.002 11.703-26.849 12.162-4.476 0.287-9.261 0.377-12.441-0.726-3.015-1.064-7.431-6.482-12.453-10.589-4.995-4.068-9.965-7.549-9.326-13.083 0.34-5.015 3.524-7.741 9.038-12.531 2.878-2.508 7.658-7.555 11.374-9.696 3.269-1.82 6.171-0.992 9.721-1.401z"/>
- <path fill="#cc9200" d="m166.054 79.791c4.952-0.61 11.738 0.611 14.86 2.918 2.918 2.172 4.954 3.357 7.601 4.207 8.857 2.918 20.942 4.466 20.432 12.442-0.578 9.536-4.285 13.62-12.192 16.066-6.314 1.936-17.906 11.468-26.696 11.978-4.509 0.319-9.178 0.394-12.335-0.696-2.989-1.054-7.393-6.466-12.382-10.541-4.959-4.04-9.928-7.395-9.202-12.873 0.401-4.859 3.477-7.655 8.945-12.411 2.854-2.482 7.542-7.586 11.239-9.741 3.233-1.824 6.201-0.943 9.73-1.349z"/>
- <path fill="#d19800" d="m166.163 79.883c4.923-0.606 11.668 0.608 14.771 2.901 2.9 2.158 4.924 3.339 7.554 4.181 8.801 2.9 20.855 4.459 20.352 12.383-0.571 9.474-4.353 13.512-12.21 15.938-6.269 1.921-17.81 11.233-26.543 11.793-4.542 0.351-9.094 0.413-12.229-0.664-2.965-1.044-7.354-6.45-12.311-10.494-4.921-4.012-9.89-7.241-9.079-12.662 0.465-4.705 3.431-7.571 8.855-12.29 2.83-2.458 7.425-7.618 11.102-9.787 3.197-1.827 6.231-0.893 9.738-1.299z"/>
- <path fill="#d69e00" d="m166.273 79.978c4.893-0.603 11.596 0.603 14.679 2.882 2.883 2.145 4.895 3.323 7.507 4.156 8.744 2.882 20.77 4.452 20.272 12.324-0.565 9.412-4.422 13.406-12.228 15.81-6.224 1.905-17.714 10.996-26.39 11.608-4.576 0.383-9.012 0.431-12.124-0.633-2.94-1.034-7.316-6.434-12.237-10.446-4.884-3.984-9.854-7.089-8.955-12.452 0.525-4.551 3.382-7.489 8.764-12.171 2.805-2.432 7.307-7.649 10.965-9.832 3.16-1.829 6.261-0.845 9.747-1.246z"/>
- <path fill="#dba300" d="m166.382 80.07c4.863-0.599 11.525 0.6 14.59 2.865 2.864 2.131 4.862 3.305 7.461 4.13 8.686 2.864 20.682 4.445 20.19 12.264-0.559 9.352-4.491 13.299-12.244 15.681-6.179 1.89-17.619 10.761-26.237 11.423-4.608 0.415-8.929 0.449-12.018-0.601-2.915-1.024-7.277-6.418-12.166-10.399-4.847-3.956-9.815-6.935-8.831-12.241 0.587-4.396 3.333-7.404 8.671-12.051 2.782-2.407 7.191-7.681 10.83-9.878 3.123-1.829 6.29-0.793 9.754-1.193z"/>
- <path fill="#e0a900" d="m166.492 80.164c4.832-0.595 11.453 0.596 14.498 2.847 2.847 2.118 4.833 3.289 7.414 4.104 8.629 2.846 20.595 4.438 20.111 12.205-0.553 9.29-4.56 13.193-12.262 15.553-6.134 1.875-17.522 10.526-26.085 11.239-4.642 0.447-8.845 0.467-11.912-0.57-2.89-1.015-7.238-6.402-12.093-10.351-4.81-3.928-9.78-6.782-8.708-12.032 0.649-4.241 3.285-7.32 8.58-11.932 2.757-2.381 7.073-7.712 10.693-9.923 3.088-1.831 6.321-0.743 9.764-1.14z"/>
- <path fill="#e5af00" d="m166.601 80.257c4.803-0.592 11.382 0.592 14.407 2.829 2.829 2.105 4.804 3.271 7.368 4.079 8.571 2.828 20.507 4.431 20.029 12.146-0.544 9.228-4.627 13.085-12.277 15.423-6.089 1.861-17.427 10.29-25.932 11.055-4.676 0.478-8.763 0.484-11.807-0.539-2.865-1.005-7.2-6.387-12.021-10.304-4.772-3.9-9.742-6.629-8.583-11.821 0.711-4.085 3.236-7.236 8.487-11.812 2.732-2.357 6.957-7.744 10.557-9.968 3.052-1.834 6.351-0.694 9.772-1.088z"/>
- <path fill="#eab500" d="m166.711 80.351c4.772-0.588 11.31 0.589 14.317 2.811 2.811 2.092 4.771 3.254 7.321 4.054 8.514 2.81 20.42 4.424 19.948 12.087-0.538 9.165-4.695 12.979-12.294 15.295-6.044 1.845-17.332 10.054-25.779 10.869-4.708 0.511-8.68 0.503-11.7-0.507-2.84-0.995-7.163-6.371-11.949-10.257-4.736-3.872-9.706-6.475-8.46-11.61 0.773-3.931 3.188-7.152 8.396-11.692 2.709-2.331 6.839-7.775 10.421-10.013 3.013-1.839 6.38-0.645 9.779-1.037z"/>
- <path fill="#efba00" d="m166.82 80.443c4.742-0.584 11.238 0.585 14.226 2.794 2.794 2.078 4.743 3.237 7.276 4.027 8.456 2.793 20.332 4.417 19.868 12.029-0.531 9.104-4.766 12.872-12.313 15.167-5.997 1.83-17.234 9.819-25.626 10.685-4.742 0.542-8.596 0.52-11.595-0.476-2.815-0.985-7.124-6.355-11.877-10.209-4.699-3.844-9.668-6.322-8.336-11.4 0.835-3.778 3.14-7.068 8.304-11.573 2.686-2.306 6.724-7.807 10.285-10.059 2.978-1.84 6.411-0.595 9.788-0.985z"/>
- <path fill="#f4c000" d="m166.93 80.537c4.711-0.58 11.166 0.582 14.135 2.776 2.775 2.066 4.713 3.22 7.229 4.002 8.399 2.775 20.246 4.41 19.787 11.969-0.522 9.043-4.832 12.765-12.328 15.039-5.952 1.815-17.139 9.584-25.473 10.501-4.776 0.574-8.513 0.538-11.49-0.445-2.79-0.976-7.085-6.34-11.804-10.162-4.662-3.816-9.632-6.168-8.213-11.189 0.896-3.623 3.092-6.984 8.213-11.454 2.66-2.281 6.604-7.838 10.147-10.104 2.942-1.844 6.441-0.547 9.797-0.933z"/>
- <path fill="#f9c600" d="m167.039 80.63c4.683-0.577 11.095 0.577 14.045 2.758 2.758 2.052 4.683 3.203 7.184 3.976 8.341 2.757 20.157 4.403 19.706 11.91-0.518 8.981-4.901 12.659-12.346 14.911-5.906 1.799-17.044 9.347-25.32 10.315-4.809 0.606-8.431 0.556-11.384-0.413-2.765-0.966-7.048-6.324-11.732-10.114-4.625-3.788-9.594-6.016-8.088-10.98 0.958-3.467 3.043-6.9 8.12-11.333 2.637-2.256 6.488-7.87 10.013-10.15 2.902-1.844 6.468-0.495 9.802-0.88z"/>
- </g>
- <path fill="#fc0" d="m154.744 90.7245c4.65-0.573 11.022 0.574 13.954 2.74 2.739 2.039 4.651 3.186 7.136 3.951 8.284 2.739 20.071 4.396 19.626 11.851-0.51 8.919-4.97 12.551-12.362 14.781-5.861 1.784-16.947 9.112-25.168 10.131-4.842 0.638-8.347 0.574-11.277-0.382-2.74-0.956-7.01-6.308-11.66-10.067-4.588-3.76-9.559-5.862-7.965-10.769 1.02-3.313 2.995-6.816 8.028-11.213 2.612-2.23 6.371-7.901 9.876-10.195 2.867-1.847 6.499-0.447 9.812-0.828z"/>
- <g transform="translate(-12.4048,10.0005)">
- <path fill="#fc0" d="m167.982 83.609c1.008 2.088 3.6 2.376 5.328 3.312 1.655 0.936 2.592 1.152 3.239 0.792 1.44-0.792 0.36-3.384-1.079-4.32-1.368-0.935-8.064-1.151-7.488 0.216z"/>
- <path fill="#f9c600" d="m168.125 83.631c0.982 2.035 3.508 2.316 5.193 3.229 1.614 0.912 2.526 1.123 3.158 0.771 1.402-0.771 0.35-3.298-1.054-4.21-1.332-0.913-7.859-1.123-7.297 0.21z"/>
- <path fill="#f4c000" d="m168.267 83.653c0.957 1.982 3.418 2.255 5.058 3.144 1.572 0.889 2.461 1.094 3.076 0.752 1.367-0.752 0.342-3.213-1.025-4.101-1.299-0.889-7.656-1.094-7.109 0.205z"/>
- <path fill="#efba00" d="m168.409 83.674c0.932 1.929 3.327 2.195 4.924 3.06 1.53 0.865 2.395 1.064 2.993 0.732 1.331-0.732 0.333-3.127-0.998-3.992-1.264-0.864-7.451-1.064-6.919 0.2z"/>
- <path fill="#eab500" d="m168.552 83.696c0.905 1.876 3.234 2.135 4.787 2.977 1.488 0.841 2.329 1.035 2.912 0.711 1.294-0.711 0.323-3.041-0.971-3.882-1.228-0.841-7.246-1.036-6.728 0.194z"/>
- <path fill="#e5af00" d="m168.694 83.718c0.881 1.823 3.144 2.075 4.653 2.892 1.446 0.818 2.264 1.006 2.83 0.692 1.257-0.692 0.313-2.956-0.943-3.773-1.195-0.818-7.043-1.007-6.54 0.189z"/>
- <path fill="#e0a900" d="m168.837 83.739c0.855 1.771 3.053 2.015 4.519 2.809 1.403 0.793 2.198 0.977 2.747 0.671 1.221-0.671 0.306-2.87-0.916-3.664-1.161-0.793-6.839-0.976-6.35 0.184z"/>
- <path fill="#dba300" d="m168.979 83.761c0.829 1.718 2.962 1.955 4.383 2.725 1.363 0.77 2.132 0.948 2.666 0.651 1.184-0.651 0.296-2.784-0.889-3.554-1.125-0.77-6.634-0.948-6.16 0.178z"/>
- <path fill="#d69e00" d="m169.121 83.782c0.804 1.665 2.871 1.895 4.249 2.641 1.32 0.747 2.066 0.918 2.583 0.631 1.148-0.631 0.287-2.698-0.861-3.444-1.091-0.746-6.43-0.919-5.971 0.172z"/>
- <path fill="#d19800" d="m169.264 83.804c0.777 1.612 2.778 1.834 4.112 2.557 1.279 0.723 2.001 0.889 2.501 0.611 1.112-0.611 0.278-2.612-0.834-3.335-1.055-0.722-6.224-0.889-5.779 0.167z"/>
- <path fill="#cc9200" d="m169.406 83.826c0.753 1.559 2.688 1.774 3.979 2.473 1.236 0.699 1.936 0.86 2.42 0.591 1.074-0.591 0.269-2.527-0.808-3.226-1.021-0.699-6.021-0.86-5.591 0.162z"/>
- <path fill="#c68c00" d="m169.549 83.847c0.728 1.506 2.597 1.714 3.844 2.389 1.194 0.675 1.869 0.831 2.337 0.571 1.039-0.571 0.26-2.441-0.779-3.116-0.988-0.675-5.818-0.831-5.402 0.156z"/>
- <path fill="#c18700" d="m169.691 83.869c0.702 1.453 2.506 1.654 3.709 2.305 1.152 0.652 1.803 0.802 2.254 0.551 1.002-0.551 0.251-2.355-0.751-3.006-0.953-0.652-5.613-0.802-5.212 0.15z"/>
- <path fill="#bc8100" d="m169.833 83.89c0.677 1.4 2.415 1.594 3.574 2.221 1.111 0.628 1.738 0.772 2.173 0.531 0.965-0.531 0.241-2.27-0.725-2.897-0.917-0.627-5.408-0.772-5.022 0.145z"/>
- <path fill="#b77b00" d="m169.976 83.912c0.65 1.347 2.322 1.533 3.438 2.137 1.069 0.604 1.673 0.743 2.091 0.511 0.93-0.511 0.233-2.184-0.696-2.788-0.884-0.603-5.205-0.743-4.833 0.14z"/>
- <path fill="#b27500" d="m170.118 83.934c0.626 1.294 2.232 1.473 3.304 2.053 1.027 0.581 1.606 0.714 2.009 0.491 0.893-0.491 0.224-2.098-0.669-2.678-0.85-0.58-5.001-0.715-4.644 0.134z"/>
- <path fill="#ad7000" d="m170.261 83.955c0.6 1.242 2.14 1.413 3.168 1.97 0.984 0.557 1.541 0.685 1.927 0.47 0.855-0.47 0.214-2.012-0.644-2.569-0.812-0.555-4.794-0.684-4.451 0.129z"/>
- <path fill="#a86a00" d="m170.403 83.977c0.574 1.189 2.05 1.353 3.034 1.886 0.942 0.533 1.475 0.656 1.844 0.45 0.82-0.45 0.205-1.926-0.615-2.459-0.779-0.533-4.591-0.656-4.263 0.123z"/>
- <path fill="#a36400" d="m170.545 83.998c0.55 1.136 1.959 1.292 2.899 1.802 0.901 0.509 1.41 0.626 1.762 0.43 0.783-0.43 0.197-1.841-0.587-2.35-0.745-0.508-4.387-0.626-4.074 0.118z"/>
- <path fill="#9e5e00" d="m170.688 84.02c0.522 1.083 1.867 1.232 2.764 1.718 0.859 0.486 1.343 0.597 1.68 0.41 0.746-0.41 0.188-1.755-0.561-2.241-0.709-0.484-4.182-0.597-3.883 0.113z"/>
- <path fill="#995900" d="m170.83 84.042c0.498 1.03 1.776 1.172 2.629 1.634 0.817 0.462 1.278 0.568 1.599 0.39 0.71-0.39 0.178-1.669-0.533-2.131-0.676-0.461-3.979-0.568-3.695 0.107z"/>
- </g>
- <g transform="translate(-12.4048,10.0005)">
- <path fill="#fc0" d="m152.875 86.29c-0.325 0.813 1.952 2.359 3.091 1.301 1.222-1.057 2.686-2.033 3.175-2.359 2.195-1.465 1.383-2.522-2.278-1.871-3.663 0.651-3.663 2.115-3.988 2.929z"/>
- <path fill="#f9c600" d="m152.934 86.279c-0.318 0.794 1.906 2.304 3.019 1.271 1.193-1.033 2.623-1.986 3.102-2.305 2.145-1.431 1.351-2.463-2.226-1.828-3.578 0.637-3.578 2.067-3.895 2.862z"/>
- <path fill="#f4c000" d="m152.993 86.269c-0.31 0.775 1.861 2.25 2.948 1.241 1.164-1.008 2.56-1.939 3.026-2.25 2.095-1.397 1.319-2.405-2.173-1.784-3.491 0.62-3.491 2.017-3.801 2.793z"/>
- <path fill="#efba00" d="m153.051 86.258c-0.302 0.757 1.817 2.195 2.878 1.211 1.136-0.984 2.497-1.892 2.952-2.195 2.044-1.363 1.287-2.347-2.118-1.741-3.409 0.606-3.409 1.968-3.712 2.725z"/>
- <path fill="#eab500" d="m153.11 86.248c-0.295 0.738 1.771 2.141 2.805 1.181 1.108-0.959 2.437-1.845 2.88-2.141 1.993-1.329 1.255-2.289-2.066-1.698-3.324 0.591-3.324 1.92-3.619 2.658z"/>
- <path fill="#e5af00" d="m153.169 86.238c-0.287 0.719 1.727 2.086 2.733 1.151 1.08-0.935 2.374-1.798 2.807-2.086 1.942-1.296 1.224-2.23-2.015-1.655s-3.238 1.87-3.525 2.59z"/>
- <path fill="#e0a900" d="m153.228 86.228c-0.28 0.7 1.681 2.032 2.661 1.121 1.052-0.91 2.312-1.751 2.732-2.031 1.893-1.262 1.191-2.172-1.961-1.611-3.152 0.559-3.152 1.82-3.432 2.521z"/>
- <path fill="#dba300" d="m153.286 86.217c-0.271 0.681 1.636 1.977 2.591 1.09 1.023-0.886 2.25-1.704 2.659-1.977 1.84-1.228 1.159-2.114-1.909-1.568-3.068 0.547-3.068 1.773-3.341 2.455z"/>
- <path fill="#d69e00" d="m153.345 86.207c-0.265 0.662 1.591 1.922 2.519 1.061 0.995-0.862 2.188-1.657 2.586-1.922 1.789-1.194 1.127-2.055-1.855-1.525-2.985 0.53-2.985 1.723-3.25 2.386z"/>
- <path fill="#d19800" d="m153.404 86.197c-0.257 0.643 1.546 1.868 2.447 1.03 0.967-0.837 2.126-1.61 2.512-1.868 1.739-1.16 1.095-1.997-1.803-1.481-2.899 0.516-2.899 1.674-3.156 2.319z"/>
- <path fill="#cc9200" d="m153.463 86.187c-0.25 0.625 1.5 1.813 2.375 1 0.939-0.813 2.064-1.563 2.439-1.813 1.688-1.126 1.063-1.938-1.75-1.438-2.814 0.5-2.814 1.625-3.064 2.251z"/>
- <path fill="#c68c00" d="m153.521 86.176c-0.242 0.605 1.456 1.758 2.304 0.97 0.911-0.788 2.002-1.516 2.366-1.758 1.637-1.092 1.031-1.88-1.698-1.395-2.729 0.486-2.729 1.576-2.972 2.183z"/>
- <path fill="#c18700" d="m153.58 86.166c-0.233 0.587 1.41 1.704 2.233 0.939 0.882-0.763 1.938-1.469 2.292-1.704 1.586-1.058 0.999-1.822-1.646-1.352-2.644 0.472-2.644 1.529-2.879 2.117z"/>
- <path fill="#bc8100" d="m153.639 86.156c-0.228 0.568 1.364 1.649 2.16 0.91 0.854-0.739 1.878-1.422 2.219-1.649 1.536-1.024 0.967-1.764-1.593-1.308s-2.559 1.477-2.786 2.047z"/>
- <path fill="#b77b00" d="m153.698 86.146c-0.22 0.549 1.32 1.594 2.089 0.879 0.825-0.715 1.815-1.375 2.146-1.595 1.484-0.99 0.935-1.705-1.54-1.265s-2.475 1.43-2.695 1.981z"/>
- <path fill="#b27500" d="m153.756 86.135c-0.211 0.53 1.275 1.54 2.019 0.85 0.797-0.69 1.753-1.328 2.072-1.54 1.434-0.957 0.902-1.646-1.487-1.221s-2.391 1.38-2.604 1.911z"/>
- <path fill="#ad7000" d="m153.815 86.125c-0.204 0.512 1.229 1.486 1.946 0.82 0.769-0.666 1.69-1.281 1.997-1.486 1.385-0.922 0.871-1.588-1.434-1.178s-2.304 1.331-2.509 1.844z"/>
- <path fill="#a86a00" d="m153.874 86.114c-0.196 0.493 1.185 1.431 1.875 0.79 0.74-0.642 1.628-1.234 1.924-1.431 1.332-0.889 0.84-1.53-1.381-1.135s-2.221 1.283-2.418 1.776z"/>
- <path fill="#a36400" d="m153.933 86.104c-0.189 0.474 1.139 1.376 1.803 0.759 0.712-0.617 1.566-1.187 1.851-1.376 1.281-0.855 0.808-1.472-1.329-1.092-2.135 0.38-2.135 1.234-2.325 1.709z"/>
- <path fill="#9e5e00" d="m153.991 86.094c-0.181 0.455 1.095 1.322 1.732 0.729 0.684-0.592 1.504-1.14 1.776-1.321 1.231-0.821 0.775-1.414-1.274-1.048-2.051 0.364-2.051 1.184-2.234 1.64z"/>
- <path fill="#995900" d="m154.05 86.083c-0.174 0.436 1.05 1.267 1.66 0.699 0.656-0.568 1.442-1.093 1.704-1.267 1.181-0.787 0.743-1.355-1.223-1.005s-1.966 1.136-2.141 1.573z"/>
- </g>
- <g transform="translate(-12.4048,10.0005)">
- <path fill="#fc0" d="m156.951 107.887c-0.229 2.858 6.343-4.286 6.743-4.915 0.856-1.543 3.715-5.886 4.172-7.715 0.857-3.2 2.401-5.543 1.429-8.915-0.343-1.086-2.742-1.372-3.829-0.687-3.086 1.829-2.629 4.058-2.972 6.115-1.143 5.831-5.143 11.717-5.543 16.117z"/>
- <path fill="#ffcc02" d="m157.22 107.441c-0.22 2.787 6.178-4.188 6.566-4.802 0.833-1.506 3.614-5.745 4.056-7.529 0.831-3.122 2.333-5.408 1.382-8.695-0.337-1.058-2.678-1.333-3.735-0.663-3.006 1.788-2.557 3.96-2.889 5.967-1.105 5.685-4.997 11.431-5.38 15.722z"/>
- <path fill="#ffcc05" d="m157.488 106.995c-0.209 2.715 6.014-4.091 6.392-4.69 0.811-1.469 3.513-5.603 3.941-7.342 0.804-3.043 2.264-5.273 1.331-8.474-0.329-1.031-2.61-1.295-3.64-0.64-2.927 1.747-2.486 3.863-2.806 5.818-1.068 5.541-4.851 11.146-5.218 15.328z"/>
- <path fill="#ffcc07" d="m157.757 106.548c-0.198 2.645 5.85-3.993 6.217-4.577 0.785-1.431 3.409-5.461 3.824-7.156 0.779-2.964 2.196-5.138 1.282-8.253-0.322-1.003-2.543-1.257-3.545-0.618-2.847 1.706-2.414 3.766-2.722 5.67-1.031 5.398-4.706 10.862-5.056 14.934z"/>
- <path fill="#ffcd0a" d="m158.026 106.102c-0.189 2.573 5.684-3.896 6.04-4.465 0.762-1.394 3.309-5.32 3.709-6.969 0.753-2.886 2.129-5.004 1.233-8.033-0.315-0.976-2.478-1.219-3.45-0.595-2.768 1.665-2.343 3.668-2.64 5.522-0.993 5.254-4.558 10.577-4.892 14.54z"/>
- <path fill="#ffcd0c" d="m158.294 105.655c-0.179 2.503 5.52-3.798 5.865-4.351 0.738-1.357 3.207-5.179 3.594-6.783 0.727-2.807 2.061-4.869 1.185-7.813-0.309-0.948-2.411-1.18-3.356-0.572-2.687 1.623-2.271 3.571-2.556 5.374-0.958 5.11-4.414 10.291-4.732 14.145z"/>
- <path fill="#ffcd0f" d="m158.563 105.209c-0.169 2.431 5.354-3.701 5.688-4.239 0.715-1.319 3.106-5.037 3.479-6.596 0.7-2.728 1.992-4.734 1.135-7.592-0.301-0.92-2.344-1.142-3.261-0.549-2.608 1.583-2.199 3.474-2.473 5.226-0.919 4.965-4.267 10.005-4.568 13.75z"/>
- <path fill="#ffcd11" d="m158.831 104.762c-0.159 2.361 5.19-3.602 5.515-4.126 0.69-1.282 3.004-4.896 3.361-6.409 0.674-2.649 1.924-4.599 1.087-7.372-0.295-0.893-2.277-1.104-3.167-0.526-2.527 1.541-2.128 3.376-2.389 5.077-0.883 4.822-4.122 9.721-4.407 13.356z"/>
- <path fill="#ffce14" d="m159.1 104.316c-0.149 2.289 5.024-3.505 5.338-4.014 0.667-1.244 2.901-4.754 3.247-6.223 0.646-2.571 1.854-4.464 1.037-7.151-0.287-0.865-2.211-1.065-3.072-0.504-2.448 1.5-2.056 3.279-2.306 4.929-0.845 4.679-3.976 9.437-4.244 12.963z"/>
- <path fill="#ffce16" d="m159.369 103.869c-0.139 2.219 4.86-3.407 5.162-3.9 0.643-1.208 2.801-4.613 3.131-6.037 0.622-2.492 1.787-4.329 0.988-6.93-0.28-0.838-2.146-1.027-2.978-0.481-2.368 1.459-1.983 3.182-2.223 4.781-0.807 4.533-3.829 9.151-4.08 12.567z"/>
- <path fill="#ffce19" d="m159.637 103.423c-0.13 2.147 4.695-3.31 4.986-3.788 0.62-1.17 2.699-4.471 3.016-5.85 0.596-2.414 1.719-4.195 0.939-6.71-0.273-0.81-2.079-0.989-2.883-0.458-2.289 1.418-1.913 3.084-2.139 4.632-0.77 4.391-3.684 8.866-3.919 12.174z"/>
- <path fill="#ffce1c" d="m159.906 102.977c-0.119 2.076 4.531-3.213 4.811-3.676 0.597-1.133 2.599-4.33 2.899-5.664 0.57-2.335 1.651-4.06 0.891-6.49-0.267-0.782-2.012-0.95-2.787-0.435-2.21 1.377-1.842 2.987-2.057 4.484-0.734 4.247-3.539 8.582-3.757 11.781z"/>
- <path fill="#ffcf1e" d="m160.174 102.53c-0.108 2.005 4.366-3.115 4.637-3.563 0.571-1.096 2.496-4.189 2.784-5.478 0.543-2.256 1.581-3.925 0.841-6.269-0.26-0.754-1.945-0.912-2.693-0.412-2.129 1.336-1.77 2.889-1.973 4.336-0.697 4.103-3.394 8.297-3.596 11.386z"/>
- <path fill="#ffcf21" d="m160.443 102.084c-0.099 1.934 4.201-3.018 4.46-3.45 0.548-1.059 2.394-4.047 2.668-5.291 0.517-2.178 1.514-3.79 0.793-6.049-0.253-0.727-1.879-0.874-2.599-0.39-2.051 1.295-1.698 2.792-1.891 4.188-0.658 3.959-3.246 8.012-3.431 10.992z"/>
- <path fill="#ffcf23" d="m160.712 101.637c-0.089 1.863 4.036-2.919 4.283-3.337 0.526-1.021 2.294-3.905 2.553-5.104 0.491-2.099 1.447-3.655 0.744-5.828-0.246-0.699-1.813-0.835-2.505-0.367-1.969 1.253-1.625 2.694-1.805 4.04-0.623 3.814-3.101 7.726-3.27 10.596z"/>
- <path fill="#ffcf26" d="m160.98 101.191c-0.079 1.792 3.872-2.822 4.107-3.225 0.502-0.984 2.192-3.764 2.438-4.918 0.464-2.02 1.378-3.52 0.694-5.607-0.238-0.672-1.746-0.797-2.41-0.344-1.89 1.212-1.555 2.597-1.723 3.891-0.583 3.671-2.953 7.442-3.106 10.203z"/>
- <path fill="#ffd028" d="m161.249 100.744c-0.068 1.721 3.707-2.724 3.933-3.112 0.478-0.947 2.091-3.623 2.321-4.731 0.439-1.942 1.311-3.386 0.646-5.387-0.232-0.645-1.68-0.758-2.316-0.321-1.81 1.171-1.481 2.5-1.639 3.743-0.548 3.527-2.809 7.156-2.945 9.808z"/>
- <path fill="#ffd02b" d="m161.517 100.298c-0.06 1.65 3.543-2.627 3.757-2.999 0.454-0.91 1.989-3.481 2.206-4.545 0.413-1.863 1.242-3.25 0.597-5.167-0.225-0.617-1.613-0.72-2.221-0.298-1.73 1.13-1.411 2.402-1.557 3.595-0.509 3.383-2.662 6.871-2.782 9.414z"/>
- <path fill="#ffd02d" d="m161.786 99.852c-0.049 1.579 3.377-2.529 3.581-2.887 0.431-0.872 1.887-3.34 2.091-4.359 0.387-1.784 1.173-3.116 0.547-4.946-0.217-0.589-1.546-0.682-2.126-0.275-1.649 1.089-1.339 2.305-1.472 3.446-0.474 3.24-2.518 6.587-2.621 9.021z"/>
- <path fill="#ffd030" d="m162.055 99.405c-0.039 1.508 3.212-2.432 3.404-2.773 0.407-0.835 1.786-3.199 1.976-4.172 0.359-1.706 1.104-2.981 0.499-4.726-0.211-0.562-1.481-0.644-2.032-0.253-1.571 1.048-1.268 2.208-1.389 3.298-0.436 3.096-2.372 6.302-2.458 8.626z"/>
- <path fill="#ffd133" d="m162.323 98.958c-0.029 1.437 3.048-2.334 3.23-2.661 0.383-0.798 1.684-3.057 1.858-3.986 0.334-1.627 1.037-2.846 0.45-4.505-0.204-0.534-1.414-0.605-1.938-0.23-1.49 1.007-1.195 2.11-1.306 3.15-0.397 2.953-2.224 6.018-2.294 8.232z"/>
- </g>
- <g transform="translate(-12.4048,10.0005)">
- <path fill="#fc0" d="m179.646 95.994c-3.168 3.456-5.4 6.767-7.2 9-1.872 2.304-6.48 5.04-4.176 7.704 1.943 2.376 9.936-1.944 16.128-6.552 6.12-4.608 15.696-8.711 11.016-13.967-2.448-2.664-8.208-2.088-10.439-0.648-1.729 1.078-2.737 1.655-5.329 4.463z"/>
- <path fill="#ffcc02" d="m179.782 96.147c-3.118 3.378-5.313 6.628-7.086 8.809-1.841 2.249-6.375 4.945-4.13 7.534 1.893 2.31 9.724-1.943 15.795-6.469 6.001-4.525 15.38-8.574 10.82-13.682-2.387-2.588-8.022-1.998-10.209-0.584-1.692 1.062-2.665 1.67-5.19 4.392z"/>
- <path fill="#ffcc05" d="m179.919 96.3c-3.068 3.3-5.227 6.488-6.973 8.619-1.81 2.193-6.271 4.85-4.085 7.364 1.843 2.243 9.513-1.943 15.463-6.386 5.882-4.442 15.064-8.437 10.623-13.396-2.323-2.513-7.835-1.907-9.978-0.52-1.655 1.044-2.593 1.684-5.05 4.319z"/>
- <path fill="#ffcc07" d="m180.055 96.454c-3.02 3.222-5.14 6.347-6.859 8.428-1.78 2.138-6.166 4.754-4.04 7.194 1.793 2.177 9.302-1.942 15.131-6.303 5.762-4.359 14.748-8.299 10.427-13.11-2.261-2.437-7.648-1.817-9.747-0.456-1.619 1.025-2.522 1.698-4.912 4.247z"/>
- <path fill="#ffcd0a" d="m180.191 96.607c-2.97 3.143-5.052 6.207-6.745 8.237-1.749 2.082-6.063 4.659-3.994 7.023 1.743 2.111 9.09-1.941 14.798-6.219 5.644-4.276 14.433-8.162 10.231-12.824-2.199-2.361-7.463-1.727-9.518-0.392-1.581 1.008-2.45 1.713-4.772 4.175z"/>
- <path fill="#ffcd0c" d="m180.327 96.761c-2.92 3.065-4.965 6.066-6.631 8.047-1.718 2.027-5.957 4.564-3.949 6.853 1.693 2.044 8.878-1.94 14.466-6.136 5.524-4.194 14.116-8.024 10.034-12.538-2.137-2.286-7.275-1.636-9.285-0.328-1.546 0.988-2.38 1.726-4.635 4.102z"/>
- <path fill="#ffcd0f" d="m180.464 96.914c-2.871 2.987-4.879 5.926-6.518 7.857-1.688 1.971-5.854 4.468-3.903 6.683 1.643 1.978 8.666-1.94 14.133-6.053 5.404-4.111 13.801-7.887 9.839-12.251-2.075-2.21-7.091-1.546-9.056-0.264-1.509 0.969-2.308 1.738-4.495 4.028z"/>
- <path fill="#ffcd11" d="m180.6 97.067c-2.821 2.909-4.792 5.786-6.404 7.667-1.657 1.916-5.748 4.373-3.858 6.512 1.593 1.912 8.455-1.938 13.802-5.969 5.284-4.028 13.484-7.75 9.641-11.966-2.012-2.134-6.902-1.456-8.823-0.199-1.474 0.951-2.238 1.752-4.358 3.955z"/>
- <path fill="#ffce14" d="m180.736 97.221c-2.771 2.83-4.705 5.645-6.29 7.476-1.626 1.86-5.644 4.278-3.813 6.342 1.542 1.845 8.244-1.938 13.47-5.886 5.166-3.945 13.169-7.612 9.444-11.68-1.949-2.059-6.716-1.365-8.592-0.135-1.437 0.933-2.166 1.766-4.219 3.883z"/>
- <path fill="#ffce16" d="m180.872 97.375c-2.722 2.752-4.617 5.504-6.176 7.286-1.595 1.805-5.539 4.182-3.767 6.172 1.49 1.779 8.031-1.937 13.136-5.803 5.046-3.862 12.853-7.475 9.249-11.394-1.889-1.983-6.53-1.274-8.362-0.071-1.4 0.914-2.095 1.779-4.08 3.81z"/>
- <path fill="#ffce19" d="m181.009 97.528c-2.673 2.674-4.53 5.364-6.063 7.095-1.564 1.749-5.435 4.087-3.722 6.001 1.44 1.713 7.82-1.936 12.804-5.719 4.927-3.78 12.537-7.338 9.052-11.108-1.825-1.907-6.343-1.185-8.13-0.007-1.364 0.896-2.024 1.793-3.941 3.738z"/>
- <path fill="#ffce1c" d="m181.145 97.682c-2.623 2.595-4.444 5.225-5.949 6.904-1.534 1.693-5.33 3.992-3.676 5.831 1.39 1.646 7.608-1.935 12.471-5.636 4.808-3.697 12.221-7.2 8.856-10.822-1.764-1.832-6.157-1.094-7.9 0.057-1.327 0.878-1.952 1.807-3.802 3.666z"/>
- <path fill="#ffcf1e" d="m181.281 97.835c-2.573 2.517-4.357 5.084-5.835 6.714-1.503 1.638-5.226 3.896-3.631 5.661 1.34 1.58 7.396-1.935 12.139-5.553 4.689-3.614 11.905-7.063 8.659-10.536-1.701-1.756-5.97-1.004-7.668 0.121-1.291 0.86-1.881 1.821-3.664 3.593z"/>
- <path fill="#ffcf21" d="m181.417 97.988c-2.522 2.439-4.27 4.944-5.721 6.524-1.472 1.582-5.121 3.801-3.586 5.491 1.29 1.513 7.186-1.934 11.807-5.47 4.569-3.531 11.589-6.926 8.463-10.25-1.639-1.68-5.783-0.914-7.438 0.186-1.254 0.84-1.809 1.834-3.525 3.519z"/>
- <path fill="#ffcf23" d="m181.554 98.142c-2.476 2.361-4.185 4.803-5.608 6.333-1.441 1.527-5.017 3.706-3.54 5.32 1.24 1.447 6.974-1.933 11.474-5.386 4.45-3.448 11.273-6.788 8.268-9.964-1.577-1.605-5.599-0.823-7.207 0.25-1.22 0.822-1.74 1.848-3.387 3.447z"/>
- <path fill="#ffcf26" d="m181.69 98.295c-2.425 2.283-4.098 4.663-5.494 6.143-1.411 1.471-4.912 3.61-3.495 5.15 1.19 1.381 6.763-1.932 11.142-5.303 4.331-3.366 10.957-6.65 8.07-9.679-1.514-1.529-5.411-0.732-6.976 0.313-1.182 0.805-1.667 1.863-3.247 3.376z"/>
- <path fill="#ffd028" d="m181.826 98.449c-2.375 2.204-4.009 4.522-5.38 5.952-1.38 1.416-4.808 3.515-3.449 4.98 1.14 1.314 6.551-1.932 10.81-5.22 4.211-3.283 10.641-6.513 7.874-9.393-1.452-1.454-5.226-0.642-6.745 0.378-1.147 0.786-1.597 1.876-3.11 3.303z"/>
- <path fill="#ffd02b" d="m181.962 98.602c-2.324 2.127-3.922 4.382-5.266 5.762-1.349 1.36-4.703 3.42-3.404 4.809 1.089 1.248 6.34-1.93 10.478-5.136 4.092-3.2 10.325-6.376 7.677-9.106-1.389-1.378-5.038-0.552-6.513 0.441-1.111 0.768-1.526 1.89-2.972 3.23z"/>
- <path fill="#ffd02d" d="m182.099 98.756c-2.276 2.048-3.836 4.241-5.153 5.571-1.318 1.305-4.599 3.324-3.359 4.639 1.039 1.182 6.128-1.93 10.146-5.053 3.973-3.117 10.009-6.238 7.48-8.82-1.328-1.303-4.852-0.462-6.282 0.506-1.074 0.748-1.454 1.903-2.832 3.157z"/>
- <path fill="#ffd030" d="m182.235 98.909c-2.228 1.97-3.749 4.101-5.039 5.381-1.288 1.249-4.494 3.229-3.313 4.469 0.988 1.115 5.916-1.929 9.813-4.97 3.853-3.034 9.693-6.101 7.285-8.535-1.267-1.227-4.666-0.371-6.052 0.57-1.038 0.731-1.384 1.918-2.694 3.085z"/>
- <path fill="#ffd133" d="m182.371 99.063c-2.177 1.892-3.662 3.96-4.925 5.19-1.257 1.193-4.39 3.133-3.268 4.298 0.938 1.049 5.704-1.928 9.479-4.886 3.734-2.952 9.377-5.963 7.088-8.249-1.203-1.151-4.479-0.281-5.821 0.634-0.999 0.713-1.31 1.931-2.553 3.013z"/>
- </g>
- <g transform="translate(-12.4048,10.0005)">
- <path fill="#fff" d="m186.414 168.569c0.864-2.808 28.872-9.432 33.48-7.272 4.536 2.16 26.279 33.768 22.392 35.496-3.888 1.657-12.24-10.512-24.408-16.128s-32.328-9.216-31.464-12.096z"/>
- <path fill="#f9f9f9" d="m187.239 168.626c0.848-2.761 28.145-9.076 32.69-6.997 4.476 2.079 25.768 32.897 21.943 34.591-3.824 1.625-11.965-10.346-23.94-15.874-11.976-5.527-31.541-8.89-30.693-11.72z"/>
- <path fill="#f4f4f4" d="m188.063 168.683c0.832-2.714 27.418-8.72 31.899-6.722 4.417 1.998 25.259 32.026 21.497 33.685-3.76 1.595-11.689-10.18-23.474-15.619-11.782-5.438-30.754-8.565-29.922-11.344z"/>
- <path fill="#efefef" d="m188.888 168.74c0.814-2.668 26.69-8.364 31.109-6.447 4.357 1.917 24.746 31.155 21.049 32.779-3.695 1.563-11.416-10.014-23.007-15.364-11.59-5.349-29.967-8.239-29.151-10.968z"/>
- <path fill="#eaeaea" d="m189.712 168.797c0.801-2.621 25.964-8.009 30.32-6.173 4.299 1.837 24.235 30.285 20.603 31.874-3.633 1.532-11.142-9.847-22.54-15.109-11.4-5.261-29.182-7.914-28.383-10.592z"/>
- <path fill="#e5e5e5" d="m190.537 168.853c0.783-2.573 25.236-7.652 29.53-5.897 4.239 1.756 23.723 29.414 20.155 30.968-3.569 1.501-10.867-9.681-22.074-14.854-11.206-5.172-28.395-7.589-27.611-10.217z"/>
- <path fill="#e0e0e0" d="m191.361 168.91c0.768-2.527 24.51-7.296 28.74-5.622 4.18 1.675 23.212 28.543 19.708 30.063-3.505 1.469-10.593-9.516-21.607-14.6-11.014-5.083-27.608-7.263-26.841-9.841z"/>
- <path fill="#dbdbdb" d="m192.186 168.967c0.751-2.48 23.781-6.941 27.95-5.347 4.119 1.593 22.7 27.671 19.26 29.157-3.441 1.438-10.318-9.349-21.141-14.345-10.821-4.994-26.821-6.938-26.069-9.465z"/>
- <path fill="#d6d6d6" d="m193.01 169.024c0.735-2.433 23.057-6.585 27.16-5.073 4.062 1.513 22.19 26.801 18.813 28.252-3.377 1.407-10.043-9.183-20.673-14.09-10.629-4.906-26.035-6.612-25.3-9.089z"/>
- <path fill="#d1d1d1" d="m193.835 169.081c0.72-2.387 22.328-6.229 26.37-4.798 4.001 1.432 21.678 25.93 18.365 27.346-3.313 1.376-9.768-9.017-20.206-13.835-10.437-4.817-25.248-6.287-24.529-8.713z"/>
- <path fill="#ccc" d="m194.659 169.137c0.703-2.339 21.603-5.873 25.58-4.521 3.942 1.351 21.167 25.059 17.918 26.44-3.249 1.345-9.493-8.851-19.739-13.58-10.245-4.729-24.462-5.963-23.759-8.339z"/>
- <path fill="#c6c6c6" d="m195.484 169.194c0.687-2.292 20.874-5.517 24.79-4.247 3.882 1.27 20.655 24.188 17.47 25.535-3.185 1.314-9.219-8.685-19.271-13.326-10.054-4.639-23.676-5.636-22.989-7.962z"/>
- <path fill="#c1c1c1" d="m196.308 169.251c0.671-2.246 20.147-5.161 24-3.973 3.822 1.19 20.145 23.318 17.022 24.63-3.121 1.283-8.943-8.519-18.805-13.071-9.859-4.551-22.888-5.311-22.217-7.586z"/>
- <path fill="#bcbcbc" d="m197.133 169.308c0.654-2.199 19.421-4.805 23.21-3.698 3.764 1.109 19.634 22.447 16.575 23.724-3.057 1.252-8.669-8.353-18.338-12.816-9.668-4.462-22.102-4.985-21.447-7.21z"/>
- <path fill="#b7b7b7" d="m197.957 169.365c0.64-2.152 18.693-4.45 22.42-3.423 3.705 1.027 19.122 21.575 16.129 22.818-2.993 1.221-8.395-8.186-17.872-12.561-9.476-4.373-21.315-4.66-20.677-6.834z"/>
- <path fill="#b2b2b2" d="m198.782 169.421c0.622-2.105 17.966-4.093 21.63-3.147 3.646 0.946 18.61 20.704 15.681 21.912-2.93 1.19-8.12-8.02-17.404-12.306-9.284-4.284-20.53-4.335-19.907-6.459z"/>
- <path fill="#adadad" d="m199.606 169.478c0.606-2.058 17.239-3.737 20.84-2.873 3.586 0.866 18.099 19.834 15.234 21.008-2.866 1.158-7.847-7.855-16.938-12.052-9.091-4.196-19.742-4.009-19.136-6.083z"/>
- <path fill="#a8a8a8" d="m200.431 169.535c0.59-2.011 16.512-3.382 20.05-2.598 3.525 0.785 17.588 18.963 14.786 20.102-2.803 1.127-7.571-7.688-16.472-11.797-8.898-4.107-18.955-3.684-18.364-5.707z"/>
- <path fill="#a3a3a3" d="m201.255 169.592c0.574-1.965 15.785-3.026 19.261-2.323 3.467 0.704 17.076 18.092 14.339 19.196-2.738 1.096-7.296-7.522-16.004-11.542-8.707-4.018-18.17-3.358-17.596-5.331z"/>
- <path fill="#9e9e9e" d="m202.08 169.649c0.559-1.918 15.059-2.67 18.47-2.048 3.407 0.623 16.565 17.221 13.892 18.29-2.674 1.065-7.022-7.356-15.537-11.287-8.515-3.929-17.383-3.033-16.825-4.955z"/>
- <path fill="#999" d="m202.904 169.705c0.542-1.871 14.331-2.314 17.68-1.773 3.349 0.542 16.055 16.35 13.444 17.385-2.61 1.034-6.747-7.19-15.07-11.032-8.322-3.841-16.596-2.708-16.054-4.58z"/>
- </g>
- <g transform="translate(-12.4048,10.0005)">
- <path fill="#fff" d="m151.134 211.625c2.881 0.144 0.145 16.271 0.145 32.903s2.231 22.464 0.144 24.552-5.688-5.399-5.688-22.031c-0.001-16.632 2.519-35.568 5.399-35.424z"/>
- <path fill="#f9f9f9" d="m151.105 212.016c2.783 0.162 0.109 16.052 0.097 32.419-0.012 16.366 2.188 22.208 0.164 24.237-2.02 2.029-5.561-5.383-5.546-21.752 0.012-16.367 2.502-35.065 5.285-34.904z"/>
- <path fill="#f4f4f4" d="m151.075 212.407c2.687 0.18 0.076 15.832 0.051 31.934-0.023 16.102 2.143 21.951 0.185 23.924-1.953 1.968-5.435-5.367-5.405-21.473 0.024-16.103 2.484-34.564 5.169-34.385z"/>
- <path fill="#efefef" d="m151.046 212.797c2.588 0.197 0.041 15.613 0.004 31.449-0.036 15.836 2.098 21.694 0.204 23.609-1.886 1.907-5.308-5.352-5.263-21.195 0.037-15.835 2.467-34.058 5.055-33.863z"/>
- <path fill="#eaeaea" d="m151.017 213.189c2.49 0.214 0.007 15.392-0.043 30.962-0.05 15.571 2.052 21.439 0.224 23.297-1.818 1.848-5.181-5.334-5.122-20.916 0.049-15.571 2.45-33.557 4.941-33.343z"/>
- <path fill="#e5e5e5" d="m150.987 213.581c2.394 0.23-0.027 15.17-0.089 30.477s2.007 21.182 0.244 22.982c-1.751 1.787-5.055-5.32-4.98-20.638 0.061-15.305 2.431-33.053 4.825-32.821z"/>
- <path fill="#e0e0e0" d="m150.958 213.971c2.297 0.248-0.062 14.951-0.136 29.99-0.074 15.041 1.962 20.927 0.264 22.668-1.683 1.728-4.928-5.301-4.839-20.356 0.074-15.04 2.414-32.551 4.711-32.302z"/>
- <path fill="#dbdbdb" d="m150.928 214.362c2.199 0.266-0.096 14.73-0.182 29.506-0.087 14.775 1.915 20.67 0.282 22.354-1.615 1.667-4.8-5.286-4.696-20.078 0.087-14.776 2.397-32.048 4.596-31.782z"/>
- <path fill="#d6d6d6" d="m150.899 214.752c2.102 0.283-0.13 14.511-0.229 29.021-0.099 14.511 1.87 20.413 0.303 22.04-1.549 1.607-4.674-5.27-4.556-19.799 0.1-14.51 2.38-31.545 4.482-31.262z"/>
- <path fill="#d1d1d1" d="m150.87 215.144c2.005 0.301-0.165 14.29-0.274 28.535-0.112 14.245 1.824 20.155 0.321 21.725-1.479 1.548-4.547-5.252-4.413-19.519 0.11-14.245 2.361-31.043 4.366-30.741z"/>
- <path fill="#ccc" d="m150.84 215.536c1.908 0.317-0.197 14.069-0.32 28.049-0.124 13.979 1.779 19.899 0.342 21.412-1.413 1.486-4.42-5.238-4.272-19.242 0.122-13.979 2.343-30.54 4.25-30.219z"/>
- <path fill="#c6c6c6" d="m150.811 215.926c1.811 0.334-0.233 13.85-0.368 27.564-0.136 13.713 1.735 19.643 0.362 21.096-1.346 1.428-4.293-5.219-4.131-18.961 0.136-13.712 2.327-30.035 4.137-29.699z"/>
- <path fill="#c1c1c1" d="m150.781 216.317c1.714 0.354-0.267 13.629-0.414 27.078s1.69 19.387 0.382 20.783c-1.277 1.367-4.166-5.203-3.989-18.682 0.148-13.449 2.308-29.533 4.021-29.179z"/>
- <path fill="#bcbcbc" d="m150.752 216.708c1.616 0.371-0.301 13.41-0.461 26.594-0.161 13.184 1.646 19.13 0.402 20.469-1.211 1.307-4.04-5.188-3.847-18.402 0.16-13.185 2.29-29.033 3.906-28.661z"/>
- <path fill="#b7b7b7" d="m150.723 217.099c1.519 0.387-0.336 13.188-0.509 26.106-0.173 12.92 1.601 18.875 0.423 20.156-1.144 1.246-3.913-5.171-3.706-18.123 0.172-12.919 2.273-28.529 3.792-28.139z"/>
- <path fill="#b2b2b2" d="m150.693 217.491c1.422 0.404-0.37 12.969-0.554 25.621-0.186 12.653 1.555 18.617 0.441 19.842-1.076 1.187-3.786-5.156-3.563-17.846 0.184-12.652 2.255-28.024 3.676-27.617z"/>
- <path fill="#adadad" d="m150.664 217.881c1.325 0.422-0.404 12.748-0.601 25.136-0.198 12.388 1.51 18.36 0.462 19.528-1.008 1.125-3.66-5.139-3.423-17.566 0.197-12.389 2.238-27.521 3.562-27.098z"/>
- <path fill="#a8a8a8" d="m150.634 218.272c1.229 0.439-0.438 12.527-0.646 24.65-0.21 12.123 1.464 18.104 0.48 19.213-0.939 1.066-3.531-5.121-3.279-17.285 0.208-12.123 2.219-27.019 3.445-26.578z"/>
- <path fill="#a3a3a3" d="m150.605 218.663c1.13 0.457-0.474 12.309-0.694 24.166-0.222 11.857 1.419 17.848 0.501 18.899-0.873 1.006-3.405-5.106-3.139-17.009 0.222-11.855 2.202-26.515 3.332-26.056z"/>
- <path fill="#9e9e9e" d="m150.576 219.054c1.033 0.474-0.507 12.088-0.741 23.68-0.234 11.593 1.374 17.591 0.521 18.585-0.806 0.946-3.279-5.089-2.997-16.729 0.233-11.591 2.184-26.011 3.217-25.536z"/>
- <path fill="#999" d="m150.546 219.444c0.937 0.492-0.541 11.868-0.787 23.195-0.246 11.326 1.329 17.335 0.541 18.271-0.737 0.885-3.151-5.074-2.855-16.449 0.245-11.328 2.166-25.509 3.101-25.017z"/>
- </g>
- <g transform="translate(-12.4048,10.0005)">
- <path fill="#fff" d="m157.434 167.161c1.735 0.192 12.437-2.218 12.822-1.254 0.386 0.772-6.651 2.893-8.966 5.303-0.771 0.771-2.796 2.603-4.049 2.41-0.964-0.096-1.543-2.121-2.989-3.664-3.471-3.47-5.688-3.181-5.013-4.531 0.579-1.06 5.207 1.446 8.195 1.736z"/>
- <path fill="#fbfbfb" d="m157.479 167.201c1.7 0.188 12.176-2.171 12.554-1.227 0.377 0.755-6.512 2.832-8.778 5.191-0.755 0.755-2.736 2.549-3.964 2.36-0.942-0.094-1.51-2.077-2.926-3.587-3.398-3.397-5.568-3.115-4.907-4.436 0.565-1.038 5.096 1.415 8.021 1.699z"/>
- <path fill="#f8f8f8" d="m157.525 167.241c1.663 0.184 11.914-2.124 12.283-1.201 0.369 0.739-6.372 2.771-8.589 5.08-0.738 0.739-2.679 2.494-3.879 2.309-0.924-0.092-1.479-2.032-2.863-3.51-3.325-3.324-5.449-3.048-4.803-4.341 0.555-1.015 4.988 1.385 7.851 1.663z"/>
- <path fill="#f5f5f5" d="m157.57 167.281c1.626 0.18 11.652-2.078 12.014-1.175 0.361 0.723-6.231 2.711-8.4 4.969-0.723 0.722-2.619 2.439-3.793 2.258-0.903-0.09-1.446-1.987-2.802-3.433-3.252-3.251-5.329-2.981-4.695-4.245 0.54-0.993 4.876 1.354 7.676 1.626z"/>
- <path fill="#f2f2f2" d="m157.615 167.321c1.59 0.176 11.391-2.031 11.745-1.148 0.352 0.706-6.093 2.649-8.212 4.856-0.707 0.707-2.562 2.385-3.709 2.208-0.883-0.088-1.413-1.943-2.738-3.356-3.179-3.178-5.209-2.914-4.591-4.15 0.529-0.971 4.768 1.324 7.505 1.59z"/>
- <path fill="#efefef" d="m157.66 167.361c1.554 0.172 11.13-1.985 11.475-1.122 0.346 0.69-5.952 2.589-8.022 4.745-0.69 0.69-2.503 2.33-3.624 2.157-0.863-0.086-1.381-1.898-2.675-3.279-3.106-3.105-5.09-2.847-4.486-4.055 0.517-0.948 4.658 1.294 7.332 1.554z"/>
- <path fill="#ebebeb" d="m157.705 167.401c1.518 0.168 10.868-1.938 11.206-1.096 0.336 0.674-5.813 2.528-7.835 4.634-0.674 0.674-2.444 2.275-3.539 2.106-0.842-0.084-1.348-1.853-2.612-3.202-3.032-3.032-4.97-2.78-4.38-3.959 0.505-0.926 4.549 1.263 7.16 1.517z"/>
- <path fill="#e8e8e8" d="m157.751 167.441c1.48 0.164 10.606-1.892 10.936-1.069 0.329 0.657-5.673 2.467-7.646 4.522-0.658 0.657-2.385 2.22-3.453 2.055-0.822-0.082-1.315-1.809-2.549-3.124-2.96-2.96-4.851-2.714-4.275-3.865 0.491-0.904 4.438 1.233 6.987 1.481z"/>
- <path fill="#e5e5e5" d="m157.796 167.481c1.444 0.16 10.346-1.845 10.666-1.043 0.32 0.641-5.532 2.406-7.458 4.41-0.641 0.642-2.325 2.166-3.367 2.005-0.803-0.08-1.284-1.764-2.486-3.047-2.887-2.887-4.732-2.647-4.17-3.769 0.48-0.882 4.329 1.202 6.815 1.444z"/>
- <path fill="#e2e2e2" d="m157.841 167.521c1.407 0.156 10.083-1.799 10.397-1.017 0.312 0.625-5.394 2.346-7.271 4.299-0.625 0.625-2.267 2.111-3.282 1.954-0.782-0.078-1.251-1.719-2.423-2.97-2.814-2.814-4.612-2.58-4.065-3.674 0.469-0.859 4.221 1.172 6.644 1.408z"/>
- <path fill="#dfdfdf" d="m157.886 167.56c1.37 0.152 9.821-1.751 10.127-0.99 0.304 0.609-5.254 2.285-7.081 4.188-0.609 0.609-2.208 2.056-3.198 1.903-0.761-0.076-1.218-1.675-2.36-2.893-2.741-2.741-4.492-2.513-3.959-3.579 0.456-0.837 4.111 1.142 6.471 1.371z"/>
- <path fill="#dbdbdb" d="m157.931 167.6c1.335 0.148 9.561-1.704 9.857-0.963 0.296 0.592-5.114 2.223-6.893 4.076-0.593 0.593-2.149 2.001-3.113 1.853-0.741-0.074-1.186-1.631-2.297-2.817-2.668-2.667-4.373-2.446-3.854-3.483 0.445-0.815 4.003 1.111 6.3 1.334z"/>
- <path fill="#d8d8d8" d="m157.977 167.64c1.298 0.144 9.299-1.658 9.587-0.937 0.288 0.576-4.974 2.163-6.704 3.964-0.576 0.577-2.091 1.947-3.027 1.803-0.721-0.072-1.153-1.586-2.234-2.74-2.596-2.594-4.253-2.379-3.748-3.388 0.431-0.792 3.891 1.081 6.126 1.298z"/>
- <path fill="#d5d5d5" d="m158.022 167.68c1.261 0.14 9.037-1.611 9.317-0.911 0.28 0.56-4.834 2.102-6.516 3.853-0.56 0.561-2.032 1.892-2.942 1.752-0.7-0.07-1.12-1.541-2.172-2.663-2.521-2.521-4.133-2.312-3.643-3.292 0.421-0.77 3.784 1.05 5.956 1.261z"/>
- <path fill="#d2d2d2" d="m158.067 167.72c1.225 0.136 8.775-1.564 9.049-0.884 0.271 0.543-4.695 2.041-6.327 3.741-0.545 0.544-1.974 1.837-2.857 1.701-0.682-0.068-1.09-1.497-2.109-2.585-2.449-2.449-4.014-2.246-3.538-3.198 0.407-0.748 3.673 1.02 5.782 1.225z"/>
- <path fill="#cfcfcf" d="m158.112 167.76c1.188 0.132 8.515-1.518 8.779-0.858 0.264 0.527-4.555 1.98-6.139 3.63-0.527 0.528-1.915 1.782-2.772 1.65-0.66-0.066-1.057-1.452-2.046-2.508-2.376-2.376-3.895-2.179-3.433-3.103 0.397-0.725 3.565 0.99 5.611 1.189z"/>
- <path fill="#ccc" d="m158.157 167.8c1.152 0.128 8.253-1.472 8.51-0.832 0.255 0.511-4.415 1.92-5.95 3.518-0.512 0.512-1.855 1.728-2.688 1.6-0.64-0.064-1.023-1.407-1.983-2.431-2.303-2.303-3.773-2.112-3.326-3.007 0.383-0.703 3.454 0.959 5.437 1.152z"/>
- <path fill="#c8c8c8" d="m158.203 167.84c1.115 0.124 7.991-1.425 8.239-0.805 0.248 0.494-4.274 1.858-5.761 3.406-0.496 0.496-1.798 1.673-2.603 1.549-0.62-0.063-0.992-1.363-1.921-2.354-2.229-2.229-3.655-2.045-3.221-2.912 0.372-0.681 3.346 0.929 5.267 1.116z"/>
- <path fill="#c5c5c5" d="m158.248 167.88c1.079 0.12 7.73-1.379 7.97-0.779 0.239 0.478-4.135 1.798-5.572 3.295-0.479 0.479-1.739 1.618-2.518 1.498-0.6-0.06-0.959-1.318-1.857-2.277-2.157-2.157-3.535-1.978-3.116-2.816 0.359-0.659 3.235 0.898 5.093 1.079z"/>
- <path fill="#c2c2c2" d="m158.293 167.92c1.042 0.116 7.469-1.332 7.701-0.753 0.231 0.462-3.995 1.737-5.385 3.184-0.463 0.463-1.68 1.563-2.432 1.447-0.579-0.058-0.927-1.273-1.796-2.2-2.084-2.084-3.415-1.911-3.01-2.721 0.348-0.636 3.127 0.868 4.922 1.043z"/>
- <path fill="#bfbfbf" d="m158.338 167.959c1.007 0.112 7.207-1.285 7.432-0.726 0.223 0.446-3.855 1.676-5.196 3.072-0.447 0.447-1.621 1.509-2.347 1.397-0.56-0.056-0.895-1.229-1.732-2.123-2.011-2.011-3.296-1.844-2.905-2.626 0.334-0.614 3.016 0.838 4.748 1.006z"/>
- </g>
- <g transform="translate(-12.4048,10.0005)">
- <path d="m194.253 11.922c-1.222 2.631-3.812 23.214-0.248 20.892 3.594-2.341 13.57-5.312 19.886-7.013 7.003-1.886-17.188-19.463-19.638-13.879z"/>
- <path fill="#060606" d="m194.485 12.307c-1.21 2.594-3.704 22.255-0.234 20.007 3.491-2.262 13.077-5.1 19.039-6.782 6.59-1.905-16.436-18.609-18.805-13.225z"/>
- <path fill="#0c0c0c" d="m194.717 12.691c-1.198 2.557-3.595 21.296-0.221 19.124 3.391-2.184 12.586-4.888 18.194-6.551 6.177-1.924-15.684-17.757-17.973-12.573z"/>
- <path fill="#131313" d="m194.949 13.076c-1.187 2.52-3.487 20.337-0.207 18.239 3.288-2.105 12.093-4.676 17.348-6.321 5.763-1.941-14.933-16.903-17.141-11.918z"/>
- <path fill="#191919" d="m195.181 13.46c-1.177 2.483-3.379 19.378-0.193 17.355 3.187-2.027 11.6-4.464 16.502-6.09 5.349-1.959-14.182-16.05-16.309-11.265z"/>
- <path fill="#1f1f1f" d="m195.413 13.845c-1.164 2.446-3.27 18.419-0.18 16.471 3.086-1.949 11.107-4.252 15.657-5.859 4.935-1.978-13.43-15.198-15.477-10.612z"/>
- <path fill="#262626" d="m195.645 14.229c-1.153 2.409-3.162 17.46-0.166 15.586 2.983-1.87 10.616-4.04 14.811-5.628 4.521-1.995-12.679-14.344-14.645-9.958z"/>
- <path fill="#2c2c2c" d="m195.878 14.614c-1.142 2.372-3.055 16.501-0.152 14.702 2.882-1.792 10.123-3.828 13.965-5.398 4.107-2.013-11.929-13.49-13.813-9.304z"/>
- <path fill="#333" d="m196.11 14.999c-1.131 2.335-2.946 15.542-0.14 13.817 2.78-1.713 9.631-3.616 13.119-5.167 3.695-2.031-11.175-12.637-12.979-8.65z"/>
- <path fill="#393939" d="m196.342 15.383c-1.118 2.299-2.838 14.583-0.126 12.934 2.68-1.636 9.139-3.404 12.274-4.937 3.28-2.049-10.425-11.784-12.148-7.997z"/>
- <path fill="#3f3f3f" d="m196.574 15.768c-1.108 2.261-2.729 13.624-0.112 12.049 2.577-1.557 8.646-3.192 11.429-4.706 2.865-2.068-9.675-10.931-11.317-7.343z"/>
- <path fill="#464646" d="m196.806 16.152c-1.097 2.225-2.622 12.665-0.1 11.165 2.477-1.479 8.154-2.98 10.583-4.475 2.453-2.086-8.922-10.078-10.483-6.69z"/>
- <path fill="#4c4c4c" d="m197.038 16.537c-1.085 2.188-2.513 11.706-0.085 10.28 2.374-1.4 7.661-2.768 9.737-4.244 2.039-2.104-8.171-9.225-9.652-6.036z"/>
- <path fill="#525252" d="m197.27 16.921c-1.073 2.151-2.405 10.747-0.071 9.396 2.272-1.322 7.168-2.556 8.891-4.013 1.625-2.122-7.42-8.371-8.82-5.383z"/>
- <path fill="#595959" d="m197.502 17.306c-1.062 2.113-2.297 9.788-0.058 8.512 2.172-1.244 6.677-2.344 8.046-3.783 1.211-2.14-6.669-7.518-7.988-4.729z"/>
- <path fill="#5f5f5f" d="m197.734 17.69c-1.05 2.077-2.188 8.829-0.044 7.627 2.069-1.165 6.184-2.132 7.2-3.552 0.797-2.157-5.917-6.664-7.156-4.075z"/>
- <path fill="#666" d="m197.966 18.075c-1.038 2.04-2.079 7.87-0.029 6.743 1.968-1.087 5.69-1.92 6.354-3.321 0.382-2.176-5.167-5.812-6.325-3.422z"/>
- <path fill="#6c6c6c" d="m198.198 18.459c-1.027 2.003-1.972 6.911-0.017 5.859 1.866-1.008 5.198-1.708 5.509-3.09-0.03-2.194-4.415-4.959-5.492-2.769z"/>
- <path fill="#727272" d="m198.43 18.844c-1.017 1.966-1.863 5.952-0.003 4.975 1.765-0.93 4.706-1.496 4.662-2.86-0.443-2.212-3.662-4.106-4.659-2.115z"/>
- <path fill="#797979" d="m198.662 19.228c-1.004 1.929-1.755 4.993 0.011 4.09 1.663-0.852 4.215-1.284 3.817-2.629-0.858-2.23-2.912-3.251-3.828-1.461z"/>
- <path fill="#7f7f7f" d="m198.894 19.612c-0.993 1.892-1.647 4.034 0.023 3.206 1.563-0.773 3.723-1.072 2.973-2.398-1.272-2.248-2.161-2.399-2.996-0.808z"/>
- </g>
- <g transform="translate(-12.4048,10.0005)">
- <path d="m143.502 46.386c-0.72 2.16 8.712 5.112 10.801 6.984 2.808 2.52 3.023 7.488 6.336 5.472 2.159-1.296 0.504-4.176-3.456-8.568-5.833-6.481-13.033-5.689-13.681-3.888z"/>
- <path fill="#050505" d="m143.991 46.582c-0.716 2.073 8.275 4.9 10.336 6.741 2.745 2.457 2.961 7.249 6.146 5.313 2.094-1.254 0.449-4.072-3.343-8.28-5.574-6.203-12.491-5.505-13.139-3.774z"/>
- <path fill="#0a0a0a" d="m144.479 46.779c-0.71 1.987 7.839 4.688 9.873 6.498 2.682 2.394 2.897 7.009 5.956 5.154 2.028-1.212 0.395-3.968-3.228-7.993-5.319-5.926-11.953-5.321-12.601-3.659z"/>
- <path fill="#0f0f0f" d="m144.967 46.976c-0.704 1.9 7.403 4.476 9.41 6.254 2.62 2.33 2.835 6.77 5.766 4.995 1.964-1.171 0.342-3.864-3.112-7.706-5.064-5.647-11.415-5.137-12.064-3.543z"/>
- <path fill="#141414" d="m145.456 47.172c-0.701 1.813 6.966 4.263 8.946 6.011 2.557 2.266 2.772 6.53 5.575 4.835 1.897-1.129 0.287-3.76-2.998-7.418-4.807-5.369-10.874-4.952-11.523-3.428z"/>
- <path fill="#191919" d="m145.944 47.369c-0.696 1.726 6.53 4.051 8.483 5.768 2.493 2.203 2.71 6.291 5.385 4.676 1.833-1.087 0.231-3.656-2.884-7.13-4.551-5.093-10.335-4.769-10.984-3.314z"/>
- <path fill="#1e1e1e" d="m146.433 47.565c-0.692 1.64 6.093 3.839 8.019 5.525 2.431 2.14 2.647 6.052 5.194 4.517 1.768-1.046 0.179-3.552-2.77-6.843-4.293-4.814-9.794-4.585-10.443-3.199z"/>
- <path fill="#232323" d="m146.921 47.762c-0.686 1.553 5.657 3.627 7.558 5.282 2.367 2.076 2.583 5.813 5.003 4.357 1.702-1.003 0.124-3.448-2.654-6.555-4.04-4.537-9.257-4.401-9.907-3.084z"/>
- <path fill="#282828" d="m147.409 47.959c-0.681 1.466 5.221 3.415 7.094 5.039 2.305 2.013 2.521 5.573 4.813 4.198 1.637-0.962 0.07-3.344-2.54-6.268-3.782-4.26-8.717-4.218-9.367-2.969z"/>
- <path fill="#2d2d2d" d="m147.898 48.156c-0.677 1.379 4.784 3.203 6.63 4.795 2.242 1.949 2.457 5.333 4.622 4.039 1.572-0.92 0.016-3.24-2.425-5.98-3.526-3.983-8.177-4.034-8.827-2.854z"/>
- <path fill="#333" d="m148.386 48.353c-0.673 1.292 4.348 2.99 6.167 4.552 2.179 1.886 2.394 5.095 4.432 3.88 1.506-0.878-0.038-3.136-2.312-5.693-3.268-3.705-7.636-3.85-8.287-2.739z"/>
- <path fill="#383838" d="m148.875 48.549c-0.668 1.206 3.911 2.778 5.703 4.309 2.116 1.823 2.331 4.855 4.242 3.721 1.439-0.836-0.093-3.032-2.197-5.405-3.013-3.428-7.098-3.667-7.748-2.625z"/>
- <path fill="#3d3d3d" d="m149.363 48.746c-0.662 1.119 3.475 2.566 5.24 4.065 2.053 1.759 2.268 4.616 4.052 3.562 1.375-0.795-0.147-2.928-2.082-5.118-2.757-3.15-6.559-3.483-7.21-2.509z"/>
- <path fill="#424242" d="m149.851 48.942c-0.657 1.032 3.039 2.354 4.776 3.823 1.99 1.696 2.205 4.376 3.861 3.402 1.31-0.753-0.201-2.824-1.967-4.831-2.5-2.871-6.018-3.298-6.67-2.394z"/>
- <path fill="#474747" d="m150.34 49.139c-0.652 0.946 2.603 2.142 4.313 3.58 1.927 1.632 2.143 4.137 3.671 3.243 1.244-0.712-0.256-2.72-1.853-4.543-2.245-2.595-5.48-3.115-6.131-2.28z"/>
- <path fill="#4c4c4c" d="m150.828 49.336c-0.647 0.859 2.166 1.93 3.851 3.336 1.863 1.569 2.079 3.898 3.48 3.084 1.179-0.67-0.31-2.616-1.739-4.255-1.988-2.317-4.94-2.932-5.592-2.165z"/>
- <path fill="#515151" d="m151.317 49.533c-0.645 0.772 1.729 1.718 3.386 3.093 1.802 1.505 2.018 3.658 3.29 2.925 1.114-0.628-0.364-2.512-1.624-3.968-1.732-2.04-4.4-2.748-5.052-2.05z"/>
- <path fill="#565656" d="m151.805 49.729c-0.639 0.685 1.293 1.505 2.923 2.85 1.738 1.442 1.954 3.419 3.1 2.766 1.048-0.586-0.418-2.408-1.509-3.681-1.476-1.762-3.862-2.563-4.514-1.935z"/>
- <path fill="#5b5b5b" d="m152.293 49.926c-0.633 0.598 0.857 1.293 2.46 2.606 1.677 1.379 1.892 3.18 2.91 2.606 0.983-0.544-0.473-2.304-1.395-3.393-1.22-1.483-3.322-2.379-3.975-1.819z"/>
- <path fill="#606060" d="m152.782 50.123c-0.629 0.512 0.42 1.081 1.996 2.363 1.613 1.315 1.828 2.94 2.719 2.447 0.918-0.502-0.525-2.2-1.28-3.105-0.963-1.207-2.782-2.196-3.435-1.705z"/>
- <path fill="#666" d="m153.27 50.319c-0.624 0.425-0.017 0.869 1.533 2.12 1.55 1.252 1.765 2.701 2.528 2.288 0.853-0.461-0.581-2.096-1.166-2.818-0.706-0.929-2.242-2.012-2.895-1.59z"/>
- </g>
- <g transform="translate(-12.4048,10.0005)">
- <path d="m193.47 45.594c-0.072 1.08 2.951 1.728 4.896 2.448 1.944 0.648 5.76 3.24 7.56 5.256 1.801 1.944 5.688 7.704 6.553 6.192 0.863-1.368-2.017-5.328-2.809-6.984s-3.239-5.256-7.128-6.48c-3.384-1.008-9-1.297-9.072-0.432z"/>
- <path fill="#060606" d="m193.779 45.67c-0.071 1.05 2.869 1.685 4.758 2.387 1.891 0.633 5.598 3.161 7.345 5.122 1.747 1.893 5.535 7.493 6.376 6.027 0.84-1.328-1.936-5.173-2.738-6.795-0.8-1.622-3.175-5.09-6.952-6.301-3.282-0.995-8.718-1.28-8.789-0.44z"/>
- <path fill="#0c0c0c" d="m194.088 45.747c-0.07 1.021 2.785 1.641 4.62 2.327 1.836 0.618 5.436 3.081 7.131 4.988 1.692 1.842 5.382 7.282 6.198 5.862 0.814-1.288-1.855-5.019-2.67-6.607-0.808-1.587-3.11-4.925-6.776-6.122-3.178-0.983-8.433-1.264-8.503-0.448z"/>
- <path fill="#131313" d="m194.397 45.824c-0.071 0.991 2.702 1.598 4.481 2.267 1.782 0.603 5.272 3.001 6.916 4.854 1.64 1.791 5.229 7.071 6.022 5.697 0.788-1.248-1.776-4.865-2.603-6.418-0.815-1.554-3.044-4.759-6.599-5.942-3.073-0.973-8.148-1.251-8.217-0.458z"/>
- <path fill="#191919" d="m194.706 45.9c-0.069 0.961 2.618 1.555 4.345 2.206 1.728 0.588 5.109 2.922 6.7 4.721 1.586 1.74 5.075 6.86 5.846 5.531 0.764-1.207-1.696-4.711-2.532-6.23-0.824-1.519-2.979-4.593-6.424-5.763-2.972-0.959-7.866-1.234-7.935-0.465z"/>
- <path fill="#1f1f1f" d="m195.015 45.977c-0.07 0.931 2.534 1.511 4.207 2.146 1.672 0.573 4.945 2.843 6.485 4.586 1.531 1.689 4.921 6.649 5.668 5.367 0.738-1.167-1.616-4.557-2.464-6.042-0.832-1.485-2.914-4.428-6.247-5.583-2.868-0.948-7.581-1.219-7.649-0.474z"/>
- <path fill="#262626" d="m195.324 46.054c-0.069 0.901 2.451 1.468 4.069 2.085 1.618 0.557 4.784 2.763 6.271 4.453 1.479 1.638 4.769 6.438 5.491 5.201 0.714-1.127-1.536-4.402-2.396-5.854-0.839-1.451-2.848-4.263-6.07-5.404-2.765-0.934-7.298-1.202-7.365-0.481z"/>
- <path fill="#2c2c2c" d="m195.632 46.13c-0.067 0.872 2.369 1.424 3.933 2.025 1.563 0.542 4.621 2.684 6.056 4.318 1.424 1.587 4.615 6.228 5.315 5.036 0.688-1.086-1.456-4.248-2.326-5.665-0.848-1.416-2.783-4.097-5.896-5.224-2.662-0.923-7.015-1.187-7.082-0.49z"/>
- <path fill="#333" d="m195.941 46.207c-0.068 0.842 2.285 1.381 3.794 1.964 1.51 0.527 4.458 2.605 5.842 4.185 1.37 1.536 4.461 6.016 5.138 4.871 0.662-1.046-1.377-4.093-2.258-5.476-0.855-1.382-2.718-3.932-5.718-5.045-2.56-0.911-6.732-1.172-6.798-0.499z"/>
- <path fill="#393939" d="m196.25 46.284c-0.066 0.813 2.202 1.338 3.656 1.904 1.456 0.512 4.296 2.525 5.627 4.051 1.317 1.485 4.308 5.805 4.961 4.706 0.638-1.006-1.296-3.939-2.188-5.288-0.863-1.348-2.652-3.766-5.542-4.866-2.457-0.899-6.449-1.157-6.514-0.507z"/>
- <path fill="#3f3f3f" d="m196.559 46.36c-0.067 0.783 2.118 1.295 3.518 1.844 1.402 0.497 4.133 2.446 5.412 3.917 1.263 1.434 4.155 5.594 4.785 4.541 0.612-0.966-1.217-3.785-2.12-5.1-0.872-1.313-2.587-3.6-5.366-4.687-2.353-0.886-6.165-1.141-6.229-0.515z"/>
- <path fill="#464646" d="m196.868 46.437c-0.065 0.753 2.035 1.251 3.38 1.783 1.349 0.482 3.972 2.367 5.197 3.783 1.21 1.383 4.002 5.383 4.608 4.375 0.588-0.926-1.137-3.63-2.052-4.911-0.879-1.279-2.521-3.435-5.189-4.507-2.25-0.874-5.881-1.125-5.944-0.523z"/>
- <path fill="#4c4c4c" d="m197.177 46.514c-0.066 0.723 1.95 1.208 3.241 1.723 1.293 0.467 3.809 2.287 4.983 3.649 1.155 1.332 3.848 5.172 4.431 4.21 0.563-0.885-1.057-3.476-1.982-4.723-0.888-1.245-2.456-3.269-5.014-4.328-2.146-0.862-5.597-1.109-5.659-0.531z"/>
- <path fill="#525252" d="m197.486 46.591c-0.066 0.693 1.868 1.164 3.104 1.662 1.239 0.452 3.646 2.208 4.769 3.515 1.102 1.281 3.695 4.961 4.254 4.045 0.537-0.845-0.976-3.321-1.913-4.534-0.896-1.21-2.391-3.103-4.838-4.148-2.044-0.851-5.315-1.095-5.376-0.54z"/>
- <path fill="#595959" d="m197.795 46.667c-0.064 0.664 1.784 1.121 2.968 1.602 1.184 0.437 3.481 2.128 4.552 3.381 1.049 1.23 3.542 4.75 4.078 3.88 0.512-0.805-0.897-3.167-1.846-4.346-0.902-1.176-2.325-2.938-4.66-3.969-1.942-0.838-5.031-1.078-5.092-0.548z"/>
- <path fill="#5f5f5f" d="m198.104 46.744c-0.065 0.634 1.701 1.078 2.829 1.541 1.13 0.421 3.318 2.049 4.338 3.248 0.994 1.179 3.388 4.539 3.899 3.715 0.487-0.765-0.815-3.013-1.775-4.157-0.911-1.142-2.261-2.772-4.485-3.79-1.837-0.826-4.746-1.064-4.806-0.557z"/>
- <path fill="#666" d="m198.413 46.821c-0.063 0.604 1.617 1.034 2.691 1.481 1.076 0.406 3.157 1.969 4.123 3.113 0.94 1.128 3.234 4.328 3.724 3.55 0.462-0.725-0.737-2.858-1.707-3.969-0.919-1.108-2.195-2.606-4.309-3.61-1.734-0.814-4.463-1.049-4.522-0.565z"/>
- <path fill="#6c6c6c" d="m198.721 46.897c-0.063 0.574 1.534 0.991 2.554 1.42 1.021 0.391 2.994 1.89 3.908 2.979 0.887 1.077 3.082 4.117 3.548 3.384 0.436-0.685-0.657-2.704-1.64-3.78-0.927-1.074-2.13-2.44-4.132-3.431-1.631-0.8-4.179-1.031-4.238-0.572z"/>
- <path fill="#727272" d="m199.03 46.974c-0.063 0.544 1.451 0.948 2.416 1.36 0.967 0.376 2.831 1.811 3.694 2.846 0.833 1.026 2.928 3.906 3.369 3.219 0.411-0.644-0.576-2.549-1.569-3.592-0.936-1.04-2.064-2.275-3.956-3.251-1.528-0.79-3.896-1.017-3.954-0.582z"/>
- <path fill="#797979" d="m199.339 47.051c-0.062 0.515 1.368 0.904 2.278 1.299 0.913 0.361 2.669 1.731 3.479 2.712 0.779 0.975 2.774 3.695 3.193 3.054 0.386-0.604-0.497-2.396-1.501-3.403-0.942-1.005-1.999-2.11-3.78-3.072-1.424-0.778-3.612-1.002-3.669-0.59z"/>
- <path fill="#7f7f7f" d="m199.648 47.127c-0.063 0.485 1.284 0.861 2.14 1.239 0.859 0.346 2.506 1.652 3.265 2.578 0.726 0.924 2.621 3.484 3.017 2.889 0.361-0.564-0.417-2.241-1.432-3.215-0.951-0.971-1.935-1.944-3.604-2.893-1.323-0.765-3.33-0.986-3.386-0.598z"/>
- </g>
- <g transform="translate(-12.4048,10.0005)">
- <path fill="#995900" d="m303.631 262.529c4.464 6.479-0.145 14.904 3.096 20.089 5.328 8.496 16.056 17.063 20.16 19.439 2.952 1.8 7.128 3.527 6.983 8.783-0.216 5.977-3.168 7.561-4.823 9.217-3.313 3.313-20.017 11.592-31.104 19.152-13.968 9.576-18.792 13.824-23.328 18.359-7.056 7.057-13.752 9.432-24.48 9.432s-15.552-2.231-18.863-5.184c-3.313-2.88-6.984-10.225-6.624-21.168 0.288-10.872 3.744-20.809 5.399-37.729 0.721-7.271 0.648-16.271 0.648-24.264 0-10.08 0.144-18.648 2.304-19.943 3.889-2.448 4.752-2.592 9.36-2.592 4.607 0 6.696 0.287 8.208 1.799 1.439 1.44 0.864 4.752 0.359 9.433-0.432 4.681 1.801 6.192 4.032 8.136 2.232 1.872 4.248 4.248 11.305 4.824 7.056 0.504 9.647-0.648 12.96-2.736 3.312-2.088 7.991-5.832 9.72-7.992 1.656-2.088 5.76-9.287 6.552-9.287 0.719 0 5.472-1.656 8.136 2.232z"/>
- <path fill="#9e5e00" d="m303.631 262.529c4.464 6.479-0.145 14.904 3.096 20.089 5.328 8.496 16.056 17.063 20.16 19.439 2.952 1.8 7.128 3.527 6.983 8.783-0.216 5.977-3.168 7.561-4.823 9.217-3.313 3.313-20.12 11.556-31.26 19.008-13.885 9.371-18.903 13.54-23.521 17.902-6.912 6.74-13.414 9.084-23.915 9.019-10.411-0.047-15.116-2.181-18.414-5.118-3.297-2.867-6.931-9.966-6.613-20.578 0.205-10.851 3.701-20.683 5.256-37.279 0.666-7.379 0.407-16.303 0.335-24.375-0.076-10.068-0.072-18.627 2.084-19.922 3.889-2.444 4.752-2.592 9.36-2.592 4.607 0 6.7 0.291 8.208 1.799 1.491 1.492 0.767 4.887 0.205 9.408-0.63 4.658 1.458 6.486 3.795 8.607 2.34 2.059 4.489 4.471 11.534 5.021 7.232 0.482 10.015-0.832 13.362-3.106 3.303-2.207 7.773-5.903 9.513-8.168 1.641-2.132 5.727-9.386 6.519-9.386 0.719 0 5.472-1.656 8.136 2.232z"/>
- <path fill="#a36400" d="m303.631 262.529c4.464 6.479-0.145 14.904 3.096 20.089 5.328 8.496 16.056 17.063 20.16 19.439 2.952 1.8 7.128 3.527 6.983 8.783-0.216 5.977-3.168 7.561-4.823 9.217-3.313 3.313-20.226 11.52-31.414 18.863-13.803 9.166-19.016 13.256-23.717 17.447-6.768 6.422-13.075 8.733-23.35 8.604-10.094-0.094-14.682-2.131-17.964-5.055-3.283-2.852-6.876-9.705-6.603-19.987 0.122-10.828 3.657-20.556 5.112-36.828 0.612-7.487 0.165-16.336 0.021-24.487-0.15-10.058-0.287-18.605 1.865-19.9 3.889-2.44 4.752-2.592 9.36-2.592 4.607 0 6.703 0.295 8.208 1.799 1.541 1.541 0.67 5.02 0.051 9.383-0.828 4.637 1.116 6.781 3.556 9.078 2.448 2.248 4.731 4.695 11.766 5.221 7.409 0.461 10.383-1.016 13.767-3.477 3.29-2.326 7.552-5.977 9.302-8.346 1.627-2.175 5.695-9.482 6.487-9.482 0.72-0.001 5.473-1.657 8.137 2.231z"/>
- <path fill="#a86a00" d="m303.631 262.529c4.464 6.479-0.145 14.904 3.096 20.089 5.328 8.496 16.056 17.063 20.16 19.439 2.952 1.8 7.128 3.527 6.983 8.783-0.216 5.977-3.168 7.561-4.823 9.217-3.313 3.313-20.329 11.484-31.568 18.72-13.721 8.961-19.127 12.972-23.911 16.989-6.624 6.105-12.737 8.384-22.785 8.189-9.777-0.141-14.245-2.08-17.514-4.99-3.27-2.836-6.822-9.445-6.591-19.396 0.038-10.807 3.613-20.43 4.968-36.378 0.558-7.597-0.076-16.368-0.292-24.599-0.228-10.047-0.504-18.584 1.645-19.879 3.889-2.438 4.752-2.592 9.36-2.592 4.607 0 6.707 0.299 8.208 1.799 1.591 1.593 0.573 5.152-0.104 9.357-1.025 4.615 0.774 7.077 3.319 9.551 2.556 2.434 4.972 4.918 11.995 5.418 7.585 0.439 10.75-1.199 14.17-3.849 3.279-2.444 7.333-6.048 9.093-8.521 1.613-2.219 5.663-9.58 6.455-9.58 0.719 0.001 5.472-1.655 8.136 2.233z"/>
- <path fill="#ad7000" d="m303.631 262.529c4.464 6.479-0.145 14.904 3.096 20.089 5.328 8.496 16.056 17.063 20.16 19.439 2.952 1.8 7.128 3.527 6.983 8.783-0.216 5.977-3.168 7.561-4.823 9.217-3.313 3.313-20.434 11.447-31.724 18.576-13.637 8.756-19.238 12.687-24.106 16.531-6.479 5.789-12.397 8.035-22.219 7.776-9.461-0.188-13.809-2.03-17.063-4.925-3.254-2.823-6.769-9.188-6.581-18.807-0.043-10.785 3.571-20.305 4.824-35.928 0.504-7.705-0.316-16.402-0.604-24.711-0.303-10.037-0.72-18.563 1.425-19.857 3.889-2.434 4.752-2.592 9.36-2.592 4.607 0 6.711 0.303 8.208 1.799 1.642 1.643 0.475 5.285-0.259 9.332-1.225 4.594 0.432 7.373 3.082 10.022 2.664 2.621 5.212 5.142 12.225 5.616 7.762 0.418 11.117-1.383 14.573-4.219 3.269-2.563 7.113-6.121 8.885-8.698 1.598-2.261 5.63-9.677 6.422-9.677 0.719 0.002 5.472-1.654 8.136 2.234z"/>
- <path fill="#b27500" d="m303.631 262.529c4.464 6.479-0.145 14.904 3.096 20.089 5.328 8.496 16.056 17.063 20.16 19.439 2.952 1.8 7.128 3.527 6.983 8.783-0.216 5.977-3.168 7.561-4.823 9.217-3.313 3.313-20.538 11.412-31.879 18.432-13.554 8.551-19.35 12.402-24.3 16.074-6.336 5.473-12.06 7.686-21.654 7.361-9.144-0.233-13.374-1.979-16.613-4.859-3.24-2.809-6.714-8.928-6.57-18.216-0.126-10.765 3.528-20.179 4.68-35.478 0.45-7.813-0.558-16.435-0.918-24.822-0.378-10.026-0.936-18.541 1.206-19.836 3.889-2.43 4.752-2.592 9.36-2.592 4.607 0 6.714 0.305 8.208 1.799 1.691 1.693 0.378 5.418-0.414 9.307-1.422 4.572 0.09 7.668 2.844 10.494 2.772 2.808 5.454 5.363 12.456 5.814 7.938 0.396 11.484-1.566 14.977-4.591 3.258-2.682 6.894-6.192 8.676-8.874 1.584-2.304 5.598-9.773 6.39-9.773 0.718 0 5.471-1.656 8.135 2.232z"/>
- <path fill="#b77b00" d="m303.631 262.529c4.464 6.479-0.145 14.904 3.096 20.089 5.328 8.496 16.056 17.063 20.16 19.439 2.952 1.8 7.128 3.527 6.983 8.783-0.216 5.977-3.168 7.561-4.823 9.217-3.313 3.313-20.643 11.376-32.033 18.288-13.472 8.345-19.461 12.118-24.494 15.616-6.192 5.156-11.723 7.338-21.089 6.949-8.827-0.281-12.938-1.93-16.164-4.795-3.226-2.795-6.66-8.67-6.56-17.627-0.209-10.742 3.485-20.052 4.536-35.027 0.396-7.92-0.799-16.467-1.23-24.934-0.454-10.015-1.152-18.52 0.985-19.814 3.889-2.426 4.752-2.592 9.36-2.592 4.607 0 6.718 0.31 8.208 1.799 1.743 1.744 0.281 5.553-0.569 9.281-1.62 4.551-0.252 7.963 2.607 10.967 2.88 2.994 5.694 5.586 12.686 6.012 8.115 0.373 11.852-1.75 15.379-4.961 3.248-2.801 6.676-6.264 8.469-9.051 1.568-2.348 5.564-9.871 6.356-9.871 0.72 0 5.473-1.656 8.137 2.232z"/>
- <path fill="#bc8100" d="m303.631 262.529c4.464 6.479-0.145 14.904 3.096 20.089 5.328 8.496 16.056 17.063 20.16 19.439 2.952 1.8 7.128 3.527 6.983 8.783-0.216 5.977-3.168 7.561-4.823 9.217-3.313 3.313-20.747 11.34-32.188 18.145-13.389 8.139-19.574 11.834-24.689 15.159-6.048 4.839-11.383 6.988-20.523 6.534-8.51-0.328-12.503-1.879-15.714-4.73-3.211-2.779-6.606-8.41-6.549-17.035-0.292-10.721 3.441-19.926 4.393-34.578 0.342-8.028-1.041-16.498-1.545-25.045-0.529-10.004-1.368-18.498 0.767-19.793 3.889-2.422 4.752-2.592 9.36-2.592 4.607 0 6.721 0.313 8.208 1.799 1.793 1.793 0.184 5.686-0.723 9.256-1.818 4.529-0.595 8.259 2.367 11.438 2.988 3.184 5.938 5.811 12.917 6.211 8.291 0.352 12.22-1.934 15.783-5.332 3.236-2.92 6.454-6.336 8.258-9.227 1.556-2.391 5.533-9.969 6.325-9.969 0.72-0.001 5.473-1.657 8.137 2.231z"/>
- <path fill="#c18700" d="m303.631 262.529c4.464 6.479-0.145 14.904 3.096 20.089 5.328 8.496 16.056 17.063 20.16 19.439 2.952 1.8 7.128 3.527 6.983 8.783-0.216 5.977-3.168 7.561-4.823 9.217-3.313 3.313-20.852 11.304-32.343 18-13.306 7.936-19.685 11.549-24.883 14.703-5.904 4.521-11.045 6.638-19.959 6.119-8.193-0.375-12.067-1.828-15.264-4.666-3.197-2.764-6.553-8.149-6.537-16.444-0.375-10.699 3.397-19.8 4.248-34.128 0.288-8.137-1.282-16.531-1.858-25.156-0.604-9.994-1.584-18.477 0.547-19.771 3.889-2.42 4.752-2.592 9.36-2.592 4.607 0 6.725 0.316 8.208 1.799 1.843 1.845 0.087 5.818-0.878 9.231-2.017 4.507-0.937 8.554 2.131 11.909 3.096 3.369 6.178 6.033 13.146 6.408 8.468 0.33 12.587-2.117 16.187-5.703 3.225-3.038 6.235-6.408 8.049-9.402 1.541-2.436 5.501-10.066 6.293-10.066 0.72-0.001 5.473-1.657 8.137 2.231z"/>
- <path fill="#c68c00" d="m303.631 262.529c4.464 6.479-0.145 14.904 3.096 20.089 5.328 8.496 16.056 17.063 20.16 19.439 2.952 1.8 7.128 3.527 6.983 8.783-0.216 5.977-3.168 7.561-4.823 9.217-3.313 3.313-20.955 11.268-32.498 17.855-13.223 7.73-19.796 11.266-25.077 14.246-5.761 4.204-10.706 6.289-19.394 5.707-7.877-0.423-11.631-1.779-14.813-4.602-3.183-2.751-6.498-7.891-6.527-15.855-0.457-10.677 3.355-19.674 4.104-33.678 0.234-8.244-1.521-16.563-2.17-25.268-0.681-9.983-1.8-18.455 0.327-19.75 3.889-2.416 4.752-2.592 9.36-2.592 4.607 0 6.729 0.32 8.208 1.799 1.894 1.895-0.011 5.951-1.033 9.207-2.214 4.484-1.278 8.848 1.895 12.379 3.203 3.558 6.418 6.258 13.377 6.607 8.644 0.309 12.952-2.301 16.589-6.074 3.215-3.156 6.016-6.479 7.841-9.58 1.526-2.477 5.468-10.162 6.26-10.162 0.718 0.001 5.471-1.655 8.135 2.233z"/>
- <path fill="#cc9200" d="m303.631 262.529c4.464 6.479-0.145 14.904 3.096 20.089 5.328 8.496 16.056 17.063 20.16 19.439 2.952 1.8 7.128 3.527 6.983 8.783-0.216 5.977-3.168 7.561-4.823 9.217-3.313 3.313-21.061 11.232-32.652 17.712-13.141 7.524-19.908 10.979-25.272 13.788-5.616 3.888-10.368 5.939-18.828 5.292-7.56-0.468-11.195-1.728-14.363-4.536-3.168-2.736-6.444-7.632-6.517-15.264-0.54-10.656 3.313-19.549 3.96-33.229 0.181-8.352-1.764-16.596-2.483-25.38-0.757-9.972-2.017-18.433 0.107-19.728 3.889-2.412 4.752-2.592 9.36-2.592 4.607 0 6.731 0.323 8.208 1.799 1.944 1.945-0.108 6.084-1.188 9.181-2.412 4.464-1.62 9.144 1.656 12.853 3.313 3.744 6.66 6.479 13.608 6.803 8.819 0.289 13.319-2.483 16.991-6.443 3.204-3.275 5.797-6.553 7.633-9.756 1.512-2.52 5.436-10.26 6.228-10.26 0.719 0 5.472-1.656 8.136 2.232z"/>
- <path fill="#d19800" d="m303.631 262.529c4.464 6.479-0.145 14.904 3.096 20.089 5.328 8.496 16.056 17.063 20.16 19.439 2.952 1.8 7.128 3.527 6.983 8.783-0.216 5.977-3.168 7.561-4.823 9.217-3.313 3.313-21.164 11.195-32.808 17.568-13.057 7.318-20.019 10.695-25.466 13.33-5.473 3.571-10.03 5.592-18.263 4.879-7.243-0.516-10.761-1.678-13.914-4.472-3.153-2.722-6.391-7.372-6.506-14.674-0.623-10.634 3.27-19.422 3.816-32.778 0.126-8.459-2.005-16.627-2.797-25.49-0.832-9.961-2.232-18.412-0.112-19.707 3.889-2.408 4.752-2.592 9.36-2.592 4.607 0 6.736 0.328 8.208 1.799 1.995 1.996-0.205 6.219-1.343 9.156-2.61 4.442-1.962 9.438 1.419 13.323 3.42 3.931 6.9 6.703 13.838 7.002 8.997 0.267 13.687-2.668 17.395-6.815 3.194-3.395 5.577-6.623 7.424-9.932 1.497-2.564 5.403-10.357 6.195-10.357 0.721 0 5.474-1.656 8.138 2.232z"/>
- <path fill="#d69e00" d="m303.631 262.529c4.464 6.479-0.145 14.904 3.096 20.089 5.328 8.496 16.056 17.063 20.16 19.439 2.952 1.8 7.128 3.527 6.983 8.783-0.216 5.977-3.168 7.561-4.823 9.217-3.313 3.313-21.27 11.16-32.962 17.424-12.975 7.114-20.132 10.412-25.661 12.874-5.327 3.254-9.69 5.242-17.697 4.464-6.927-0.563-10.325-1.627-13.464-4.406-3.14-2.707-6.337-7.113-6.494-14.084-0.706-10.611 3.225-19.295 3.672-32.328 0.072-8.567-2.247-16.66-3.111-25.603-0.907-9.95-2.448-18.39-0.331-19.685 3.889-2.404 4.752-2.592 9.36-2.592 4.607 0 6.739 0.332 8.208 1.799 2.045 2.045-0.302 6.352-1.497 9.131-2.808 4.421-2.304 9.734 1.18 13.795 3.528 4.119 7.144 6.927 14.069 7.199 9.173 0.246 14.055-2.851 17.799-7.185 3.182-3.514 5.356-6.696 7.214-10.108 1.483-2.607 5.371-10.455 6.163-10.455 0.719 0 5.472-1.656 8.136 2.232z"/>
- <path fill="#dba300" d="m303.631 262.529c4.464 6.479-0.145 14.904 3.096 20.089 5.328 8.496 16.056 17.063 20.16 19.439 2.952 1.8 7.128 3.527 6.983 8.783-0.216 5.977-3.168 7.561-4.823 9.217-3.313 3.313-21.373 11.124-33.116 17.279-12.893 6.91-20.243 10.127-25.855 12.418-5.184 2.937-9.353 4.892-17.133 4.05-6.609-0.609-9.889-1.577-13.014-4.343-3.125-2.692-6.282-6.854-6.483-13.492-0.789-10.592 3.182-19.17 3.528-31.879 0.018-8.676-2.488-16.692-3.425-25.713-0.982-9.94-2.664-18.369-0.551-19.664 3.889-2.401 4.752-2.592 9.36-2.592 4.607 0 6.743 0.334 8.208 1.799 2.095 2.097-0.399 6.484-1.652 9.105-3.006 4.398-2.646 10.029 0.943 14.268 3.636 4.305 7.384 7.148 14.299 7.397 9.349 0.224 14.422-3.034 18.202-7.558 3.171-3.631 5.137-6.768 7.005-10.284 1.469-2.649 5.339-10.552 6.131-10.552 0.72 0.001 5.473-1.655 8.137 2.233z"/>
- <path fill="#e0a900" d="m303.631 262.529c4.464 6.479-0.145 14.904 3.096 20.089 5.328 8.496 16.056 17.063 20.16 19.439 2.952 1.8 7.128 3.527 6.983 8.783-0.216 5.977-3.168 7.561-4.823 9.217-3.313 3.313-21.478 11.088-33.271 17.136-12.81 6.704-20.354 9.843-26.05 11.96-5.04 2.62-9.015 4.543-16.567 3.637-6.293-0.656-9.453-1.527-12.563-4.277-3.11-2.68-6.229-6.596-6.474-12.903-0.871-10.569 3.141-19.044 3.384-31.428-0.035-8.784-2.728-16.726-3.735-25.826-1.06-9.929-2.88-18.347-0.771-19.642 3.889-2.397 4.752-2.592 9.36-2.592 4.607 0 6.747 0.338 8.208 1.799 2.146 2.146-0.497 6.617-1.808 9.08-3.203 4.377-2.987 10.324 0.706 14.738 3.744 4.493 7.624 7.373 14.529 7.596 9.526 0.203 14.789-3.217 18.605-7.926 3.161-3.752 4.918-6.841 6.797-10.463 1.454-2.693 5.306-10.648 6.098-10.648 0.719-0.001 5.472-1.657 8.136 2.231z"/>
- <path fill="#e5af00" d="m303.631 262.529c4.464 6.479-0.145 14.904 3.096 20.089 5.328 8.496 16.056 17.063 20.16 19.439 2.952 1.8 7.128 3.527 6.983 8.783-0.216 5.977-3.168 7.561-4.823 9.217-3.313 3.313-21.582 11.052-33.427 16.992-12.726 6.498-20.466 9.558-26.244 11.502-4.896 2.304-8.676 4.193-16.002 3.222-5.976-0.702-9.018-1.476-12.114-4.212-3.096-2.664-6.174-6.336-6.462-12.313-0.953-10.547 3.097-18.918 3.24-30.978-0.09-8.892-2.97-16.758-4.05-25.938-1.134-9.918-3.096-18.324-0.99-19.619 3.889-2.395 4.752-2.592 9.36-2.592 4.607 0 6.75 0.342 8.208 1.799 2.196 2.197-0.594 6.75-1.962 9.055-3.402 4.355-3.33 10.619 0.468 15.21 3.852 4.681 7.866 7.597 14.76 7.794 9.702 0.18 15.156-3.402 19.008-8.298 3.15-3.87 4.698-6.912 6.589-10.638 1.439-2.736 5.273-10.746 6.065-10.746 0.72 0 5.473-1.656 8.137 2.232z"/>
- <path fill="#eab500" d="m303.631 262.529c4.464 6.479-0.145 14.904 3.096 20.089 5.328 8.496 16.056 17.063 20.16 19.439 2.952 1.8 7.128 3.527 6.983 8.783-0.216 5.977-3.168 7.561-4.823 9.217-3.313 3.313-21.687 11.016-33.582 16.848-12.643 6.293-20.576 9.274-26.438 11.045-4.752 1.987-8.338 3.846-15.438 2.809-5.658-0.75-8.582-1.426-11.664-4.147-3.08-2.649-6.119-6.077-6.45-11.722-1.037-10.526 3.053-18.792 3.096-30.528-0.144-9-3.211-16.79-4.363-26.049-1.21-9.907-3.312-18.304-1.21-19.599 3.889-2.391 4.752-2.592 9.36-2.592 4.607 0 6.754 0.346 8.208 1.799 2.247 2.248-0.691 6.885-2.117 9.029-3.6 4.336-3.672 10.916 0.231 15.682 3.96 4.867 8.106 7.82 14.989 7.992 9.879 0.158 15.523-3.586 19.411-8.668 3.141-3.99 4.479-6.984 6.38-10.814 1.426-2.78 5.241-10.844 6.033-10.844 0.721-0.001 5.474-1.657 8.138 2.231z"/>
- <path fill="#efba00" d="m303.631 262.529c4.464 6.479-0.145 14.904 3.096 20.089 5.328 8.496 16.056 17.063 20.16 19.439 2.952 1.8 7.128 3.527 6.983 8.783-0.216 5.977-3.168 7.561-4.823 9.217-3.313 3.313-21.791 10.98-33.735 16.703-12.562 6.089-20.69 8.99-26.633 10.589-4.608 1.67-7.999 3.496-14.872 2.394-5.343-0.796-8.147-1.375-11.215-4.082-3.066-2.636-6.065-5.818-6.439-11.132-1.12-10.504 3.009-18.666 2.952-30.077-0.198-9.109-3.453-16.822-4.677-26.162-1.285-9.896-3.528-18.281-1.43-19.576 3.889-2.387 4.752-2.592 9.36-2.592 4.607 0 6.757 0.35 8.208 1.799 2.297 2.297-0.788 7.018-2.271 9.004-3.798 4.314-4.014 11.211-0.008 16.154 4.068 5.055 8.35 8.043 15.221 8.189 10.056 0.137 15.892-3.77 19.815-9.039 3.128-4.107 4.258-7.057 6.17-10.99 1.411-2.824 5.209-10.941 6.001-10.941 0.72-0.001 5.473-1.657 8.137 2.231z"/>
- <path fill="#f4c000" d="m303.631 262.529c4.464 6.479-0.145 14.904 3.096 20.089 5.328 8.496 16.056 17.063 20.16 19.439 2.952 1.8 7.128 3.527 6.983 8.783-0.216 5.977-3.168 7.561-4.823 9.217-3.313 3.313-21.896 10.943-33.891 16.561-12.478 5.883-20.801 8.704-26.827 10.131-4.464 1.353-7.661 3.146-14.307 1.979-5.025-0.843-7.711-1.325-10.765-4.019-3.053-2.621-6.012-5.558-6.429-10.541-1.203-10.482 2.966-18.539 2.809-29.627-0.253-9.217-3.694-16.855-4.99-26.272-1.361-9.886-3.744-18.261-1.649-19.556 3.889-2.383 4.752-2.592 9.36-2.592 4.607 0 6.761 0.353 8.208 1.799 2.347 2.349-0.885 7.15-2.426 8.979-3.996 4.291-4.356 11.505-0.245 16.625 4.176 5.241 8.59 8.265 15.451 8.388 10.23 0.115 16.258-3.953 20.218-9.41 3.117-4.227 4.039-7.129 5.961-11.168 1.396-2.865 5.177-11.037 5.969-11.037 0.72 0 5.473-1.656 8.137 2.232z"/>
- <path fill="#f9c600" d="m303.631 262.529c4.464 6.479-0.145 14.904 3.096 20.089 5.328 8.496 16.056 17.063 20.16 19.439 2.952 1.8 7.128 3.527 6.983 8.783-0.216 5.977-3.168 7.561-4.823 9.217-3.313 3.313-21.999 10.908-34.046 16.416-12.395 5.678-20.912 8.421-27.021 9.674-4.32 1.036-7.322 2.797-13.741 1.566-4.709-0.891-7.275-1.275-10.314-3.953-3.037-2.607-5.958-5.299-6.419-9.951-1.284-10.461 2.925-18.414 2.664-29.178-0.306-9.324-3.934-16.887-5.302-26.385-1.437-9.875-3.96-18.238-1.869-19.533 3.889-2.379 4.752-2.592 9.36-2.592 4.607 0 6.765 0.356 8.208 1.799 2.397 2.398-0.983 7.283-2.581 8.955-4.194 4.269-4.698 11.799-0.482 17.096 4.284 5.429 8.83 8.488 15.682 8.586 10.407 0.094 16.625-4.137 20.621-9.781 3.106-4.345 3.819-7.199 5.753-11.344 1.382-2.909 5.144-11.135 5.936-11.135 0.718 0 5.471-1.656 8.135 2.232z"/>
- <path fill="#fc0" d="m303.631 262.529c4.464 6.479-0.145 14.904 3.096 20.089 5.328 8.496 16.056 17.063 20.16 19.439 2.952 1.8 7.128 3.527 6.983 8.783-0.216 5.977-3.168 7.561-4.823 9.217-3.313 3.313-22.104 10.872-34.2 16.271-12.313 5.473-21.024 8.137-27.217 9.217-4.176 0.72-6.983 2.447-13.176 1.151-4.392-0.937-6.84-1.224-9.864-3.888-3.023-2.592-5.903-5.04-6.407-9.359-1.368-10.441 2.88-18.289 2.52-28.729-0.36-9.432-4.176-16.92-5.616-26.496-1.512-9.864-4.176-18.217-2.088-19.512 3.889-2.377 4.752-2.592 9.36-2.592 4.607 0 6.768 0.359 8.208 1.799 2.448 2.449-1.08 7.416-2.736 8.929-4.392 4.248-5.04 12.096-0.72 17.567 4.392 5.617 9.072 8.713 15.912 8.785 10.584 0.071 16.992-4.32 21.023-10.152 3.097-4.465 3.601-7.272 5.544-11.521 1.368-2.952 5.112-11.231 5.904-11.231 0.72 0.001 5.473-1.655 8.137 2.233z"/>
- </g>
- <g transform="translate(-12.4048,10.0005)">
- <path fill="#fc0" d="m236.263 275.762c-0.709-0.258-3.932-15.209-2.191-16.239 3.351-1.997 4.253-2.319 8.377-2.319s6.057 0.322 7.346 1.61c2.126 2.127-1.159 6.702-2.448 7.991-3.738 3.673-10.375 9.215-11.084 8.957z"/>
- <path fill="#ffcc02" d="m236.492 275.286c-0.77-0.326-4.102-14.719-2.368-15.742 3.344-1.992 4.278-2.211 8.322-2.211 4.124 0 5.976 0.269 7.282 1.602 2.105 2.136-1.119 6.572-2.398 7.852-3.727 3.663-10.081 8.811-10.838 8.499z"/>
- <path fill="#ffcc05" d="m236.721 274.809c-0.832-0.393-4.273-14.229-2.547-15.247 3.339-1.983 4.306-2.101 8.269-2.101 4.124 0 5.896 0.213 7.217 1.592 2.087 2.146-1.076 6.443-2.346 7.714-3.718 3.653-9.788 8.409-10.593 8.042z"/>
- <path fill="#ffcc07" d="m236.949 274.333c-0.892-0.461-4.443-13.74-2.722-14.75 3.331-1.979 4.33-1.992 8.213-1.992 4.124 0 5.814 0.158 7.151 1.582 2.068 2.156-1.033 6.316-2.294 7.574-3.707 3.644-9.494 8.007-10.348 7.586z"/>
- <path fill="#ffcd0a" d="m237.178 273.855c-0.954-0.528-4.614-13.249-2.9-14.254 3.326-1.972 4.355-1.882 8.158-1.882 4.124 0 5.734 0.104 7.089 1.572 2.048 2.166-0.993 6.187-2.243 7.437-3.699 3.634-9.202 7.605-10.104 7.127z"/>
- <path fill="#ffcd0c" d="m237.407 273.377c-1.015-0.596-4.785-12.758-3.077-13.758 3.319-1.965 4.382-1.771 8.104-1.771 4.124 0 5.653 0.049 7.023 1.563 2.029 2.176-0.951 6.057-2.19 7.299-3.69 3.623-8.91 7.201-9.86 6.667z"/>
- <path fill="#ffcd0f" d="m237.636 272.901c-1.077-0.662-4.956-12.27-3.256-13.261 3.313-1.959 4.408-1.663 8.05-1.663 4.124 0 5.573-0.006 6.959 1.553 2.01 2.186-0.908 5.93-2.14 7.159-3.679 3.614-8.615 6.8-9.613 6.212z"/>
- <path fill="#ffcd11" d="m237.864 272.424c-1.137-0.731-5.126-11.779-3.431-12.766 3.306-1.951 4.433-1.553 7.994-1.553 4.123 0 5.492-0.061 6.895 1.543 1.991 2.193-0.867 5.801-2.089 7.021-3.669 3.606-8.321 6.397-9.369 5.755z"/>
- <path fill="#ffce14" d="m238.093 271.948c-1.197-0.799-5.297-11.289-3.607-12.27 3.299-1.946 4.459-1.443 7.938-1.443 4.124 0 5.412-0.115 6.83 1.533 1.973 2.204-0.824 5.671-2.037 6.883-3.659 3.596-8.028 5.993-9.124 5.297z"/>
- <path fill="#ffce16" d="m238.322 271.471c-1.26-0.867-5.468-10.801-3.786-11.773 3.293-1.939 4.485-1.334 7.884-1.334 4.124 0 5.332-0.171 6.767 1.524 1.953 2.213-0.783 5.542-1.985 6.743-3.651 3.586-7.736 5.591-8.88 4.84z"/>
- <path fill="#ffce19" d="m238.551 270.995c-1.32-0.935-5.639-10.312-3.963-11.277 3.286-1.934 4.511-1.225 7.829-1.225 4.124 0 5.252-0.226 6.702 1.514 1.934 2.224-0.741 5.414-1.934 6.605-3.64 3.576-7.442 5.187-8.634 4.383z"/>
- <path fill="#ffce1c" d="m238.779 270.517c-1.382-1.002-5.809-9.821-4.14-10.781 3.279-1.926 4.535-1.114 7.774-1.114 4.124 0 5.171-0.279 6.637 1.504 1.914 2.233-0.698 5.285-1.882 6.467-3.63 3.566-7.148 4.784-8.389 3.924z"/>
- <path fill="#ffcf1e" d="m239.008 270.04c-1.442-1.068-5.979-9.33-4.316-10.283 3.272-1.922 4.562-1.006 7.72-1.006 4.124 0 5.09-0.334 6.572 1.494 1.895 2.244-0.657 5.156-1.83 6.328-3.622 3.556-6.857 4.383-8.146 3.467z"/>
- <path fill="#ffcf21" d="m239.237 269.563c-1.505-1.137-6.151-8.841-4.495-9.788 3.267-1.914 4.588-0.896 7.666-0.896 4.124 0 5.009-0.389 6.508 1.486 1.875 2.252-0.616 5.025-1.778 6.188-3.613 3.548-6.564 3.981-7.901 3.01z"/>
- <path fill="#ffcf23" d="m239.466 269.086c-1.565-1.205-6.321-8.352-4.672-9.293 3.262-1.906 4.613-0.785 7.61-0.785 4.124 0 4.93-0.444 6.444 1.476 1.855 2.261-0.573 4.897-1.728 6.052-3.601 3.537-6.269 3.575-7.654 2.55z"/>
- <path fill="#ffcf26" d="m239.694 268.61c-1.627-1.273-6.492-7.861-4.849-8.796 3.255-1.901 4.64-0.677 7.556-0.677 4.124 0 4.849-0.499 6.379 1.466 1.837 2.271-0.531 4.769-1.675 5.912-3.593 3.528-5.977 3.174-7.411 2.095z"/>
- <path fill="#ffd028" d="m239.923 268.133c-1.688-1.34-6.663-7.373-5.025-8.301 3.248-1.895 4.665-0.566 7.501-0.566 4.124 0 4.768-0.555 6.314 1.456 1.817 2.28-0.489 4.64-1.624 5.774-3.583 3.519-5.684 2.771-7.166 1.637z"/>
- <path fill="#ffd02b" d="m240.152 267.657c-1.749-1.408-6.834-6.883-5.203-7.805 3.241-1.889 4.69-0.457 7.446-0.457 4.124 0 4.687-0.609 6.25 1.447 1.798 2.289-0.448 4.51-1.573 5.635-3.572 3.509-5.39 2.367-6.92 1.18z"/>
- <path fill="#ffd02d" d="m240.381 267.178c-1.811-1.475-7.005-6.391-5.381-7.307 3.235-1.881 4.717-0.348 7.393-0.348 4.124 0 4.606-0.664 6.185 1.438 1.779 2.299-0.405 4.381-1.521 5.496-3.564 3.501-5.098 1.965-6.676 0.721z"/>
- <path fill="#ffd030" d="m240.609 266.702c-1.871-1.543-7.175-5.902-5.557-6.811 3.228-1.875 4.741-0.238 7.336-0.238 4.124 0 4.526-0.719 6.122 1.428 1.759 2.31-0.364 4.252-1.471 5.357-3.552 3.49-4.803 1.562-6.43 0.264z"/>
- <path fill="#ffd133" d="m240.838 266.225c-1.933-1.611-7.346-5.413-5.734-6.314 3.222-1.869 4.768-0.129 7.281-0.129 4.124 0 4.446-0.773 6.058 1.418 1.74 2.318-0.322 4.123-1.418 5.219-3.545 3.48-4.512 1.16-6.187-0.194z"/>
- </g>
- <g transform="translate(-12.4048,10.0005)">
- <path fill="#fc0" d="m302.769 263.374c3.742 5.461-0.062 12.76 2.638 17.117-6.809-6.258-9.938-8.834-19.324 0.367 2.577-3.742 3.129-6.257 4.725-9.814 1.104-2.455 4.354-9.57 5.029-9.57 0.613-0.001 4.724-1.35 6.932 1.9z"/>
- <path fill="#ffcc02" d="m302.73 263.413c3.655 5.334 0.035 12.601 2.578 16.723-6.668-6.098-9.729-8.666-18.908 0.322 2.421-3.527 3.025-6.094 4.605-9.592 1.122-2.462 4.243-9.302 4.951-9.311 0.628-0.008 4.617-1.318 6.774 1.858z"/>
- <path fill="#ffcc05" d="m302.691 263.45c3.568 5.209 0.132 12.441 2.517 16.332-6.526-5.938-9.519-8.5-18.492 0.277 2.268-3.314 2.924-5.934 4.488-9.372 1.141-2.468 4.132-9.032 4.873-9.052 0.641-0.013 4.508-1.284 6.614 1.815z"/>
- <path fill="#ffcc07" d="m302.652 263.487c3.48 5.086 0.229 12.282 2.457 15.939-6.386-5.777-9.311-8.332-18.076 0.232 2.111-3.1 2.819-5.771 4.369-9.15 1.158-2.475 4.021-8.762 4.795-8.791 0.655-0.019 4.399-1.254 6.455 1.77z"/>
- <path fill="#ffcd0a" d="m302.614 263.524c3.393 4.96 0.323 12.123 2.396 15.549-6.245-5.617-9.102-8.164-17.66 0.188 1.955-2.887 2.716-5.611 4.251-8.93 1.176-2.481 3.91-8.494 4.716-8.533 0.67-0.027 4.291-1.219 6.297 1.726z"/>
- <path fill="#ffcd0c" d="m302.575 263.562c3.306 4.835 0.419 11.964 2.335 15.155-6.104-5.457-8.891-7.996-17.244 0.143 1.8-2.673 2.613-5.449 4.133-8.707 1.194-2.488 3.8-8.225 4.638-8.273 0.684-0.036 4.182-1.189 6.138 1.682z"/>
- <path fill="#ffcd0f" d="m302.536 263.599c3.219 4.71 0.517 11.805 2.275 14.765-5.963-5.299-8.683-7.83-16.828 0.098 1.644-2.461 2.51-5.289 4.015-8.486 1.212-2.496 3.688-7.956 4.559-8.016 0.698-0.04 4.075-1.155 5.979 1.639z"/>
- <path fill="#ffcd11" d="m302.497 263.637c3.131 4.585 0.612 11.645 2.216 14.371-5.822-5.137-8.474-7.661-16.413 0.053 1.489-2.245 2.406-5.125 3.896-8.264 1.229-2.504 3.576-7.688 4.479-7.756 0.714-0.046 3.968-1.123 5.822 1.596z"/>
- <path fill="#ffce14" d="m302.458 263.674c3.044 4.459 0.708 11.486 2.154 13.979-5.681-4.978-8.263-7.493-15.996 0.009 1.334-2.033 2.303-4.965 3.779-8.043 1.247-2.511 3.464-7.418 4.4-7.498 0.728-0.052 3.859-1.089 5.663 1.553z"/>
- <path fill="#ffce16" d="m302.42 263.711c2.956 4.336 0.804 11.328 2.094 13.588-5.54-4.817-8.055-7.326-15.58-0.036 1.178-1.819 2.199-4.804 3.659-7.822 1.267-2.517 3.354-7.149 4.323-7.237 0.741-0.061 3.75-1.058 5.504 1.507z"/>
- <path fill="#ffce19" d="m302.381 263.749c2.868 4.211 0.9 11.168 2.033 13.196-5.398-4.657-7.845-7.159-15.164-0.081 1.022-1.605 2.097-4.642 3.542-7.601 1.283-2.524 3.241-6.88 4.244-6.979 0.755-0.067 3.642-1.026 5.345 1.465z"/>
- <path fill="#ffce1c" d="m302.342 263.788c2.78 4.084 0.997 11.008 1.973 12.803-5.258-4.498-7.635-6.991-14.748-0.127 0.867-1.391 1.994-4.479 3.424-7.379 1.302-2.531 3.13-6.61 4.166-6.719 0.768-0.074 3.532-0.992 5.185 1.422z"/>
- <path fill="#ffcf1e" d="m302.302 263.825c2.693 3.959 1.093 10.85 1.913 12.411-5.117-4.338-7.427-6.825-14.333-0.172 0.713-1.177 1.891-4.317 3.307-7.157 1.318-2.537 3.018-6.342 4.086-6.461 0.784-0.08 3.426-0.959 5.027 1.379z"/>
- <path fill="#ffcf21" d="m302.263 263.862c2.606 3.834 1.188 10.689 1.853 12.02-4.976-4.178-7.217-6.657-13.916-0.217 0.556-0.963 1.786-4.156 3.188-6.936 1.337-2.545 2.906-6.072 4.008-6.202 0.797-0.086 3.318-0.927 4.867 1.335z"/>
- <path fill="#ffcf23" d="m302.225 263.899c2.519 3.71 1.285 10.531 1.791 11.628-4.835-4.019-7.008-6.489-13.5-0.262 0.4-0.75 1.684-3.994 3.068-6.714 1.356-2.553 2.797-5.805 3.931-5.943 0.813-0.093 3.209-0.895 4.71 1.291z"/>
- <path fill="#ffcf26" d="m302.186 263.937c2.431 3.584 1.381 10.371 1.73 11.235-4.693-3.857-6.798-6.322-13.084-0.307 0.245-0.535 1.58-3.832 2.951-6.492 1.373-2.56 2.686-5.535 3.852-5.685 0.828-0.1 3.101-0.861 4.551 1.249z"/>
- <path fill="#ffd028" d="m302.147 263.974c2.344 3.46 1.477 10.213 1.671 10.845-4.553-3.699-6.589-6.156-12.668-0.354 0.089-0.321 1.477-3.67 2.832-6.271 1.392-2.565 2.574-5.267 3.772-5.425 0.842-0.104 2.994-0.828 4.393 1.205z"/>
- <path fill="#ffd02b" d="m302.108 264.012c2.257 3.334 1.573 10.053 1.61 10.451-4.412-3.537-6.38-5.987-12.253-0.396-0.064-0.109 1.374-3.51 2.716-6.05 1.408-2.573 2.462-4.997 3.693-5.166 0.856-0.112 2.886-0.796 4.234 1.161z"/>
- <path fill="#ffd02d" d="m302.069 264.049c2.17 3.209 1.67 9.894 1.55 10.061-4.271-3.379-6.17-5.82-11.836-0.441-0.221 0.104 1.271-3.35 2.596-5.83 1.428-2.58 2.352-4.728 3.615-4.906 0.87-0.12 2.777-0.765 4.075 1.116z"/>
- <path fill="#ffd030" d="m302.03 264.086c2.082 3.084 1.767 9.736 1.49 9.668-4.131-3.219-5.961-5.652-11.42-0.486-0.377 0.318 1.167-3.188 2.478-5.607 1.445-2.586 2.239-4.459 3.536-4.647 0.884-0.127 2.669-0.732 3.916 1.072z"/>
- <path fill="#ffd133" d="m301.991 264.124c1.995 2.959 1.862 9.576 1.43 9.277-3.989-3.059-5.752-5.486-11.005-0.531-0.532 0.531 1.064-3.027 2.36-5.387 1.463-2.594 2.128-4.189 3.458-4.389 0.899-0.133 2.561-0.699 3.757 1.03z"/>
- </g>
- <g transform="translate(-12.4048,10.0005)">
- <path fill="#fc0" d="m305.862 283.481c5.977 7.848 17.064 16.271 21.024 18.576 2.88 1.656 7.056 3.6 6.983 8.783-0.144 5.904-3.168 7.561-4.823 9.217-3.313 3.313-22.177 10.943-34.2 16.271-12.24 5.4-21.097 8.209-27.217 9.217-4.104 0.647-7.056 2.375-13.176 1.151-4.32-0.864-6.912-1.296-9.864-3.888-2.951-2.52-5.976-5.184-6.407-9.359-1.225-10.369 3.672-16.921 8.424-25.921 3.888-7.2 11.735-8.64 16.632-7.991 17.568 2.375 16.416-8.641 21.24-13.465 4.464-4.463 17.208-8.064 21.384-2.591z"/>
- <path fill="#ffcc02" d="m305.81 283.553c5.962 7.83 17.024 16.234 20.975 18.533 2.873 1.652 7.039 3.592 6.969 8.764-0.145 5.891-3.161 7.542-4.813 9.195-3.304 3.304-22.34 10.992-34.24 16.088-12.259 5.176-20.647 7.873-26.802 8.959-4.077 0.684-7.156 2.394-13.258 1.177-4.304-0.854-6.767-1.231-9.707-3.812-2.939-2.51-5.756-4.961-6.185-9.117-1.211-10.34 3.365-16.657 8.044-25.65 3.89-7.375 11.791-8.434 16.665-7.777 17.514 2.414 16.206-8.959 21.02-13.772 4.452-4.454 17.166-8.047 21.332-2.588z"/>
- <path fill="#ffcc05" d="m305.76 283.627c5.946 7.812 16.982 16.195 20.925 18.488 2.866 1.648 7.022 3.584 6.951 8.743-0.144 5.876-3.153 7.524-4.801 9.173-3.298 3.297-22.506 11.043-34.28 15.907-12.279 4.949-20.201 7.538-26.389 8.699-4.051 0.721-7.256 2.413-13.341 1.202-4.286-0.846-6.619-1.168-9.55-3.733-2.924-2.501-5.536-4.741-5.959-8.877-1.198-10.312 3.058-16.394 7.664-25.379 3.89-7.552 11.845-8.229 16.698-7.563 17.458 2.453 15.995-9.279 20.797-14.08 4.443-4.443 17.127-8.026 21.285-2.58z"/>
- <path fill="#ffcc07" d="m305.707 283.702c5.935 7.791 16.943 16.156 20.876 18.444 2.859 1.644 7.007 3.574 6.935 8.722-0.144 5.862-3.146 7.508-4.79 9.151-3.288 3.289-22.668 11.093-34.319 15.726-12.298 4.723-19.753 7.202-25.974 8.44-4.024 0.756-7.357 2.431-13.423 1.226-4.27-0.836-6.473-1.101-9.394-3.654-2.911-2.492-5.317-4.52-5.735-8.635-1.185-10.285 2.75-16.133 7.284-25.109 3.892-7.727 11.9-8.023 16.731-7.35 17.402 2.494 15.785-9.599 20.575-14.389 4.433-4.432 17.087-8.007 21.234-2.572z"/>
- <path fill="#ffcd0a" d="m305.655 283.774c5.92 7.773 16.904 16.119 20.826 18.4 2.854 1.642 6.99 3.566 6.919 8.703-0.143 5.848-3.138 7.488-4.779 9.129-3.28 3.281-22.832 11.143-34.358 15.543-12.317 4.498-19.307 6.867-25.561 8.182-3.997 0.793-7.457 2.45-13.506 1.251-4.252-0.828-6.325-1.036-9.236-3.577-2.896-2.482-5.096-4.298-5.51-8.393-1.172-10.258 2.443-15.869 6.904-24.84 3.892-7.901 11.955-7.818 16.763-7.135 17.349 2.532 15.576-9.918 20.355-14.697 4.422-4.422 17.046-7.987 21.183-2.566z"/>
- <path fill="#ffcd0c" d="m305.603 283.847c5.906 7.756 16.864 16.081 20.777 18.358 2.846 1.635 6.973 3.557 6.901 8.68-0.142 5.835-3.131 7.472-4.767 9.107-3.273 3.273-22.997 11.193-34.399 15.361-12.337 4.273-18.858 6.533-25.146 7.924-3.971 0.829-7.557 2.469-13.588 1.276-4.234-0.82-6.179-0.972-9.078-3.5-2.884-2.474-4.878-4.076-5.287-8.152-1.158-10.229 2.137-15.606 6.523-24.569 3.895-8.076 12.01-7.611 16.797-6.92 17.293 2.571 15.366-10.236 20.134-15.004 4.412-4.411 17.006-7.969 21.133-2.561z"/>
- <path fill="#ffcd0f" d="m305.552 283.92c5.892 7.736 16.824 16.043 20.728 18.313 2.839 1.634 6.957 3.55 6.886 8.66-0.142 5.821-3.124 7.454-4.756 9.086-3.266 3.267-23.161 11.243-34.438 15.179-12.356 4.047-18.411 6.198-24.733 7.666-3.943 0.865-7.656 2.486-13.67 1.301-4.218-0.812-6.032-0.908-8.922-3.422-2.869-2.465-4.656-3.855-5.063-7.91-1.145-10.203 1.83-15.344 6.145-24.299 3.895-8.252 12.064-7.408 16.83-6.707 17.237 2.61 15.154-10.557 19.912-15.313 4.399-4.399 16.963-7.949 21.081-2.554z"/>
- <path fill="#ffcd11" d="m305.501 283.993c5.877 7.719 16.782 16.004 20.678 18.271 2.833 1.628 6.939 3.54 6.869 8.639-0.143 5.807-3.116 7.436-4.745 9.064-3.257 3.258-23.324 11.293-34.479 14.996-12.375 3.822-17.963 5.863-24.319 7.408-3.917 0.9-7.757 2.504-13.752 1.324-4.2-0.802-5.886-0.842-8.765-3.344-2.856-2.454-4.438-3.633-4.838-7.669-1.132-10.173 1.521-15.081 5.764-24.029 3.896-8.426 12.119-7.2 16.863-6.491 17.183 2.649 14.945-10.875 19.689-15.621 4.391-4.389 16.926-7.93 21.035-2.548z"/>
- <path fill="#ffce14" d="m305.448 284.066c5.863 7.701 16.743 15.966 20.629 18.228 2.826 1.625 6.924 3.531 6.853 8.619-0.142 5.793-3.108 7.418-4.733 9.043-3.25 3.25-23.489 11.342-34.518 14.813-12.396 3.598-17.517 5.529-23.905 7.148-3.891 0.938-7.857 2.524-13.834 1.351-4.185-0.793-5.74-0.776-8.609-3.267-2.841-2.444-4.217-3.412-4.613-7.426-1.118-10.146 1.216-14.818 5.385-23.76 3.896-8.602 12.174-6.996 16.896-6.277 17.128 2.688 14.735-11.195 19.468-15.929 4.378-4.38 16.883-7.911 20.981-2.543z"/>
- <path fill="#ffce16" d="m305.396 284.139c5.85 7.682 16.703 15.928 20.579 18.184 2.82 1.62 6.907 3.523 6.837 8.598-0.141 5.779-3.101 7.4-4.722 9.021-3.242 3.242-23.653 11.393-34.559 14.631-12.414 3.372-17.068 5.194-23.491 6.891-3.862 0.975-7.957 2.543-13.917 1.375-4.167-0.783-5.592-0.713-8.451-3.188-2.827-2.437-3.997-3.19-4.389-7.187-1.105-10.117 0.908-14.555 5.004-23.487 3.898-8.776 12.229-6.79 16.928-6.063 17.074 2.728 14.525-11.515 19.248-16.236 4.37-4.371 16.845-7.894 20.933-2.539z"/>
- <path fill="#ffce19" d="m305.344 284.211c5.836 7.664 16.663 15.891 20.529 18.141 2.813 1.617 6.892 3.516 6.82 8.578-0.14 5.765-3.093 7.382-4.71 8.999-3.235 3.233-23.817 11.442-34.598 14.448-12.434 3.146-16.621 4.859-23.077 6.633-3.837 1.01-8.058 2.561-13.999 1.4-4.15-0.775-5.446-0.648-8.295-3.111-2.814-2.426-3.777-2.969-4.164-6.944-1.094-10.09 0.601-14.293 4.624-23.22 3.898-8.951 12.282-6.584 16.961-5.848 17.019 2.767 14.314-11.834 19.025-16.545 4.361-4.359 16.806-7.872 20.884-2.531z"/>
- <path fill="#ffce1c" d="m305.292 284.286c5.822 7.646 16.623 15.852 20.481 18.096 2.806 1.613 6.874 3.507 6.804 8.558-0.141 5.751-3.086 7.364-4.699 8.978-3.227 3.227-23.981 11.492-34.638 14.267-12.453 2.921-16.173 4.524-22.663 6.374-3.81 1.046-8.158 2.578-14.082 1.424-4.133-0.766-5.299-0.583-8.137-3.033-2.801-2.416-3.558-2.748-3.94-6.703-1.08-10.062 0.293-14.029 4.244-22.947 3.9-9.127 12.338-6.379 16.994-5.635 16.964 2.805 14.105-12.152 18.805-16.853 4.348-4.351 16.763-7.856 20.831-2.526z"/>
- <path fill="#ffcf1e" d="m305.241 284.358c5.808 7.627 16.582 15.814 20.432 18.053 2.799 1.609 6.856 3.498 6.787 8.536-0.141 5.738-3.079 7.347-4.688 8.957-3.219 3.218-24.145 11.541-34.677 14.084-12.473 2.695-15.727 4.188-22.25 6.115-3.783 1.083-8.258 2.599-14.163 1.448-4.116-0.756-5.153-0.518-7.981-2.954-2.786-2.408-3.337-2.526-3.716-6.462-1.066-10.034-0.013-13.766 3.864-22.678 3.901-9.303 12.393-6.172 17.027-5.42 16.908 2.844 13.896-12.473 18.583-17.16 4.338-4.337 16.723-7.835 20.782-2.519z"/>
- <path fill="#ffcf21" d="m305.189 284.431c5.793 7.608 16.542 15.776 20.382 18.009 2.792 1.605 6.84 3.49 6.771 8.516-0.14 5.725-3.071 7.33-4.677 8.936-3.211 3.211-24.309 11.591-34.717 13.902-12.491 2.47-15.278 3.854-21.836 5.856-3.756 1.119-8.357 2.616-14.246 1.474-4.099-0.748-5.006-0.453-7.823-2.877-2.772-2.398-3.118-2.306-3.492-6.22-1.053-10.007-0.319-13.505 3.484-22.407 3.903-9.479 12.448-5.969 17.062-5.207 16.853 2.883 13.684-12.791 18.36-17.469 4.328-4.328 16.683-7.819 20.732-2.513z"/>
- <path fill="#ffcf23" d="m305.137 284.504c5.778 7.59 16.503 15.736 20.332 17.965 2.786 1.602 6.825 3.482 6.755 8.496-0.139 5.709-3.064 7.311-4.665 8.912-3.204 3.203-24.474 11.642-34.759 13.721-12.51 2.244-14.829 3.52-21.421 5.598-3.729 1.155-8.457 2.635-14.327 1.499-4.082-0.739-4.86-0.389-7.667-2.8-2.76-2.389-2.897-2.083-3.268-5.979-1.04-9.979-0.627-13.24 3.104-22.138 3.903-9.653 12.503-5.762 17.093-4.991 16.799 2.922 13.475-13.111 18.141-17.777 4.318-4.316 16.643-7.799 20.682-2.506z"/>
- <path fill="#ffcf26" d="m305.086 284.579c5.765 7.57 16.463 15.697 20.282 17.92 2.779 1.599 6.809 3.474 6.738 8.476-0.139 5.696-3.056 7.293-4.654 8.892-3.194 3.194-24.637 11.69-34.797 13.536-12.529 2.021-14.382 3.185-21.007 5.341-3.703 1.191-8.559 2.652-14.411 1.523-4.065-0.73-4.713-0.324-7.509-2.723-2.745-2.379-2.679-1.861-3.043-5.735-1.027-9.952-0.936-12.979 2.724-21.868 3.905-9.828 12.557-5.557 17.126-4.777 16.744 2.961 13.265-13.431 17.919-18.084 4.307-4.309 16.602-7.783 20.632-2.501z"/>
- <path fill="#ffd028" d="m305.033 284.651c5.752 7.553 16.423 15.66 20.234 17.878 2.771 1.593 6.791 3.464 6.722 8.454-0.139 5.682-3.049 7.275-4.643 8.869-3.188 3.188-24.801 11.74-34.838 13.355-12.548 1.793-13.935 2.85-20.593 5.082-3.676 1.228-8.658 2.67-14.493 1.547-4.048-0.721-4.565-0.258-7.353-2.644-2.731-2.37-2.457-1.64-2.818-5.495-1.014-9.923-1.242-12.716 2.345-21.597 3.905-10.004 12.611-5.351 17.158-4.563 16.689 3 13.055-13.75 17.698-18.393 4.297-4.295 16.562-7.761 20.581-2.493z"/>
- <path fill="#ffd02b" d="m304.982 284.724c5.737 7.534 16.382 15.622 20.184 17.834 2.766 1.59 6.774 3.456 6.705 8.433-0.138 5.67-3.041 7.26-4.631 8.85-3.18 3.179-24.966 11.789-34.877 13.172-12.568 1.568-13.487 2.515-20.179 4.824-3.65 1.263-8.759 2.688-14.575 1.572-4.031-0.713-4.42-0.195-7.196-2.566-2.718-2.361-2.238-1.42-2.594-5.254-1.001-9.896-1.549-12.453 1.964-21.328 3.907-10.178 12.666-5.145 17.192-4.348 16.634 3.039 12.844-14.068 17.476-18.701 4.285-4.286 16.521-7.743 20.531-2.488z"/>
- <path fill="#ffd02d" d="m304.93 284.797c5.723 7.516 16.342 15.584 20.135 17.789 2.758 1.588 6.758 3.449 6.688 8.414-0.138 5.654-3.034 7.24-4.619 8.826-3.173 3.172-25.13 11.84-34.918 12.99-12.587 1.344-13.039 2.18-19.766 4.564-3.622 1.301-8.856 2.709-14.657 1.599-4.014-0.704-4.272-0.13-7.039-2.489-2.702-2.352-2.018-1.197-2.369-5.012-0.987-9.868-1.855-12.189 1.584-21.057 3.908-10.354 12.722-4.94 17.226-4.135 16.578 3.078 12.634-14.389 17.254-19.009 4.275-4.273 16.481-7.721 20.481-2.48z"/>
- <path fill="#ffd030" d="m304.879 284.87c5.709 7.498 16.302 15.547 20.085 17.748 2.752 1.582 6.741 3.438 6.673 8.391-0.139 5.642-3.027 7.224-4.609 8.806-3.164 3.164-25.293 11.89-34.956 12.808-12.606 1.119-12.592 1.844-19.352 4.308-3.596 1.336-8.958 2.726-14.739 1.622-3.997-0.695-4.127-0.065-6.882-2.411-2.69-2.343-1.799-0.976-2.146-4.771-0.974-9.84-2.163-11.928 1.204-20.787 3.91-10.529 12.777-4.734 17.258-3.92 16.524 3.117 12.424-14.707 17.034-19.316 4.263-4.267 16.439-7.706 20.43-2.478z"/>
- <path fill="#ffd133" d="m304.826 284.943c5.695 7.479 16.263 15.509 20.036 17.703 2.745 1.579 6.726 3.431 6.656 8.372-0.137 5.627-3.02 7.205-4.597 8.783-3.157 3.156-25.458 11.939-34.997 12.625-12.626 0.893-12.145 1.51-18.938 4.049-3.569 1.373-9.058 2.745-14.822 1.646-3.979-0.686-3.979 0-6.725-2.332-2.676-2.334-1.578-0.756-1.921-4.529-0.961-9.813-2.471-11.665 0.824-20.516 3.91-10.705 12.83-4.529 17.29-3.707 16.47 3.156 12.215-15.027 16.813-19.625 4.255-4.253 16.401-7.684 20.381-2.469z"/>
- </g>
- <g transform="translate(-12.4048,10.0005)">
- <path fill="#995900" d="m52.494 273.618c-6.479 4.68-22.896 4.248-27.072 9.719-4.104 5.473 0.145 13.393 0.072 28.08 0 6.265-1.08 11.017-1.8 14.832-1.008 4.824-1.656 8.209 0.36 11.664 3.672 6.121 9.575 7.633 43.344 14.688 18.072 3.744 35.136 13.464 46.584 14.399 11.448 0.865 13.896-2.951 20.88-9.144 6.912-6.192 9.144-4.248 8.928-17.856-0.216-13.535-8.928-17.567-18.792-33.191s-11.448-18.504-18-28.872c-6.552-10.224-19.512-28.8-26.928-29.017-5.904-0.144-9.216 3.024-12.888 6.769s-8.208 13.248-14.688 17.929z"/>
- <path fill="#9e5e00" d="m52.598 273.905c-6.397 4.702-22.475 3.788-27.062 9.512-4.154 5.414 0.228 13.276 0.098 27.955-0.025 6.23-1.152 10.881-1.937 14.877-1.037 4.871-1.678 8.201 0.349 11.619 3.787 6.162 9.695 7.123 43.456 14.168 18.061 3.737 34.541 13.307 46.343 14.112 11.186 0.792 13.564-2.829 20.463-8.96 6.896-6.195 9.024-4.277 8.858-17.406-0.075-13.521-8.305-17.349-18.169-32.973s-11.448-18.504-18-28.872c-6.552-10.224-19.512-28.8-26.928-29.017-5.904-0.144-9.216 3.024-12.888 6.769s-8.153 13.479-14.583 18.216z"/>
- <path fill="#a36400" d="m52.703 274.193c-6.314 4.724-22.054 3.327-27.051 9.304-4.204 5.356 0.31 13.16 0.123 27.828-0.051 6.198-1.225 10.748-2.074 14.924-1.065 4.918-1.699 8.194 0.339 11.571 3.902 6.206 9.813 6.617 43.567 13.651 18.05 3.73 33.948 13.146 46.101 13.824 10.923 0.72 13.234-2.707 20.045-8.777 6.885-6.199 8.907-4.305 8.792-16.956 0.064-13.507-7.683-17.129-17.547-32.753s-11.448-18.504-18-28.872c-6.552-10.224-19.512-28.8-26.928-29.017-5.904-0.144-9.216 3.024-12.888 6.769s-8.1 13.709-14.479 18.504z"/>
- <path fill="#a86a00" d="m52.807 274.481c-6.231 4.745-21.633 2.866-27.04 9.094-4.255 5.299 0.393 13.047 0.148 27.702-0.076 6.167-1.297 10.616-2.211 14.972-1.095 4.965-1.721 8.188 0.328 11.524 4.018 6.25 9.932 6.108 43.679 13.134 18.039 3.721 33.354 12.988 45.86 13.535 10.659 0.648 12.902-2.585 19.627-8.593 6.869-6.203 8.788-4.335 8.723-16.507 0.205-13.492-7.06-16.909-16.924-32.533s-11.448-18.504-18-28.872c-6.552-10.224-19.512-28.8-26.928-29.017-5.904-0.144-9.216 3.024-12.888 6.769s-8.045 13.94-14.374 18.792z"/>
- <path fill="#ad7000" d="m52.912 274.769c-6.149 4.767-21.211 2.405-27.029 8.885-4.306 5.242 0.476 12.931 0.173 27.576-0.101 6.136-1.368 10.483-2.347 15.019-1.123 5.012-1.742 8.181 0.316 11.478 4.133 6.293 10.052 5.603 43.791 12.614 18.028 3.716 32.76 12.83 45.619 13.248 10.396 0.576 12.57-2.463 19.21-8.409 6.854-6.206 8.668-4.363 8.653-16.056 0.347-13.479-6.437-16.69-16.301-32.314s-11.448-18.504-18-28.872c-6.552-10.224-19.512-28.8-26.928-29.017-5.904-0.144-9.216 3.024-12.888 6.769s-7.991 14.169-14.269 19.079z"/>
- <path fill="#b27500" d="m53.016 275.057c-6.066 4.787-20.79 1.943-27.019 8.676-4.355 5.184 0.559 12.816 0.198 27.45-0.126 6.103-1.44 10.351-2.484 15.065-1.151 5.059-1.764 8.172 0.307 11.431 4.248 6.336 10.17 5.094 43.901 12.096 18.019 3.708 32.166 12.672 45.378 12.96 10.135 0.504 12.24-2.34 18.792-8.227 6.841-6.209 8.551-4.391 8.586-15.605 0.486-13.464-5.813-16.47-15.678-32.094s-11.448-18.504-18-28.872c-6.552-10.224-19.512-28.8-26.928-29.017-5.904-0.144-9.216 3.024-12.888 6.769s-7.937 14.399-14.165 19.368z"/>
- <path fill="#b77b00" d="m53.121 275.344c-5.983 4.811-20.369 1.484-27.008 8.469-4.406 5.126 0.641 12.7 0.224 27.324-0.151 6.068-1.512 10.216-2.621 15.111-1.181 5.105-1.785 8.166 0.295 11.385 4.363 6.379 10.289 4.586 44.014 11.576 18.008 3.701 31.572 12.515 45.137 12.672 9.872 0.433 11.909-2.217 18.375-8.041 6.825-6.215 8.431-4.422 8.518-15.156 0.627-13.45-5.191-16.251-15.056-31.875s-11.448-18.504-18-28.872c-6.552-10.224-19.512-28.8-26.928-29.017-5.904-0.144-9.216 3.024-12.888 6.769s-7.884 14.631-14.062 19.655z"/>
- <path fill="#bc8100" d="m53.225 275.633c-5.9 4.832-19.948 1.023-26.997 8.259-4.457 5.069 0.724 12.585 0.249 27.198-0.177 6.037-1.584 10.082-2.758 15.158-1.21 5.152-1.808 8.158 0.284 11.338 4.479 6.422 10.407 4.078 44.125 11.059 17.997 3.693 30.979 12.355 44.896 12.384 9.608 0.36 11.578-2.095 17.957-7.858 6.812-6.217 8.313-4.449 8.45-14.707 0.766-13.435-4.569-16.03-14.434-31.654s-11.448-18.504-18-28.872c-6.552-10.224-19.512-28.8-26.928-29.017-5.904-0.144-9.216 3.024-12.888 6.769s-7.829 14.859-13.956 19.943z"/>
- <path fill="#c18700" d="m53.329 275.92c-5.817 4.854-19.526 0.563-26.985 8.051-4.507 5.011 0.807 12.47 0.273 27.072-0.201 6.004-1.655 9.949-2.894 15.205-1.239 5.199-1.829 8.151 0.273 11.291 4.594 6.465 10.526 3.57 44.236 10.541 17.985 3.686 30.384 12.196 44.655 12.096 9.345 0.287 11.245-1.973 17.539-7.676 6.797-6.221 8.193-4.479 8.381-14.256 0.906-13.42-3.946-15.812-13.811-31.436s-11.448-18.504-18-28.872c-6.552-10.224-19.512-28.8-26.928-29.017-5.904-0.144-9.216 3.024-12.888 6.769s-7.774 15.094-13.851 20.232z"/>
- <path fill="#c68c00" d="m53.433 276.209c-5.734 4.875-19.104 0.101-26.975 7.84-4.558 4.955 0.89 12.355 0.299 26.947-0.227 5.973-1.728 9.816-3.031 15.252-1.267 5.246-1.851 8.145 0.263 11.244 4.709 6.508 10.646 3.063 44.349 10.022 17.975 3.679 29.79 12.038 44.413 11.808 9.083 0.217 10.915-1.851 17.122-7.492 6.782-6.224 8.074-4.506 8.313-13.806 1.048-13.405-3.323-15.592-13.188-31.216s-11.448-18.504-18-28.872c-6.552-10.224-19.512-28.8-26.928-29.017-5.904-0.144-9.216 3.024-12.888 6.769s-7.722 15.322-13.749 20.521z"/>
- <path fill="#cc9200" d="m53.538 276.497c-5.651 4.896-18.684-0.359-26.964 7.633-4.607 4.896 0.972 12.24 0.324 26.82-0.252 5.939-1.8 9.684-3.168 15.299-1.296 5.293-1.872 8.137 0.252 11.196 4.824 6.552 10.764 2.556 44.46 9.505 17.964 3.672 29.196 11.879 44.172 11.52 8.82 0.144 10.584-1.729 16.704-7.309 6.768-6.228 7.956-4.535 8.244-13.355 1.188-13.393-2.7-15.372-12.564-30.996s-11.448-18.504-18-28.872c-6.552-10.224-19.512-28.8-26.928-29.017-5.904-0.144-9.216 3.024-12.888 6.769s-7.668 15.551-13.644 20.807z"/>
- <path fill="#d19800" d="m53.642 276.786c-5.569 4.918-18.263-0.82-26.953 7.424-4.658 4.838 1.055 12.123 0.35 26.693-0.277 5.907-1.872 9.551-3.305 15.346-1.325 5.34-1.894 8.129 0.241 11.15 4.938 6.596 10.883 2.048 44.571 8.984 17.953 3.666 28.602 11.723 43.931 11.232 8.558 0.072 10.253-1.605 16.287-7.123 6.753-6.232 7.837-4.566 8.175-12.906 1.329-13.379-2.077-15.153-11.941-30.777s-11.448-18.504-18-28.872c-6.552-10.224-19.512-28.8-26.928-29.017-5.904-0.144-9.216 3.024-12.888 6.769s-7.614 15.783-13.54 21.097z"/>
- <path fill="#d69e00" d="m53.747 277.073c-5.486 4.94-17.842-1.281-26.942 7.215-4.709 4.781 1.138 12.01 0.374 26.568-0.302 5.875-1.943 9.417-3.441 15.393-1.354 5.387-1.915 8.123 0.23 11.104 5.055 6.639 11.002 1.541 44.684 8.467 17.942 3.658 28.008 11.563 43.688 10.944 8.296 0 9.923-1.483 15.869-6.941 6.74-6.235 7.72-4.593 8.108-12.456 1.468-13.363-1.455-14.933-11.319-30.557s-11.448-18.504-18-28.872c-6.552-10.224-19.512-28.8-26.928-29.017-5.904-0.144-9.216 3.024-12.888 6.769s-7.56 16.012-13.435 21.383z"/>
- <path fill="#dba300" d="m53.851 277.361c-5.403 4.962-17.421-1.741-26.932 7.007-4.759 4.723 1.221 11.893 0.399 26.441-0.327 5.843-2.016 9.283-3.578 15.439-1.383 5.434-1.937 8.115 0.22 11.057 5.169 6.682 11.12 1.033 44.795 7.949 17.932 3.649 27.414 11.404 43.448 10.656 8.031-0.072 9.59-1.361 15.451-6.758 6.725-6.238 7.6-4.623 8.039-12.006 1.609-13.35-0.832-14.714-10.696-30.338s-11.448-18.504-18-28.872c-6.552-10.224-19.512-28.8-26.928-29.017-5.904-0.144-9.216 3.024-12.888 6.769s-7.504 16.245-13.33 21.673z"/>
- <path fill="#e0a900" d="m53.956 277.649c-5.321 4.982-16.999-2.203-26.921 6.797-4.81 4.666 1.303 11.779 0.425 26.316-0.353 5.811-2.088 9.15-3.715 15.486-1.411 5.48-1.959 8.108 0.208 11.01 5.285 6.725 11.239 0.525 44.907 7.431 17.92 3.644 26.819 11.246 43.207 10.368 7.769-0.145 9.259-1.239 15.034-6.574 6.71-6.242 7.479-4.65 7.97-11.557 1.75-13.334-0.209-14.493-10.073-30.117s-11.448-18.504-18-28.872c-6.552-10.224-19.512-28.8-26.928-29.017-5.904-0.144-9.216 3.024-12.888 6.769s-7.452 16.474-13.226 21.96z"/>
- <path fill="#e5af00" d="m54.06 277.937c-5.238 5.004-16.578-2.664-26.91 6.588-4.86 4.608 1.386 11.664 0.45 26.19-0.378 5.777-2.16 9.018-3.853 15.533-1.439 5.526-1.979 8.101 0.198 10.963 5.4 6.768 11.358 0.018 45.018 6.912 17.91 3.635 26.227 11.088 42.967 10.08 7.506-0.217 8.928-1.117 14.615-6.391 6.696-6.246 7.362-4.68 7.902-11.105 1.89-13.32 0.414-14.274-9.45-29.898s-11.448-18.504-18-28.872c-6.552-10.224-19.512-28.8-26.928-29.017-5.904-0.144-9.216 3.024-12.888 6.769s-7.397 16.704-13.121 22.248z"/>
- <path fill="#eab500" d="m54.165 278.225c-5.155 5.025-16.157-3.124-26.899 6.38-4.91 4.55 1.469 11.548 0.476 26.063-0.403 5.746-2.232 8.885-3.989 15.58-1.469 5.573-2.002 8.094 0.188 10.916 5.515 6.812 11.477-0.49 45.129 6.394 17.899 3.629 25.633 10.93 42.725 9.792 7.243-0.288 8.598-0.993 14.199-6.206 6.681-6.25 7.243-4.709 7.833-10.656 2.031-13.306 1.037-14.055-8.827-29.679s-11.448-18.504-18-28.872c-6.552-10.224-19.512-28.8-26.928-29.017-5.904-0.144-9.216 3.024-12.888 6.769s-7.346 16.935-13.019 22.536z"/>
- <path fill="#efba00" d="m54.269 278.513c-5.073 5.048-15.736-3.585-26.889 6.171-4.961 4.492 1.552 11.434 0.5 25.938-0.428 5.713-2.304 8.752-4.125 15.627-1.498 5.621-2.023 8.086 0.176 10.869 5.631 6.854 11.596-0.996 45.241 5.875 17.889 3.623 25.038 10.771 42.483 9.504 6.981-0.359 8.266-0.871 13.781-6.022 6.668-6.253 7.125-4.737 7.766-10.206 2.17-13.291 1.659-13.835-8.205-29.459s-11.448-18.504-18-28.872c-6.552-10.224-19.512-28.8-26.928-29.017-5.904-0.144-9.216 3.024-12.888 6.769s-7.289 17.164-12.912 22.823z"/>
- <path fill="#f4c000" d="m54.374 278.801c-4.99 5.068-15.314-4.047-26.878 5.962-5.012 4.435 1.634 11.317 0.525 25.812-0.453 5.682-2.376 8.618-4.263 15.674-1.526 5.668-2.045 8.08 0.166 10.822 5.745 6.898 11.714-1.505 45.353 5.357 17.878 3.613 24.444 10.613 42.243 9.216 6.717-0.433 7.934-0.749 13.362-5.839 6.653-6.258 7.007-4.768 7.697-9.756 2.312-13.277 2.282-13.616-7.582-29.24s-11.448-18.504-18-28.872c-6.552-10.224-19.512-28.8-26.928-29.017-5.904-0.144-9.216 3.024-12.888 6.769s-7.235 17.395-12.807 23.112z"/>
- <path fill="#f9c600" d="m54.477 279.088c-4.906 5.092-14.893-4.506-26.866 5.754-5.062 4.377 1.717 11.203 0.551 25.686-0.479 5.648-2.448 8.485-4.399 15.721-1.555 5.715-2.066 8.072 0.155 10.775 5.86 6.941 11.833-2.012 45.464 4.839 17.867 3.607 23.851 10.454 42.001 8.929 6.455-0.504 7.604-0.627 12.946-5.656 6.638-6.26 6.886-4.795 7.628-9.307 2.452-13.262 2.905-13.396-6.959-29.02s-11.448-18.504-18-28.872c-6.552-10.224-19.512-28.8-26.928-29.017-5.904-0.144-9.216 3.024-12.888 6.769s-7.182 17.626-12.705 23.399z"/>
- <path fill="#fc0" d="m54.582 279.377c-4.823 5.111-14.472-4.969-26.855 5.543-5.112 4.32 1.8 11.088 0.576 25.561-0.504 5.616-2.521 8.352-4.536 15.768-1.584 5.76-2.088 8.064 0.144 10.729 5.977 6.984 11.952-2.52 45.576 4.32 17.856 3.6 23.256 10.295 41.76 8.64 6.192-0.576 7.272-0.504 12.528-5.472 6.624-6.264 6.768-4.824 7.56-8.856 2.592-13.248 3.528-13.176-6.336-28.8s-11.448-18.504-18-28.872c-6.552-10.224-19.512-28.8-26.928-29.017-5.904-0.144-9.216 3.024-12.888 6.769s-7.129 17.855-12.601 23.687z"/>
- </g>
- <g transform="translate(-12.4048,10.0005)">
- <path fill="#fc0" d="m57.701 285.002c-4.278 4.539-18.28-1.36-24.892 3.631-4.732 3.5 2.398 7.908 1.426 20.873-0.389 4.926-3.824 5.834-2.398 12.64 1.103 5.121 2.27 4.991 4.214 7.325 5.315 6.223 4.084 1.686 34.355 7.777 16.011 3.242 20.938 9.271 37.596 7.779 5.575-0.518 6.612-0.453 11.279-4.926 5.964-5.575 2.917-4.408 3.565-7.973 2.269-11.863 0.453-13.938-8.428-28.004-8.88-14.066-8.102-14.844-13.936-24.113-5.834-9.141-13.872-25.799-20.549-25.93-5.25-0.129-8.297 2.723-11.603 6.094-3.305 3.372-5.768 19.643-10.629 24.827z"/>
- <path fill="#ffcc02" d="m57.995 285.094c-4.461 4.701-18.604-1.196-25.06 3.705-4.701 3.514 2.578 8.05 1.608 20.68-0.4 4.896-3.733 5.877-2.458 12.634 0.986 5.093 2.357 4.938 4.334 7.201 5.686 6.131 4.673 1.826 34.119 7.743 15.918 3.211 20.815 9.215 37.372 7.732 5.541-0.513 6.479-0.463 11.155-4.849 5.865-5.407 2.858-4.287 3.412-8.058 2.066-11.787 0.442-13.981-8.188-27.649-8.83-13.983-8.143-14.698-13.941-23.913-5.8-9.085-13.701-25.805-20.338-25.934-5.219-0.129-8.248 2.705-11.533 6.057-3.287 3.352-5.644 19.505-10.482 24.651z"/>
- <path fill="#ffcc05" d="m58.289 285.185c-4.644 4.866-18.93-1.031-25.229 3.78-4.669 3.527 2.759 8.191 1.792 20.488-0.413 4.866-3.642 5.918-2.519 12.625 0.872 5.066 2.447 4.887 4.455 7.078 6.057 6.04 5.263 1.969 33.883 7.709 15.825 3.18 20.693 9.159 37.148 7.686 5.508-0.506 6.345-0.471 11.03-4.77 5.768-5.24 2.803-4.168 3.26-8.142 1.865-11.716 0.432-14.027-7.949-27.298-8.78-13.899-8.183-14.553-13.948-23.713-5.764-9.03-13.529-25.811-20.126-25.938-5.188-0.129-8.198 2.688-11.465 6.021-3.266 3.331-5.517 19.368-10.332 24.474z"/>
- <path fill="#ffcc07" d="m58.584 285.276c-4.827 5.03-19.255-0.865-25.397 3.855-4.639 3.541 2.938 8.332 1.975 20.295-0.425 4.838-3.551 5.961-2.578 12.619 0.757 5.039 2.536 4.834 4.575 6.955 6.428 5.949 5.852 2.108 33.646 7.674 15.733 3.147 20.571 9.103 36.925 7.639 5.475-0.501 6.211-0.48 10.905-4.693 5.67-5.072 2.745-4.045 3.107-8.224 1.663-11.642 0.42-14.073-7.711-26.946-8.73-13.814-8.223-14.406-13.952-23.511-5.729-8.976-13.358-25.817-19.916-25.944-5.156-0.127-8.148 2.674-11.396 5.984s-5.391 19.229-10.183 24.297z"/>
- <path fill="#ffcd0a" d="m58.878 285.368c-5.01 5.193-19.579-0.701-25.565 3.93-4.607 3.555 3.117 8.475 2.157 20.102-0.437 4.809-3.459 6.004-2.639 12.613 0.643 5.011 2.626 4.781 4.695 6.83 6.799 5.857 6.442 2.25 33.411 7.64 15.641 3.118 20.45 9.048 36.701 7.593 5.44-0.494 6.076-0.488 10.781-4.615 5.57-4.904 2.688-3.926 2.954-8.308 1.462-11.569 0.409-14.118-7.472-26.593-8.68-13.732-8.263-14.262-13.958-23.311-5.695-8.922-13.188-25.824-19.705-25.951-5.125-0.127-8.1 2.658-11.326 5.949-3.227 3.289-5.266 19.091-10.034 24.121z"/>
- <path fill="#ffcd0c" d="m59.173 285.458c-5.193 5.358-19.905-0.535-25.734 4.008-4.577 3.566 3.297 8.613 2.34 19.908-0.449 4.778-3.368 6.045-2.698 12.605 0.526 4.982 2.715 4.729 4.815 6.707 7.17 5.766 7.031 2.391 33.175 7.604 15.549 3.088 20.328 8.994 36.477 7.547 5.408-0.488 5.943-0.498 10.657-4.537 5.472-4.737 2.63-3.805 2.802-8.393 1.261-11.494 0.398-14.162-7.232-26.24-8.63-13.647-8.304-14.117-13.964-23.109-5.66-8.867-13.017-25.829-19.494-25.956-5.094-0.126-8.05 2.642-11.257 5.912-3.21 3.27-5.142 18.955-9.887 23.944z"/>
- <path fill="#ffcd0f" d="m59.467 285.547c-5.376 5.523-20.229-0.369-25.903 4.084-4.545 3.58 3.478 8.756 2.523 19.715-0.461 4.75-3.277 6.088-2.758 12.599 0.411 4.955 2.804 4.677 4.936 6.584 7.541 5.675 7.621 2.532 32.938 7.569 15.456 3.056 20.206 8.938 36.253 7.5 5.375-0.482 5.811-0.506 10.533-4.459 5.374-4.57 2.572-3.686 2.649-8.477 1.058-11.42 0.387-14.209-6.995-25.888-8.58-13.563-8.344-13.972-13.969-22.909-5.626-8.813-12.846-25.834-19.283-25.961-5.063-0.125-8 2.625-11.188 5.877-3.188 3.251-5.015 18.818-9.736 23.766z"/>
- <path fill="#ffcd11" d="m59.76 285.639c-5.559 5.688-20.555-0.205-26.071 4.158-4.515 3.594 3.657 8.896 2.706 19.521-0.473 4.721-3.186 6.131-2.818 12.594 0.297 4.926 2.894 4.623 5.057 6.459 7.911 5.584 8.21 2.674 32.703 7.535 15.362 3.025 20.084 8.883 36.027 7.453 5.342-0.477 5.677-0.515 10.409-4.381 5.275-4.402 2.516-3.564 2.497-8.561 0.855-11.348 0.375-14.254-6.756-25.535-8.53-13.479-8.385-13.825-13.976-22.709-5.59-8.758-12.673-25.842-19.071-25.965-5.031-0.125-7.951 2.608-11.119 5.838-3.168 3.232-4.888 18.684-9.588 23.593z"/>
- <path fill="#ffce14" d="m60.055 285.73c-5.742 5.851-20.88-0.04-26.24 4.233-4.483 3.607 3.837 9.039 2.889 19.33-0.485 4.69-3.095 6.172-2.878 12.584 0.182 4.9 2.982 4.572 5.177 6.338 8.282 5.492 8.8 2.814 32.467 7.498 15.271 2.996 19.962 8.828 35.804 7.408 5.309-0.472 5.543-0.523 10.285-4.304 5.177-4.235 2.458-3.444 2.344-8.644 0.654-11.273 0.364-14.299-6.518-25.184-8.479-13.395-8.425-13.679-13.98-22.507-5.556-8.704-12.502-25.849-18.86-25.972-5-0.123-7.901 2.593-11.05 5.803s-4.765 18.547-9.44 23.417z"/>
- <path fill="#ffce16" d="m60.349 285.821c-5.925 6.016-21.205 0.125-26.408 4.309-4.453 3.621 4.017 9.18 3.07 19.137-0.496 4.662-3.002 6.215-2.938 12.579 0.066 4.872 3.072 4.518 5.298 6.213 8.653 5.401 9.389 2.956 32.23 7.464 15.178 2.964 19.84 8.771 35.58 7.361 5.275-0.465 5.409-0.532 10.159-4.225 5.079-4.068 2.401-3.324 2.192-8.729 0.452-11.2 0.354-14.346-6.279-24.831-8.429-13.312-8.464-13.534-13.985-22.306-5.521-8.65-12.331-25.854-18.649-25.978-4.969-0.123-7.853 2.577-10.98 5.767-3.129 3.19-4.637 18.409-9.29 23.239z"/>
- <path fill="#ffce19" d="m60.643 285.911c-6.107 6.18-21.529 0.291-26.577 4.385-4.421 3.635 4.197 9.322 3.254 18.945-0.508 4.631-2.911 6.256-2.997 12.571-0.049 4.845 3.161 4.465 5.418 6.089 9.023 5.309 9.979 3.098 31.994 7.43 15.085 2.934 19.718 8.717 35.355 7.314 5.242-0.459 5.276-0.541 10.036-4.148 4.98-3.899 2.344-3.203 2.039-8.811 0.25-11.127 0.342-14.391-6.04-24.479-8.38-13.228-8.505-13.389-13.991-22.105-5.486-8.596-12.16-25.859-18.438-25.982-4.938-0.123-7.803 2.561-10.911 5.73-3.109 3.17-4.513 18.272-9.142 23.061z"/>
- <path fill="#ffce1c" d="m60.938 286.002c-6.291 6.344-21.855 0.455-26.746 4.459-4.391 3.648 4.377 9.463 3.437 18.752-0.521 4.603-2.82 6.299-3.058 12.564-0.163 4.817 3.251 4.413 5.539 5.965 9.395 5.219 10.567 3.24 31.758 7.396 14.993 2.903 19.597 8.661 35.132 7.269 5.209-0.453 5.143-0.55 9.912-4.07 4.882-3.732 2.286-3.082 1.887-8.895 0.048-11.053 0.329-14.436-5.802-24.126-8.33-13.144-8.545-13.243-13.997-21.905-5.451-8.541-11.988-25.865-18.228-25.988-4.906-0.121-7.753 2.545-10.843 5.695-3.088 3.149-4.385 18.132-8.991 22.884z"/>
- <path fill="#ffcf1e" d="m61.232 286.092c-6.473 6.51-22.18 0.621-26.914 4.535-4.359 3.662 4.557 9.604 3.619 18.559-0.532 4.574-2.729 6.342-3.117 12.559-0.278 4.789 3.34 4.36 5.659 5.842 9.766 5.127 11.157 3.381 31.521 7.359 14.9 2.872 19.475 8.607 34.908 7.223 5.176-0.447 5.008-0.559 9.787-3.992 4.784-3.565 2.229-2.963 1.735-8.979-0.155-10.98 0.317-14.482-5.564-23.773-8.279-13.061-8.585-13.098-14.002-21.705-5.416-8.485-11.817-25.871-18.017-25.992-4.875-0.121-7.704 2.527-10.773 5.658-3.068 3.128-4.26 17.995-8.842 22.706z"/>
- <path fill="#ffcf21" d="m61.526 286.184c-6.655 6.673-22.505 0.785-27.082 4.611-4.328 3.674 4.736 9.744 3.802 18.365-0.544 4.543-2.638 6.383-3.178 12.551-0.394 4.761 3.43 4.308 5.78 5.718 10.136 5.036 11.746 3.522 31.285 7.325 14.808 2.841 19.353 8.551 34.685 7.176 5.142-0.441 4.875-0.567 9.663-3.914 4.685-3.398 2.171-2.842 1.582-9.063-0.357-10.906 0.307-14.527-5.325-23.422-8.23-12.976-8.625-12.951-14.008-21.503-5.382-8.432-11.646-25.878-17.806-25.999-4.844-0.119-7.654 2.512-10.704 5.622-3.049 3.109-4.134 17.859-8.694 22.533z"/>
- <path fill="#ffcf23" d="m61.821 286.275c-6.839 6.837-22.83 0.95-27.251 4.687-4.298 3.688 4.916 9.886 3.984 18.172-0.557 4.515-2.546 6.426-3.237 12.545-0.509 4.732 3.519 4.255 5.9 5.594 10.507 4.945 12.336 3.663 31.05 7.29 14.715 2.812 19.23 8.496 34.46 7.129 5.108-0.435 4.74-0.575 9.538-3.835 4.587-3.23 2.113-2.723 1.43-9.146-0.559-10.834 0.296-14.572-5.086-23.069-8.18-12.892-8.666-12.806-14.014-21.302-5.347-8.377-11.476-25.885-17.595-26.004-4.813-0.119-7.605 2.496-10.635 5.584-3.029 3.088-4.008 17.722-8.544 22.355z"/>
- <path fill="#ffcf26" d="m62.115 286.366c-7.021 7.002-23.154 1.115-27.42 4.762-4.266 3.701 5.096 10.027 4.168 17.979-0.568 4.486-2.455 6.469-3.297 12.538-0.624 4.706 3.607 4.203 6.021 5.472 10.878 4.852 12.925 3.803 30.813 7.254 14.622 2.78 19.108 8.441 34.236 7.084 5.075-0.43 4.606-0.584 9.413-3.759 4.489-3.063 2.058-2.601 1.277-9.229-0.761-10.76 0.284-14.618-4.848-22.717-8.129-12.809-8.706-12.66-14.019-21.102-5.313-8.322-11.304-25.891-17.384-26.01-4.781-0.118-7.556 2.48-10.566 5.55-3.008 3.068-3.881 17.584-8.394 22.178z"/>
- <path fill="#ffd028" d="m62.409 286.456c-7.204 7.166-23.479 1.281-27.588 4.838-4.235 3.715 5.275 10.168 4.351 17.787-0.58 4.455-2.364 6.51-3.357 12.53-0.738 4.679 3.697 4.149 6.142 5.347 11.249 4.763 13.515 3.946 30.577 7.221 14.529 2.748 18.986 8.386 34.012 7.037 5.043-0.424 4.474-0.594 9.289-3.68 4.392-2.897 2-2.481 1.125-9.314-0.963-10.686 0.273-14.664-4.608-22.364-8.079-12.726-8.746-12.517-14.024-20.901-5.277-8.269-11.133-25.896-17.173-26.015-4.75-0.116-7.506 2.464-10.497 5.513-2.992 3.047-3.759 17.447-8.249 22.001z"/>
- <path fill="#ffd02b" d="m62.704 286.547c-7.388 7.33-23.805 1.445-27.757 4.912-4.204 3.729 5.455 10.311 4.533 17.594-0.593 4.427-2.272 6.553-3.417 12.523-0.854 4.651 3.786 4.098 6.262 5.225 11.619 4.671 14.104 4.087 30.341 7.185 14.438 2.72 18.864 8.33 33.787 6.991 5.01-0.418 4.341-0.604 9.166-3.604 4.292-2.729 1.942-2.359 0.972-9.396-1.163-10.613 0.263-14.709-4.369-22.012-8.03-12.641-8.787-12.371-14.03-20.7-5.243-8.214-10.962-25.903-16.962-26.021-4.719-0.117-7.457 2.447-10.428 5.477-2.972 3.029-3.632 17.313-8.098 21.826z"/>
- <path fill="#ffd02d" d="m62.998 286.638c-7.57 7.493-24.13 1.61-27.925 4.987-4.174 3.742 5.635 10.451 4.716 17.4-0.604 4.398-2.182 6.596-3.478 12.518-0.969 4.623 3.875 4.045 6.382 5.101 11.991 4.579 14.694 4.228 30.105 7.149 14.345 2.688 18.743 8.275 33.563 6.944 4.977-0.411 4.207-0.61 9.042-3.524 4.193-2.562 1.884-2.239 0.819-9.481-1.366-10.538 0.251-14.754-4.133-21.659-7.979-12.557-8.825-12.224-14.034-20.498-5.208-8.16-10.791-25.91-16.751-26.027-4.688-0.114-7.407 2.433-10.358 5.441-2.951 3.01-3.505 17.174-7.948 21.649z"/>
- <path fill="#ffd030" d="m63.292 286.729c-7.753 7.658-24.454 1.775-28.094 5.063-4.142 3.756 5.815 10.594 4.899 17.209-0.616 4.367-2.09 6.638-3.537 12.51-1.084 4.596 3.964 3.992 6.502 4.977 12.362 4.488 15.283 4.369 29.869 7.115 14.252 2.656 18.621 8.22 33.34 6.898 4.943-0.406 4.073-0.621 8.917-3.447 4.095-2.395 1.828-2.119 0.667-9.565-1.568-10.465 0.239-14.8-3.894-21.307-7.929-12.474-8.866-12.078-14.04-20.298-5.173-8.105-10.619-25.916-16.54-26.031-4.656-0.115-7.357 2.415-10.289 5.404-2.932 2.988-3.38 17.036-7.8 21.472z"/>
- <path fill="#ffd133" d="m63.587 286.82c-7.937 7.822-24.78 1.94-28.263 5.138-4.111 3.77 5.995 10.734 5.081 17.016-0.627 4.339-1.998 6.68-3.597 12.504-1.199 4.568 4.054 3.939 6.623 4.854 12.732 4.396 15.873 4.51 29.633 7.08 14.16 2.625 18.499 8.164 33.116 6.852 4.909-0.4 3.939-0.629 8.793-3.369 3.997-2.227 1.77-1.999 0.514-9.648-1.771-10.393 0.228-14.846-3.654-20.955-7.88-12.39-8.907-11.934-14.046-20.098-5.139-8.051-10.448-25.922-16.329-26.037-4.625-0.113-7.309 2.398-10.221 5.368s-3.254 16.897-7.65 21.295z"/>
- </g>
- <g transform="translate(-12.4048,10.0005)">
- <path d="m88.782 218.681c-0.936 2.088-1.728 20.017 2.952 27 4.68 6.911 3.312 10.872-1.872 5.616-5.4-5.112-8.928-12.816-9-18.145 0-3.096 2.376-15.84 3.313-17.208 1.007-1.44 5.327 1.153 4.607 2.737z"/>
- <path fill="#030303" d="m88.692 219.032c-0.903 2.34-1.656 19.698 3.01 26.668 4.665 6.901 3.186 10.49-1.84 5.356-5.23-4.997-8.607-12.47-8.741-17.787-0.043-3.114 2.236-15.419 3.133-16.791 0.961-1.394 5.126 0.989 4.438 2.554z"/>
- <path fill="#070707" d="m88.602 219.379c-0.871 2.593-1.584 19.383 3.067 26.338 4.65 6.891 3.06 10.109-1.808 5.098-5.062-4.882-8.287-12.125-8.481-17.432-0.087-3.131 2.095-14.998 2.952-16.373 0.915-1.345 4.926 0.828 4.27 2.369z"/>
- <path fill="#0b0b0b" d="m88.512 219.729c-0.839 2.844-1.513 19.066 3.124 26.006 4.638 6.881 2.935 9.729-1.774 4.84-4.893-4.768-7.967-11.779-8.223-17.076-0.129-3.149 1.955-14.576 2.772-15.955 0.868-1.299 4.724 0.665 4.101 2.185z"/>
- <path fill="#0f0f0f" d="m88.422 220.079c-0.806 3.096-1.439 18.748 3.183 25.674 4.623 6.869 2.809 9.347-1.742 4.58-4.724-4.651-7.646-11.434-7.963-16.719-0.173-3.168 1.814-14.154 2.592-15.537 0.819-1.252 4.52 0.504 3.93 2.002z"/>
- <path fill="#131313" d="m88.332 220.426c-0.773 3.349-1.368 18.433 3.24 25.345 4.608 6.858 2.682 8.964-1.71 4.319-4.554-4.535-7.326-11.088-7.704-16.361-0.216-3.186 1.674-13.734 2.412-15.12 0.774-1.206 4.32 0.343 3.762 1.817z"/>
- <path fill="#161616" d="m88.242 220.777c-0.741 3.601-1.296 18.115 3.298 25.013 4.594 6.848 2.556 8.582-1.678 4.061-4.385-4.421-7.006-10.742-7.444-16.006-0.26-3.203 1.533-13.313 2.231-14.702 0.728-1.16 4.118 0.18 3.593 1.634z"/>
- <path fill="#1a1a1a" d="m88.152 221.125c-0.709 3.853-1.224 17.799 3.355 24.682 4.579 6.837 2.43 8.201-1.646 3.802-4.216-4.306-6.686-10.397-7.186-15.649-0.303-3.221 1.394-12.892 2.052-14.285 0.682-1.112 3.918 0.018 3.425 1.45z"/>
- <path fill="#1e1e1e" d="m88.062 221.475c-0.677 4.104-1.152 17.482 3.413 24.35 4.564 6.826 2.304 7.82-1.613 3.543-4.046-4.191-6.365-10.051-6.927-15.293-0.345-3.24 1.253-12.47 1.872-13.867 0.634-1.066 3.716-0.144 3.255 1.267z"/>
- <path fill="#222" d="m87.972 221.825c-0.645 4.355-1.08 17.164 3.47 24.018 4.551 6.816 2.179 7.439-1.58 3.285-3.877-4.076-6.044-9.707-6.667-14.938-0.389-3.258 1.112-12.049 1.691-13.449 0.587-1.019 3.514-0.306 3.086 1.084z"/>
- <path fill="#262626" d="m87.883 222.172c-0.612 4.609-1.009 16.849 3.527 23.688 4.536 6.804 2.052 7.056-1.548 3.024-3.708-3.961-5.724-9.36-6.408-14.58-0.432-3.276 0.973-11.629 1.513-13.032 0.54-0.971 3.311-0.467 2.916 0.9z"/>
- <path fill="#2a2a2a" d="m87.792 222.523c-0.579 4.86-0.936 16.531 3.586 23.356 4.521 6.793 1.926 6.675-1.516 2.765-3.539-3.845-5.403-9.015-6.148-14.224-0.476-3.293 0.831-11.207 1.332-12.614 0.493-0.925 3.11-0.63 2.746 0.717z"/>
- <path fill="#2d2d2d" d="m87.702 222.872c-0.547 5.112-0.864 16.215 3.644 23.025 4.507 6.783 1.8 6.293-1.483 2.506-3.369-3.73-5.083-8.669-5.89-13.867-0.519-3.312 0.691-10.785 1.152-12.197 0.446-0.878 2.908-0.792 2.577 0.533z"/>
- <path fill="#313131" d="m87.612 223.221c-0.515 5.363-0.792 15.898 3.701 22.693 4.492 6.772 1.674 5.912-1.451 2.248-3.2-3.615-4.763-8.324-5.63-13.512-0.563-3.33 0.551-10.363 0.972-11.779 0.399-0.831 2.707-0.953 2.408 0.35z"/>
- <path fill="#353535" d="m87.522 223.57c-0.482 5.616-0.72 15.581 3.758 22.363 4.479 6.761 1.549 5.53-1.418 1.987-3.031-3.5-4.442-7.978-5.371-13.154-0.604-3.348 0.41-9.943 0.792-11.361 0.352-0.785 2.506-1.115 2.239 0.165z"/>
- <path fill="#393939" d="m87.432 223.918c-0.45 5.869-0.648 15.265 3.815 22.033 4.464 6.75 1.422 5.147-1.386 1.728-2.862-3.384-4.122-7.632-5.112-12.798-0.647-3.366 0.271-9.522 0.612-10.944 0.307-0.737 2.305-1.278 2.071-0.019z"/>
- <path fill="#3d3d3d" d="m87.343 224.269c-0.418 6.12-0.576 14.946 3.873 21.7 4.45 6.74 1.296 4.767-1.354 1.469-2.692-3.27-3.802-7.286-4.853-12.441-0.691-3.383 0.129-9.101 0.432-10.527 0.26-0.691 2.103-1.44 1.902-0.201z"/>
- <path fill="#414141" d="m87.252 224.618c-0.385 6.373-0.504 14.631 3.932 21.369 4.436 6.729 1.17 4.385-1.321 1.211-2.523-3.154-3.481-6.941-4.594-12.086-0.734-3.402-0.011-8.68 0.252-10.109 0.212-0.644 1.901-1.602 1.731-0.385z"/>
- <path fill="#444" d="m87.162 224.967c-0.353 6.623-0.432 14.314 3.989 21.037 4.421 6.719 1.044 4.004-1.289 0.951-2.354-3.039-3.161-6.595-4.334-11.729-0.778-3.42-0.151-8.258 0.071-9.691 0.166-0.597 1.7-1.763 1.563-0.568z"/>
- <path fill="#484848" d="m87.072 225.316c-0.32 6.876-0.36 13.997 4.047 20.707 4.406 6.707 0.918 3.622-1.257 0.692-2.186-2.924-2.841-6.25-4.075-11.373-0.82-3.438-0.292-7.838-0.108-9.273 0.119-0.551 1.498-1.926 1.393-0.753z"/>
- <path fill="#4c4c4c" d="m86.982 225.665c-0.288 7.129-0.288 13.68 4.104 20.377 4.393 6.695 0.792 3.24-1.224 0.432s-2.52-5.904-3.816-11.016c-0.863-3.457-0.432-7.416-0.287-8.856 0.071-0.505 1.295-2.089 1.223-0.937z"/>
- </g>
- <g transform="translate(-12.4048,10.0005)">
- <path d="m88.782 218.681c4.32-9.433 6.696-19.584 12.888-29.448 6.12-9.792 3.672-13.608-0.863-8.64-4.536 4.968-9.504 15.48-9.504 15.48s-5.832 9.216-7.128 19.872c-0.217 1.8 3.887 4.248 4.607 2.736z"/>
- <path fill="#020202" d="m88.968 218.071c4.279-9.5 6.615-19.246 12.586-28.802 5.901-9.488 3.608-13.279-0.764-8.472-4.403 4.847-9.302 15.236-9.368 15.381 0 0-5.637 8.993-6.877 19.239-0.209 1.771 3.72 4.145 4.423 2.654z"/>
- <path fill="#050505" d="m89.152 217.459c4.239-9.566 6.535-18.908 12.284-28.155 5.683-9.183 3.547-12.95-0.663-8.303-4.27 4.725-9.099 14.991-9.231 15.282 0 0-5.442 8.766-6.627 18.605-0.201 1.741 3.554 4.042 4.237 2.571z"/>
- <path fill="#070707" d="m89.338 216.849c4.199-9.634 6.454-18.572 11.981-27.51 5.465-8.878 3.484-12.621-0.563-8.135-4.137 4.605-8.896 14.748-9.096 15.184 0 0-5.247 8.542-6.376 17.972-0.192 1.713 3.387 3.937 4.054 2.489z"/>
- <path fill="#0a0a0a" d="m89.522 216.239c4.159-9.701 6.375-18.234 11.68-26.865 5.247-8.573 3.422-12.292-0.461-7.966-4.005 4.483-8.693 14.503-8.96 15.085 0 0-5.053 8.317-6.126 17.337-0.186 1.684 3.219 3.837 3.867 2.409z"/>
- <path fill="#0c0c0c" d="m89.708 215.627c4.118-9.769 6.294-17.897 11.376-26.218 5.029-8.268 3.36-11.962-0.359-7.797-3.871 4.361-8.49 14.259-8.823 14.985 0 0-4.858 8.093-5.876 16.706-0.179 1.653 3.051 3.731 3.682 2.324z"/>
- <path fill="#0f0f0f" d="m89.893 215.017c4.077-9.836 6.213-17.56 11.073-25.573 4.812-7.963 3.298-11.633-0.259-7.629-3.738 4.241-8.288 14.015-8.688 14.887 0 0-4.663 7.868-5.625 16.072-0.169 1.624 2.886 3.628 3.499 2.243z"/>
- <path fill="#111" d="m90.078 214.407c4.037-9.904 6.133-17.224 10.772-24.928 4.593-7.658 3.234-11.304-0.159-7.46-3.605 4.119-8.085 13.771-8.551 14.788 0 0-4.47 7.645-5.375 15.439-0.162 1.594 2.718 3.524 3.313 2.161z"/>
- <path fill="#141414" d="m90.263 213.795c3.997-9.971 6.052-16.885 10.47-24.281 4.374-7.353 3.172-10.975-0.059-7.291-3.472 3.998-7.882 13.526-8.415 14.689 0 0-4.273 7.418-5.124 14.805-0.154 1.565 2.551 3.421 3.128 2.078z"/>
- <path fill="#161616" d="m90.449 213.184c3.956-10.037 5.972-16.548 10.167-23.635 4.156-7.048 3.11-10.645 0.043-7.123-3.34 3.877-7.68 13.283-8.279 14.591 0 0-4.08 7.194-4.874 14.172-0.147 1.535 2.383 3.317 2.943 1.995z"/>
- <path fill="#191919" d="m90.634 212.573c3.916-10.105 5.892-16.209 9.865-22.989 3.938-6.743 3.047-10.316 0.144-6.954-3.207 3.755-7.477 13.038-8.143 14.491 0 0-3.886 6.969-4.624 13.54-0.139 1.506 2.217 3.213 2.758 1.912z"/>
- <path fill="#1c1c1c" d="m90.819 211.963c3.875-10.174 5.811-15.874 9.563-22.344 3.721-6.438 2.984-9.987 0.244-6.785-3.073 3.634-7.274 12.793-8.007 14.392 0 0-3.69 6.745-4.373 12.905-0.131 1.477 2.049 3.112 2.573 1.832z"/>
- <path fill="#1e1e1e" d="m91.004 211.352c3.836-10.24 5.73-15.536 9.262-21.698 3.501-6.133 2.922-9.658 0.344-6.617-2.94 3.513-7.071 12.55-7.87 14.293 0 0-3.496 6.521-4.123 12.272-0.124 1.447 1.881 3.009 2.387 1.75z"/>
- <path fill="#212121" d="m91.189 210.741c3.795-10.307 5.649-15.198 8.958-21.052 3.284-5.828 2.859-9.328 0.445-6.448-2.808 3.392-6.868 12.305-7.734 14.195 0 0-3.301 6.295-3.872 11.639-0.115 1.418 1.715 2.904 2.203 1.666z"/>
- <path fill="#232323" d="m91.375 210.129c3.754-10.373 5.569-14.86 8.655-20.405 3.066-5.523 2.797-8.999 0.547-6.279-2.675 3.27-6.666 12.061-7.599 14.097 0 0-3.106 6.07-3.622 11.004-0.107 1.388 1.548 2.801 2.019 1.583z"/>
- <path fill="#262626" d="m91.559 209.519c3.714-10.44 5.489-14.523 8.354-19.76 2.847-5.218 2.735-8.67 0.647-6.111-2.542 3.149-6.463 11.817-7.462 13.997 0 0-2.912 5.848-3.372 10.373-0.099 1.357 1.381 2.697 1.833 1.501z"/>
- <path fill="#282828" d="m91.745 208.909c3.674-10.509 5.408-14.187 8.051-19.115 2.629-4.913 2.672-8.341 0.748-5.942-2.409 3.028-6.261 11.573-7.326 13.898 0 0-2.717 5.621-3.121 9.738-0.092 1.33 1.213 2.595 1.648 1.421z"/>
- <path fill="#2b2b2b" d="m91.929 208.297c3.634-10.575 5.328-13.848 7.75-18.468 2.41-4.608 2.609-8.011 0.848-5.773-2.275 2.906-6.058 11.328-7.189 13.799 0 0-2.522 5.397-2.871 9.106-0.084 1.299 1.046 2.491 1.462 1.336z"/>
- <path fill="#2d2d2d" d="m92.115 207.687c3.593-10.643 5.247-13.512 7.447-17.823 2.191-4.303 2.547-7.682 0.949-5.605-2.144 2.786-5.855 11.085-7.055 13.701 0 0-2.327 5.172-2.62 8.473-0.076 1.269 0.881 2.386 1.279 1.254z"/>
- <path fill="#303030" d="m92.301 207.077c3.552-10.71 5.167-13.175 7.145-17.178 1.974-3.998 2.484-7.353 1.05-5.436-2.011 2.664-5.652 10.84-6.918 13.602 0 0-2.133 4.947-2.37 7.839-0.07 1.24 0.712 2.283 1.093 1.173z"/>
- <path fill="#333" d="m92.485 206.465c3.513-10.778 5.087-12.837 6.843-16.531s2.422-7.024 1.15-5.268c-1.877 2.543-5.449 10.596-6.781 13.502 0 0-1.938 4.724-2.12 7.207-0.061 1.211 0.545 2.18 0.908 1.09z"/>
- </g>
- <g transform="translate(-12.4048,10.0005)">
- <path d="m273.03 225.592c2.088-5.903 1.872-20.951-3.456-30.671-1.872-3.528-3.672-7.632-4.752-7.848-1.152-0.216-3.24 2.088-3.024 2.448 0.288 0.576 10.009 14.256 7.992 32.832-0.144 1.513 2.736 4.608 3.24 3.239z"/>
- <path fill="#030303" d="m272.936 224.831c2.025-5.719 1.753-20.379-3.344-29.663-1.815-3.407-3.535-7.374-4.595-7.59-1.122-0.214-3.125 2.022-2.925 2.367 0.258 0.562 9.605 13.778 7.729 31.753-0.129 1.487 2.647 4.456 3.135 3.133z"/>
- <path fill="#070707" d="m272.841 224.068c1.967-5.532 1.637-19.808-3.228-28.654-1.762-3.286-3.401-7.115-4.44-7.332-1.091-0.211-3.009 1.956-2.824 2.287 0.227 0.548 9.201 13.299 7.466 30.672-0.118 1.463 2.555 4.305 3.026 3.027z"/>
- <path fill="#0b0b0b" d="m272.747 223.305c1.904-5.348 1.518-19.235-3.115-27.645-1.706-3.165-3.265-6.856-4.282-7.073-1.062-0.21-2.896 1.889-2.727 2.206 0.197 0.534 8.799 12.821 7.203 29.592-0.103 1.44 2.466 4.153 2.921 2.92z"/>
- <path fill="#0f0f0f" d="m272.652 222.542c1.843-5.162 1.398-18.662-3.001-26.635-1.65-3.044-3.13-6.598-4.127-6.815-1.03-0.207-2.779 1.823-2.626 2.126 0.167 0.52 8.396 12.341 6.94 28.511-0.09 1.416 2.376 4.001 2.814 2.813z"/>
- <path fill="#131313" d="m272.558 221.779c1.78-4.976 1.279-18.09-2.889-25.626-1.595-2.923-2.994-6.34-3.97-6.557-1-0.205-2.664 1.756-2.527 2.045 0.137 0.506 7.993 11.861 6.679 27.432-0.078 1.392 2.285 3.849 2.707 2.706z"/>
- <path fill="#161616" d="m272.463 221.016c1.721-4.79 1.163-17.518-2.773-24.617-1.539-2.802-2.858-6.081-3.814-6.299-0.969-0.203-2.548 1.691-2.427 1.965 0.106 0.492 7.59 11.383 6.415 26.352-0.065 1.369 2.194 3.697 2.599 2.599z"/>
- <path fill="#1a1a1a" d="m272.369 220.254c1.659-4.605 1.044-16.946-2.66-23.609-1.483-2.681-2.723-5.822-3.658-6.04-0.938-0.201-2.434 1.624-2.326 1.884 0.074 0.478 7.185 10.904 6.15 25.271-0.051 1.344 2.106 3.546 2.494 2.494z"/>
- <path fill="#1e1e1e" d="m272.274 219.491c1.598-4.42 0.926-16.373-2.546-22.6-1.43-2.56-2.587-5.564-3.501-5.782-0.908-0.198-2.319 1.558-2.229 1.804 0.044 0.464 6.782 10.425 5.889 24.19-0.037 1.321 2.016 3.396 2.387 2.388z"/>
- <path fill="#222" d="m272.18 218.728c1.535-4.233 0.807-15.802-2.434-21.59-1.373-2.439-2.452-5.306-3.345-5.524-0.877-0.197-2.203 1.491-2.128 1.723 0.014 0.45 6.379 9.947 5.625 23.111-0.023 1.297 1.927 3.242 2.282 2.28z"/>
- <path fill="#262626" d="m272.085 217.965c1.476-4.049 0.69-15.229-2.318-20.582-1.317-2.317-2.316-5.046-3.188-5.265-0.847-0.194-2.088 1.425-2.029 1.642-0.016 0.436 5.977 9.468 5.362 22.032-0.011 1.272 1.835 3.089 2.173 2.173z"/>
- <path fill="#2a2a2a" d="m271.991 217.202c1.413-3.861 0.571-14.656-2.206-19.572-1.262-2.196-2.18-4.788-3.032-5.007-0.815-0.191-1.973 1.36-1.929 1.562-0.047 0.422 5.573 8.988 5.099 20.951 0.003 1.247 1.746 2.939 2.068 2.066z"/>
- <path fill="#2d2d2d" d="m271.896 216.439c1.353-3.677 0.453-14.084-2.091-18.563-1.207-2.076-2.045-4.529-2.876-4.749-0.786-0.19-1.858 1.293-1.83 1.481-0.077 0.408 5.17 8.51 4.836 19.87 0.017 1.226 1.656 2.789 1.961 1.961z"/>
- <path fill="#313131" d="m271.802 215.676c1.29-3.491 0.334-13.512-1.979-17.553-1.151-1.956-1.909-4.272-2.72-4.493-0.755-0.187-1.742 1.227-1.73 1.401-0.106 0.394 4.768 8.031 4.573 18.791 0.031 1.202 1.567 2.637 1.856 1.854z"/>
- <path fill="#353535" d="m271.707 214.915c1.23-3.307 0.217-12.94-1.864-16.545-1.096-1.834-1.773-4.014-2.563-4.234-0.725-0.185-1.627 1.16-1.631 1.32-0.138 0.38 4.364 7.552 4.311 17.71 0.042 1.176 1.475 2.485 1.747 1.749z"/>
- <path fill="#393939" d="m271.613 214.151c1.168-3.119 0.098-12.367-1.751-15.535-1.04-1.714-1.638-3.755-2.407-3.976-0.693-0.183-1.512 1.094-1.531 1.24-0.168 0.366 3.962 7.074 4.049 16.63 0.055 1.153 1.384 2.332 1.64 1.641z"/>
- <path fill="#3d3d3d" d="m271.518 213.388c1.106-2.935-0.021-11.796-1.638-14.527-0.983-1.592-1.502-3.496-2.25-3.716-0.664-0.181-1.396 1.028-1.432 1.159-0.198 0.352 3.558 6.594 3.785 15.549 0.07 1.13 1.296 2.183 1.535 1.535z"/>
- <path fill="#414141" d="m271.424 212.625c1.047-2.75-0.139-11.223-1.522-13.518-0.93-1.471-1.367-3.238-2.094-3.459-0.635-0.178-1.282 0.962-1.333 1.079-0.229 0.338 3.153 6.114 3.521 14.47 0.083 1.106 1.205 2.03 1.428 1.428z"/>
- <path fill="#444" d="m271.329 211.862c0.985-2.563-0.256-10.65-1.409-12.508-0.874-1.35-1.23-2.979-1.938-3.2-0.604-0.177-1.166 0.895-1.233 0.998-0.259 0.324 2.751 5.636 3.259 13.39 0.096 1.082 1.115 1.876 1.321 1.32z"/>
- <path fill="#484848" d="m271.235 211.099c0.923-2.377-0.375-10.077-1.296-11.499-0.818-1.229-1.097-2.72-1.781-2.942-0.573-0.174-1.052 0.829-1.134 0.918-0.289 0.309 2.348 5.156 2.996 12.309 0.11 1.058 1.025 1.726 1.215 1.214z"/>
- <path fill="#4c4c4c" d="m271.14 210.336c0.861-2.192-0.493-9.506-1.183-10.49-0.763-1.107-0.96-2.463-1.625-2.684-0.542-0.172-0.936 0.762-1.034 0.836-0.319 0.297 1.945 4.68 2.733 11.229 0.124 1.035 0.936 1.576 1.109 1.109z"/>
- </g>
- <g transform="translate(-12.4048,10.0005)">
- <path d="m264.822 187.073c-10.224-13.968-23.472-18.504-22.104-14.112 0 0 10.152 5.76 19.08 16.56 1.728 2.088 4.608-0.288 3.024-2.448z"/>
- <path fill="#030303" d="m264.372 186.687c-9.924-13.495-22.894-17.912-21.539-13.7 0.018 0.012 9.901 5.614 18.609 16.071 1.678 2.016 4.467-0.285 2.93-2.371z"/>
- <path fill="#070707" d="m263.922 186.3c-9.624-13.022-22.316-17.319-20.975-13.287 0.036 0.023 9.652 5.467 18.139 15.582 1.628 1.943 4.325-0.283 2.836-2.295z"/>
- <path fill="#0b0b0b" d="m263.472 185.913c-9.324-12.549-21.739-16.726-20.41-12.874 0.053 0.034 9.4 5.32 17.668 15.093 1.578 1.871 4.183-0.28 2.742-2.219z"/>
- <path fill="#0f0f0f" d="m263.022 185.527c-9.024-12.077-21.162-16.134-19.847-12.462 0.071 0.045 9.151 5.174 17.198 14.604 1.529 1.798 4.043-0.278 2.649-2.142z"/>
- <path fill="#131313" d="m262.571 185.14c-8.723-11.603-20.583-15.541-19.28-12.049 0.088 0.056 8.901 5.027 16.728 14.114 1.477 1.726 3.899-0.275 2.552-2.065z"/>
- <path fill="#161616" d="m262.121 184.753c-8.423-11.13-20.006-14.948-18.716-11.636 0.106 0.067 8.651 4.88 16.257 13.625 1.428 1.654 3.759-0.272 2.459-1.989z"/>
- <path fill="#1a1a1a" d="m261.671 184.367c-8.124-10.658-19.428-14.356-18.15-11.224 0.124 0.078 8.399 4.734 15.785 13.136 1.378 1.581 3.617-0.27 2.365-1.912z"/>
- <path fill="#1e1e1e" d="m261.221 183.98c-7.824-10.185-18.851-13.763-17.588-10.811 0.143 0.089 8.151 4.587 15.315 12.647 1.33 1.508 3.477-0.267 2.273-1.836z"/>
- <path fill="#222" d="m260.771 183.593c-7.524-9.711-18.273-13.17-17.022-10.398 0.159 0.1 7.9 4.44 14.844 12.158 1.279 1.436 3.335-0.265 2.178-1.76z"/>
- <path fill="#262626" d="m260.321 183.206c-7.224-9.238-17.695-12.578-16.458-9.985 0.177 0.111 7.65 4.293 14.374 11.668 1.229 1.364 3.193-0.262 2.084-1.683z"/>
- <path fill="#2a2a2a" d="m259.871 182.82c-6.924-8.766-17.118-11.986-15.893-9.573 0.193 0.122 7.398 4.147 13.902 11.179 1.18 1.291 3.053-0.259 1.991-1.606z"/>
- <path fill="#2d2d2d" d="m259.42 182.433c-6.623-8.293-16.539-11.393-15.328-9.16 0.214 0.133 7.15 4 13.434 10.69 1.128 1.219 2.909-0.257 1.894-1.53z"/>
- <path fill="#313131" d="m258.97 182.046c-6.323-7.819-15.963-10.8-14.764-8.747 0.23 0.144 6.899 3.853 12.962 10.201 1.08 1.146 2.769-0.254 1.802-1.454z"/>
- <path fill="#353535" d="m258.52 181.66c-6.023-7.347-15.384-10.208-14.199-8.335 0.248 0.155 6.649 3.707 12.492 9.712 1.028 1.073 2.627-0.252 1.707-1.377z"/>
- <path fill="#393939" d="m258.07 181.273c-5.723-6.874-14.807-9.615-13.634-7.922 0.265 0.166 6.398 3.56 12.021 9.222 0.978 1.002 2.485-0.249 1.613-1.3z"/>
- <path fill="#3d3d3d" d="m257.62 180.886c-5.423-6.401-14.229-9.021-13.07-7.509 0.283 0.177 6.149 3.413 11.552 8.733 0.927 0.929 2.343-0.246 1.518-1.224z"/>
- <path fill="#414141" d="m257.17 180.5c-5.124-5.928-13.65-8.43-12.505-7.097 0.301 0.188 5.898 3.267 11.079 8.244 0.879 0.856 2.203-0.244 1.426-1.147z"/>
- <path fill="#444" d="m256.719 180.113c-4.823-5.455-13.073-7.837-11.94-6.684 0.319 0.199 5.649 3.12 10.609 7.755 0.829 0.784 2.061-0.241 1.331-1.071z"/>
- <path fill="#484848" d="m256.269 179.726c-4.523-4.982-12.495-7.244-11.375-6.271 0.336 0.21 5.397 2.973 10.138 7.266 0.779 0.711 1.92-0.239 1.237-0.995z"/>
- <path fill="#4c4c4c" d="m255.819 179.339c-4.223-4.509-11.918-6.652-10.812-5.859 0.354 0.222 5.148 2.827 9.668 6.777 0.73 0.639 1.779-0.236 1.144-0.918z"/>
- </g>
- <g transform="translate(-12.4048,10.0005)">
- <path d="m273.03 225.592c0.144 6.265-5.76 22.248-7.992 21.673-2.52-0.576 0.504-5.257 2.809-13.177 0.936-3.312 1.655-11.447 1.943-11.735 0.936-0.936 3.24 1.728 3.24 3.239z"/>
- <path fill="#050505" d="m272.846 226.116c0.103 6.082-5.638 21.594-7.797 21.018-2.422-0.567 0.548-5.146 2.814-12.928 0.899-3.178 1.595-10.947 1.887-11.25 0.914-0.927 3.147 1.527 3.096 3.16z"/>
- <path fill="#0a0a0a" d="m272.662 226.637c0.063 5.902-5.514 20.939-7.601 20.363-2.323-0.558 0.592-5.035 2.82-12.681 0.861-3.041 1.534-10.446 1.83-10.761 0.89-0.917 3.054 1.327 2.951 3.079z"/>
- <path fill="#0f0f0f" d="m272.478 227.159c0.021 5.721-5.392 20.284-7.405 19.711-2.224-0.55 0.635-4.927 2.827-12.434 0.824-2.907 1.473-9.945 1.773-10.273 0.866-0.911 2.959 1.125 2.805 2.996z"/>
- <path fill="#141414" d="m272.294 227.68c-0.02 5.539-5.268 19.63-7.21 19.057-2.125-0.541 0.68-4.816 2.835-12.186 0.786-2.771 1.412-9.445 1.717-9.786 0.84-0.901 2.863 0.924 2.658 2.915z"/>
- <path fill="#191919" d="m272.11 228.202c-0.063 5.359-5.146 18.977-7.014 18.403-2.027-0.532 0.722-4.706 2.841-11.938 0.748-2.637 1.351-8.944 1.659-9.299 0.818-0.893 2.77 0.722 2.514 2.834z"/>
- <path fill="#1e1e1e" d="m271.926 228.723c-0.103 5.179-5.021 18.322-6.818 17.75-1.928-0.523 0.766-4.596 2.848-11.691 0.711-2.5 1.29-8.443 1.603-8.811 0.792-0.885 2.674 0.522 2.367 2.752z"/>
- <path fill="#232323" d="m271.742 229.245c-0.144 4.998-4.9 17.668-6.623 17.096-1.83-0.514 0.811-4.485 2.854-11.442 0.673-2.366 1.229-7.944 1.545-8.325 0.771-0.876 2.583 0.32 2.224 2.671z"/>
- <path fill="#282828" d="m271.558 229.766c-0.186 4.816-4.777 17.013-6.428 16.443-1.731-0.506 0.854-4.377 2.86-11.196 0.636-2.231 1.168-7.443 1.488-7.837 0.749-0.866 2.49 0.119 2.08 2.59z"/>
- <path fill="#2d2d2d" d="m271.374 230.288c-0.226 4.637-4.653 16.359-6.231 15.789-1.632-0.496 0.896-4.266 2.866-10.947 0.6-2.098 1.107-6.943 1.433-7.351 0.722-0.859 2.393-0.081 1.932 2.509z"/>
- <path fill="#333" d="m271.19 230.809c-0.268 4.456-4.531 15.705-6.036 15.136-1.534-0.489 0.94-4.155 2.873-10.7 0.561-1.961 1.046-6.443 1.375-6.863 0.7-0.848 2.3-0.282 1.788 2.427z"/>
- <path fill="#383838" d="m271.006 231.331c-0.308 4.275-4.407 15.051-5.841 14.482-1.435-0.48 0.984-4.046 2.88-10.453 0.524-1.826 0.985-5.941 1.318-6.375 0.676-0.84 2.206-0.483 1.643 2.346z"/>
- <path fill="#3d3d3d" d="m270.822 231.853c-0.35 4.093-4.285 14.396-5.645 13.828-1.338-0.472 1.027-3.937 2.886-10.206 0.485-1.691 0.924-5.441 1.261-5.887 0.653-0.832 2.113-0.684 1.498 2.265z"/>
- <path fill="#424242" d="m270.638 232.374c-0.392 3.914-4.162 13.742-5.45 13.176-1.238-0.463 1.072-3.826 2.893-9.959 0.449-1.555 0.863-4.94 1.204-5.399 0.629-0.824 2.019-0.886 1.353 2.182z"/>
- <path fill="#474747" d="m270.454 232.896c-0.432 3.731-4.039 13.087-5.254 12.521-1.14-0.453 1.115-3.715 2.9-9.711 0.411-1.42 0.802-4.439 1.146-4.912 0.606-0.815 1.925-1.086 1.208 2.102z"/>
- <path fill="#4c4c4c" d="m270.27 233.417c-0.474 3.553-3.916 12.434-5.06 11.869-1.041-0.445 1.159-3.606 2.907-9.463 0.373-1.287 0.741-3.941 1.089-4.427 0.583-0.806 1.832-1.287 1.064 2.021z"/>
- <path fill="#515151" d="m270.086 233.939c-0.514 3.37-3.793 11.778-4.862 11.214-0.942-0.436 1.201-3.496 2.913-9.216 0.336-1.151 0.68-3.438 1.032-3.938 0.558-0.797 1.736-1.489 0.917 1.94z"/>
- <path fill="#565656" d="m269.902 234.461c-0.555 3.188-3.671 11.123-4.667 10.56-0.844-0.429 1.246-3.386 2.919-8.968 0.298-1.016 0.619-2.939 0.976-3.451 0.535-0.788 1.643-1.689 0.772 1.859z"/>
- <path fill="#5b5b5b" d="m269.718 234.982c-0.597 3.009-3.548 10.47-4.472 9.907-0.745-0.42 1.29-3.275 2.926-8.721 0.262-0.881 0.559-2.438 0.919-2.963 0.511-0.781 1.549-1.89 0.627 1.777z"/>
- <path fill="#606060" d="m269.534 235.504c-0.638 2.828-3.425 9.814-4.276 9.252-0.646-0.409 1.333-3.166 2.933-8.473 0.224-0.746 0.497-1.938 0.862-2.476 0.487-0.769 1.454-2.09 0.481 1.697z"/>
- <path fill="#666" d="m269.35 236.025c-0.68 2.647-3.303 9.161-4.081 8.599-0.548-0.4 1.377-3.056 2.938-8.225 0.187-0.611 0.437-1.438 0.806-1.988 0.464-0.763 1.361-2.293 0.337 1.614z"/>
- </g>
- <g transform="translate(-12.4048,10.0005)">
- <path d="m251.07 187.865c-1.537 1.622-2.903 9.991 0.938 12.893 3.844 2.818 10.59-2.391 10.59-5.379-0.086-6.746-9.991-9.222-11.528-7.514z"/>
- <path fill="#010101" d="m251.207 188.006c-1.559 1.611-2.876 9.823 0.857 12.667 3.731 2.764 10.349-2.273 10.384-5.279-0.047-6.576-9.681-9.083-11.241-7.388z"/>
- <path fill="#030303" d="m251.344 188.146c-1.582 1.601-2.85 9.653 0.774 12.438 3.62 2.709 10.109-2.154 10.178-5.177-0.007-6.404-9.37-8.943-10.952-7.261z"/>
- <path fill="#050505" d="m251.481 188.287c-1.604 1.589-2.823 9.484 0.691 12.211 3.511 2.653 9.869-2.037 9.975-5.078 0.031-6.232-9.061-8.802-10.666-7.133z"/>
- <path fill="#070707" d="m251.617 188.427c-1.626 1.579-2.795 9.316 0.611 11.984 3.397 2.6 9.629-1.918 9.768-4.976 0.071-6.062-8.751-8.664-10.379-7.008z"/>
- <path fill="#090909" d="m251.754 188.567c-1.648 1.568-2.768 9.146 0.529 11.758 3.287 2.543 9.389-1.802 9.563-4.875 0.109-5.892-8.441-8.525-10.092-6.883z"/>
- <path fill="#0b0b0b" d="m251.891 188.708c-1.671 1.557-2.741 8.978 0.445 11.529 3.177 2.489 9.15-1.683 9.358-4.774 0.15-5.72-8.13-8.385-9.803-6.755z"/>
- <path fill="#0d0d0d" d="m252.028 188.848c-1.694 1.546-2.715 8.809 0.364 11.302 3.064 2.435 8.908-1.565 9.152-4.673 0.189-5.549-7.82-8.245-9.516-6.629z"/>
- <path fill="#0f0f0f" d="m252.165 188.989c-1.716 1.535-2.688 8.64 0.282 11.074 2.953 2.38 8.669-1.447 8.948-4.572 0.226-5.378-7.512-8.106-9.23-6.502z"/>
- <path fill="#111" d="m252.301 189.129c-1.737 1.524-2.659 8.471 0.2 10.847 2.844 2.325 8.431-1.33 8.743-4.471 0.266-5.207-7.201-7.966-8.943-6.376z"/>
- <path fill="#131313" d="m252.438 189.269c-1.76 1.514-2.633 8.304 0.118 10.619 2.73 2.271 8.189-1.212 8.538-4.369 0.305-5.036-6.892-7.827-8.656-6.25z"/>
- <path fill="#151515" d="m252.575 189.41c-1.783 1.503-2.606 8.133 0.036 10.391 2.62 2.216 7.949-1.094 8.332-4.268 0.344-4.865-6.581-7.687-8.368-6.123z"/>
- <path fill="#161616" d="m252.712 189.55c-1.805 1.492-2.58 7.965-0.046 10.164 2.508 2.162 7.709-0.975 8.127-4.167 0.383-4.694-6.272-7.548-8.081-5.997z"/>
- <path fill="#181818" d="m252.849 189.691c-1.828 1.481-2.554 7.796-0.129 9.937 2.397 2.105 7.47-0.857 7.922-4.066 0.423-4.524-5.961-7.409-7.793-5.871z"/>
- <path fill="#1a1a1a" d="m252.985 189.831c-1.85 1.47-2.525 7.626-0.21 9.708 2.286 2.053 7.229-0.74 7.717-3.964 0.461-4.352-5.652-7.269-7.507-5.744z"/>
- <path fill="#1c1c1c" d="m253.122 189.971c-1.872 1.46-2.499 7.459-0.292 9.482 2.175 1.996 6.989-0.623 7.511-3.865 0.501-4.18-5.341-7.128-7.219-5.617z"/>
- <path fill="#1e1e1e" d="m253.259 190.112c-1.895 1.448-2.472 7.289-0.375 9.254 2.064 1.942 6.75-0.504 7.308-3.763 0.539-4.01-5.033-6.99-6.933-5.491z"/>
- <path fill="#202020" d="m253.396 190.252c-1.917 1.438-2.445 7.122-0.457 9.027 1.953 1.888 6.51-0.386 7.102-3.662 0.578-3.839-4.722-6.85-6.645-5.365z"/>
- <path fill="#222" d="m253.533 190.393c-1.939 1.426-2.418 6.951-0.539 8.799 1.841 1.832 6.271-0.268 6.896-3.561 0.618-3.668-4.412-6.711-6.357-5.238z"/>
- <path fill="#242424" d="m253.669 190.533c-1.961 1.416-2.391 6.783-0.621 8.572 1.731 1.776 6.03-0.149 6.692-3.46 0.657-3.497-4.102-6.571-6.071-5.112z"/>
- <path fill="#262626" d="m253.806 190.673c-1.984 1.405-2.364 6.615-0.703 8.344 1.619 1.724 5.79-0.032 6.485-3.358 0.697-3.326-3.791-6.432-5.782-4.986z"/>
- </g>
- <g transform="translate(-12.4048,10.0005)">
- <path d="m250.71 256.698c1.513 1.512 2.809-2.232 4.32-3.457 1.512-1.224 3.96-3.888 8.856-3.888s4.535-0.144 4.319-2.017c-0.144-1.799-1.584-1.655-5.903-1.008-4.32 0.576-7.2 2.809-8.929 4.824-1.654 1.945-3.527 4.681-2.663 5.546z"/>
- <path fill="#050505" d="m251.043 256.331c1.459 1.449 2.703-2.121 4.205-3.308 1.501-1.187 3.931-3.731 8.64-3.731 4.71-0.002 4.415-0.129 4.209-1.94-0.139-1.743-1.543-1.593-5.749-0.979-4.207 0.543-7.029 2.703-8.712 4.648-1.616 1.877-3.438 4.474-2.593 5.31z"/>
- <path fill="#0a0a0a" d="m251.376 255.961c1.406 1.389 2.6-2.008 4.089-3.156 1.491-1.148 3.901-3.576 8.425-3.577 4.521-0.001 4.293-0.11 4.096-1.862-0.132-1.688-1.501-1.531-5.594-0.951-4.093 0.51-6.857 2.596-8.495 4.471-1.575 1.812-3.348 4.271-2.521 5.075z"/>
- <path fill="#0f0f0f" d="m251.709 255.594c1.354 1.326 2.494-1.895 3.975-3.008 1.479-1.111 3.871-3.42 8.207-3.422s4.171-0.094 3.984-1.785c-0.126-1.631-1.46-1.467-5.438-0.924-3.979 0.479-6.687 2.492-8.28 4.297-1.533 1.747-3.257 4.066-2.448 4.842z"/>
- <path fill="#141414" d="m252.042 255.226c1.302 1.265 2.39-1.783 3.858-2.856 1.47-1.076 3.842-3.266 7.991-3.268s4.05-0.077 3.873-1.709c-0.119-1.575-1.419-1.404-5.284-0.895-3.865 0.444-6.515 2.385-8.063 4.121-1.49 1.678-3.165 3.861-2.375 4.607z"/>
- <path fill="#191919" d="m252.374 254.859c1.249 1.202 2.285-1.671 3.744-2.708 1.458-1.037 3.813-3.109 7.774-3.111 3.963-0.004 3.929-0.061 3.761-1.633-0.113-1.519-1.377-1.341-5.128-0.867-3.751 0.414-6.344 2.279-7.847 3.945-1.449 1.613-3.075 3.656-2.304 4.374z"/>
- <path fill="#1e1e1e" d="m252.707 254.491c1.196 1.141 2.182-1.559 3.628-2.558 1.448-1 3.783-2.954 7.56-2.957 3.775-0.003 3.806-0.043 3.648-1.556-0.106-1.461-1.336-1.277-4.974-0.838-3.637 0.379-6.172 2.174-7.63 3.77-1.408 1.546-2.984 3.451-2.232 4.139z"/>
- <path fill="#232323" d="m253.04 254.124c1.144 1.078 2.076-1.447 3.514-2.41 1.437-0.961 3.753-2.797 7.342-2.799 3.589-0.004 3.685-0.027 3.537-1.48-0.101-1.405-1.294-1.215-4.818-0.811-3.524 0.349-6.001 2.068-7.415 3.594-1.367 1.48-2.894 3.245-2.16 3.906z"/>
- <path fill="#282828" d="m253.373 253.754c1.09 1.018 1.972-1.334 3.398-2.258 1.426-0.926 3.723-2.642 7.125-2.646 3.402-0.005 3.563-0.011 3.426-1.403-0.095-1.349-1.253-1.15-4.664-0.781-3.409 0.314-5.829 1.961-7.198 3.418-1.325 1.415-2.803 3.041-2.087 3.67z"/>
- <path fill="#2d2d2d" d="m253.706 253.388c1.038 0.954 1.866-1.222 3.282-2.11 1.416-0.887 3.694-2.486 6.909-2.49 3.217-0.004 3.441 0.008 3.313-1.326-0.088-1.293-1.212-1.088-4.508-0.754-3.296 0.283-5.658 1.857-6.981 3.244-1.284 1.345-2.712 2.836-2.015 3.436z"/>
- <path fill="#333" d="m254.039 253.02c0.985 0.893 1.762-1.109 3.167-1.96s3.664-2.33 6.693-2.335c3.029-0.006 3.32 0.023 3.202-1.249-0.082-1.237-1.171-1.024-4.354-0.726-3.182 0.25-5.485 1.75-6.765 3.066-1.243 1.282-2.622 2.634-1.943 3.204z"/>
- <path fill="#383838" d="m254.372 252.652c0.933 0.831 1.657-0.998 3.051-1.81 1.396-0.813 3.636-2.174 6.478-2.18 2.843-0.006 3.199 0.039 3.09-1.172-0.076-1.181-1.129-0.963-4.198-0.697-3.068 0.217-5.314 1.644-6.55 2.891-1.202 1.214-2.531 2.427-1.871 2.968z"/>
- <path fill="#3d3d3d" d="m254.704 252.284c0.88 0.771 1.553-0.885 2.938-1.66 1.383-0.775 3.604-2.019 6.26-2.024 2.656-0.007 3.078 0.058 2.979-1.095-0.069-1.125-1.088-0.899-4.044-0.67-2.954 0.185-5.144 1.539-6.333 2.715-1.16 1.148-2.441 2.222-1.8 2.734z"/>
- <path fill="#424242" d="m255.037 251.917c0.827 0.707 1.448-0.773 2.821-1.51 1.373-0.738 3.576-1.863 6.044-1.871 2.47-0.007 2.956 0.074 2.867-1.018-0.063-1.068-1.046-0.836-3.889-0.641-2.841 0.151-4.973 1.433-6.116 2.539-1.119 1.083-2.35 2.018-1.727 2.501z"/>
- <path fill="#474747" d="m255.37 251.549c0.774 0.645 1.344-0.661 2.706-1.362 1.362-0.7 3.545-1.706 5.828-1.713 2.283-0.009 2.834 0.09 2.754-0.942-0.057-1.012-1.005-0.773-3.733-0.613-2.727 0.119-4.801 1.328-5.899 2.365-1.078 1.013-2.26 1.81-1.656 2.265z"/>
- <path fill="#4c4c4c" d="m255.703 251.181c0.721 0.584 1.239-0.55 2.59-1.212 1.353-0.663 3.517-1.551 5.612-1.559 2.096-0.009 2.713 0.107 2.643-0.865-0.051-0.955-0.964-0.709-3.577-0.584-2.613 0.086-4.631 1.222-5.686 2.188-1.035 0.949-2.168 1.607-1.582 2.032z"/>
- <path fill="#515151" d="m256.036 250.813c0.669 0.521 1.134-0.436 2.476-1.063 1.341-0.625 3.485-1.395 5.395-1.402 1.91-0.01 2.591 0.124 2.531-0.789-0.044-0.898-0.922-0.646-3.423-0.557-2.499 0.055-4.458 1.117-5.469 2.014-0.994 0.882-2.077 1.402-1.51 1.797z"/>
- <path fill="#565656" d="m256.369 250.446c0.616 0.459 1.029-0.324 2.36-0.912 1.33-0.589 3.456-1.24 5.178-1.248 1.723-0.01 2.47 0.141 2.42-0.713-0.039-0.842-0.881-0.582-3.268-0.527-2.387 0.021-4.287 1.01-5.252 1.836-0.953 0.816-1.987 1.199-1.438 1.564z"/>
- <path fill="#5b5b5b" d="m256.701 250.079c0.564 0.397 0.926-0.213 2.245-0.764s3.427-1.084 4.963-1.093c1.536-0.011 2.348 0.157 2.307-0.636-0.031-0.785-0.839-0.52-3.112-0.5-2.271-0.01-4.116 0.906-5.035 1.662-0.913 0.751-1.898 0.993-1.368 1.331z"/>
- <path fill="#606060" d="m257.034 249.709c0.511 0.336 0.821-0.1 2.13-0.612 1.309-0.515 3.397-0.929 4.746-0.938 1.351-0.01 2.227 0.176 2.196-0.558-0.026-0.729-0.799-0.457-2.958-0.472-2.158-0.043-3.945 0.799-4.82 1.486-0.87 0.682-1.805 0.788-1.294 1.094z"/>
- <path fill="#666" d="m257.367 249.342c0.458 0.273 0.716 0.012 2.014-0.465 1.299-0.476 3.368-0.771 4.53-0.781 1.163-0.012 2.105 0.191 2.084-0.482-0.02-0.673-0.757-0.393-2.803-0.443-2.044-0.076-3.773 0.693-4.604 1.311-0.828 0.616-1.714 0.582-1.221 0.86z"/>
- </g>
- <g transform="translate(-12.4048,10.0005)">
- <path d="m270.222 247.265c0 2.304 4.68 3.096 9.144 3.743 4.392 0.648 7.92 1.513 8.136 6.121 0.216 4.535-0.936 7.775 1.08 7.416 4.32-0.793 5.904-5.473 5.832-7.633 0-2.16-3.168-6.047-8.855-8.207-4.177-1.584-7.2-2.305-10.872-2.449-4.897-0.214-4.465 1.009-4.465 1.009z"/>
- <path fill="#030303" d="m270.348 247.304c0.012 2.239 4.643 2.97 9.049 3.639 4.352 0.675 7.75 1.511 8.11 6.002 0.345 4.415-0.854 7.515 1.136 7.188 4.145-0.739 5.688-5.2 5.607-7.332-0.015-2.151-3.118-5.91-8.733-8.038-4.129-1.563-7.11-2.298-10.74-2.452-4.754-0.217-4.438 0.952-4.429 0.993z"/>
- <path fill="#070707" d="m270.474 247.342c0.023 2.174 4.605 2.845 8.953 3.533 4.312 0.701 7.58 1.508 8.087 5.885 0.471 4.295-0.771 7.252 1.189 6.963 3.97-0.689 5.472-4.93 5.384-7.033-0.028-2.145-3.068-5.773-8.61-7.87-4.082-1.543-7.022-2.291-10.609-2.456-4.612-0.218-4.412 0.896-4.394 0.978z"/>
- <path fill="#0b0b0b" d="m270.6 247.379c0.035 2.109 4.568 2.721 8.857 3.431 4.271 0.728 7.411 1.506 8.063 5.767 0.599 4.174-0.689 6.988 1.245 6.735 3.795-0.638 5.257-4.66 5.159-6.733-0.044-2.137-3.019-5.636-8.488-7.701-4.035-1.522-6.933-2.285-10.478-2.459-4.469-0.219-4.384 0.837-4.358 0.96z"/>
- <path fill="#0f0f0f" d="m270.726 247.418c0.047 2.043 4.531 2.595 8.762 3.324 4.232 0.754 7.242 1.504 8.039 5.649 0.725 4.052-0.608 6.728 1.299 6.509 3.621-0.586 5.041-4.389 4.937-6.436-0.06-2.127-2.971-5.496-8.367-7.53-3.988-1.502-6.842-2.278-10.346-2.464-4.328-0.22-4.359 0.784-4.324 0.948z"/>
- <path fill="#131313" d="m270.852 247.458c0.059 1.978 4.495 2.469 8.667 3.219 4.19 0.781 7.071 1.502 8.014 5.531 0.854 3.932-0.526 6.465 1.354 6.283 3.445-0.535 4.824-4.119 4.712-6.137-0.074-2.119-2.92-5.359-8.245-7.361-3.941-1.482-6.753-2.271-10.213-2.469-4.186-0.221-4.333 0.726-4.289 0.934z"/>
- <path fill="#161616" d="m270.978 247.495c0.07 1.914 4.458 2.344 8.57 3.115 4.151 0.807 6.903 1.5 7.99 5.413 0.98 3.812-0.443 6.202 1.409 6.056 3.271-0.482 4.609-3.848 4.488-5.836-0.088-2.111-2.871-5.222-8.123-7.193-3.894-1.461-6.663-2.264-10.081-2.471-4.043-0.223-4.306 0.67-4.253 0.916z"/>
- <path fill="#1a1a1a" d="m271.104 247.534c0.082 1.848 4.422 2.219 8.476 3.01 4.111 0.832 6.734 1.498 7.965 5.295 1.108 3.69-0.36 5.94 1.464 5.83 3.097-0.433 4.394-3.578 4.265-5.537-0.104-2.104-2.821-5.084-8-7.023-3.848-1.441-6.575-2.26-9.949-2.477-3.905-0.223-4.283 0.613-4.221 0.902z"/>
- <path fill="#1e1e1e" d="m271.23 247.573c0.094 1.781 4.385 2.092 8.381 2.904 4.07 0.859 6.563 1.495 7.939 5.178 1.236 3.568-0.278 5.678 1.52 5.602 2.921-0.381 4.177-3.305 4.04-5.237-0.118-2.097-2.771-4.946-7.878-6.854-3.8-1.42-6.485-2.252-9.817-2.479-3.762-0.226-4.256 0.556-4.185 0.886z"/>
- <path fill="#222" d="m271.356 247.61c0.105 1.717 4.348 1.969 8.285 2.801 4.029 0.885 6.395 1.493 7.916 5.059 1.362 3.449-0.197 5.416 1.573 5.377 2.746-0.329 3.962-3.036 3.816-4.939-0.133-2.087-2.722-4.808-7.756-6.684-3.753-1.4-6.396-2.247-9.686-2.484-3.618-0.227-4.227 0.499-4.148 0.87z"/>
- <path fill="#262626" d="m271.482 247.648c0.118 1.651 4.311 1.843 8.189 2.694 3.99 0.914 6.226 1.492 7.892 4.943 1.491 3.328-0.115 5.152 1.629 5.149 2.571-0.278 3.746-2.765 3.592-4.64-0.146-2.08-2.672-4.672-7.634-6.516-3.705-1.38-6.306-2.24-9.553-2.488-3.478-0.225-4.203 0.446-4.115 0.858z"/>
- <path fill="#2a2a2a" d="m271.608 247.687c0.129 1.587 4.273 1.716 8.094 2.59 3.95 0.938 6.056 1.489 7.867 4.825 1.618 3.206-0.033 4.891 1.684 4.922 2.396-0.227 3.53-2.494 3.368-4.34-0.162-2.072-2.623-4.534-7.512-6.348-3.658-1.358-6.216-2.232-9.421-2.492-3.336-0.226-4.177 0.39-4.08 0.843z"/>
- <path fill="#2d2d2d" d="m271.734 247.725c0.141 1.521 4.237 1.591 7.999 2.484 3.909 0.967 5.886 1.488 7.842 4.707 1.746 3.086 0.05 4.629 1.739 4.697 2.221-0.176 3.313-2.225 3.144-4.041-0.177-2.064-2.572-4.396-7.389-6.178-3.612-1.339-6.128-2.227-9.29-2.497-3.194-0.227-4.151 0.334-4.045 0.828z"/>
- <path fill="#313131" d="m271.86 247.763c0.153 1.456 4.2 1.466 7.903 2.381 3.869 0.991 5.717 1.485 7.817 4.589 1.873 2.965 0.132 4.365 1.794 4.469 2.046-0.123 3.099-1.953 2.92-3.742-0.191-2.055-2.523-4.258-7.267-6.008-3.565-1.318-6.038-2.22-9.158-2.5-3.051-0.229-4.124 0.276-4.009 0.811z"/>
- <path fill="#353535" d="m271.986 247.801c0.165 1.392 4.163 1.341 7.808 2.275 3.829 1.018 5.547 1.483 7.794 4.473 2 2.843 0.213 4.103 1.848 4.242 1.873-0.074 2.883-1.683 2.696-3.443-0.206-2.047-2.474-4.12-7.145-5.838-3.517-1.299-5.948-2.215-9.026-2.506-2.91-0.229-4.099 0.221-3.975 0.797z"/>
- <path fill="#393939" d="m272.112 247.84c0.176 1.326 4.126 1.215 7.712 2.17 3.789 1.045 5.378 1.482 7.771 4.354 2.127 2.723 0.295 3.842 1.901 4.016 1.698-0.021 2.667-1.412 2.474-3.144-0.222-2.038-2.426-3.981-7.023-5.669-3.47-1.277-5.859-2.208-8.894-2.509-2.769-0.231-4.074 0.164-3.941 0.782z"/>
- <path fill="#3d3d3d" d="m272.238 247.877c0.188 1.262 4.089 1.09 7.617 2.066 3.749 1.071 5.208 1.479 7.745 4.236 2.255 2.602 0.377 3.578 1.957 3.789 1.522 0.029 2.451-1.141 2.249-2.844-0.236-2.033-2.375-3.846-6.901-5.5-3.423-1.258-5.769-2.203-8.762-2.514-2.626-0.231-4.046 0.109-3.905 0.767z"/>
- <path fill="#414141" d="m272.364 247.917c0.2 1.195 4.052 0.965 7.522 1.961 3.708 1.098 5.037 1.477 7.72 4.119 2.383 2.479 0.46 3.315 2.012 3.562 1.348 0.081 2.236-0.87 2.025-2.545-0.251-2.022-2.325-3.707-6.778-5.331-3.377-1.237-5.681-2.195-8.631-2.518-2.485-0.233-4.02 0.05-3.87 0.752z"/>
- <path fill="#444" d="m272.49 247.956c0.212 1.129 4.015 0.838 7.426 1.855 3.668 1.124 4.869 1.475 7.696 4 2.51 2.359 0.542 3.055 2.067 3.336 1.173 0.133 2.02-0.6 1.801-2.246-0.266-2.016-2.276-3.568-6.656-5.16-3.329-1.218-5.591-2.189-8.499-2.521-2.343-0.235-3.994-0.007-3.835 0.736z"/>
- <path fill="#484848" d="m272.616 247.993c0.223 1.065 3.979 0.715 7.331 1.752 3.628 1.15 4.699 1.473 7.671 3.883 2.638 2.238 0.624 2.791 2.122 3.108 0.998 0.185 1.804-0.329 1.577-1.946-0.28-2.008-2.227-3.432-6.534-4.992-3.282-1.196-5.501-2.182-8.367-2.525-2.201-0.235-3.968-0.064-3.8 0.72z"/>
- <path fill="#4c4c4c" d="m272.742 248.032c0.235 1 3.941 0.588 7.235 1.645 3.588 1.178 4.529 1.472 7.646 3.766 2.766 2.118 0.706 2.529 2.177 2.883 0.823 0.235 1.589-0.059 1.354-1.648-0.295-1.998-2.177-3.293-6.412-4.822-3.235-1.176-5.412-2.176-8.235-2.529-2.059-0.239-3.942-0.119-3.765 0.705z"/>
- </g>
- <g transform="translate(-12.4048,10.0005)">
- <path fill="#4c4c4c" d="m287.565 252.854c1.646 1 1.353 2.059 2.412 2.766 0.528 0.352 1.412 0.352 0.882-1-0.706-1.588-1.294-2.472-4.941-3.943-2.353-0.941-1.882 0.059 1.647 2.177z"/>
- <path fill="#505050" d="m287.609 252.868c1.605 0.975 1.32 2.008 2.353 2.696 0.517 0.343 1.377 0.343 0.86-0.976-0.689-1.549-1.262-2.41-4.82-3.846-2.295-0.917-1.836 0.059 1.607 2.126z"/>
- <path fill="#545454" d="m287.652 252.879c1.567 0.951 1.287 1.957 2.294 2.629 0.503 0.334 1.343 0.334 0.839-0.951-0.671-1.51-1.23-2.35-4.699-3.749-2.238-0.893-1.79 0.058 1.566 2.071z"/>
- <path fill="#575757" d="m287.696 252.891c1.526 0.926 1.254 1.908 2.235 2.563 0.489 0.325 1.308 0.325 0.816-0.928-0.653-1.471-1.199-2.289-4.578-3.652-2.179-0.872-1.743 0.055 1.527 2.017z"/>
- <path fill="#5b5b5b" d="m287.74 252.903c1.485 0.902 1.22 1.857 2.175 2.494 0.479 0.318 1.274 0.318 0.796-0.902-0.637-1.432-1.167-2.229-4.457-3.556-2.122-0.849-1.697 0.054 1.486 1.964z"/>
- <path fill="#5f5f5f" d="m287.783 252.915c1.446 0.879 1.188 1.808 2.117 2.426 0.464 0.31 1.239 0.31 0.773-0.877-0.619-1.394-1.136-2.168-4.336-3.459-2.064-0.826-1.65 0.052 1.446 1.91z"/>
- <path fill="#636363" d="m287.827 252.926c1.405 0.854 1.154 1.758 2.057 2.359 0.452 0.301 1.205 0.301 0.754-0.853-0.603-1.354-1.104-2.108-4.216-3.363-2.007-0.801-1.605 0.053 1.405 1.857z"/>
- <path fill="#676767" d="m287.871 252.94c1.364 0.828 1.121 1.705 1.998 2.29 0.438 0.292 1.17 0.292 0.731-0.828-0.585-1.315-1.072-2.047-4.095-3.267-1.948-0.779-1.558 0.05 1.366 1.805z"/>
- <path fill="#6b6b6b" d="m287.914 252.952c1.325 0.805 1.088 1.655 1.94 2.223 0.425 0.283 1.135 0.283 0.709-0.803-0.568-1.277-1.041-1.988-3.974-3.17-1.891-0.757-1.512 0.047 1.325 1.75z"/>
- <path fill="#6e6e6e" d="m287.958 252.963c1.284 0.779 1.056 1.605 1.88 2.156 0.413 0.274 1.102 0.274 0.688-0.779-0.551-1.238-1.009-1.926-3.853-3.073-1.833-0.733-1.466 0.046 1.285 1.696z"/>
- <path fill="#727272" d="m288.002 252.976c1.243 0.755 1.021 1.554 1.821 2.087 0.399 0.266 1.066 0.266 0.666-0.755-0.533-1.199-0.977-1.865-3.731-2.976-1.776-0.71-1.421 0.045 1.244 1.644z"/>
- <path fill="#767676" d="m288.045 252.989c1.203 0.73 0.989 1.504 1.763 2.02 0.387 0.257 1.031 0.257 0.645-0.731-0.516-1.159-0.946-1.805-3.61-2.879-1.72-0.688-1.376 0.042 1.202 1.59z"/>
- <path fill="#7a7a7a" d="m288.089 253c1.163 0.705 0.955 1.453 1.703 1.951 0.373 0.25 0.997 0.25 0.623-0.705-0.499-1.121-0.914-1.744-3.489-2.783-1.661-0.664-1.329 0.041 1.163 1.537z"/>
- <path fill="#7e7e7e" d="m288.133 253.012c1.122 0.682 0.923 1.404 1.644 1.885 0.361 0.24 0.962 0.24 0.602-0.682-0.481-1.082-0.882-1.684-3.367-2.687-1.605-0.64-1.285 0.041 1.121 1.484z"/>
- <path fill="#828282" d="m288.176 253.025c1.082 0.657 0.89 1.353 1.586 1.815 0.348 0.232 0.927 0.232 0.578-0.656-0.463-1.043-0.85-1.623-3.245-2.59-1.547-0.618-1.237 0.039 1.081 1.431z"/>
- <path fill="#858585" d="m288.22 253.038c1.042 0.631 0.855 1.301 1.524 1.748 0.335 0.223 0.894 0.223 0.559-0.633-0.446-1.005-0.818-1.563-3.125-2.492-1.488-0.596-1.19 0.037 1.042 1.377z"/>
- <path fill="#898989" d="m288.264 253.049c1.001 0.607 0.821 1.252 1.466 1.681 0.322 0.214 0.857 0.214 0.536-0.608-0.43-0.965-0.786-1.502-3.004-2.396-1.43-0.573-1.144 0.034 1.002 1.323z"/>
- <path fill="#8d8d8d" d="m288.307 253.061c0.961 0.584 0.79 1.201 1.407 1.613 0.309 0.205 0.823 0.205 0.515-0.584-0.412-0.926-0.755-1.441-2.883-2.299-1.373-0.548-1.098 0.034 0.961 1.27z"/>
- <path fill="#919191" d="m288.351 253.073c0.921 0.559 0.756 1.151 1.348 1.547 0.296 0.196 0.789 0.196 0.493-0.56-0.395-0.888-0.723-1.381-2.762-2.204-1.315-0.525-1.052 0.033 0.921 1.217z"/>
- <path fill="#959595" d="m288.395 253.084c0.88 0.535 0.723 1.102 1.289 1.479 0.282 0.189 0.754 0.189 0.471-0.534-0.377-0.849-0.691-1.321-2.641-2.106-1.257-0.505-1.006 0.031 0.881 1.161z"/>
- <path fill="#999" d="m288.438 253.097c0.84 0.51 0.689 1.05 1.229 1.409 0.271 0.181 0.721 0.181 0.45-0.51-0.36-0.81-0.66-1.26-2.52-2.01-1.199-0.48-0.959 0.031 0.841 1.111z"/>
- </g>
- <g transform="translate(-12.4048,10.0005)">
- <path d="m222.275 107.427c-0.738 0.902 0.574 8.365 5.412 13.285 4.839 4.838 7.791 4.838 9.759 2.706 3.771-4.018 0.738-7.791-1.558-10.415-2.297-2.624-5.248-1.722-7.955-4.346-2.706-2.624-4.592-2.46-5.658-1.23z"/>
- <path fill="#050505" d="m222.345 107.494c-0.732 0.895 0.569 8.3 5.369 13.182 4.803 4.801 7.731 4.801 9.685 2.685 3.742-3.987 0.731-7.73-1.546-10.334-2.278-2.604-5.208-1.709-7.894-4.312-2.684-2.604-4.556-2.441-5.614-1.221z"/>
- <path fill="#0a0a0a" d="m222.416 107.561c-0.727 0.888 0.565 8.235 5.328 13.079 4.763 4.763 7.67 4.763 9.607 2.664 3.713-3.956 0.727-7.67-1.534-10.253-2.26-2.584-5.166-1.696-7.831-4.279-2.664-2.583-4.521-2.422-5.57-1.211z"/>
- <path fill="#0f0f0f" d="m222.486 107.628c-0.721 0.881 0.561 8.17 5.286 12.976 4.726 4.725 7.608 4.725 9.532 2.642 3.684-3.924 0.72-7.609-1.522-10.172-2.243-2.563-5.126-1.682-7.77-4.244-2.643-2.563-4.485-2.403-5.526-1.202z"/>
- <path fill="#141414" d="m222.556 107.695c-0.716 0.874 0.557 8.105 5.243 12.872 4.689 4.688 7.55 4.688 9.456 2.622 3.655-3.893 0.716-7.549-1.51-10.091-2.224-2.543-5.085-1.669-7.707-4.211-2.621-2.543-4.449-2.384-5.482-1.192z"/>
- <path fill="#191919" d="m222.627 107.762c-0.71 0.867 0.552 8.04 5.202 12.769 4.65 4.65 7.488 4.65 9.379 2.601 3.626-3.862 0.71-7.489-1.497-10.011s-5.044-1.655-7.646-4.177-4.414-2.364-5.438-1.182z"/>
- <path fill="#1e1e1e" d="m222.697 107.829c-0.704 0.86 0.547 7.975 5.16 12.666 4.613 4.612 7.428 4.612 9.304 2.579 3.596-3.83 0.703-7.427-1.486-9.929-2.188-2.502-5.003-1.642-7.584-4.143-2.579-2.502-4.378-2.346-5.394-1.173z"/>
- <path fill="#232323" d="m222.767 107.896c-0.697 0.853 0.543 7.91 5.117 12.562 4.576 4.575 7.367 4.575 9.229 2.559 3.567-3.8 0.698-7.367-1.473-9.848-2.171-2.482-4.963-1.629-7.522-4.11s-4.343-2.326-5.351-1.163z"/>
- <path fill="#282828" d="m222.838 107.963c-0.691 0.846 0.538 7.845 5.076 12.459 4.537 4.537 7.307 4.537 9.152 2.538 3.537-3.769 0.691-7.307-1.461-9.768-2.154-2.461-4.922-1.615-7.461-4.076-2.538-2.461-4.307-2.307-5.306-1.153z"/>
- <path fill="#2d2d2d" d="m222.908 108.03c-0.686 0.839 0.534 7.78 5.034 12.355 4.5 4.499 7.246 4.499 9.076 2.516 3.509-3.737 0.686-7.246-1.449-9.686-2.135-2.441-4.881-1.602-7.399-4.042-2.516-2.44-4.271-2.287-5.262-1.143z"/>
- <path fill="#333" d="m222.978 108.096c-0.681 0.832 0.529 7.715 4.992 12.253 4.463 4.462 7.186 4.462 9.001 2.496 3.479-3.706 0.68-7.186-1.438-9.605-2.118-2.42-4.841-1.588-7.337-4.008s-4.235-2.27-5.218-1.136z"/>
- <path fill="#383838" d="m223.048 108.163c-0.674 0.825 0.526 7.65 4.95 12.15 4.425 4.425 7.125 4.425 8.925 2.475 3.45-3.675 0.676-7.125-1.425-9.525-2.099-2.4-4.8-1.575-7.274-3.975-2.475-2.399-4.201-2.25-5.176-1.125z"/>
- <path fill="#3d3d3d" d="m223.119 108.23c-0.669 0.818 0.521 7.585 4.908 12.047 4.387 4.387 7.063 4.387 8.849 2.453 3.42-3.643 0.669-7.064-1.413-9.443-2.082-2.38-4.759-1.562-7.214-3.941-2.453-2.38-4.164-2.231-5.13-1.116z"/>
- <path fill="#424242" d="m223.189 108.297c-0.663 0.811 0.516 7.52 4.866 11.944 4.35 4.349 7.004 4.349 8.772 2.432 3.392-3.612 0.663-7.004-1.4-9.363-2.064-2.359-4.719-1.548-7.151-3.907-2.433-2.359-4.129-2.212-5.087-1.106z"/>
- <path fill="#474747" d="m223.259 108.364c-0.656 0.804 0.513 7.455 4.824 11.84 4.313 4.312 6.944 4.312 8.697 2.412 3.362-3.582 0.658-6.944-1.388-9.282-2.046-2.339-4.679-1.535-7.09-3.874-2.411-2.338-4.093-2.192-5.043-1.096z"/>
- <path fill="#4c4c4c" d="m223.33 108.431c-0.651 0.797 0.507 7.39 4.782 11.737 4.274 4.274 6.882 4.274 8.621 2.39 3.332-3.55 0.651-6.883-1.377-9.201s-4.636-1.521-7.028-3.839c-2.39-2.318-4.057-2.174-4.998-1.087z"/>
- <path fill="#515151" d="m223.4 108.498c-0.646 0.79 0.503 7.325 4.74 11.634 4.236 4.236 6.821 4.236 8.545 2.369 3.304-3.519 0.646-6.822-1.364-9.12s-4.596-1.508-6.966-3.806c-2.369-2.298-4.022-2.154-4.955-1.077z"/>
- <path fill="#565656" d="m223.47 108.565c-0.641 0.783 0.499 7.26 4.697 11.53 4.199 4.199 6.763 4.199 8.471 2.349 3.273-3.488 0.64-6.762-1.353-9.039-1.993-2.278-4.556-1.495-6.905-3.773-2.347-2.277-3.985-2.135-4.91-1.067z"/>
- <path fill="#5b5b5b" d="m223.541 108.632c-0.635 0.776 0.493 7.195 4.656 11.427 4.161 4.161 6.701 4.161 8.393 2.327 3.245-3.456 0.636-6.701-1.34-8.958-1.975-2.257-4.514-1.48-6.843-3.738-2.327-2.257-3.95-2.116-4.866-1.058z"/>
- <path fill="#606060" d="m223.611 108.699c-0.629 0.769 0.489 7.13 4.614 11.324 4.124 4.123 6.64 4.123 8.317 2.306 3.215-3.425 0.628-6.641-1.328-8.877-1.957-2.237-4.474-1.468-6.78-3.705-2.306-2.236-3.915-2.097-4.823-1.048z"/>
- <path fill="#666" d="m223.681 108.765c-0.623 0.762 0.484 7.065 4.571 11.221 4.086 4.086 6.58 4.086 8.242 2.285 3.187-3.394 0.623-6.58-1.315-8.796-1.939-2.217-4.434-1.455-6.72-3.671-2.284-2.216-3.878-2.078-4.778-1.039z"/>
- </g>
- <g transform="translate(-12.4048,10.0005)">
- <path fill="#fc0" d="m137.79 109.277c1.978 1.366 2.031 1.607 4.948 3.514 4.64 3.768 12.885 4.616 16.922 4.75 9.233 1.467 25.738-7.161 32.273-11.111 3.291-2.463 9.38-7.551 11.659-7.637 1.405 1.485-0.66 1.792-3.587 3.775-3.906 2.779-7.25 5.156-13.172 8.515-6.338 3.316-16.078 8.794-28.548 8.054-6.542-0.959-6.566-1.024-10.606-3.086-2.4-1.732-7.901-4.608-9.889-6.774z"/>
- <linearGradient id="al" x1="129.342" gradientUnits="userSpaceOnUse" x2="195.598" gradientTransform="matrix(1,0,0,-1,8.3999,368.3)" y1="259.305" y2="259.305">
- <stop stop-color="#FAC700" offset="0"/>
- <stop stop-color="#F7C400" offset=".415"/>
- <stop stop-color="#F7C400" offset="1"/>
- </linearGradient>
- <path fill="url(#al)" d="m137.742 109.259c1.926 1.274 2.165 1.643 5.083 3.554 4.616 3.734 12.716 4.616 16.796 4.763 9.365 1.452 26.05-7.294 32.356-11.159 3.357-2.506 9.344-7.498 11.595-7.604 1.365 1.472-0.728 1.768-3.688 3.814-3.889 2.753-7.119 5.065-12.972 8.383-6.29 3.291-16.078 8.795-28.536 8.104-6.561-0.945-6.851-1.07-10.758-3.079-2.468-1.755-7.876-4.587-9.876-6.776z"/>
- <linearGradient id="am" x1="129.293" gradientUnits="userSpaceOnUse" x2="195.554" gradientTransform="matrix(1,0,0,-1,8.3999,368.3)" y1="259.311" y2="259.311">
- <stop stop-color="#F6C200" offset="0"/>
- <stop stop-color="#EFBC00" offset=".415"/>
- <stop stop-color="#EFBC00" offset="1"/>
- </linearGradient>
- <path fill="url(#am)" d="m137.693 109.24c1.876 1.183 2.3 1.68 5.218 3.595 4.593 3.7 12.548 4.616 16.67 4.776 9.498 1.437 26.364-7.428 32.44-11.207 3.425-2.55 9.308-7.444 11.528-7.57 1.326 1.457-0.795 1.743-3.788 3.854-3.87 2.725-6.99 4.973-12.771 8.25-6.243 3.266-16.078 8.796-28.525 8.154-6.579-0.931-7.134-1.117-10.908-3.073-2.536-1.779-7.852-4.567-9.864-6.779z"/>
- <linearGradient id="an" x1="129.245" gradientUnits="userSpaceOnUse" x2="195.51" gradientTransform="matrix(1,0,0,-1,8.3999,368.3)" y1="259.317" y2="259.317">
- <stop stop-color="#F1BD00" offset="0"/>
- <stop stop-color="#E8B500" offset=".415"/>
- <stop stop-color="#E8B500" offset="1"/>
- </linearGradient>
- <path fill="url(#an)" d="m137.645 109.222c1.825 1.091 2.434 1.715 5.352 3.635 4.569 3.665 12.38 4.615 16.544 4.789 9.631 1.422 26.677-7.562 32.524-11.255 3.491-2.594 9.271-7.392 11.463-7.538 1.287 1.442-0.861 1.718-3.889 3.893-3.853 2.699-6.86 4.882-12.57 8.119-6.195 3.241-16.078 8.797-28.513 8.203-6.6-0.916-7.418-1.163-11.061-3.066-2.603-1.801-7.826-4.546-9.85-6.78z"/>
- <linearGradient id="ao" x1="129.196" gradientUnits="userSpaceOnUse" x2="195.465" gradientTransform="matrix(1,0,0,-1,8.3999,368.3)" y1="259.322" y2="259.322">
- <stop stop-color="#EDB800" offset="0"/>
- <stop stop-color="#E0AD00" offset=".415"/>
- <stop stop-color="#E0AD00" offset="1"/>
- </linearGradient>
- <path fill="url(#ao)" d="m137.596 109.203c1.774 1 2.568 1.752 5.487 3.676 4.545 3.631 12.211 4.615 16.418 4.801 9.764 1.408 26.989-7.695 32.608-11.302 3.557-2.637 9.236-7.338 11.396-7.505 1.247 1.427-0.928 1.693-3.99 3.932-3.833 2.672-6.729 4.791-12.369 7.986-6.148 3.217-16.078 8.799-28.501 8.254-6.619-0.902-7.702-1.21-11.21-3.059-2.672-1.825-7.803-4.525-9.839-6.783z"/>
- <linearGradient id="ap" x1="129.148" gradientUnits="userSpaceOnUse" x2="195.422" gradientTransform="matrix(1,0,0,-1,8.3999,368.3)" y1="259.327" y2="259.327">
- <stop stop-color="#E9B300" offset="0"/>
- <stop stop-color="#D8A500" offset=".415"/>
- <stop stop-color="#D8A500" offset="1"/>
- </linearGradient>
- <path fill="url(#ap)" d="m137.548 109.184c1.724 0.909 2.703 1.788 5.622 3.717 4.522 3.597 12.043 4.615 16.292 4.814 9.896 1.393 27.303-7.829 32.692-11.35 3.624-2.681 9.2-7.286 11.331-7.472 1.208 1.412-0.995 1.668-4.092 3.972-3.814 2.644-6.6 4.698-12.168 7.853-6.101 3.192-16.077 8.8-28.489 8.303-6.638-0.887-7.986-1.256-11.361-3.052-2.741-1.848-7.779-4.504-9.827-6.785z"/>
- <linearGradient id="aq" x1="129.099" gradientUnits="userSpaceOnUse" x2="195.379" gradientTransform="matrix(1,0,0,-1,8.3999,368.3)" y1="259.332" y2="259.332">
- <stop stop-color="#E4AE00" offset="0"/>
- <stop stop-color="#D19E00" offset=".415"/>
- <stop stop-color="#D19E00" offset="1"/>
- </linearGradient>
- <path fill="url(#aq)" d="m137.499 109.166c1.673 0.817 2.838 1.824 5.757 3.757 4.499 3.562 11.875 4.614 16.166 4.827 10.029 1.378 27.615-7.963 32.776-11.398 3.691-2.725 9.164-7.232 11.265-7.439 1.169 1.397-1.061 1.644-4.191 4.01-3.796 2.618-6.469 4.608-11.968 7.722-6.053 3.167-16.077 8.801-28.478 8.353-6.657-0.873-8.27-1.303-11.512-3.046-2.809-1.87-7.755-4.483-9.815-6.786z"/>
- <linearGradient id="ar" x1="129.051" gradientUnits="userSpaceOnUse" x2="195.338" gradientTransform="matrix(1,0,0,-1,8.3999,368.3)" y1="259.336" y2="259.336">
- <stop stop-color="#E0A900" offset="0"/>
- <stop stop-color="#C99600" offset=".415"/>
- <stop stop-color="#C99600" offset="1"/>
- </linearGradient>
- <path fill="url(#ar)" d="m137.451 109.147c1.622 0.726 2.972 1.86 5.892 3.798 4.475 3.528 11.705 4.614 16.04 4.84 10.161 1.362 27.929-8.097 32.859-11.447 3.757-2.767 9.128-7.178 11.2-7.405 1.13 1.382-1.128 1.619-4.294 4.049-3.777 2.592-6.339 4.517-11.767 7.589-6.005 3.143-16.077 8.803-28.466 8.404-6.676-0.859-8.553-1.35-11.663-3.039-2.876-1.894-7.729-4.462-9.801-6.789z"/>
- <linearGradient id="w" x1="129.003" gradientUnits="userSpaceOnUse" x2="195.296" gradientTransform="matrix(1,0,0,-1,8.3999,368.3)" y1="259.34" y2="259.34">
- <stop stop-color="#DCA400" offset="0"/>
- <stop stop-color="#C18E00" offset=".415"/>
- <stop stop-color="#C18E00" offset="1"/>
- </linearGradient>
- <path fill="url(#w)" d="m137.403 109.129c1.571 0.634 3.105 1.896 6.026 3.838 4.45 3.494 11.536 4.614 15.913 4.852 10.295 1.348 28.241-8.23 32.943-11.494 3.824-2.811 9.092-7.125 11.134-7.373 1.092 1.367-1.194 1.594-4.394 4.088-3.759 2.565-6.209 4.425-11.566 7.457-5.957 3.118-16.077 8.804-28.454 8.453-6.694-0.844-8.837-1.396-11.813-3.032-2.945-1.916-7.706-4.44-9.789-6.789z"/>
- <linearGradient id="x" x1="128.954" gradientUnits="userSpaceOnUse" x2="195.255" gradientTransform="matrix(1,0,0,-1,8.3999,368.3)" y1="259.343" y2="259.343">
- <stop stop-color="#D79F00" offset="0"/>
- <stop stop-color="#BA8700" offset=".415"/>
- <stop stop-color="#BA8700" offset="1"/>
- </linearGradient>
- <path fill="url(#x)" d="m137.354 109.11c1.521 0.543 3.241 1.932 6.161 3.879 4.428 3.459 11.368 4.613 15.788 4.865 10.427 1.333 28.554-8.364 33.026-11.542 3.892-2.855 9.057-7.073 11.068-7.339 1.052 1.353-1.261 1.569-4.495 4.127-3.74 2.538-6.078 4.334-11.365 7.325-5.91 3.093-16.077 8.805-28.441 8.503-6.716-0.83-9.121-1.443-11.966-3.026-3.012-1.939-7.68-4.42-9.776-6.792z"/>
- <linearGradient id="y" x1="128.906" gradientUnits="userSpaceOnUse" x2="195.216" gradientTransform="matrix(1,0,0,-1,8.3999,368.3)" y1="259.348" y2="259.348">
- <stop stop-color="#D39B00" offset="0"/>
- <stop stop-color="#B27F00" offset=".415"/>
- <stop stop-color="#B27F00" offset="1"/>
- </linearGradient>
- <path fill="url(#y)" d="m137.306 109.091c1.47 0.451 3.375 1.969 6.296 3.919 4.403 3.426 11.2 4.614 15.662 4.879 10.559 1.318 28.865-8.498 33.109-11.59 3.958-2.899 9.021-7.02 11.003-7.306 1.013 1.337-1.328 1.544-4.596 4.167-3.722 2.511-5.949 4.242-11.165 7.192-5.862 3.068-16.077 8.807-28.43 8.553-6.734-0.816-9.405-1.489-12.116-3.019-3.08-1.963-7.656-4.4-9.763-6.795z"/>
- <linearGradient id="z" x1="128.857" gradientUnits="userSpaceOnUse" x2="195.176" gradientTransform="matrix(1,0,0,-1,8.3999,368.3)" y1="259.35" y2="259.35">
- <stop stop-color="#CF9600" offset="0"/>
- <stop stop-color="#a70" offset=".415"/>
- <stop stop-color="#a70" offset="1"/>
- </linearGradient>
- <path fill="url(#z)" d="m137.257 109.073c1.421 0.359 3.511 2.005 6.432 3.959 4.38 3.392 11.032 4.614 15.536 4.892 10.691 1.303 29.179-8.631 33.193-11.638 4.024-2.942 8.984-6.967 10.938-7.274 0.973 1.323-1.396 1.521-4.697 4.206-3.703 2.484-5.818 4.151-10.964 7.06-5.814 3.043-16.077 8.808-28.418 8.603-6.753-0.802-9.689-1.535-12.268-3.012-3.149-1.986-7.632-4.378-9.752-6.796z"/>
- <linearGradient id="aa" x1="128.809" gradientUnits="userSpaceOnUse" x2="195.137" gradientTransform="matrix(1,0,0,-1,8.3999,368.3)" y1="259.354" y2="259.354">
- <stop stop-color="#CA9100" offset="0"/>
- <stop stop-color="#A37000" offset=".415"/>
- <stop stop-color="#A37000" offset="1"/>
- </linearGradient>
- <path fill="url(#aa)" d="m137.209 109.054c1.368 0.268 3.645 2.041 6.565 4 4.356 3.357 10.864 4.613 15.41 4.904 10.824 1.289 29.493-8.764 33.277-11.685 4.092-2.986 8.948-6.914 10.871-7.241 0.935 1.308-1.461 1.496-4.797 4.245-3.685 2.457-5.688 4.06-10.763 6.928-5.768 3.018-16.077 8.809-28.407 8.653-6.771-0.788-9.972-1.582-12.418-3.006-3.216-2.008-7.607-4.357-9.738-6.798z"/>
- <linearGradient id="ab" x1="128.76" gradientUnits="userSpaceOnUse" x2="195.099" gradientTransform="matrix(1,0,0,-1,8.3999,368.3)" y1="259.356" y2="259.356">
- <stop stop-color="#C68C00" offset="0"/>
- <stop stop-color="#9B6800" offset=".415"/>
- <stop stop-color="#9B6800" offset="1"/>
- </linearGradient>
- <path fill="url(#ab)" d="m137.16 109.036c1.318 0.176 3.779 2.077 6.701 4.04 4.333 3.323 10.695 4.613 15.284 4.917 10.957 1.274 29.805-8.898 33.36-11.733 4.158-3.03 8.912-6.86 10.807-7.208 0.894 1.292-1.528 1.471-4.899 4.284-3.666 2.43-5.558 3.968-10.562 6.796-5.72 2.993-16.077 8.81-28.396 8.702-6.791-0.773-10.256-1.628-12.568-2.999-3.285-2.031-7.583-4.336-9.727-6.799z"/>
- <linearGradient id="ac" x1="128.712" gradientUnits="userSpaceOnUse" x2="195.062" gradientTransform="matrix(1,0,0,-1,8.3999,368.3)" y1="259.358" y2="259.358">
- <stop stop-color="#C28700" offset="0"/>
- <stop stop-color="#936000" offset=".415"/>
- <stop stop-color="#936000" offset="1"/>
- </linearGradient>
- <path fill="url(#ac)" d="m137.112 109.017c1.267 0.085 3.912 2.113 6.835 4.081 4.31 3.289 10.527 4.613 15.158 4.93 11.09 1.258 30.118-9.032 33.445-11.782 4.225-3.072 8.877-6.807 10.739-7.174 0.855 1.278-1.595 1.446-5 4.323-3.647 2.404-5.427 3.877-10.36 6.663-5.673 2.969-16.077 8.812-28.384 8.753-6.811-0.759-10.54-1.675-12.719-2.992-3.353-2.055-7.559-4.315-9.714-6.802z"/>
- <linearGradient id="ad" x1="128.663" gradientUnits="userSpaceOnUse" x2="195.025" gradientTransform="matrix(1,0,0,-1,8.3999,368.3)" y1="259.36" y2="259.36">
- <stop stop-color="#BD8200" offset="0"/>
- <stop stop-color="#8C5900" offset=".415"/>
- <stop stop-color="#8C5900" offset="1"/>
- </linearGradient>
- <path fill="url(#ad)" d="m137.063 108.998c1.217-0.006 4.047 2.15 6.97 4.122 4.286 3.254 10.359 4.612 15.032 4.943 11.223 1.243 30.431-9.166 33.53-11.83 4.289-3.116 8.84-6.753 10.673-7.141 0.815 1.263-1.661 1.421-5.101 4.362-3.63 2.377-5.298 3.785-10.161 6.531-5.624 2.944-16.075 8.813-28.37 8.802-6.83-0.744-10.824-1.721-12.87-2.985-3.422-2.077-7.535-4.294-9.703-6.804z"/>
- <linearGradient id="ae" x1="128.615" gradientUnits="userSpaceOnUse" x2="194.989" gradientTransform="matrix(1,0,0,-1,8.3999,368.3)" y1="259.362" y2="259.362">
- <stop stop-color="#B97D00" offset="0"/>
- <stop stop-color="#845100" offset=".415"/>
- <stop stop-color="#845100" offset="1"/>
- </linearGradient>
- <path fill="url(#ae)" d="m137.015 108.98c1.166-0.098 4.181 2.185 7.104 4.162 4.262 3.22 10.19 4.612 14.906 4.955 11.354 1.229 30.743-9.299 33.613-11.877 4.356-3.16 8.804-6.7 10.607-7.108 0.776 1.248-1.728 1.397-5.202 4.401-3.61 2.35-5.167 3.694-9.96 6.399-5.576 2.919-16.076 8.814-28.358 8.852-6.85-0.73-11.108-1.768-13.021-2.979-3.489-2.1-7.51-4.273-9.689-6.805z"/>
- <linearGradient id="af" x1="128.567" gradientUnits="userSpaceOnUse" x2="194.954" gradientTransform="matrix(1,0,0,-1,8.3999,368.3)" y1="259.364" y2="259.364">
- <stop stop-color="#B57800" offset="0"/>
- <stop stop-color="#7C4900" offset=".415"/>
- <stop stop-color="#7C4900" offset="1"/>
- </linearGradient>
- <path fill="url(#af)" d="m136.967 108.961c1.115-0.189 4.315 2.222 7.239 4.203 4.239 3.186 10.021 4.612 14.78 4.968 11.488 1.214 31.057-9.433 33.697-11.925 4.424-3.203 8.768-6.647 10.542-7.075 0.736 1.233-1.795 1.372-5.303 4.44-3.593 2.323-5.038 3.603-9.759 6.266-5.529 2.895-16.077 8.816-28.348 8.903-6.868-0.716-11.392-1.815-13.172-2.972-3.557-2.124-7.485-4.252-9.676-6.808z"/>
- <linearGradient id="ah" x1="128.518" gradientUnits="userSpaceOnUse" x2="194.918" gradientTransform="matrix(1,0,0,-1,8.3999,368.3)" y1="259.366" y2="259.366">
- <stop stop-color="#B07300" offset="0"/>
- <stop stop-color="#754200" offset=".415"/>
- <stop stop-color="#754200" offset="1"/>
- </linearGradient>
- <path fill="url(#ah)" d="m136.918 108.943c1.064-0.281 4.45 2.257 7.374 4.243 4.216 3.151 9.854 4.611 14.654 4.981 11.621 1.199 31.37-9.567 33.781-11.973 4.49-3.247 8.731-6.594 10.476-7.042 0.698 1.218-1.861 1.347-5.403 4.479-3.573 2.296-4.906 3.511-9.558 6.134-5.48 2.87-16.076 8.817-28.336 8.952-6.887-0.701-11.675-1.861-13.323-2.965-3.626-2.146-7.462-4.231-9.665-6.809z"/>
- <linearGradient id="ai" x1="128.47" gradientUnits="userSpaceOnUse" x2="194.886" gradientTransform="matrix(1,0,0,-1,8.3999,368.3)" y1="259.367" y2="259.367">
- <stop stop-color="#AC6E00" offset="0"/>
- <stop stop-color="#6D3A00" offset=".415"/>
- <stop stop-color="#6D3A00" offset="1"/>
- </linearGradient>
- <path fill="url(#ai)" d="m136.87 108.924c1.013-0.372 4.584 2.294 7.509 4.284 4.191 3.117 9.685 4.611 14.528 4.994 11.753 1.184 31.682-9.701 33.864-12.021 4.557-3.291 8.695-6.542 10.411-7.009 0.657 1.203-1.929 1.322-5.504 4.518-3.557 2.269-4.777 3.42-9.358 6.002-5.434 2.845-16.076 8.818-28.324 9.002-6.907-0.687-11.959-1.908-13.474-2.959-3.694-2.169-7.437-4.21-9.652-6.811z"/>
- <linearGradient id="aj" x1="128.421" gradientUnits="userSpaceOnUse" x2="194.85" gradientTransform="matrix(1,0,0,-1,8.3999,368.3)" y1="259.369" y2="259.369">
- <stop stop-color="#A86A00" offset="0"/>
- <stop stop-color="#663200" offset=".415"/>
- <stop stop-color="#663200" offset="1"/>
- </linearGradient>
- <path fill="url(#aj)" d="m136.821 108.905c0.963-0.464 4.719 2.33 7.644 4.324 4.168 3.083 9.517 4.611 14.402 5.007 11.886 1.169 31.995-9.834 33.948-12.069 4.624-3.334 8.66-6.487 10.345-6.976 0.619 1.188-1.995 1.298-5.604 4.558-3.537 2.242-4.647 3.328-9.157 5.869-5.386 2.82-16.076 8.82-28.313 9.052-6.926-0.673-12.243-1.954-13.625-2.952-3.762-2.192-7.413-4.189-9.64-6.813z"/>
- </g>
- </g>
-</svg>
+<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="100%" width="100%" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" viewBox="0 0 349.46883 405.12272"> + <title>Tux</title> + <desc>For more information see: http://commons.wikimedia.org/wiki/Image:Tux.svg</desc> + <radialGradient id="ag" gradientUnits="userSpaceOnUse" cy="-551.04" cx="274.822" gradientTransform="matrix(.5671 0 0 -.2835 81.263 201.645)" r="165.384"> + <stop stop-opacity=".502" offset="0"/> + <stop stop-opacity="0" offset="1"/> + </radialGradient> + <path fill="url(#ag)" d="m330.892 357.885c0 25.898-41.989 46.893-93.785 46.893-51.795 0-93.784-20.994-93.784-46.893s41.989-46.893 93.784-46.893c51.795 0.001 93.785 20.995 93.785 46.893z"/> + <radialGradient id="ak" gradientUnits="userSpaceOnUse" cy="-551.042" cx="268.794" gradientTransform="matrix(.5823 0 0 -.2835 -61.6052 201.14)" r="165.383"> + <stop stop-opacity=".502" offset="0"/> + <stop stop-opacity="0" offset="1"/> + </radialGradient> + <path fill="url(#ak)" d="m191.223 357.381c0 25.897-43.117 46.892-96.306 46.892-53.188 0-96.305-20.994-96.305-46.892s43.117-46.893 96.305-46.893c53.188 0.001 96.306 20.995 96.306 46.893z"/> + <g transform="translate(8.99996 9.00046)"> + <path d="m292.327 256.606c-4.752 19.584-28.872 60.48-41.688 78.48-12.815 18.072-11.231 34.344-34.92 28.008-23.616-6.336-30.24-5.184-54.647-3.744-24.265 1.439-19.009-0.721-34.2 6.12-15.12 6.84-65.88-82.944-69.984-99.647-4.031-16.705-5.976-14.689 4.536-32.761 10.513-18.071 12.024-35.928 25.92-57.816 13.896-21.96 29.952-33.12 28.8-49.896-4.535-62.28-8.136-93.384 19.513-107.784 26.352-13.68 48.384-5.544 57.096-0.864 3.744 2.016 11.376 5.904 17.064 12.744 5.688 6.696 10.8 16.848 13.68 29.664 5.904 25.704-2.448 17.208 4.248 46.656 6.624 29.375 20.088 43.775 36.504 67.031 16.414 23.257 33.55 61.633 28.078 83.809z"/> + <g transform="translate(-12.4048,10.0005)"> + <path fill="#666" d="m148.47 94.049c4.319-1.728 3.592-1.958 6.472-8.222 2.304-4.824 4.328-6.898 4.256-14.242 0-7.2-2.232-9.648-5.616-14.328-3.24-4.464-8.424-4.68-11.664-4.104-1.872 0.288-4.319 2.664-5.976 6.192-1.08 2.376-1.944 5.4-2.017 8.568-0.216 8.496 0.505 11.736 2.448 17.496 2.305 6.769 7.921 10.297 12.097 8.64z"/> + <path fill="#6d6d6d" d="m148.47 94.023c4.293-1.717 3.563-1.954 6.425-8.178 2.289-4.793 4.312-6.861 4.271-14.164 0.027-7.152-2.162-9.702-5.488-14.201-3.296-4.345-8.376-4.509-11.593-3.953-1.916 0.283-4.354 2.569-6.038 5.968-1.159 2.31-2.016 5.353-2.087 8.535-0.212 8.438 0.547 11.691 2.46 17.417 2.268 6.731 7.901 10.221 12.05 8.576z"/> + <path fill="#757575" d="m148.471 93.996c4.264-1.706 3.533-1.95 6.377-8.133 2.273-4.762 4.296-6.823 4.288-14.085 0.053-7.105-2.093-9.756-5.363-14.075-3.35-4.225-8.327-4.338-11.52-3.801-1.961 0.278-4.389 2.474-6.099 5.744-1.242 2.245-2.089 5.305-2.16 8.501-0.207 8.38 0.591 11.647 2.473 17.34 2.231 6.691 7.881 10.144 12.004 8.509z"/> + <path fill="#7c7c7c" d="m148.471 93.969c4.235-1.694 3.506-1.946 6.329-8.089 2.26-4.731 4.28-6.786 4.304-14.006 0.081-7.058-2.021-9.811-5.236-13.948-3.403-4.105-8.278-4.167-11.446-3.649-2.006 0.273-4.424 2.379-6.16 5.519-1.322 2.179-2.161 5.257-2.232 8.468-0.202 8.323 0.636 11.603 2.486 17.261 2.191 6.654 7.859 10.068 11.955 8.444z"/> + <path fill="#848484" d="m148.471 93.943c4.209-1.684 3.477-1.942 6.282-8.045 2.245-4.7 4.266-6.749 4.319-13.928 0.107-7.01-1.95-9.864-5.109-13.821-3.458-3.985-8.23-3.996-11.375-3.498-2.049 0.268-4.458 2.284-6.222 5.295-1.403 2.114-2.233 5.21-2.303 8.435-0.198 8.265 0.679 11.559 2.498 17.183 2.156 6.615 7.842 9.992 11.91 8.379z"/> + <path fill="#8c8c8c" d="m148.471 93.916c4.181-1.672 3.448-1.938 6.235-8 2.23-4.668 4.249-6.711 4.335-13.85 0.134-6.962-1.88-9.918-4.982-13.695-3.513-3.865-8.183-3.825-11.303-3.347-2.094 0.263-4.492 2.189-6.283 5.07-1.484 2.049-2.306 5.163-2.375 8.401-0.193 8.207 0.723 11.515 2.511 17.105 2.118 6.58 7.821 9.919 11.862 8.316z"/> + <path fill="#939393" d="m148.472 93.889c4.152-1.661 3.419-1.934 6.188-7.956 2.215-4.638 4.233-6.674 4.35-13.771 0.161-6.915-1.809-9.972-4.854-13.568-3.567-3.746-8.134-3.654-11.23-3.195-2.138 0.259-4.527 2.094-6.345 4.847-1.564 1.983-2.378 5.115-2.447 8.368-0.188 8.149 0.767 11.47 2.523 17.026 2.079 6.54 7.8 9.841 11.815 8.249z"/> + <path fill="#9b9b9b" d="m148.472 93.863c4.125-1.65 3.391-1.93 6.141-7.912 2.2-4.607 4.217-6.637 4.366-13.693 0.188-6.868-1.739-10.026-4.729-13.441-3.621-3.626-8.085-3.484-11.157-3.044-2.183 0.253-4.562 1.999-6.406 4.622-1.646 1.918-2.45 5.068-2.52 8.335-0.185 8.091 0.811 11.426 2.535 16.948 2.044 6.502 7.782 9.766 11.77 8.185z"/> + <path fill="#a3a3a3" d="m148.472 93.836c4.097-1.639 3.361-1.926 6.094-7.867 2.185-4.576 4.201-6.599 4.382-13.614 0.214-6.82-1.669-10.081-4.603-13.315-3.676-3.506-8.036-3.313-11.084-2.893-2.229 0.249-4.598 1.904-6.47 4.398-1.726 1.852-2.521 5.021-2.591 8.301-0.18 8.034 0.854 11.382 2.548 16.87 2.008 6.465 7.763 9.691 11.724 8.12z"/> + <path fill="#aaa" d="m148.472 93.809c4.069-1.628 3.334-1.922 6.047-7.823 2.17-4.544 4.185-6.562 4.396-13.536 0.242-6.772-1.597-10.134-4.475-13.188-3.73-3.387-7.989-3.142-11.013-2.741-2.271 0.243-4.632 1.809-6.53 4.173-1.808 1.787-2.594 4.974-2.662 8.268-0.176 7.976 0.897 11.337 2.56 16.792 1.97 6.427 7.743 9.615 11.677 8.055z"/> + <path fill="#b2b2b2" d="m148.473 93.782c4.041-1.617 3.304-1.918 5.999-7.778 2.154-4.514 4.169-6.524 4.412-13.458 0.269-6.725-1.526-10.188-4.349-13.062-3.784-3.267-7.939-2.971-10.939-2.589-2.316 0.238-4.666 1.714-6.592 3.949-1.888 1.721-2.667 4.926-2.734 8.234-0.171 7.918 0.941 11.293 2.572 16.713 1.933 6.391 7.723 9.541 11.631 7.991z"/> + <path fill="#bababa" d="m148.473 93.756c4.014-1.606 3.275-1.914 5.951-7.734 2.141-4.482 4.153-6.487 4.43-13.379 0.295-6.678-1.457-10.243-4.223-12.935-3.839-3.147-7.892-2.8-10.867-2.438-2.36 0.233-4.701 1.619-6.653 3.725-1.969 1.656-2.739 4.879-2.806 8.201-0.167 7.86 0.984 11.249 2.585 16.636 1.895 6.35 7.702 9.462 11.583 7.924z"/> + <path fill="#c1c1c1" d="m148.473 93.729c3.985-1.595 3.247-1.91 5.904-7.69 2.125-4.451 4.138-6.45 4.445-13.3 0.321-6.63-1.387-10.297-4.096-12.808-3.894-3.028-7.844-2.629-10.795-2.287-2.405 0.229-4.735 1.524-6.716 3.5-2.049 1.59-2.811 4.831-2.878 8.167-0.161 7.802 1.029 11.205 2.599 16.557 1.859 6.314 7.683 9.389 11.537 7.861z"/> + <path fill="#c9c9c9" d="m148.473 93.702c3.958-1.583 3.219-1.906 5.857-7.646 2.11-4.42 4.121-6.412 4.46-13.222 0.35-6.583-1.315-10.351-3.969-12.682-3.947-2.908-7.794-2.458-10.722-2.135-2.45 0.224-4.771 1.429-6.777 3.276-2.13 1.525-2.883 4.784-2.95 8.135-0.157 7.745 1.073 11.16 2.611 16.479 1.821 6.276 7.663 9.313 11.49 7.795z"/> + <path fill="#d1d1d1" d="m148.474 93.676c3.93-1.573 3.188-1.902 5.809-7.601 2.097-4.389 4.107-6.375 4.477-13.144 0.375-6.535-1.245-10.404-3.842-12.555-4.002-2.788-7.747-2.287-10.65-1.984-2.493 0.219-4.805 1.334-6.837 3.052-2.213 1.459-2.957 4.736-3.022 8.101-0.153 7.687 1.116 11.116 2.623 16.401 1.782 6.237 7.642 9.237 11.442 7.73z"/> + <path fill="#d8d8d8" d="m148.474 93.649c3.901-1.562 3.16-1.898 5.762-7.557 2.082-4.358 4.091-6.338 4.493-13.065 0.401-6.487-1.176-10.458-3.716-12.428-4.057-2.668-7.698-2.116-10.578-1.832-2.538 0.214-4.839 1.239-6.899 2.827-2.292 1.394-3.029 4.689-3.094 8.068-0.148 7.629 1.16 11.072 2.636 16.322 1.746 6.2 7.623 9.161 11.396 7.665z"/> + <path fill="#e0e0e0" d="m148.474 93.622c3.875-1.55 3.132-1.894 5.715-7.512 2.066-4.327 4.075-6.3 4.508-12.987 0.429-6.44-1.104-10.513-3.588-12.302-4.111-2.549-7.65-1.945-10.506-1.681-2.582 0.209-4.874 1.144-6.961 2.604-2.373 1.328-3.102 4.642-3.165 8.034-0.145 7.571 1.204 11.027 2.647 16.244 1.709 6.162 7.604 9.086 11.35 7.6z"/> + <path fill="#e8e8e8" d="m148.474 93.596c3.847-1.54 3.104-1.89 5.668-7.468 2.052-4.296 4.059-6.263 4.523-12.908 0.456-6.393-1.034-10.567-3.462-12.175-4.165-2.429-7.601-1.774-10.433-1.529-2.627 0.204-4.908 1.049-7.023 2.379-2.453 1.263-3.173 4.594-3.236 8.001-0.141 7.514 1.247 10.983 2.659 16.166 1.673 6.123 7.585 9.008 11.304 7.534z"/> + <path fill="#efefef" d="m148.475 93.569c3.817-1.528 3.073-1.886 5.62-7.424 2.036-4.265 4.043-6.226 4.539-12.83 0.482-6.345-0.964-10.621-3.336-12.048-4.219-2.31-7.552-1.604-10.359-1.378-2.672 0.199-4.943 0.954-7.084 2.155-2.535 1.197-3.246 4.546-3.311 7.967-0.135 7.456 1.292 10.939 2.673 16.087 1.636 6.087 7.565 8.935 11.258 7.471z"/> + <path fill="#f7f7f7" d="m148.475 93.542c3.791-1.517 3.046-1.882 5.572-7.379 2.022-4.234 4.027-6.188 4.556-12.751 0.51-6.297-0.894-10.675-3.208-11.921-4.274-2.19-7.505-1.433-10.289-1.227-2.715 0.194-4.978 0.859-7.146 1.93-2.614 1.132-3.317 4.5-3.381 7.935-0.131 7.398 1.335 10.895 2.686 16.009 1.597 6.047 7.544 8.858 11.21 7.404z"/> + <path fill="#fff" d="m148.475 93.516c3.763-1.506 3.017-1.878 5.525-7.335 2.007-4.203 4.012-6.151 4.571-12.673 0.536-6.25-0.823-10.729-3.082-11.795-4.328-2.07-7.456-1.262-10.216-1.075-2.76 0.189-5.012 0.764-7.207 1.706-2.696 1.066-3.39 4.452-3.453 7.901-0.126 7.34 1.379 10.85 2.698 15.931 1.561 6.01 7.525 8.782 11.164 7.34z"/> + </g> + <path d="m132.033 74.7465c2.16 0 4.896 1.44 6.191 3.384 1.368 1.944 2.376 4.68 2.376 7.776 0 4.608-0.504 9.72-3.239 11.304-0.864 0.504-2.736 0.936-3.816 0.936-2.448 0-2.664-1.584-4.968-3.96-0.792-0.864-3.168-5.04-3.168-8.496 0-2.16-0.504-5.256 1.368-7.992 1.296-2.016 2.952-2.952 5.256-2.952z"/> + <g transform="translate(-12.4048,10.0005)"> + <path d="m143.862 68.608c0.844-1.305 4.222-0.69 5.45 1.996 1.229 2.687 0.998 8.522 0.153 8.829-2.226 0.691-1.535-2.534-3.454-5.451-1.919-2.762-2.994-4.067-2.149-5.374z"/> + <path fill="#070707" d="m143.916 68.664c0.833-1.289 4.169-0.681 5.381 1.971 1.215 2.653 0.985 8.414 0.152 8.717-2.198 0.682-1.516-2.502-3.411-5.382-1.895-2.728-2.956-4.017-2.122-5.306z"/> + <path fill="#0f0f0f" d="m143.97 68.719c0.822-1.272 4.114-0.673 5.312 1.945 1.198 2.619 0.973 8.306 0.15 8.605-2.169 0.673-1.497-2.47-3.367-5.313-1.871-2.692-2.918-3.964-2.095-5.237z"/> + <path fill="#161616" d="m144.024 68.774c0.812-1.255 4.062-0.664 5.243 1.92 1.182 2.585 0.96 8.198 0.147 8.493-2.141 0.665-1.477-2.438-3.323-5.244-1.846-2.657-2.88-3.913-2.067-5.169z"/> + <path fill="#1e1e1e" d="m144.078 68.829c0.801-1.239 4.008-0.655 5.174 1.895 1.167 2.551 0.947 8.09 0.146 8.381-2.113 0.656-1.458-2.405-3.28-5.174-1.821-2.623-2.842-3.863-2.04-5.102z"/> + <path fill="#262626" d="m144.132 68.884c0.791-1.222 3.955-0.646 5.105 1.87 1.151 2.517 0.935 7.982 0.144 8.27-2.085 0.647-1.438-2.374-3.235-5.105-1.798-2.589-2.805-3.812-2.014-5.035z"/> + <path fill="#2d2d2d" d="m144.186 68.939c0.779-1.206 3.9-0.638 5.036 1.844 1.135 2.483 0.922 7.874 0.142 8.158-2.057 0.639-1.419-2.341-3.192-5.037-1.773-2.552-2.766-3.758-1.986-4.965z"/> + <path fill="#353535" d="m144.24 68.994c0.769-1.189 3.848-0.629 4.967 1.819 1.12 2.449 0.909 7.766 0.141 8.046-2.028 0.629-1.399-2.31-3.148-4.967-1.75-2.518-2.73-3.708-1.96-4.898z"/> + <path fill="#3d3d3d" d="m144.294 69.049c0.76-1.172 3.794-0.621 4.898 1.793 1.104 2.415 0.896 7.658 0.138 7.934-2 0.621-1.38-2.277-3.104-4.898-1.725-2.482-2.691-3.655-1.932-4.829z"/> + <path fill="#444" d="m144.348 69.104c0.748-1.156 3.74-0.612 4.829 1.768 1.088 2.38 0.884 7.55 0.136 7.822-1.973 0.612-1.36-2.245-3.062-4.829-1.699-2.448-2.651-3.604-1.903-4.761z"/> + <path fill="#4c4c4c" d="m144.402 69.16c0.737-1.14 3.687-0.603 4.76 1.743 1.073 2.347 0.871 7.442 0.134 7.71-1.943 0.604-1.341-2.213-3.017-4.76-1.676-2.414-2.614-3.554-1.877-4.693z"/> + <path fill="#545454" d="m144.456 69.215c0.727-1.123 3.634-0.595 4.691 1.717 1.057 2.313 0.857 7.334 0.132 7.598-1.916 0.595-1.321-2.181-2.973-4.691-1.652-2.378-2.577-3.501-1.85-4.624z"/> + <path fill="#5b5b5b" d="m144.51 69.27c0.717-1.106 3.58-0.585 4.622 1.692 1.041 2.278 0.847 7.226 0.131 7.486-1.888 0.586-1.303-2.149-2.93-4.622-1.628-2.343-2.539-3.45-1.823-4.556z"/> + <path fill="#636363" d="m144.564 69.325c0.705-1.09 3.526-0.577 4.553 1.667 1.026 2.245 0.833 7.118 0.128 7.375-1.858 0.577-1.282-2.117-2.885-4.553-1.604-2.309-2.501-3.399-1.796-4.489z"/> + <path fill="#6b6b6b" d="m144.618 69.38c0.694-1.073 3.473-0.568 4.483 1.642 1.011 2.21 0.82 7.01 0.127 7.263-1.831 0.568-1.264-2.084-2.842-4.484-1.578-2.274-2.462-3.347-1.768-4.421z"/> + <path fill="#727272" d="m144.672 69.435c0.685-1.057 3.42-0.56 4.414 1.617 0.995 2.176 0.81 6.902 0.125 7.15-1.803 0.56-1.243-2.053-2.798-4.415-1.554-2.238-2.425-3.295-1.741-4.352z"/> + <path fill="#7a7a7a" d="m144.726 69.49c0.673-1.041 3.365-0.551 4.345 1.591 0.979 2.143 0.796 6.794 0.123 7.039-1.775 0.551-1.224-2.021-2.754-4.346-1.53-2.203-2.387-3.244-1.714-4.284z"/> + <path fill="#828282" d="m144.78 69.545c0.662-1.023 3.313-0.542 4.276 1.566 0.964 2.108 0.782 6.686 0.121 6.926-1.746 0.542-1.204-1.988-2.711-4.276-1.505-2.167-2.348-3.192-1.686-4.216z"/> + <path fill="#898989" d="m144.834 69.6c0.652-1.007 3.259-0.533 4.207 1.541s0.771 6.578 0.119 6.815c-1.718 0.534-1.185-1.956-2.666-4.207-1.482-2.134-2.311-3.142-1.66-4.149z"/> + <path fill="#919191" d="m144.888 69.655c0.641-0.99 3.206-0.524 4.138 1.516 0.933 2.04 0.758 6.47 0.117 6.703-1.69 0.525-1.165-1.924-2.623-4.138-1.457-2.098-2.273-3.09-1.632-4.081z"/> + <path fill="#999" d="m144.942 69.71c0.63-0.974 3.152-0.516 4.069 1.49s0.744 6.362 0.114 6.591c-1.662 0.516-1.146-1.892-2.579-4.069-1.432-2.062-2.234-3.037-1.604-4.012z"/> + </g> + <g transform="translate(-12.4048,10.0005)"> + <path fill="#666" d="m193.11 94.985c10.8-1.152 14.616-5.328 16.56-12.6 1.729-6.48 1.801-13.68-3.023-22.104-4.536-8.063-7.128-9.36-13.681-9.864-10.079-0.864-14.832 6.192-17.063 11.232-2.376 5.472-1.872 4.68-1.729 11.592 0.145 7.272 4.245 9.299 6.766 13.835 2.519 4.465 10.946 7.982 12.17 7.909z"/> + <path fill="#6d6d6d" d="m193.115 94.944c10.759-1.131 14.618-5.354 16.515-12.569 1.701-6.525 1.785-13.686-3.002-21.912-4.434-7.797-7.038-9.081-13.512-9.581-10.049-0.861-14.941 5.873-17.181 10.874-2.304 5.28-1.878 4.718-1.726 11.539 0.16 7.268 4.268 9.223 6.784 13.76 2.521 4.475 10.898 7.962 12.122 7.889z"/> + <path fill="#757575" d="m193.12 94.902c10.718-1.11 14.62-5.379 16.469-12.538 1.676-6.57 1.771-13.692-2.979-21.721-4.331-7.53-6.947-8.801-13.344-9.297-10.018-0.858-15.05 5.553-17.298 10.516-2.229 5.087-1.885 4.757-1.722 11.487 0.176 7.264 4.289 9.146 6.803 13.686 2.52 4.485 10.848 7.942 12.071 7.867z"/> + <path fill="#7c7c7c" d="m193.126 94.861c10.675-1.09 14.621-5.405 16.423-12.507 1.648-6.616 1.756-13.698-2.958-21.529-4.229-7.263-6.856-8.522-13.176-9.014-9.985-0.854-15.158 5.234-17.414 10.158-2.156 4.895-1.891 4.795-1.719 11.434 0.193 7.26 4.31 9.07 6.822 13.611 2.52 4.495 10.798 7.922 12.022 7.847z"/> + <path fill="#848484" d="m193.131 94.82c10.635-1.069 14.623-5.431 16.377-12.476 1.622-6.661 1.741-13.704-2.936-21.337-4.126-6.996-6.767-8.242-13.008-8.73-9.955-0.852-15.267 4.915-17.53 9.8-2.084 4.703-1.896 4.833-1.716 11.38 0.209 7.256 4.332 8.995 6.841 13.537 2.52 4.505 10.748 7.902 11.972 7.826z"/> + <path fill="#8c8c8c" d="m193.136 94.778c10.593-1.048 14.625-5.457 16.331-12.445 1.596-6.706 1.726-13.709-2.913-21.145-4.025-6.729-6.678-7.963-12.841-8.447-9.924-0.848-15.375 4.595-17.647 9.441-2.01 4.51-1.903 4.872-1.712 11.328 0.225 7.251 4.354 8.918 6.858 13.462 2.521 4.517 10.7 7.883 11.924 7.806z"/> + <path fill="#939393" d="m193.141 94.737c10.552-1.027 14.627-5.482 16.286-12.414 1.568-6.751 1.711-13.715-2.893-20.954-3.922-6.462-6.586-7.683-12.672-8.163-9.892-0.845-15.483 4.276-17.764 9.083-1.938 4.318-1.909 4.91-1.709 11.275 0.24 7.247 4.375 8.842 6.878 13.387 2.521 4.528 10.651 7.863 11.874 7.786z"/> + <path fill="#9b9b9b" d="m193.146 94.695c10.51-1.007 14.63-5.508 16.241-12.382 1.542-6.796 1.694-13.721-2.87-20.762-3.82-6.195-6.496-7.404-12.504-7.879-9.861-0.842-15.592 3.956-17.882 8.725-1.863 4.126-1.915 4.949-1.706 11.223 0.258 7.243 4.397 8.766 6.897 13.313 2.521 4.535 10.601 7.841 11.824 7.762z"/> + <path fill="#a3a3a3" d="m193.151 94.654c10.469-0.986 14.632-5.534 16.196-12.351 1.515-6.842 1.68-13.727-2.85-20.57-3.717-5.928-6.405-7.125-12.335-7.596-9.83-0.839-15.7 3.637-17.998 8.367-1.791 3.933-1.922 4.987-1.703 11.169 0.273 7.239 4.419 8.689 6.916 13.238 2.521 4.547 10.551 7.822 11.774 7.743z"/> + <path fill="#aaa" d="m193.157 94.612c10.427-0.965 14.633-5.56 16.149-12.32 1.488-6.887 1.666-13.733-2.826-20.379-3.615-5.661-6.316-6.845-12.168-7.313-9.799-0.835-15.809 3.317-18.114 8.009-1.718 3.741-1.928 5.025-1.7 11.117 0.29 7.235 4.44 8.613 6.936 13.163 2.519 4.558 10.499 7.804 11.723 7.723z"/> + <path fill="#b2b2b2" d="m193.162 94.571c10.386-0.944 14.635-5.585 16.104-12.289 1.462-6.932 1.649-13.739-2.806-20.188-3.512-5.394-6.225-6.565-11.999-7.029-9.768-0.833-15.917 2.998-18.23 7.651-1.646 3.549-1.935 5.064-1.697 11.064 0.306 7.231 4.462 8.537 6.954 13.088 2.52 4.569 10.451 7.784 11.674 7.703z"/> + <path fill="#bababa" d="m193.167 94.529c10.345-0.923 14.638-5.611 16.059-12.258 1.436-6.977 1.636-13.744-2.782-19.995-3.41-5.127-6.135-6.286-11.832-6.746-9.736-0.829-16.025 2.679-18.347 7.293-1.572 3.356-1.941 5.103-1.694 11.011 0.322 7.227 4.484 8.461 6.973 13.014 2.519 4.579 10.4 7.764 11.623 7.681z"/> + <path fill="#c1c1c1" d="m193.172 94.488c10.304-0.903 14.64-5.637 16.014-12.227 1.409-7.022 1.62-13.75-2.762-19.804-3.308-4.86-6.044-6.006-11.662-6.462-9.705-0.826-16.135 2.359-18.466 6.935-1.498 3.164-1.945 5.141-1.689 10.958 0.338 7.223 4.506 8.385 6.991 12.939 2.519 4.59 10.351 7.744 11.574 7.661z"/> + <path fill="#c9c9c9" d="m193.177 94.447c10.262-0.882 14.641-5.663 15.967-12.196 1.383-7.068 1.605-13.756-2.738-19.612-3.206-4.593-5.954-5.727-11.496-6.179-9.673-0.823-16.242 2.04-18.581 6.577-1.425 2.972-1.952 5.179-1.687 10.906 0.354 7.219 4.526 8.308 7.01 12.865 2.52 4.598 10.302 7.723 11.525 7.639z"/> + <path fill="#d1d1d1" d="m193.182 94.405c10.221-0.861 14.643-5.688 15.922-12.165 1.355-7.113 1.591-13.762-2.717-19.42-3.104-4.326-5.864-5.448-11.327-5.895-9.644-0.82-16.352 1.721-18.698 6.219-1.353 2.779-1.959 5.217-1.684 10.853 0.369 7.214 4.549 8.232 7.028 12.79 2.521 4.609 10.254 7.703 11.476 7.618z"/> + <path fill="#d8d8d8" d="m193.187 94.364c10.179-0.841 14.645-5.714 15.876-12.133 1.33-7.158 1.576-13.768-2.694-19.229-3.001-4.059-5.773-5.168-11.16-5.612-9.61-0.817-16.459 1.401-18.813 5.861-1.279 2.586-1.965 5.256-1.682 10.8 0.387 7.21 4.571 8.156 7.049 12.715 2.519 4.619 10.202 7.684 11.424 7.598z"/> + <path fill="#e0e0e0" d="m193.193 94.322c10.137-0.82 14.646-5.74 15.83-12.103 1.303-7.203 1.561-13.773-2.673-19.037-2.898-3.792-5.684-4.889-10.991-5.328-9.58-0.813-16.568 1.082-18.931 5.502-1.206 2.395-1.972 5.294-1.679 10.747 0.403 7.207 4.592 8.08 7.067 12.641 2.521 4.631 10.154 7.666 11.377 7.578z"/> + <path fill="#e8e8e8" d="m193.198 94.281c10.096-0.799 14.648-5.766 15.785-12.071 1.275-7.249 1.545-13.779-2.651-18.845-2.796-3.525-5.593-4.609-10.823-5.044-9.549-0.81-16.677 0.762-19.048 5.145-1.133 2.202-1.978 5.333-1.675 10.694 0.419 7.202 4.614 8.003 7.086 12.566 2.52 4.638 10.103 7.643 11.326 7.555z"/> + <path fill="#efefef" d="m193.203 94.239c10.055-0.778 14.65-5.792 15.739-12.04 1.25-7.293 1.531-13.785-2.629-18.653-2.694-3.258-5.502-4.33-10.655-4.761-9.517-0.807-16.785 0.443-19.165 4.786-1.059 2.01-1.983 5.372-1.671 10.642 0.435 7.198 4.636 7.928 7.104 12.492 2.52 4.649 10.055 7.624 11.277 7.534z"/> + <path fill="#f7f7f7" d="m193.208 94.198c10.014-0.757 14.652-5.817 15.694-12.009 1.223-7.339 1.516-13.792-2.607-18.462-2.592-2.991-5.413-4.05-10.486-4.478-9.487-0.804-16.895 0.124-19.282 4.428-0.986 1.817-1.989 5.41-1.668 10.589 0.451 7.194 4.657 7.851 7.123 12.417 2.519 4.661 10.004 7.605 11.226 7.515z"/> + <path fill="#fff" d="m193.213 94.156c9.973-0.737 14.654-5.843 15.648-11.978 1.197-7.384 1.501-13.797-2.585-18.27-2.489-2.724-5.322-3.771-10.319-4.194-9.455-0.801-17.002-0.196-19.397 4.07-0.913 1.625-1.996 5.448-1.665 10.536 0.467 7.19 4.679 7.775 7.142 12.342 2.519 4.671 9.954 7.586 11.176 7.494z"/> + </g> + <path d="m179.841 74.4585c5.4 0 8.568 4.824 9.648 11.016 0.432 2.808-0.216 6.048-1.944 8.28-1.944 2.592-5.4 4.176-8.208 4.176-2.664 0-5.688 0.432-7.271-1.728-1.584-2.232-1.944-7.2-1.944-10.728 0-3.96 1.152-6.768 3.168-9 1.511-1.657 4.247-2.016 6.551-2.016z"/> + <g transform="translate(-12.4048,10.0005)"> + <path d="m192.591 66.68c0.98-0.653 2.612 0 4.489 2.122 2.039 2.285 2.938 4.08 0.489 5.385-1.877 0.98-2.448-1.958-3.59-3.182-1.795-1.959-3.346-3.02-1.388-4.325z"/> + <path fill="#070707" d="m192.631 66.738c0.96-0.649 2.573 0 4.423 2.09 2.009 2.251 2.864 4.02 0.481 5.305-1.837 0.977-2.403-1.929-3.525-3.135-1.768-1.925-3.296-2.965-1.379-4.26z"/> + <path fill="#0f0f0f" d="m192.671 66.797c0.939-0.645 2.534 0 4.356 2.059 1.978 2.217 2.792 3.958 0.474 5.225-1.798 0.974-2.357-1.9-3.46-3.087-1.742-1.895-3.247-2.913-1.37-4.197z"/> + <path fill="#161616" d="m192.711 66.855c0.919-0.641 2.495 0 4.289 2.027 1.948 2.184 2.721 3.898 0.467 5.146-1.759 0.971-2.313-1.871-3.396-3.041-1.715-1.861-3.197-2.858-1.36-4.132z"/> + <path fill="#1e1e1e" d="m192.751 66.914c0.899-0.637 2.457 0 4.223 1.996 1.918 2.149 2.647 3.838 0.46 5.065-1.72 0.968-2.269-1.842-3.331-2.993-1.689-1.83-3.148-2.805-1.352-4.068z"/> + <path fill="#262626" d="m192.791 66.973c0.878-0.633 2.418 0 4.155 1.964 1.888 2.116 2.576 3.777 0.453 4.986-1.68 0.965-2.224-1.813-3.267-2.946-1.661-1.798-3.097-2.752-1.341-4.004z"/> + <path fill="#2d2d2d" d="m192.831 67.031c0.858-0.629 2.379 0 4.089 1.933 1.857 2.082 2.503 3.717 0.445 4.906-1.641 0.961-2.178-1.784-3.201-2.898-1.636-1.767-3.048-2.7-1.333-3.941z"/> + <path fill="#353535" d="m192.87 67.09c0.838-0.625 2.341 0 4.023 1.902 1.827 2.047 2.431 3.656 0.438 4.826-1.601 0.958-2.133-1.755-3.137-2.852-1.608-1.735-2.998-2.646-1.324-3.876z"/> + <path fill="#3d3d3d" d="m192.91 67.148c0.818-0.621 2.302 0 3.956 1.87 1.797 2.014 2.359 3.596 0.431 4.746-1.562 0.956-2.088-1.726-3.071-2.804-1.583-1.702-2.95-2.592-1.316-3.812z"/> + <path fill="#444" d="m192.95 67.207c0.798-0.617 2.263 0 3.889 1.839 1.768 1.98 2.287 3.535 0.425 4.666-1.523 0.952-2.043-1.697-3.008-2.757-1.556-1.671-2.899-2.539-1.306-3.748z"/> + <path fill="#4c4c4c" d="m192.99 67.266c0.777-0.614 2.224 0 3.823 1.807 1.735 1.946 2.214 3.474 0.416 4.586-1.483 0.949-1.998-1.667-2.942-2.709-1.529-1.639-2.85-2.486-1.297-3.684z"/> + <path fill="#545454" d="m193.03 67.325c0.757-0.61 2.185 0 3.756 1.775 1.706 1.912 2.143 3.414 0.409 4.506-1.444 0.946-1.953-1.639-2.878-2.663-1.502-1.606-2.799-2.431-1.287-3.618z"/> + <path fill="#5b5b5b" d="m193.07 67.383c0.736-0.605 2.146 0 3.688 1.744 1.677 1.878 2.07 3.353 0.402 4.426-1.405 0.943-1.908-1.609-2.813-2.615-1.475-1.575-2.749-2.378-1.277-3.555z"/> + <path fill="#636363" d="m193.11 67.442c0.716-0.602 2.106 0 3.622 1.712 1.646 1.844 1.998 3.293 0.395 4.347-1.364 0.94-1.862-1.581-2.748-2.568-1.449-1.543-2.701-2.326-1.269-3.491z"/> + <path fill="#6b6b6b" d="m193.15 67.5c0.696-0.598 2.069 0 3.556 1.681 1.615 1.811 1.925 3.232 0.387 4.267-1.325 0.937-1.818-1.552-2.683-2.521-1.423-1.511-2.651-2.272-1.26-3.427z"/> + <path fill="#727272" d="m193.19 67.559c0.675-0.594 2.03 0 3.489 1.649 1.585 1.777 1.853 3.172 0.38 4.187-1.287 0.935-1.774-1.522-2.619-2.473-1.396-1.48-2.601-2.219-1.25-3.363z"/> + <path fill="#7a7a7a" d="m193.23 67.618c0.654-0.59 1.991 0 3.422 1.618 1.555 1.743 1.781 3.111 0.373 4.107-1.247 0.931-1.729-1.494-2.554-2.426-1.369-1.448-2.551-2.166-1.241-3.299z"/> + <path fill="#828282" d="m193.269 67.677c0.635-0.586 1.953 0 3.355 1.586 1.525 1.708 1.709 3.05 0.366 4.026-1.208 0.928-1.684-1.464-2.489-2.378-1.342-1.416-2.501-2.112-1.232-3.234z"/> + <path fill="#898989" d="m193.309 67.735c0.614-0.582 1.914 0 3.29 1.555 1.493 1.675 1.636 2.99 0.357 3.947-1.169 0.925-1.639-1.435-2.424-2.332-1.316-1.384-2.452-2.058-1.223-3.17z"/> + <path fill="#919191" d="m193.349 67.794c0.595-0.578 1.875 0 3.223 1.523 1.464 1.641 1.564 2.93 0.351 3.867-1.129 0.922-1.594-1.406-2.359-2.284-1.29-1.352-2.403-2.005-1.215-3.106z"/> + <path fill="#999" d="m193.389 67.853c0.573-0.574 1.836 0 3.155 1.492 1.435 1.607 1.492 2.869 0.345 3.787-1.091 0.919-1.55-1.377-2.295-2.237-1.263-1.32-2.353-1.953-1.205-3.042z"/> + </g> + <g transform="translate(-12.4048,10.0005)"> + <path d="m165.498 69.906c1.693-0.654 3.012-0.69 5.63 1.036 3.166 2.088 1.705 5.245-0.779 4.601-2.146-0.556-2.417-0.681-4.391-1.086-3.101-0.648-3.641-3.322-0.46-4.551z"/> + <path fill="#050505" d="m165.564 70.033c1.658-0.629 2.973-0.656 5.555 1.026 3.066 2.009 1.654 5.012-0.805 4.38-2.131-0.547-2.345-0.656-4.284-1.052-3.055-0.634-3.587-3.173-0.466-4.354z"/> + <path fill="#0a0a0a" d="m165.63 70.16c1.623-0.604 2.935-0.622 5.481 1.015 2.965 1.93 1.602 4.779-0.83 4.159-2.119-0.539-2.274-0.63-4.179-1.018-3.009-0.618-3.533-3.022-0.472-4.156z"/> + <path fill="#0f0f0f" d="m165.696 70.287c1.587-0.579 2.895-0.587 5.406 1.005 2.864 1.851 1.551 4.546-0.855 3.938-2.105-0.53-2.203-0.605-4.073-0.983-2.963-0.604-3.48-2.873-0.478-3.96z"/> + <path fill="#141414" d="m165.761 70.413c1.553-0.553 2.856-0.553 5.331 0.995 2.766 1.772 1.5 4.313-0.88 3.717-2.092-0.521-2.131-0.58-3.967-0.949-2.916-0.588-3.425-2.723-0.484-3.763z"/> + <path fill="#191919" d="m165.827 70.54c1.519-0.528 2.818-0.519 5.258 0.984 2.664 1.693 1.448 4.079-0.905 3.497-2.079-0.513-2.06-0.554-3.861-0.915-2.873-0.573-3.373-2.573-0.492-3.566z"/> + <path fill="#1e1e1e" d="m165.893 70.667c1.482-0.503 2.778-0.484 5.183 0.974 2.564 1.614 1.397 3.846-0.93 3.276-2.067-0.504-1.989-0.529-3.756-0.88-2.826-0.559-3.319-2.425-0.497-3.37z"/> + <path fill="#232323" d="m165.959 70.793c1.447-0.478 2.74-0.45 5.108 0.964 2.464 1.535 1.345 3.613-0.955 3.055-2.053-0.496-1.917-0.503-3.651-0.846-2.779-0.543-3.264-2.274-0.502-3.173z"/> + <path fill="#282828" d="m166.025 70.92c1.412-0.453 2.701-0.416 5.034 0.954 2.362 1.456 1.293 3.38-0.981 2.834-2.04-0.487-1.845-0.478-3.545-0.812-2.733-0.528-3.21-2.125-0.508-2.976z"/> + <path fill="#2d2d2d" d="m166.09 71.047c1.378-0.428 2.663-0.382 4.96 0.943 2.264 1.377 1.242 3.146-1.006 2.613-2.026-0.478-1.773-0.453-3.438-0.777-2.688-0.513-3.158-1.974-0.516-2.779z"/> + <path fill="#333" d="m166.156 71.173c1.343-0.402 2.624-0.347 4.885 0.933 2.163 1.298 1.191 2.914-1.029 2.392-2.015-0.47-1.703-0.428-3.334-0.743-2.642-0.498-3.104-1.824-0.522-2.582z"/> + <path fill="#383838" d="m166.222 71.3c1.307-0.377 2.585-0.313 4.81 0.922 2.063 1.219 1.14 2.681-1.055 2.171-2.001-0.461-1.631-0.402-3.229-0.708-2.594-0.483-3.048-1.674-0.526-2.385z"/> + <path fill="#3d3d3d" d="m166.288 71.427c1.272-0.352 2.546-0.279 4.736 0.913 1.962 1.14 1.088 2.447-1.081 1.95-1.988-0.452-1.56-0.377-3.122-0.674-2.55-0.469-2.995-1.526-0.533-2.189z"/> + <path fill="#424242" d="m166.354 71.554c1.236-0.327 2.507-0.245 4.661 0.902 1.861 1.061 1.037 2.214-1.106 1.729-1.974-0.444-1.488-0.352-3.016-0.64-2.504-0.453-2.942-1.375-0.539-1.991z"/> + <path fill="#474747" d="m166.419 71.68c1.203-0.302 2.469-0.21 4.587 0.892 1.762 0.982 0.986 1.98-1.13 1.508-1.962-0.435-1.417-0.326-2.911-0.606-2.458-0.437-2.888-1.224-0.546-1.794z"/> + <path fill="#4c4c4c" d="m166.485 71.807c1.167-0.276 2.429-0.176 4.513 0.882 1.66 0.903 0.935 1.748-1.156 1.288-1.948-0.426-1.345-0.301-2.805-0.572-2.412-0.423-2.834-1.076-0.552-1.598z"/> + <path fill="#515151" d="m166.551 71.934c1.133-0.251 2.391-0.142 4.438 0.871 1.56 0.824 0.883 1.515-1.181 1.067-1.936-0.417-1.274-0.275-2.699-0.537-2.366-0.408-2.781-0.926-0.558-1.401z"/> + <path fill="#565656" d="m166.617 72.061c1.097-0.227 2.351-0.108 4.363 0.861 1.46 0.745 0.831 1.281-1.206 0.846-1.922-0.409-1.202-0.25-2.594-0.503-2.319-0.393-2.726-0.777-0.563-1.204z"/> + <path fill="#5b5b5b" d="m166.683 72.187c1.062-0.201 2.312-0.073 4.289 0.851 1.358 0.666 0.778 1.048-1.231 0.625-1.91-0.4-1.131-0.225-2.489-0.469-2.274-0.377-2.672-0.626-0.569-1.007z"/> + <path fill="#606060" d="m166.748 72.314c1.027-0.176 2.274-0.04 4.215 0.84 1.26 0.587 0.729 0.815-1.256 0.404-1.896-0.392-1.06-0.2-2.383-0.435-2.228-0.361-2.619-0.475-0.576-0.809z"/> + <path fill="#666" d="m166.814 72.44c0.992-0.151 2.234-0.005 4.14 0.83 1.159 0.508 0.677 0.582-1.281 0.183-1.883-0.383-0.987-0.174-2.276-0.4-2.183-0.346-2.566-0.325-0.583-0.613z"/> + </g> + <g transform="translate(-12.4048,10.0005)"> + <path fill="#666" d="m159.99 128.249c-9.36 0.36-24.192-25.848-24.552-14.976-0.288 9.216 0.216 9.072 0.216 18 0 5.976-2.736 6.408-8.64 15.408-3.024 4.752-5.4 9.864-7.272 15.048-1.152 3.096-2.232 6.336-3.096 9.504-0.36 1.584-1.008 3.24-1.368 4.824-2.952 10.872-13.464 24.264-15.912 35.136-2.448 10.8-5.328 17.712-4.968 32.185 0.36 14.472 0.504 10.295 4.896 13.896 4.32 3.601 8.784 6.983 15.624 13.032 7.2 6.264 22.177 17.208 24.192 20.592 2.16 3.456 2.088 11.232 0.792 13.752-1.296 2.448-12.6 3.816-12.528 3.816-0.071 0 9.864 13.68 11.809 15.623 1.872 1.873 9.936 10.873 42.768 4.752 18.504-3.455 32.832-13.823 43.2-23.832 13.392-13.031 6.624-16.775 8.352-23.327 2.521-9.433 10.729-12.96 12.601-23.616 0.216-1.512 0.72-2.664 2.088-4.896 2.088-3.168 1.584-9.432 1.584-15.191 0-14.977-1.729-30.24-5.185-41.472-3.168-10.512-8.208-17.856-12.527-27.36-8.641-18.936-8.208-27.432-15.912-39.528-8.784-13.968-4.464-23.256-16.128-22.68-14.546 0.79-26.282 20.734-40.034 21.31z"/> + <path fill="#6d6d6d" d="m159.973 129.334c-9.281 0.353-23.746-25.511-24.242-15.179-0.316 8.755 0.1 8.678 0.03 17.247-0.15 5.87-2.953 6.637-8.727 15.481-3.013 4.763-5.273 9.812-6.993 14.877-0.968 3.253-1.56 6.422-2.43 9.526-0.415 1.642-1.497 3.187-2.185 5.042-3.254 10.78-13.545 24.182-15.961 34.877-2.466 10.81-5.37 17.694-4.961 32.141 0.366 14 0.395 10.177 4.773 13.816 4.283 3.616 8.839 7.069 15.662 13.103 7.183 6.248 22.237 17.216 24.243 20.588 2.149 3.444 2.131 11.317 0.844 13.823-1.284 2.439-12.579 3.875-12.508 3.875-0.071 0 9.815 13.566 11.757 15.508 1.87 1.87 9.902 10.809 42.678 4.704 18.524-3.455 33.124-13.753 43.078-23.856 12.789-12.762 6.107-16.773 7.826-23.291 2.513-9.416 11.277-12.961 13.143-23.602 0.216-1.508 0.754-2.654 2.113-4.876 2.096-3.202 1.561-9.447 1.582-15.185 0.067-15.027-1.705-30.234-5.159-41.434-3.171-10.483-8.204-17.817-12.515-27.305-8.624-18.906-8.221-27.415-15.933-39.474-8.586-13.613-4.601-22.583-16.011-21.99-14.374 0.826-26.375 21.016-40.104 21.584z"/> + <path fill="#757575" d="m159.955 130.419c-9.201 0.346-23.299-25.175-23.931-15.383-0.344 8.295-0.017 8.284-0.156 16.494-0.301 5.764-3.17 6.867-8.812 15.555-3.002 4.774-5.148 9.76-6.714 14.706-0.784 3.41-0.889 6.508-1.764 9.548-0.471 1.699-1.986 3.133-3.003 5.259-3.554 10.688-13.624 24.1-16.009 34.619-2.483 10.82-5.411 17.678-4.954 32.097 0.373 13.528 0.285 10.058 4.651 13.739 4.244 3.632 8.893 7.154 15.699 13.171 7.167 6.233 22.299 17.224 24.294 20.585 2.142 3.432 2.175 11.404 0.896 13.896-1.271 2.428-12.558 3.932-12.486 3.932-0.071 0 9.768 13.453 11.705 15.392 1.867 1.867 9.867 10.744 42.588 4.655 18.545-3.453 33.415-13.682 42.956-23.879 12.187-12.492 5.591-16.771 7.3-23.258 2.507-9.398 11.826-12.959 13.687-23.586 0.215-1.5 0.788-2.643 2.138-4.854 2.104-3.235 1.538-9.462 1.58-15.178 0.133-15.076-1.681-30.228-5.135-41.394-3.173-10.455-8.199-17.779-12.501-27.25-8.609-18.877-8.234-27.399-15.952-39.42-8.389-13.258-4.739-21.911-15.895-21.301-14.21 0.859-26.474 21.295-40.182 21.855z"/> + <path fill="#7c7c7c" d="m159.938 131.504c-9.122 0.338-22.854-24.838-23.622-15.586-0.37 7.833-0.131 7.89-0.341 15.741-0.452 5.657-3.388 7.096-8.899 15.628-2.99 4.785-5.021 9.708-6.433 14.535-0.602 3.566-0.218 6.594-1.099 9.57-0.526 1.756-2.475 3.08-3.82 5.477-3.854 10.596-13.703 24.016-16.057 34.361-2.501 10.829-5.453 17.66-4.948 32.052 0.38 13.059 0.177 9.939 4.529 13.66 4.208 3.648 8.948 7.239 15.739 13.242 7.149 6.217 22.358 17.232 24.345 20.581 2.13 3.42 2.216 11.489 0.946 13.968-1.259 2.417-12.538 3.99-12.466 3.99-0.072 0 9.718 13.34 11.653 15.275 1.865 1.864 9.833 10.681 42.498 4.607 18.565-3.453 33.706-13.609 42.834-23.902 11.583-12.223 5.074-16.771 6.774-23.223 2.499-9.382 12.375-12.959 14.229-23.57 0.215-1.496 0.821-2.633 2.162-4.834 2.111-3.271 1.516-9.478 1.578-15.173 0.199-15.125-1.657-30.221-5.109-41.354-3.177-10.427-8.196-17.741-12.488-27.195-8.594-18.848-8.247-27.383-15.972-39.366-8.192-12.903-4.877-21.239-15.779-20.612-14.041 0.894-26.569 21.576-40.254 22.128z"/> + <path fill="#848484" d="m159.921 132.589c-9.043 0.331-22.406-24.502-23.312-15.79-0.398 7.373-0.247 7.496-0.527 14.988-0.602 5.551-3.604 7.326-8.984 15.702-2.98 4.796-4.896 9.656-6.154 14.364-0.417 3.723 0.455 6.679-0.432 9.592-0.582 1.813-2.964 3.026-4.639 5.694-4.153 10.504-13.782 23.936-16.104 34.104-2.519 10.838-5.495 17.643-4.941 32.008 0.387 12.586 0.067 9.819 4.407 13.582 4.171 3.664 9.002 7.324 15.777 13.311 7.132 6.201 22.419 17.24 24.396 20.576 2.12 3.41 2.259 11.578 0.998 14.041-1.247 2.408-12.517 4.049-12.446 4.049-0.07 0 9.67 13.227 11.604 15.16 1.861 1.861 9.798 10.615 42.409 4.558 18.584-3.45 33.996-13.538 42.711-23.926 10.979-11.952 4.557-16.769 6.248-23.187 2.491-9.367 12.924-12.959 14.771-23.557 0.215-1.49 0.856-2.622 2.188-4.813 2.118-3.305 1.491-9.494 1.575-15.166 0.267-15.174-1.635-30.215-5.086-41.314-3.179-10.399-8.19-17.703-12.473-27.141-8.579-18.818-8.262-27.366-15.994-39.312-7.993-12.547-5.013-20.565-15.661-19.922-13.876 0.927-26.669 21.855-40.331 22.399z"/> + <path fill="#8c8c8c" d="m159.903 133.674c-8.963 0.323-21.961-24.165-23.001-15.994-0.426 6.912-0.363 7.102-0.713 14.236-0.753 5.445-3.821 7.554-9.071 15.775-2.969 4.807-4.768 9.604-5.875 14.192-0.232 3.881 1.128 6.766 0.234 9.615-0.638 1.87-3.452 2.972-5.455 5.911-4.455 10.413-13.862 23.853-16.153 33.845-2.537 10.849-5.537 17.625-4.935 31.963 0.393 12.115-0.042 9.701 4.285 13.505 4.133 3.68 9.057 7.409 15.814 13.38 7.116 6.188 22.48 17.248 24.447 20.574 2.109 3.398 2.301 11.662 1.049 14.113-1.235 2.396-12.496 4.104-12.425 4.104-0.071 0 9.622 13.114 11.552 15.045 1.86 1.858 9.763 10.552 42.319 4.509 18.604-3.449 34.288-13.467 42.589-23.949 10.377-11.682 4.04-16.766 5.721-23.15 2.486-9.35 13.474-12.959 15.316-23.542 0.214-1.483 0.89-2.611 2.213-4.793 2.126-3.339 1.468-9.507 1.573-15.158 0.333-15.224-1.611-30.208-5.062-41.276-3.181-10.37-8.186-17.664-12.459-27.085-8.563-18.789-8.275-27.35-16.014-39.258-7.796-12.192-5.151-19.893-15.545-19.233-13.707 0.961-26.763 22.134-40.404 22.671z"/> + <path fill="#939393" d="m159.886 134.759c-8.885 0.316-21.516-23.829-22.691-16.197-0.454 6.451-0.479 6.708-0.899 13.482-0.903 5.339-4.038 7.784-9.157 15.849-2.957 4.818-4.642 9.552-5.595 14.021-0.05 4.037 1.799 6.852 0.9 9.637-0.693 1.928-3.941 2.919-6.273 6.129-4.756 10.32-13.941 23.77-16.201 33.587-2.555 10.858-5.579 17.608-4.928 31.92 0.399 11.644-0.151 9.581 4.162 13.424 4.096 3.697 9.111 7.494 15.854 13.451 7.099 6.17 22.541 17.256 24.498 20.569 2.1 3.387 2.344 11.75 1.101 14.186-1.223 2.387-12.476 4.163-12.404 4.163-0.071 0 9.573 13.001 11.5 14.929 1.857 1.856 9.729 10.488 42.229 4.461 18.625-3.449 34.579-13.396 42.467-23.973 9.774-11.412 3.523-16.764 5.195-23.115 2.479-9.334 14.022-12.959 15.858-23.527 0.214-1.479 0.924-2.601 2.238-4.772 2.134-3.373 1.445-9.522 1.571-15.151 0.399-15.273-1.587-30.201-5.036-41.237-3.185-10.342-8.184-17.625-12.446-27.03-8.548-18.76-8.288-27.333-16.034-39.204-7.598-11.837-5.289-19.221-15.428-18.544-13.543 0.994-26.863 22.413-40.481 22.942z"/> + <path fill="#9b9b9b" d="m159.868 135.844c-8.805 0.308-21.068-23.492-22.381-16.401-0.481 5.991-0.594 6.314-1.085 12.73-1.053 5.232-4.253 8.013-9.243 15.922-2.946 4.829-4.515 9.5-5.314 13.85 0.133 4.194 2.471 6.937 1.565 9.658-0.749 1.986-4.43 2.866-7.091 6.347-5.056 10.229-14.021 23.689-16.249 33.329-2.572 10.868-5.621 17.591-4.921 31.876 0.405 11.172-0.261 9.463 4.04 13.346 4.058 3.713 9.166 7.58 15.892 13.521 7.082 6.155 22.601 17.265 24.548 20.567 2.092 3.373 2.388 11.834 1.152 14.256-1.21 2.377-12.454 4.222-12.383 4.222-0.071 0 9.523 12.888 11.45 14.813 1.854 1.854 9.692 10.424 42.138 4.412 18.645-3.447 34.871-13.324 42.345-23.996 9.171-11.143 3.007-16.762 4.669-23.08 2.472-9.317 14.572-12.959 16.401-23.514 0.214-1.473 0.958-2.588 2.265-4.75 2.142-3.408 1.421-9.539 1.568-15.145 0.466-15.324-1.564-30.196-5.012-41.198-3.187-10.313-8.179-17.587-12.433-26.976-8.533-18.73-8.301-27.316-16.054-39.149-7.401-11.482-5.426-18.548-15.313-17.855-13.373 1.029-26.958 22.694-40.554 23.215z"/> + <path fill="#a3a3a3" d="m159.851 136.929c-8.727 0.301-20.622-23.156-22.071-16.604-0.509 5.529-0.71 5.919-1.271 11.976-1.203 5.126-4.47 8.243-9.328 15.996-2.936 4.84-4.39 9.448-5.036 13.679 0.316 4.351 3.143 7.023 2.231 9.68-0.804 2.043-4.919 2.812-7.908 6.563-5.356 10.137-14.101 23.607-16.298 33.072-2.589 10.877-5.661 17.574-4.913 31.832 0.412 10.699-0.37 9.342 3.918 13.268 4.021 3.729 9.221 7.664 15.93 13.59 7.064 6.139 22.661 17.271 24.599 20.563 2.081 3.363 2.43 11.922 1.204 14.33-1.198 2.365-12.434 4.278-12.363 4.278-0.07 0 9.477 12.774 11.399 14.697 1.851 1.851 9.659 10.36 42.048 4.364 18.666-3.447 35.162-13.254 42.223-24.021 8.568-10.873 2.49-16.761 4.144-23.045 2.464-9.301 15.121-12.958 16.943-23.498 0.215-1.467 0.992-2.579 2.29-4.729 2.148-3.441 1.398-9.553 1.566-15.139 0.532-15.373-1.541-30.189-4.987-41.158-3.188-10.285-8.174-17.549-12.419-26.921-8.518-18.701-8.313-27.3-16.073-39.096-7.204-11.126-5.564-17.875-15.196-17.165-13.21 1.064-27.058 22.975-40.632 23.488z"/> + <path fill="#aaa" d="m159.834 138.014c-8.646 0.293-20.176-22.819-21.761-16.808-0.536 5.069-0.826 5.526-1.457 11.224-1.354 5.02-4.687 8.472-9.416 16.069-2.924 4.851-4.262 9.396-4.756 13.508 0.501 4.507 3.814 7.109 2.897 9.702-0.858 2.1-5.406 2.759-8.725 6.782-5.657 10.045-14.181 23.524-16.347 32.812-2.606 10.888-5.703 17.557-4.906 31.787 0.418 10.229-0.479 9.225 3.795 13.189 3.984 3.745 9.275 7.749 15.968 13.66 7.048 6.124 22.723 17.279 24.651 20.559 2.07 3.352 2.472 12.008 1.255 14.402-1.186 2.355-12.414 4.337-12.343 4.337-0.071 0 9.428 12.66 11.348 14.581 1.85 1.848 9.624 10.297 41.958 4.314 18.687-3.444 35.453-13.18 42.102-24.043 7.965-10.602 1.973-16.758 3.616-23.01 2.457-9.283 15.67-12.957 17.487-23.482 0.214-1.461 1.026-2.568 2.315-4.709 2.155-3.477 1.375-9.568 1.563-15.131 0.6-15.424-1.518-30.184-4.963-41.119-3.192-10.257-8.17-17.511-12.405-26.866-8.502-18.672-8.328-27.284-16.095-39.042-7.005-10.771-5.701-17.203-15.078-16.476-13.04 1.098-27.152 23.255-40.703 23.76z"/> + <path fill="#b2b2b2" d="m159.816 139.099c-8.567 0.286-19.729-22.483-21.45-17.012-0.563 4.608-0.942 5.132-1.643 10.471-1.506 4.914-4.904 8.701-9.502 16.143-2.913 4.862-4.137 9.344-4.477 13.336 0.685 4.665 4.486 7.195 3.564 9.725-0.915 2.157-5.897 2.705-9.543 6.999-5.958 9.953-14.262 23.443-16.396 32.554-2.624 10.898-5.745 17.54-4.9 31.744 0.426 9.757-0.588 9.105 3.674 13.111 3.945 3.761 9.33 7.834 16.006 13.729 7.032 6.109 22.783 17.288 24.702 20.557 2.06 3.338 2.515 12.094 1.306 14.473-1.173 2.346-12.392 4.395-12.321 4.395-0.07 0 9.379 12.549 11.296 14.465 1.847 1.848 9.591 10.234 41.868 4.268 18.706-3.444 35.745-13.11 41.979-24.066 7.361-10.332 1.456-16.757 3.091-22.974 2.45-9.269 16.219-12.958 18.03-23.47 0.213-1.455 1.06-2.557 2.34-4.688 2.164-3.509 1.352-9.583 1.562-15.124 0.665-15.473-1.494-30.177-4.938-41.08-3.195-10.228-8.166-17.472-12.393-26.811-8.486-18.642-8.341-27.267-16.114-38.987-6.809-10.416-5.838-16.531-14.962-15.787-12.873 1.129-27.25 23.531-40.779 24.029z"/> + <path fill="#bababa" d="m159.799 140.184c-8.487 0.279-19.282-22.146-21.141-17.215-0.591 4.147-1.057 4.737-1.828 9.717-1.656 4.808-5.121 8.931-9.588 16.217-2.902 4.873-4.01 9.292-4.197 13.165 0.868 4.822 5.158 7.281 4.23 9.747-0.971 2.215-6.385 2.651-10.361 7.216-6.258 9.861-14.339 23.36-16.442 32.297-2.643 10.906-5.787 17.521-4.894 31.699 0.432 9.285-0.697 8.986 3.552 13.032 3.908 3.776 9.384 7.919 16.043 13.799 7.016 6.093 22.845 17.296 24.753 20.552 2.051 3.328 2.559 12.18 1.358 14.547-1.161 2.334-12.372 4.451-12.301 4.451-0.071 0 9.33 12.436 11.245 14.35 1.844 1.844 9.555 10.17 41.777 4.219 18.727-3.443 36.036-13.039 41.857-24.09 6.759-10.063 0.939-16.756 2.565-22.939 2.442-9.25 16.768-12.957 18.572-23.453 0.213-1.451 1.095-2.547 2.365-4.668 2.171-3.543 1.329-9.599 1.56-15.117 0.732-15.522-1.471-30.172-4.913-41.042-3.197-10.2-8.161-17.433-12.379-26.756-8.471-18.612-8.354-27.25-16.135-38.933-6.609-10.061-5.976-15.858-14.845-15.098-12.706 1.165-27.347 23.813-40.853 24.303z"/> + <path fill="#c1c1c1" d="m159.781 141.269c-8.408 0.271-18.837-21.81-20.83-17.419-0.619 3.687-1.173 4.344-2.014 8.965-1.808 4.701-5.338 9.16-9.674 16.29-2.892 4.884-3.885 9.24-3.918 12.994 1.052 4.978 5.829 7.367 4.896 9.769-1.026 2.272-6.874 2.598-11.178 7.434-6.56 9.769-14.419 23.277-16.491 32.039-2.66 10.916-5.829 17.504-4.887 31.656 0.438 8.813-0.807 8.867 3.43 12.953 3.87 3.793 9.438 8.004 16.082 13.868 6.997 6.077 22.904 17.304 24.803 20.55 2.041 3.314 2.601 12.266 1.409 14.617-1.149 2.324-12.351 4.51-12.28 4.51-0.07 0 9.282 12.321 11.194 14.233 1.841 1.842 9.521 10.106 41.688 4.17 18.746-3.44 36.326-12.967 41.734-24.112 6.156-9.793 0.423-16.754 2.038-22.904 2.438-9.235 17.318-12.957 19.117-23.438 0.212-1.444 1.128-2.536 2.39-4.647 2.18-3.578 1.306-9.613 1.558-15.11 0.799-15.571-1.447-30.165-4.889-41.002-3.2-10.172-8.156-17.395-12.364-26.701-8.456-18.583-8.367-27.234-16.155-38.88-6.413-9.705-6.114-15.185-14.729-14.408-12.541 1.197-27.445 24.091-40.93 24.573z"/> + <path fill="#c9c9c9" d="m159.764 142.354c-8.329 0.264-18.392-21.473-20.521-17.622-0.646 3.225-1.289 3.949-2.2 8.211-1.957 4.596-5.555 9.39-9.761 16.364-2.879 4.895-3.757 9.188-3.638 12.823 1.235 5.135 6.502 7.453 5.562 9.791-1.081 2.329-7.362 2.544-11.995 7.651-6.859 9.677-14.499 23.195-16.54 31.78-2.677 10.927-5.87 17.488-4.879 31.611 0.444 8.344-0.916 8.748 3.307 12.875 3.834 3.81 9.492 8.09 16.121 13.939 6.98 6.061 22.965 17.311 24.854 20.545 2.031 3.303 2.643 12.352 1.461 14.69-1.137 2.313-12.33 4.567-12.26 4.567-0.07 0 9.233 12.209 11.143 14.117 1.839 1.84 9.486 10.043 41.599 4.122 18.767-3.44 36.618-12.896 41.612-24.137 5.554-9.522-0.094-16.751 1.513-22.868 2.43-9.219 17.866-12.957 19.659-23.424 0.213-1.439 1.162-2.525 2.415-4.627 2.188-3.612 1.282-9.629 1.556-15.104 0.865-15.621-1.424-30.158-4.864-40.962-3.202-10.144-8.153-17.357-12.351-26.646-8.441-18.554-8.381-27.218-16.176-38.826-6.216-9.35-6.251-14.513-14.612-13.719-12.374 1.235-27.543 24.375-41.005 24.849z"/> + <path fill="#d1d1d1" d="m159.747 143.439c-8.25 0.256-17.944-21.137-20.21-17.826-0.675 2.765-1.406 3.555-2.386 7.459-2.108 4.489-5.772 9.619-9.847 16.437-2.869 4.906-3.631 9.136-3.358 12.652 1.419 5.292 7.174 7.538 6.228 9.812-1.137 2.387-7.852 2.491-12.813 7.869-7.161 9.586-14.579 23.114-16.588 31.522-2.695 10.938-5.912 17.471-4.873 31.568 0.451 7.871-1.025 8.629 3.185 12.797 3.796 3.824 9.547 8.174 16.158 14.008 6.964 6.047 23.026 17.32 24.905 20.541 2.021 3.292 2.686 12.439 1.513 14.764-1.125 2.303-12.31 4.625-12.239 4.625-0.07 0 9.186 12.094 11.092 14.002 1.836 1.836 9.45 9.978 41.509 4.072 18.786-3.439 36.909-12.824 41.49-24.16 4.948-9.252-0.611-16.748 0.985-22.832 2.423-9.203 18.415-12.957 20.203-23.41 0.212-1.434 1.196-2.514 2.44-4.605 2.193-3.646 1.259-9.645 1.553-15.098 0.932-15.67-1.4-30.151-4.84-40.922-3.205-10.115-8.148-17.319-12.336-26.592-8.427-18.524-8.396-27.201-16.197-38.771-6.017-8.995-6.388-13.84-14.495-13.03-12.207 1.266-27.64 24.652-41.079 25.118z"/> + <path fill="#d8d8d8" d="m159.729 144.524c-8.17 0.249-17.498-20.8-19.9-18.03-0.702 2.304-1.521 3.162-2.571 6.706-2.259 4.383-5.988 9.848-9.933 16.511-2.858 4.917-3.504 9.084-3.079 12.48 1.604 5.449 7.846 7.625 6.895 9.835-1.193 2.444-8.342 2.438-13.631 8.087-7.461 9.493-14.658 23.031-16.637 31.262-2.712 10.947-5.953 17.455-4.865 31.524 0.458 7.399-1.135 8.511 3.063 12.718 3.758 3.842 9.601 8.26 16.196 14.078 6.946 6.031 23.087 17.328 24.956 20.538 2.011 3.28 2.729 12.524 1.563 14.835-1.112 2.293-12.289 4.684-12.218 4.684-0.071 0 9.136 11.981 11.04 13.886 1.834 1.834 9.417 9.913 41.419 4.024 18.807-3.438 37.2-12.752 41.368-24.184 4.346-8.982-1.128-16.747 0.46-22.798 2.416-9.187 18.964-12.956 20.746-23.394 0.211-1.429 1.229-2.504 2.465-4.586 2.202-3.681 1.236-9.658 1.551-15.091 0.998-15.72-1.377-30.146-4.814-40.884-3.208-10.086-8.145-17.28-12.323-26.536-8.411-18.495-8.408-27.185-16.217-38.717-5.82-8.64-6.526-13.168-14.38-12.341-12.04 1.303-27.736 24.934-41.154 25.393z"/> + <path fill="#e0e0e0" d="m159.712 145.609c-8.091 0.241-17.052-20.464-19.59-18.233-0.729 1.843-1.637 2.767-2.757 5.953-2.409 4.276-6.206 10.077-10.02 16.584-2.847 4.928-3.378 9.032-2.8 12.309 1.787 5.606 8.519 7.711 7.561 9.857-1.248 2.502-8.829 2.384-14.448 8.304-7.761 9.402-14.738 22.95-16.684 31.006-2.731 10.955-5.996 17.436-4.859 31.48 0.464 6.928-1.244 8.389 2.939 12.639 3.722 3.857 9.656 8.344 16.234 14.148 6.932 6.014 23.148 17.336 25.008 20.533 2 3.268 2.771 12.611 1.615 14.907-1.1 2.282-12.268 4.741-12.198 4.741-0.069 0 9.089 11.867 10.989 13.77 1.831 1.831 9.382 9.85 41.329 3.977 18.827-3.438 37.492-12.683 41.246-24.207 3.743-8.715-1.646-16.746-0.066-22.762 2.409-9.171 19.514-12.957 21.289-23.381 0.211-1.422 1.265-2.494 2.49-4.564 2.21-3.715 1.213-9.674 1.549-15.084 1.065-15.77-1.354-30.139-4.791-40.844-3.21-10.058-8.14-17.241-12.309-26.481-8.396-18.466-8.421-27.168-16.237-38.664-5.622-8.284-6.663-12.495-14.262-11.651-11.872 1.335-27.833 25.212-41.228 25.663z"/> + <path fill="#e8e8e8" d="m159.694 146.694c-8.012 0.234-16.605-20.127-19.279-18.437-0.757 1.383-1.753 2.373-2.943 5.2-2.56 4.171-6.423 10.307-10.105 16.658-2.835 4.939-3.251 8.979-2.52 12.138 1.97 5.763 9.189 7.796 8.226 9.879-1.303 2.559-9.318 2.33-15.265 8.521-8.063 9.31-14.818 22.867-16.733 30.748-2.748 10.967-6.037 17.419-4.853 31.436 0.472 6.457-1.353 8.271 2.818 12.562 3.685 3.873 9.711 8.429 16.273 14.218 6.913 6 23.207 17.344 25.058 20.529 1.991 3.257 2.814 12.697 1.666 14.98-1.087 2.271-12.247 4.799-12.177 4.799-0.07 0 9.04 11.755 10.938 13.654 1.829 1.828 9.349 9.785 41.239 3.926 18.847-3.435 37.783-12.609 41.124-24.229 3.14-8.444-2.161-16.743-0.592-22.728 2.401-9.152 20.062-12.955 21.831-23.364 0.211-1.417 1.298-2.483 2.516-4.544 2.217-3.748 1.19-9.689 1.547-15.076 1.132-15.82-1.331-30.133-4.766-40.806-3.213-10.03-8.136-17.203-12.296-26.427-8.38-18.436-8.435-27.151-16.257-38.609-5.425-7.929-6.802-11.822-14.146-10.962-11.706 1.368-27.931 25.491-41.304 25.934z"/> + <path fill="#efefef" d="m159.677 147.779c-7.934 0.226-16.16-19.791-18.97-18.64-0.785 0.921-1.869 1.979-3.13 4.447-2.71 4.064-6.639 10.536-10.19 16.731-2.824 4.95-3.125 8.928-2.24 11.967 2.152 5.919 9.86 7.882 8.892 9.901-1.358 2.616-9.808 2.277-16.083 8.739-8.363 9.218-14.896 22.784-16.781 30.489-2.766 10.977-6.079 17.402-4.846 31.393 0.478 5.984-1.462 8.152 2.696 12.482 3.646 3.889 9.765 8.514 16.311 14.287 6.896 5.983 23.269 17.352 25.109 20.526 1.98 3.245 2.855 12.782 1.718 15.052-1.076 2.262-12.227 4.857-12.156 4.857-0.07 0 8.991 11.641 10.887 13.537 1.826 1.826 9.313 9.723 41.148 3.879 18.868-3.434 38.074-12.538 41.002-24.254 2.537-8.174-2.678-16.741-1.119-22.69 2.396-9.138 20.612-12.957 22.375-23.351 0.212-1.412 1.332-2.473 2.541-4.523 2.226-3.783 1.166-9.704 1.545-15.07 1.197-15.869-1.307-30.125-4.741-40.766-3.215-10.002-8.131-17.165-12.282-26.372-8.365-18.407-8.447-27.135-16.277-38.555-5.228-7.574-6.938-11.15-14.029-10.272-11.541 1.402-28.029 25.771-41.38 26.206z"/> + <path fill="#f7f7f7" d="m159.66 148.864c-7.854 0.219-15.714-19.454-18.66-18.844-0.812 0.461-1.983 1.585-3.314 3.694-2.86 3.958-6.856 10.766-10.278 16.805-2.813 4.961-2.998 8.876-1.96 11.796 2.337 6.076 10.533 7.968 9.558 9.923-1.415 2.673-10.296 2.223-16.899 8.956-8.664 9.126-14.978 22.702-16.83 30.23-2.783 10.986-6.121 17.386-4.839 31.349 0.484 5.515-1.571 8.033 2.573 12.403 3.609 3.906 9.82 8.6 16.35 14.357 6.88 5.969 23.329 17.36 25.16 20.523 1.971 3.232 2.898 12.869 1.77 15.124-1.063 2.252-12.206 4.915-12.136 4.915-0.07 0 8.942 11.527 10.835 13.422 1.824 1.822 9.279 9.658 41.059 3.83 18.889-3.434 38.366-12.467 40.881-24.278 1.934-7.903-3.195-16.739-1.646-22.655 2.388-9.121 21.161-12.955 22.918-23.336 0.211-1.404 1.366-2.461 2.566-4.502 2.232-3.816 1.143-9.719 1.542-15.063 1.265-15.92-1.283-30.12-4.717-40.727-3.219-9.974-8.128-17.127-12.269-26.317-8.349-18.378-8.461-27.119-16.298-38.501-5.029-7.219-7.075-10.478-13.912-9.584-11.373 1.438-28.126 26.053-41.454 26.48z"/> + <path fill="#fff" d="m159.642 149.949c-7.774 0.211-15.268-19.118-18.35-19.048-0.84 0-2.1 1.191-3.501 2.941-3.011 3.852-7.072 10.995-10.363 16.878-2.803 4.972-2.872 8.824-1.682 11.625 2.521 6.233 11.205 8.054 10.225 9.945-1.471 2.731-10.785 2.17-17.719 9.174-8.964 9.034-15.056 22.621-16.877 29.973-2.801 10.995-6.163 17.368-4.832 31.304 0.49 5.043-1.681 7.914 2.451 12.325 3.571 3.923 9.874 8.685 16.387 14.427 6.863 5.953 23.391 17.368 25.211 20.521 1.962 3.221 2.942 12.954 1.821 15.196-1.051 2.24-12.185 4.972-12.115 4.972-0.069 0 8.895 11.416 10.784 13.307 1.821 1.82 9.244 9.595 40.97 3.781 18.907-3.431 38.656-12.396 40.758-24.302 1.331-7.633-3.712-16.736-2.171-22.619 2.381-9.104 21.71-12.956 23.461-23.321 0.21-1.399 1.399-2.45 2.591-4.481 2.24-3.852 1.12-9.734 1.54-15.057 1.331-15.968-1.26-30.113-4.692-40.688-3.221-9.945-8.123-17.088-12.255-26.262-8.334-18.348-8.474-27.102-16.318-38.447-4.832-6.863-7.213-9.805-13.796-8.894-11.205 1.469-28.222 26.33-41.528 26.75z"/> + </g> + <path fill="#995900" d="m152.553 88.8575c5.256-0.648 12.456 0.648 15.769 3.096 3.096 2.304 5.256 3.528 8.063 4.464 9.433 3.096 21.816 4.536 21.24 13.032-0.648 10.151-3.6 14.688-12.024 17.351-6.768 2.088-18.863 13.824-28.224 13.824-4.176 0-10.008 0.216-13.392-1.008-3.24-1.152-7.776-6.624-13.104-11.016-5.328-4.32-10.296-8.928-10.439-14.976-0.217-6.407 3.96-8.496 9.863-13.607 3.097-2.736 8.712-7.272 12.601-9.288 3.599-1.799 5.903-1.439 9.647-1.872z"/> + <g transform="translate(-12.4048,10.0005)"> + <path fill="#9e5f00" d="m165.068 78.951c5.225-0.644 12.384 0.645 15.677 3.079 3.078 2.29 5.227 3.51 8.018 4.438 9.375 3.078 21.729 4.529 21.159 12.973-0.641 10.09-3.669 14.581-12.041 17.223-6.723 2.073-18.768 13.589-28.07 13.64-4.21 0.032-9.926 0.234-13.287-0.977-3.215-1.142-7.737-6.608-13.031-10.969-5.291-4.292-10.26-8.774-10.317-14.765-0.153-6.252 3.912-8.411 9.773-13.488 3.071-2.71 8.594-7.303 12.463-9.333 3.563-1.803 5.933-1.392 9.656-1.821z"/> + <path fill="#a36400" d="m165.177 79.044c5.195-0.641 12.313 0.64 15.587 3.06 3.06 2.278 5.194 3.494 7.971 4.413 9.317 3.06 21.641 4.522 21.078 12.914-0.634 10.027-3.737 14.474-12.058 17.094-6.678 2.057-18.673 13.352-27.919 13.454-4.241 0.064-9.842 0.252-13.18-0.945-3.19-1.133-7.7-6.592-12.96-10.921-5.254-4.264-10.222-8.622-10.192-14.555-0.093-6.099 3.863-8.329 9.681-13.369 3.048-2.685 8.478-7.335 12.328-9.379 3.526-1.804 5.963-1.338 9.664-1.766z"/> + <path fill="#a86a00" d="m165.287 79.138c5.165-0.637 12.241 0.637 15.496 3.043 3.042 2.264 5.165 3.476 7.924 4.387 9.26 3.042 21.556 4.515 20.998 12.854-0.627 9.968-3.805 14.368-12.074 16.967-6.633 2.042-18.576 13.117-27.766 13.27-4.276 0.096-9.759 0.27-13.075-0.914-3.165-1.123-7.661-6.577-12.887-10.874-5.217-4.236-10.187-8.468-10.069-14.345-0.03-5.943 3.815-8.244 9.589-13.249 3.023-2.66 8.36-7.366 12.191-9.424 3.49-1.808 5.993-1.291 9.673-1.715z"/> + <path fill="#ad7000" d="m165.396 79.23c5.135-0.633 12.17 0.633 15.404 3.025 3.025 2.251 5.137 3.46 7.88 4.361 9.201 3.025 21.467 4.508 20.917 12.796-0.62 9.905-3.874 14.26-12.093 16.837-6.586 2.027-18.479 12.882-27.611 13.086-4.311 0.127-9.677 0.287-12.971-0.883-3.14-1.113-7.622-6.561-12.814-10.826-5.18-4.208-10.148-8.315-9.945-14.135 0.031-5.789 3.768-8.16 9.497-13.129 2.999-2.635 8.244-7.398 12.055-9.47 3.454-1.808 6.023-1.24 9.681-1.662z"/> + <path fill="#b27600" d="m165.506 79.325c5.105-0.63 12.099 0.629 15.314 3.007 3.007 2.237 5.104 3.442 7.832 4.335 9.145 3.007 21.38 4.501 20.837 12.737-0.614 9.844-3.943 14.154-12.109 16.709-6.541 2.011-18.385 12.645-27.46 12.9-4.342 0.16-9.592 0.306-12.862-0.851-3.115-1.103-7.584-6.545-12.743-10.779-5.144-4.18-10.112-8.162-9.821-13.924 0.092-5.634 3.718-8.076 9.405-13.009 2.975-2.609 8.126-7.429 11.919-9.514 3.416-1.812 6.052-1.192 9.688-1.611z"/> + <path fill="#b77b00" d="m165.615 79.417c5.075-0.626 12.026 0.626 15.224 2.989 2.989 2.225 5.075 3.425 7.786 4.31 9.087 2.989 21.292 4.494 20.756 12.678-0.606 9.781-4.012 14.046-12.126 16.581-6.496 1.997-18.289 12.41-27.307 12.716-4.376 0.191-9.51 0.323-12.758-0.82-3.09-1.094-7.546-6.53-12.671-10.732-5.106-4.152-10.074-8.008-9.697-13.713 0.155-5.479 3.67-7.992 9.313-12.889 2.951-2.585 8.011-7.461 11.783-9.56 3.38-1.814 6.083-1.143 9.697-1.56z"/> + <path fill="#bc8100" d="m165.725 79.511c5.044-0.622 11.954 0.622 15.133 2.972 2.971 2.211 5.045 3.408 7.739 4.284 9.029 2.971 21.205 4.487 20.675 12.619-0.6 9.719-4.079 13.939-12.143 16.451-6.45 1.982-18.192 12.175-27.153 12.532-4.41 0.223-9.428 0.341-12.653-0.789-3.065-1.084-7.507-6.514-12.598-10.684-5.069-4.124-10.038-7.855-9.574-13.504 0.217-5.324 3.622-7.908 9.222-12.77 2.926-2.559 7.894-7.492 11.646-9.605 3.344-1.816 6.113-1.092 9.706-1.506z"/> + <path fill="#c18700" d="m165.834 79.604c5.015-0.618 11.883 0.619 15.043 2.954 2.953 2.198 5.015 3.391 7.693 4.259 8.972 2.953 21.118 4.48 20.594 12.559-0.593 9.66-4.147 13.833-12.159 16.324-6.405 1.967-18.098 11.94-27.002 12.347-4.441 0.255-9.343 0.359-12.546-0.757-3.04-1.074-7.469-6.498-12.526-10.637-5.032-4.096-10-7.701-9.45-13.293 0.278-5.169 3.574-7.823 9.13-12.649 2.903-2.534 7.776-7.524 11.511-9.651 3.306-1.821 6.141-1.044 9.712-1.456z"/> + <path fill="#c68d00" d="m165.944 79.697c4.984-0.615 11.811 0.614 14.952 2.936 2.935 2.184 4.983 3.374 7.646 4.233 8.915 2.935 21.031 4.473 20.515 12.5-0.586 9.597-4.218 13.726-12.177 16.195-6.36 1.951-18.002 11.703-26.849 12.162-4.476 0.287-9.261 0.377-12.441-0.726-3.015-1.064-7.431-6.482-12.453-10.589-4.995-4.068-9.965-7.549-9.326-13.083 0.34-5.015 3.524-7.741 9.038-12.531 2.878-2.508 7.658-7.555 11.374-9.696 3.269-1.82 6.171-0.992 9.721-1.401z"/> + <path fill="#cc9200" d="m166.054 79.791c4.952-0.61 11.738 0.611 14.86 2.918 2.918 2.172 4.954 3.357 7.601 4.207 8.857 2.918 20.942 4.466 20.432 12.442-0.578 9.536-4.285 13.62-12.192 16.066-6.314 1.936-17.906 11.468-26.696 11.978-4.509 0.319-9.178 0.394-12.335-0.696-2.989-1.054-7.393-6.466-12.382-10.541-4.959-4.04-9.928-7.395-9.202-12.873 0.401-4.859 3.477-7.655 8.945-12.411 2.854-2.482 7.542-7.586 11.239-9.741 3.233-1.824 6.201-0.943 9.73-1.349z"/> + <path fill="#d19800" d="m166.163 79.883c4.923-0.606 11.668 0.608 14.771 2.901 2.9 2.158 4.924 3.339 7.554 4.181 8.801 2.9 20.855 4.459 20.352 12.383-0.571 9.474-4.353 13.512-12.21 15.938-6.269 1.921-17.81 11.233-26.543 11.793-4.542 0.351-9.094 0.413-12.229-0.664-2.965-1.044-7.354-6.45-12.311-10.494-4.921-4.012-9.89-7.241-9.079-12.662 0.465-4.705 3.431-7.571 8.855-12.29 2.83-2.458 7.425-7.618 11.102-9.787 3.197-1.827 6.231-0.893 9.738-1.299z"/> + <path fill="#d69e00" d="m166.273 79.978c4.893-0.603 11.596 0.603 14.679 2.882 2.883 2.145 4.895 3.323 7.507 4.156 8.744 2.882 20.77 4.452 20.272 12.324-0.565 9.412-4.422 13.406-12.228 15.81-6.224 1.905-17.714 10.996-26.39 11.608-4.576 0.383-9.012 0.431-12.124-0.633-2.94-1.034-7.316-6.434-12.237-10.446-4.884-3.984-9.854-7.089-8.955-12.452 0.525-4.551 3.382-7.489 8.764-12.171 2.805-2.432 7.307-7.649 10.965-9.832 3.16-1.829 6.261-0.845 9.747-1.246z"/> + <path fill="#dba300" d="m166.382 80.07c4.863-0.599 11.525 0.6 14.59 2.865 2.864 2.131 4.862 3.305 7.461 4.13 8.686 2.864 20.682 4.445 20.19 12.264-0.559 9.352-4.491 13.299-12.244 15.681-6.179 1.89-17.619 10.761-26.237 11.423-4.608 0.415-8.929 0.449-12.018-0.601-2.915-1.024-7.277-6.418-12.166-10.399-4.847-3.956-9.815-6.935-8.831-12.241 0.587-4.396 3.333-7.404 8.671-12.051 2.782-2.407 7.191-7.681 10.83-9.878 3.123-1.829 6.29-0.793 9.754-1.193z"/> + <path fill="#e0a900" d="m166.492 80.164c4.832-0.595 11.453 0.596 14.498 2.847 2.847 2.118 4.833 3.289 7.414 4.104 8.629 2.846 20.595 4.438 20.111 12.205-0.553 9.29-4.56 13.193-12.262 15.553-6.134 1.875-17.522 10.526-26.085 11.239-4.642 0.447-8.845 0.467-11.912-0.57-2.89-1.015-7.238-6.402-12.093-10.351-4.81-3.928-9.78-6.782-8.708-12.032 0.649-4.241 3.285-7.32 8.58-11.932 2.757-2.381 7.073-7.712 10.693-9.923 3.088-1.831 6.321-0.743 9.764-1.14z"/> + <path fill="#e5af00" d="m166.601 80.257c4.803-0.592 11.382 0.592 14.407 2.829 2.829 2.105 4.804 3.271 7.368 4.079 8.571 2.828 20.507 4.431 20.029 12.146-0.544 9.228-4.627 13.085-12.277 15.423-6.089 1.861-17.427 10.29-25.932 11.055-4.676 0.478-8.763 0.484-11.807-0.539-2.865-1.005-7.2-6.387-12.021-10.304-4.772-3.9-9.742-6.629-8.583-11.821 0.711-4.085 3.236-7.236 8.487-11.812 2.732-2.357 6.957-7.744 10.557-9.968 3.052-1.834 6.351-0.694 9.772-1.088z"/> + <path fill="#eab500" d="m166.711 80.351c4.772-0.588 11.31 0.589 14.317 2.811 2.811 2.092 4.771 3.254 7.321 4.054 8.514 2.81 20.42 4.424 19.948 12.087-0.538 9.165-4.695 12.979-12.294 15.295-6.044 1.845-17.332 10.054-25.779 10.869-4.708 0.511-8.68 0.503-11.7-0.507-2.84-0.995-7.163-6.371-11.949-10.257-4.736-3.872-9.706-6.475-8.46-11.61 0.773-3.931 3.188-7.152 8.396-11.692 2.709-2.331 6.839-7.775 10.421-10.013 3.013-1.839 6.38-0.645 9.779-1.037z"/> + <path fill="#efba00" d="m166.82 80.443c4.742-0.584 11.238 0.585 14.226 2.794 2.794 2.078 4.743 3.237 7.276 4.027 8.456 2.793 20.332 4.417 19.868 12.029-0.531 9.104-4.766 12.872-12.313 15.167-5.997 1.83-17.234 9.819-25.626 10.685-4.742 0.542-8.596 0.52-11.595-0.476-2.815-0.985-7.124-6.355-11.877-10.209-4.699-3.844-9.668-6.322-8.336-11.4 0.835-3.778 3.14-7.068 8.304-11.573 2.686-2.306 6.724-7.807 10.285-10.059 2.978-1.84 6.411-0.595 9.788-0.985z"/> + <path fill="#f4c000" d="m166.93 80.537c4.711-0.58 11.166 0.582 14.135 2.776 2.775 2.066 4.713 3.22 7.229 4.002 8.399 2.775 20.246 4.41 19.787 11.969-0.522 9.043-4.832 12.765-12.328 15.039-5.952 1.815-17.139 9.584-25.473 10.501-4.776 0.574-8.513 0.538-11.49-0.445-2.79-0.976-7.085-6.34-11.804-10.162-4.662-3.816-9.632-6.168-8.213-11.189 0.896-3.623 3.092-6.984 8.213-11.454 2.66-2.281 6.604-7.838 10.147-10.104 2.942-1.844 6.441-0.547 9.797-0.933z"/> + <path fill="#f9c600" d="m167.039 80.63c4.683-0.577 11.095 0.577 14.045 2.758 2.758 2.052 4.683 3.203 7.184 3.976 8.341 2.757 20.157 4.403 19.706 11.91-0.518 8.981-4.901 12.659-12.346 14.911-5.906 1.799-17.044 9.347-25.32 10.315-4.809 0.606-8.431 0.556-11.384-0.413-2.765-0.966-7.048-6.324-11.732-10.114-4.625-3.788-9.594-6.016-8.088-10.98 0.958-3.467 3.043-6.9 8.12-11.333 2.637-2.256 6.488-7.87 10.013-10.15 2.902-1.844 6.468-0.495 9.802-0.88z"/> + </g> + <path fill="#fc0" d="m154.744 90.7245c4.65-0.573 11.022 0.574 13.954 2.74 2.739 2.039 4.651 3.186 7.136 3.951 8.284 2.739 20.071 4.396 19.626 11.851-0.51 8.919-4.97 12.551-12.362 14.781-5.861 1.784-16.947 9.112-25.168 10.131-4.842 0.638-8.347 0.574-11.277-0.382-2.74-0.956-7.01-6.308-11.66-10.067-4.588-3.76-9.559-5.862-7.965-10.769 1.02-3.313 2.995-6.816 8.028-11.213 2.612-2.23 6.371-7.901 9.876-10.195 2.867-1.847 6.499-0.447 9.812-0.828z"/> + <g transform="translate(-12.4048,10.0005)"> + <path fill="#fc0" d="m167.982 83.609c1.008 2.088 3.6 2.376 5.328 3.312 1.655 0.936 2.592 1.152 3.239 0.792 1.44-0.792 0.36-3.384-1.079-4.32-1.368-0.935-8.064-1.151-7.488 0.216z"/> + <path fill="#f9c600" d="m168.125 83.631c0.982 2.035 3.508 2.316 5.193 3.229 1.614 0.912 2.526 1.123 3.158 0.771 1.402-0.771 0.35-3.298-1.054-4.21-1.332-0.913-7.859-1.123-7.297 0.21z"/> + <path fill="#f4c000" d="m168.267 83.653c0.957 1.982 3.418 2.255 5.058 3.144 1.572 0.889 2.461 1.094 3.076 0.752 1.367-0.752 0.342-3.213-1.025-4.101-1.299-0.889-7.656-1.094-7.109 0.205z"/> + <path fill="#efba00" d="m168.409 83.674c0.932 1.929 3.327 2.195 4.924 3.06 1.53 0.865 2.395 1.064 2.993 0.732 1.331-0.732 0.333-3.127-0.998-3.992-1.264-0.864-7.451-1.064-6.919 0.2z"/> + <path fill="#eab500" d="m168.552 83.696c0.905 1.876 3.234 2.135 4.787 2.977 1.488 0.841 2.329 1.035 2.912 0.711 1.294-0.711 0.323-3.041-0.971-3.882-1.228-0.841-7.246-1.036-6.728 0.194z"/> + <path fill="#e5af00" d="m168.694 83.718c0.881 1.823 3.144 2.075 4.653 2.892 1.446 0.818 2.264 1.006 2.83 0.692 1.257-0.692 0.313-2.956-0.943-3.773-1.195-0.818-7.043-1.007-6.54 0.189z"/> + <path fill="#e0a900" d="m168.837 83.739c0.855 1.771 3.053 2.015 4.519 2.809 1.403 0.793 2.198 0.977 2.747 0.671 1.221-0.671 0.306-2.87-0.916-3.664-1.161-0.793-6.839-0.976-6.35 0.184z"/> + <path fill="#dba300" d="m168.979 83.761c0.829 1.718 2.962 1.955 4.383 2.725 1.363 0.77 2.132 0.948 2.666 0.651 1.184-0.651 0.296-2.784-0.889-3.554-1.125-0.77-6.634-0.948-6.16 0.178z"/> + <path fill="#d69e00" d="m169.121 83.782c0.804 1.665 2.871 1.895 4.249 2.641 1.32 0.747 2.066 0.918 2.583 0.631 1.148-0.631 0.287-2.698-0.861-3.444-1.091-0.746-6.43-0.919-5.971 0.172z"/> + <path fill="#d19800" d="m169.264 83.804c0.777 1.612 2.778 1.834 4.112 2.557 1.279 0.723 2.001 0.889 2.501 0.611 1.112-0.611 0.278-2.612-0.834-3.335-1.055-0.722-6.224-0.889-5.779 0.167z"/> + <path fill="#cc9200" d="m169.406 83.826c0.753 1.559 2.688 1.774 3.979 2.473 1.236 0.699 1.936 0.86 2.42 0.591 1.074-0.591 0.269-2.527-0.808-3.226-1.021-0.699-6.021-0.86-5.591 0.162z"/> + <path fill="#c68c00" d="m169.549 83.847c0.728 1.506 2.597 1.714 3.844 2.389 1.194 0.675 1.869 0.831 2.337 0.571 1.039-0.571 0.26-2.441-0.779-3.116-0.988-0.675-5.818-0.831-5.402 0.156z"/> + <path fill="#c18700" d="m169.691 83.869c0.702 1.453 2.506 1.654 3.709 2.305 1.152 0.652 1.803 0.802 2.254 0.551 1.002-0.551 0.251-2.355-0.751-3.006-0.953-0.652-5.613-0.802-5.212 0.15z"/> + <path fill="#bc8100" d="m169.833 83.89c0.677 1.4 2.415 1.594 3.574 2.221 1.111 0.628 1.738 0.772 2.173 0.531 0.965-0.531 0.241-2.27-0.725-2.897-0.917-0.627-5.408-0.772-5.022 0.145z"/> + <path fill="#b77b00" d="m169.976 83.912c0.65 1.347 2.322 1.533 3.438 2.137 1.069 0.604 1.673 0.743 2.091 0.511 0.93-0.511 0.233-2.184-0.696-2.788-0.884-0.603-5.205-0.743-4.833 0.14z"/> + <path fill="#b27500" d="m170.118 83.934c0.626 1.294 2.232 1.473 3.304 2.053 1.027 0.581 1.606 0.714 2.009 0.491 0.893-0.491 0.224-2.098-0.669-2.678-0.85-0.58-5.001-0.715-4.644 0.134z"/> + <path fill="#ad7000" d="m170.261 83.955c0.6 1.242 2.14 1.413 3.168 1.97 0.984 0.557 1.541 0.685 1.927 0.47 0.855-0.47 0.214-2.012-0.644-2.569-0.812-0.555-4.794-0.684-4.451 0.129z"/> + <path fill="#a86a00" d="m170.403 83.977c0.574 1.189 2.05 1.353 3.034 1.886 0.942 0.533 1.475 0.656 1.844 0.45 0.82-0.45 0.205-1.926-0.615-2.459-0.779-0.533-4.591-0.656-4.263 0.123z"/> + <path fill="#a36400" d="m170.545 83.998c0.55 1.136 1.959 1.292 2.899 1.802 0.901 0.509 1.41 0.626 1.762 0.43 0.783-0.43 0.197-1.841-0.587-2.35-0.745-0.508-4.387-0.626-4.074 0.118z"/> + <path fill="#9e5e00" d="m170.688 84.02c0.522 1.083 1.867 1.232 2.764 1.718 0.859 0.486 1.343 0.597 1.68 0.41 0.746-0.41 0.188-1.755-0.561-2.241-0.709-0.484-4.182-0.597-3.883 0.113z"/> + <path fill="#995900" d="m170.83 84.042c0.498 1.03 1.776 1.172 2.629 1.634 0.817 0.462 1.278 0.568 1.599 0.39 0.71-0.39 0.178-1.669-0.533-2.131-0.676-0.461-3.979-0.568-3.695 0.107z"/> + </g> + <g transform="translate(-12.4048,10.0005)"> + <path fill="#fc0" d="m152.875 86.29c-0.325 0.813 1.952 2.359 3.091 1.301 1.222-1.057 2.686-2.033 3.175-2.359 2.195-1.465 1.383-2.522-2.278-1.871-3.663 0.651-3.663 2.115-3.988 2.929z"/> + <path fill="#f9c600" d="m152.934 86.279c-0.318 0.794 1.906 2.304 3.019 1.271 1.193-1.033 2.623-1.986 3.102-2.305 2.145-1.431 1.351-2.463-2.226-1.828-3.578 0.637-3.578 2.067-3.895 2.862z"/> + <path fill="#f4c000" d="m152.993 86.269c-0.31 0.775 1.861 2.25 2.948 1.241 1.164-1.008 2.56-1.939 3.026-2.25 2.095-1.397 1.319-2.405-2.173-1.784-3.491 0.62-3.491 2.017-3.801 2.793z"/> + <path fill="#efba00" d="m153.051 86.258c-0.302 0.757 1.817 2.195 2.878 1.211 1.136-0.984 2.497-1.892 2.952-2.195 2.044-1.363 1.287-2.347-2.118-1.741-3.409 0.606-3.409 1.968-3.712 2.725z"/> + <path fill="#eab500" d="m153.11 86.248c-0.295 0.738 1.771 2.141 2.805 1.181 1.108-0.959 2.437-1.845 2.88-2.141 1.993-1.329 1.255-2.289-2.066-1.698-3.324 0.591-3.324 1.92-3.619 2.658z"/> + <path fill="#e5af00" d="m153.169 86.238c-0.287 0.719 1.727 2.086 2.733 1.151 1.08-0.935 2.374-1.798 2.807-2.086 1.942-1.296 1.224-2.23-2.015-1.655s-3.238 1.87-3.525 2.59z"/> + <path fill="#e0a900" d="m153.228 86.228c-0.28 0.7 1.681 2.032 2.661 1.121 1.052-0.91 2.312-1.751 2.732-2.031 1.893-1.262 1.191-2.172-1.961-1.611-3.152 0.559-3.152 1.82-3.432 2.521z"/> + <path fill="#dba300" d="m153.286 86.217c-0.271 0.681 1.636 1.977 2.591 1.09 1.023-0.886 2.25-1.704 2.659-1.977 1.84-1.228 1.159-2.114-1.909-1.568-3.068 0.547-3.068 1.773-3.341 2.455z"/> + <path fill="#d69e00" d="m153.345 86.207c-0.265 0.662 1.591 1.922 2.519 1.061 0.995-0.862 2.188-1.657 2.586-1.922 1.789-1.194 1.127-2.055-1.855-1.525-2.985 0.53-2.985 1.723-3.25 2.386z"/> + <path fill="#d19800" d="m153.404 86.197c-0.257 0.643 1.546 1.868 2.447 1.03 0.967-0.837 2.126-1.61 2.512-1.868 1.739-1.16 1.095-1.997-1.803-1.481-2.899 0.516-2.899 1.674-3.156 2.319z"/> + <path fill="#cc9200" d="m153.463 86.187c-0.25 0.625 1.5 1.813 2.375 1 0.939-0.813 2.064-1.563 2.439-1.813 1.688-1.126 1.063-1.938-1.75-1.438-2.814 0.5-2.814 1.625-3.064 2.251z"/> + <path fill="#c68c00" d="m153.521 86.176c-0.242 0.605 1.456 1.758 2.304 0.97 0.911-0.788 2.002-1.516 2.366-1.758 1.637-1.092 1.031-1.88-1.698-1.395-2.729 0.486-2.729 1.576-2.972 2.183z"/> + <path fill="#c18700" d="m153.58 86.166c-0.233 0.587 1.41 1.704 2.233 0.939 0.882-0.763 1.938-1.469 2.292-1.704 1.586-1.058 0.999-1.822-1.646-1.352-2.644 0.472-2.644 1.529-2.879 2.117z"/> + <path fill="#bc8100" d="m153.639 86.156c-0.228 0.568 1.364 1.649 2.16 0.91 0.854-0.739 1.878-1.422 2.219-1.649 1.536-1.024 0.967-1.764-1.593-1.308s-2.559 1.477-2.786 2.047z"/> + <path fill="#b77b00" d="m153.698 86.146c-0.22 0.549 1.32 1.594 2.089 0.879 0.825-0.715 1.815-1.375 2.146-1.595 1.484-0.99 0.935-1.705-1.54-1.265s-2.475 1.43-2.695 1.981z"/> + <path fill="#b27500" d="m153.756 86.135c-0.211 0.53 1.275 1.54 2.019 0.85 0.797-0.69 1.753-1.328 2.072-1.54 1.434-0.957 0.902-1.646-1.487-1.221s-2.391 1.38-2.604 1.911z"/> + <path fill="#ad7000" d="m153.815 86.125c-0.204 0.512 1.229 1.486 1.946 0.82 0.769-0.666 1.69-1.281 1.997-1.486 1.385-0.922 0.871-1.588-1.434-1.178s-2.304 1.331-2.509 1.844z"/> + <path fill="#a86a00" d="m153.874 86.114c-0.196 0.493 1.185 1.431 1.875 0.79 0.74-0.642 1.628-1.234 1.924-1.431 1.332-0.889 0.84-1.53-1.381-1.135s-2.221 1.283-2.418 1.776z"/> + <path fill="#a36400" d="m153.933 86.104c-0.189 0.474 1.139 1.376 1.803 0.759 0.712-0.617 1.566-1.187 1.851-1.376 1.281-0.855 0.808-1.472-1.329-1.092-2.135 0.38-2.135 1.234-2.325 1.709z"/> + <path fill="#9e5e00" d="m153.991 86.094c-0.181 0.455 1.095 1.322 1.732 0.729 0.684-0.592 1.504-1.14 1.776-1.321 1.231-0.821 0.775-1.414-1.274-1.048-2.051 0.364-2.051 1.184-2.234 1.64z"/> + <path fill="#995900" d="m154.05 86.083c-0.174 0.436 1.05 1.267 1.66 0.699 0.656-0.568 1.442-1.093 1.704-1.267 1.181-0.787 0.743-1.355-1.223-1.005s-1.966 1.136-2.141 1.573z"/> + </g> + <g transform="translate(-12.4048,10.0005)"> + <path fill="#fc0" d="m156.951 107.887c-0.229 2.858 6.343-4.286 6.743-4.915 0.856-1.543 3.715-5.886 4.172-7.715 0.857-3.2 2.401-5.543 1.429-8.915-0.343-1.086-2.742-1.372-3.829-0.687-3.086 1.829-2.629 4.058-2.972 6.115-1.143 5.831-5.143 11.717-5.543 16.117z"/> + <path fill="#ffcc02" d="m157.22 107.441c-0.22 2.787 6.178-4.188 6.566-4.802 0.833-1.506 3.614-5.745 4.056-7.529 0.831-3.122 2.333-5.408 1.382-8.695-0.337-1.058-2.678-1.333-3.735-0.663-3.006 1.788-2.557 3.96-2.889 5.967-1.105 5.685-4.997 11.431-5.38 15.722z"/> + <path fill="#ffcc05" d="m157.488 106.995c-0.209 2.715 6.014-4.091 6.392-4.69 0.811-1.469 3.513-5.603 3.941-7.342 0.804-3.043 2.264-5.273 1.331-8.474-0.329-1.031-2.61-1.295-3.64-0.64-2.927 1.747-2.486 3.863-2.806 5.818-1.068 5.541-4.851 11.146-5.218 15.328z"/> + <path fill="#ffcc07" d="m157.757 106.548c-0.198 2.645 5.85-3.993 6.217-4.577 0.785-1.431 3.409-5.461 3.824-7.156 0.779-2.964 2.196-5.138 1.282-8.253-0.322-1.003-2.543-1.257-3.545-0.618-2.847 1.706-2.414 3.766-2.722 5.67-1.031 5.398-4.706 10.862-5.056 14.934z"/> + <path fill="#ffcd0a" d="m158.026 106.102c-0.189 2.573 5.684-3.896 6.04-4.465 0.762-1.394 3.309-5.32 3.709-6.969 0.753-2.886 2.129-5.004 1.233-8.033-0.315-0.976-2.478-1.219-3.45-0.595-2.768 1.665-2.343 3.668-2.64 5.522-0.993 5.254-4.558 10.577-4.892 14.54z"/> + <path fill="#ffcd0c" d="m158.294 105.655c-0.179 2.503 5.52-3.798 5.865-4.351 0.738-1.357 3.207-5.179 3.594-6.783 0.727-2.807 2.061-4.869 1.185-7.813-0.309-0.948-2.411-1.18-3.356-0.572-2.687 1.623-2.271 3.571-2.556 5.374-0.958 5.11-4.414 10.291-4.732 14.145z"/> + <path fill="#ffcd0f" d="m158.563 105.209c-0.169 2.431 5.354-3.701 5.688-4.239 0.715-1.319 3.106-5.037 3.479-6.596 0.7-2.728 1.992-4.734 1.135-7.592-0.301-0.92-2.344-1.142-3.261-0.549-2.608 1.583-2.199 3.474-2.473 5.226-0.919 4.965-4.267 10.005-4.568 13.75z"/> + <path fill="#ffcd11" d="m158.831 104.762c-0.159 2.361 5.19-3.602 5.515-4.126 0.69-1.282 3.004-4.896 3.361-6.409 0.674-2.649 1.924-4.599 1.087-7.372-0.295-0.893-2.277-1.104-3.167-0.526-2.527 1.541-2.128 3.376-2.389 5.077-0.883 4.822-4.122 9.721-4.407 13.356z"/> + <path fill="#ffce14" d="m159.1 104.316c-0.149 2.289 5.024-3.505 5.338-4.014 0.667-1.244 2.901-4.754 3.247-6.223 0.646-2.571 1.854-4.464 1.037-7.151-0.287-0.865-2.211-1.065-3.072-0.504-2.448 1.5-2.056 3.279-2.306 4.929-0.845 4.679-3.976 9.437-4.244 12.963z"/> + <path fill="#ffce16" d="m159.369 103.869c-0.139 2.219 4.86-3.407 5.162-3.9 0.643-1.208 2.801-4.613 3.131-6.037 0.622-2.492 1.787-4.329 0.988-6.93-0.28-0.838-2.146-1.027-2.978-0.481-2.368 1.459-1.983 3.182-2.223 4.781-0.807 4.533-3.829 9.151-4.08 12.567z"/> + <path fill="#ffce19" d="m159.637 103.423c-0.13 2.147 4.695-3.31 4.986-3.788 0.62-1.17 2.699-4.471 3.016-5.85 0.596-2.414 1.719-4.195 0.939-6.71-0.273-0.81-2.079-0.989-2.883-0.458-2.289 1.418-1.913 3.084-2.139 4.632-0.77 4.391-3.684 8.866-3.919 12.174z"/> + <path fill="#ffce1c" d="m159.906 102.977c-0.119 2.076 4.531-3.213 4.811-3.676 0.597-1.133 2.599-4.33 2.899-5.664 0.57-2.335 1.651-4.06 0.891-6.49-0.267-0.782-2.012-0.95-2.787-0.435-2.21 1.377-1.842 2.987-2.057 4.484-0.734 4.247-3.539 8.582-3.757 11.781z"/> + <path fill="#ffcf1e" d="m160.174 102.53c-0.108 2.005 4.366-3.115 4.637-3.563 0.571-1.096 2.496-4.189 2.784-5.478 0.543-2.256 1.581-3.925 0.841-6.269-0.26-0.754-1.945-0.912-2.693-0.412-2.129 1.336-1.77 2.889-1.973 4.336-0.697 4.103-3.394 8.297-3.596 11.386z"/> + <path fill="#ffcf21" d="m160.443 102.084c-0.099 1.934 4.201-3.018 4.46-3.45 0.548-1.059 2.394-4.047 2.668-5.291 0.517-2.178 1.514-3.79 0.793-6.049-0.253-0.727-1.879-0.874-2.599-0.39-2.051 1.295-1.698 2.792-1.891 4.188-0.658 3.959-3.246 8.012-3.431 10.992z"/> + <path fill="#ffcf23" d="m160.712 101.637c-0.089 1.863 4.036-2.919 4.283-3.337 0.526-1.021 2.294-3.905 2.553-5.104 0.491-2.099 1.447-3.655 0.744-5.828-0.246-0.699-1.813-0.835-2.505-0.367-1.969 1.253-1.625 2.694-1.805 4.04-0.623 3.814-3.101 7.726-3.27 10.596z"/> + <path fill="#ffcf26" d="m160.98 101.191c-0.079 1.792 3.872-2.822 4.107-3.225 0.502-0.984 2.192-3.764 2.438-4.918 0.464-2.02 1.378-3.52 0.694-5.607-0.238-0.672-1.746-0.797-2.41-0.344-1.89 1.212-1.555 2.597-1.723 3.891-0.583 3.671-2.953 7.442-3.106 10.203z"/> + <path fill="#ffd028" d="m161.249 100.744c-0.068 1.721 3.707-2.724 3.933-3.112 0.478-0.947 2.091-3.623 2.321-4.731 0.439-1.942 1.311-3.386 0.646-5.387-0.232-0.645-1.68-0.758-2.316-0.321-1.81 1.171-1.481 2.5-1.639 3.743-0.548 3.527-2.809 7.156-2.945 9.808z"/> + <path fill="#ffd02b" d="m161.517 100.298c-0.06 1.65 3.543-2.627 3.757-2.999 0.454-0.91 1.989-3.481 2.206-4.545 0.413-1.863 1.242-3.25 0.597-5.167-0.225-0.617-1.613-0.72-2.221-0.298-1.73 1.13-1.411 2.402-1.557 3.595-0.509 3.383-2.662 6.871-2.782 9.414z"/> + <path fill="#ffd02d" d="m161.786 99.852c-0.049 1.579 3.377-2.529 3.581-2.887 0.431-0.872 1.887-3.34 2.091-4.359 0.387-1.784 1.173-3.116 0.547-4.946-0.217-0.589-1.546-0.682-2.126-0.275-1.649 1.089-1.339 2.305-1.472 3.446-0.474 3.24-2.518 6.587-2.621 9.021z"/> + <path fill="#ffd030" d="m162.055 99.405c-0.039 1.508 3.212-2.432 3.404-2.773 0.407-0.835 1.786-3.199 1.976-4.172 0.359-1.706 1.104-2.981 0.499-4.726-0.211-0.562-1.481-0.644-2.032-0.253-1.571 1.048-1.268 2.208-1.389 3.298-0.436 3.096-2.372 6.302-2.458 8.626z"/> + <path fill="#ffd133" d="m162.323 98.958c-0.029 1.437 3.048-2.334 3.23-2.661 0.383-0.798 1.684-3.057 1.858-3.986 0.334-1.627 1.037-2.846 0.45-4.505-0.204-0.534-1.414-0.605-1.938-0.23-1.49 1.007-1.195 2.11-1.306 3.15-0.397 2.953-2.224 6.018-2.294 8.232z"/> + </g> + <g transform="translate(-12.4048,10.0005)"> + <path fill="#fc0" d="m179.646 95.994c-3.168 3.456-5.4 6.767-7.2 9-1.872 2.304-6.48 5.04-4.176 7.704 1.943 2.376 9.936-1.944 16.128-6.552 6.12-4.608 15.696-8.711 11.016-13.967-2.448-2.664-8.208-2.088-10.439-0.648-1.729 1.078-2.737 1.655-5.329 4.463z"/> + <path fill="#ffcc02" d="m179.782 96.147c-3.118 3.378-5.313 6.628-7.086 8.809-1.841 2.249-6.375 4.945-4.13 7.534 1.893 2.31 9.724-1.943 15.795-6.469 6.001-4.525 15.38-8.574 10.82-13.682-2.387-2.588-8.022-1.998-10.209-0.584-1.692 1.062-2.665 1.67-5.19 4.392z"/> + <path fill="#ffcc05" d="m179.919 96.3c-3.068 3.3-5.227 6.488-6.973 8.619-1.81 2.193-6.271 4.85-4.085 7.364 1.843 2.243 9.513-1.943 15.463-6.386 5.882-4.442 15.064-8.437 10.623-13.396-2.323-2.513-7.835-1.907-9.978-0.52-1.655 1.044-2.593 1.684-5.05 4.319z"/> + <path fill="#ffcc07" d="m180.055 96.454c-3.02 3.222-5.14 6.347-6.859 8.428-1.78 2.138-6.166 4.754-4.04 7.194 1.793 2.177 9.302-1.942 15.131-6.303 5.762-4.359 14.748-8.299 10.427-13.11-2.261-2.437-7.648-1.817-9.747-0.456-1.619 1.025-2.522 1.698-4.912 4.247z"/> + <path fill="#ffcd0a" d="m180.191 96.607c-2.97 3.143-5.052 6.207-6.745 8.237-1.749 2.082-6.063 4.659-3.994 7.023 1.743 2.111 9.09-1.941 14.798-6.219 5.644-4.276 14.433-8.162 10.231-12.824-2.199-2.361-7.463-1.727-9.518-0.392-1.581 1.008-2.45 1.713-4.772 4.175z"/> + <path fill="#ffcd0c" d="m180.327 96.761c-2.92 3.065-4.965 6.066-6.631 8.047-1.718 2.027-5.957 4.564-3.949 6.853 1.693 2.044 8.878-1.94 14.466-6.136 5.524-4.194 14.116-8.024 10.034-12.538-2.137-2.286-7.275-1.636-9.285-0.328-1.546 0.988-2.38 1.726-4.635 4.102z"/> + <path fill="#ffcd0f" d="m180.464 96.914c-2.871 2.987-4.879 5.926-6.518 7.857-1.688 1.971-5.854 4.468-3.903 6.683 1.643 1.978 8.666-1.94 14.133-6.053 5.404-4.111 13.801-7.887 9.839-12.251-2.075-2.21-7.091-1.546-9.056-0.264-1.509 0.969-2.308 1.738-4.495 4.028z"/> + <path fill="#ffcd11" d="m180.6 97.067c-2.821 2.909-4.792 5.786-6.404 7.667-1.657 1.916-5.748 4.373-3.858 6.512 1.593 1.912 8.455-1.938 13.802-5.969 5.284-4.028 13.484-7.75 9.641-11.966-2.012-2.134-6.902-1.456-8.823-0.199-1.474 0.951-2.238 1.752-4.358 3.955z"/> + <path fill="#ffce14" d="m180.736 97.221c-2.771 2.83-4.705 5.645-6.29 7.476-1.626 1.86-5.644 4.278-3.813 6.342 1.542 1.845 8.244-1.938 13.47-5.886 5.166-3.945 13.169-7.612 9.444-11.68-1.949-2.059-6.716-1.365-8.592-0.135-1.437 0.933-2.166 1.766-4.219 3.883z"/> + <path fill="#ffce16" d="m180.872 97.375c-2.722 2.752-4.617 5.504-6.176 7.286-1.595 1.805-5.539 4.182-3.767 6.172 1.49 1.779 8.031-1.937 13.136-5.803 5.046-3.862 12.853-7.475 9.249-11.394-1.889-1.983-6.53-1.274-8.362-0.071-1.4 0.914-2.095 1.779-4.08 3.81z"/> + <path fill="#ffce19" d="m181.009 97.528c-2.673 2.674-4.53 5.364-6.063 7.095-1.564 1.749-5.435 4.087-3.722 6.001 1.44 1.713 7.82-1.936 12.804-5.719 4.927-3.78 12.537-7.338 9.052-11.108-1.825-1.907-6.343-1.185-8.13-0.007-1.364 0.896-2.024 1.793-3.941 3.738z"/> + <path fill="#ffce1c" d="m181.145 97.682c-2.623 2.595-4.444 5.225-5.949 6.904-1.534 1.693-5.33 3.992-3.676 5.831 1.39 1.646 7.608-1.935 12.471-5.636 4.808-3.697 12.221-7.2 8.856-10.822-1.764-1.832-6.157-1.094-7.9 0.057-1.327 0.878-1.952 1.807-3.802 3.666z"/> + <path fill="#ffcf1e" d="m181.281 97.835c-2.573 2.517-4.357 5.084-5.835 6.714-1.503 1.638-5.226 3.896-3.631 5.661 1.34 1.58 7.396-1.935 12.139-5.553 4.689-3.614 11.905-7.063 8.659-10.536-1.701-1.756-5.97-1.004-7.668 0.121-1.291 0.86-1.881 1.821-3.664 3.593z"/> + <path fill="#ffcf21" d="m181.417 97.988c-2.522 2.439-4.27 4.944-5.721 6.524-1.472 1.582-5.121 3.801-3.586 5.491 1.29 1.513 7.186-1.934 11.807-5.47 4.569-3.531 11.589-6.926 8.463-10.25-1.639-1.68-5.783-0.914-7.438 0.186-1.254 0.84-1.809 1.834-3.525 3.519z"/> + <path fill="#ffcf23" d="m181.554 98.142c-2.476 2.361-4.185 4.803-5.608 6.333-1.441 1.527-5.017 3.706-3.54 5.32 1.24 1.447 6.974-1.933 11.474-5.386 4.45-3.448 11.273-6.788 8.268-9.964-1.577-1.605-5.599-0.823-7.207 0.25-1.22 0.822-1.74 1.848-3.387 3.447z"/> + <path fill="#ffcf26" d="m181.69 98.295c-2.425 2.283-4.098 4.663-5.494 6.143-1.411 1.471-4.912 3.61-3.495 5.15 1.19 1.381 6.763-1.932 11.142-5.303 4.331-3.366 10.957-6.65 8.07-9.679-1.514-1.529-5.411-0.732-6.976 0.313-1.182 0.805-1.667 1.863-3.247 3.376z"/> + <path fill="#ffd028" d="m181.826 98.449c-2.375 2.204-4.009 4.522-5.38 5.952-1.38 1.416-4.808 3.515-3.449 4.98 1.14 1.314 6.551-1.932 10.81-5.22 4.211-3.283 10.641-6.513 7.874-9.393-1.452-1.454-5.226-0.642-6.745 0.378-1.147 0.786-1.597 1.876-3.11 3.303z"/> + <path fill="#ffd02b" d="m181.962 98.602c-2.324 2.127-3.922 4.382-5.266 5.762-1.349 1.36-4.703 3.42-3.404 4.809 1.089 1.248 6.34-1.93 10.478-5.136 4.092-3.2 10.325-6.376 7.677-9.106-1.389-1.378-5.038-0.552-6.513 0.441-1.111 0.768-1.526 1.89-2.972 3.23z"/> + <path fill="#ffd02d" d="m182.099 98.756c-2.276 2.048-3.836 4.241-5.153 5.571-1.318 1.305-4.599 3.324-3.359 4.639 1.039 1.182 6.128-1.93 10.146-5.053 3.973-3.117 10.009-6.238 7.48-8.82-1.328-1.303-4.852-0.462-6.282 0.506-1.074 0.748-1.454 1.903-2.832 3.157z"/> + <path fill="#ffd030" d="m182.235 98.909c-2.228 1.97-3.749 4.101-5.039 5.381-1.288 1.249-4.494 3.229-3.313 4.469 0.988 1.115 5.916-1.929 9.813-4.97 3.853-3.034 9.693-6.101 7.285-8.535-1.267-1.227-4.666-0.371-6.052 0.57-1.038 0.731-1.384 1.918-2.694 3.085z"/> + <path fill="#ffd133" d="m182.371 99.063c-2.177 1.892-3.662 3.96-4.925 5.19-1.257 1.193-4.39 3.133-3.268 4.298 0.938 1.049 5.704-1.928 9.479-4.886 3.734-2.952 9.377-5.963 7.088-8.249-1.203-1.151-4.479-0.281-5.821 0.634-0.999 0.713-1.31 1.931-2.553 3.013z"/> + </g> + <g transform="translate(-12.4048,10.0005)"> + <path fill="#fff" d="m186.414 168.569c0.864-2.808 28.872-9.432 33.48-7.272 4.536 2.16 26.279 33.768 22.392 35.496-3.888 1.657-12.24-10.512-24.408-16.128s-32.328-9.216-31.464-12.096z"/> + <path fill="#f9f9f9" d="m187.239 168.626c0.848-2.761 28.145-9.076 32.69-6.997 4.476 2.079 25.768 32.897 21.943 34.591-3.824 1.625-11.965-10.346-23.94-15.874-11.976-5.527-31.541-8.89-30.693-11.72z"/> + <path fill="#f4f4f4" d="m188.063 168.683c0.832-2.714 27.418-8.72 31.899-6.722 4.417 1.998 25.259 32.026 21.497 33.685-3.76 1.595-11.689-10.18-23.474-15.619-11.782-5.438-30.754-8.565-29.922-11.344z"/> + <path fill="#efefef" d="m188.888 168.74c0.814-2.668 26.69-8.364 31.109-6.447 4.357 1.917 24.746 31.155 21.049 32.779-3.695 1.563-11.416-10.014-23.007-15.364-11.59-5.349-29.967-8.239-29.151-10.968z"/> + <path fill="#eaeaea" d="m189.712 168.797c0.801-2.621 25.964-8.009 30.32-6.173 4.299 1.837 24.235 30.285 20.603 31.874-3.633 1.532-11.142-9.847-22.54-15.109-11.4-5.261-29.182-7.914-28.383-10.592z"/> + <path fill="#e5e5e5" d="m190.537 168.853c0.783-2.573 25.236-7.652 29.53-5.897 4.239 1.756 23.723 29.414 20.155 30.968-3.569 1.501-10.867-9.681-22.074-14.854-11.206-5.172-28.395-7.589-27.611-10.217z"/> + <path fill="#e0e0e0" d="m191.361 168.91c0.768-2.527 24.51-7.296 28.74-5.622 4.18 1.675 23.212 28.543 19.708 30.063-3.505 1.469-10.593-9.516-21.607-14.6-11.014-5.083-27.608-7.263-26.841-9.841z"/> + <path fill="#dbdbdb" d="m192.186 168.967c0.751-2.48 23.781-6.941 27.95-5.347 4.119 1.593 22.7 27.671 19.26 29.157-3.441 1.438-10.318-9.349-21.141-14.345-10.821-4.994-26.821-6.938-26.069-9.465z"/> + <path fill="#d6d6d6" d="m193.01 169.024c0.735-2.433 23.057-6.585 27.16-5.073 4.062 1.513 22.19 26.801 18.813 28.252-3.377 1.407-10.043-9.183-20.673-14.09-10.629-4.906-26.035-6.612-25.3-9.089z"/> + <path fill="#d1d1d1" d="m193.835 169.081c0.72-2.387 22.328-6.229 26.37-4.798 4.001 1.432 21.678 25.93 18.365 27.346-3.313 1.376-9.768-9.017-20.206-13.835-10.437-4.817-25.248-6.287-24.529-8.713z"/> + <path fill="#ccc" d="m194.659 169.137c0.703-2.339 21.603-5.873 25.58-4.521 3.942 1.351 21.167 25.059 17.918 26.44-3.249 1.345-9.493-8.851-19.739-13.58-10.245-4.729-24.462-5.963-23.759-8.339z"/> + <path fill="#c6c6c6" d="m195.484 169.194c0.687-2.292 20.874-5.517 24.79-4.247 3.882 1.27 20.655 24.188 17.47 25.535-3.185 1.314-9.219-8.685-19.271-13.326-10.054-4.639-23.676-5.636-22.989-7.962z"/> + <path fill="#c1c1c1" d="m196.308 169.251c0.671-2.246 20.147-5.161 24-3.973 3.822 1.19 20.145 23.318 17.022 24.63-3.121 1.283-8.943-8.519-18.805-13.071-9.859-4.551-22.888-5.311-22.217-7.586z"/> + <path fill="#bcbcbc" d="m197.133 169.308c0.654-2.199 19.421-4.805 23.21-3.698 3.764 1.109 19.634 22.447 16.575 23.724-3.057 1.252-8.669-8.353-18.338-12.816-9.668-4.462-22.102-4.985-21.447-7.21z"/> + <path fill="#b7b7b7" d="m197.957 169.365c0.64-2.152 18.693-4.45 22.42-3.423 3.705 1.027 19.122 21.575 16.129 22.818-2.993 1.221-8.395-8.186-17.872-12.561-9.476-4.373-21.315-4.66-20.677-6.834z"/> + <path fill="#b2b2b2" d="m198.782 169.421c0.622-2.105 17.966-4.093 21.63-3.147 3.646 0.946 18.61 20.704 15.681 21.912-2.93 1.19-8.12-8.02-17.404-12.306-9.284-4.284-20.53-4.335-19.907-6.459z"/> + <path fill="#adadad" d="m199.606 169.478c0.606-2.058 17.239-3.737 20.84-2.873 3.586 0.866 18.099 19.834 15.234 21.008-2.866 1.158-7.847-7.855-16.938-12.052-9.091-4.196-19.742-4.009-19.136-6.083z"/> + <path fill="#a8a8a8" d="m200.431 169.535c0.59-2.011 16.512-3.382 20.05-2.598 3.525 0.785 17.588 18.963 14.786 20.102-2.803 1.127-7.571-7.688-16.472-11.797-8.898-4.107-18.955-3.684-18.364-5.707z"/> + <path fill="#a3a3a3" d="m201.255 169.592c0.574-1.965 15.785-3.026 19.261-2.323 3.467 0.704 17.076 18.092 14.339 19.196-2.738 1.096-7.296-7.522-16.004-11.542-8.707-4.018-18.17-3.358-17.596-5.331z"/> + <path fill="#9e9e9e" d="m202.08 169.649c0.559-1.918 15.059-2.67 18.47-2.048 3.407 0.623 16.565 17.221 13.892 18.29-2.674 1.065-7.022-7.356-15.537-11.287-8.515-3.929-17.383-3.033-16.825-4.955z"/> + <path fill="#999" d="m202.904 169.705c0.542-1.871 14.331-2.314 17.68-1.773 3.349 0.542 16.055 16.35 13.444 17.385-2.61 1.034-6.747-7.19-15.07-11.032-8.322-3.841-16.596-2.708-16.054-4.58z"/> + </g> + <g transform="translate(-12.4048,10.0005)"> + <path fill="#fff" d="m151.134 211.625c2.881 0.144 0.145 16.271 0.145 32.903s2.231 22.464 0.144 24.552-5.688-5.399-5.688-22.031c-0.001-16.632 2.519-35.568 5.399-35.424z"/> + <path fill="#f9f9f9" d="m151.105 212.016c2.783 0.162 0.109 16.052 0.097 32.419-0.012 16.366 2.188 22.208 0.164 24.237-2.02 2.029-5.561-5.383-5.546-21.752 0.012-16.367 2.502-35.065 5.285-34.904z"/> + <path fill="#f4f4f4" d="m151.075 212.407c2.687 0.18 0.076 15.832 0.051 31.934-0.023 16.102 2.143 21.951 0.185 23.924-1.953 1.968-5.435-5.367-5.405-21.473 0.024-16.103 2.484-34.564 5.169-34.385z"/> + <path fill="#efefef" d="m151.046 212.797c2.588 0.197 0.041 15.613 0.004 31.449-0.036 15.836 2.098 21.694 0.204 23.609-1.886 1.907-5.308-5.352-5.263-21.195 0.037-15.835 2.467-34.058 5.055-33.863z"/> + <path fill="#eaeaea" d="m151.017 213.189c2.49 0.214 0.007 15.392-0.043 30.962-0.05 15.571 2.052 21.439 0.224 23.297-1.818 1.848-5.181-5.334-5.122-20.916 0.049-15.571 2.45-33.557 4.941-33.343z"/> + <path fill="#e5e5e5" d="m150.987 213.581c2.394 0.23-0.027 15.17-0.089 30.477s2.007 21.182 0.244 22.982c-1.751 1.787-5.055-5.32-4.98-20.638 0.061-15.305 2.431-33.053 4.825-32.821z"/> + <path fill="#e0e0e0" d="m150.958 213.971c2.297 0.248-0.062 14.951-0.136 29.99-0.074 15.041 1.962 20.927 0.264 22.668-1.683 1.728-4.928-5.301-4.839-20.356 0.074-15.04 2.414-32.551 4.711-32.302z"/> + <path fill="#dbdbdb" d="m150.928 214.362c2.199 0.266-0.096 14.73-0.182 29.506-0.087 14.775 1.915 20.67 0.282 22.354-1.615 1.667-4.8-5.286-4.696-20.078 0.087-14.776 2.397-32.048 4.596-31.782z"/> + <path fill="#d6d6d6" d="m150.899 214.752c2.102 0.283-0.13 14.511-0.229 29.021-0.099 14.511 1.87 20.413 0.303 22.04-1.549 1.607-4.674-5.27-4.556-19.799 0.1-14.51 2.38-31.545 4.482-31.262z"/> + <path fill="#d1d1d1" d="m150.87 215.144c2.005 0.301-0.165 14.29-0.274 28.535-0.112 14.245 1.824 20.155 0.321 21.725-1.479 1.548-4.547-5.252-4.413-19.519 0.11-14.245 2.361-31.043 4.366-30.741z"/> + <path fill="#ccc" d="m150.84 215.536c1.908 0.317-0.197 14.069-0.32 28.049-0.124 13.979 1.779 19.899 0.342 21.412-1.413 1.486-4.42-5.238-4.272-19.242 0.122-13.979 2.343-30.54 4.25-30.219z"/> + <path fill="#c6c6c6" d="m150.811 215.926c1.811 0.334-0.233 13.85-0.368 27.564-0.136 13.713 1.735 19.643 0.362 21.096-1.346 1.428-4.293-5.219-4.131-18.961 0.136-13.712 2.327-30.035 4.137-29.699z"/> + <path fill="#c1c1c1" d="m150.781 216.317c1.714 0.354-0.267 13.629-0.414 27.078s1.69 19.387 0.382 20.783c-1.277 1.367-4.166-5.203-3.989-18.682 0.148-13.449 2.308-29.533 4.021-29.179z"/> + <path fill="#bcbcbc" d="m150.752 216.708c1.616 0.371-0.301 13.41-0.461 26.594-0.161 13.184 1.646 19.13 0.402 20.469-1.211 1.307-4.04-5.188-3.847-18.402 0.16-13.185 2.29-29.033 3.906-28.661z"/> + <path fill="#b7b7b7" d="m150.723 217.099c1.519 0.387-0.336 13.188-0.509 26.106-0.173 12.92 1.601 18.875 0.423 20.156-1.144 1.246-3.913-5.171-3.706-18.123 0.172-12.919 2.273-28.529 3.792-28.139z"/> + <path fill="#b2b2b2" d="m150.693 217.491c1.422 0.404-0.37 12.969-0.554 25.621-0.186 12.653 1.555 18.617 0.441 19.842-1.076 1.187-3.786-5.156-3.563-17.846 0.184-12.652 2.255-28.024 3.676-27.617z"/> + <path fill="#adadad" d="m150.664 217.881c1.325 0.422-0.404 12.748-0.601 25.136-0.198 12.388 1.51 18.36 0.462 19.528-1.008 1.125-3.66-5.139-3.423-17.566 0.197-12.389 2.238-27.521 3.562-27.098z"/> + <path fill="#a8a8a8" d="m150.634 218.272c1.229 0.439-0.438 12.527-0.646 24.65-0.21 12.123 1.464 18.104 0.48 19.213-0.939 1.066-3.531-5.121-3.279-17.285 0.208-12.123 2.219-27.019 3.445-26.578z"/> + <path fill="#a3a3a3" d="m150.605 218.663c1.13 0.457-0.474 12.309-0.694 24.166-0.222 11.857 1.419 17.848 0.501 18.899-0.873 1.006-3.405-5.106-3.139-17.009 0.222-11.855 2.202-26.515 3.332-26.056z"/> + <path fill="#9e9e9e" d="m150.576 219.054c1.033 0.474-0.507 12.088-0.741 23.68-0.234 11.593 1.374 17.591 0.521 18.585-0.806 0.946-3.279-5.089-2.997-16.729 0.233-11.591 2.184-26.011 3.217-25.536z"/> + <path fill="#999" d="m150.546 219.444c0.937 0.492-0.541 11.868-0.787 23.195-0.246 11.326 1.329 17.335 0.541 18.271-0.737 0.885-3.151-5.074-2.855-16.449 0.245-11.328 2.166-25.509 3.101-25.017z"/> + </g> + <g transform="translate(-12.4048,10.0005)"> + <path fill="#fff" d="m157.434 167.161c1.735 0.192 12.437-2.218 12.822-1.254 0.386 0.772-6.651 2.893-8.966 5.303-0.771 0.771-2.796 2.603-4.049 2.41-0.964-0.096-1.543-2.121-2.989-3.664-3.471-3.47-5.688-3.181-5.013-4.531 0.579-1.06 5.207 1.446 8.195 1.736z"/> + <path fill="#fbfbfb" d="m157.479 167.201c1.7 0.188 12.176-2.171 12.554-1.227 0.377 0.755-6.512 2.832-8.778 5.191-0.755 0.755-2.736 2.549-3.964 2.36-0.942-0.094-1.51-2.077-2.926-3.587-3.398-3.397-5.568-3.115-4.907-4.436 0.565-1.038 5.096 1.415 8.021 1.699z"/> + <path fill="#f8f8f8" d="m157.525 167.241c1.663 0.184 11.914-2.124 12.283-1.201 0.369 0.739-6.372 2.771-8.589 5.08-0.738 0.739-2.679 2.494-3.879 2.309-0.924-0.092-1.479-2.032-2.863-3.51-3.325-3.324-5.449-3.048-4.803-4.341 0.555-1.015 4.988 1.385 7.851 1.663z"/> + <path fill="#f5f5f5" d="m157.57 167.281c1.626 0.18 11.652-2.078 12.014-1.175 0.361 0.723-6.231 2.711-8.4 4.969-0.723 0.722-2.619 2.439-3.793 2.258-0.903-0.09-1.446-1.987-2.802-3.433-3.252-3.251-5.329-2.981-4.695-4.245 0.54-0.993 4.876 1.354 7.676 1.626z"/> + <path fill="#f2f2f2" d="m157.615 167.321c1.59 0.176 11.391-2.031 11.745-1.148 0.352 0.706-6.093 2.649-8.212 4.856-0.707 0.707-2.562 2.385-3.709 2.208-0.883-0.088-1.413-1.943-2.738-3.356-3.179-3.178-5.209-2.914-4.591-4.15 0.529-0.971 4.768 1.324 7.505 1.59z"/> + <path fill="#efefef" d="m157.66 167.361c1.554 0.172 11.13-1.985 11.475-1.122 0.346 0.69-5.952 2.589-8.022 4.745-0.69 0.69-2.503 2.33-3.624 2.157-0.863-0.086-1.381-1.898-2.675-3.279-3.106-3.105-5.09-2.847-4.486-4.055 0.517-0.948 4.658 1.294 7.332 1.554z"/> + <path fill="#ebebeb" d="m157.705 167.401c1.518 0.168 10.868-1.938 11.206-1.096 0.336 0.674-5.813 2.528-7.835 4.634-0.674 0.674-2.444 2.275-3.539 2.106-0.842-0.084-1.348-1.853-2.612-3.202-3.032-3.032-4.97-2.78-4.38-3.959 0.505-0.926 4.549 1.263 7.16 1.517z"/> + <path fill="#e8e8e8" d="m157.751 167.441c1.48 0.164 10.606-1.892 10.936-1.069 0.329 0.657-5.673 2.467-7.646 4.522-0.658 0.657-2.385 2.22-3.453 2.055-0.822-0.082-1.315-1.809-2.549-3.124-2.96-2.96-4.851-2.714-4.275-3.865 0.491-0.904 4.438 1.233 6.987 1.481z"/> + <path fill="#e5e5e5" d="m157.796 167.481c1.444 0.16 10.346-1.845 10.666-1.043 0.32 0.641-5.532 2.406-7.458 4.41-0.641 0.642-2.325 2.166-3.367 2.005-0.803-0.08-1.284-1.764-2.486-3.047-2.887-2.887-4.732-2.647-4.17-3.769 0.48-0.882 4.329 1.202 6.815 1.444z"/> + <path fill="#e2e2e2" d="m157.841 167.521c1.407 0.156 10.083-1.799 10.397-1.017 0.312 0.625-5.394 2.346-7.271 4.299-0.625 0.625-2.267 2.111-3.282 1.954-0.782-0.078-1.251-1.719-2.423-2.97-2.814-2.814-4.612-2.58-4.065-3.674 0.469-0.859 4.221 1.172 6.644 1.408z"/> + <path fill="#dfdfdf" d="m157.886 167.56c1.37 0.152 9.821-1.751 10.127-0.99 0.304 0.609-5.254 2.285-7.081 4.188-0.609 0.609-2.208 2.056-3.198 1.903-0.761-0.076-1.218-1.675-2.36-2.893-2.741-2.741-4.492-2.513-3.959-3.579 0.456-0.837 4.111 1.142 6.471 1.371z"/> + <path fill="#dbdbdb" d="m157.931 167.6c1.335 0.148 9.561-1.704 9.857-0.963 0.296 0.592-5.114 2.223-6.893 4.076-0.593 0.593-2.149 2.001-3.113 1.853-0.741-0.074-1.186-1.631-2.297-2.817-2.668-2.667-4.373-2.446-3.854-3.483 0.445-0.815 4.003 1.111 6.3 1.334z"/> + <path fill="#d8d8d8" d="m157.977 167.64c1.298 0.144 9.299-1.658 9.587-0.937 0.288 0.576-4.974 2.163-6.704 3.964-0.576 0.577-2.091 1.947-3.027 1.803-0.721-0.072-1.153-1.586-2.234-2.74-2.596-2.594-4.253-2.379-3.748-3.388 0.431-0.792 3.891 1.081 6.126 1.298z"/> + <path fill="#d5d5d5" d="m158.022 167.68c1.261 0.14 9.037-1.611 9.317-0.911 0.28 0.56-4.834 2.102-6.516 3.853-0.56 0.561-2.032 1.892-2.942 1.752-0.7-0.07-1.12-1.541-2.172-2.663-2.521-2.521-4.133-2.312-3.643-3.292 0.421-0.77 3.784 1.05 5.956 1.261z"/> + <path fill="#d2d2d2" d="m158.067 167.72c1.225 0.136 8.775-1.564 9.049-0.884 0.271 0.543-4.695 2.041-6.327 3.741-0.545 0.544-1.974 1.837-2.857 1.701-0.682-0.068-1.09-1.497-2.109-2.585-2.449-2.449-4.014-2.246-3.538-3.198 0.407-0.748 3.673 1.02 5.782 1.225z"/> + <path fill="#cfcfcf" d="m158.112 167.76c1.188 0.132 8.515-1.518 8.779-0.858 0.264 0.527-4.555 1.98-6.139 3.63-0.527 0.528-1.915 1.782-2.772 1.65-0.66-0.066-1.057-1.452-2.046-2.508-2.376-2.376-3.895-2.179-3.433-3.103 0.397-0.725 3.565 0.99 5.611 1.189z"/> + <path fill="#ccc" d="m158.157 167.8c1.152 0.128 8.253-1.472 8.51-0.832 0.255 0.511-4.415 1.92-5.95 3.518-0.512 0.512-1.855 1.728-2.688 1.6-0.64-0.064-1.023-1.407-1.983-2.431-2.303-2.303-3.773-2.112-3.326-3.007 0.383-0.703 3.454 0.959 5.437 1.152z"/> + <path fill="#c8c8c8" d="m158.203 167.84c1.115 0.124 7.991-1.425 8.239-0.805 0.248 0.494-4.274 1.858-5.761 3.406-0.496 0.496-1.798 1.673-2.603 1.549-0.62-0.063-0.992-1.363-1.921-2.354-2.229-2.229-3.655-2.045-3.221-2.912 0.372-0.681 3.346 0.929 5.267 1.116z"/> + <path fill="#c5c5c5" d="m158.248 167.88c1.079 0.12 7.73-1.379 7.97-0.779 0.239 0.478-4.135 1.798-5.572 3.295-0.479 0.479-1.739 1.618-2.518 1.498-0.6-0.06-0.959-1.318-1.857-2.277-2.157-2.157-3.535-1.978-3.116-2.816 0.359-0.659 3.235 0.898 5.093 1.079z"/> + <path fill="#c2c2c2" d="m158.293 167.92c1.042 0.116 7.469-1.332 7.701-0.753 0.231 0.462-3.995 1.737-5.385 3.184-0.463 0.463-1.68 1.563-2.432 1.447-0.579-0.058-0.927-1.273-1.796-2.2-2.084-2.084-3.415-1.911-3.01-2.721 0.348-0.636 3.127 0.868 4.922 1.043z"/> + <path fill="#bfbfbf" d="m158.338 167.959c1.007 0.112 7.207-1.285 7.432-0.726 0.223 0.446-3.855 1.676-5.196 3.072-0.447 0.447-1.621 1.509-2.347 1.397-0.56-0.056-0.895-1.229-1.732-2.123-2.011-2.011-3.296-1.844-2.905-2.626 0.334-0.614 3.016 0.838 4.748 1.006z"/> + </g> + <g transform="translate(-12.4048,10.0005)"> + <path d="m194.253 11.922c-1.222 2.631-3.812 23.214-0.248 20.892 3.594-2.341 13.57-5.312 19.886-7.013 7.003-1.886-17.188-19.463-19.638-13.879z"/> + <path fill="#060606" d="m194.485 12.307c-1.21 2.594-3.704 22.255-0.234 20.007 3.491-2.262 13.077-5.1 19.039-6.782 6.59-1.905-16.436-18.609-18.805-13.225z"/> + <path fill="#0c0c0c" d="m194.717 12.691c-1.198 2.557-3.595 21.296-0.221 19.124 3.391-2.184 12.586-4.888 18.194-6.551 6.177-1.924-15.684-17.757-17.973-12.573z"/> + <path fill="#131313" d="m194.949 13.076c-1.187 2.52-3.487 20.337-0.207 18.239 3.288-2.105 12.093-4.676 17.348-6.321 5.763-1.941-14.933-16.903-17.141-11.918z"/> + <path fill="#191919" d="m195.181 13.46c-1.177 2.483-3.379 19.378-0.193 17.355 3.187-2.027 11.6-4.464 16.502-6.09 5.349-1.959-14.182-16.05-16.309-11.265z"/> + <path fill="#1f1f1f" d="m195.413 13.845c-1.164 2.446-3.27 18.419-0.18 16.471 3.086-1.949 11.107-4.252 15.657-5.859 4.935-1.978-13.43-15.198-15.477-10.612z"/> + <path fill="#262626" d="m195.645 14.229c-1.153 2.409-3.162 17.46-0.166 15.586 2.983-1.87 10.616-4.04 14.811-5.628 4.521-1.995-12.679-14.344-14.645-9.958z"/> + <path fill="#2c2c2c" d="m195.878 14.614c-1.142 2.372-3.055 16.501-0.152 14.702 2.882-1.792 10.123-3.828 13.965-5.398 4.107-2.013-11.929-13.49-13.813-9.304z"/> + <path fill="#333" d="m196.11 14.999c-1.131 2.335-2.946 15.542-0.14 13.817 2.78-1.713 9.631-3.616 13.119-5.167 3.695-2.031-11.175-12.637-12.979-8.65z"/> + <path fill="#393939" d="m196.342 15.383c-1.118 2.299-2.838 14.583-0.126 12.934 2.68-1.636 9.139-3.404 12.274-4.937 3.28-2.049-10.425-11.784-12.148-7.997z"/> + <path fill="#3f3f3f" d="m196.574 15.768c-1.108 2.261-2.729 13.624-0.112 12.049 2.577-1.557 8.646-3.192 11.429-4.706 2.865-2.068-9.675-10.931-11.317-7.343z"/> + <path fill="#464646" d="m196.806 16.152c-1.097 2.225-2.622 12.665-0.1 11.165 2.477-1.479 8.154-2.98 10.583-4.475 2.453-2.086-8.922-10.078-10.483-6.69z"/> + <path fill="#4c4c4c" d="m197.038 16.537c-1.085 2.188-2.513 11.706-0.085 10.28 2.374-1.4 7.661-2.768 9.737-4.244 2.039-2.104-8.171-9.225-9.652-6.036z"/> + <path fill="#525252" d="m197.27 16.921c-1.073 2.151-2.405 10.747-0.071 9.396 2.272-1.322 7.168-2.556 8.891-4.013 1.625-2.122-7.42-8.371-8.82-5.383z"/> + <path fill="#595959" d="m197.502 17.306c-1.062 2.113-2.297 9.788-0.058 8.512 2.172-1.244 6.677-2.344 8.046-3.783 1.211-2.14-6.669-7.518-7.988-4.729z"/> + <path fill="#5f5f5f" d="m197.734 17.69c-1.05 2.077-2.188 8.829-0.044 7.627 2.069-1.165 6.184-2.132 7.2-3.552 0.797-2.157-5.917-6.664-7.156-4.075z"/> + <path fill="#666" d="m197.966 18.075c-1.038 2.04-2.079 7.87-0.029 6.743 1.968-1.087 5.69-1.92 6.354-3.321 0.382-2.176-5.167-5.812-6.325-3.422z"/> + <path fill="#6c6c6c" d="m198.198 18.459c-1.027 2.003-1.972 6.911-0.017 5.859 1.866-1.008 5.198-1.708 5.509-3.09-0.03-2.194-4.415-4.959-5.492-2.769z"/> + <path fill="#727272" d="m198.43 18.844c-1.017 1.966-1.863 5.952-0.003 4.975 1.765-0.93 4.706-1.496 4.662-2.86-0.443-2.212-3.662-4.106-4.659-2.115z"/> + <path fill="#797979" d="m198.662 19.228c-1.004 1.929-1.755 4.993 0.011 4.09 1.663-0.852 4.215-1.284 3.817-2.629-0.858-2.23-2.912-3.251-3.828-1.461z"/> + <path fill="#7f7f7f" d="m198.894 19.612c-0.993 1.892-1.647 4.034 0.023 3.206 1.563-0.773 3.723-1.072 2.973-2.398-1.272-2.248-2.161-2.399-2.996-0.808z"/> + </g> + <g transform="translate(-12.4048,10.0005)"> + <path d="m143.502 46.386c-0.72 2.16 8.712 5.112 10.801 6.984 2.808 2.52 3.023 7.488 6.336 5.472 2.159-1.296 0.504-4.176-3.456-8.568-5.833-6.481-13.033-5.689-13.681-3.888z"/> + <path fill="#050505" d="m143.991 46.582c-0.716 2.073 8.275 4.9 10.336 6.741 2.745 2.457 2.961 7.249 6.146 5.313 2.094-1.254 0.449-4.072-3.343-8.28-5.574-6.203-12.491-5.505-13.139-3.774z"/> + <path fill="#0a0a0a" d="m144.479 46.779c-0.71 1.987 7.839 4.688 9.873 6.498 2.682 2.394 2.897 7.009 5.956 5.154 2.028-1.212 0.395-3.968-3.228-7.993-5.319-5.926-11.953-5.321-12.601-3.659z"/> + <path fill="#0f0f0f" d="m144.967 46.976c-0.704 1.9 7.403 4.476 9.41 6.254 2.62 2.33 2.835 6.77 5.766 4.995 1.964-1.171 0.342-3.864-3.112-7.706-5.064-5.647-11.415-5.137-12.064-3.543z"/> + <path fill="#141414" d="m145.456 47.172c-0.701 1.813 6.966 4.263 8.946 6.011 2.557 2.266 2.772 6.53 5.575 4.835 1.897-1.129 0.287-3.76-2.998-7.418-4.807-5.369-10.874-4.952-11.523-3.428z"/> + <path fill="#191919" d="m145.944 47.369c-0.696 1.726 6.53 4.051 8.483 5.768 2.493 2.203 2.71 6.291 5.385 4.676 1.833-1.087 0.231-3.656-2.884-7.13-4.551-5.093-10.335-4.769-10.984-3.314z"/> + <path fill="#1e1e1e" d="m146.433 47.565c-0.692 1.64 6.093 3.839 8.019 5.525 2.431 2.14 2.647 6.052 5.194 4.517 1.768-1.046 0.179-3.552-2.77-6.843-4.293-4.814-9.794-4.585-10.443-3.199z"/> + <path fill="#232323" d="m146.921 47.762c-0.686 1.553 5.657 3.627 7.558 5.282 2.367 2.076 2.583 5.813 5.003 4.357 1.702-1.003 0.124-3.448-2.654-6.555-4.04-4.537-9.257-4.401-9.907-3.084z"/> + <path fill="#282828" d="m147.409 47.959c-0.681 1.466 5.221 3.415 7.094 5.039 2.305 2.013 2.521 5.573 4.813 4.198 1.637-0.962 0.07-3.344-2.54-6.268-3.782-4.26-8.717-4.218-9.367-2.969z"/> + <path fill="#2d2d2d" d="m147.898 48.156c-0.677 1.379 4.784 3.203 6.63 4.795 2.242 1.949 2.457 5.333 4.622 4.039 1.572-0.92 0.016-3.24-2.425-5.98-3.526-3.983-8.177-4.034-8.827-2.854z"/> + <path fill="#333" d="m148.386 48.353c-0.673 1.292 4.348 2.99 6.167 4.552 2.179 1.886 2.394 5.095 4.432 3.88 1.506-0.878-0.038-3.136-2.312-5.693-3.268-3.705-7.636-3.85-8.287-2.739z"/> + <path fill="#383838" d="m148.875 48.549c-0.668 1.206 3.911 2.778 5.703 4.309 2.116 1.823 2.331 4.855 4.242 3.721 1.439-0.836-0.093-3.032-2.197-5.405-3.013-3.428-7.098-3.667-7.748-2.625z"/> + <path fill="#3d3d3d" d="m149.363 48.746c-0.662 1.119 3.475 2.566 5.24 4.065 2.053 1.759 2.268 4.616 4.052 3.562 1.375-0.795-0.147-2.928-2.082-5.118-2.757-3.15-6.559-3.483-7.21-2.509z"/> + <path fill="#424242" d="m149.851 48.942c-0.657 1.032 3.039 2.354 4.776 3.823 1.99 1.696 2.205 4.376 3.861 3.402 1.31-0.753-0.201-2.824-1.967-4.831-2.5-2.871-6.018-3.298-6.67-2.394z"/> + <path fill="#474747" d="m150.34 49.139c-0.652 0.946 2.603 2.142 4.313 3.58 1.927 1.632 2.143 4.137 3.671 3.243 1.244-0.712-0.256-2.72-1.853-4.543-2.245-2.595-5.48-3.115-6.131-2.28z"/> + <path fill="#4c4c4c" d="m150.828 49.336c-0.647 0.859 2.166 1.93 3.851 3.336 1.863 1.569 2.079 3.898 3.48 3.084 1.179-0.67-0.31-2.616-1.739-4.255-1.988-2.317-4.94-2.932-5.592-2.165z"/> + <path fill="#515151" d="m151.317 49.533c-0.645 0.772 1.729 1.718 3.386 3.093 1.802 1.505 2.018 3.658 3.29 2.925 1.114-0.628-0.364-2.512-1.624-3.968-1.732-2.04-4.4-2.748-5.052-2.05z"/> + <path fill="#565656" d="m151.805 49.729c-0.639 0.685 1.293 1.505 2.923 2.85 1.738 1.442 1.954 3.419 3.1 2.766 1.048-0.586-0.418-2.408-1.509-3.681-1.476-1.762-3.862-2.563-4.514-1.935z"/> + <path fill="#5b5b5b" d="m152.293 49.926c-0.633 0.598 0.857 1.293 2.46 2.606 1.677 1.379 1.892 3.18 2.91 2.606 0.983-0.544-0.473-2.304-1.395-3.393-1.22-1.483-3.322-2.379-3.975-1.819z"/> + <path fill="#606060" d="m152.782 50.123c-0.629 0.512 0.42 1.081 1.996 2.363 1.613 1.315 1.828 2.94 2.719 2.447 0.918-0.502-0.525-2.2-1.28-3.105-0.963-1.207-2.782-2.196-3.435-1.705z"/> + <path fill="#666" d="m153.27 50.319c-0.624 0.425-0.017 0.869 1.533 2.12 1.55 1.252 1.765 2.701 2.528 2.288 0.853-0.461-0.581-2.096-1.166-2.818-0.706-0.929-2.242-2.012-2.895-1.59z"/> + </g> + <g transform="translate(-12.4048,10.0005)"> + <path d="m193.47 45.594c-0.072 1.08 2.951 1.728 4.896 2.448 1.944 0.648 5.76 3.24 7.56 5.256 1.801 1.944 5.688 7.704 6.553 6.192 0.863-1.368-2.017-5.328-2.809-6.984s-3.239-5.256-7.128-6.48c-3.384-1.008-9-1.297-9.072-0.432z"/> + <path fill="#060606" d="m193.779 45.67c-0.071 1.05 2.869 1.685 4.758 2.387 1.891 0.633 5.598 3.161 7.345 5.122 1.747 1.893 5.535 7.493 6.376 6.027 0.84-1.328-1.936-5.173-2.738-6.795-0.8-1.622-3.175-5.09-6.952-6.301-3.282-0.995-8.718-1.28-8.789-0.44z"/> + <path fill="#0c0c0c" d="m194.088 45.747c-0.07 1.021 2.785 1.641 4.62 2.327 1.836 0.618 5.436 3.081 7.131 4.988 1.692 1.842 5.382 7.282 6.198 5.862 0.814-1.288-1.855-5.019-2.67-6.607-0.808-1.587-3.11-4.925-6.776-6.122-3.178-0.983-8.433-1.264-8.503-0.448z"/> + <path fill="#131313" d="m194.397 45.824c-0.071 0.991 2.702 1.598 4.481 2.267 1.782 0.603 5.272 3.001 6.916 4.854 1.64 1.791 5.229 7.071 6.022 5.697 0.788-1.248-1.776-4.865-2.603-6.418-0.815-1.554-3.044-4.759-6.599-5.942-3.073-0.973-8.148-1.251-8.217-0.458z"/> + <path fill="#191919" d="m194.706 45.9c-0.069 0.961 2.618 1.555 4.345 2.206 1.728 0.588 5.109 2.922 6.7 4.721 1.586 1.74 5.075 6.86 5.846 5.531 0.764-1.207-1.696-4.711-2.532-6.23-0.824-1.519-2.979-4.593-6.424-5.763-2.972-0.959-7.866-1.234-7.935-0.465z"/> + <path fill="#1f1f1f" d="m195.015 45.977c-0.07 0.931 2.534 1.511 4.207 2.146 1.672 0.573 4.945 2.843 6.485 4.586 1.531 1.689 4.921 6.649 5.668 5.367 0.738-1.167-1.616-4.557-2.464-6.042-0.832-1.485-2.914-4.428-6.247-5.583-2.868-0.948-7.581-1.219-7.649-0.474z"/> + <path fill="#262626" d="m195.324 46.054c-0.069 0.901 2.451 1.468 4.069 2.085 1.618 0.557 4.784 2.763 6.271 4.453 1.479 1.638 4.769 6.438 5.491 5.201 0.714-1.127-1.536-4.402-2.396-5.854-0.839-1.451-2.848-4.263-6.07-5.404-2.765-0.934-7.298-1.202-7.365-0.481z"/> + <path fill="#2c2c2c" d="m195.632 46.13c-0.067 0.872 2.369 1.424 3.933 2.025 1.563 0.542 4.621 2.684 6.056 4.318 1.424 1.587 4.615 6.228 5.315 5.036 0.688-1.086-1.456-4.248-2.326-5.665-0.848-1.416-2.783-4.097-5.896-5.224-2.662-0.923-7.015-1.187-7.082-0.49z"/> + <path fill="#333" d="m195.941 46.207c-0.068 0.842 2.285 1.381 3.794 1.964 1.51 0.527 4.458 2.605 5.842 4.185 1.37 1.536 4.461 6.016 5.138 4.871 0.662-1.046-1.377-4.093-2.258-5.476-0.855-1.382-2.718-3.932-5.718-5.045-2.56-0.911-6.732-1.172-6.798-0.499z"/> + <path fill="#393939" d="m196.25 46.284c-0.066 0.813 2.202 1.338 3.656 1.904 1.456 0.512 4.296 2.525 5.627 4.051 1.317 1.485 4.308 5.805 4.961 4.706 0.638-1.006-1.296-3.939-2.188-5.288-0.863-1.348-2.652-3.766-5.542-4.866-2.457-0.899-6.449-1.157-6.514-0.507z"/> + <path fill="#3f3f3f" d="m196.559 46.36c-0.067 0.783 2.118 1.295 3.518 1.844 1.402 0.497 4.133 2.446 5.412 3.917 1.263 1.434 4.155 5.594 4.785 4.541 0.612-0.966-1.217-3.785-2.12-5.1-0.872-1.313-2.587-3.6-5.366-4.687-2.353-0.886-6.165-1.141-6.229-0.515z"/> + <path fill="#464646" d="m196.868 46.437c-0.065 0.753 2.035 1.251 3.38 1.783 1.349 0.482 3.972 2.367 5.197 3.783 1.21 1.383 4.002 5.383 4.608 4.375 0.588-0.926-1.137-3.63-2.052-4.911-0.879-1.279-2.521-3.435-5.189-4.507-2.25-0.874-5.881-1.125-5.944-0.523z"/> + <path fill="#4c4c4c" d="m197.177 46.514c-0.066 0.723 1.95 1.208 3.241 1.723 1.293 0.467 3.809 2.287 4.983 3.649 1.155 1.332 3.848 5.172 4.431 4.21 0.563-0.885-1.057-3.476-1.982-4.723-0.888-1.245-2.456-3.269-5.014-4.328-2.146-0.862-5.597-1.109-5.659-0.531z"/> + <path fill="#525252" d="m197.486 46.591c-0.066 0.693 1.868 1.164 3.104 1.662 1.239 0.452 3.646 2.208 4.769 3.515 1.102 1.281 3.695 4.961 4.254 4.045 0.537-0.845-0.976-3.321-1.913-4.534-0.896-1.21-2.391-3.103-4.838-4.148-2.044-0.851-5.315-1.095-5.376-0.54z"/> + <path fill="#595959" d="m197.795 46.667c-0.064 0.664 1.784 1.121 2.968 1.602 1.184 0.437 3.481 2.128 4.552 3.381 1.049 1.23 3.542 4.75 4.078 3.88 0.512-0.805-0.897-3.167-1.846-4.346-0.902-1.176-2.325-2.938-4.66-3.969-1.942-0.838-5.031-1.078-5.092-0.548z"/> + <path fill="#5f5f5f" d="m198.104 46.744c-0.065 0.634 1.701 1.078 2.829 1.541 1.13 0.421 3.318 2.049 4.338 3.248 0.994 1.179 3.388 4.539 3.899 3.715 0.487-0.765-0.815-3.013-1.775-4.157-0.911-1.142-2.261-2.772-4.485-3.79-1.837-0.826-4.746-1.064-4.806-0.557z"/> + <path fill="#666" d="m198.413 46.821c-0.063 0.604 1.617 1.034 2.691 1.481 1.076 0.406 3.157 1.969 4.123 3.113 0.94 1.128 3.234 4.328 3.724 3.55 0.462-0.725-0.737-2.858-1.707-3.969-0.919-1.108-2.195-2.606-4.309-3.61-1.734-0.814-4.463-1.049-4.522-0.565z"/> + <path fill="#6c6c6c" d="m198.721 46.897c-0.063 0.574 1.534 0.991 2.554 1.42 1.021 0.391 2.994 1.89 3.908 2.979 0.887 1.077 3.082 4.117 3.548 3.384 0.436-0.685-0.657-2.704-1.64-3.78-0.927-1.074-2.13-2.44-4.132-3.431-1.631-0.8-4.179-1.031-4.238-0.572z"/> + <path fill="#727272" d="m199.03 46.974c-0.063 0.544 1.451 0.948 2.416 1.36 0.967 0.376 2.831 1.811 3.694 2.846 0.833 1.026 2.928 3.906 3.369 3.219 0.411-0.644-0.576-2.549-1.569-3.592-0.936-1.04-2.064-2.275-3.956-3.251-1.528-0.79-3.896-1.017-3.954-0.582z"/> + <path fill="#797979" d="m199.339 47.051c-0.062 0.515 1.368 0.904 2.278 1.299 0.913 0.361 2.669 1.731 3.479 2.712 0.779 0.975 2.774 3.695 3.193 3.054 0.386-0.604-0.497-2.396-1.501-3.403-0.942-1.005-1.999-2.11-3.78-3.072-1.424-0.778-3.612-1.002-3.669-0.59z"/> + <path fill="#7f7f7f" d="m199.648 47.127c-0.063 0.485 1.284 0.861 2.14 1.239 0.859 0.346 2.506 1.652 3.265 2.578 0.726 0.924 2.621 3.484 3.017 2.889 0.361-0.564-0.417-2.241-1.432-3.215-0.951-0.971-1.935-1.944-3.604-2.893-1.323-0.765-3.33-0.986-3.386-0.598z"/> + </g> + <g transform="translate(-12.4048,10.0005)"> + <path fill="#995900" d="m303.631 262.529c4.464 6.479-0.145 14.904 3.096 20.089 5.328 8.496 16.056 17.063 20.16 19.439 2.952 1.8 7.128 3.527 6.983 8.783-0.216 5.977-3.168 7.561-4.823 9.217-3.313 3.313-20.017 11.592-31.104 19.152-13.968 9.576-18.792 13.824-23.328 18.359-7.056 7.057-13.752 9.432-24.48 9.432s-15.552-2.231-18.863-5.184c-3.313-2.88-6.984-10.225-6.624-21.168 0.288-10.872 3.744-20.809 5.399-37.729 0.721-7.271 0.648-16.271 0.648-24.264 0-10.08 0.144-18.648 2.304-19.943 3.889-2.448 4.752-2.592 9.36-2.592 4.607 0 6.696 0.287 8.208 1.799 1.439 1.44 0.864 4.752 0.359 9.433-0.432 4.681 1.801 6.192 4.032 8.136 2.232 1.872 4.248 4.248 11.305 4.824 7.056 0.504 9.647-0.648 12.96-2.736 3.312-2.088 7.991-5.832 9.72-7.992 1.656-2.088 5.76-9.287 6.552-9.287 0.719 0 5.472-1.656 8.136 2.232z"/> + <path fill="#9e5e00" d="m303.631 262.529c4.464 6.479-0.145 14.904 3.096 20.089 5.328 8.496 16.056 17.063 20.16 19.439 2.952 1.8 7.128 3.527 6.983 8.783-0.216 5.977-3.168 7.561-4.823 9.217-3.313 3.313-20.12 11.556-31.26 19.008-13.885 9.371-18.903 13.54-23.521 17.902-6.912 6.74-13.414 9.084-23.915 9.019-10.411-0.047-15.116-2.181-18.414-5.118-3.297-2.867-6.931-9.966-6.613-20.578 0.205-10.851 3.701-20.683 5.256-37.279 0.666-7.379 0.407-16.303 0.335-24.375-0.076-10.068-0.072-18.627 2.084-19.922 3.889-2.444 4.752-2.592 9.36-2.592 4.607 0 6.7 0.291 8.208 1.799 1.491 1.492 0.767 4.887 0.205 9.408-0.63 4.658 1.458 6.486 3.795 8.607 2.34 2.059 4.489 4.471 11.534 5.021 7.232 0.482 10.015-0.832 13.362-3.106 3.303-2.207 7.773-5.903 9.513-8.168 1.641-2.132 5.727-9.386 6.519-9.386 0.719 0 5.472-1.656 8.136 2.232z"/> + <path fill="#a36400" d="m303.631 262.529c4.464 6.479-0.145 14.904 3.096 20.089 5.328 8.496 16.056 17.063 20.16 19.439 2.952 1.8 7.128 3.527 6.983 8.783-0.216 5.977-3.168 7.561-4.823 9.217-3.313 3.313-20.226 11.52-31.414 18.863-13.803 9.166-19.016 13.256-23.717 17.447-6.768 6.422-13.075 8.733-23.35 8.604-10.094-0.094-14.682-2.131-17.964-5.055-3.283-2.852-6.876-9.705-6.603-19.987 0.122-10.828 3.657-20.556 5.112-36.828 0.612-7.487 0.165-16.336 0.021-24.487-0.15-10.058-0.287-18.605 1.865-19.9 3.889-2.44 4.752-2.592 9.36-2.592 4.607 0 6.703 0.295 8.208 1.799 1.541 1.541 0.67 5.02 0.051 9.383-0.828 4.637 1.116 6.781 3.556 9.078 2.448 2.248 4.731 4.695 11.766 5.221 7.409 0.461 10.383-1.016 13.767-3.477 3.29-2.326 7.552-5.977 9.302-8.346 1.627-2.175 5.695-9.482 6.487-9.482 0.72-0.001 5.473-1.657 8.137 2.231z"/> + <path fill="#a86a00" d="m303.631 262.529c4.464 6.479-0.145 14.904 3.096 20.089 5.328 8.496 16.056 17.063 20.16 19.439 2.952 1.8 7.128 3.527 6.983 8.783-0.216 5.977-3.168 7.561-4.823 9.217-3.313 3.313-20.329 11.484-31.568 18.72-13.721 8.961-19.127 12.972-23.911 16.989-6.624 6.105-12.737 8.384-22.785 8.189-9.777-0.141-14.245-2.08-17.514-4.99-3.27-2.836-6.822-9.445-6.591-19.396 0.038-10.807 3.613-20.43 4.968-36.378 0.558-7.597-0.076-16.368-0.292-24.599-0.228-10.047-0.504-18.584 1.645-19.879 3.889-2.438 4.752-2.592 9.36-2.592 4.607 0 6.707 0.299 8.208 1.799 1.591 1.593 0.573 5.152-0.104 9.357-1.025 4.615 0.774 7.077 3.319 9.551 2.556 2.434 4.972 4.918 11.995 5.418 7.585 0.439 10.75-1.199 14.17-3.849 3.279-2.444 7.333-6.048 9.093-8.521 1.613-2.219 5.663-9.58 6.455-9.58 0.719 0.001 5.472-1.655 8.136 2.233z"/> + <path fill="#ad7000" d="m303.631 262.529c4.464 6.479-0.145 14.904 3.096 20.089 5.328 8.496 16.056 17.063 20.16 19.439 2.952 1.8 7.128 3.527 6.983 8.783-0.216 5.977-3.168 7.561-4.823 9.217-3.313 3.313-20.434 11.447-31.724 18.576-13.637 8.756-19.238 12.687-24.106 16.531-6.479 5.789-12.397 8.035-22.219 7.776-9.461-0.188-13.809-2.03-17.063-4.925-3.254-2.823-6.769-9.188-6.581-18.807-0.043-10.785 3.571-20.305 4.824-35.928 0.504-7.705-0.316-16.402-0.604-24.711-0.303-10.037-0.72-18.563 1.425-19.857 3.889-2.434 4.752-2.592 9.36-2.592 4.607 0 6.711 0.303 8.208 1.799 1.642 1.643 0.475 5.285-0.259 9.332-1.225 4.594 0.432 7.373 3.082 10.022 2.664 2.621 5.212 5.142 12.225 5.616 7.762 0.418 11.117-1.383 14.573-4.219 3.269-2.563 7.113-6.121 8.885-8.698 1.598-2.261 5.63-9.677 6.422-9.677 0.719 0.002 5.472-1.654 8.136 2.234z"/> + <path fill="#b27500" d="m303.631 262.529c4.464 6.479-0.145 14.904 3.096 20.089 5.328 8.496 16.056 17.063 20.16 19.439 2.952 1.8 7.128 3.527 6.983 8.783-0.216 5.977-3.168 7.561-4.823 9.217-3.313 3.313-20.538 11.412-31.879 18.432-13.554 8.551-19.35 12.402-24.3 16.074-6.336 5.473-12.06 7.686-21.654 7.361-9.144-0.233-13.374-1.979-16.613-4.859-3.24-2.809-6.714-8.928-6.57-18.216-0.126-10.765 3.528-20.179 4.68-35.478 0.45-7.813-0.558-16.435-0.918-24.822-0.378-10.026-0.936-18.541 1.206-19.836 3.889-2.43 4.752-2.592 9.36-2.592 4.607 0 6.714 0.305 8.208 1.799 1.691 1.693 0.378 5.418-0.414 9.307-1.422 4.572 0.09 7.668 2.844 10.494 2.772 2.808 5.454 5.363 12.456 5.814 7.938 0.396 11.484-1.566 14.977-4.591 3.258-2.682 6.894-6.192 8.676-8.874 1.584-2.304 5.598-9.773 6.39-9.773 0.718 0 5.471-1.656 8.135 2.232z"/> + <path fill="#b77b00" d="m303.631 262.529c4.464 6.479-0.145 14.904 3.096 20.089 5.328 8.496 16.056 17.063 20.16 19.439 2.952 1.8 7.128 3.527 6.983 8.783-0.216 5.977-3.168 7.561-4.823 9.217-3.313 3.313-20.643 11.376-32.033 18.288-13.472 8.345-19.461 12.118-24.494 15.616-6.192 5.156-11.723 7.338-21.089 6.949-8.827-0.281-12.938-1.93-16.164-4.795-3.226-2.795-6.66-8.67-6.56-17.627-0.209-10.742 3.485-20.052 4.536-35.027 0.396-7.92-0.799-16.467-1.23-24.934-0.454-10.015-1.152-18.52 0.985-19.814 3.889-2.426 4.752-2.592 9.36-2.592 4.607 0 6.718 0.31 8.208 1.799 1.743 1.744 0.281 5.553-0.569 9.281-1.62 4.551-0.252 7.963 2.607 10.967 2.88 2.994 5.694 5.586 12.686 6.012 8.115 0.373 11.852-1.75 15.379-4.961 3.248-2.801 6.676-6.264 8.469-9.051 1.568-2.348 5.564-9.871 6.356-9.871 0.72 0 5.473-1.656 8.137 2.232z"/> + <path fill="#bc8100" d="m303.631 262.529c4.464 6.479-0.145 14.904 3.096 20.089 5.328 8.496 16.056 17.063 20.16 19.439 2.952 1.8 7.128 3.527 6.983 8.783-0.216 5.977-3.168 7.561-4.823 9.217-3.313 3.313-20.747 11.34-32.188 18.145-13.389 8.139-19.574 11.834-24.689 15.159-6.048 4.839-11.383 6.988-20.523 6.534-8.51-0.328-12.503-1.879-15.714-4.73-3.211-2.779-6.606-8.41-6.549-17.035-0.292-10.721 3.441-19.926 4.393-34.578 0.342-8.028-1.041-16.498-1.545-25.045-0.529-10.004-1.368-18.498 0.767-19.793 3.889-2.422 4.752-2.592 9.36-2.592 4.607 0 6.721 0.313 8.208 1.799 1.793 1.793 0.184 5.686-0.723 9.256-1.818 4.529-0.595 8.259 2.367 11.438 2.988 3.184 5.938 5.811 12.917 6.211 8.291 0.352 12.22-1.934 15.783-5.332 3.236-2.92 6.454-6.336 8.258-9.227 1.556-2.391 5.533-9.969 6.325-9.969 0.72-0.001 5.473-1.657 8.137 2.231z"/> + <path fill="#c18700" d="m303.631 262.529c4.464 6.479-0.145 14.904 3.096 20.089 5.328 8.496 16.056 17.063 20.16 19.439 2.952 1.8 7.128 3.527 6.983 8.783-0.216 5.977-3.168 7.561-4.823 9.217-3.313 3.313-20.852 11.304-32.343 18-13.306 7.936-19.685 11.549-24.883 14.703-5.904 4.521-11.045 6.638-19.959 6.119-8.193-0.375-12.067-1.828-15.264-4.666-3.197-2.764-6.553-8.149-6.537-16.444-0.375-10.699 3.397-19.8 4.248-34.128 0.288-8.137-1.282-16.531-1.858-25.156-0.604-9.994-1.584-18.477 0.547-19.771 3.889-2.42 4.752-2.592 9.36-2.592 4.607 0 6.725 0.316 8.208 1.799 1.843 1.845 0.087 5.818-0.878 9.231-2.017 4.507-0.937 8.554 2.131 11.909 3.096 3.369 6.178 6.033 13.146 6.408 8.468 0.33 12.587-2.117 16.187-5.703 3.225-3.038 6.235-6.408 8.049-9.402 1.541-2.436 5.501-10.066 6.293-10.066 0.72-0.001 5.473-1.657 8.137 2.231z"/> + <path fill="#c68c00" d="m303.631 262.529c4.464 6.479-0.145 14.904 3.096 20.089 5.328 8.496 16.056 17.063 20.16 19.439 2.952 1.8 7.128 3.527 6.983 8.783-0.216 5.977-3.168 7.561-4.823 9.217-3.313 3.313-20.955 11.268-32.498 17.855-13.223 7.73-19.796 11.266-25.077 14.246-5.761 4.204-10.706 6.289-19.394 5.707-7.877-0.423-11.631-1.779-14.813-4.602-3.183-2.751-6.498-7.891-6.527-15.855-0.457-10.677 3.355-19.674 4.104-33.678 0.234-8.244-1.521-16.563-2.17-25.268-0.681-9.983-1.8-18.455 0.327-19.75 3.889-2.416 4.752-2.592 9.36-2.592 4.607 0 6.729 0.32 8.208 1.799 1.894 1.895-0.011 5.951-1.033 9.207-2.214 4.484-1.278 8.848 1.895 12.379 3.203 3.558 6.418 6.258 13.377 6.607 8.644 0.309 12.952-2.301 16.589-6.074 3.215-3.156 6.016-6.479 7.841-9.58 1.526-2.477 5.468-10.162 6.26-10.162 0.718 0.001 5.471-1.655 8.135 2.233z"/> + <path fill="#cc9200" d="m303.631 262.529c4.464 6.479-0.145 14.904 3.096 20.089 5.328 8.496 16.056 17.063 20.16 19.439 2.952 1.8 7.128 3.527 6.983 8.783-0.216 5.977-3.168 7.561-4.823 9.217-3.313 3.313-21.061 11.232-32.652 17.712-13.141 7.524-19.908 10.979-25.272 13.788-5.616 3.888-10.368 5.939-18.828 5.292-7.56-0.468-11.195-1.728-14.363-4.536-3.168-2.736-6.444-7.632-6.517-15.264-0.54-10.656 3.313-19.549 3.96-33.229 0.181-8.352-1.764-16.596-2.483-25.38-0.757-9.972-2.017-18.433 0.107-19.728 3.889-2.412 4.752-2.592 9.36-2.592 4.607 0 6.731 0.323 8.208 1.799 1.944 1.945-0.108 6.084-1.188 9.181-2.412 4.464-1.62 9.144 1.656 12.853 3.313 3.744 6.66 6.479 13.608 6.803 8.819 0.289 13.319-2.483 16.991-6.443 3.204-3.275 5.797-6.553 7.633-9.756 1.512-2.52 5.436-10.26 6.228-10.26 0.719 0 5.472-1.656 8.136 2.232z"/> + <path fill="#d19800" d="m303.631 262.529c4.464 6.479-0.145 14.904 3.096 20.089 5.328 8.496 16.056 17.063 20.16 19.439 2.952 1.8 7.128 3.527 6.983 8.783-0.216 5.977-3.168 7.561-4.823 9.217-3.313 3.313-21.164 11.195-32.808 17.568-13.057 7.318-20.019 10.695-25.466 13.33-5.473 3.571-10.03 5.592-18.263 4.879-7.243-0.516-10.761-1.678-13.914-4.472-3.153-2.722-6.391-7.372-6.506-14.674-0.623-10.634 3.27-19.422 3.816-32.778 0.126-8.459-2.005-16.627-2.797-25.49-0.832-9.961-2.232-18.412-0.112-19.707 3.889-2.408 4.752-2.592 9.36-2.592 4.607 0 6.736 0.328 8.208 1.799 1.995 1.996-0.205 6.219-1.343 9.156-2.61 4.442-1.962 9.438 1.419 13.323 3.42 3.931 6.9 6.703 13.838 7.002 8.997 0.267 13.687-2.668 17.395-6.815 3.194-3.395 5.577-6.623 7.424-9.932 1.497-2.564 5.403-10.357 6.195-10.357 0.721 0 5.474-1.656 8.138 2.232z"/> + <path fill="#d69e00" d="m303.631 262.529c4.464 6.479-0.145 14.904 3.096 20.089 5.328 8.496 16.056 17.063 20.16 19.439 2.952 1.8 7.128 3.527 6.983 8.783-0.216 5.977-3.168 7.561-4.823 9.217-3.313 3.313-21.27 11.16-32.962 17.424-12.975 7.114-20.132 10.412-25.661 12.874-5.327 3.254-9.69 5.242-17.697 4.464-6.927-0.563-10.325-1.627-13.464-4.406-3.14-2.707-6.337-7.113-6.494-14.084-0.706-10.611 3.225-19.295 3.672-32.328 0.072-8.567-2.247-16.66-3.111-25.603-0.907-9.95-2.448-18.39-0.331-19.685 3.889-2.404 4.752-2.592 9.36-2.592 4.607 0 6.739 0.332 8.208 1.799 2.045 2.045-0.302 6.352-1.497 9.131-2.808 4.421-2.304 9.734 1.18 13.795 3.528 4.119 7.144 6.927 14.069 7.199 9.173 0.246 14.055-2.851 17.799-7.185 3.182-3.514 5.356-6.696 7.214-10.108 1.483-2.607 5.371-10.455 6.163-10.455 0.719 0 5.472-1.656 8.136 2.232z"/> + <path fill="#dba300" d="m303.631 262.529c4.464 6.479-0.145 14.904 3.096 20.089 5.328 8.496 16.056 17.063 20.16 19.439 2.952 1.8 7.128 3.527 6.983 8.783-0.216 5.977-3.168 7.561-4.823 9.217-3.313 3.313-21.373 11.124-33.116 17.279-12.893 6.91-20.243 10.127-25.855 12.418-5.184 2.937-9.353 4.892-17.133 4.05-6.609-0.609-9.889-1.577-13.014-4.343-3.125-2.692-6.282-6.854-6.483-13.492-0.789-10.592 3.182-19.17 3.528-31.879 0.018-8.676-2.488-16.692-3.425-25.713-0.982-9.94-2.664-18.369-0.551-19.664 3.889-2.401 4.752-2.592 9.36-2.592 4.607 0 6.743 0.334 8.208 1.799 2.095 2.097-0.399 6.484-1.652 9.105-3.006 4.398-2.646 10.029 0.943 14.268 3.636 4.305 7.384 7.148 14.299 7.397 9.349 0.224 14.422-3.034 18.202-7.558 3.171-3.631 5.137-6.768 7.005-10.284 1.469-2.649 5.339-10.552 6.131-10.552 0.72 0.001 5.473-1.655 8.137 2.233z"/> + <path fill="#e0a900" d="m303.631 262.529c4.464 6.479-0.145 14.904 3.096 20.089 5.328 8.496 16.056 17.063 20.16 19.439 2.952 1.8 7.128 3.527 6.983 8.783-0.216 5.977-3.168 7.561-4.823 9.217-3.313 3.313-21.478 11.088-33.271 17.136-12.81 6.704-20.354 9.843-26.05 11.96-5.04 2.62-9.015 4.543-16.567 3.637-6.293-0.656-9.453-1.527-12.563-4.277-3.11-2.68-6.229-6.596-6.474-12.903-0.871-10.569 3.141-19.044 3.384-31.428-0.035-8.784-2.728-16.726-3.735-25.826-1.06-9.929-2.88-18.347-0.771-19.642 3.889-2.397 4.752-2.592 9.36-2.592 4.607 0 6.747 0.338 8.208 1.799 2.146 2.146-0.497 6.617-1.808 9.08-3.203 4.377-2.987 10.324 0.706 14.738 3.744 4.493 7.624 7.373 14.529 7.596 9.526 0.203 14.789-3.217 18.605-7.926 3.161-3.752 4.918-6.841 6.797-10.463 1.454-2.693 5.306-10.648 6.098-10.648 0.719-0.001 5.472-1.657 8.136 2.231z"/> + <path fill="#e5af00" d="m303.631 262.529c4.464 6.479-0.145 14.904 3.096 20.089 5.328 8.496 16.056 17.063 20.16 19.439 2.952 1.8 7.128 3.527 6.983 8.783-0.216 5.977-3.168 7.561-4.823 9.217-3.313 3.313-21.582 11.052-33.427 16.992-12.726 6.498-20.466 9.558-26.244 11.502-4.896 2.304-8.676 4.193-16.002 3.222-5.976-0.702-9.018-1.476-12.114-4.212-3.096-2.664-6.174-6.336-6.462-12.313-0.953-10.547 3.097-18.918 3.24-30.978-0.09-8.892-2.97-16.758-4.05-25.938-1.134-9.918-3.096-18.324-0.99-19.619 3.889-2.395 4.752-2.592 9.36-2.592 4.607 0 6.75 0.342 8.208 1.799 2.196 2.197-0.594 6.75-1.962 9.055-3.402 4.355-3.33 10.619 0.468 15.21 3.852 4.681 7.866 7.597 14.76 7.794 9.702 0.18 15.156-3.402 19.008-8.298 3.15-3.87 4.698-6.912 6.589-10.638 1.439-2.736 5.273-10.746 6.065-10.746 0.72 0 5.473-1.656 8.137 2.232z"/> + <path fill="#eab500" d="m303.631 262.529c4.464 6.479-0.145 14.904 3.096 20.089 5.328 8.496 16.056 17.063 20.16 19.439 2.952 1.8 7.128 3.527 6.983 8.783-0.216 5.977-3.168 7.561-4.823 9.217-3.313 3.313-21.687 11.016-33.582 16.848-12.643 6.293-20.576 9.274-26.438 11.045-4.752 1.987-8.338 3.846-15.438 2.809-5.658-0.75-8.582-1.426-11.664-4.147-3.08-2.649-6.119-6.077-6.45-11.722-1.037-10.526 3.053-18.792 3.096-30.528-0.144-9-3.211-16.79-4.363-26.049-1.21-9.907-3.312-18.304-1.21-19.599 3.889-2.391 4.752-2.592 9.36-2.592 4.607 0 6.754 0.346 8.208 1.799 2.247 2.248-0.691 6.885-2.117 9.029-3.6 4.336-3.672 10.916 0.231 15.682 3.96 4.867 8.106 7.82 14.989 7.992 9.879 0.158 15.523-3.586 19.411-8.668 3.141-3.99 4.479-6.984 6.38-10.814 1.426-2.78 5.241-10.844 6.033-10.844 0.721-0.001 5.474-1.657 8.138 2.231z"/> + <path fill="#efba00" d="m303.631 262.529c4.464 6.479-0.145 14.904 3.096 20.089 5.328 8.496 16.056 17.063 20.16 19.439 2.952 1.8 7.128 3.527 6.983 8.783-0.216 5.977-3.168 7.561-4.823 9.217-3.313 3.313-21.791 10.98-33.735 16.703-12.562 6.089-20.69 8.99-26.633 10.589-4.608 1.67-7.999 3.496-14.872 2.394-5.343-0.796-8.147-1.375-11.215-4.082-3.066-2.636-6.065-5.818-6.439-11.132-1.12-10.504 3.009-18.666 2.952-30.077-0.198-9.109-3.453-16.822-4.677-26.162-1.285-9.896-3.528-18.281-1.43-19.576 3.889-2.387 4.752-2.592 9.36-2.592 4.607 0 6.757 0.35 8.208 1.799 2.297 2.297-0.788 7.018-2.271 9.004-3.798 4.314-4.014 11.211-0.008 16.154 4.068 5.055 8.35 8.043 15.221 8.189 10.056 0.137 15.892-3.77 19.815-9.039 3.128-4.107 4.258-7.057 6.17-10.99 1.411-2.824 5.209-10.941 6.001-10.941 0.72-0.001 5.473-1.657 8.137 2.231z"/> + <path fill="#f4c000" d="m303.631 262.529c4.464 6.479-0.145 14.904 3.096 20.089 5.328 8.496 16.056 17.063 20.16 19.439 2.952 1.8 7.128 3.527 6.983 8.783-0.216 5.977-3.168 7.561-4.823 9.217-3.313 3.313-21.896 10.943-33.891 16.561-12.478 5.883-20.801 8.704-26.827 10.131-4.464 1.353-7.661 3.146-14.307 1.979-5.025-0.843-7.711-1.325-10.765-4.019-3.053-2.621-6.012-5.558-6.429-10.541-1.203-10.482 2.966-18.539 2.809-29.627-0.253-9.217-3.694-16.855-4.99-26.272-1.361-9.886-3.744-18.261-1.649-19.556 3.889-2.383 4.752-2.592 9.36-2.592 4.607 0 6.761 0.353 8.208 1.799 2.347 2.349-0.885 7.15-2.426 8.979-3.996 4.291-4.356 11.505-0.245 16.625 4.176 5.241 8.59 8.265 15.451 8.388 10.23 0.115 16.258-3.953 20.218-9.41 3.117-4.227 4.039-7.129 5.961-11.168 1.396-2.865 5.177-11.037 5.969-11.037 0.72 0 5.473-1.656 8.137 2.232z"/> + <path fill="#f9c600" d="m303.631 262.529c4.464 6.479-0.145 14.904 3.096 20.089 5.328 8.496 16.056 17.063 20.16 19.439 2.952 1.8 7.128 3.527 6.983 8.783-0.216 5.977-3.168 7.561-4.823 9.217-3.313 3.313-21.999 10.908-34.046 16.416-12.395 5.678-20.912 8.421-27.021 9.674-4.32 1.036-7.322 2.797-13.741 1.566-4.709-0.891-7.275-1.275-10.314-3.953-3.037-2.607-5.958-5.299-6.419-9.951-1.284-10.461 2.925-18.414 2.664-29.178-0.306-9.324-3.934-16.887-5.302-26.385-1.437-9.875-3.96-18.238-1.869-19.533 3.889-2.379 4.752-2.592 9.36-2.592 4.607 0 6.765 0.356 8.208 1.799 2.397 2.398-0.983 7.283-2.581 8.955-4.194 4.269-4.698 11.799-0.482 17.096 4.284 5.429 8.83 8.488 15.682 8.586 10.407 0.094 16.625-4.137 20.621-9.781 3.106-4.345 3.819-7.199 5.753-11.344 1.382-2.909 5.144-11.135 5.936-11.135 0.718 0 5.471-1.656 8.135 2.232z"/> + <path fill="#fc0" d="m303.631 262.529c4.464 6.479-0.145 14.904 3.096 20.089 5.328 8.496 16.056 17.063 20.16 19.439 2.952 1.8 7.128 3.527 6.983 8.783-0.216 5.977-3.168 7.561-4.823 9.217-3.313 3.313-22.104 10.872-34.2 16.271-12.313 5.473-21.024 8.137-27.217 9.217-4.176 0.72-6.983 2.447-13.176 1.151-4.392-0.937-6.84-1.224-9.864-3.888-3.023-2.592-5.903-5.04-6.407-9.359-1.368-10.441 2.88-18.289 2.52-28.729-0.36-9.432-4.176-16.92-5.616-26.496-1.512-9.864-4.176-18.217-2.088-19.512 3.889-2.377 4.752-2.592 9.36-2.592 4.607 0 6.768 0.359 8.208 1.799 2.448 2.449-1.08 7.416-2.736 8.929-4.392 4.248-5.04 12.096-0.72 17.567 4.392 5.617 9.072 8.713 15.912 8.785 10.584 0.071 16.992-4.32 21.023-10.152 3.097-4.465 3.601-7.272 5.544-11.521 1.368-2.952 5.112-11.231 5.904-11.231 0.72 0.001 5.473-1.655 8.137 2.233z"/> + </g> + <g transform="translate(-12.4048,10.0005)"> + <path fill="#fc0" d="m236.263 275.762c-0.709-0.258-3.932-15.209-2.191-16.239 3.351-1.997 4.253-2.319 8.377-2.319s6.057 0.322 7.346 1.61c2.126 2.127-1.159 6.702-2.448 7.991-3.738 3.673-10.375 9.215-11.084 8.957z"/> + <path fill="#ffcc02" d="m236.492 275.286c-0.77-0.326-4.102-14.719-2.368-15.742 3.344-1.992 4.278-2.211 8.322-2.211 4.124 0 5.976 0.269 7.282 1.602 2.105 2.136-1.119 6.572-2.398 7.852-3.727 3.663-10.081 8.811-10.838 8.499z"/> + <path fill="#ffcc05" d="m236.721 274.809c-0.832-0.393-4.273-14.229-2.547-15.247 3.339-1.983 4.306-2.101 8.269-2.101 4.124 0 5.896 0.213 7.217 1.592 2.087 2.146-1.076 6.443-2.346 7.714-3.718 3.653-9.788 8.409-10.593 8.042z"/> + <path fill="#ffcc07" d="m236.949 274.333c-0.892-0.461-4.443-13.74-2.722-14.75 3.331-1.979 4.33-1.992 8.213-1.992 4.124 0 5.814 0.158 7.151 1.582 2.068 2.156-1.033 6.316-2.294 7.574-3.707 3.644-9.494 8.007-10.348 7.586z"/> + <path fill="#ffcd0a" d="m237.178 273.855c-0.954-0.528-4.614-13.249-2.9-14.254 3.326-1.972 4.355-1.882 8.158-1.882 4.124 0 5.734 0.104 7.089 1.572 2.048 2.166-0.993 6.187-2.243 7.437-3.699 3.634-9.202 7.605-10.104 7.127z"/> + <path fill="#ffcd0c" d="m237.407 273.377c-1.015-0.596-4.785-12.758-3.077-13.758 3.319-1.965 4.382-1.771 8.104-1.771 4.124 0 5.653 0.049 7.023 1.563 2.029 2.176-0.951 6.057-2.19 7.299-3.69 3.623-8.91 7.201-9.86 6.667z"/> + <path fill="#ffcd0f" d="m237.636 272.901c-1.077-0.662-4.956-12.27-3.256-13.261 3.313-1.959 4.408-1.663 8.05-1.663 4.124 0 5.573-0.006 6.959 1.553 2.01 2.186-0.908 5.93-2.14 7.159-3.679 3.614-8.615 6.8-9.613 6.212z"/> + <path fill="#ffcd11" d="m237.864 272.424c-1.137-0.731-5.126-11.779-3.431-12.766 3.306-1.951 4.433-1.553 7.994-1.553 4.123 0 5.492-0.061 6.895 1.543 1.991 2.193-0.867 5.801-2.089 7.021-3.669 3.606-8.321 6.397-9.369 5.755z"/> + <path fill="#ffce14" d="m238.093 271.948c-1.197-0.799-5.297-11.289-3.607-12.27 3.299-1.946 4.459-1.443 7.938-1.443 4.124 0 5.412-0.115 6.83 1.533 1.973 2.204-0.824 5.671-2.037 6.883-3.659 3.596-8.028 5.993-9.124 5.297z"/> + <path fill="#ffce16" d="m238.322 271.471c-1.26-0.867-5.468-10.801-3.786-11.773 3.293-1.939 4.485-1.334 7.884-1.334 4.124 0 5.332-0.171 6.767 1.524 1.953 2.213-0.783 5.542-1.985 6.743-3.651 3.586-7.736 5.591-8.88 4.84z"/> + <path fill="#ffce19" d="m238.551 270.995c-1.32-0.935-5.639-10.312-3.963-11.277 3.286-1.934 4.511-1.225 7.829-1.225 4.124 0 5.252-0.226 6.702 1.514 1.934 2.224-0.741 5.414-1.934 6.605-3.64 3.576-7.442 5.187-8.634 4.383z"/> + <path fill="#ffce1c" d="m238.779 270.517c-1.382-1.002-5.809-9.821-4.14-10.781 3.279-1.926 4.535-1.114 7.774-1.114 4.124 0 5.171-0.279 6.637 1.504 1.914 2.233-0.698 5.285-1.882 6.467-3.63 3.566-7.148 4.784-8.389 3.924z"/> + <path fill="#ffcf1e" d="m239.008 270.04c-1.442-1.068-5.979-9.33-4.316-10.283 3.272-1.922 4.562-1.006 7.72-1.006 4.124 0 5.09-0.334 6.572 1.494 1.895 2.244-0.657 5.156-1.83 6.328-3.622 3.556-6.857 4.383-8.146 3.467z"/> + <path fill="#ffcf21" d="m239.237 269.563c-1.505-1.137-6.151-8.841-4.495-9.788 3.267-1.914 4.588-0.896 7.666-0.896 4.124 0 5.009-0.389 6.508 1.486 1.875 2.252-0.616 5.025-1.778 6.188-3.613 3.548-6.564 3.981-7.901 3.01z"/> + <path fill="#ffcf23" d="m239.466 269.086c-1.565-1.205-6.321-8.352-4.672-9.293 3.262-1.906 4.613-0.785 7.61-0.785 4.124 0 4.93-0.444 6.444 1.476 1.855 2.261-0.573 4.897-1.728 6.052-3.601 3.537-6.269 3.575-7.654 2.55z"/> + <path fill="#ffcf26" d="m239.694 268.61c-1.627-1.273-6.492-7.861-4.849-8.796 3.255-1.901 4.64-0.677 7.556-0.677 4.124 0 4.849-0.499 6.379 1.466 1.837 2.271-0.531 4.769-1.675 5.912-3.593 3.528-5.977 3.174-7.411 2.095z"/> + <path fill="#ffd028" d="m239.923 268.133c-1.688-1.34-6.663-7.373-5.025-8.301 3.248-1.895 4.665-0.566 7.501-0.566 4.124 0 4.768-0.555 6.314 1.456 1.817 2.28-0.489 4.64-1.624 5.774-3.583 3.519-5.684 2.771-7.166 1.637z"/> + <path fill="#ffd02b" d="m240.152 267.657c-1.749-1.408-6.834-6.883-5.203-7.805 3.241-1.889 4.69-0.457 7.446-0.457 4.124 0 4.687-0.609 6.25 1.447 1.798 2.289-0.448 4.51-1.573 5.635-3.572 3.509-5.39 2.367-6.92 1.18z"/> + <path fill="#ffd02d" d="m240.381 267.178c-1.811-1.475-7.005-6.391-5.381-7.307 3.235-1.881 4.717-0.348 7.393-0.348 4.124 0 4.606-0.664 6.185 1.438 1.779 2.299-0.405 4.381-1.521 5.496-3.564 3.501-5.098 1.965-6.676 0.721z"/> + <path fill="#ffd030" d="m240.609 266.702c-1.871-1.543-7.175-5.902-5.557-6.811 3.228-1.875 4.741-0.238 7.336-0.238 4.124 0 4.526-0.719 6.122 1.428 1.759 2.31-0.364 4.252-1.471 5.357-3.552 3.49-4.803 1.562-6.43 0.264z"/> + <path fill="#ffd133" d="m240.838 266.225c-1.933-1.611-7.346-5.413-5.734-6.314 3.222-1.869 4.768-0.129 7.281-0.129 4.124 0 4.446-0.773 6.058 1.418 1.74 2.318-0.322 4.123-1.418 5.219-3.545 3.48-4.512 1.16-6.187-0.194z"/> + </g> + <g transform="translate(-12.4048,10.0005)"> + <path fill="#fc0" d="m302.769 263.374c3.742 5.461-0.062 12.76 2.638 17.117-6.809-6.258-9.938-8.834-19.324 0.367 2.577-3.742 3.129-6.257 4.725-9.814 1.104-2.455 4.354-9.57 5.029-9.57 0.613-0.001 4.724-1.35 6.932 1.9z"/> + <path fill="#ffcc02" d="m302.73 263.413c3.655 5.334 0.035 12.601 2.578 16.723-6.668-6.098-9.729-8.666-18.908 0.322 2.421-3.527 3.025-6.094 4.605-9.592 1.122-2.462 4.243-9.302 4.951-9.311 0.628-0.008 4.617-1.318 6.774 1.858z"/> + <path fill="#ffcc05" d="m302.691 263.45c3.568 5.209 0.132 12.441 2.517 16.332-6.526-5.938-9.519-8.5-18.492 0.277 2.268-3.314 2.924-5.934 4.488-9.372 1.141-2.468 4.132-9.032 4.873-9.052 0.641-0.013 4.508-1.284 6.614 1.815z"/> + <path fill="#ffcc07" d="m302.652 263.487c3.48 5.086 0.229 12.282 2.457 15.939-6.386-5.777-9.311-8.332-18.076 0.232 2.111-3.1 2.819-5.771 4.369-9.15 1.158-2.475 4.021-8.762 4.795-8.791 0.655-0.019 4.399-1.254 6.455 1.77z"/> + <path fill="#ffcd0a" d="m302.614 263.524c3.393 4.96 0.323 12.123 2.396 15.549-6.245-5.617-9.102-8.164-17.66 0.188 1.955-2.887 2.716-5.611 4.251-8.93 1.176-2.481 3.91-8.494 4.716-8.533 0.67-0.027 4.291-1.219 6.297 1.726z"/> + <path fill="#ffcd0c" d="m302.575 263.562c3.306 4.835 0.419 11.964 2.335 15.155-6.104-5.457-8.891-7.996-17.244 0.143 1.8-2.673 2.613-5.449 4.133-8.707 1.194-2.488 3.8-8.225 4.638-8.273 0.684-0.036 4.182-1.189 6.138 1.682z"/> + <path fill="#ffcd0f" d="m302.536 263.599c3.219 4.71 0.517 11.805 2.275 14.765-5.963-5.299-8.683-7.83-16.828 0.098 1.644-2.461 2.51-5.289 4.015-8.486 1.212-2.496 3.688-7.956 4.559-8.016 0.698-0.04 4.075-1.155 5.979 1.639z"/> + <path fill="#ffcd11" d="m302.497 263.637c3.131 4.585 0.612 11.645 2.216 14.371-5.822-5.137-8.474-7.661-16.413 0.053 1.489-2.245 2.406-5.125 3.896-8.264 1.229-2.504 3.576-7.688 4.479-7.756 0.714-0.046 3.968-1.123 5.822 1.596z"/> + <path fill="#ffce14" d="m302.458 263.674c3.044 4.459 0.708 11.486 2.154 13.979-5.681-4.978-8.263-7.493-15.996 0.009 1.334-2.033 2.303-4.965 3.779-8.043 1.247-2.511 3.464-7.418 4.4-7.498 0.728-0.052 3.859-1.089 5.663 1.553z"/> + <path fill="#ffce16" d="m302.42 263.711c2.956 4.336 0.804 11.328 2.094 13.588-5.54-4.817-8.055-7.326-15.58-0.036 1.178-1.819 2.199-4.804 3.659-7.822 1.267-2.517 3.354-7.149 4.323-7.237 0.741-0.061 3.75-1.058 5.504 1.507z"/> + <path fill="#ffce19" d="m302.381 263.749c2.868 4.211 0.9 11.168 2.033 13.196-5.398-4.657-7.845-7.159-15.164-0.081 1.022-1.605 2.097-4.642 3.542-7.601 1.283-2.524 3.241-6.88 4.244-6.979 0.755-0.067 3.642-1.026 5.345 1.465z"/> + <path fill="#ffce1c" d="m302.342 263.788c2.78 4.084 0.997 11.008 1.973 12.803-5.258-4.498-7.635-6.991-14.748-0.127 0.867-1.391 1.994-4.479 3.424-7.379 1.302-2.531 3.13-6.61 4.166-6.719 0.768-0.074 3.532-0.992 5.185 1.422z"/> + <path fill="#ffcf1e" d="m302.302 263.825c2.693 3.959 1.093 10.85 1.913 12.411-5.117-4.338-7.427-6.825-14.333-0.172 0.713-1.177 1.891-4.317 3.307-7.157 1.318-2.537 3.018-6.342 4.086-6.461 0.784-0.08 3.426-0.959 5.027 1.379z"/> + <path fill="#ffcf21" d="m302.263 263.862c2.606 3.834 1.188 10.689 1.853 12.02-4.976-4.178-7.217-6.657-13.916-0.217 0.556-0.963 1.786-4.156 3.188-6.936 1.337-2.545 2.906-6.072 4.008-6.202 0.797-0.086 3.318-0.927 4.867 1.335z"/> + <path fill="#ffcf23" d="m302.225 263.899c2.519 3.71 1.285 10.531 1.791 11.628-4.835-4.019-7.008-6.489-13.5-0.262 0.4-0.75 1.684-3.994 3.068-6.714 1.356-2.553 2.797-5.805 3.931-5.943 0.813-0.093 3.209-0.895 4.71 1.291z"/> + <path fill="#ffcf26" d="m302.186 263.937c2.431 3.584 1.381 10.371 1.73 11.235-4.693-3.857-6.798-6.322-13.084-0.307 0.245-0.535 1.58-3.832 2.951-6.492 1.373-2.56 2.686-5.535 3.852-5.685 0.828-0.1 3.101-0.861 4.551 1.249z"/> + <path fill="#ffd028" d="m302.147 263.974c2.344 3.46 1.477 10.213 1.671 10.845-4.553-3.699-6.589-6.156-12.668-0.354 0.089-0.321 1.477-3.67 2.832-6.271 1.392-2.565 2.574-5.267 3.772-5.425 0.842-0.104 2.994-0.828 4.393 1.205z"/> + <path fill="#ffd02b" d="m302.108 264.012c2.257 3.334 1.573 10.053 1.61 10.451-4.412-3.537-6.38-5.987-12.253-0.396-0.064-0.109 1.374-3.51 2.716-6.05 1.408-2.573 2.462-4.997 3.693-5.166 0.856-0.112 2.886-0.796 4.234 1.161z"/> + <path fill="#ffd02d" d="m302.069 264.049c2.17 3.209 1.67 9.894 1.55 10.061-4.271-3.379-6.17-5.82-11.836-0.441-0.221 0.104 1.271-3.35 2.596-5.83 1.428-2.58 2.352-4.728 3.615-4.906 0.87-0.12 2.777-0.765 4.075 1.116z"/> + <path fill="#ffd030" d="m302.03 264.086c2.082 3.084 1.767 9.736 1.49 9.668-4.131-3.219-5.961-5.652-11.42-0.486-0.377 0.318 1.167-3.188 2.478-5.607 1.445-2.586 2.239-4.459 3.536-4.647 0.884-0.127 2.669-0.732 3.916 1.072z"/> + <path fill="#ffd133" d="m301.991 264.124c1.995 2.959 1.862 9.576 1.43 9.277-3.989-3.059-5.752-5.486-11.005-0.531-0.532 0.531 1.064-3.027 2.36-5.387 1.463-2.594 2.128-4.189 3.458-4.389 0.899-0.133 2.561-0.699 3.757 1.03z"/> + </g> + <g transform="translate(-12.4048,10.0005)"> + <path fill="#fc0" d="m305.862 283.481c5.977 7.848 17.064 16.271 21.024 18.576 2.88 1.656 7.056 3.6 6.983 8.783-0.144 5.904-3.168 7.561-4.823 9.217-3.313 3.313-22.177 10.943-34.2 16.271-12.24 5.4-21.097 8.209-27.217 9.217-4.104 0.647-7.056 2.375-13.176 1.151-4.32-0.864-6.912-1.296-9.864-3.888-2.951-2.52-5.976-5.184-6.407-9.359-1.225-10.369 3.672-16.921 8.424-25.921 3.888-7.2 11.735-8.64 16.632-7.991 17.568 2.375 16.416-8.641 21.24-13.465 4.464-4.463 17.208-8.064 21.384-2.591z"/> + <path fill="#ffcc02" d="m305.81 283.553c5.962 7.83 17.024 16.234 20.975 18.533 2.873 1.652 7.039 3.592 6.969 8.764-0.145 5.891-3.161 7.542-4.813 9.195-3.304 3.304-22.34 10.992-34.24 16.088-12.259 5.176-20.647 7.873-26.802 8.959-4.077 0.684-7.156 2.394-13.258 1.177-4.304-0.854-6.767-1.231-9.707-3.812-2.939-2.51-5.756-4.961-6.185-9.117-1.211-10.34 3.365-16.657 8.044-25.65 3.89-7.375 11.791-8.434 16.665-7.777 17.514 2.414 16.206-8.959 21.02-13.772 4.452-4.454 17.166-8.047 21.332-2.588z"/> + <path fill="#ffcc05" d="m305.76 283.627c5.946 7.812 16.982 16.195 20.925 18.488 2.866 1.648 7.022 3.584 6.951 8.743-0.144 5.876-3.153 7.524-4.801 9.173-3.298 3.297-22.506 11.043-34.28 15.907-12.279 4.949-20.201 7.538-26.389 8.699-4.051 0.721-7.256 2.413-13.341 1.202-4.286-0.846-6.619-1.168-9.55-3.733-2.924-2.501-5.536-4.741-5.959-8.877-1.198-10.312 3.058-16.394 7.664-25.379 3.89-7.552 11.845-8.229 16.698-7.563 17.458 2.453 15.995-9.279 20.797-14.08 4.443-4.443 17.127-8.026 21.285-2.58z"/> + <path fill="#ffcc07" d="m305.707 283.702c5.935 7.791 16.943 16.156 20.876 18.444 2.859 1.644 7.007 3.574 6.935 8.722-0.144 5.862-3.146 7.508-4.79 9.151-3.288 3.289-22.668 11.093-34.319 15.726-12.298 4.723-19.753 7.202-25.974 8.44-4.024 0.756-7.357 2.431-13.423 1.226-4.27-0.836-6.473-1.101-9.394-3.654-2.911-2.492-5.317-4.52-5.735-8.635-1.185-10.285 2.75-16.133 7.284-25.109 3.892-7.727 11.9-8.023 16.731-7.35 17.402 2.494 15.785-9.599 20.575-14.389 4.433-4.432 17.087-8.007 21.234-2.572z"/> + <path fill="#ffcd0a" d="m305.655 283.774c5.92 7.773 16.904 16.119 20.826 18.4 2.854 1.642 6.99 3.566 6.919 8.703-0.143 5.848-3.138 7.488-4.779 9.129-3.28 3.281-22.832 11.143-34.358 15.543-12.317 4.498-19.307 6.867-25.561 8.182-3.997 0.793-7.457 2.45-13.506 1.251-4.252-0.828-6.325-1.036-9.236-3.577-2.896-2.482-5.096-4.298-5.51-8.393-1.172-10.258 2.443-15.869 6.904-24.84 3.892-7.901 11.955-7.818 16.763-7.135 17.349 2.532 15.576-9.918 20.355-14.697 4.422-4.422 17.046-7.987 21.183-2.566z"/> + <path fill="#ffcd0c" d="m305.603 283.847c5.906 7.756 16.864 16.081 20.777 18.358 2.846 1.635 6.973 3.557 6.901 8.68-0.142 5.835-3.131 7.472-4.767 9.107-3.273 3.273-22.997 11.193-34.399 15.361-12.337 4.273-18.858 6.533-25.146 7.924-3.971 0.829-7.557 2.469-13.588 1.276-4.234-0.82-6.179-0.972-9.078-3.5-2.884-2.474-4.878-4.076-5.287-8.152-1.158-10.229 2.137-15.606 6.523-24.569 3.895-8.076 12.01-7.611 16.797-6.92 17.293 2.571 15.366-10.236 20.134-15.004 4.412-4.411 17.006-7.969 21.133-2.561z"/> + <path fill="#ffcd0f" d="m305.552 283.92c5.892 7.736 16.824 16.043 20.728 18.313 2.839 1.634 6.957 3.55 6.886 8.66-0.142 5.821-3.124 7.454-4.756 9.086-3.266 3.267-23.161 11.243-34.438 15.179-12.356 4.047-18.411 6.198-24.733 7.666-3.943 0.865-7.656 2.486-13.67 1.301-4.218-0.812-6.032-0.908-8.922-3.422-2.869-2.465-4.656-3.855-5.063-7.91-1.145-10.203 1.83-15.344 6.145-24.299 3.895-8.252 12.064-7.408 16.83-6.707 17.237 2.61 15.154-10.557 19.912-15.313 4.399-4.399 16.963-7.949 21.081-2.554z"/> + <path fill="#ffcd11" d="m305.501 283.993c5.877 7.719 16.782 16.004 20.678 18.271 2.833 1.628 6.939 3.54 6.869 8.639-0.143 5.807-3.116 7.436-4.745 9.064-3.257 3.258-23.324 11.293-34.479 14.996-12.375 3.822-17.963 5.863-24.319 7.408-3.917 0.9-7.757 2.504-13.752 1.324-4.2-0.802-5.886-0.842-8.765-3.344-2.856-2.454-4.438-3.633-4.838-7.669-1.132-10.173 1.521-15.081 5.764-24.029 3.896-8.426 12.119-7.2 16.863-6.491 17.183 2.649 14.945-10.875 19.689-15.621 4.391-4.389 16.926-7.93 21.035-2.548z"/> + <path fill="#ffce14" d="m305.448 284.066c5.863 7.701 16.743 15.966 20.629 18.228 2.826 1.625 6.924 3.531 6.853 8.619-0.142 5.793-3.108 7.418-4.733 9.043-3.25 3.25-23.489 11.342-34.518 14.813-12.396 3.598-17.517 5.529-23.905 7.148-3.891 0.938-7.857 2.524-13.834 1.351-4.185-0.793-5.74-0.776-8.609-3.267-2.841-2.444-4.217-3.412-4.613-7.426-1.118-10.146 1.216-14.818 5.385-23.76 3.896-8.602 12.174-6.996 16.896-6.277 17.128 2.688 14.735-11.195 19.468-15.929 4.378-4.38 16.883-7.911 20.981-2.543z"/> + <path fill="#ffce16" d="m305.396 284.139c5.85 7.682 16.703 15.928 20.579 18.184 2.82 1.62 6.907 3.523 6.837 8.598-0.141 5.779-3.101 7.4-4.722 9.021-3.242 3.242-23.653 11.393-34.559 14.631-12.414 3.372-17.068 5.194-23.491 6.891-3.862 0.975-7.957 2.543-13.917 1.375-4.167-0.783-5.592-0.713-8.451-3.188-2.827-2.437-3.997-3.19-4.389-7.187-1.105-10.117 0.908-14.555 5.004-23.487 3.898-8.776 12.229-6.79 16.928-6.063 17.074 2.728 14.525-11.515 19.248-16.236 4.37-4.371 16.845-7.894 20.933-2.539z"/> + <path fill="#ffce19" d="m305.344 284.211c5.836 7.664 16.663 15.891 20.529 18.141 2.813 1.617 6.892 3.516 6.82 8.578-0.14 5.765-3.093 7.382-4.71 8.999-3.235 3.233-23.817 11.442-34.598 14.448-12.434 3.146-16.621 4.859-23.077 6.633-3.837 1.01-8.058 2.561-13.999 1.4-4.15-0.775-5.446-0.648-8.295-3.111-2.814-2.426-3.777-2.969-4.164-6.944-1.094-10.09 0.601-14.293 4.624-23.22 3.898-8.951 12.282-6.584 16.961-5.848 17.019 2.767 14.314-11.834 19.025-16.545 4.361-4.359 16.806-7.872 20.884-2.531z"/> + <path fill="#ffce1c" d="m305.292 284.286c5.822 7.646 16.623 15.852 20.481 18.096 2.806 1.613 6.874 3.507 6.804 8.558-0.141 5.751-3.086 7.364-4.699 8.978-3.227 3.227-23.981 11.492-34.638 14.267-12.453 2.921-16.173 4.524-22.663 6.374-3.81 1.046-8.158 2.578-14.082 1.424-4.133-0.766-5.299-0.583-8.137-3.033-2.801-2.416-3.558-2.748-3.94-6.703-1.08-10.062 0.293-14.029 4.244-22.947 3.9-9.127 12.338-6.379 16.994-5.635 16.964 2.805 14.105-12.152 18.805-16.853 4.348-4.351 16.763-7.856 20.831-2.526z"/> + <path fill="#ffcf1e" d="m305.241 284.358c5.808 7.627 16.582 15.814 20.432 18.053 2.799 1.609 6.856 3.498 6.787 8.536-0.141 5.738-3.079 7.347-4.688 8.957-3.219 3.218-24.145 11.541-34.677 14.084-12.473 2.695-15.727 4.188-22.25 6.115-3.783 1.083-8.258 2.599-14.163 1.448-4.116-0.756-5.153-0.518-7.981-2.954-2.786-2.408-3.337-2.526-3.716-6.462-1.066-10.034-0.013-13.766 3.864-22.678 3.901-9.303 12.393-6.172 17.027-5.42 16.908 2.844 13.896-12.473 18.583-17.16 4.338-4.337 16.723-7.835 20.782-2.519z"/> + <path fill="#ffcf21" d="m305.189 284.431c5.793 7.608 16.542 15.776 20.382 18.009 2.792 1.605 6.84 3.49 6.771 8.516-0.14 5.725-3.071 7.33-4.677 8.936-3.211 3.211-24.309 11.591-34.717 13.902-12.491 2.47-15.278 3.854-21.836 5.856-3.756 1.119-8.357 2.616-14.246 1.474-4.099-0.748-5.006-0.453-7.823-2.877-2.772-2.398-3.118-2.306-3.492-6.22-1.053-10.007-0.319-13.505 3.484-22.407 3.903-9.479 12.448-5.969 17.062-5.207 16.853 2.883 13.684-12.791 18.36-17.469 4.328-4.328 16.683-7.819 20.732-2.513z"/> + <path fill="#ffcf23" d="m305.137 284.504c5.778 7.59 16.503 15.736 20.332 17.965 2.786 1.602 6.825 3.482 6.755 8.496-0.139 5.709-3.064 7.311-4.665 8.912-3.204 3.203-24.474 11.642-34.759 13.721-12.51 2.244-14.829 3.52-21.421 5.598-3.729 1.155-8.457 2.635-14.327 1.499-4.082-0.739-4.86-0.389-7.667-2.8-2.76-2.389-2.897-2.083-3.268-5.979-1.04-9.979-0.627-13.24 3.104-22.138 3.903-9.653 12.503-5.762 17.093-4.991 16.799 2.922 13.475-13.111 18.141-17.777 4.318-4.316 16.643-7.799 20.682-2.506z"/> + <path fill="#ffcf26" d="m305.086 284.579c5.765 7.57 16.463 15.697 20.282 17.92 2.779 1.599 6.809 3.474 6.738 8.476-0.139 5.696-3.056 7.293-4.654 8.892-3.194 3.194-24.637 11.69-34.797 13.536-12.529 2.021-14.382 3.185-21.007 5.341-3.703 1.191-8.559 2.652-14.411 1.523-4.065-0.73-4.713-0.324-7.509-2.723-2.745-2.379-2.679-1.861-3.043-5.735-1.027-9.952-0.936-12.979 2.724-21.868 3.905-9.828 12.557-5.557 17.126-4.777 16.744 2.961 13.265-13.431 17.919-18.084 4.307-4.309 16.602-7.783 20.632-2.501z"/> + <path fill="#ffd028" d="m305.033 284.651c5.752 7.553 16.423 15.66 20.234 17.878 2.771 1.593 6.791 3.464 6.722 8.454-0.139 5.682-3.049 7.275-4.643 8.869-3.188 3.188-24.801 11.74-34.838 13.355-12.548 1.793-13.935 2.85-20.593 5.082-3.676 1.228-8.658 2.67-14.493 1.547-4.048-0.721-4.565-0.258-7.353-2.644-2.731-2.37-2.457-1.64-2.818-5.495-1.014-9.923-1.242-12.716 2.345-21.597 3.905-10.004 12.611-5.351 17.158-4.563 16.689 3 13.055-13.75 17.698-18.393 4.297-4.295 16.562-7.761 20.581-2.493z"/> + <path fill="#ffd02b" d="m304.982 284.724c5.737 7.534 16.382 15.622 20.184 17.834 2.766 1.59 6.774 3.456 6.705 8.433-0.138 5.67-3.041 7.26-4.631 8.85-3.18 3.179-24.966 11.789-34.877 13.172-12.568 1.568-13.487 2.515-20.179 4.824-3.65 1.263-8.759 2.688-14.575 1.572-4.031-0.713-4.42-0.195-7.196-2.566-2.718-2.361-2.238-1.42-2.594-5.254-1.001-9.896-1.549-12.453 1.964-21.328 3.907-10.178 12.666-5.145 17.192-4.348 16.634 3.039 12.844-14.068 17.476-18.701 4.285-4.286 16.521-7.743 20.531-2.488z"/> + <path fill="#ffd02d" d="m304.93 284.797c5.723 7.516 16.342 15.584 20.135 17.789 2.758 1.588 6.758 3.449 6.688 8.414-0.138 5.654-3.034 7.24-4.619 8.826-3.173 3.172-25.13 11.84-34.918 12.99-12.587 1.344-13.039 2.18-19.766 4.564-3.622 1.301-8.856 2.709-14.657 1.599-4.014-0.704-4.272-0.13-7.039-2.489-2.702-2.352-2.018-1.197-2.369-5.012-0.987-9.868-1.855-12.189 1.584-21.057 3.908-10.354 12.722-4.94 17.226-4.135 16.578 3.078 12.634-14.389 17.254-19.009 4.275-4.273 16.481-7.721 20.481-2.48z"/> + <path fill="#ffd030" d="m304.879 284.87c5.709 7.498 16.302 15.547 20.085 17.748 2.752 1.582 6.741 3.438 6.673 8.391-0.139 5.642-3.027 7.224-4.609 8.806-3.164 3.164-25.293 11.89-34.956 12.808-12.606 1.119-12.592 1.844-19.352 4.308-3.596 1.336-8.958 2.726-14.739 1.622-3.997-0.695-4.127-0.065-6.882-2.411-2.69-2.343-1.799-0.976-2.146-4.771-0.974-9.84-2.163-11.928 1.204-20.787 3.91-10.529 12.777-4.734 17.258-3.92 16.524 3.117 12.424-14.707 17.034-19.316 4.263-4.267 16.439-7.706 20.43-2.478z"/> + <path fill="#ffd133" d="m304.826 284.943c5.695 7.479 16.263 15.509 20.036 17.703 2.745 1.579 6.726 3.431 6.656 8.372-0.137 5.627-3.02 7.205-4.597 8.783-3.157 3.156-25.458 11.939-34.997 12.625-12.626 0.893-12.145 1.51-18.938 4.049-3.569 1.373-9.058 2.745-14.822 1.646-3.979-0.686-3.979 0-6.725-2.332-2.676-2.334-1.578-0.756-1.921-4.529-0.961-9.813-2.471-11.665 0.824-20.516 3.91-10.705 12.83-4.529 17.29-3.707 16.47 3.156 12.215-15.027 16.813-19.625 4.255-4.253 16.401-7.684 20.381-2.469z"/> + </g> + <g transform="translate(-12.4048,10.0005)"> + <path fill="#995900" d="m52.494 273.618c-6.479 4.68-22.896 4.248-27.072 9.719-4.104 5.473 0.145 13.393 0.072 28.08 0 6.265-1.08 11.017-1.8 14.832-1.008 4.824-1.656 8.209 0.36 11.664 3.672 6.121 9.575 7.633 43.344 14.688 18.072 3.744 35.136 13.464 46.584 14.399 11.448 0.865 13.896-2.951 20.88-9.144 6.912-6.192 9.144-4.248 8.928-17.856-0.216-13.535-8.928-17.567-18.792-33.191s-11.448-18.504-18-28.872c-6.552-10.224-19.512-28.8-26.928-29.017-5.904-0.144-9.216 3.024-12.888 6.769s-8.208 13.248-14.688 17.929z"/> + <path fill="#9e5e00" d="m52.598 273.905c-6.397 4.702-22.475 3.788-27.062 9.512-4.154 5.414 0.228 13.276 0.098 27.955-0.025 6.23-1.152 10.881-1.937 14.877-1.037 4.871-1.678 8.201 0.349 11.619 3.787 6.162 9.695 7.123 43.456 14.168 18.061 3.737 34.541 13.307 46.343 14.112 11.186 0.792 13.564-2.829 20.463-8.96 6.896-6.195 9.024-4.277 8.858-17.406-0.075-13.521-8.305-17.349-18.169-32.973s-11.448-18.504-18-28.872c-6.552-10.224-19.512-28.8-26.928-29.017-5.904-0.144-9.216 3.024-12.888 6.769s-8.153 13.479-14.583 18.216z"/> + <path fill="#a36400" d="m52.703 274.193c-6.314 4.724-22.054 3.327-27.051 9.304-4.204 5.356 0.31 13.16 0.123 27.828-0.051 6.198-1.225 10.748-2.074 14.924-1.065 4.918-1.699 8.194 0.339 11.571 3.902 6.206 9.813 6.617 43.567 13.651 18.05 3.73 33.948 13.146 46.101 13.824 10.923 0.72 13.234-2.707 20.045-8.777 6.885-6.199 8.907-4.305 8.792-16.956 0.064-13.507-7.683-17.129-17.547-32.753s-11.448-18.504-18-28.872c-6.552-10.224-19.512-28.8-26.928-29.017-5.904-0.144-9.216 3.024-12.888 6.769s-8.1 13.709-14.479 18.504z"/> + <path fill="#a86a00" d="m52.807 274.481c-6.231 4.745-21.633 2.866-27.04 9.094-4.255 5.299 0.393 13.047 0.148 27.702-0.076 6.167-1.297 10.616-2.211 14.972-1.095 4.965-1.721 8.188 0.328 11.524 4.018 6.25 9.932 6.108 43.679 13.134 18.039 3.721 33.354 12.988 45.86 13.535 10.659 0.648 12.902-2.585 19.627-8.593 6.869-6.203 8.788-4.335 8.723-16.507 0.205-13.492-7.06-16.909-16.924-32.533s-11.448-18.504-18-28.872c-6.552-10.224-19.512-28.8-26.928-29.017-5.904-0.144-9.216 3.024-12.888 6.769s-8.045 13.94-14.374 18.792z"/> + <path fill="#ad7000" d="m52.912 274.769c-6.149 4.767-21.211 2.405-27.029 8.885-4.306 5.242 0.476 12.931 0.173 27.576-0.101 6.136-1.368 10.483-2.347 15.019-1.123 5.012-1.742 8.181 0.316 11.478 4.133 6.293 10.052 5.603 43.791 12.614 18.028 3.716 32.76 12.83 45.619 13.248 10.396 0.576 12.57-2.463 19.21-8.409 6.854-6.206 8.668-4.363 8.653-16.056 0.347-13.479-6.437-16.69-16.301-32.314s-11.448-18.504-18-28.872c-6.552-10.224-19.512-28.8-26.928-29.017-5.904-0.144-9.216 3.024-12.888 6.769s-7.991 14.169-14.269 19.079z"/> + <path fill="#b27500" d="m53.016 275.057c-6.066 4.787-20.79 1.943-27.019 8.676-4.355 5.184 0.559 12.816 0.198 27.45-0.126 6.103-1.44 10.351-2.484 15.065-1.151 5.059-1.764 8.172 0.307 11.431 4.248 6.336 10.17 5.094 43.901 12.096 18.019 3.708 32.166 12.672 45.378 12.96 10.135 0.504 12.24-2.34 18.792-8.227 6.841-6.209 8.551-4.391 8.586-15.605 0.486-13.464-5.813-16.47-15.678-32.094s-11.448-18.504-18-28.872c-6.552-10.224-19.512-28.8-26.928-29.017-5.904-0.144-9.216 3.024-12.888 6.769s-7.937 14.399-14.165 19.368z"/> + <path fill="#b77b00" d="m53.121 275.344c-5.983 4.811-20.369 1.484-27.008 8.469-4.406 5.126 0.641 12.7 0.224 27.324-0.151 6.068-1.512 10.216-2.621 15.111-1.181 5.105-1.785 8.166 0.295 11.385 4.363 6.379 10.289 4.586 44.014 11.576 18.008 3.701 31.572 12.515 45.137 12.672 9.872 0.433 11.909-2.217 18.375-8.041 6.825-6.215 8.431-4.422 8.518-15.156 0.627-13.45-5.191-16.251-15.056-31.875s-11.448-18.504-18-28.872c-6.552-10.224-19.512-28.8-26.928-29.017-5.904-0.144-9.216 3.024-12.888 6.769s-7.884 14.631-14.062 19.655z"/> + <path fill="#bc8100" d="m53.225 275.633c-5.9 4.832-19.948 1.023-26.997 8.259-4.457 5.069 0.724 12.585 0.249 27.198-0.177 6.037-1.584 10.082-2.758 15.158-1.21 5.152-1.808 8.158 0.284 11.338 4.479 6.422 10.407 4.078 44.125 11.059 17.997 3.693 30.979 12.355 44.896 12.384 9.608 0.36 11.578-2.095 17.957-7.858 6.812-6.217 8.313-4.449 8.45-14.707 0.766-13.435-4.569-16.03-14.434-31.654s-11.448-18.504-18-28.872c-6.552-10.224-19.512-28.8-26.928-29.017-5.904-0.144-9.216 3.024-12.888 6.769s-7.829 14.859-13.956 19.943z"/> + <path fill="#c18700" d="m53.329 275.92c-5.817 4.854-19.526 0.563-26.985 8.051-4.507 5.011 0.807 12.47 0.273 27.072-0.201 6.004-1.655 9.949-2.894 15.205-1.239 5.199-1.829 8.151 0.273 11.291 4.594 6.465 10.526 3.57 44.236 10.541 17.985 3.686 30.384 12.196 44.655 12.096 9.345 0.287 11.245-1.973 17.539-7.676 6.797-6.221 8.193-4.479 8.381-14.256 0.906-13.42-3.946-15.812-13.811-31.436s-11.448-18.504-18-28.872c-6.552-10.224-19.512-28.8-26.928-29.017-5.904-0.144-9.216 3.024-12.888 6.769s-7.774 15.094-13.851 20.232z"/> + <path fill="#c68c00" d="m53.433 276.209c-5.734 4.875-19.104 0.101-26.975 7.84-4.558 4.955 0.89 12.355 0.299 26.947-0.227 5.973-1.728 9.816-3.031 15.252-1.267 5.246-1.851 8.145 0.263 11.244 4.709 6.508 10.646 3.063 44.349 10.022 17.975 3.679 29.79 12.038 44.413 11.808 9.083 0.217 10.915-1.851 17.122-7.492 6.782-6.224 8.074-4.506 8.313-13.806 1.048-13.405-3.323-15.592-13.188-31.216s-11.448-18.504-18-28.872c-6.552-10.224-19.512-28.8-26.928-29.017-5.904-0.144-9.216 3.024-12.888 6.769s-7.722 15.322-13.749 20.521z"/> + <path fill="#cc9200" d="m53.538 276.497c-5.651 4.896-18.684-0.359-26.964 7.633-4.607 4.896 0.972 12.24 0.324 26.82-0.252 5.939-1.8 9.684-3.168 15.299-1.296 5.293-1.872 8.137 0.252 11.196 4.824 6.552 10.764 2.556 44.46 9.505 17.964 3.672 29.196 11.879 44.172 11.52 8.82 0.144 10.584-1.729 16.704-7.309 6.768-6.228 7.956-4.535 8.244-13.355 1.188-13.393-2.7-15.372-12.564-30.996s-11.448-18.504-18-28.872c-6.552-10.224-19.512-28.8-26.928-29.017-5.904-0.144-9.216 3.024-12.888 6.769s-7.668 15.551-13.644 20.807z"/> + <path fill="#d19800" d="m53.642 276.786c-5.569 4.918-18.263-0.82-26.953 7.424-4.658 4.838 1.055 12.123 0.35 26.693-0.277 5.907-1.872 9.551-3.305 15.346-1.325 5.34-1.894 8.129 0.241 11.15 4.938 6.596 10.883 2.048 44.571 8.984 17.953 3.666 28.602 11.723 43.931 11.232 8.558 0.072 10.253-1.605 16.287-7.123 6.753-6.232 7.837-4.566 8.175-12.906 1.329-13.379-2.077-15.153-11.941-30.777s-11.448-18.504-18-28.872c-6.552-10.224-19.512-28.8-26.928-29.017-5.904-0.144-9.216 3.024-12.888 6.769s-7.614 15.783-13.54 21.097z"/> + <path fill="#d69e00" d="m53.747 277.073c-5.486 4.94-17.842-1.281-26.942 7.215-4.709 4.781 1.138 12.01 0.374 26.568-0.302 5.875-1.943 9.417-3.441 15.393-1.354 5.387-1.915 8.123 0.23 11.104 5.055 6.639 11.002 1.541 44.684 8.467 17.942 3.658 28.008 11.563 43.688 10.944 8.296 0 9.923-1.483 15.869-6.941 6.74-6.235 7.72-4.593 8.108-12.456 1.468-13.363-1.455-14.933-11.319-30.557s-11.448-18.504-18-28.872c-6.552-10.224-19.512-28.8-26.928-29.017-5.904-0.144-9.216 3.024-12.888 6.769s-7.56 16.012-13.435 21.383z"/> + <path fill="#dba300" d="m53.851 277.361c-5.403 4.962-17.421-1.741-26.932 7.007-4.759 4.723 1.221 11.893 0.399 26.441-0.327 5.843-2.016 9.283-3.578 15.439-1.383 5.434-1.937 8.115 0.22 11.057 5.169 6.682 11.12 1.033 44.795 7.949 17.932 3.649 27.414 11.404 43.448 10.656 8.031-0.072 9.59-1.361 15.451-6.758 6.725-6.238 7.6-4.623 8.039-12.006 1.609-13.35-0.832-14.714-10.696-30.338s-11.448-18.504-18-28.872c-6.552-10.224-19.512-28.8-26.928-29.017-5.904-0.144-9.216 3.024-12.888 6.769s-7.504 16.245-13.33 21.673z"/> + <path fill="#e0a900" d="m53.956 277.649c-5.321 4.982-16.999-2.203-26.921 6.797-4.81 4.666 1.303 11.779 0.425 26.316-0.353 5.811-2.088 9.15-3.715 15.486-1.411 5.48-1.959 8.108 0.208 11.01 5.285 6.725 11.239 0.525 44.907 7.431 17.92 3.644 26.819 11.246 43.207 10.368 7.769-0.145 9.259-1.239 15.034-6.574 6.71-6.242 7.479-4.65 7.97-11.557 1.75-13.334-0.209-14.493-10.073-30.117s-11.448-18.504-18-28.872c-6.552-10.224-19.512-28.8-26.928-29.017-5.904-0.144-9.216 3.024-12.888 6.769s-7.452 16.474-13.226 21.96z"/> + <path fill="#e5af00" d="m54.06 277.937c-5.238 5.004-16.578-2.664-26.91 6.588-4.86 4.608 1.386 11.664 0.45 26.19-0.378 5.777-2.16 9.018-3.853 15.533-1.439 5.526-1.979 8.101 0.198 10.963 5.4 6.768 11.358 0.018 45.018 6.912 17.91 3.635 26.227 11.088 42.967 10.08 7.506-0.217 8.928-1.117 14.615-6.391 6.696-6.246 7.362-4.68 7.902-11.105 1.89-13.32 0.414-14.274-9.45-29.898s-11.448-18.504-18-28.872c-6.552-10.224-19.512-28.8-26.928-29.017-5.904-0.144-9.216 3.024-12.888 6.769s-7.397 16.704-13.121 22.248z"/> + <path fill="#eab500" d="m54.165 278.225c-5.155 5.025-16.157-3.124-26.899 6.38-4.91 4.55 1.469 11.548 0.476 26.063-0.403 5.746-2.232 8.885-3.989 15.58-1.469 5.573-2.002 8.094 0.188 10.916 5.515 6.812 11.477-0.49 45.129 6.394 17.899 3.629 25.633 10.93 42.725 9.792 7.243-0.288 8.598-0.993 14.199-6.206 6.681-6.25 7.243-4.709 7.833-10.656 2.031-13.306 1.037-14.055-8.827-29.679s-11.448-18.504-18-28.872c-6.552-10.224-19.512-28.8-26.928-29.017-5.904-0.144-9.216 3.024-12.888 6.769s-7.346 16.935-13.019 22.536z"/> + <path fill="#efba00" d="m54.269 278.513c-5.073 5.048-15.736-3.585-26.889 6.171-4.961 4.492 1.552 11.434 0.5 25.938-0.428 5.713-2.304 8.752-4.125 15.627-1.498 5.621-2.023 8.086 0.176 10.869 5.631 6.854 11.596-0.996 45.241 5.875 17.889 3.623 25.038 10.771 42.483 9.504 6.981-0.359 8.266-0.871 13.781-6.022 6.668-6.253 7.125-4.737 7.766-10.206 2.17-13.291 1.659-13.835-8.205-29.459s-11.448-18.504-18-28.872c-6.552-10.224-19.512-28.8-26.928-29.017-5.904-0.144-9.216 3.024-12.888 6.769s-7.289 17.164-12.912 22.823z"/> + <path fill="#f4c000" d="m54.374 278.801c-4.99 5.068-15.314-4.047-26.878 5.962-5.012 4.435 1.634 11.317 0.525 25.812-0.453 5.682-2.376 8.618-4.263 15.674-1.526 5.668-2.045 8.08 0.166 10.822 5.745 6.898 11.714-1.505 45.353 5.357 17.878 3.613 24.444 10.613 42.243 9.216 6.717-0.433 7.934-0.749 13.362-5.839 6.653-6.258 7.007-4.768 7.697-9.756 2.312-13.277 2.282-13.616-7.582-29.24s-11.448-18.504-18-28.872c-6.552-10.224-19.512-28.8-26.928-29.017-5.904-0.144-9.216 3.024-12.888 6.769s-7.235 17.395-12.807 23.112z"/> + <path fill="#f9c600" d="m54.477 279.088c-4.906 5.092-14.893-4.506-26.866 5.754-5.062 4.377 1.717 11.203 0.551 25.686-0.479 5.648-2.448 8.485-4.399 15.721-1.555 5.715-2.066 8.072 0.155 10.775 5.86 6.941 11.833-2.012 45.464 4.839 17.867 3.607 23.851 10.454 42.001 8.929 6.455-0.504 7.604-0.627 12.946-5.656 6.638-6.26 6.886-4.795 7.628-9.307 2.452-13.262 2.905-13.396-6.959-29.02s-11.448-18.504-18-28.872c-6.552-10.224-19.512-28.8-26.928-29.017-5.904-0.144-9.216 3.024-12.888 6.769s-7.182 17.626-12.705 23.399z"/> + <path fill="#fc0" d="m54.582 279.377c-4.823 5.111-14.472-4.969-26.855 5.543-5.112 4.32 1.8 11.088 0.576 25.561-0.504 5.616-2.521 8.352-4.536 15.768-1.584 5.76-2.088 8.064 0.144 10.729 5.977 6.984 11.952-2.52 45.576 4.32 17.856 3.6 23.256 10.295 41.76 8.64 6.192-0.576 7.272-0.504 12.528-5.472 6.624-6.264 6.768-4.824 7.56-8.856 2.592-13.248 3.528-13.176-6.336-28.8s-11.448-18.504-18-28.872c-6.552-10.224-19.512-28.8-26.928-29.017-5.904-0.144-9.216 3.024-12.888 6.769s-7.129 17.855-12.601 23.687z"/> + </g> + <g transform="translate(-12.4048,10.0005)"> + <path fill="#fc0" d="m57.701 285.002c-4.278 4.539-18.28-1.36-24.892 3.631-4.732 3.5 2.398 7.908 1.426 20.873-0.389 4.926-3.824 5.834-2.398 12.64 1.103 5.121 2.27 4.991 4.214 7.325 5.315 6.223 4.084 1.686 34.355 7.777 16.011 3.242 20.938 9.271 37.596 7.779 5.575-0.518 6.612-0.453 11.279-4.926 5.964-5.575 2.917-4.408 3.565-7.973 2.269-11.863 0.453-13.938-8.428-28.004-8.88-14.066-8.102-14.844-13.936-24.113-5.834-9.141-13.872-25.799-20.549-25.93-5.25-0.129-8.297 2.723-11.603 6.094-3.305 3.372-5.768 19.643-10.629 24.827z"/> + <path fill="#ffcc02" d="m57.995 285.094c-4.461 4.701-18.604-1.196-25.06 3.705-4.701 3.514 2.578 8.05 1.608 20.68-0.4 4.896-3.733 5.877-2.458 12.634 0.986 5.093 2.357 4.938 4.334 7.201 5.686 6.131 4.673 1.826 34.119 7.743 15.918 3.211 20.815 9.215 37.372 7.732 5.541-0.513 6.479-0.463 11.155-4.849 5.865-5.407 2.858-4.287 3.412-8.058 2.066-11.787 0.442-13.981-8.188-27.649-8.83-13.983-8.143-14.698-13.941-23.913-5.8-9.085-13.701-25.805-20.338-25.934-5.219-0.129-8.248 2.705-11.533 6.057-3.287 3.352-5.644 19.505-10.482 24.651z"/> + <path fill="#ffcc05" d="m58.289 285.185c-4.644 4.866-18.93-1.031-25.229 3.78-4.669 3.527 2.759 8.191 1.792 20.488-0.413 4.866-3.642 5.918-2.519 12.625 0.872 5.066 2.447 4.887 4.455 7.078 6.057 6.04 5.263 1.969 33.883 7.709 15.825 3.18 20.693 9.159 37.148 7.686 5.508-0.506 6.345-0.471 11.03-4.77 5.768-5.24 2.803-4.168 3.26-8.142 1.865-11.716 0.432-14.027-7.949-27.298-8.78-13.899-8.183-14.553-13.948-23.713-5.764-9.03-13.529-25.811-20.126-25.938-5.188-0.129-8.198 2.688-11.465 6.021-3.266 3.331-5.517 19.368-10.332 24.474z"/> + <path fill="#ffcc07" d="m58.584 285.276c-4.827 5.03-19.255-0.865-25.397 3.855-4.639 3.541 2.938 8.332 1.975 20.295-0.425 4.838-3.551 5.961-2.578 12.619 0.757 5.039 2.536 4.834 4.575 6.955 6.428 5.949 5.852 2.108 33.646 7.674 15.733 3.147 20.571 9.103 36.925 7.639 5.475-0.501 6.211-0.48 10.905-4.693 5.67-5.072 2.745-4.045 3.107-8.224 1.663-11.642 0.42-14.073-7.711-26.946-8.73-13.814-8.223-14.406-13.952-23.511-5.729-8.976-13.358-25.817-19.916-25.944-5.156-0.127-8.148 2.674-11.396 5.984s-5.391 19.229-10.183 24.297z"/> + <path fill="#ffcd0a" d="m58.878 285.368c-5.01 5.193-19.579-0.701-25.565 3.93-4.607 3.555 3.117 8.475 2.157 20.102-0.437 4.809-3.459 6.004-2.639 12.613 0.643 5.011 2.626 4.781 4.695 6.83 6.799 5.857 6.442 2.25 33.411 7.64 15.641 3.118 20.45 9.048 36.701 7.593 5.44-0.494 6.076-0.488 10.781-4.615 5.57-4.904 2.688-3.926 2.954-8.308 1.462-11.569 0.409-14.118-7.472-26.593-8.68-13.732-8.263-14.262-13.958-23.311-5.695-8.922-13.188-25.824-19.705-25.951-5.125-0.127-8.1 2.658-11.326 5.949-3.227 3.289-5.266 19.091-10.034 24.121z"/> + <path fill="#ffcd0c" d="m59.173 285.458c-5.193 5.358-19.905-0.535-25.734 4.008-4.577 3.566 3.297 8.613 2.34 19.908-0.449 4.778-3.368 6.045-2.698 12.605 0.526 4.982 2.715 4.729 4.815 6.707 7.17 5.766 7.031 2.391 33.175 7.604 15.549 3.088 20.328 8.994 36.477 7.547 5.408-0.488 5.943-0.498 10.657-4.537 5.472-4.737 2.63-3.805 2.802-8.393 1.261-11.494 0.398-14.162-7.232-26.24-8.63-13.647-8.304-14.117-13.964-23.109-5.66-8.867-13.017-25.829-19.494-25.956-5.094-0.126-8.05 2.642-11.257 5.912-3.21 3.27-5.142 18.955-9.887 23.944z"/> + <path fill="#ffcd0f" d="m59.467 285.547c-5.376 5.523-20.229-0.369-25.903 4.084-4.545 3.58 3.478 8.756 2.523 19.715-0.461 4.75-3.277 6.088-2.758 12.599 0.411 4.955 2.804 4.677 4.936 6.584 7.541 5.675 7.621 2.532 32.938 7.569 15.456 3.056 20.206 8.938 36.253 7.5 5.375-0.482 5.811-0.506 10.533-4.459 5.374-4.57 2.572-3.686 2.649-8.477 1.058-11.42 0.387-14.209-6.995-25.888-8.58-13.563-8.344-13.972-13.969-22.909-5.626-8.813-12.846-25.834-19.283-25.961-5.063-0.125-8 2.625-11.188 5.877-3.188 3.251-5.015 18.818-9.736 23.766z"/> + <path fill="#ffcd11" d="m59.76 285.639c-5.559 5.688-20.555-0.205-26.071 4.158-4.515 3.594 3.657 8.896 2.706 19.521-0.473 4.721-3.186 6.131-2.818 12.594 0.297 4.926 2.894 4.623 5.057 6.459 7.911 5.584 8.21 2.674 32.703 7.535 15.362 3.025 20.084 8.883 36.027 7.453 5.342-0.477 5.677-0.515 10.409-4.381 5.275-4.402 2.516-3.564 2.497-8.561 0.855-11.348 0.375-14.254-6.756-25.535-8.53-13.479-8.385-13.825-13.976-22.709-5.59-8.758-12.673-25.842-19.071-25.965-5.031-0.125-7.951 2.608-11.119 5.838-3.168 3.232-4.888 18.684-9.588 23.593z"/> + <path fill="#ffce14" d="m60.055 285.73c-5.742 5.851-20.88-0.04-26.24 4.233-4.483 3.607 3.837 9.039 2.889 19.33-0.485 4.69-3.095 6.172-2.878 12.584 0.182 4.9 2.982 4.572 5.177 6.338 8.282 5.492 8.8 2.814 32.467 7.498 15.271 2.996 19.962 8.828 35.804 7.408 5.309-0.472 5.543-0.523 10.285-4.304 5.177-4.235 2.458-3.444 2.344-8.644 0.654-11.273 0.364-14.299-6.518-25.184-8.479-13.395-8.425-13.679-13.98-22.507-5.556-8.704-12.502-25.849-18.86-25.972-5-0.123-7.901 2.593-11.05 5.803s-4.765 18.547-9.44 23.417z"/> + <path fill="#ffce16" d="m60.349 285.821c-5.925 6.016-21.205 0.125-26.408 4.309-4.453 3.621 4.017 9.18 3.07 19.137-0.496 4.662-3.002 6.215-2.938 12.579 0.066 4.872 3.072 4.518 5.298 6.213 8.653 5.401 9.389 2.956 32.23 7.464 15.178 2.964 19.84 8.771 35.58 7.361 5.275-0.465 5.409-0.532 10.159-4.225 5.079-4.068 2.401-3.324 2.192-8.729 0.452-11.2 0.354-14.346-6.279-24.831-8.429-13.312-8.464-13.534-13.985-22.306-5.521-8.65-12.331-25.854-18.649-25.978-4.969-0.123-7.853 2.577-10.98 5.767-3.129 3.19-4.637 18.409-9.29 23.239z"/> + <path fill="#ffce19" d="m60.643 285.911c-6.107 6.18-21.529 0.291-26.577 4.385-4.421 3.635 4.197 9.322 3.254 18.945-0.508 4.631-2.911 6.256-2.997 12.571-0.049 4.845 3.161 4.465 5.418 6.089 9.023 5.309 9.979 3.098 31.994 7.43 15.085 2.934 19.718 8.717 35.355 7.314 5.242-0.459 5.276-0.541 10.036-4.148 4.98-3.899 2.344-3.203 2.039-8.811 0.25-11.127 0.342-14.391-6.04-24.479-8.38-13.228-8.505-13.389-13.991-22.105-5.486-8.596-12.16-25.859-18.438-25.982-4.938-0.123-7.803 2.561-10.911 5.73-3.109 3.17-4.513 18.272-9.142 23.061z"/> + <path fill="#ffce1c" d="m60.938 286.002c-6.291 6.344-21.855 0.455-26.746 4.459-4.391 3.648 4.377 9.463 3.437 18.752-0.521 4.603-2.82 6.299-3.058 12.564-0.163 4.817 3.251 4.413 5.539 5.965 9.395 5.219 10.567 3.24 31.758 7.396 14.993 2.903 19.597 8.661 35.132 7.269 5.209-0.453 5.143-0.55 9.912-4.07 4.882-3.732 2.286-3.082 1.887-8.895 0.048-11.053 0.329-14.436-5.802-24.126-8.33-13.144-8.545-13.243-13.997-21.905-5.451-8.541-11.988-25.865-18.228-25.988-4.906-0.121-7.753 2.545-10.843 5.695-3.088 3.149-4.385 18.132-8.991 22.884z"/> + <path fill="#ffcf1e" d="m61.232 286.092c-6.473 6.51-22.18 0.621-26.914 4.535-4.359 3.662 4.557 9.604 3.619 18.559-0.532 4.574-2.729 6.342-3.117 12.559-0.278 4.789 3.34 4.36 5.659 5.842 9.766 5.127 11.157 3.381 31.521 7.359 14.9 2.872 19.475 8.607 34.908 7.223 5.176-0.447 5.008-0.559 9.787-3.992 4.784-3.565 2.229-2.963 1.735-8.979-0.155-10.98 0.317-14.482-5.564-23.773-8.279-13.061-8.585-13.098-14.002-21.705-5.416-8.485-11.817-25.871-18.017-25.992-4.875-0.121-7.704 2.527-10.773 5.658-3.068 3.128-4.26 17.995-8.842 22.706z"/> + <path fill="#ffcf21" d="m61.526 286.184c-6.655 6.673-22.505 0.785-27.082 4.611-4.328 3.674 4.736 9.744 3.802 18.365-0.544 4.543-2.638 6.383-3.178 12.551-0.394 4.761 3.43 4.308 5.78 5.718 10.136 5.036 11.746 3.522 31.285 7.325 14.808 2.841 19.353 8.551 34.685 7.176 5.142-0.441 4.875-0.567 9.663-3.914 4.685-3.398 2.171-2.842 1.582-9.063-0.357-10.906 0.307-14.527-5.325-23.422-8.23-12.976-8.625-12.951-14.008-21.503-5.382-8.432-11.646-25.878-17.806-25.999-4.844-0.119-7.654 2.512-10.704 5.622-3.049 3.109-4.134 17.859-8.694 22.533z"/> + <path fill="#ffcf23" d="m61.821 286.275c-6.839 6.837-22.83 0.95-27.251 4.687-4.298 3.688 4.916 9.886 3.984 18.172-0.557 4.515-2.546 6.426-3.237 12.545-0.509 4.732 3.519 4.255 5.9 5.594 10.507 4.945 12.336 3.663 31.05 7.29 14.715 2.812 19.23 8.496 34.46 7.129 5.108-0.435 4.74-0.575 9.538-3.835 4.587-3.23 2.113-2.723 1.43-9.146-0.559-10.834 0.296-14.572-5.086-23.069-8.18-12.892-8.666-12.806-14.014-21.302-5.347-8.377-11.476-25.885-17.595-26.004-4.813-0.119-7.605 2.496-10.635 5.584-3.029 3.088-4.008 17.722-8.544 22.355z"/> + <path fill="#ffcf26" d="m62.115 286.366c-7.021 7.002-23.154 1.115-27.42 4.762-4.266 3.701 5.096 10.027 4.168 17.979-0.568 4.486-2.455 6.469-3.297 12.538-0.624 4.706 3.607 4.203 6.021 5.472 10.878 4.852 12.925 3.803 30.813 7.254 14.622 2.78 19.108 8.441 34.236 7.084 5.075-0.43 4.606-0.584 9.413-3.759 4.489-3.063 2.058-2.601 1.277-9.229-0.761-10.76 0.284-14.618-4.848-22.717-8.129-12.809-8.706-12.66-14.019-21.102-5.313-8.322-11.304-25.891-17.384-26.01-4.781-0.118-7.556 2.48-10.566 5.55-3.008 3.068-3.881 17.584-8.394 22.178z"/> + <path fill="#ffd028" d="m62.409 286.456c-7.204 7.166-23.479 1.281-27.588 4.838-4.235 3.715 5.275 10.168 4.351 17.787-0.58 4.455-2.364 6.51-3.357 12.53-0.738 4.679 3.697 4.149 6.142 5.347 11.249 4.763 13.515 3.946 30.577 7.221 14.529 2.748 18.986 8.386 34.012 7.037 5.043-0.424 4.474-0.594 9.289-3.68 4.392-2.897 2-2.481 1.125-9.314-0.963-10.686 0.273-14.664-4.608-22.364-8.079-12.726-8.746-12.517-14.024-20.901-5.277-8.269-11.133-25.896-17.173-26.015-4.75-0.116-7.506 2.464-10.497 5.513-2.992 3.047-3.759 17.447-8.249 22.001z"/> + <path fill="#ffd02b" d="m62.704 286.547c-7.388 7.33-23.805 1.445-27.757 4.912-4.204 3.729 5.455 10.311 4.533 17.594-0.593 4.427-2.272 6.553-3.417 12.523-0.854 4.651 3.786 4.098 6.262 5.225 11.619 4.671 14.104 4.087 30.341 7.185 14.438 2.72 18.864 8.33 33.787 6.991 5.01-0.418 4.341-0.604 9.166-3.604 4.292-2.729 1.942-2.359 0.972-9.396-1.163-10.613 0.263-14.709-4.369-22.012-8.03-12.641-8.787-12.371-14.03-20.7-5.243-8.214-10.962-25.903-16.962-26.021-4.719-0.117-7.457 2.447-10.428 5.477-2.972 3.029-3.632 17.313-8.098 21.826z"/> + <path fill="#ffd02d" d="m62.998 286.638c-7.57 7.493-24.13 1.61-27.925 4.987-4.174 3.742 5.635 10.451 4.716 17.4-0.604 4.398-2.182 6.596-3.478 12.518-0.969 4.623 3.875 4.045 6.382 5.101 11.991 4.579 14.694 4.228 30.105 7.149 14.345 2.688 18.743 8.275 33.563 6.944 4.977-0.411 4.207-0.61 9.042-3.524 4.193-2.562 1.884-2.239 0.819-9.481-1.366-10.538 0.251-14.754-4.133-21.659-7.979-12.557-8.825-12.224-14.034-20.498-5.208-8.16-10.791-25.91-16.751-26.027-4.688-0.114-7.407 2.433-10.358 5.441-2.951 3.01-3.505 17.174-7.948 21.649z"/> + <path fill="#ffd030" d="m63.292 286.729c-7.753 7.658-24.454 1.775-28.094 5.063-4.142 3.756 5.815 10.594 4.899 17.209-0.616 4.367-2.09 6.638-3.537 12.51-1.084 4.596 3.964 3.992 6.502 4.977 12.362 4.488 15.283 4.369 29.869 7.115 14.252 2.656 18.621 8.22 33.34 6.898 4.943-0.406 4.073-0.621 8.917-3.447 4.095-2.395 1.828-2.119 0.667-9.565-1.568-10.465 0.239-14.8-3.894-21.307-7.929-12.474-8.866-12.078-14.04-20.298-5.173-8.105-10.619-25.916-16.54-26.031-4.656-0.115-7.357 2.415-10.289 5.404-2.932 2.988-3.38 17.036-7.8 21.472z"/> + <path fill="#ffd133" d="m63.587 286.82c-7.937 7.822-24.78 1.94-28.263 5.138-4.111 3.77 5.995 10.734 5.081 17.016-0.627 4.339-1.998 6.68-3.597 12.504-1.199 4.568 4.054 3.939 6.623 4.854 12.732 4.396 15.873 4.51 29.633 7.08 14.16 2.625 18.499 8.164 33.116 6.852 4.909-0.4 3.939-0.629 8.793-3.369 3.997-2.227 1.77-1.999 0.514-9.648-1.771-10.393 0.228-14.846-3.654-20.955-7.88-12.39-8.907-11.934-14.046-20.098-5.139-8.051-10.448-25.922-16.329-26.037-4.625-0.113-7.309 2.398-10.221 5.368s-3.254 16.897-7.65 21.295z"/> + </g> + <g transform="translate(-12.4048,10.0005)"> + <path d="m88.782 218.681c-0.936 2.088-1.728 20.017 2.952 27 4.68 6.911 3.312 10.872-1.872 5.616-5.4-5.112-8.928-12.816-9-18.145 0-3.096 2.376-15.84 3.313-17.208 1.007-1.44 5.327 1.153 4.607 2.737z"/> + <path fill="#030303" d="m88.692 219.032c-0.903 2.34-1.656 19.698 3.01 26.668 4.665 6.901 3.186 10.49-1.84 5.356-5.23-4.997-8.607-12.47-8.741-17.787-0.043-3.114 2.236-15.419 3.133-16.791 0.961-1.394 5.126 0.989 4.438 2.554z"/> + <path fill="#070707" d="m88.602 219.379c-0.871 2.593-1.584 19.383 3.067 26.338 4.65 6.891 3.06 10.109-1.808 5.098-5.062-4.882-8.287-12.125-8.481-17.432-0.087-3.131 2.095-14.998 2.952-16.373 0.915-1.345 4.926 0.828 4.27 2.369z"/> + <path fill="#0b0b0b" d="m88.512 219.729c-0.839 2.844-1.513 19.066 3.124 26.006 4.638 6.881 2.935 9.729-1.774 4.84-4.893-4.768-7.967-11.779-8.223-17.076-0.129-3.149 1.955-14.576 2.772-15.955 0.868-1.299 4.724 0.665 4.101 2.185z"/> + <path fill="#0f0f0f" d="m88.422 220.079c-0.806 3.096-1.439 18.748 3.183 25.674 4.623 6.869 2.809 9.347-1.742 4.58-4.724-4.651-7.646-11.434-7.963-16.719-0.173-3.168 1.814-14.154 2.592-15.537 0.819-1.252 4.52 0.504 3.93 2.002z"/> + <path fill="#131313" d="m88.332 220.426c-0.773 3.349-1.368 18.433 3.24 25.345 4.608 6.858 2.682 8.964-1.71 4.319-4.554-4.535-7.326-11.088-7.704-16.361-0.216-3.186 1.674-13.734 2.412-15.12 0.774-1.206 4.32 0.343 3.762 1.817z"/> + <path fill="#161616" d="m88.242 220.777c-0.741 3.601-1.296 18.115 3.298 25.013 4.594 6.848 2.556 8.582-1.678 4.061-4.385-4.421-7.006-10.742-7.444-16.006-0.26-3.203 1.533-13.313 2.231-14.702 0.728-1.16 4.118 0.18 3.593 1.634z"/> + <path fill="#1a1a1a" d="m88.152 221.125c-0.709 3.853-1.224 17.799 3.355 24.682 4.579 6.837 2.43 8.201-1.646 3.802-4.216-4.306-6.686-10.397-7.186-15.649-0.303-3.221 1.394-12.892 2.052-14.285 0.682-1.112 3.918 0.018 3.425 1.45z"/> + <path fill="#1e1e1e" d="m88.062 221.475c-0.677 4.104-1.152 17.482 3.413 24.35 4.564 6.826 2.304 7.82-1.613 3.543-4.046-4.191-6.365-10.051-6.927-15.293-0.345-3.24 1.253-12.47 1.872-13.867 0.634-1.066 3.716-0.144 3.255 1.267z"/> + <path fill="#222" d="m87.972 221.825c-0.645 4.355-1.08 17.164 3.47 24.018 4.551 6.816 2.179 7.439-1.58 3.285-3.877-4.076-6.044-9.707-6.667-14.938-0.389-3.258 1.112-12.049 1.691-13.449 0.587-1.019 3.514-0.306 3.086 1.084z"/> + <path fill="#262626" d="m87.883 222.172c-0.612 4.609-1.009 16.849 3.527 23.688 4.536 6.804 2.052 7.056-1.548 3.024-3.708-3.961-5.724-9.36-6.408-14.58-0.432-3.276 0.973-11.629 1.513-13.032 0.54-0.971 3.311-0.467 2.916 0.9z"/> + <path fill="#2a2a2a" d="m87.792 222.523c-0.579 4.86-0.936 16.531 3.586 23.356 4.521 6.793 1.926 6.675-1.516 2.765-3.539-3.845-5.403-9.015-6.148-14.224-0.476-3.293 0.831-11.207 1.332-12.614 0.493-0.925 3.11-0.63 2.746 0.717z"/> + <path fill="#2d2d2d" d="m87.702 222.872c-0.547 5.112-0.864 16.215 3.644 23.025 4.507 6.783 1.8 6.293-1.483 2.506-3.369-3.73-5.083-8.669-5.89-13.867-0.519-3.312 0.691-10.785 1.152-12.197 0.446-0.878 2.908-0.792 2.577 0.533z"/> + <path fill="#313131" d="m87.612 223.221c-0.515 5.363-0.792 15.898 3.701 22.693 4.492 6.772 1.674 5.912-1.451 2.248-3.2-3.615-4.763-8.324-5.63-13.512-0.563-3.33 0.551-10.363 0.972-11.779 0.399-0.831 2.707-0.953 2.408 0.35z"/> + <path fill="#353535" d="m87.522 223.57c-0.482 5.616-0.72 15.581 3.758 22.363 4.479 6.761 1.549 5.53-1.418 1.987-3.031-3.5-4.442-7.978-5.371-13.154-0.604-3.348 0.41-9.943 0.792-11.361 0.352-0.785 2.506-1.115 2.239 0.165z"/> + <path fill="#393939" d="m87.432 223.918c-0.45 5.869-0.648 15.265 3.815 22.033 4.464 6.75 1.422 5.147-1.386 1.728-2.862-3.384-4.122-7.632-5.112-12.798-0.647-3.366 0.271-9.522 0.612-10.944 0.307-0.737 2.305-1.278 2.071-0.019z"/> + <path fill="#3d3d3d" d="m87.343 224.269c-0.418 6.12-0.576 14.946 3.873 21.7 4.45 6.74 1.296 4.767-1.354 1.469-2.692-3.27-3.802-7.286-4.853-12.441-0.691-3.383 0.129-9.101 0.432-10.527 0.26-0.691 2.103-1.44 1.902-0.201z"/> + <path fill="#414141" d="m87.252 224.618c-0.385 6.373-0.504 14.631 3.932 21.369 4.436 6.729 1.17 4.385-1.321 1.211-2.523-3.154-3.481-6.941-4.594-12.086-0.734-3.402-0.011-8.68 0.252-10.109 0.212-0.644 1.901-1.602 1.731-0.385z"/> + <path fill="#444" d="m87.162 224.967c-0.353 6.623-0.432 14.314 3.989 21.037 4.421 6.719 1.044 4.004-1.289 0.951-2.354-3.039-3.161-6.595-4.334-11.729-0.778-3.42-0.151-8.258 0.071-9.691 0.166-0.597 1.7-1.763 1.563-0.568z"/> + <path fill="#484848" d="m87.072 225.316c-0.32 6.876-0.36 13.997 4.047 20.707 4.406 6.707 0.918 3.622-1.257 0.692-2.186-2.924-2.841-6.25-4.075-11.373-0.82-3.438-0.292-7.838-0.108-9.273 0.119-0.551 1.498-1.926 1.393-0.753z"/> + <path fill="#4c4c4c" d="m86.982 225.665c-0.288 7.129-0.288 13.68 4.104 20.377 4.393 6.695 0.792 3.24-1.224 0.432s-2.52-5.904-3.816-11.016c-0.863-3.457-0.432-7.416-0.287-8.856 0.071-0.505 1.295-2.089 1.223-0.937z"/> + </g> + <g transform="translate(-12.4048,10.0005)"> + <path d="m88.782 218.681c4.32-9.433 6.696-19.584 12.888-29.448 6.12-9.792 3.672-13.608-0.863-8.64-4.536 4.968-9.504 15.48-9.504 15.48s-5.832 9.216-7.128 19.872c-0.217 1.8 3.887 4.248 4.607 2.736z"/> + <path fill="#020202" d="m88.968 218.071c4.279-9.5 6.615-19.246 12.586-28.802 5.901-9.488 3.608-13.279-0.764-8.472-4.403 4.847-9.302 15.236-9.368 15.381 0 0-5.637 8.993-6.877 19.239-0.209 1.771 3.72 4.145 4.423 2.654z"/> + <path fill="#050505" d="m89.152 217.459c4.239-9.566 6.535-18.908 12.284-28.155 5.683-9.183 3.547-12.95-0.663-8.303-4.27 4.725-9.099 14.991-9.231 15.282 0 0-5.442 8.766-6.627 18.605-0.201 1.741 3.554 4.042 4.237 2.571z"/> + <path fill="#070707" d="m89.338 216.849c4.199-9.634 6.454-18.572 11.981-27.51 5.465-8.878 3.484-12.621-0.563-8.135-4.137 4.605-8.896 14.748-9.096 15.184 0 0-5.247 8.542-6.376 17.972-0.192 1.713 3.387 3.937 4.054 2.489z"/> + <path fill="#0a0a0a" d="m89.522 216.239c4.159-9.701 6.375-18.234 11.68-26.865 5.247-8.573 3.422-12.292-0.461-7.966-4.005 4.483-8.693 14.503-8.96 15.085 0 0-5.053 8.317-6.126 17.337-0.186 1.684 3.219 3.837 3.867 2.409z"/> + <path fill="#0c0c0c" d="m89.708 215.627c4.118-9.769 6.294-17.897 11.376-26.218 5.029-8.268 3.36-11.962-0.359-7.797-3.871 4.361-8.49 14.259-8.823 14.985 0 0-4.858 8.093-5.876 16.706-0.179 1.653 3.051 3.731 3.682 2.324z"/> + <path fill="#0f0f0f" d="m89.893 215.017c4.077-9.836 6.213-17.56 11.073-25.573 4.812-7.963 3.298-11.633-0.259-7.629-3.738 4.241-8.288 14.015-8.688 14.887 0 0-4.663 7.868-5.625 16.072-0.169 1.624 2.886 3.628 3.499 2.243z"/> + <path fill="#111" d="m90.078 214.407c4.037-9.904 6.133-17.224 10.772-24.928 4.593-7.658 3.234-11.304-0.159-7.46-3.605 4.119-8.085 13.771-8.551 14.788 0 0-4.47 7.645-5.375 15.439-0.162 1.594 2.718 3.524 3.313 2.161z"/> + <path fill="#141414" d="m90.263 213.795c3.997-9.971 6.052-16.885 10.47-24.281 4.374-7.353 3.172-10.975-0.059-7.291-3.472 3.998-7.882 13.526-8.415 14.689 0 0-4.273 7.418-5.124 14.805-0.154 1.565 2.551 3.421 3.128 2.078z"/> + <path fill="#161616" d="m90.449 213.184c3.956-10.037 5.972-16.548 10.167-23.635 4.156-7.048 3.11-10.645 0.043-7.123-3.34 3.877-7.68 13.283-8.279 14.591 0 0-4.08 7.194-4.874 14.172-0.147 1.535 2.383 3.317 2.943 1.995z"/> + <path fill="#191919" d="m90.634 212.573c3.916-10.105 5.892-16.209 9.865-22.989 3.938-6.743 3.047-10.316 0.144-6.954-3.207 3.755-7.477 13.038-8.143 14.491 0 0-3.886 6.969-4.624 13.54-0.139 1.506 2.217 3.213 2.758 1.912z"/> + <path fill="#1c1c1c" d="m90.819 211.963c3.875-10.174 5.811-15.874 9.563-22.344 3.721-6.438 2.984-9.987 0.244-6.785-3.073 3.634-7.274 12.793-8.007 14.392 0 0-3.69 6.745-4.373 12.905-0.131 1.477 2.049 3.112 2.573 1.832z"/> + <path fill="#1e1e1e" d="m91.004 211.352c3.836-10.24 5.73-15.536 9.262-21.698 3.501-6.133 2.922-9.658 0.344-6.617-2.94 3.513-7.071 12.55-7.87 14.293 0 0-3.496 6.521-4.123 12.272-0.124 1.447 1.881 3.009 2.387 1.75z"/> + <path fill="#212121" d="m91.189 210.741c3.795-10.307 5.649-15.198 8.958-21.052 3.284-5.828 2.859-9.328 0.445-6.448-2.808 3.392-6.868 12.305-7.734 14.195 0 0-3.301 6.295-3.872 11.639-0.115 1.418 1.715 2.904 2.203 1.666z"/> + <path fill="#232323" d="m91.375 210.129c3.754-10.373 5.569-14.86 8.655-20.405 3.066-5.523 2.797-8.999 0.547-6.279-2.675 3.27-6.666 12.061-7.599 14.097 0 0-3.106 6.07-3.622 11.004-0.107 1.388 1.548 2.801 2.019 1.583z"/> + <path fill="#262626" d="m91.559 209.519c3.714-10.44 5.489-14.523 8.354-19.76 2.847-5.218 2.735-8.67 0.647-6.111-2.542 3.149-6.463 11.817-7.462 13.997 0 0-2.912 5.848-3.372 10.373-0.099 1.357 1.381 2.697 1.833 1.501z"/> + <path fill="#282828" d="m91.745 208.909c3.674-10.509 5.408-14.187 8.051-19.115 2.629-4.913 2.672-8.341 0.748-5.942-2.409 3.028-6.261 11.573-7.326 13.898 0 0-2.717 5.621-3.121 9.738-0.092 1.33 1.213 2.595 1.648 1.421z"/> + <path fill="#2b2b2b" d="m91.929 208.297c3.634-10.575 5.328-13.848 7.75-18.468 2.41-4.608 2.609-8.011 0.848-5.773-2.275 2.906-6.058 11.328-7.189 13.799 0 0-2.522 5.397-2.871 9.106-0.084 1.299 1.046 2.491 1.462 1.336z"/> + <path fill="#2d2d2d" d="m92.115 207.687c3.593-10.643 5.247-13.512 7.447-17.823 2.191-4.303 2.547-7.682 0.949-5.605-2.144 2.786-5.855 11.085-7.055 13.701 0 0-2.327 5.172-2.62 8.473-0.076 1.269 0.881 2.386 1.279 1.254z"/> + <path fill="#303030" d="m92.301 207.077c3.552-10.71 5.167-13.175 7.145-17.178 1.974-3.998 2.484-7.353 1.05-5.436-2.011 2.664-5.652 10.84-6.918 13.602 0 0-2.133 4.947-2.37 7.839-0.07 1.24 0.712 2.283 1.093 1.173z"/> + <path fill="#333" d="m92.485 206.465c3.513-10.778 5.087-12.837 6.843-16.531s2.422-7.024 1.15-5.268c-1.877 2.543-5.449 10.596-6.781 13.502 0 0-1.938 4.724-2.12 7.207-0.061 1.211 0.545 2.18 0.908 1.09z"/> + </g> + <g transform="translate(-12.4048,10.0005)"> + <path d="m273.03 225.592c2.088-5.903 1.872-20.951-3.456-30.671-1.872-3.528-3.672-7.632-4.752-7.848-1.152-0.216-3.24 2.088-3.024 2.448 0.288 0.576 10.009 14.256 7.992 32.832-0.144 1.513 2.736 4.608 3.24 3.239z"/> + <path fill="#030303" d="m272.936 224.831c2.025-5.719 1.753-20.379-3.344-29.663-1.815-3.407-3.535-7.374-4.595-7.59-1.122-0.214-3.125 2.022-2.925 2.367 0.258 0.562 9.605 13.778 7.729 31.753-0.129 1.487 2.647 4.456 3.135 3.133z"/> + <path fill="#070707" d="m272.841 224.068c1.967-5.532 1.637-19.808-3.228-28.654-1.762-3.286-3.401-7.115-4.44-7.332-1.091-0.211-3.009 1.956-2.824 2.287 0.227 0.548 9.201 13.299 7.466 30.672-0.118 1.463 2.555 4.305 3.026 3.027z"/> + <path fill="#0b0b0b" d="m272.747 223.305c1.904-5.348 1.518-19.235-3.115-27.645-1.706-3.165-3.265-6.856-4.282-7.073-1.062-0.21-2.896 1.889-2.727 2.206 0.197 0.534 8.799 12.821 7.203 29.592-0.103 1.44 2.466 4.153 2.921 2.92z"/> + <path fill="#0f0f0f" d="m272.652 222.542c1.843-5.162 1.398-18.662-3.001-26.635-1.65-3.044-3.13-6.598-4.127-6.815-1.03-0.207-2.779 1.823-2.626 2.126 0.167 0.52 8.396 12.341 6.94 28.511-0.09 1.416 2.376 4.001 2.814 2.813z"/> + <path fill="#131313" d="m272.558 221.779c1.78-4.976 1.279-18.09-2.889-25.626-1.595-2.923-2.994-6.34-3.97-6.557-1-0.205-2.664 1.756-2.527 2.045 0.137 0.506 7.993 11.861 6.679 27.432-0.078 1.392 2.285 3.849 2.707 2.706z"/> + <path fill="#161616" d="m272.463 221.016c1.721-4.79 1.163-17.518-2.773-24.617-1.539-2.802-2.858-6.081-3.814-6.299-0.969-0.203-2.548 1.691-2.427 1.965 0.106 0.492 7.59 11.383 6.415 26.352-0.065 1.369 2.194 3.697 2.599 2.599z"/> + <path fill="#1a1a1a" d="m272.369 220.254c1.659-4.605 1.044-16.946-2.66-23.609-1.483-2.681-2.723-5.822-3.658-6.04-0.938-0.201-2.434 1.624-2.326 1.884 0.074 0.478 7.185 10.904 6.15 25.271-0.051 1.344 2.106 3.546 2.494 2.494z"/> + <path fill="#1e1e1e" d="m272.274 219.491c1.598-4.42 0.926-16.373-2.546-22.6-1.43-2.56-2.587-5.564-3.501-5.782-0.908-0.198-2.319 1.558-2.229 1.804 0.044 0.464 6.782 10.425 5.889 24.19-0.037 1.321 2.016 3.396 2.387 2.388z"/> + <path fill="#222" d="m272.18 218.728c1.535-4.233 0.807-15.802-2.434-21.59-1.373-2.439-2.452-5.306-3.345-5.524-0.877-0.197-2.203 1.491-2.128 1.723 0.014 0.45 6.379 9.947 5.625 23.111-0.023 1.297 1.927 3.242 2.282 2.28z"/> + <path fill="#262626" d="m272.085 217.965c1.476-4.049 0.69-15.229-2.318-20.582-1.317-2.317-2.316-5.046-3.188-5.265-0.847-0.194-2.088 1.425-2.029 1.642-0.016 0.436 5.977 9.468 5.362 22.032-0.011 1.272 1.835 3.089 2.173 2.173z"/> + <path fill="#2a2a2a" d="m271.991 217.202c1.413-3.861 0.571-14.656-2.206-19.572-1.262-2.196-2.18-4.788-3.032-5.007-0.815-0.191-1.973 1.36-1.929 1.562-0.047 0.422 5.573 8.988 5.099 20.951 0.003 1.247 1.746 2.939 2.068 2.066z"/> + <path fill="#2d2d2d" d="m271.896 216.439c1.353-3.677 0.453-14.084-2.091-18.563-1.207-2.076-2.045-4.529-2.876-4.749-0.786-0.19-1.858 1.293-1.83 1.481-0.077 0.408 5.17 8.51 4.836 19.87 0.017 1.226 1.656 2.789 1.961 1.961z"/> + <path fill="#313131" d="m271.802 215.676c1.29-3.491 0.334-13.512-1.979-17.553-1.151-1.956-1.909-4.272-2.72-4.493-0.755-0.187-1.742 1.227-1.73 1.401-0.106 0.394 4.768 8.031 4.573 18.791 0.031 1.202 1.567 2.637 1.856 1.854z"/> + <path fill="#353535" d="m271.707 214.915c1.23-3.307 0.217-12.94-1.864-16.545-1.096-1.834-1.773-4.014-2.563-4.234-0.725-0.185-1.627 1.16-1.631 1.32-0.138 0.38 4.364 7.552 4.311 17.71 0.042 1.176 1.475 2.485 1.747 1.749z"/> + <path fill="#393939" d="m271.613 214.151c1.168-3.119 0.098-12.367-1.751-15.535-1.04-1.714-1.638-3.755-2.407-3.976-0.693-0.183-1.512 1.094-1.531 1.24-0.168 0.366 3.962 7.074 4.049 16.63 0.055 1.153 1.384 2.332 1.64 1.641z"/> + <path fill="#3d3d3d" d="m271.518 213.388c1.106-2.935-0.021-11.796-1.638-14.527-0.983-1.592-1.502-3.496-2.25-3.716-0.664-0.181-1.396 1.028-1.432 1.159-0.198 0.352 3.558 6.594 3.785 15.549 0.07 1.13 1.296 2.183 1.535 1.535z"/> + <path fill="#414141" d="m271.424 212.625c1.047-2.75-0.139-11.223-1.522-13.518-0.93-1.471-1.367-3.238-2.094-3.459-0.635-0.178-1.282 0.962-1.333 1.079-0.229 0.338 3.153 6.114 3.521 14.47 0.083 1.106 1.205 2.03 1.428 1.428z"/> + <path fill="#444" d="m271.329 211.862c0.985-2.563-0.256-10.65-1.409-12.508-0.874-1.35-1.23-2.979-1.938-3.2-0.604-0.177-1.166 0.895-1.233 0.998-0.259 0.324 2.751 5.636 3.259 13.39 0.096 1.082 1.115 1.876 1.321 1.32z"/> + <path fill="#484848" d="m271.235 211.099c0.923-2.377-0.375-10.077-1.296-11.499-0.818-1.229-1.097-2.72-1.781-2.942-0.573-0.174-1.052 0.829-1.134 0.918-0.289 0.309 2.348 5.156 2.996 12.309 0.11 1.058 1.025 1.726 1.215 1.214z"/> + <path fill="#4c4c4c" d="m271.14 210.336c0.861-2.192-0.493-9.506-1.183-10.49-0.763-1.107-0.96-2.463-1.625-2.684-0.542-0.172-0.936 0.762-1.034 0.836-0.319 0.297 1.945 4.68 2.733 11.229 0.124 1.035 0.936 1.576 1.109 1.109z"/> + </g> + <g transform="translate(-12.4048,10.0005)"> + <path d="m264.822 187.073c-10.224-13.968-23.472-18.504-22.104-14.112 0 0 10.152 5.76 19.08 16.56 1.728 2.088 4.608-0.288 3.024-2.448z"/> + <path fill="#030303" d="m264.372 186.687c-9.924-13.495-22.894-17.912-21.539-13.7 0.018 0.012 9.901 5.614 18.609 16.071 1.678 2.016 4.467-0.285 2.93-2.371z"/> + <path fill="#070707" d="m263.922 186.3c-9.624-13.022-22.316-17.319-20.975-13.287 0.036 0.023 9.652 5.467 18.139 15.582 1.628 1.943 4.325-0.283 2.836-2.295z"/> + <path fill="#0b0b0b" d="m263.472 185.913c-9.324-12.549-21.739-16.726-20.41-12.874 0.053 0.034 9.4 5.32 17.668 15.093 1.578 1.871 4.183-0.28 2.742-2.219z"/> + <path fill="#0f0f0f" d="m263.022 185.527c-9.024-12.077-21.162-16.134-19.847-12.462 0.071 0.045 9.151 5.174 17.198 14.604 1.529 1.798 4.043-0.278 2.649-2.142z"/> + <path fill="#131313" d="m262.571 185.14c-8.723-11.603-20.583-15.541-19.28-12.049 0.088 0.056 8.901 5.027 16.728 14.114 1.477 1.726 3.899-0.275 2.552-2.065z"/> + <path fill="#161616" d="m262.121 184.753c-8.423-11.13-20.006-14.948-18.716-11.636 0.106 0.067 8.651 4.88 16.257 13.625 1.428 1.654 3.759-0.272 2.459-1.989z"/> + <path fill="#1a1a1a" d="m261.671 184.367c-8.124-10.658-19.428-14.356-18.15-11.224 0.124 0.078 8.399 4.734 15.785 13.136 1.378 1.581 3.617-0.27 2.365-1.912z"/> + <path fill="#1e1e1e" d="m261.221 183.98c-7.824-10.185-18.851-13.763-17.588-10.811 0.143 0.089 8.151 4.587 15.315 12.647 1.33 1.508 3.477-0.267 2.273-1.836z"/> + <path fill="#222" d="m260.771 183.593c-7.524-9.711-18.273-13.17-17.022-10.398 0.159 0.1 7.9 4.44 14.844 12.158 1.279 1.436 3.335-0.265 2.178-1.76z"/> + <path fill="#262626" d="m260.321 183.206c-7.224-9.238-17.695-12.578-16.458-9.985 0.177 0.111 7.65 4.293 14.374 11.668 1.229 1.364 3.193-0.262 2.084-1.683z"/> + <path fill="#2a2a2a" d="m259.871 182.82c-6.924-8.766-17.118-11.986-15.893-9.573 0.193 0.122 7.398 4.147 13.902 11.179 1.18 1.291 3.053-0.259 1.991-1.606z"/> + <path fill="#2d2d2d" d="m259.42 182.433c-6.623-8.293-16.539-11.393-15.328-9.16 0.214 0.133 7.15 4 13.434 10.69 1.128 1.219 2.909-0.257 1.894-1.53z"/> + <path fill="#313131" d="m258.97 182.046c-6.323-7.819-15.963-10.8-14.764-8.747 0.23 0.144 6.899 3.853 12.962 10.201 1.08 1.146 2.769-0.254 1.802-1.454z"/> + <path fill="#353535" d="m258.52 181.66c-6.023-7.347-15.384-10.208-14.199-8.335 0.248 0.155 6.649 3.707 12.492 9.712 1.028 1.073 2.627-0.252 1.707-1.377z"/> + <path fill="#393939" d="m258.07 181.273c-5.723-6.874-14.807-9.615-13.634-7.922 0.265 0.166 6.398 3.56 12.021 9.222 0.978 1.002 2.485-0.249 1.613-1.3z"/> + <path fill="#3d3d3d" d="m257.62 180.886c-5.423-6.401-14.229-9.021-13.07-7.509 0.283 0.177 6.149 3.413 11.552 8.733 0.927 0.929 2.343-0.246 1.518-1.224z"/> + <path fill="#414141" d="m257.17 180.5c-5.124-5.928-13.65-8.43-12.505-7.097 0.301 0.188 5.898 3.267 11.079 8.244 0.879 0.856 2.203-0.244 1.426-1.147z"/> + <path fill="#444" d="m256.719 180.113c-4.823-5.455-13.073-7.837-11.94-6.684 0.319 0.199 5.649 3.12 10.609 7.755 0.829 0.784 2.061-0.241 1.331-1.071z"/> + <path fill="#484848" d="m256.269 179.726c-4.523-4.982-12.495-7.244-11.375-6.271 0.336 0.21 5.397 2.973 10.138 7.266 0.779 0.711 1.92-0.239 1.237-0.995z"/> + <path fill="#4c4c4c" d="m255.819 179.339c-4.223-4.509-11.918-6.652-10.812-5.859 0.354 0.222 5.148 2.827 9.668 6.777 0.73 0.639 1.779-0.236 1.144-0.918z"/> + </g> + <g transform="translate(-12.4048,10.0005)"> + <path d="m273.03 225.592c0.144 6.265-5.76 22.248-7.992 21.673-2.52-0.576 0.504-5.257 2.809-13.177 0.936-3.312 1.655-11.447 1.943-11.735 0.936-0.936 3.24 1.728 3.24 3.239z"/> + <path fill="#050505" d="m272.846 226.116c0.103 6.082-5.638 21.594-7.797 21.018-2.422-0.567 0.548-5.146 2.814-12.928 0.899-3.178 1.595-10.947 1.887-11.25 0.914-0.927 3.147 1.527 3.096 3.16z"/> + <path fill="#0a0a0a" d="m272.662 226.637c0.063 5.902-5.514 20.939-7.601 20.363-2.323-0.558 0.592-5.035 2.82-12.681 0.861-3.041 1.534-10.446 1.83-10.761 0.89-0.917 3.054 1.327 2.951 3.079z"/> + <path fill="#0f0f0f" d="m272.478 227.159c0.021 5.721-5.392 20.284-7.405 19.711-2.224-0.55 0.635-4.927 2.827-12.434 0.824-2.907 1.473-9.945 1.773-10.273 0.866-0.911 2.959 1.125 2.805 2.996z"/> + <path fill="#141414" d="m272.294 227.68c-0.02 5.539-5.268 19.63-7.21 19.057-2.125-0.541 0.68-4.816 2.835-12.186 0.786-2.771 1.412-9.445 1.717-9.786 0.84-0.901 2.863 0.924 2.658 2.915z"/> + <path fill="#191919" d="m272.11 228.202c-0.063 5.359-5.146 18.977-7.014 18.403-2.027-0.532 0.722-4.706 2.841-11.938 0.748-2.637 1.351-8.944 1.659-9.299 0.818-0.893 2.77 0.722 2.514 2.834z"/> + <path fill="#1e1e1e" d="m271.926 228.723c-0.103 5.179-5.021 18.322-6.818 17.75-1.928-0.523 0.766-4.596 2.848-11.691 0.711-2.5 1.29-8.443 1.603-8.811 0.792-0.885 2.674 0.522 2.367 2.752z"/> + <path fill="#232323" d="m271.742 229.245c-0.144 4.998-4.9 17.668-6.623 17.096-1.83-0.514 0.811-4.485 2.854-11.442 0.673-2.366 1.229-7.944 1.545-8.325 0.771-0.876 2.583 0.32 2.224 2.671z"/> + <path fill="#282828" d="m271.558 229.766c-0.186 4.816-4.777 17.013-6.428 16.443-1.731-0.506 0.854-4.377 2.86-11.196 0.636-2.231 1.168-7.443 1.488-7.837 0.749-0.866 2.49 0.119 2.08 2.59z"/> + <path fill="#2d2d2d" d="m271.374 230.288c-0.226 4.637-4.653 16.359-6.231 15.789-1.632-0.496 0.896-4.266 2.866-10.947 0.6-2.098 1.107-6.943 1.433-7.351 0.722-0.859 2.393-0.081 1.932 2.509z"/> + <path fill="#333" d="m271.19 230.809c-0.268 4.456-4.531 15.705-6.036 15.136-1.534-0.489 0.94-4.155 2.873-10.7 0.561-1.961 1.046-6.443 1.375-6.863 0.7-0.848 2.3-0.282 1.788 2.427z"/> + <path fill="#383838" d="m271.006 231.331c-0.308 4.275-4.407 15.051-5.841 14.482-1.435-0.48 0.984-4.046 2.88-10.453 0.524-1.826 0.985-5.941 1.318-6.375 0.676-0.84 2.206-0.483 1.643 2.346z"/> + <path fill="#3d3d3d" d="m270.822 231.853c-0.35 4.093-4.285 14.396-5.645 13.828-1.338-0.472 1.027-3.937 2.886-10.206 0.485-1.691 0.924-5.441 1.261-5.887 0.653-0.832 2.113-0.684 1.498 2.265z"/> + <path fill="#424242" d="m270.638 232.374c-0.392 3.914-4.162 13.742-5.45 13.176-1.238-0.463 1.072-3.826 2.893-9.959 0.449-1.555 0.863-4.94 1.204-5.399 0.629-0.824 2.019-0.886 1.353 2.182z"/> + <path fill="#474747" d="m270.454 232.896c-0.432 3.731-4.039 13.087-5.254 12.521-1.14-0.453 1.115-3.715 2.9-9.711 0.411-1.42 0.802-4.439 1.146-4.912 0.606-0.815 1.925-1.086 1.208 2.102z"/> + <path fill="#4c4c4c" d="m270.27 233.417c-0.474 3.553-3.916 12.434-5.06 11.869-1.041-0.445 1.159-3.606 2.907-9.463 0.373-1.287 0.741-3.941 1.089-4.427 0.583-0.806 1.832-1.287 1.064 2.021z"/> + <path fill="#515151" d="m270.086 233.939c-0.514 3.37-3.793 11.778-4.862 11.214-0.942-0.436 1.201-3.496 2.913-9.216 0.336-1.151 0.68-3.438 1.032-3.938 0.558-0.797 1.736-1.489 0.917 1.94z"/> + <path fill="#565656" d="m269.902 234.461c-0.555 3.188-3.671 11.123-4.667 10.56-0.844-0.429 1.246-3.386 2.919-8.968 0.298-1.016 0.619-2.939 0.976-3.451 0.535-0.788 1.643-1.689 0.772 1.859z"/> + <path fill="#5b5b5b" d="m269.718 234.982c-0.597 3.009-3.548 10.47-4.472 9.907-0.745-0.42 1.29-3.275 2.926-8.721 0.262-0.881 0.559-2.438 0.919-2.963 0.511-0.781 1.549-1.89 0.627 1.777z"/> + <path fill="#606060" d="m269.534 235.504c-0.638 2.828-3.425 9.814-4.276 9.252-0.646-0.409 1.333-3.166 2.933-8.473 0.224-0.746 0.497-1.938 0.862-2.476 0.487-0.769 1.454-2.09 0.481 1.697z"/> + <path fill="#666" d="m269.35 236.025c-0.68 2.647-3.303 9.161-4.081 8.599-0.548-0.4 1.377-3.056 2.938-8.225 0.187-0.611 0.437-1.438 0.806-1.988 0.464-0.763 1.361-2.293 0.337 1.614z"/> + </g> + <g transform="translate(-12.4048,10.0005)"> + <path d="m251.07 187.865c-1.537 1.622-2.903 9.991 0.938 12.893 3.844 2.818 10.59-2.391 10.59-5.379-0.086-6.746-9.991-9.222-11.528-7.514z"/> + <path fill="#010101" d="m251.207 188.006c-1.559 1.611-2.876 9.823 0.857 12.667 3.731 2.764 10.349-2.273 10.384-5.279-0.047-6.576-9.681-9.083-11.241-7.388z"/> + <path fill="#030303" d="m251.344 188.146c-1.582 1.601-2.85 9.653 0.774 12.438 3.62 2.709 10.109-2.154 10.178-5.177-0.007-6.404-9.37-8.943-10.952-7.261z"/> + <path fill="#050505" d="m251.481 188.287c-1.604 1.589-2.823 9.484 0.691 12.211 3.511 2.653 9.869-2.037 9.975-5.078 0.031-6.232-9.061-8.802-10.666-7.133z"/> + <path fill="#070707" d="m251.617 188.427c-1.626 1.579-2.795 9.316 0.611 11.984 3.397 2.6 9.629-1.918 9.768-4.976 0.071-6.062-8.751-8.664-10.379-7.008z"/> + <path fill="#090909" d="m251.754 188.567c-1.648 1.568-2.768 9.146 0.529 11.758 3.287 2.543 9.389-1.802 9.563-4.875 0.109-5.892-8.441-8.525-10.092-6.883z"/> + <path fill="#0b0b0b" d="m251.891 188.708c-1.671 1.557-2.741 8.978 0.445 11.529 3.177 2.489 9.15-1.683 9.358-4.774 0.15-5.72-8.13-8.385-9.803-6.755z"/> + <path fill="#0d0d0d" d="m252.028 188.848c-1.694 1.546-2.715 8.809 0.364 11.302 3.064 2.435 8.908-1.565 9.152-4.673 0.189-5.549-7.82-8.245-9.516-6.629z"/> + <path fill="#0f0f0f" d="m252.165 188.989c-1.716 1.535-2.688 8.64 0.282 11.074 2.953 2.38 8.669-1.447 8.948-4.572 0.226-5.378-7.512-8.106-9.23-6.502z"/> + <path fill="#111" d="m252.301 189.129c-1.737 1.524-2.659 8.471 0.2 10.847 2.844 2.325 8.431-1.33 8.743-4.471 0.266-5.207-7.201-7.966-8.943-6.376z"/> + <path fill="#131313" d="m252.438 189.269c-1.76 1.514-2.633 8.304 0.118 10.619 2.73 2.271 8.189-1.212 8.538-4.369 0.305-5.036-6.892-7.827-8.656-6.25z"/> + <path fill="#151515" d="m252.575 189.41c-1.783 1.503-2.606 8.133 0.036 10.391 2.62 2.216 7.949-1.094 8.332-4.268 0.344-4.865-6.581-7.687-8.368-6.123z"/> + <path fill="#161616" d="m252.712 189.55c-1.805 1.492-2.58 7.965-0.046 10.164 2.508 2.162 7.709-0.975 8.127-4.167 0.383-4.694-6.272-7.548-8.081-5.997z"/> + <path fill="#181818" d="m252.849 189.691c-1.828 1.481-2.554 7.796-0.129 9.937 2.397 2.105 7.47-0.857 7.922-4.066 0.423-4.524-5.961-7.409-7.793-5.871z"/> + <path fill="#1a1a1a" d="m252.985 189.831c-1.85 1.47-2.525 7.626-0.21 9.708 2.286 2.053 7.229-0.74 7.717-3.964 0.461-4.352-5.652-7.269-7.507-5.744z"/> + <path fill="#1c1c1c" d="m253.122 189.971c-1.872 1.46-2.499 7.459-0.292 9.482 2.175 1.996 6.989-0.623 7.511-3.865 0.501-4.18-5.341-7.128-7.219-5.617z"/> + <path fill="#1e1e1e" d="m253.259 190.112c-1.895 1.448-2.472 7.289-0.375 9.254 2.064 1.942 6.75-0.504 7.308-3.763 0.539-4.01-5.033-6.99-6.933-5.491z"/> + <path fill="#202020" d="m253.396 190.252c-1.917 1.438-2.445 7.122-0.457 9.027 1.953 1.888 6.51-0.386 7.102-3.662 0.578-3.839-4.722-6.85-6.645-5.365z"/> + <path fill="#222" d="m253.533 190.393c-1.939 1.426-2.418 6.951-0.539 8.799 1.841 1.832 6.271-0.268 6.896-3.561 0.618-3.668-4.412-6.711-6.357-5.238z"/> + <path fill="#242424" d="m253.669 190.533c-1.961 1.416-2.391 6.783-0.621 8.572 1.731 1.776 6.03-0.149 6.692-3.46 0.657-3.497-4.102-6.571-6.071-5.112z"/> + <path fill="#262626" d="m253.806 190.673c-1.984 1.405-2.364 6.615-0.703 8.344 1.619 1.724 5.79-0.032 6.485-3.358 0.697-3.326-3.791-6.432-5.782-4.986z"/> + </g> + <g transform="translate(-12.4048,10.0005)"> + <path d="m250.71 256.698c1.513 1.512 2.809-2.232 4.32-3.457 1.512-1.224 3.96-3.888 8.856-3.888s4.535-0.144 4.319-2.017c-0.144-1.799-1.584-1.655-5.903-1.008-4.32 0.576-7.2 2.809-8.929 4.824-1.654 1.945-3.527 4.681-2.663 5.546z"/> + <path fill="#050505" d="m251.043 256.331c1.459 1.449 2.703-2.121 4.205-3.308 1.501-1.187 3.931-3.731 8.64-3.731 4.71-0.002 4.415-0.129 4.209-1.94-0.139-1.743-1.543-1.593-5.749-0.979-4.207 0.543-7.029 2.703-8.712 4.648-1.616 1.877-3.438 4.474-2.593 5.31z"/> + <path fill="#0a0a0a" d="m251.376 255.961c1.406 1.389 2.6-2.008 4.089-3.156 1.491-1.148 3.901-3.576 8.425-3.577 4.521-0.001 4.293-0.11 4.096-1.862-0.132-1.688-1.501-1.531-5.594-0.951-4.093 0.51-6.857 2.596-8.495 4.471-1.575 1.812-3.348 4.271-2.521 5.075z"/> + <path fill="#0f0f0f" d="m251.709 255.594c1.354 1.326 2.494-1.895 3.975-3.008 1.479-1.111 3.871-3.42 8.207-3.422s4.171-0.094 3.984-1.785c-0.126-1.631-1.46-1.467-5.438-0.924-3.979 0.479-6.687 2.492-8.28 4.297-1.533 1.747-3.257 4.066-2.448 4.842z"/> + <path fill="#141414" d="m252.042 255.226c1.302 1.265 2.39-1.783 3.858-2.856 1.47-1.076 3.842-3.266 7.991-3.268s4.05-0.077 3.873-1.709c-0.119-1.575-1.419-1.404-5.284-0.895-3.865 0.444-6.515 2.385-8.063 4.121-1.49 1.678-3.165 3.861-2.375 4.607z"/> + <path fill="#191919" d="m252.374 254.859c1.249 1.202 2.285-1.671 3.744-2.708 1.458-1.037 3.813-3.109 7.774-3.111 3.963-0.004 3.929-0.061 3.761-1.633-0.113-1.519-1.377-1.341-5.128-0.867-3.751 0.414-6.344 2.279-7.847 3.945-1.449 1.613-3.075 3.656-2.304 4.374z"/> + <path fill="#1e1e1e" d="m252.707 254.491c1.196 1.141 2.182-1.559 3.628-2.558 1.448-1 3.783-2.954 7.56-2.957 3.775-0.003 3.806-0.043 3.648-1.556-0.106-1.461-1.336-1.277-4.974-0.838-3.637 0.379-6.172 2.174-7.63 3.77-1.408 1.546-2.984 3.451-2.232 4.139z"/> + <path fill="#232323" d="m253.04 254.124c1.144 1.078 2.076-1.447 3.514-2.41 1.437-0.961 3.753-2.797 7.342-2.799 3.589-0.004 3.685-0.027 3.537-1.48-0.101-1.405-1.294-1.215-4.818-0.811-3.524 0.349-6.001 2.068-7.415 3.594-1.367 1.48-2.894 3.245-2.16 3.906z"/> + <path fill="#282828" d="m253.373 253.754c1.09 1.018 1.972-1.334 3.398-2.258 1.426-0.926 3.723-2.642 7.125-2.646 3.402-0.005 3.563-0.011 3.426-1.403-0.095-1.349-1.253-1.15-4.664-0.781-3.409 0.314-5.829 1.961-7.198 3.418-1.325 1.415-2.803 3.041-2.087 3.67z"/> + <path fill="#2d2d2d" d="m253.706 253.388c1.038 0.954 1.866-1.222 3.282-2.11 1.416-0.887 3.694-2.486 6.909-2.49 3.217-0.004 3.441 0.008 3.313-1.326-0.088-1.293-1.212-1.088-4.508-0.754-3.296 0.283-5.658 1.857-6.981 3.244-1.284 1.345-2.712 2.836-2.015 3.436z"/> + <path fill="#333" d="m254.039 253.02c0.985 0.893 1.762-1.109 3.167-1.96s3.664-2.33 6.693-2.335c3.029-0.006 3.32 0.023 3.202-1.249-0.082-1.237-1.171-1.024-4.354-0.726-3.182 0.25-5.485 1.75-6.765 3.066-1.243 1.282-2.622 2.634-1.943 3.204z"/> + <path fill="#383838" d="m254.372 252.652c0.933 0.831 1.657-0.998 3.051-1.81 1.396-0.813 3.636-2.174 6.478-2.18 2.843-0.006 3.199 0.039 3.09-1.172-0.076-1.181-1.129-0.963-4.198-0.697-3.068 0.217-5.314 1.644-6.55 2.891-1.202 1.214-2.531 2.427-1.871 2.968z"/> + <path fill="#3d3d3d" d="m254.704 252.284c0.88 0.771 1.553-0.885 2.938-1.66 1.383-0.775 3.604-2.019 6.26-2.024 2.656-0.007 3.078 0.058 2.979-1.095-0.069-1.125-1.088-0.899-4.044-0.67-2.954 0.185-5.144 1.539-6.333 2.715-1.16 1.148-2.441 2.222-1.8 2.734z"/> + <path fill="#424242" d="m255.037 251.917c0.827 0.707 1.448-0.773 2.821-1.51 1.373-0.738 3.576-1.863 6.044-1.871 2.47-0.007 2.956 0.074 2.867-1.018-0.063-1.068-1.046-0.836-3.889-0.641-2.841 0.151-4.973 1.433-6.116 2.539-1.119 1.083-2.35 2.018-1.727 2.501z"/> + <path fill="#474747" d="m255.37 251.549c0.774 0.645 1.344-0.661 2.706-1.362 1.362-0.7 3.545-1.706 5.828-1.713 2.283-0.009 2.834 0.09 2.754-0.942-0.057-1.012-1.005-0.773-3.733-0.613-2.727 0.119-4.801 1.328-5.899 2.365-1.078 1.013-2.26 1.81-1.656 2.265z"/> + <path fill="#4c4c4c" d="m255.703 251.181c0.721 0.584 1.239-0.55 2.59-1.212 1.353-0.663 3.517-1.551 5.612-1.559 2.096-0.009 2.713 0.107 2.643-0.865-0.051-0.955-0.964-0.709-3.577-0.584-2.613 0.086-4.631 1.222-5.686 2.188-1.035 0.949-2.168 1.607-1.582 2.032z"/> + <path fill="#515151" d="m256.036 250.813c0.669 0.521 1.134-0.436 2.476-1.063 1.341-0.625 3.485-1.395 5.395-1.402 1.91-0.01 2.591 0.124 2.531-0.789-0.044-0.898-0.922-0.646-3.423-0.557-2.499 0.055-4.458 1.117-5.469 2.014-0.994 0.882-2.077 1.402-1.51 1.797z"/> + <path fill="#565656" d="m256.369 250.446c0.616 0.459 1.029-0.324 2.36-0.912 1.33-0.589 3.456-1.24 5.178-1.248 1.723-0.01 2.47 0.141 2.42-0.713-0.039-0.842-0.881-0.582-3.268-0.527-2.387 0.021-4.287 1.01-5.252 1.836-0.953 0.816-1.987 1.199-1.438 1.564z"/> + <path fill="#5b5b5b" d="m256.701 250.079c0.564 0.397 0.926-0.213 2.245-0.764s3.427-1.084 4.963-1.093c1.536-0.011 2.348 0.157 2.307-0.636-0.031-0.785-0.839-0.52-3.112-0.5-2.271-0.01-4.116 0.906-5.035 1.662-0.913 0.751-1.898 0.993-1.368 1.331z"/> + <path fill="#606060" d="m257.034 249.709c0.511 0.336 0.821-0.1 2.13-0.612 1.309-0.515 3.397-0.929 4.746-0.938 1.351-0.01 2.227 0.176 2.196-0.558-0.026-0.729-0.799-0.457-2.958-0.472-2.158-0.043-3.945 0.799-4.82 1.486-0.87 0.682-1.805 0.788-1.294 1.094z"/> + <path fill="#666" d="m257.367 249.342c0.458 0.273 0.716 0.012 2.014-0.465 1.299-0.476 3.368-0.771 4.53-0.781 1.163-0.012 2.105 0.191 2.084-0.482-0.02-0.673-0.757-0.393-2.803-0.443-2.044-0.076-3.773 0.693-4.604 1.311-0.828 0.616-1.714 0.582-1.221 0.86z"/> + </g> + <g transform="translate(-12.4048,10.0005)"> + <path d="m270.222 247.265c0 2.304 4.68 3.096 9.144 3.743 4.392 0.648 7.92 1.513 8.136 6.121 0.216 4.535-0.936 7.775 1.08 7.416 4.32-0.793 5.904-5.473 5.832-7.633 0-2.16-3.168-6.047-8.855-8.207-4.177-1.584-7.2-2.305-10.872-2.449-4.897-0.214-4.465 1.009-4.465 1.009z"/> + <path fill="#030303" d="m270.348 247.304c0.012 2.239 4.643 2.97 9.049 3.639 4.352 0.675 7.75 1.511 8.11 6.002 0.345 4.415-0.854 7.515 1.136 7.188 4.145-0.739 5.688-5.2 5.607-7.332-0.015-2.151-3.118-5.91-8.733-8.038-4.129-1.563-7.11-2.298-10.74-2.452-4.754-0.217-4.438 0.952-4.429 0.993z"/> + <path fill="#070707" d="m270.474 247.342c0.023 2.174 4.605 2.845 8.953 3.533 4.312 0.701 7.58 1.508 8.087 5.885 0.471 4.295-0.771 7.252 1.189 6.963 3.97-0.689 5.472-4.93 5.384-7.033-0.028-2.145-3.068-5.773-8.61-7.87-4.082-1.543-7.022-2.291-10.609-2.456-4.612-0.218-4.412 0.896-4.394 0.978z"/> + <path fill="#0b0b0b" d="m270.6 247.379c0.035 2.109 4.568 2.721 8.857 3.431 4.271 0.728 7.411 1.506 8.063 5.767 0.599 4.174-0.689 6.988 1.245 6.735 3.795-0.638 5.257-4.66 5.159-6.733-0.044-2.137-3.019-5.636-8.488-7.701-4.035-1.522-6.933-2.285-10.478-2.459-4.469-0.219-4.384 0.837-4.358 0.96z"/> + <path fill="#0f0f0f" d="m270.726 247.418c0.047 2.043 4.531 2.595 8.762 3.324 4.232 0.754 7.242 1.504 8.039 5.649 0.725 4.052-0.608 6.728 1.299 6.509 3.621-0.586 5.041-4.389 4.937-6.436-0.06-2.127-2.971-5.496-8.367-7.53-3.988-1.502-6.842-2.278-10.346-2.464-4.328-0.22-4.359 0.784-4.324 0.948z"/> + <path fill="#131313" d="m270.852 247.458c0.059 1.978 4.495 2.469 8.667 3.219 4.19 0.781 7.071 1.502 8.014 5.531 0.854 3.932-0.526 6.465 1.354 6.283 3.445-0.535 4.824-4.119 4.712-6.137-0.074-2.119-2.92-5.359-8.245-7.361-3.941-1.482-6.753-2.271-10.213-2.469-4.186-0.221-4.333 0.726-4.289 0.934z"/> + <path fill="#161616" d="m270.978 247.495c0.07 1.914 4.458 2.344 8.57 3.115 4.151 0.807 6.903 1.5 7.99 5.413 0.98 3.812-0.443 6.202 1.409 6.056 3.271-0.482 4.609-3.848 4.488-5.836-0.088-2.111-2.871-5.222-8.123-7.193-3.894-1.461-6.663-2.264-10.081-2.471-4.043-0.223-4.306 0.67-4.253 0.916z"/> + <path fill="#1a1a1a" d="m271.104 247.534c0.082 1.848 4.422 2.219 8.476 3.01 4.111 0.832 6.734 1.498 7.965 5.295 1.108 3.69-0.36 5.94 1.464 5.83 3.097-0.433 4.394-3.578 4.265-5.537-0.104-2.104-2.821-5.084-8-7.023-3.848-1.441-6.575-2.26-9.949-2.477-3.905-0.223-4.283 0.613-4.221 0.902z"/> + <path fill="#1e1e1e" d="m271.23 247.573c0.094 1.781 4.385 2.092 8.381 2.904 4.07 0.859 6.563 1.495 7.939 5.178 1.236 3.568-0.278 5.678 1.52 5.602 2.921-0.381 4.177-3.305 4.04-5.237-0.118-2.097-2.771-4.946-7.878-6.854-3.8-1.42-6.485-2.252-9.817-2.479-3.762-0.226-4.256 0.556-4.185 0.886z"/> + <path fill="#222" d="m271.356 247.61c0.105 1.717 4.348 1.969 8.285 2.801 4.029 0.885 6.395 1.493 7.916 5.059 1.362 3.449-0.197 5.416 1.573 5.377 2.746-0.329 3.962-3.036 3.816-4.939-0.133-2.087-2.722-4.808-7.756-6.684-3.753-1.4-6.396-2.247-9.686-2.484-3.618-0.227-4.227 0.499-4.148 0.87z"/> + <path fill="#262626" d="m271.482 247.648c0.118 1.651 4.311 1.843 8.189 2.694 3.99 0.914 6.226 1.492 7.892 4.943 1.491 3.328-0.115 5.152 1.629 5.149 2.571-0.278 3.746-2.765 3.592-4.64-0.146-2.08-2.672-4.672-7.634-6.516-3.705-1.38-6.306-2.24-9.553-2.488-3.478-0.225-4.203 0.446-4.115 0.858z"/> + <path fill="#2a2a2a" d="m271.608 247.687c0.129 1.587 4.273 1.716 8.094 2.59 3.95 0.938 6.056 1.489 7.867 4.825 1.618 3.206-0.033 4.891 1.684 4.922 2.396-0.227 3.53-2.494 3.368-4.34-0.162-2.072-2.623-4.534-7.512-6.348-3.658-1.358-6.216-2.232-9.421-2.492-3.336-0.226-4.177 0.39-4.08 0.843z"/> + <path fill="#2d2d2d" d="m271.734 247.725c0.141 1.521 4.237 1.591 7.999 2.484 3.909 0.967 5.886 1.488 7.842 4.707 1.746 3.086 0.05 4.629 1.739 4.697 2.221-0.176 3.313-2.225 3.144-4.041-0.177-2.064-2.572-4.396-7.389-6.178-3.612-1.339-6.128-2.227-9.29-2.497-3.194-0.227-4.151 0.334-4.045 0.828z"/> + <path fill="#313131" d="m271.86 247.763c0.153 1.456 4.2 1.466 7.903 2.381 3.869 0.991 5.717 1.485 7.817 4.589 1.873 2.965 0.132 4.365 1.794 4.469 2.046-0.123 3.099-1.953 2.92-3.742-0.191-2.055-2.523-4.258-7.267-6.008-3.565-1.318-6.038-2.22-9.158-2.5-3.051-0.229-4.124 0.276-4.009 0.811z"/> + <path fill="#353535" d="m271.986 247.801c0.165 1.392 4.163 1.341 7.808 2.275 3.829 1.018 5.547 1.483 7.794 4.473 2 2.843 0.213 4.103 1.848 4.242 1.873-0.074 2.883-1.683 2.696-3.443-0.206-2.047-2.474-4.12-7.145-5.838-3.517-1.299-5.948-2.215-9.026-2.506-2.91-0.229-4.099 0.221-3.975 0.797z"/> + <path fill="#393939" d="m272.112 247.84c0.176 1.326 4.126 1.215 7.712 2.17 3.789 1.045 5.378 1.482 7.771 4.354 2.127 2.723 0.295 3.842 1.901 4.016 1.698-0.021 2.667-1.412 2.474-3.144-0.222-2.038-2.426-3.981-7.023-5.669-3.47-1.277-5.859-2.208-8.894-2.509-2.769-0.231-4.074 0.164-3.941 0.782z"/> + <path fill="#3d3d3d" d="m272.238 247.877c0.188 1.262 4.089 1.09 7.617 2.066 3.749 1.071 5.208 1.479 7.745 4.236 2.255 2.602 0.377 3.578 1.957 3.789 1.522 0.029 2.451-1.141 2.249-2.844-0.236-2.033-2.375-3.846-6.901-5.5-3.423-1.258-5.769-2.203-8.762-2.514-2.626-0.231-4.046 0.109-3.905 0.767z"/> + <path fill="#414141" d="m272.364 247.917c0.2 1.195 4.052 0.965 7.522 1.961 3.708 1.098 5.037 1.477 7.72 4.119 2.383 2.479 0.46 3.315 2.012 3.562 1.348 0.081 2.236-0.87 2.025-2.545-0.251-2.022-2.325-3.707-6.778-5.331-3.377-1.237-5.681-2.195-8.631-2.518-2.485-0.233-4.02 0.05-3.87 0.752z"/> + <path fill="#444" d="m272.49 247.956c0.212 1.129 4.015 0.838 7.426 1.855 3.668 1.124 4.869 1.475 7.696 4 2.51 2.359 0.542 3.055 2.067 3.336 1.173 0.133 2.02-0.6 1.801-2.246-0.266-2.016-2.276-3.568-6.656-5.16-3.329-1.218-5.591-2.189-8.499-2.521-2.343-0.235-3.994-0.007-3.835 0.736z"/> + <path fill="#484848" d="m272.616 247.993c0.223 1.065 3.979 0.715 7.331 1.752 3.628 1.15 4.699 1.473 7.671 3.883 2.638 2.238 0.624 2.791 2.122 3.108 0.998 0.185 1.804-0.329 1.577-1.946-0.28-2.008-2.227-3.432-6.534-4.992-3.282-1.196-5.501-2.182-8.367-2.525-2.201-0.235-3.968-0.064-3.8 0.72z"/> + <path fill="#4c4c4c" d="m272.742 248.032c0.235 1 3.941 0.588 7.235 1.645 3.588 1.178 4.529 1.472 7.646 3.766 2.766 2.118 0.706 2.529 2.177 2.883 0.823 0.235 1.589-0.059 1.354-1.648-0.295-1.998-2.177-3.293-6.412-4.822-3.235-1.176-5.412-2.176-8.235-2.529-2.059-0.239-3.942-0.119-3.765 0.705z"/> + </g> + <g transform="translate(-12.4048,10.0005)"> + <path fill="#4c4c4c" d="m287.565 252.854c1.646 1 1.353 2.059 2.412 2.766 0.528 0.352 1.412 0.352 0.882-1-0.706-1.588-1.294-2.472-4.941-3.943-2.353-0.941-1.882 0.059 1.647 2.177z"/> + <path fill="#505050" d="m287.609 252.868c1.605 0.975 1.32 2.008 2.353 2.696 0.517 0.343 1.377 0.343 0.86-0.976-0.689-1.549-1.262-2.41-4.82-3.846-2.295-0.917-1.836 0.059 1.607 2.126z"/> + <path fill="#545454" d="m287.652 252.879c1.567 0.951 1.287 1.957 2.294 2.629 0.503 0.334 1.343 0.334 0.839-0.951-0.671-1.51-1.23-2.35-4.699-3.749-2.238-0.893-1.79 0.058 1.566 2.071z"/> + <path fill="#575757" d="m287.696 252.891c1.526 0.926 1.254 1.908 2.235 2.563 0.489 0.325 1.308 0.325 0.816-0.928-0.653-1.471-1.199-2.289-4.578-3.652-2.179-0.872-1.743 0.055 1.527 2.017z"/> + <path fill="#5b5b5b" d="m287.74 252.903c1.485 0.902 1.22 1.857 2.175 2.494 0.479 0.318 1.274 0.318 0.796-0.902-0.637-1.432-1.167-2.229-4.457-3.556-2.122-0.849-1.697 0.054 1.486 1.964z"/> + <path fill="#5f5f5f" d="m287.783 252.915c1.446 0.879 1.188 1.808 2.117 2.426 0.464 0.31 1.239 0.31 0.773-0.877-0.619-1.394-1.136-2.168-4.336-3.459-2.064-0.826-1.65 0.052 1.446 1.91z"/> + <path fill="#636363" d="m287.827 252.926c1.405 0.854 1.154 1.758 2.057 2.359 0.452 0.301 1.205 0.301 0.754-0.853-0.603-1.354-1.104-2.108-4.216-3.363-2.007-0.801-1.605 0.053 1.405 1.857z"/> + <path fill="#676767" d="m287.871 252.94c1.364 0.828 1.121 1.705 1.998 2.29 0.438 0.292 1.17 0.292 0.731-0.828-0.585-1.315-1.072-2.047-4.095-3.267-1.948-0.779-1.558 0.05 1.366 1.805z"/> + <path fill="#6b6b6b" d="m287.914 252.952c1.325 0.805 1.088 1.655 1.94 2.223 0.425 0.283 1.135 0.283 0.709-0.803-0.568-1.277-1.041-1.988-3.974-3.17-1.891-0.757-1.512 0.047 1.325 1.75z"/> + <path fill="#6e6e6e" d="m287.958 252.963c1.284 0.779 1.056 1.605 1.88 2.156 0.413 0.274 1.102 0.274 0.688-0.779-0.551-1.238-1.009-1.926-3.853-3.073-1.833-0.733-1.466 0.046 1.285 1.696z"/> + <path fill="#727272" d="m288.002 252.976c1.243 0.755 1.021 1.554 1.821 2.087 0.399 0.266 1.066 0.266 0.666-0.755-0.533-1.199-0.977-1.865-3.731-2.976-1.776-0.71-1.421 0.045 1.244 1.644z"/> + <path fill="#767676" d="m288.045 252.989c1.203 0.73 0.989 1.504 1.763 2.02 0.387 0.257 1.031 0.257 0.645-0.731-0.516-1.159-0.946-1.805-3.61-2.879-1.72-0.688-1.376 0.042 1.202 1.59z"/> + <path fill="#7a7a7a" d="m288.089 253c1.163 0.705 0.955 1.453 1.703 1.951 0.373 0.25 0.997 0.25 0.623-0.705-0.499-1.121-0.914-1.744-3.489-2.783-1.661-0.664-1.329 0.041 1.163 1.537z"/> + <path fill="#7e7e7e" d="m288.133 253.012c1.122 0.682 0.923 1.404 1.644 1.885 0.361 0.24 0.962 0.24 0.602-0.682-0.481-1.082-0.882-1.684-3.367-2.687-1.605-0.64-1.285 0.041 1.121 1.484z"/> + <path fill="#828282" d="m288.176 253.025c1.082 0.657 0.89 1.353 1.586 1.815 0.348 0.232 0.927 0.232 0.578-0.656-0.463-1.043-0.85-1.623-3.245-2.59-1.547-0.618-1.237 0.039 1.081 1.431z"/> + <path fill="#858585" d="m288.22 253.038c1.042 0.631 0.855 1.301 1.524 1.748 0.335 0.223 0.894 0.223 0.559-0.633-0.446-1.005-0.818-1.563-3.125-2.492-1.488-0.596-1.19 0.037 1.042 1.377z"/> + <path fill="#898989" d="m288.264 253.049c1.001 0.607 0.821 1.252 1.466 1.681 0.322 0.214 0.857 0.214 0.536-0.608-0.43-0.965-0.786-1.502-3.004-2.396-1.43-0.573-1.144 0.034 1.002 1.323z"/> + <path fill="#8d8d8d" d="m288.307 253.061c0.961 0.584 0.79 1.201 1.407 1.613 0.309 0.205 0.823 0.205 0.515-0.584-0.412-0.926-0.755-1.441-2.883-2.299-1.373-0.548-1.098 0.034 0.961 1.27z"/> + <path fill="#919191" d="m288.351 253.073c0.921 0.559 0.756 1.151 1.348 1.547 0.296 0.196 0.789 0.196 0.493-0.56-0.395-0.888-0.723-1.381-2.762-2.204-1.315-0.525-1.052 0.033 0.921 1.217z"/> + <path fill="#959595" d="m288.395 253.084c0.88 0.535 0.723 1.102 1.289 1.479 0.282 0.189 0.754 0.189 0.471-0.534-0.377-0.849-0.691-1.321-2.641-2.106-1.257-0.505-1.006 0.031 0.881 1.161z"/> + <path fill="#999" d="m288.438 253.097c0.84 0.51 0.689 1.05 1.229 1.409 0.271 0.181 0.721 0.181 0.45-0.51-0.36-0.81-0.66-1.26-2.52-2.01-1.199-0.48-0.959 0.031 0.841 1.111z"/> + </g> + <g transform="translate(-12.4048,10.0005)"> + <path d="m222.275 107.427c-0.738 0.902 0.574 8.365 5.412 13.285 4.839 4.838 7.791 4.838 9.759 2.706 3.771-4.018 0.738-7.791-1.558-10.415-2.297-2.624-5.248-1.722-7.955-4.346-2.706-2.624-4.592-2.46-5.658-1.23z"/> + <path fill="#050505" d="m222.345 107.494c-0.732 0.895 0.569 8.3 5.369 13.182 4.803 4.801 7.731 4.801 9.685 2.685 3.742-3.987 0.731-7.73-1.546-10.334-2.278-2.604-5.208-1.709-7.894-4.312-2.684-2.604-4.556-2.441-5.614-1.221z"/> + <path fill="#0a0a0a" d="m222.416 107.561c-0.727 0.888 0.565 8.235 5.328 13.079 4.763 4.763 7.67 4.763 9.607 2.664 3.713-3.956 0.727-7.67-1.534-10.253-2.26-2.584-5.166-1.696-7.831-4.279-2.664-2.583-4.521-2.422-5.57-1.211z"/> + <path fill="#0f0f0f" d="m222.486 107.628c-0.721 0.881 0.561 8.17 5.286 12.976 4.726 4.725 7.608 4.725 9.532 2.642 3.684-3.924 0.72-7.609-1.522-10.172-2.243-2.563-5.126-1.682-7.77-4.244-2.643-2.563-4.485-2.403-5.526-1.202z"/> + <path fill="#141414" d="m222.556 107.695c-0.716 0.874 0.557 8.105 5.243 12.872 4.689 4.688 7.55 4.688 9.456 2.622 3.655-3.893 0.716-7.549-1.51-10.091-2.224-2.543-5.085-1.669-7.707-4.211-2.621-2.543-4.449-2.384-5.482-1.192z"/> + <path fill="#191919" d="m222.627 107.762c-0.71 0.867 0.552 8.04 5.202 12.769 4.65 4.65 7.488 4.65 9.379 2.601 3.626-3.862 0.71-7.489-1.497-10.011s-5.044-1.655-7.646-4.177-4.414-2.364-5.438-1.182z"/> + <path fill="#1e1e1e" d="m222.697 107.829c-0.704 0.86 0.547 7.975 5.16 12.666 4.613 4.612 7.428 4.612 9.304 2.579 3.596-3.83 0.703-7.427-1.486-9.929-2.188-2.502-5.003-1.642-7.584-4.143-2.579-2.502-4.378-2.346-5.394-1.173z"/> + <path fill="#232323" d="m222.767 107.896c-0.697 0.853 0.543 7.91 5.117 12.562 4.576 4.575 7.367 4.575 9.229 2.559 3.567-3.8 0.698-7.367-1.473-9.848-2.171-2.482-4.963-1.629-7.522-4.11s-4.343-2.326-5.351-1.163z"/> + <path fill="#282828" d="m222.838 107.963c-0.691 0.846 0.538 7.845 5.076 12.459 4.537 4.537 7.307 4.537 9.152 2.538 3.537-3.769 0.691-7.307-1.461-9.768-2.154-2.461-4.922-1.615-7.461-4.076-2.538-2.461-4.307-2.307-5.306-1.153z"/> + <path fill="#2d2d2d" d="m222.908 108.03c-0.686 0.839 0.534 7.78 5.034 12.355 4.5 4.499 7.246 4.499 9.076 2.516 3.509-3.737 0.686-7.246-1.449-9.686-2.135-2.441-4.881-1.602-7.399-4.042-2.516-2.44-4.271-2.287-5.262-1.143z"/> + <path fill="#333" d="m222.978 108.096c-0.681 0.832 0.529 7.715 4.992 12.253 4.463 4.462 7.186 4.462 9.001 2.496 3.479-3.706 0.68-7.186-1.438-9.605-2.118-2.42-4.841-1.588-7.337-4.008s-4.235-2.27-5.218-1.136z"/> + <path fill="#383838" d="m223.048 108.163c-0.674 0.825 0.526 7.65 4.95 12.15 4.425 4.425 7.125 4.425 8.925 2.475 3.45-3.675 0.676-7.125-1.425-9.525-2.099-2.4-4.8-1.575-7.274-3.975-2.475-2.399-4.201-2.25-5.176-1.125z"/> + <path fill="#3d3d3d" d="m223.119 108.23c-0.669 0.818 0.521 7.585 4.908 12.047 4.387 4.387 7.063 4.387 8.849 2.453 3.42-3.643 0.669-7.064-1.413-9.443-2.082-2.38-4.759-1.562-7.214-3.941-2.453-2.38-4.164-2.231-5.13-1.116z"/> + <path fill="#424242" d="m223.189 108.297c-0.663 0.811 0.516 7.52 4.866 11.944 4.35 4.349 7.004 4.349 8.772 2.432 3.392-3.612 0.663-7.004-1.4-9.363-2.064-2.359-4.719-1.548-7.151-3.907-2.433-2.359-4.129-2.212-5.087-1.106z"/> + <path fill="#474747" d="m223.259 108.364c-0.656 0.804 0.513 7.455 4.824 11.84 4.313 4.312 6.944 4.312 8.697 2.412 3.362-3.582 0.658-6.944-1.388-9.282-2.046-2.339-4.679-1.535-7.09-3.874-2.411-2.338-4.093-2.192-5.043-1.096z"/> + <path fill="#4c4c4c" d="m223.33 108.431c-0.651 0.797 0.507 7.39 4.782 11.737 4.274 4.274 6.882 4.274 8.621 2.39 3.332-3.55 0.651-6.883-1.377-9.201s-4.636-1.521-7.028-3.839c-2.39-2.318-4.057-2.174-4.998-1.087z"/> + <path fill="#515151" d="m223.4 108.498c-0.646 0.79 0.503 7.325 4.74 11.634 4.236 4.236 6.821 4.236 8.545 2.369 3.304-3.519 0.646-6.822-1.364-9.12s-4.596-1.508-6.966-3.806c-2.369-2.298-4.022-2.154-4.955-1.077z"/> + <path fill="#565656" d="m223.47 108.565c-0.641 0.783 0.499 7.26 4.697 11.53 4.199 4.199 6.763 4.199 8.471 2.349 3.273-3.488 0.64-6.762-1.353-9.039-1.993-2.278-4.556-1.495-6.905-3.773-2.347-2.277-3.985-2.135-4.91-1.067z"/> + <path fill="#5b5b5b" d="m223.541 108.632c-0.635 0.776 0.493 7.195 4.656 11.427 4.161 4.161 6.701 4.161 8.393 2.327 3.245-3.456 0.636-6.701-1.34-8.958-1.975-2.257-4.514-1.48-6.843-3.738-2.327-2.257-3.95-2.116-4.866-1.058z"/> + <path fill="#606060" d="m223.611 108.699c-0.629 0.769 0.489 7.13 4.614 11.324 4.124 4.123 6.64 4.123 8.317 2.306 3.215-3.425 0.628-6.641-1.328-8.877-1.957-2.237-4.474-1.468-6.78-3.705-2.306-2.236-3.915-2.097-4.823-1.048z"/> + <path fill="#666" d="m223.681 108.765c-0.623 0.762 0.484 7.065 4.571 11.221 4.086 4.086 6.58 4.086 8.242 2.285 3.187-3.394 0.623-6.58-1.315-8.796-1.939-2.217-4.434-1.455-6.72-3.671-2.284-2.216-3.878-2.078-4.778-1.039z"/> + </g> + <g transform="translate(-12.4048,10.0005)"> + <path fill="#fc0" d="m137.79 109.277c1.978 1.366 2.031 1.607 4.948 3.514 4.64 3.768 12.885 4.616 16.922 4.75 9.233 1.467 25.738-7.161 32.273-11.111 3.291-2.463 9.38-7.551 11.659-7.637 1.405 1.485-0.66 1.792-3.587 3.775-3.906 2.779-7.25 5.156-13.172 8.515-6.338 3.316-16.078 8.794-28.548 8.054-6.542-0.959-6.566-1.024-10.606-3.086-2.4-1.732-7.901-4.608-9.889-6.774z"/> + <linearGradient id="al" x1="129.342" gradientUnits="userSpaceOnUse" x2="195.598" gradientTransform="matrix(1,0,0,-1,8.3999,368.3)" y1="259.305" y2="259.305"> + <stop stop-color="#FAC700" offset="0"/> + <stop stop-color="#F7C400" offset=".415"/> + <stop stop-color="#F7C400" offset="1"/> + </linearGradient> + <path fill="url(#al)" d="m137.742 109.259c1.926 1.274 2.165 1.643 5.083 3.554 4.616 3.734 12.716 4.616 16.796 4.763 9.365 1.452 26.05-7.294 32.356-11.159 3.357-2.506 9.344-7.498 11.595-7.604 1.365 1.472-0.728 1.768-3.688 3.814-3.889 2.753-7.119 5.065-12.972 8.383-6.29 3.291-16.078 8.795-28.536 8.104-6.561-0.945-6.851-1.07-10.758-3.079-2.468-1.755-7.876-4.587-9.876-6.776z"/> + <linearGradient id="am" x1="129.293" gradientUnits="userSpaceOnUse" x2="195.554" gradientTransform="matrix(1,0,0,-1,8.3999,368.3)" y1="259.311" y2="259.311"> + <stop stop-color="#F6C200" offset="0"/> + <stop stop-color="#EFBC00" offset=".415"/> + <stop stop-color="#EFBC00" offset="1"/> + </linearGradient> + <path fill="url(#am)" d="m137.693 109.24c1.876 1.183 2.3 1.68 5.218 3.595 4.593 3.7 12.548 4.616 16.67 4.776 9.498 1.437 26.364-7.428 32.44-11.207 3.425-2.55 9.308-7.444 11.528-7.57 1.326 1.457-0.795 1.743-3.788 3.854-3.87 2.725-6.99 4.973-12.771 8.25-6.243 3.266-16.078 8.796-28.525 8.154-6.579-0.931-7.134-1.117-10.908-3.073-2.536-1.779-7.852-4.567-9.864-6.779z"/> + <linearGradient id="an" x1="129.245" gradientUnits="userSpaceOnUse" x2="195.51" gradientTransform="matrix(1,0,0,-1,8.3999,368.3)" y1="259.317" y2="259.317"> + <stop stop-color="#F1BD00" offset="0"/> + <stop stop-color="#E8B500" offset=".415"/> + <stop stop-color="#E8B500" offset="1"/> + </linearGradient> + <path fill="url(#an)" d="m137.645 109.222c1.825 1.091 2.434 1.715 5.352 3.635 4.569 3.665 12.38 4.615 16.544 4.789 9.631 1.422 26.677-7.562 32.524-11.255 3.491-2.594 9.271-7.392 11.463-7.538 1.287 1.442-0.861 1.718-3.889 3.893-3.853 2.699-6.86 4.882-12.57 8.119-6.195 3.241-16.078 8.797-28.513 8.203-6.6-0.916-7.418-1.163-11.061-3.066-2.603-1.801-7.826-4.546-9.85-6.78z"/> + <linearGradient id="ao" x1="129.196" gradientUnits="userSpaceOnUse" x2="195.465" gradientTransform="matrix(1,0,0,-1,8.3999,368.3)" y1="259.322" y2="259.322"> + <stop stop-color="#EDB800" offset="0"/> + <stop stop-color="#E0AD00" offset=".415"/> + <stop stop-color="#E0AD00" offset="1"/> + </linearGradient> + <path fill="url(#ao)" d="m137.596 109.203c1.774 1 2.568 1.752 5.487 3.676 4.545 3.631 12.211 4.615 16.418 4.801 9.764 1.408 26.989-7.695 32.608-11.302 3.557-2.637 9.236-7.338 11.396-7.505 1.247 1.427-0.928 1.693-3.99 3.932-3.833 2.672-6.729 4.791-12.369 7.986-6.148 3.217-16.078 8.799-28.501 8.254-6.619-0.902-7.702-1.21-11.21-3.059-2.672-1.825-7.803-4.525-9.839-6.783z"/> + <linearGradient id="ap" x1="129.148" gradientUnits="userSpaceOnUse" x2="195.422" gradientTransform="matrix(1,0,0,-1,8.3999,368.3)" y1="259.327" y2="259.327"> + <stop stop-color="#E9B300" offset="0"/> + <stop stop-color="#D8A500" offset=".415"/> + <stop stop-color="#D8A500" offset="1"/> + </linearGradient> + <path fill="url(#ap)" d="m137.548 109.184c1.724 0.909 2.703 1.788 5.622 3.717 4.522 3.597 12.043 4.615 16.292 4.814 9.896 1.393 27.303-7.829 32.692-11.35 3.624-2.681 9.2-7.286 11.331-7.472 1.208 1.412-0.995 1.668-4.092 3.972-3.814 2.644-6.6 4.698-12.168 7.853-6.101 3.192-16.077 8.8-28.489 8.303-6.638-0.887-7.986-1.256-11.361-3.052-2.741-1.848-7.779-4.504-9.827-6.785z"/> + <linearGradient id="aq" x1="129.099" gradientUnits="userSpaceOnUse" x2="195.379" gradientTransform="matrix(1,0,0,-1,8.3999,368.3)" y1="259.332" y2="259.332"> + <stop stop-color="#E4AE00" offset="0"/> + <stop stop-color="#D19E00" offset=".415"/> + <stop stop-color="#D19E00" offset="1"/> + </linearGradient> + <path fill="url(#aq)" d="m137.499 109.166c1.673 0.817 2.838 1.824 5.757 3.757 4.499 3.562 11.875 4.614 16.166 4.827 10.029 1.378 27.615-7.963 32.776-11.398 3.691-2.725 9.164-7.232 11.265-7.439 1.169 1.397-1.061 1.644-4.191 4.01-3.796 2.618-6.469 4.608-11.968 7.722-6.053 3.167-16.077 8.801-28.478 8.353-6.657-0.873-8.27-1.303-11.512-3.046-2.809-1.87-7.755-4.483-9.815-6.786z"/> + <linearGradient id="ar" x1="129.051" gradientUnits="userSpaceOnUse" x2="195.338" gradientTransform="matrix(1,0,0,-1,8.3999,368.3)" y1="259.336" y2="259.336"> + <stop stop-color="#E0A900" offset="0"/> + <stop stop-color="#C99600" offset=".415"/> + <stop stop-color="#C99600" offset="1"/> + </linearGradient> + <path fill="url(#ar)" d="m137.451 109.147c1.622 0.726 2.972 1.86 5.892 3.798 4.475 3.528 11.705 4.614 16.04 4.84 10.161 1.362 27.929-8.097 32.859-11.447 3.757-2.767 9.128-7.178 11.2-7.405 1.13 1.382-1.128 1.619-4.294 4.049-3.777 2.592-6.339 4.517-11.767 7.589-6.005 3.143-16.077 8.803-28.466 8.404-6.676-0.859-8.553-1.35-11.663-3.039-2.876-1.894-7.729-4.462-9.801-6.789z"/> + <linearGradient id="w" x1="129.003" gradientUnits="userSpaceOnUse" x2="195.296" gradientTransform="matrix(1,0,0,-1,8.3999,368.3)" y1="259.34" y2="259.34"> + <stop stop-color="#DCA400" offset="0"/> + <stop stop-color="#C18E00" offset=".415"/> + <stop stop-color="#C18E00" offset="1"/> + </linearGradient> + <path fill="url(#w)" d="m137.403 109.129c1.571 0.634 3.105 1.896 6.026 3.838 4.45 3.494 11.536 4.614 15.913 4.852 10.295 1.348 28.241-8.23 32.943-11.494 3.824-2.811 9.092-7.125 11.134-7.373 1.092 1.367-1.194 1.594-4.394 4.088-3.759 2.565-6.209 4.425-11.566 7.457-5.957 3.118-16.077 8.804-28.454 8.453-6.694-0.844-8.837-1.396-11.813-3.032-2.945-1.916-7.706-4.44-9.789-6.789z"/> + <linearGradient id="x" x1="128.954" gradientUnits="userSpaceOnUse" x2="195.255" gradientTransform="matrix(1,0,0,-1,8.3999,368.3)" y1="259.343" y2="259.343"> + <stop stop-color="#D79F00" offset="0"/> + <stop stop-color="#BA8700" offset=".415"/> + <stop stop-color="#BA8700" offset="1"/> + </linearGradient> + <path fill="url(#x)" d="m137.354 109.11c1.521 0.543 3.241 1.932 6.161 3.879 4.428 3.459 11.368 4.613 15.788 4.865 10.427 1.333 28.554-8.364 33.026-11.542 3.892-2.855 9.057-7.073 11.068-7.339 1.052 1.353-1.261 1.569-4.495 4.127-3.74 2.538-6.078 4.334-11.365 7.325-5.91 3.093-16.077 8.805-28.441 8.503-6.716-0.83-9.121-1.443-11.966-3.026-3.012-1.939-7.68-4.42-9.776-6.792z"/> + <linearGradient id="y" x1="128.906" gradientUnits="userSpaceOnUse" x2="195.216" gradientTransform="matrix(1,0,0,-1,8.3999,368.3)" y1="259.348" y2="259.348"> + <stop stop-color="#D39B00" offset="0"/> + <stop stop-color="#B27F00" offset=".415"/> + <stop stop-color="#B27F00" offset="1"/> + </linearGradient> + <path fill="url(#y)" d="m137.306 109.091c1.47 0.451 3.375 1.969 6.296 3.919 4.403 3.426 11.2 4.614 15.662 4.879 10.559 1.318 28.865-8.498 33.109-11.59 3.958-2.899 9.021-7.02 11.003-7.306 1.013 1.337-1.328 1.544-4.596 4.167-3.722 2.511-5.949 4.242-11.165 7.192-5.862 3.068-16.077 8.807-28.43 8.553-6.734-0.816-9.405-1.489-12.116-3.019-3.08-1.963-7.656-4.4-9.763-6.795z"/> + <linearGradient id="z" x1="128.857" gradientUnits="userSpaceOnUse" x2="195.176" gradientTransform="matrix(1,0,0,-1,8.3999,368.3)" y1="259.35" y2="259.35"> + <stop stop-color="#CF9600" offset="0"/> + <stop stop-color="#a70" offset=".415"/> + <stop stop-color="#a70" offset="1"/> + </linearGradient> + <path fill="url(#z)" d="m137.257 109.073c1.421 0.359 3.511 2.005 6.432 3.959 4.38 3.392 11.032 4.614 15.536 4.892 10.691 1.303 29.179-8.631 33.193-11.638 4.024-2.942 8.984-6.967 10.938-7.274 0.973 1.323-1.396 1.521-4.697 4.206-3.703 2.484-5.818 4.151-10.964 7.06-5.814 3.043-16.077 8.808-28.418 8.603-6.753-0.802-9.689-1.535-12.268-3.012-3.149-1.986-7.632-4.378-9.752-6.796z"/> + <linearGradient id="aa" x1="128.809" gradientUnits="userSpaceOnUse" x2="195.137" gradientTransform="matrix(1,0,0,-1,8.3999,368.3)" y1="259.354" y2="259.354"> + <stop stop-color="#CA9100" offset="0"/> + <stop stop-color="#A37000" offset=".415"/> + <stop stop-color="#A37000" offset="1"/> + </linearGradient> + <path fill="url(#aa)" d="m137.209 109.054c1.368 0.268 3.645 2.041 6.565 4 4.356 3.357 10.864 4.613 15.41 4.904 10.824 1.289 29.493-8.764 33.277-11.685 4.092-2.986 8.948-6.914 10.871-7.241 0.935 1.308-1.461 1.496-4.797 4.245-3.685 2.457-5.688 4.06-10.763 6.928-5.768 3.018-16.077 8.809-28.407 8.653-6.771-0.788-9.972-1.582-12.418-3.006-3.216-2.008-7.607-4.357-9.738-6.798z"/> + <linearGradient id="ab" x1="128.76" gradientUnits="userSpaceOnUse" x2="195.099" gradientTransform="matrix(1,0,0,-1,8.3999,368.3)" y1="259.356" y2="259.356"> + <stop stop-color="#C68C00" offset="0"/> + <stop stop-color="#9B6800" offset=".415"/> + <stop stop-color="#9B6800" offset="1"/> + </linearGradient> + <path fill="url(#ab)" d="m137.16 109.036c1.318 0.176 3.779 2.077 6.701 4.04 4.333 3.323 10.695 4.613 15.284 4.917 10.957 1.274 29.805-8.898 33.36-11.733 4.158-3.03 8.912-6.86 10.807-7.208 0.894 1.292-1.528 1.471-4.899 4.284-3.666 2.43-5.558 3.968-10.562 6.796-5.72 2.993-16.077 8.81-28.396 8.702-6.791-0.773-10.256-1.628-12.568-2.999-3.285-2.031-7.583-4.336-9.727-6.799z"/> + <linearGradient id="ac" x1="128.712" gradientUnits="userSpaceOnUse" x2="195.062" gradientTransform="matrix(1,0,0,-1,8.3999,368.3)" y1="259.358" y2="259.358"> + <stop stop-color="#C28700" offset="0"/> + <stop stop-color="#936000" offset=".415"/> + <stop stop-color="#936000" offset="1"/> + </linearGradient> + <path fill="url(#ac)" d="m137.112 109.017c1.267 0.085 3.912 2.113 6.835 4.081 4.31 3.289 10.527 4.613 15.158 4.93 11.09 1.258 30.118-9.032 33.445-11.782 4.225-3.072 8.877-6.807 10.739-7.174 0.855 1.278-1.595 1.446-5 4.323-3.647 2.404-5.427 3.877-10.36 6.663-5.673 2.969-16.077 8.812-28.384 8.753-6.811-0.759-10.54-1.675-12.719-2.992-3.353-2.055-7.559-4.315-9.714-6.802z"/> + <linearGradient id="ad" x1="128.663" gradientUnits="userSpaceOnUse" x2="195.025" gradientTransform="matrix(1,0,0,-1,8.3999,368.3)" y1="259.36" y2="259.36"> + <stop stop-color="#BD8200" offset="0"/> + <stop stop-color="#8C5900" offset=".415"/> + <stop stop-color="#8C5900" offset="1"/> + </linearGradient> + <path fill="url(#ad)" d="m137.063 108.998c1.217-0.006 4.047 2.15 6.97 4.122 4.286 3.254 10.359 4.612 15.032 4.943 11.223 1.243 30.431-9.166 33.53-11.83 4.289-3.116 8.84-6.753 10.673-7.141 0.815 1.263-1.661 1.421-5.101 4.362-3.63 2.377-5.298 3.785-10.161 6.531-5.624 2.944-16.075 8.813-28.37 8.802-6.83-0.744-10.824-1.721-12.87-2.985-3.422-2.077-7.535-4.294-9.703-6.804z"/> + <linearGradient id="ae" x1="128.615" gradientUnits="userSpaceOnUse" x2="194.989" gradientTransform="matrix(1,0,0,-1,8.3999,368.3)" y1="259.362" y2="259.362"> + <stop stop-color="#B97D00" offset="0"/> + <stop stop-color="#845100" offset=".415"/> + <stop stop-color="#845100" offset="1"/> + </linearGradient> + <path fill="url(#ae)" d="m137.015 108.98c1.166-0.098 4.181 2.185 7.104 4.162 4.262 3.22 10.19 4.612 14.906 4.955 11.354 1.229 30.743-9.299 33.613-11.877 4.356-3.16 8.804-6.7 10.607-7.108 0.776 1.248-1.728 1.397-5.202 4.401-3.61 2.35-5.167 3.694-9.96 6.399-5.576 2.919-16.076 8.814-28.358 8.852-6.85-0.73-11.108-1.768-13.021-2.979-3.489-2.1-7.51-4.273-9.689-6.805z"/> + <linearGradient id="af" x1="128.567" gradientUnits="userSpaceOnUse" x2="194.954" gradientTransform="matrix(1,0,0,-1,8.3999,368.3)" y1="259.364" y2="259.364"> + <stop stop-color="#B57800" offset="0"/> + <stop stop-color="#7C4900" offset=".415"/> + <stop stop-color="#7C4900" offset="1"/> + </linearGradient> + <path fill="url(#af)" d="m136.967 108.961c1.115-0.189 4.315 2.222 7.239 4.203 4.239 3.186 10.021 4.612 14.78 4.968 11.488 1.214 31.057-9.433 33.697-11.925 4.424-3.203 8.768-6.647 10.542-7.075 0.736 1.233-1.795 1.372-5.303 4.44-3.593 2.323-5.038 3.603-9.759 6.266-5.529 2.895-16.077 8.816-28.348 8.903-6.868-0.716-11.392-1.815-13.172-2.972-3.557-2.124-7.485-4.252-9.676-6.808z"/> + <linearGradient id="ah" x1="128.518" gradientUnits="userSpaceOnUse" x2="194.918" gradientTransform="matrix(1,0,0,-1,8.3999,368.3)" y1="259.366" y2="259.366"> + <stop stop-color="#B07300" offset="0"/> + <stop stop-color="#754200" offset=".415"/> + <stop stop-color="#754200" offset="1"/> + </linearGradient> + <path fill="url(#ah)" d="m136.918 108.943c1.064-0.281 4.45 2.257 7.374 4.243 4.216 3.151 9.854 4.611 14.654 4.981 11.621 1.199 31.37-9.567 33.781-11.973 4.49-3.247 8.731-6.594 10.476-7.042 0.698 1.218-1.861 1.347-5.403 4.479-3.573 2.296-4.906 3.511-9.558 6.134-5.48 2.87-16.076 8.817-28.336 8.952-6.887-0.701-11.675-1.861-13.323-2.965-3.626-2.146-7.462-4.231-9.665-6.809z"/> + <linearGradient id="ai" x1="128.47" gradientUnits="userSpaceOnUse" x2="194.886" gradientTransform="matrix(1,0,0,-1,8.3999,368.3)" y1="259.367" y2="259.367"> + <stop stop-color="#AC6E00" offset="0"/> + <stop stop-color="#6D3A00" offset=".415"/> + <stop stop-color="#6D3A00" offset="1"/> + </linearGradient> + <path fill="url(#ai)" d="m136.87 108.924c1.013-0.372 4.584 2.294 7.509 4.284 4.191 3.117 9.685 4.611 14.528 4.994 11.753 1.184 31.682-9.701 33.864-12.021 4.557-3.291 8.695-6.542 10.411-7.009 0.657 1.203-1.929 1.322-5.504 4.518-3.557 2.269-4.777 3.42-9.358 6.002-5.434 2.845-16.076 8.818-28.324 9.002-6.907-0.687-11.959-1.908-13.474-2.959-3.694-2.169-7.437-4.21-9.652-6.811z"/> + <linearGradient id="aj" x1="128.421" gradientUnits="userSpaceOnUse" x2="194.85" gradientTransform="matrix(1,0,0,-1,8.3999,368.3)" y1="259.369" y2="259.369"> + <stop stop-color="#A86A00" offset="0"/> + <stop stop-color="#663200" offset=".415"/> + <stop stop-color="#663200" offset="1"/> + </linearGradient> + <path fill="url(#aj)" d="m136.821 108.905c0.963-0.464 4.719 2.33 7.644 4.324 4.168 3.083 9.517 4.611 14.402 5.007 11.886 1.169 31.995-9.834 33.948-12.069 4.624-3.334 8.66-6.487 10.345-6.976 0.619 1.188-1.995 1.298-5.604 4.558-3.537 2.242-4.647 3.328-9.157 5.869-5.386 2.82-16.076 8.82-28.313 9.052-6.926-0.673-12.243-1.954-13.625-2.952-3.762-2.192-7.413-4.189-9.64-6.813z"/> + </g> + </g> +</svg> diff --git a/tests/phpunit/data/resourceloader/add.gif b/tests/phpunit/data/resourceloader/add.gif Binary files differnew file mode 100644 index 00000000..5f454ca1 --- /dev/null +++ b/tests/phpunit/data/resourceloader/add.gif diff --git a/tests/phpunit/data/resourceloader/bold-a.svg b/tests/phpunit/data/resourceloader/bold-a.svg new file mode 100644 index 00000000..4b828779 --- /dev/null +++ b/tests/phpunit/data/resourceloader/bold-a.svg @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"> + <g id="bold-a"> + <path d="M16 18h3l-5-12h-3l-5 12h3l1.25-3h4.5l1.25 3zm-4.917-5l1.417-3.4 1.417 3.4h-2.834z"/> + </g> +</svg> diff --git a/tests/phpunit/data/resourceloader/bold-b.svg b/tests/phpunit/data/resourceloader/bold-b.svg new file mode 100644 index 00000000..4f648203 --- /dev/null +++ b/tests/phpunit/data/resourceloader/bold-b.svg @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"> + <g id="bold-b"> + <path id="b" d="M7 18h6c2 0 4-1 4-3 0-1.064.011-1.975-1.989-3 2-.975 1.989-1.935 1.989-3 0-2-2-3-4-3h-6v12zm7-8c0 1.001 0 1-2 1h-2v-3h2c2 0 2 0 2 1v1zm-2 6h-2v-3h2c2 0 2 0 2 1v1s0 1-2 1z"/> + </g> +</svg> diff --git a/tests/phpunit/data/resourceloader/bold-f.svg b/tests/phpunit/data/resourceloader/bold-f.svg new file mode 100644 index 00000000..357d2e5d --- /dev/null +++ b/tests/phpunit/data/resourceloader/bold-f.svg @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"> + <g id="bold-f"> + <path id="f" d="M16 8v-2h-8v12h3v-5h4v-2h-4v-3z"/> + </g> +</svg> diff --git a/tests/phpunit/data/resourceloader/help-ltr.svg b/tests/phpunit/data/resourceloader/help-ltr.svg new file mode 100644 index 00000000..bb2545c5 --- /dev/null +++ b/tests/phpunit/data/resourceloader/help-ltr.svg @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?> +<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"> + <g id="help"> + <path id="circle" d="M12.001 2.085c-5.478 0-9.916 4.438-9.916 9.916 0 5.476 4.438 9.914 9.916 9.914 5.476 0 9.914-4.438 9.914-9.914 0-5.478-4.438-9.916-9.914-9.916zm.001 18c-4.465 0-8.084-3.619-8.084-8.083 0-4.465 3.619-8.084 8.084-8.084 4.464 0 8.083 3.619 8.083 8.084 0 4.464-3.619 8.083-8.083 8.083z"/> + <g id="question-mark"> + <path id="top" d="M11.766 6.688c-2.5 0-3.219 2.188-3.219 2.188l1.411.854s.298-.791.901-1.229c.516-.375 1.625-.625 2.219.125.701.885-.17 1.587-1.078 2.719-.953 1.186-1 3.655-1 3.655h1.969s.135-2.318 1.041-3.381c.603-.707 1.443-1.338 1.443-2.494s-1.187-2.437-3.687-2.437z"/> + <path id="bottom" d="M11 16h2v2h-2z"/> + </g> + </g> +</svg> diff --git a/tests/phpunit/data/resourceloader/help-rtl.svg b/tests/phpunit/data/resourceloader/help-rtl.svg new file mode 100644 index 00000000..255ae95b --- /dev/null +++ b/tests/phpunit/data/resourceloader/help-rtl.svg @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?> +<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"> + <g id="help"> + <path id="circle" d="M12.001 2.085c-5.478 0-9.916 4.438-9.916 9.916 0 5.476 4.438 9.914 9.916 9.914 5.476 0 9.914-4.438 9.914-9.914 0-5.478-4.438-9.916-9.914-9.916zm.001 18c-4.465 0-8.084-3.619-8.084-8.083 0-4.465 3.619-8.084 8.084-8.084 4.464 0 8.083 3.619 8.083 8.084 0 4.464-3.619 8.083-8.083 8.083z"/> + <g id="question-mark" transform="translate(24, 0) scale(-1, 1)"> + <path id="top" d="M11.766 6.688c-2.5 0-3.219 2.188-3.219 2.188l1.411.854s.298-.791.901-1.229c.516-.375 1.625-.625 2.219.125.701.885-.17 1.587-1.078 2.719-.953 1.186-1 3.655-1 3.655h1.969s.135-2.318 1.041-3.381c.603-.707 1.443-1.338 1.443-2.494s-1.187-2.437-3.687-2.437z"/> + <path id="bottom" d="M11 16h2v2h-2z"/> + </g> + </g> +</svg> diff --git a/tests/phpunit/data/resourceloader/next.svg b/tests/phpunit/data/resourceloader/next.svg new file mode 100644 index 00000000..02b4e387 --- /dev/null +++ b/tests/phpunit/data/resourceloader/next.svg @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"> + <path d="M16.5 13.1l-8.9 8.9c-.8-.8-.8-2 0-2.8l6.1-6.1-6-6.1c-.8-.8-.8-2 0-2.8l8.8 8.9z" id="path108"/> +</svg> diff --git a/tests/phpunit/data/resourceloader/next_massage.svg b/tests/phpunit/data/resourceloader/next_massage.svg new file mode 100644 index 00000000..bbd1a8d6 --- /dev/null +++ b/tests/phpunit/data/resourceloader/next_massage.svg @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"> + <path d="M 16.5 13.1 l -8.9 8.9 c -0.8 -0.8 -0.8 -2 0 -2.8 l 6.1 -6.1 -6 -6.1 c -0.8 -0.8 -0.8 -2 0 -2.8 l 8.8 8.9 z" id="path108"/> +</svg> diff --git a/tests/phpunit/data/resourceloader/prev.svg b/tests/phpunit/data/resourceloader/prev.svg new file mode 100644 index 00000000..f31ec095 --- /dev/null +++ b/tests/phpunit/data/resourceloader/prev.svg @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"> + <path d="M7 13.1l8.9 8.9c.8-.8.8-2 0-2.8l-6.1-6.1 6-6.1c.8-.8.8-2 0-2.8l-8.8 8.9z"/> +</svg> diff --git a/tests/phpunit/data/resourceloader/remove.svg b/tests/phpunit/data/resourceloader/remove.svg new file mode 100644 index 00000000..6ad79174 --- /dev/null +++ b/tests/phpunit/data/resourceloader/remove.svg @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"> + <g id="remove"> + <path id="trash-can" d="M12 10h-1v6h1v-6zm-2 0h-1v6h1v-6zm4 0h-1v6h1v-6zm0-4v-1h-5v1h-3v3h1v7.966l1 1.031v-.074.077h6.984l.016-.018v.015l1-1.031v-7.966h1v-3h-3zm1 11h-7v-8h7v8zm1-9h-9v-1h9v1z"/> + </g> +</svg> diff --git a/tests/phpunit/data/resourceloader/remove_variantize.svg b/tests/phpunit/data/resourceloader/remove_variantize.svg new file mode 100644 index 00000000..bcbe8712 --- /dev/null +++ b/tests/phpunit/data/resourceloader/remove_variantize.svg @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><g fill="red"> + <g xmlns:default="http://www.w3.org/2000/svg" id="remove"> + <path id="trash-can" d="M12 10h-1v6h1v-6zm-2 0h-1v6h1v-6zm4 0h-1v6h1v-6zm0-4v-1h-5v1h-3v3h1v7.966l1 1.031v-.074.077h6.984l.016-.018v.015l1-1.031v-7.966h1v-3h-3zm1 11h-7v-8h7v8zm1-9h-9v-1h9v1z"/> + </g> +</g></svg> diff --git a/tests/phpunit/data/templates/foobar.mustache b/tests/phpunit/data/templates/foobar.mustache new file mode 100644 index 00000000..a0423896 --- /dev/null +++ b/tests/phpunit/data/templates/foobar.mustache @@ -0,0 +1 @@ +hello world! diff --git a/tests/phpunit/data/templates/foobar_args.mustache b/tests/phpunit/data/templates/foobar_args.mustache new file mode 100644 index 00000000..cfbe3d0f --- /dev/null +++ b/tests/phpunit/data/templates/foobar_args.mustache @@ -0,0 +1 @@ +hello {{planet}}! diff --git a/tests/phpunit/includes/BlockTest.php b/tests/phpunit/includes/BlockTest.php index b248d24e..19741621 100644 --- a/tests/phpunit/includes/BlockTest.php +++ b/tests/phpunit/includes/BlockTest.php @@ -133,6 +133,7 @@ class BlockTest extends MediaWikiLangTestCase { $username = 'BlockedUserToCreateAccountWith'; $u = User::newFromName( $username ); $u->setPassword( 'NotRandomPass' ); + $u->setId( 14146 ); $u->addToDatabase(); unset( $u ); @@ -200,6 +201,12 @@ class BlockTest extends MediaWikiLangTestCase { $oldBlock->delete(); } + // Local perspective (blockee on current wiki)... + $user = User::newFromName( 'UserOnForeignWiki' ); + $user->addToDatabase(); + // Set user ID to match the test value + $this->db->update( 'user', array( 'user_id' => 14146 ), array( 'user_id' => $user->getId() ) ); + // Foreign perspective (blockee not on current wiki)... $block = new Block( /* $address */ 'UserOnForeignWiki', @@ -221,11 +228,6 @@ class BlockTest extends MediaWikiLangTestCase { $res = $block->insert( $this->db ); $this->assertTrue( (bool)$res['id'], 'Block succeeded' ); - // Local perspective (blockee on current wiki)... - $user = User::newFromName( 'UserOnForeignWiki' ); - $user->addToDatabase(); - // Set user ID to match the test value - $this->db->update( 'user', array( 'user_id' => 14146 ), array( 'user_id' => $user->getId() ) ); $user = null; // clear $block = Block::newFromID( $res['id'] ); diff --git a/tests/phpunit/includes/EditPageTest.php b/tests/phpunit/includes/EditPageTest.php index 702fce4c..15778e40 100644 --- a/tests/phpunit/includes/EditPageTest.php +++ b/tests/phpunit/includes/EditPageTest.php @@ -217,7 +217,8 @@ class EditPageTest extends MediaWikiLangTestCase { EditPage::AS_SUCCESS_NEW_ARTICLE, '' ), - array( 'expected registered MediaWiki: page whose default content is empty not being created if empty', + array( 'expected registered MediaWiki: page whose default content is empty' + . ' not being created if empty', 'MediaWiki:Ipb-default-expiry', 'UTSysop', '', @@ -246,7 +247,9 @@ class EditPageTest extends MediaWikiLangTestCase { * @dataProvider provideCreatePages * @covers EditPage */ - public function testCreatePage( $desc, $pageTitle, $user, $editText, $expectedCode, $expectedText, $ignoreBlank = false ) { + public function testCreatePage( + $desc, $pageTitle, $user, $editText, $expectedCode, $expectedText, $ignoreBlank = false + ) { $edit = array( 'wpTextbox1' => $editText ); if ( $ignoreBlank ) { $edit['wpIgnoreBlankArticle'] = 1; diff --git a/tests/phpunit/includes/GitInfoTest.php b/tests/phpunit/includes/GitInfoTest.php index e22f5050..c3539d0e 100644 --- a/tests/phpunit/includes/GitInfoTest.php +++ b/tests/phpunit/includes/GitInfoTest.php @@ -10,7 +10,7 @@ class GitInfoTest extends MediaWikiTestCase { } public function testValidJsonData() { - $dir = $GLOBALS['IP'] . '/testValidJsonData'; + $dir = $GLOBALS['IP'] . DIRECTORY_SEPARATOR . 'testValidJsonData'; $fixture = new GitInfo( $dir ); $this->assertTrue( $fixture->cacheIsComplete() ); diff --git a/tests/phpunit/includes/GlobalFunctions/GlobalTest.php b/tests/phpunit/includes/GlobalFunctions/GlobalTest.php index 3acc48e2..1e30273e 100644 --- a/tests/phpunit/includes/GlobalFunctions/GlobalTest.php +++ b/tests/phpunit/includes/GlobalFunctions/GlobalTest.php @@ -7,7 +7,7 @@ class GlobalTest extends MediaWikiTestCase { protected function setUp() { parent::setUp(); - $readOnlyFile = tempnam( wfTempDir(), "mwtest_readonly" ); + $readOnlyFile = $this->getNewTempFile(); unlink( $readOnlyFile ); $this->setMwGlobals( array( @@ -22,16 +22,6 @@ class GlobalTest extends MediaWikiTestCase { ) ); } - protected function tearDown() { - global $wgReadOnlyFile; - - if ( file_exists( $wgReadOnlyFile ) ) { - unlink( $wgReadOnlyFile ); - } - - parent::tearDown(); - } - /** * @dataProvider provideForWfArrayDiff2 * @covers ::wfArrayDiff2 @@ -312,46 +302,42 @@ class GlobalTest extends MediaWikiTestCase { * @covers ::wfDebugMem */ public function testDebugFunctionTest() { + $debugLogFile = $this->getNewTempFile(); - global $wgDebugLogFile, $wgDebugTimestamps; - - $old_log_file = $wgDebugLogFile; - $wgDebugLogFile = tempnam( wfTempDir(), 'mw-' ); - # @todo FIXME: $wgDebugTimestamps should be tested - $old_wgDebugTimestamps = $wgDebugTimestamps; - $wgDebugTimestamps = false; + $this->setMwGlobals( array( + 'wgDebugLogFile' => $debugLogFile, + # @todo FIXME: $wgDebugTimestamps should be tested + 'wgDebugTimestamps' => false + ) ); wfDebug( "This is a normal string" ); - $this->assertEquals( "This is a normal string", file_get_contents( $wgDebugLogFile ) ); - unlink( $wgDebugLogFile ); + $this->assertEquals( "This is a normal string\n", file_get_contents( $debugLogFile ) ); + unlink( $debugLogFile ); wfDebug( "This is nöt an ASCII string" ); - $this->assertEquals( "This is nöt an ASCII string", file_get_contents( $wgDebugLogFile ) ); - unlink( $wgDebugLogFile ); + $this->assertEquals( "This is nöt an ASCII string\n", file_get_contents( $debugLogFile ) ); + unlink( $debugLogFile ); wfDebug( "\00305This has böth UTF and control chars\003" ); $this->assertEquals( - " 05This has böth UTF and control chars ", - file_get_contents( $wgDebugLogFile ) + " 05This has böth UTF and control chars \n", + file_get_contents( $debugLogFile ) ); - unlink( $wgDebugLogFile ); + unlink( $debugLogFile ); wfDebugMem(); $this->assertGreaterThan( 1000, - preg_replace( '/\D/', '', file_get_contents( $wgDebugLogFile ) ) + preg_replace( '/\D/', '', file_get_contents( $debugLogFile ) ) ); - unlink( $wgDebugLogFile ); + unlink( $debugLogFile ); wfDebugMem( true ); $this->assertGreaterThan( 1000000, - preg_replace( '/\D/', '', file_get_contents( $wgDebugLogFile ) ) + preg_replace( '/\D/', '', file_get_contents( $debugLogFile ) ) ); - unlink( $wgDebugLogFile ); - - $wgDebugLogFile = $old_log_file; - $wgDebugTimestamps = $old_wgDebugTimestamps; + unlink( $debugLogFile ); } /** @@ -389,24 +375,6 @@ class GlobalTest extends MediaWikiTestCase { } /** - * @covers ::swap - */ - public function testSwapVarsTest() { - $this->hideDeprecated( 'swap' ); - - $var1 = 1; - $var2 = 2; - - $this->assertEquals( $var1, 1, 'var1 is set originally' ); - $this->assertEquals( $var2, 2, 'var1 is set originally' ); - - swap( $var1, $var2 ); - - $this->assertEquals( $var1, 2, 'var1 is swapped' ); - $this->assertEquals( $var2, 1, 'var2 is swapped' ); - } - - /** * @covers ::wfPercent */ public function testWfPercentTest() { @@ -705,21 +673,21 @@ class GlobalTest extends MediaWikiTestCase { } /** - * @dataProvider provideWfShellMaintenanceCmdList - * @covers ::wfShellMaintenanceCmd + * @dataProvider provideWfShellWikiCmdList + * @covers ::wfShellWikiCmd */ - public function testWfShellMaintenanceCmd( $script, $parameters, $options, + public function testWfShellWikiCmd( $script, $parameters, $options, $expected, $description ) { if ( wfIsWindows() ) { // Approximation that's good enough for our purposes just now $expected = str_replace( "'", '"', $expected ); } - $actual = wfShellMaintenanceCmd( $script, $parameters, $options ); + $actual = wfShellWikiCmd( $script, $parameters, $options ); $this->assertEquals( $expected, $actual, $description ); } - public static function provideWfShellMaintenanceCmdList() { + public static function provideWfShellWikiCmdList() { global $wgPhpCli; return array( diff --git a/tests/phpunit/includes/GlobalFunctions/wfAppendQueryTest.php b/tests/phpunit/includes/GlobalFunctions/wfAppendQueryTest.php new file mode 100644 index 00000000..54e1f896 --- /dev/null +++ b/tests/phpunit/includes/GlobalFunctions/wfAppendQueryTest.php @@ -0,0 +1,67 @@ +<?php + +/** + * @group GlobalFunctions + * @covers ::wfAppendQuery + */ +class WfAppendQueryTest extends MediaWikiTestCase { + /** + * @dataProvider provideAppendQuery + */ + public function testAppendQuery( $url, $query, $expected, $message = null ) { + $this->assertEquals( $expected, wfAppendQuery( $url, $query ), $message ); + } + + public static function provideAppendQuery() { + return array( + array( + 'http://www.example.org/index.php', + '', + 'http://www.example.org/index.php', + 'No query' + ), + array( + 'http://www.example.org/index.php', + array( 'foo' => 'bar' ), + 'http://www.example.org/index.php?foo=bar', + 'Set query array' + ), + array( + 'http://www.example.org/index.php?foz=baz', + 'foo=bar', + 'http://www.example.org/index.php?foz=baz&foo=bar', + 'Set query string' + ), + array( + 'http://www.example.org/index.php?foo=bar', + '', + 'http://www.example.org/index.php?foo=bar', + 'Empty string with query' + ), + array( + 'http://www.example.org/index.php?foo=bar', + array( 'baz' => 'quux' ), + 'http://www.example.org/index.php?foo=bar&baz=quux', + 'Add query array' + ), + array( + 'http://www.example.org/index.php?foo=bar', + 'baz=quux', + 'http://www.example.org/index.php?foo=bar&baz=quux', + 'Add query string' + ), + array( + 'http://www.example.org/index.php?foo=bar', + array( 'baz' => 'quux', 'foo' => 'baz' ), + 'http://www.example.org/index.php?foo=bar&baz=quux&foo=baz', + 'Modify query array' + ), + array( + 'http://www.example.org/index.php?foo=bar', + 'baz=quux&foo=baz', + 'http://www.example.org/index.php?foo=bar&baz=quux&foo=baz', + 'Modify query string' + ) + ); + } +} diff --git a/tests/phpunit/includes/GlobalFunctions/wfEscapeShellArgTest.php b/tests/phpunit/includes/GlobalFunctions/wfEscapeShellArgTest.php new file mode 100644 index 00000000..cb334d2f --- /dev/null +++ b/tests/phpunit/includes/GlobalFunctions/wfEscapeShellArgTest.php @@ -0,0 +1,43 @@ +<?php + +/** + * @group GlobalFunctions + * @covers ::wfEscapeShellArg + */ +class wfEscapeShellArgTest extends MediaWikiTestCase { + public function testSingleInput() { + if ( wfIsWindows() ) { + $expected = '"blah"'; + } else { + $expected = "'blah'"; + } + + $actual = wfEscapeShellArg( 'blah' ); + + $this->assertEquals( $expected, $actual ); + } + + public function testMultipleArgs() { + if ( wfIsWindows() ) { + $expected = '"foo" "bar" "baz"'; + } else { + $expected = "'foo' 'bar' 'baz'"; + } + + $actual = wfEscapeShellArg( 'foo', 'bar', 'baz' ); + + $this->assertEquals( $expected, $actual ); + } + + public function testMultipleArgsAsArray() { + if ( wfIsWindows() ) { + $expected = '"foo" "bar" "baz"'; + } else { + $expected = "'foo' 'bar' 'baz'"; + } + + $actual = wfEscapeShellArg( array( 'foo', 'bar', 'baz' ) ); + + $this->assertEquals( $expected, $actual ); + } +} diff --git a/tests/phpunit/includes/GlobalFunctions/wfThumbIsStandardTest.php b/tests/phpunit/includes/GlobalFunctions/wfThumbIsStandardTest.php new file mode 100644 index 00000000..448250a6 --- /dev/null +++ b/tests/phpunit/includes/GlobalFunctions/wfThumbIsStandardTest.php @@ -0,0 +1,104 @@ +<?php + +/** + * @group GlobalFunctions + * @covers ::wfThumbIsStandard + */ +class WfThumbIsStandardTest extends MediaWikiTestCase { + + protected function setUp() { + parent::setUp(); + + $this->setMwGlobals( array( + 'wgThumbLimits' => array( + 100, + 401 + ), + 'wgImageLimits' => array( + array( 300, 225 ), + array( 800, 600 ), + ), + 'wgMediaHandlers' => array( + 'unknown/unknown' => 'MockBitmapHandler', + ), + ) ); + } + + public static function provideThumbParams() { + return array( + // Thumb limits + array( + 'Standard thumb width', + true, + array( 'width' => 100 ), + ), + array( + 'Standard thumb width', + true, + array( 'width' => 401 ), + ), + // wfThumbIsStandard should match Linker::processResponsiveImages + // in its rounding behaviour. + array( + 'Standard thumb width (HiDPI 1.5x) - incorrect rounding', + false, + array( 'width' => 601 ), + ), + array( + 'Standard thumb width (HiDPI 1.5x)', + true, + array( 'width' => 602 ), + ), + array( + 'Standard thumb width (HiDPI 2x)', + true, + array( 'width' => 802 ), + ), + array( + 'Non-standard thumb width', + false, + array( 'width' => 300 ), + ), + // Image limits + // Note: Image limits are measured as pairs. Individual values + // may be non-standard based on the aspect ratio. + array( + 'Standard image width/height pair', + true, + array( 'width' => 250, 'height' => 225 ), + ), + array( + 'Standard image width/height pair', + true, + array( 'width' => 667, 'height' => 600 ), + ), + array( + 'Standard image width where image does not fit aspect ratio', + false, + array( 'width' => 300 ), + ), + array( + 'Implicit width from image width/height pair aspect ratio fit', + true, + // 2000x1800 fit inside 300x225 makes w=250 + array( 'width' => 250 ), + ), + array( + 'Height-only is always non-standard', + false, + array( 'height' => 225 ), + ), + ); + } + + /** + * @dataProvider provideThumbParams + */ + public function testIsStandard( $message, $expected, $params ) { + $this->assertSame( + $expected, + wfThumbIsStandard( new FakeDimensionFile( array( 2000, 1800 ) ), $params ), + $message + ); + } +} diff --git a/tests/phpunit/includes/HtmlFormatterTest.php b/tests/phpunit/includes/HtmlFormatterTest.php index 9dbfa452..1c3e8539 100644 --- a/tests/phpunit/includes/HtmlFormatterTest.php +++ b/tests/phpunit/includes/HtmlFormatterTest.php @@ -4,6 +4,20 @@ * @group HtmlFormatter */ class HtmlFormatterTest extends MediaWikiTestCase { + + /** + * Use TidySupport to check whether we should use $wgTidyInternal. + * + * The Tidy extension in HHVM does not support error text return, so it is + * nominally usable, but does not pass tests which require error text from + * Tidy. + */ + protected function setUp() { + parent::setUp(); + $tidySupport = new TidySupport(); + $this->setMwGlobals( 'wgTidyInternal', $tidySupport->isInternal() ); + } + /** * @dataProvider getHtmlData * diff --git a/tests/phpunit/includes/HtmlTest.php b/tests/phpunit/includes/HtmlTest.php index a8829cd8..c5797c4f 100644 --- a/tests/phpunit/includes/HtmlTest.php +++ b/tests/phpunit/includes/HtmlTest.php @@ -637,7 +637,7 @@ class HtmlTest extends MediaWikiTestCase { . 'Depending on compatibility mode IE might use "button", instead.', ); - # <select> specifc handling + # <select> specific handling $cases[] = array( '<select multiple></select>', 'select', array( 'size' => '4', 'multiple' => true ), ); @@ -715,7 +715,7 @@ class HtmlTest extends MediaWikiTestCase { 'Input wrapper with type and value.' ); $this->assertEquals( - '<input name=testname class=mw-ui-input>', + '<input name=testname>', Html::input( 'testname' ), 'Input wrapper with all default values.' ); @@ -764,6 +764,30 @@ class HtmlTest extends MediaWikiTestCase { 'Label wrapper' ); } + + public static function provideSrcSetImages() { + return array( + array( array(), '', 'when there are no images, return empty string' ), + array( + array( '1x' => '1x.png', '1.5x' => '1_5x.png', '2x' => '2x.png' ), + '1x.png 1x, 1_5x.png 1.5x, 2x.png 2x', + 'pixel depth keys may include a trailing "x"' + ), + array( + array( '1' => '1x.png', '1.5' => '1_5x.png', '2' => '2x.png' ), + '1x.png 1x, 1_5x.png 1.5x, 2x.png 2x', + 'pixel depth keys may omit a trailing "x"' + ), + ); + } + + /** + * @dataProvider provideSrcSetImages + * @covers Html::srcSet + */ + public function testSrcSet( $images, $expected, $message ) { + $this->assertEquals( Html::srcSet( $images ), $expected, $message ); + } } class HtmlTestValue { diff --git a/tests/phpunit/includes/HttpTest.php b/tests/phpunit/includes/HttpTest.php index 9b53381e..8a0dff78 100644 --- a/tests/phpunit/includes/HttpTest.php +++ b/tests/phpunit/includes/HttpTest.php @@ -1,6 +1,7 @@ <?php + /** - * @group Broken + * @group Http */ class HttpTest extends MediaWikiTestCase { /** @@ -92,8 +93,10 @@ class HttpTest extends MediaWikiTestCase { array( true, 'http://user:pass@host', 'Username and password provided' ), # (\S+) - host part is made of anything not whitespaces - array( false, 'http://!"èèè¿¿¿~~\'', 'hostname is made of any non whitespace' ), - array( false, 'http://exam:ple.org/', 'hostname can not use colons!' ), + // commented these out in order to remove @group Broken + // @todo are these valid tests? if so, fix Http::isValidURI so it can handle them + //array( false, 'http://!"èèè¿¿¿~~\'', 'hostname is made of any non whitespace' ), + //array( false, 'http://exam:ple.org/', 'hostname can not use colons!' ), # (:[0-9]+)? - port number array( true, 'http://example.org:80/' ), @@ -135,7 +138,7 @@ class HttpTest extends MediaWikiTestCase { * HTTP redirects). */ public function testRelativeRedirections() { - $h = MWHttpRequestTester::factory( 'http://oldsite/file.ext' ); + $h = MWHttpRequestTester::factory( 'http://oldsite/file.ext', array(), __METHOD__ ); # Forge a Location header $h->setRespHeaders( 'location', array( @@ -171,6 +174,310 @@ class HttpTest extends MediaWikiTestCase { $h->getFinalUrl( "Relative file path Location: should keep the latest host and scheme!" ) ); } + + /** + * Constant values are from PHP 5.3.28 using cURL 7.24.0 + * @see http://php.net/manual/en/curl.constants.php + * + * All constant values are present so that developers don’t need to remember + * to add them if added at a later date. The commented out constants were + * not found anywhere in the MediaWiki core code. + * + * Commented out constants that were not available in: + * HipHop VM 3.3.0 (rel) + * Compiler: heads/master-0-g08810d920dfff59e0774cf2d651f92f13a637175 + * Repo schema: 3214fc2c684a4520485f715ee45f33f2182324b1 + * Extension API: 20140829 + * + * Commented out constants that were removed in PHP 5.6.0 + * + * @covers CurlHttpRequest::execute + */ + public function provideCurlConstants() { + return array( + array( 'CURLAUTH_ANY' ), + array( 'CURLAUTH_ANYSAFE' ), + array( 'CURLAUTH_BASIC' ), + array( 'CURLAUTH_DIGEST' ), + array( 'CURLAUTH_GSSNEGOTIATE' ), + array( 'CURLAUTH_NTLM' ), + // array( 'CURLCLOSEPOLICY_CALLBACK' ), // removed in PHP 5.6.0 + // array( 'CURLCLOSEPOLICY_LEAST_RECENTLY_USED' ), // removed in PHP 5.6.0 + // array( 'CURLCLOSEPOLICY_LEAST_TRAFFIC' ), // removed in PHP 5.6.0 + // array( 'CURLCLOSEPOLICY_OLDEST' ), // removed in PHP 5.6.0 + // array( 'CURLCLOSEPOLICY_SLOWEST' ), // removed in PHP 5.6.0 + array( 'CURLE_ABORTED_BY_CALLBACK' ), + array( 'CURLE_BAD_CALLING_ORDER' ), + array( 'CURLE_BAD_CONTENT_ENCODING' ), + array( 'CURLE_BAD_FUNCTION_ARGUMENT' ), + array( 'CURLE_BAD_PASSWORD_ENTERED' ), + array( 'CURLE_COULDNT_CONNECT' ), + array( 'CURLE_COULDNT_RESOLVE_HOST' ), + array( 'CURLE_COULDNT_RESOLVE_PROXY' ), + array( 'CURLE_FAILED_INIT' ), + array( 'CURLE_FILESIZE_EXCEEDED' ), + array( 'CURLE_FILE_COULDNT_READ_FILE' ), + array( 'CURLE_FTP_ACCESS_DENIED' ), + array( 'CURLE_FTP_BAD_DOWNLOAD_RESUME' ), + array( 'CURLE_FTP_CANT_GET_HOST' ), + array( 'CURLE_FTP_CANT_RECONNECT' ), + array( 'CURLE_FTP_COULDNT_GET_SIZE' ), + array( 'CURLE_FTP_COULDNT_RETR_FILE' ), + array( 'CURLE_FTP_COULDNT_SET_ASCII' ), + array( 'CURLE_FTP_COULDNT_SET_BINARY' ), + array( 'CURLE_FTP_COULDNT_STOR_FILE' ), + array( 'CURLE_FTP_COULDNT_USE_REST' ), + array( 'CURLE_FTP_PORT_FAILED' ), + array( 'CURLE_FTP_QUOTE_ERROR' ), + array( 'CURLE_FTP_SSL_FAILED' ), + array( 'CURLE_FTP_USER_PASSWORD_INCORRECT' ), + array( 'CURLE_FTP_WEIRD_227_FORMAT' ), + array( 'CURLE_FTP_WEIRD_PASS_REPLY' ), + array( 'CURLE_FTP_WEIRD_PASV_REPLY' ), + array( 'CURLE_FTP_WEIRD_SERVER_REPLY' ), + array( 'CURLE_FTP_WEIRD_USER_REPLY' ), + array( 'CURLE_FTP_WRITE_ERROR' ), + array( 'CURLE_FUNCTION_NOT_FOUND' ), + array( 'CURLE_GOT_NOTHING' ), + array( 'CURLE_HTTP_NOT_FOUND' ), + array( 'CURLE_HTTP_PORT_FAILED' ), + array( 'CURLE_HTTP_POST_ERROR' ), + array( 'CURLE_HTTP_RANGE_ERROR' ), + array( 'CURLE_LDAP_CANNOT_BIND' ), + array( 'CURLE_LDAP_INVALID_URL' ), + array( 'CURLE_LDAP_SEARCH_FAILED' ), + array( 'CURLE_LIBRARY_NOT_FOUND' ), + array( 'CURLE_MALFORMAT_USER' ), + array( 'CURLE_OBSOLETE' ), + array( 'CURLE_OK' ), + array( 'CURLE_OPERATION_TIMEOUTED' ), + array( 'CURLE_OUT_OF_MEMORY' ), + array( 'CURLE_PARTIAL_FILE' ), + array( 'CURLE_READ_ERROR' ), + array( 'CURLE_RECV_ERROR' ), + array( 'CURLE_SEND_ERROR' ), + array( 'CURLE_SHARE_IN_USE' ), + // array( 'CURLE_SSH' ), // not present in HHVM 3.3.0-dev + array( 'CURLE_SSL_CACERT' ), + array( 'CURLE_SSL_CERTPROBLEM' ), + array( 'CURLE_SSL_CIPHER' ), + array( 'CURLE_SSL_CONNECT_ERROR' ), + array( 'CURLE_SSL_ENGINE_NOTFOUND' ), + array( 'CURLE_SSL_ENGINE_SETFAILED' ), + array( 'CURLE_SSL_PEER_CERTIFICATE' ), + array( 'CURLE_TELNET_OPTION_SYNTAX' ), + array( 'CURLE_TOO_MANY_REDIRECTS' ), + array( 'CURLE_UNKNOWN_TELNET_OPTION' ), + array( 'CURLE_UNSUPPORTED_PROTOCOL' ), + array( 'CURLE_URL_MALFORMAT' ), + array( 'CURLE_URL_MALFORMAT_USER' ), + array( 'CURLE_WRITE_ERROR' ), + array( 'CURLFTPAUTH_DEFAULT' ), + array( 'CURLFTPAUTH_SSL' ), + array( 'CURLFTPAUTH_TLS' ), + // array( 'CURLFTPMETHOD_MULTICWD' ), // not present in HHVM 3.3.0-dev + // array( 'CURLFTPMETHOD_NOCWD' ), // not present in HHVM 3.3.0-dev + // array( 'CURLFTPMETHOD_SINGLECWD' ), // not present in HHVM 3.3.0-dev + array( 'CURLFTPSSL_ALL' ), + array( 'CURLFTPSSL_CONTROL' ), + array( 'CURLFTPSSL_NONE' ), + array( 'CURLFTPSSL_TRY' ), + // array( 'CURLINFO_CERTINFO' ), // not present in HHVM 3.3.0-dev + array( 'CURLINFO_CONNECT_TIME' ), + array( 'CURLINFO_CONTENT_LENGTH_DOWNLOAD' ), + array( 'CURLINFO_CONTENT_LENGTH_UPLOAD' ), + array( 'CURLINFO_CONTENT_TYPE' ), + array( 'CURLINFO_EFFECTIVE_URL' ), + array( 'CURLINFO_FILETIME' ), + array( 'CURLINFO_HEADER_OUT' ), + array( 'CURLINFO_HEADER_SIZE' ), + array( 'CURLINFO_HTTP_CODE' ), + array( 'CURLINFO_NAMELOOKUP_TIME' ), + array( 'CURLINFO_PRETRANSFER_TIME' ), + array( 'CURLINFO_PRIVATE' ), + array( 'CURLINFO_REDIRECT_COUNT' ), + array( 'CURLINFO_REDIRECT_TIME' ), + // array( 'CURLINFO_REDIRECT_URL' ), // not present in HHVM 3.3.0-dev + array( 'CURLINFO_REQUEST_SIZE' ), + array( 'CURLINFO_SIZE_DOWNLOAD' ), + array( 'CURLINFO_SIZE_UPLOAD' ), + array( 'CURLINFO_SPEED_DOWNLOAD' ), + array( 'CURLINFO_SPEED_UPLOAD' ), + array( 'CURLINFO_SSL_VERIFYRESULT' ), + array( 'CURLINFO_STARTTRANSFER_TIME' ), + array( 'CURLINFO_TOTAL_TIME' ), + array( 'CURLMSG_DONE' ), + array( 'CURLM_BAD_EASY_HANDLE' ), + array( 'CURLM_BAD_HANDLE' ), + array( 'CURLM_CALL_MULTI_PERFORM' ), + array( 'CURLM_INTERNAL_ERROR' ), + array( 'CURLM_OK' ), + array( 'CURLM_OUT_OF_MEMORY' ), + array( 'CURLOPT_AUTOREFERER' ), + array( 'CURLOPT_BINARYTRANSFER' ), + array( 'CURLOPT_BUFFERSIZE' ), + array( 'CURLOPT_CAINFO' ), + array( 'CURLOPT_CAPATH' ), + // array( 'CURLOPT_CERTINFO' ), // not present in HHVM 3.3.0-dev + // array( 'CURLOPT_CLOSEPOLICY' ), // removed in PHP 5.6.0 + array( 'CURLOPT_CONNECTTIMEOUT' ), + array( 'CURLOPT_CONNECTTIMEOUT_MS' ), + array( 'CURLOPT_COOKIE' ), + array( 'CURLOPT_COOKIEFILE' ), + array( 'CURLOPT_COOKIEJAR' ), + array( 'CURLOPT_COOKIESESSION' ), + array( 'CURLOPT_CRLF' ), + array( 'CURLOPT_CUSTOMREQUEST' ), + array( 'CURLOPT_DNS_CACHE_TIMEOUT' ), + array( 'CURLOPT_DNS_USE_GLOBAL_CACHE' ), + array( 'CURLOPT_EGDSOCKET' ), + array( 'CURLOPT_ENCODING' ), + array( 'CURLOPT_FAILONERROR' ), + array( 'CURLOPT_FILE' ), + array( 'CURLOPT_FILETIME' ), + array( 'CURLOPT_FOLLOWLOCATION' ), + array( 'CURLOPT_FORBID_REUSE' ), + array( 'CURLOPT_FRESH_CONNECT' ), + array( 'CURLOPT_FTPAPPEND' ), + array( 'CURLOPT_FTPLISTONLY' ), + array( 'CURLOPT_FTPPORT' ), + array( 'CURLOPT_FTPSSLAUTH' ), + array( 'CURLOPT_FTP_CREATE_MISSING_DIRS' ), + // array( 'CURLOPT_FTP_FILEMETHOD' ), // not present in HHVM 3.3.0-dev + // array( 'CURLOPT_FTP_SKIP_PASV_IP' ), // not present in HHVM 3.3.0-dev + array( 'CURLOPT_FTP_SSL' ), + array( 'CURLOPT_FTP_USE_EPRT' ), + array( 'CURLOPT_FTP_USE_EPSV' ), + array( 'CURLOPT_HEADER' ), + array( 'CURLOPT_HEADERFUNCTION' ), + array( 'CURLOPT_HTTP200ALIASES' ), + array( 'CURLOPT_HTTPAUTH' ), + array( 'CURLOPT_HTTPGET' ), + array( 'CURLOPT_HTTPHEADER' ), + array( 'CURLOPT_HTTPPROXYTUNNEL' ), + array( 'CURLOPT_HTTP_VERSION' ), + array( 'CURLOPT_INFILE' ), + array( 'CURLOPT_INFILESIZE' ), + array( 'CURLOPT_INTERFACE' ), + array( 'CURLOPT_IPRESOLVE' ), + // array( 'CURLOPT_KEYPASSWD' ), // not present in HHVM 3.3.0-dev + array( 'CURLOPT_KRB4LEVEL' ), + array( 'CURLOPT_LOW_SPEED_LIMIT' ), + array( 'CURLOPT_LOW_SPEED_TIME' ), + array( 'CURLOPT_MAXCONNECTS' ), + array( 'CURLOPT_MAXREDIRS' ), + // array( 'CURLOPT_MAX_RECV_SPEED_LARGE' ), // not present in HHVM 3.3.0-dev + // array( 'CURLOPT_MAX_SEND_SPEED_LARGE' ), // not present in HHVM 3.3.0-dev + array( 'CURLOPT_NETRC' ), + array( 'CURLOPT_NOBODY' ), + array( 'CURLOPT_NOPROGRESS' ), + array( 'CURLOPT_NOSIGNAL' ), + array( 'CURLOPT_PORT' ), + array( 'CURLOPT_POST' ), + array( 'CURLOPT_POSTFIELDS' ), + array( 'CURLOPT_POSTQUOTE' ), + array( 'CURLOPT_POSTREDIR' ), + array( 'CURLOPT_PRIVATE' ), + array( 'CURLOPT_PROGRESSFUNCTION' ), + // array( 'CURLOPT_PROTOCOLS' ), // not present in HHVM 3.3.0-dev + array( 'CURLOPT_PROXY' ), + array( 'CURLOPT_PROXYAUTH' ), + array( 'CURLOPT_PROXYPORT' ), + array( 'CURLOPT_PROXYTYPE' ), + array( 'CURLOPT_PROXYUSERPWD' ), + array( 'CURLOPT_PUT' ), + array( 'CURLOPT_QUOTE' ), + array( 'CURLOPT_RANDOM_FILE' ), + array( 'CURLOPT_RANGE' ), + array( 'CURLOPT_READDATA' ), + array( 'CURLOPT_READFUNCTION' ), + // array( 'CURLOPT_REDIR_PROTOCOLS' ), // not present in HHVM 3.3.0-dev + array( 'CURLOPT_REFERER' ), + array( 'CURLOPT_RESUME_FROM' ), + array( 'CURLOPT_RETURNTRANSFER' ), + // array( 'CURLOPT_SSH_AUTH_TYPES' ), // not present in HHVM 3.3.0-dev + // array( 'CURLOPT_SSH_HOST_PUBLIC_KEY_MD5' ), // not present in HHVM 3.3.0-dev + // array( 'CURLOPT_SSH_PRIVATE_KEYFILE' ), // not present in HHVM 3.3.0-dev + // array( 'CURLOPT_SSH_PUBLIC_KEYFILE' ), // not present in HHVM 3.3.0-dev + array( 'CURLOPT_SSLCERT' ), + array( 'CURLOPT_SSLCERTPASSWD' ), + array( 'CURLOPT_SSLCERTTYPE' ), + array( 'CURLOPT_SSLENGINE' ), + array( 'CURLOPT_SSLENGINE_DEFAULT' ), + array( 'CURLOPT_SSLKEY' ), + array( 'CURLOPT_SSLKEYPASSWD' ), + array( 'CURLOPT_SSLKEYTYPE' ), + array( 'CURLOPT_SSLVERSION' ), + array( 'CURLOPT_SSL_CIPHER_LIST' ), + array( 'CURLOPT_SSL_VERIFYHOST' ), + array( 'CURLOPT_SSL_VERIFYPEER' ), + array( 'CURLOPT_STDERR' ), + array( 'CURLOPT_TCP_NODELAY' ), + array( 'CURLOPT_TIMECONDITION' ), + array( 'CURLOPT_TIMEOUT' ), + array( 'CURLOPT_TIMEOUT_MS' ), + array( 'CURLOPT_TIMEVALUE' ), + array( 'CURLOPT_TRANSFERTEXT' ), + array( 'CURLOPT_UNRESTRICTED_AUTH' ), + array( 'CURLOPT_UPLOAD' ), + array( 'CURLOPT_URL' ), + array( 'CURLOPT_USERAGENT' ), + array( 'CURLOPT_USERPWD' ), + array( 'CURLOPT_VERBOSE' ), + array( 'CURLOPT_WRITEFUNCTION' ), + array( 'CURLOPT_WRITEHEADER' ), + // array( 'CURLPROTO_ALL' ), // not present in HHVM 3.3.0-dev + // array( 'CURLPROTO_DICT' ), // not present in HHVM 3.3.0-dev + // array( 'CURLPROTO_FILE' ), // not present in HHVM 3.3.0-dev + // array( 'CURLPROTO_FTP' ), // not present in HHVM 3.3.0-dev + // array( 'CURLPROTO_FTPS' ), // not present in HHVM 3.3.0-dev + // array( 'CURLPROTO_HTTP' ), // not present in HHVM 3.3.0-dev + // array( 'CURLPROTO_HTTPS' ), // not present in HHVM 3.3.0-dev + // array( 'CURLPROTO_LDAP' ), // not present in HHVM 3.3.0-dev + // array( 'CURLPROTO_LDAPS' ), // not present in HHVM 3.3.0-dev + // array( 'CURLPROTO_SCP' ), // not present in HHVM 3.3.0-dev + // array( 'CURLPROTO_SFTP' ), // not present in HHVM 3.3.0-dev + // array( 'CURLPROTO_TELNET' ), // not present in HHVM 3.3.0-dev + // array( 'CURLPROTO_TFTP' ), // not present in HHVM 3.3.0-dev + array( 'CURLPROXY_HTTP' ), + // array( 'CURLPROXY_SOCKS4' ), // not present in HHVM 3.3.0-dev + array( 'CURLPROXY_SOCKS5' ), + // array( 'CURLSSH_AUTH_DEFAULT' ), // not present in HHVM 3.3.0-dev + // array( 'CURLSSH_AUTH_HOST' ), // not present in HHVM 3.3.0-dev + // array( 'CURLSSH_AUTH_KEYBOARD' ), // not present in HHVM 3.3.0-dev + // array( 'CURLSSH_AUTH_NONE' ), // not present in HHVM 3.3.0-dev + // array( 'CURLSSH_AUTH_PASSWORD' ), // not present in HHVM 3.3.0-dev + // array( 'CURLSSH_AUTH_PUBLICKEY' ), // not present in HHVM 3.3.0-dev + array( 'CURLVERSION_NOW' ), + array( 'CURL_HTTP_VERSION_1_0' ), + array( 'CURL_HTTP_VERSION_1_1' ), + array( 'CURL_HTTP_VERSION_NONE' ), + array( 'CURL_IPRESOLVE_V4' ), + array( 'CURL_IPRESOLVE_V6' ), + array( 'CURL_IPRESOLVE_WHATEVER' ), + array( 'CURL_NETRC_IGNORED' ), + array( 'CURL_NETRC_OPTIONAL' ), + array( 'CURL_NETRC_REQUIRED' ), + array( 'CURL_TIMECOND_IFMODSINCE' ), + array( 'CURL_TIMECOND_IFUNMODSINCE' ), + array( 'CURL_TIMECOND_LASTMOD' ), + array( 'CURL_VERSION_IPV6' ), + array( 'CURL_VERSION_KERBEROS4' ), + array( 'CURL_VERSION_LIBZ' ), + array( 'CURL_VERSION_SSL' ), + ); + } + + /** + * Added this test based on an issue experienced with HHVM 3.3.0-dev + * where it did not define a cURL constant. + * + * @bug 70570 + * @dataProvider provideCurlConstants + */ + public function testCurlConstants( $value ) { + $this->assertTrue( defined( $value ), $value . ' not defined' ); + } } /** @@ -179,7 +486,7 @@ class HttpTest extends MediaWikiTestCase { class MWHttpRequestTester extends MWHttpRequest { // function derived from the MWHttpRequest factory function but // returns appropriate tester class here - public static function factory( $url, $options = null ) { + public static function factory( $url, $options = null, $caller = __METHOD__ ) { if ( !Http::$httpEngine ) { Http::$httpEngine = function_exists( 'curl_init' ) ? 'curl' : 'php'; } elseif ( Http::$httpEngine == 'curl' && !function_exists( 'curl_init' ) ) { @@ -189,7 +496,7 @@ class MWHttpRequestTester extends MWHttpRequest { switch ( Http::$httpEngine ) { case 'curl': - return new CurlHttpRequestTester( $url, $options ); + return new CurlHttpRequestTester( $url, $options, $caller ); case 'php': if ( !wfIniGetBool( 'allow_url_fopen' ) ) { throw new MWException( __METHOD__ . @@ -197,7 +504,7 @@ class MWHttpRequestTester extends MWHttpRequest { . 'If possible, curl should be used instead. See http://php.net/curl.' ); } - return new PhpHttpRequestTester( $url, $options ); + return new PhpHttpRequestTester( $url, $options, $caller ); default: } } diff --git a/tests/phpunit/includes/ImportTest.php b/tests/phpunit/includes/ImportTest.php index 2fce6bfb..ea753e81 100644 --- a/tests/phpunit/includes/ImportTest.php +++ b/tests/phpunit/includes/ImportTest.php @@ -28,13 +28,14 @@ class ImportTest extends MediaWikiLangTestCase { $source = $this->getInputStreamSource( $xml ); $redirect = null; - $callback = function ( $title, $origTitle, $revCount, $sRevCount, $pageInfo ) use ( &$redirect ) { + $callback = function ( Title $title, ForeignTitle $foreignTitle, $revCount, + $sRevCount, $pageInfo ) use ( &$redirect ) { if ( array_key_exists( 'redirect', $pageInfo ) ) { $redirect = $pageInfo['redirect']; } }; - $importer = new WikiImporter( $source ); + $importer = new WikiImporter( $source, ConfigFactory::getDefaultInstance()->makeConfig( 'main' ) ); $importer->setPageOutCallback( $callback ); $importer->doImport(); @@ -45,7 +46,7 @@ class ImportTest extends MediaWikiLangTestCase { return array( array( <<< EOF -<mediawiki> +<mediawiki xmlns="http://www.mediawiki.org/xml/export-0.10/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mediawiki.org/xml/export-0.10/ http://www.mediawiki.org/xml/export-0.10.xsd" version="0.10" xml:lang="en"> <page> <title>Test</title> <ns>0</ns> @@ -59,10 +60,10 @@ class ImportTest extends MediaWikiLangTestCase { <id>10</id> </contributor> <comment>Admin moved page [[Test]] to [[Test22]]</comment> - <text xml:space="preserve" bytes="20">#REDIRECT [[Test22]]</text> - <sha1>tq456o9x3abm7r9ozi6km8yrbbc56o6</sha1> <model>wikitext</model> <format>text/x-wiki</format> + <text xml:space="preserve" bytes="20">#REDIRECT [[Test22]]</text> + <sha1>tq456o9x3abm7r9ozi6km8yrbbc56o6</sha1> </revision> </page> </mediawiki> @@ -72,7 +73,7 @@ EOF ), array( <<< EOF -<mediawiki> +<mediawiki xmlns="http://www.mediawiki.org/xml/export-0.9/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mediawiki.org/xml/export-0.9/ http://www.mediawiki.org/xml/export-0.9.xsd" version="0.9" xml:lang="en"> <page> <title>Test</title> <ns>0</ns> @@ -98,4 +99,59 @@ EOF ); } + /** + * @covers WikiImporter::handleSiteInfo + * @dataProvider getSiteInfoXML + * @param string $xml + * @param array|null $namespaces + */ + public function testSiteInfoContainsNamespaces( $xml, $namespaces ) { + $source = $this->getInputStreamSource( $xml ); + + $importNamespaces = null; + $callback = function ( array $siteinfo, $innerImporter ) use ( &$importNamespaces ) { + $importNamespaces = $siteinfo['_namespaces']; + }; + + $importer = new WikiImporter( $source, ConfigFactory::getDefaultInstance()->makeConfig( 'main' ) ); + $importer->setSiteInfoCallback( $callback ); + $importer->doImport(); + + $this->assertEquals( $importNamespaces, $namespaces ); + } + + public function getSiteInfoXML() { + return array( + array( + <<< EOF +<mediawiki xmlns="http://www.mediawiki.org/xml/export-0.10/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mediawiki.org/xml/export-0.10/ http://www.mediawiki.org/xml/export-0.10.xsd" version="0.10" xml:lang="en"> + <siteinfo> + <namespaces> + <namespace key="-2" case="first-letter">Media</namespace> + <namespace key="-1" case="first-letter">Special</namespace> + <namespace key="0" case="first-letter" /> + <namespace key="1" case="first-letter">Talk</namespace> + <namespace key="2" case="first-letter">User</namespace> + <namespace key="3" case="first-letter">User talk</namespace> + <namespace key="100" case="first-letter">Portal</namespace> + <namespace key="101" case="first-letter">Portal talk</namespace> + </namespaces> + </siteinfo> +</mediawiki> +EOF + , + array( + '-2' => 'Media', + '-1' => 'Special', + '0' => '', + '1' => 'Talk', + '2' => 'User', + '3' => 'User talk', + '100' => 'Portal', + '101' => 'Portal talk', + ) + ), + ); + } + } diff --git a/tests/phpunit/includes/LinkerTest.php b/tests/phpunit/includes/LinkerTest.php index 7b84107e..823c9330 100644 --- a/tests/phpunit/includes/LinkerTest.php +++ b/tests/phpunit/includes/LinkerTest.php @@ -149,10 +149,14 @@ class LinkerTest extends MediaWikiLangTestCase { "pre /* autocomment */ post", ), array( - '/* autocomment */ multiple? <a href="/wiki/Special:BlankPage#autocomment2" title="Special:BlankPage">→</a><span dir="auto"><span class="autocomment">autocomment2: </span> </span>', + '<a href="/wiki/Special:BlankPage#autocomment" title="Special:BlankPage">→</a><span dir="auto"><span class="autocomment">autocomment: </span> multiple? <a href="/wiki/Special:BlankPage#autocomment2" title="Special:BlankPage">→</a><span dir="auto"><span class="autocomment">autocomment2: </span> </span></span>', "/* autocomment */ multiple? /* autocomment2 */ ", ), array( + '<a href="/wiki/Special:BlankPage#autocomment_containing_.2F.2A" title="Special:BlankPage">→</a><span dir="auto"><span class="autocomment">autocomment containing /*: </span> T70361</span>', + "/* autocomment containing /* */ T70361" + ), + array( '<a href="#autocomment">→</a><span dir="auto"><span class="autocomment">autocomment</span></span>', "/* autocomment */", false, true @@ -189,4 +193,54 @@ class LinkerTest extends MediaWikiLangTestCase { ), ); } + + /** + * @covers Linker::formatLinksInComment + * @dataProvider provideCasesForFormatLinksInComment + */ + public function testFormatLinksInComment( $expected, $input, $wiki ) { + + $conf = new SiteConfiguration(); + $conf->settings = array( + 'wgServer' => array( + 'enwiki' => '//en.example.org' + ), + 'wgArticlePath' => array( + 'enwiki' => '/w/$1', + ), + ); + $conf->suffixes = array( 'wiki' ); + $this->setMwGlobals( array( + 'wgScript' => '/wiki/index.php', + 'wgArticlePath' => '/wiki/$1', + 'wgWellFormedXml' => true, + 'wgCapitalLinks' => true, + 'wgConf' => $conf, + ) ); + + $this->assertEquals( + $expected, + Linker::formatLinksInComment( $input, Title::newFromText( 'Special:BlankPage' ), false, $wiki ) + ); + } + + public static function provideCasesForFormatLinksInComment() { + return array( + array( + 'foo bar <a href="/wiki/Special:BlankPage" title="Special:BlankPage">Special:BlankPage</a>', + 'foo bar [[Special:BlankPage]]', + null, + ), + array( + '<a class="external" rel="nofollow" href="//en.example.org/w/Foo%27bar">Foo\'bar</a>', + "[[Foo'bar]]", + 'enwiki', + ), + array( + 'foo bar <a class="external" rel="nofollow" href="//en.example.org/w/Special:BlankPage">Special:BlankPage</a>', + 'foo bar [[Special:BlankPage]]', + 'enwiki', + ), + ); + } } diff --git a/tests/phpunit/includes/MWTimestampTest.php b/tests/phpunit/includes/MWTimestampTest.php index dcb98563..36562545 100644 --- a/tests/phpunit/includes/MWTimestampTest.php +++ b/tests/phpunit/includes/MWTimestampTest.php @@ -8,6 +8,9 @@ class MWTimestampTest extends MediaWikiLangTestCase { protected function setUp() { parent::setUp(); + // Avoid 'GetHumanTimestamp' hook and others + $this->setMwGlobals( 'wgHooks', array() ); + RequestContext::getMain()->setLanguage( Language::factory( 'en' ) ); } @@ -79,6 +82,17 @@ class MWTimestampTest extends MediaWikiLangTestCase { } /** + * Test an out of range timestamp + * @dataProvider provideOutOfRangeTimestamps + * @expectedException TimestampException + * @covers MWTimestamp + */ + public function testOutOfRangeTimestamps( $format, $input ) { + $timestamp = new MWTimestamp( $input ); + $timestamp->getTimestamp( $format ); + } + + /** * Test requesting an invalid output format. * @expectedException TimestampException * @covers MWTimestamp::getTimestamp @@ -111,6 +125,18 @@ class MWTimestampTest extends MediaWikiLangTestCase { } /** + * Returns a list of out of range timestamps in the format: + * array( type, timestamp_of_type ) + */ + public static function provideOutOfRangeTimestamps() { + return array( + // Various formats + array( TS_MW, '-62167219201' ), // -0001-12-31T23:59:59Z + array( TS_MW, '253402300800' ), // 10000-01-01T00:00:00Z + ); + } + + /** * @dataProvider provideHumanTimestampTests * @covers MWTimestamp::getHumanTimestamp */ diff --git a/tests/phpunit/includes/MediaWikiVersionFetcherTest.php b/tests/phpunit/includes/MediaWikiVersionFetcherTest.php index e548f817..fa59ef29 100644 --- a/tests/phpunit/includes/MediaWikiVersionFetcherTest.php +++ b/tests/phpunit/includes/MediaWikiVersionFetcherTest.php @@ -8,7 +8,6 @@ * * @group ComposerHooks * - * @licence GNU GPL v2+ * @author Jeroen De Dauw < jeroendedauw@gmail.com > */ class MediaWikiVersionFetcherTest extends PHPUnit_Framework_TestCase { diff --git a/tests/phpunit/includes/MessageTest.php b/tests/phpunit/includes/MessageTest.php index f3d2a84a..99ec2e42 100644 --- a/tests/phpunit/includes/MessageTest.php +++ b/tests/phpunit/includes/MessageTest.php @@ -16,22 +16,11 @@ class MessageTest extends MediaWikiLangTestCase { * @dataProvider provideConstructor */ public function testConstructor( $expectedLang, $key, $params, $language ) { - $reflection = new ReflectionClass( 'Message' ); - - $keyProperty = $reflection->getProperty( 'key' ); - $keyProperty->setAccessible( true ); - - $paramsProperty = $reflection->getProperty( 'parameters' ); - $paramsProperty->setAccessible( true ); - - $langProperty = $reflection->getProperty( 'language' ); - $langProperty->setAccessible( true ); - $message = new Message( $key, $params, $language ); - $this->assertEquals( $key, $keyProperty->getValue( $message ) ); - $this->assertEquals( $params, $paramsProperty->getValue( $message ) ); - $this->assertEquals( $expectedLang, $langProperty->getValue( $message ) ); + $this->assertEquals( $key, $message->getKey() ); + $this->assertEquals( $params, $message->getParams() ); + $this->assertEquals( $expectedLang, $message->getLanguage() ); } public static function provideConstructor() { @@ -45,21 +34,62 @@ class MessageTest extends MediaWikiLangTestCase { ); } - public static function provideTestParams() { + public static function provideConstructorParams() { return array( - array( array() ), - array( array( 'foo' ), 'foo' ), - array( array( 'foo', 'bar' ), 'foo', 'bar' ), - array( array( 'baz' ), array( 'baz' ) ), - array( array( 'baz', 'foo' ), array( 'baz', 'foo' ) ), - array( array( 'baz', 'foo' ), array( 'baz', 'foo' ), 'hhh' ), - array( array( 'baz', 'foo' ), array( 'baz', 'foo' ), 'hhh', array( 'ahahahahha' ) ), - array( array( 'baz', 'foo' ), array( 'baz', 'foo' ), array( 'ahahahahha' ) ), - array( array( 'baz' ), array( 'baz' ), array( 'ahahahahha' ) ), + array( + array(), + array(), + ), + array( + array( 'foo' ), + array( 'foo' ), + ), + array( + array( 'foo', 'bar' ), + array( 'foo', 'bar' ), + ), + array( + array( 'baz' ), + array( array( 'baz' ) ), + ), + array( + array( 'baz', 'foo' ), + array( array( 'baz', 'foo' ) ), + ), + array( + array( 'baz', 'foo' ), + array( array( 'baz', 'foo' ), 'hhh' ), + ), + array( + array( 'baz', 'foo' ), + array( array( 'baz', 'foo' ), 'hhh', array( 'ahahahahha' ) ), + ), + array( + array( 'baz', 'foo' ), + array( array( 'baz', 'foo' ), array( 'ahahahahha' ) ), + ), + array( + array( 'baz' ), + array( array( 'baz' ), array( 'ahahahahha' ) ), + ), ); } - public function getLanguageProvider() { + /** + * @covers Message::__construct + * @covers Message::getParams + * @dataProvider provideConstructorParams + */ + public function testConstructorParams( $expected, $args ) { + $msg = new Message( 'imasomething' ); + + $returned = call_user_func_array( array( $msg, 'params' ), $args ); + + $this->assertSame( $msg, $returned ); + $this->assertEquals( $expected, $msg->getParams() ); + } + + public static function provideConstructorLanguage() { return array( array( 'foo', array( 'bar' ), 'en' ), array( 'foo', array( 'bar' ), 'de' ) @@ -67,27 +97,98 @@ class MessageTest extends MediaWikiLangTestCase { } /** + * @covers Message::__construct * @covers Message::getLanguage - * @dataProvider getLanguageProvider + * @dataProvider provideConstructorLanguage */ - public function testGetLanguageCode( $key, $params, $languageCode ) { + public function testConstructorLanguage( $key, $params, $languageCode ) { $language = Language::factory( $languageCode ); $message = new Message( $key, $params, $language ); $this->assertEquals( $language, $message->getLanguage() ); } + public static function provideKeys() { + return array( + 'string' => array( + 'key' => 'mainpage', + 'expected' => array( 'mainpage' ), + ), + 'single' => array( + 'key' => array( 'mainpage' ), + 'expected' => array( 'mainpage' ), + ), + 'multi' => array( + 'key' => array( 'mainpage-foo', 'mainpage-bar', 'mainpage' ), + 'expected' => array( 'mainpage-foo', 'mainpage-bar', 'mainpage' ), + ), + 'empty' => array( + 'key' => array(), + 'expected' => null, + 'exception' => 'InvalidArgumentException', + ), + 'null' => array( + 'key' => null, + 'expected' => null, + 'exception' => 'InvalidArgumentException', + ), + 'bad type' => array( + 'key' => 123, + 'expected' => null, + 'exception' => 'InvalidArgumentException', + ), + ); + } + /** - * @covers Message::params - * @dataProvider provideTestParams + * @covers Message::__construct + * @covers Message::getKey + * @covers Message::isMultiKey + * @covers Message::getKeysToTry + * @dataProvider provideKeys */ - public function testParams( $expected ) { - $msg = new Message( 'imasomething' ); + public function testKeys( $key, $expected, $exception = null ) { + if ( $exception ) { + $this->setExpectedException( $exception ); + } + + $msg = new Message( $key ); + $this->assertContains( $msg->getKey(), $expected ); + $this->assertEquals( $expected, $msg->getKeysToTry() ); + $this->assertEquals( count( $expected ) > 1, $msg->isMultiKey() ); + } - $returned = call_user_func_array( array( $msg, 'params' ), array_slice( func_get_args(), 1 ) ); + /** + * @covers ::wfMessage + */ + public function testWfMessage() { + $this->assertInstanceOf( 'Message', wfMessage( 'mainpage' ) ); + $this->assertInstanceOf( 'Message', wfMessage( 'i-dont-exist-evar' ) ); + } - $this->assertSame( $msg, $returned ); - $this->assertEquals( $expected, $msg->getParams() ); + /** + * @covers Message::newFromKey + */ + public function testNewFromKey() { + $this->assertInstanceOf( 'Message', Message::newFromKey( 'mainpage' ) ); + $this->assertInstanceOf( 'Message', Message::newFromKey( 'i-dont-exist-evar' ) ); + } + + /** + * @covers ::wfMessage + * @covers Message::__construct + */ + public function testWfMessageParams() { + $this->assertEquals( 'Return to $1.', wfMessage( 'returnto' )->text() ); + $this->assertEquals( 'Return to $1.', wfMessage( 'returnto', array() )->text() ); + $this->assertEquals( + 'You have foo (bar).', + wfMessage( 'youhavenewmessages', 'foo', 'bar' )->text() + ); + $this->assertEquals( + 'You have foo (bar).', + wfMessage( 'youhavenewmessages', array( 'foo', 'bar' ) )->text() + ); } /** @@ -104,14 +205,42 @@ class MessageTest extends MediaWikiLangTestCase { /** * @covers Message::__construct + * @covers Message::text + * @covers Message::plain + * @covers Message::escaped + * @covers Message::toString */ - public function testKey() { - $this->assertInstanceOf( 'Message', wfMessage( 'mainpage' ) ); - $this->assertInstanceOf( 'Message', wfMessage( 'i-dont-exist-evar' ) ); + public function testToStringKey() { $this->assertEquals( 'Main Page', wfMessage( 'mainpage' )->text() ); - $this->assertEquals( '<i-dont-exist-evar>', wfMessage( 'i-dont-exist-evar' )->text() ); + $this->assertEquals( '<i-dont-exist-evar>', wfMessage( 'i-dont-exist-evar' )->text() ); + $this->assertEquals( '<i<dont>exist-evar>', wfMessage( 'i<dont>exist-evar' )->text() ); $this->assertEquals( '<i-dont-exist-evar>', wfMessage( 'i-dont-exist-evar' )->plain() ); + $this->assertEquals( '<i<dont>exist-evar>', wfMessage( 'i<dont>exist-evar' )->plain() ); $this->assertEquals( '<i-dont-exist-evar>', wfMessage( 'i-dont-exist-evar' )->escaped() ); + $this->assertEquals( + '<i<dont>exist-evar>', + wfMessage( 'i<dont>exist-evar' )->escaped() + ); + } + + public static function provideToString() { + return array( + array( 'mainpage', 'Main Page' ), + array( 'i-dont-exist-evar', '<i-dont-exist-evar>' ), + array( 'i-dont-exist-evar', '<i-dont-exist-evar>', 'escaped' ), + ); + } + + /** + * @covers Message::toString + * @covers Message::__toString + * @dataProvider provideToString + */ + public function testToString( $key, $expect, $format = 'plain' ) { + $msg = new Message( $key ); + $msg->$format(); + $this->assertEquals( $expect, $msg->toString() ); + $this->assertEquals( $expect, $msg->__toString() ); } /** @@ -132,26 +261,10 @@ class MessageTest extends MediaWikiLangTestCase { } /** - * @covers Message::__construct - */ - public function testMessageParams() { - $this->assertEquals( 'Return to $1.', wfMessage( 'returnto' )->text() ); - $this->assertEquals( 'Return to $1.', wfMessage( 'returnto', array() )->text() ); - $this->assertEquals( - 'You have foo (bar).', - wfMessage( 'youhavenewmessages', 'foo', 'bar' )->text() - ); - $this->assertEquals( - 'You have foo (bar).', - wfMessage( 'youhavenewmessages', array( 'foo', 'bar' ) )->text() - ); - } - - /** - * @covers Message::__construct + * @covers Message::rawParam * @covers Message::rawParams */ - public function testMessageParamSubstitution() { + public function testRawParams() { $this->assertEquals( '(Заглавная страница)', wfMessage( 'parentheses', 'Заглавная страница' )->plain() @@ -171,10 +284,21 @@ class MessageTest extends MediaWikiLangTestCase { } /** - * @covers Message::__construct + * @covers RawMessage::__construct + * @covers RawMessage::fetchMessage + */ + public function testRawMessage() { + $msg = new RawMessage( 'example &' ); + $this->assertEquals( 'example &', $msg->plain() ); + $this->assertEquals( 'example &', $msg->escaped() ); + } + + /** * @covers Message::params + * @covers Message::toString + * @covers Message::replaceParameters */ - public function testDeliciouslyManyParams() { + public function testReplaceManyParams() { $msg = new RawMessage( '$1$2$3$4$5$6$7$8$9$10$11$12' ); // One less than above has placeholders $params = array( 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k' ); @@ -183,12 +307,20 @@ class MessageTest extends MediaWikiLangTestCase { $msg->params( $params )->plain(), 'Params > 9 are replaced correctly' ); + + $msg = new RawMessage( 'Params$*' ); + $params = array( 'ab', 'bc', 'cd' ); + $this->assertEquals( + 'Params: ab, bc, cd', + $msg->params( $params )->text() + ); } /** + * @covers Message::numParam * @covers Message::numParams */ - public function testMessageNumParams() { + public function testNumParams() { $lang = Language::factory( 'en' ); $msg = new RawMessage( '$1' ); @@ -200,9 +332,10 @@ class MessageTest extends MediaWikiLangTestCase { } /** + * @covers Message::durationParam * @covers Message::durationParams */ - public function testMessageDurationParams() { + public function testDurationParams() { $lang = Language::factory( 'en' ); $msg = new RawMessage( '$1' ); @@ -216,9 +349,10 @@ class MessageTest extends MediaWikiLangTestCase { /** * FIXME: This should not need database, but Language#formatExpiry does (bug 55912) * @group Database + * @covers Message::expiryParam * @covers Message::expiryParams */ - public function testMessageExpiryParams() { + public function testExpiryParams() { $lang = Language::factory( 'en' ); $msg = new RawMessage( '$1' ); @@ -230,9 +364,10 @@ class MessageTest extends MediaWikiLangTestCase { } /** + * @covers Message::timeperiodParam * @covers Message::timeperiodParams */ - public function testMessageTimeperiodParams() { + public function testTimeperiodParams() { $lang = Language::factory( 'en' ); $msg = new RawMessage( '$1' ); @@ -244,9 +379,10 @@ class MessageTest extends MediaWikiLangTestCase { } /** + * @covers Message::sizeParam * @covers Message::sizeParams */ - public function testMessageSizeParams() { + public function testSizeParams() { $lang = Language::factory( 'en' ); $msg = new RawMessage( '$1' ); @@ -258,9 +394,10 @@ class MessageTest extends MediaWikiLangTestCase { } /** + * @covers Message::bitrateParam * @covers Message::bitrateParams */ - public function testMessageBitrateParams() { + public function testBitrateParams() { $lang = Language::factory( 'en' ); $msg = new RawMessage( '$1' ); @@ -271,6 +408,100 @@ class MessageTest extends MediaWikiLangTestCase { ); } + public static function providePlaintextParams() { + return array( + array( + 'one $2 <div>foo</div> [[Bar]] {{Baz}} <', + 'plain', + ), + + array( + // expect + 'one $2 <div>foo</div> [[Bar]] {{Baz}} <', + // format + 'text', + ), + array( + 'one $2 <div>foo</div> [[Bar]] {{Baz}} &lt;', + 'escaped', + ), + + array( + 'one $2 <div>foo</div> [[Bar]] {{Baz}} &lt;', + 'parse', + ), + + array( + "<p>one $2 <div>foo</div> [[Bar]] {{Baz}} &lt;\n</p>", + 'parseAsBlock', + ), + ); + } + + /** + * @covers Message::plaintextParam + * @covers Message::plaintextParams + * @covers Message::formatPlaintext + * @covers Message::toString + * @covers Message::parse + * @covers Message::parseAsBlock + * @dataProvider providePlaintextParams + */ + public function testPlaintextParams( $expect, $format ) { + $lang = Language::factory( 'en' ); + + $msg = new RawMessage( '$1 $2' ); + $params = array( + 'one $2', + '<div>foo</div> [[Bar]] {{Baz}} <', + ); + $this->assertEquals( + $expect, + $msg->inLanguage( $lang )->plaintextParams( $params )->$format(), + "Fail formatting for $format" + ); + } + + public static function provideParser() { + return array( + array( + "''&'' <x><!-- x -->", + 'plain', + ), + + array( + "''&'' <x><!-- x -->", + 'text', + ), + array( + '<i>&</i> <x>', + 'parse', + ), + + array( + "<p><i>&</i> <x>\n</p>", + 'parseAsBlock', + ), + ); + } + + /** + * @covers Message::text + * @covers Message::parse + * @covers Message::parseAsBlock + * @covers Message::toString + * @covers Message::transformText + * @covers Message::parseText + * @dataProvider provideParser + */ + public function testParser( $expect, $format ) { + $msg = new RawMessage( "''&'' <x><!-- x -->" ); + $this->assertEquals( + $expect, + $msg->inLanguage( 'en' )->$format() + ); + } + /** * @covers Message::inContentLanguage */ @@ -317,52 +548,4 @@ class MessageTest extends MediaWikiLangTestCase { public function testInLanguageThrows() { wfMessage( 'foo' )->inLanguage( 123 ); } - - public function keyProvider() { - return array( - 'string' => array( - 'key' => 'mainpage', - 'expected' => array( 'mainpage' ), - ), - 'single' => array( - 'key' => array( 'mainpage' ), - 'expected' => array( 'mainpage' ), - ), - 'multi' => array( - 'key' => array( 'mainpage-foo', 'mainpage-bar', 'mainpage' ), - 'expected' => array( 'mainpage-foo', 'mainpage-bar', 'mainpage' ), - ), - 'empty' => array( - 'key' => array(), - 'expected' => null, - 'exception' => 'InvalidArgumentException', - ), - 'null' => array( - 'key' => null, - 'expected' => null, - 'exception' => 'InvalidArgumentException', - ), - 'bad type' => array( - 'key' => 17, - 'expected' => null, - 'exception' => 'InvalidArgumentException', - ), - ); - } - - /** - * @dataProvider keyProvider() - * - * @covers Message::getKey - */ - public function testGetKey( $key, $expected, $exception = null ) { - if ( $exception ) { - $this->setExpectedException( $exception ); - } - - $msg = new Message( $key ); - $this->assertEquals( $expected, $msg->getKeysToTry() ); - $this->assertEquals( count( $expected ) > 1, $msg->isMultiKey() ); - $this->assertContains( $msg->getKey(), $expected ); - } } diff --git a/tests/phpunit/includes/MovePageTest.php b/tests/phpunit/includes/MovePageTest.php new file mode 100644 index 00000000..9501e452 --- /dev/null +++ b/tests/phpunit/includes/MovePageTest.php @@ -0,0 +1,63 @@ +<?php + +/** + * @group Database + */ +class MovePageTest extends MediaWikiTestCase { + + /** + * @dataProvider provideIsValidMove + * @covers MovePage::isValidMove + * @covers MovePage::isValidFileMove + */ + public function testIsValidMove( $old, $new, $error ) { + $this->setMwGlobals( 'wgContentHandlerUseDB', false ); + $mp = new MovePage( + Title::newFromText( $old ), + Title::newFromText( $new ) + ); + $status = $mp->isValidMove(); + if ( $error === true ) { + $this->assertTrue( $status->isGood() ); + } else { + $this->assertTrue( $status->hasMessage( $error ) ); + } + } + + /** + * This should be kept in sync with TitleTest::provideTestIsValidMoveOperation + */ + public static function provideIsValidMove() { + return array( + // for MovePage::isValidMove + array( 'Test', 'Test', 'selfmove' ), + array( 'Special:FooBar', 'Test', 'immobile-source-namespace' ), + array( 'Test', 'Special:FooBar', 'immobile-target-namespace' ), + array( 'MediaWiki:Common.js', 'Help:Some wikitext page', 'bad-target-model' ), + array( 'Page', 'File:Test.jpg', 'nonfile-cannot-move-to-file' ), + // for MovePage::isValidFileMove + array( 'File:Test.jpg', 'Page', 'imagenocrossnamespace' ), + ); + } + + /** + * Integration test to catch regressions like T74870. Taken and modified + * from SemanticMediaWiki + */ + public function testTitleMoveCompleteIntegrationTest() { + $oldTitle = Title::newFromText( 'Help:Some title' ); + WikiPage::factory( $oldTitle )->doEditContent( new WikitextContent( 'foo' ), 'bar' ); + $newTitle = Title::newFromText( 'Help:Some other title' ); + $this->assertNull( + WikiPage::factory( $newTitle )->getRevision() + ); + + $this->assertTrue( $oldTitle->moveTo( $newTitle, false, 'test1', true ) ); + $this->assertNotNull( + WikiPage::factory( $oldTitle )->getRevision() + ); + $this->assertNotNull( + WikiPage::factory( $newTitle)->getRevision() + ); + } +} diff --git a/tests/phpunit/includes/OutputPageTest.php b/tests/phpunit/includes/OutputPageTest.php index d7e8cd31..6c6d95ee 100644 --- a/tests/phpunit/includes/OutputPageTest.php +++ b/tests/phpunit/includes/OutputPageTest.php @@ -172,18 +172,18 @@ mw.test.baz({token:123});mw.loader.state({"test.quux":"ready"}); array( array( 'test.quux', ResourceLoaderModule::TYPE_COMBINED ), '<script>if(window.mw){ -mw.loader.implement("test.quux",function($,jQuery){mw.test.baz({token:123});},{"css":[".mw-icon{transition:none}\n"]},{}); +mw.loader.implement("test.quux",function($,jQuery){mw.test.baz({token:123});},{"css":[".mw-icon{transition:none}\n"]}); }</script> ' ), - // Load module script with with ESI + // Load module script with ESI array( array( 'test.foo', ResourceLoaderModule::TYPE_SCRIPTS, true ), '<script><esi:include src="http://127.0.0.1:8080/w/load.php?debug=false&lang=en&modules=test.foo&only=scripts&skin=fallback&*" /></script> ' ), - // Load module styles with with ESI + // Load module styles with ESI array( array( 'test.foo', ResourceLoaderModule::TYPE_STYLES, true ), '<style><esi:include src="http://127.0.0.1:8080/w/load.php?debug=false&lang=en&modules=test.foo&only=styles&skin=fallback&*" /></style> @@ -203,9 +203,13 @@ mw.loader.implement("test.quux",function($,jQuery){mw.test.baz({token:123});},{" // Load two modules in separate groups array( array( array( 'test.group.foo', 'test.group.bar' ), ResourceLoaderModule::TYPE_COMBINED ), - '<script src="http://127.0.0.1:8080/w/load.php?debug=false&lang=en&modules=test.group.bar&skin=fallback&*"></script> -<script src="http://127.0.0.1:8080/w/load.php?debug=false&lang=en&modules=test.group.foo&skin=fallback&*"></script> -', + '<script>if(window.mw){ +document.write("\u003Cscript src=\"http://127.0.0.1:8080/w/load.php?debug=false\u0026amp;lang=en\u0026amp;modules=test.group.bar\u0026amp;skin=fallback\u0026amp;*\"\u003E\u003C/script\u003E"); +}</script> +<script>if(window.mw){ +document.write("\u003Cscript src=\"http://127.0.0.1:8080/w/load.php?debug=false\u0026amp;lang=en\u0026amp;modules=test.group.foo\u0026amp;skin=fallback\u0026amp;*\"\u003E\u003C/script\u003E"); +}</script> +' ), ); } @@ -213,6 +217,11 @@ mw.loader.implement("test.quux",function($,jQuery){mw.test.baz({token:123});},{" /** * @dataProvider provideMakeResourceLoaderLink * @covers OutputPage::makeResourceLoaderLink + * @covers ResourceLoader::makeLoaderImplementScript + * @covers ResourceLoader::makeModuleResponse + * @covers ResourceLoader::makeInlineScript + * @covers ResourceLoader::makeLoaderStateScript + * @covers ResourceLoader::createLoaderURL */ public function testMakeResourceLoaderLink( $args, $expectedHtml ) { $this->setMwGlobals( array( @@ -230,6 +239,7 @@ mw.loader.implement("test.quux",function($,jQuery){mw.test.baz({token:123});},{" $ctx->setLanguage( 'en' ); $out = new OutputPage( $ctx ); $rl = $out->getResourceLoader(); + $rl->setMessageBlobStore( new NullMessageBlobStore() ); $rl->register( array( 'test.foo' => new ResourceLoaderTestModule( array( 'script' => 'mw.test.foo( { a: true } );', @@ -271,3 +281,26 @@ mw.loader.implement("test.quux",function($,jQuery){mw.test.baz({token:123});},{" $this->assertEquals( $expectedHtml, $actualHtml ); } } + +/** + * MessageBlobStore that doesn't do anything + */ +class NullMessageBlobStore extends MessageBlobStore { + public function get ( ResourceLoader $resourceLoader, $modules, $lang ) { + return array(); + } + + public function insertMessageBlob ( $name, ResourceLoaderModule $module, $lang ) { + return false; + } + + public function updateModule ( $name, ResourceLoaderModule $module, $lang ) { + return; + } + + public function updateMessage ( $key ) { + } + public function clear() { + } +} + diff --git a/tests/phpunit/includes/PrefixSearchTest.php b/tests/phpunit/includes/PrefixSearchTest.php new file mode 100644 index 00000000..d63541b7 --- /dev/null +++ b/tests/phpunit/includes/PrefixSearchTest.php @@ -0,0 +1,306 @@ +<?php +/** + * @group Search + * @group Database + */ +class PrefixSearchTest extends MediaWikiLangTestCase { + + public function addDBData() { + $this->insertPage( 'Sandbox' ); + $this->insertPage( 'Bar' ); + $this->insertPage( 'Example' ); + $this->insertPage( 'Example Bar' ); + $this->insertPage( 'Example Foo' ); + $this->insertPage( 'Example Foo/Bar' ); + $this->insertPage( 'Example/Baz' ); + $this->insertPage( 'Redirect test', '#REDIRECT [[Redirect Test]]' ); + $this->insertPage( 'Redirect Test' ); + $this->insertPage( 'Redirect Test Worse Result' ); + $this->insertPage( 'Redirect test2', '#REDIRECT [[Redirect Test2]]' ); + $this->insertPage( 'Redirect TEST2', '#REDIRECT [[Redirect Test2]]' ); + $this->insertPage( 'Redirect Test2' ); + $this->insertPage( 'Redirect Test2 Worse Result' ); + + $this->insertPage( 'Talk:Sandbox' ); + $this->insertPage( 'Talk:Example' ); + + $this->insertPage( 'User:Example' ); + } + + protected function setUp() { + parent::setUp(); + + if ( !$this->isWikitextNS( NS_MAIN ) ) { + $this->markTestSkipped( 'Main namespace does not support wikitext.' ); + } + + // Avoid special pages from extensions interferring with the tests + $this->setMwGlobals( 'wgSpecialPages', array() ); + } + + protected function searchProvision( Array $results = null ) { + if ( $results === null ) { + $this->setMwGlobals( 'wgHooks', array() ); + } else { + $this->setMwGlobals( 'wgHooks', array( + 'PrefixSearchBackend' => array( + function ( $namespaces, $search, $limit, &$srchres ) use ( $results ) { + $srchres = $results; + return false; + } + ), + ) ); + } + } + + public static function provideSearch() { + return array( + array( array( + 'Empty string', + 'query' => '', + 'results' => array(), + ) ), + array( array( + 'Main namespace with title prefix', + 'query' => 'Ex', + 'results' => array( + 'Example', + 'Example/Baz', + 'Example Bar', + ), + // Third result when testing offset + 'offsetresult' => array( + 'Example Foo', + ), + ) ), + array( array( + 'Talk namespace prefix', + 'query' => 'Talk:', + 'results' => array( + 'Talk:Example', + 'Talk:Sandbox', + ), + ) ), + array( array( + 'User namespace prefix', + 'query' => 'User:', + 'results' => array( + 'User:Example', + ), + ) ), + array( array( + 'Special namespace prefix', + 'query' => 'Special:', + 'results' => array( + 'Special:ActiveUsers', + 'Special:AllMessages', + 'Special:AllMyFiles', + ), + // Third result when testing offset + 'offsetresult' => array( + 'Special:AllMyUploads', + ), + ) ), + array( array( + 'Special namespace with prefix', + 'query' => 'Special:Un', + 'results' => array( + 'Special:Unblock', + 'Special:UncategorizedCategories', + 'Special:UncategorizedFiles', + ), + // Third result when testing offset + 'offsetresult' => array( + 'Special:UncategorizedImages', + ), + ) ), + array( array( + 'Special page name', + 'query' => 'Special:EditWatchlist', + 'results' => array( + 'Special:EditWatchlist', + ), + ) ), + array( array( + 'Special page subpages', + 'query' => 'Special:EditWatchlist/', + 'results' => array( + 'Special:EditWatchlist/clear', + 'Special:EditWatchlist/raw', + ), + ) ), + array( array( + 'Special page subpages with prefix', + 'query' => 'Special:EditWatchlist/cl', + 'results' => array( + 'Special:EditWatchlist/clear', + ), + ) ), + ); + } + + /** + * @dataProvider provideSearch + * @covers PrefixSearch::search + * @covers PrefixSearch::searchBackend + */ + public function testSearch( Array $case ) { + $this->searchProvision( null ); + $searcher = new StringPrefixSearch; + $results = $searcher->search( $case['query'], 3 ); + $this->assertEquals( + $case['results'], + $results, + $case[0] + ); + } + + /** + * @dataProvider provideSearch + * @covers PrefixSearch::search + * @covers PrefixSearch::searchBackend + */ + public function testSearchWithOffset( Array $case ) { + $this->searchProvision( null ); + $searcher = new StringPrefixSearch; + $results = $searcher->search( $case['query'], 3, array(), 1 ); + + // We don't expect the first result when offsetting + array_shift( $case['results'] ); + // And sometimes we expect a different last result + $expected = isset( $case['offsetresult'] ) ? + array_merge( $case['results'], $case['offsetresult'] ) : + $case['results']; + + $this->assertEquals( + $expected, + $results, + $case[0] + ); + } + + public static function provideSearchBackend() { + return array( + array( array( + 'Simple case', + 'provision' => array( + 'Bar', + 'Barcelona', + 'Barbara', + ), + 'query' => 'Bar', + 'results' => array( + 'Bar', + 'Barcelona', + 'Barbara', + ), + ) ), + array( array( + 'Exact match not on top (bug 70958)', + 'provision' => array( + 'Barcelona', + 'Bar', + 'Barbara', + ), + 'query' => 'Bar', + 'results' => array( + 'Bar', + 'Barcelona', + 'Barbara', + ), + ) ), + array( array( + 'Exact match missing (bug 70958)', + 'provision' => array( + 'Barcelona', + 'Barbara', + 'Bart', + ), + 'query' => 'Bar', + 'results' => array( + 'Bar', + 'Barcelona', + 'Barbara', + ), + ) ), + array( array( + 'Exact match missing and not existing', + 'provision' => array( + 'Exile', + 'Exist', + 'External', + ), + 'query' => 'Ex', + 'results' => array( + 'Exile', + 'Exist', + 'External', + ), + ) ), + array( array( + "Exact match shouldn't override already found match if " . + "exact is redirect and found isn't", + 'provision' => array( + // Target of the exact match is low in the list + 'Redirect Test Worse Result', + 'Redirect Test', + ), + 'query' => 'redirect test', + 'results' => array( + // Redirect target is pulled up and exact match isn't added + 'Redirect Test', + 'Redirect Test Worse Result', + ), + ) ), + array( array( + "Exact match shouldn't override already found match if " . + "both exact match and found match are redirect", + 'provision' => array( + // Another redirect to the same target as the exact match + // is low in the list + 'Redirect Test2 Worse Result', + 'Redirect test2', + ), + 'query' => 'redirect TEST2', + 'results' => array( + // Found redirect is pulled to the top and exact match isn't + // added + 'Redirect test2', + 'Redirect Test2 Worse Result', + ), + ) ), + array( array( + "Exact match should override any already found matches that " . + "are redirects to it", + 'provision' => array( + // Another redirect to the same target as the exact match + // is low in the list + 'Redirect Test Worse Result', + 'Redirect test', + ), + 'query' => 'Redirect Test', + 'results' => array( + // Found redirect is pulled to the top and exact match isn't + // added + 'Redirect Test', + 'Redirect Test Worse Result', + ), + ) ), + ); + } + + /** + * @dataProvider provideSearchBackend + * @covers PrefixSearch::searchBackend + */ + public function testSearchBackend( Array $case ) { + $this->searchProvision( $case['provision'] ); + $searcher = new StringPrefixSearch; + $results = $searcher->search( $case['query'], 3 ); + $this->assertEquals( + $case['results'], + $results, + $case[0] + ); + } +} diff --git a/tests/phpunit/includes/SampleTest.php b/tests/phpunit/includes/SampleTest.php index 25858110..c5944d16 100644 --- a/tests/phpunit/includes/SampleTest.php +++ b/tests/phpunit/includes/SampleTest.php @@ -97,7 +97,7 @@ class TestSample extends MediaWikiLangTestCase { // @codingStandardsIgnoreStart Ignore long line warning /** - * @expectedException MWException object + * @expectedException InvalidArgumentException * See http://phpunit.de/manual/3.7/en/appendixes.annotations.html#appendixes.annotations.expectedException */ // @codingStandardsIgnoreEnd diff --git a/tests/phpunit/includes/SanitizerTest.php b/tests/phpunit/includes/SanitizerTest.php index 50c1e509..c615c460 100644 --- a/tests/phpunit/includes/SanitizerTest.php +++ b/tests/phpunit/includes/SanitizerTest.php @@ -6,12 +6,6 @@ */ class SanitizerTest extends MediaWikiTestCase { - protected function setUp() { - parent::setUp(); - - AutoLoader::loadClass( 'Sanitizer' ); - } - /** * @covers Sanitizer::decodeCharReferences */ @@ -85,7 +79,7 @@ class SanitizerTest extends MediaWikiTestCase { */ public function testInvalidNumberedEntities() { $this->assertEquals( - UTF8_REPLACEMENT, + UtfNormal\Constants::UTF8_REPLACEMENT, Sanitizer::decodeCharReferences( "�" ), 'Invalid numbered entity' ); @@ -346,4 +340,25 @@ class SanitizerTest extends MediaWikiTestCase { $message ); } + + /** + * @dataProvider provideEscapeHtmlAllowEntities + * @covers Sanitizer::escapeHtmlAllowEntities + */ + public function testEscapeHtmlAllowEntities( $expected, $html ) { + $this->assertEquals( + $expected, + Sanitizer::escapeHtmlAllowEntities( $html ) + ); + } + + public static function provideEscapeHtmlAllowEntities() { + return array( + array( 'foo', 'foo' ), + array( 'a¡b', 'a¡b' ), + array( 'foo'bar', "foo'bar" ), + array( '<script>foo</script>', '<script>foo</script>' ), + ); + } + } diff --git a/tests/phpunit/includes/StatusTest.php b/tests/phpunit/includes/StatusTest.php index 628c59b6..c013f4fc 100644 --- a/tests/phpunit/includes/StatusTest.php +++ b/tests/phpunit/includes/StatusTest.php @@ -57,6 +57,17 @@ class StatusTest extends MediaWikiLangTestCase { } /** + * + */ + public function testOkAndErrors() { + $status = Status::newGood( 'foo' ); + $this->assertTrue( $status->ok ); + $status = Status::newFatal( 'foo', 1, 2 ); + $this->assertFalse( $status->ok ); + $this->assertArrayEquals( array( array( 'type' => 'error', 'message' => 'foo', 'params' => array( 1, 2 ) ) ), $status->errors ); + } + + /** * @dataProvider provideSetResult * @covers Status::setResult */ @@ -109,7 +120,9 @@ class StatusTest extends MediaWikiLangTestCase { public function testIsGood( $ok, $errors, $expected ) { $status = new Status(); $status->ok = $ok; - $status->errors = $errors; + foreach ( $errors as $error ) { + $status->warning( $error ); + } $this->assertEquals( $expected, $status->isGood() ); } diff --git a/tests/phpunit/includes/TemplateParserTest.php b/tests/phpunit/includes/TemplateParserTest.php new file mode 100644 index 00000000..81854ff3 --- /dev/null +++ b/tests/phpunit/includes/TemplateParserTest.php @@ -0,0 +1,63 @@ +<?php + +/** + * @group Templates + */ +class TemplateParserTest extends MediaWikiTestCase { + + protected $templateDir; + + protected function setUp() { + parent::setUp(); + + $this->setMwGlobals( array( + 'wgSecretKey' => 'foo', + 'wgMemc' => new EmptyBagOStuff(), + ) ); + + $this->templateDir = dirname( __DIR__ ) . '/data/templates/'; + } + + /** + * @dataProvider provideProcessTemplate + * @covers TemplateParser::processTemplate + * @covers TemplateParser::getTemplate + * @covers TemplateParser::getTemplateFilename + */ + public function testProcessTemplate( $name, $args, $result, $exception = false ) { + if ( $exception ) { + $this->setExpectedException( $exception ); + } + $tp = new TemplateParser( $this->templateDir ); + $this->assertEquals( $result, $tp->processTemplate( $name, $args ) ); + } + + public static function provideProcessTemplate() { + return array( + array( + 'foobar', + array(), + "hello world!\n" + ), + array( + 'foobar_args', + array( + 'planet' => 'world', + ), + "hello world!\n", + ), + array( + '../foobar', + array(), + false, + 'UnexpectedValueException' + ), + array( + 'nonexistenttemplate', + array(), + false, + 'RuntimeException', + ) + ); + } +} diff --git a/tests/phpunit/includes/TestUser.php b/tests/phpunit/includes/TestUser.php index 610a6acd..754568d0 100644 --- a/tests/phpunit/includes/TestUser.php +++ b/tests/phpunit/includes/TestUser.php @@ -5,24 +5,41 @@ * like password if we log in via the API. */ class TestUser { + /** + * @deprecated Since 1.25. Use TestUser::getUser()->getName() + * @private + * @var string + */ public $username; + + /** + * @deprecated Since 1.25. Use TestUser::getPassword() + * @private + * @var string + */ public $password; - public $email; - public $groups; + + /** + * @deprecated Since 1.25. Use TestUser::getUser() + * @private + * @var User + */ public $user; + private function assertNotReal() { + global $wgDBprefix; + if ( $wgDBprefix !== MediaWikiTestCase::DB_PREFIX && $wgDBprefix !== MediaWikiTestCase::ORA_DB_PREFIX ) { + throw new MWException( "Can't create user on real database" ); + } + } + public function __construct( $username, $realname = 'Real Name', $email = 'sample@example.com', $groups = array() ) { - $this->username = $username; - $this->realname = $realname; - $this->email = $email; - $this->groups = $groups; + $this->assertNotReal(); - // don't allow user to hardcode or select passwords -- people sometimes run tests - // on live wikis. Sometimes we create sysop users in these tests. A sysop user with - // a known password would be a Bad Thing. - $this->password = User::randomPassword(); + $this->username = $username; + $this->password = 'TestUser'; $this->user = User::newFromName( $this->username ); $this->user->load(); @@ -31,32 +48,99 @@ class TestUser { // But for now, we just need to create or update the user with the desired properties. // we particularly need the new password, since we just generated it randomly. // In core MediaWiki, there is no functionality to delete users, so this is the best we can do. - if ( !$this->user->getID() ) { + if ( !$this->user->isLoggedIn() ) { // create the user $this->user = User::createNew( $this->username, array( - "email" => $this->email, - "real_name" => $this->realname + "email" => $email, + "real_name" => $realname ) ); + if ( !$this->user ) { - throw new Exception( "error creating user" ); + throw new MWException( "Error creating TestUser " . $username ); } } - // update the user to use the new random password and other details - $this->user->setPassword( $this->password ); - $this->user->setEmail( $this->email ); - $this->user->setRealName( $this->realname ); + // Update the user to use the password and other details + $change = $this->setPassword( $this->password ) || + $this->setEmail( $email ) || + $this->setRealName( $realname ); // Adjust groups by adding any missing ones and removing any extras $currentGroups = $this->user->getGroups(); - foreach ( array_diff( $this->groups, $currentGroups ) as $group ) { + foreach ( array_diff( $groups, $currentGroups ) as $group ) { $this->user->addGroup( $group ); } - foreach ( array_diff( $currentGroups, $this->groups ) as $group ) { + foreach ( array_diff( $currentGroups, $groups ) as $group ) { $this->user->removeGroup( $group ); } - $this->user->saveSettings(); + if ( $change ) { + $this->user->saveSettings(); + } + } + + /** + * @param string $realname + * @return bool + */ + private function setRealName( $realname ) { + if ( $this->user->getRealName() !== $realname ) { + $this->user->setRealName( $realname ); + return true; + } + + return false; + } + + /** + * @param string $email + * @return bool + */ + private function setEmail( $email ) { + if ( $this->user->getEmail() !== $email ) { + $this->user->setEmail( $email ); + return true; + } + + return false; + } + + /** + * @param string $password + * @return bool + */ + private function setPassword( $password ) { + $passwordFactory = $this->user->getPasswordFactory(); + $oldDefaultType = $passwordFactory->getDefaultType(); + + // A is unsalted MD5 (thus fast) ... we don't care about security here, this is test only + $passwordFactory->setDefaultType( 'A' ); + $newPassword = $passwordFactory->newFromPlaintext( $password, $this->user->getPassword() ); + + $change = false; + if ( !$this->user->getPassword()->equals( $newPassword ) ) { + // Password changed + $this->user->setPassword( $password ); + $change = true; + } + + $passwordFactory->setDefaultType( $oldDefaultType ); + + return $change; + } + + /** + * @return User + */ + public function getUser() { + return $this->user; + } + + /** + * @return string + */ + public function getPassword() { + return $this->password; } } diff --git a/tests/phpunit/includes/TestingAccessWrapper.php b/tests/phpunit/includes/TestingAccessWrapper.php new file mode 100644 index 00000000..84c0f9b5 --- /dev/null +++ b/tests/phpunit/includes/TestingAccessWrapper.php @@ -0,0 +1,50 @@ +<?php +/** + * Circumvent access restrictions on object internals + * + * This can be helpful for writing tests that can probe object internals, + * without having to modify the class under test to accomodate. + * + * Wrap an object with private methods as follows: + * $title = TestingAccessWrapper::newFromObject( Title::newFromDBkey( $key ) ); + * + * You can access private and protected instance methods and variables: + * $formatter = $title->getTitleFormatter(); + * + * TODO: + * - Provide access to static methods and properties. + * - Organize other helper classes in tests/testHelpers.inc into a directory. + */ +class TestingAccessWrapper { + public $object; + + /** + * Return the same object, without access restrictions. + */ + public static function newFromObject( $object ) { + $wrapper = new TestingAccessWrapper(); + $wrapper->object = $object; + return $wrapper; + } + + public function __call( $method, $args ) { + $classReflection = new ReflectionClass( $this->object ); + $methodReflection = $classReflection->getMethod( $method ); + $methodReflection->setAccessible( true ); + return $methodReflection->invokeArgs( $this->object, $args ); + } + + public function __set( $name, $value ) { + $classReflection = new ReflectionClass( $this->object ); + $propertyReflection = $classReflection->getProperty( $name ); + $propertyReflection->setAccessible( true ); + $propertyReflection->setValue( $this->object, $value ); + } + + public function __get( $name ) { + $classReflection = new ReflectionClass( $this->object ); + $propertyReflection = $classReflection->getProperty( $name ); + $propertyReflection->setAccessible( true ); + return $propertyReflection->getValue( $this->object ); + } +} diff --git a/tests/phpunit/includes/TestingAccessWrapperTest.php b/tests/phpunit/includes/TestingAccessWrapperTest.php new file mode 100644 index 00000000..7e5b91a1 --- /dev/null +++ b/tests/phpunit/includes/TestingAccessWrapperTest.php @@ -0,0 +1,34 @@ +<?php + +class TestingAccessWrapperTest extends MediaWikiTestCase { + protected $raw; + protected $wrapped; + + function setUp() { + parent::setUp(); + + require_once __DIR__ . '/../data/helpers/WellProtectedClass.php'; + $this->raw = new WellProtectedClass(); + $this->wrapped = TestingAccessWrapper::newFromObject( $this->raw ); + } + + function testGetProperty() { + $this->assertSame( 1, $this->wrapped->property ); + } + + function testSetProperty() { + $this->wrapped->property = 10; + $this->assertSame( 10, $this->wrapped->property ); + $this->assertSame( 10, $this->raw->getProperty() ); + } + + function testCallMethod() { + $this->wrapped->incrementPropertyValue(); + $this->assertSame( 2, $this->wrapped->property ); + $this->assertSame( 2, $this->raw->getProperty() ); + } + + function testCallMethodTwoArgs() { + $this->assertSame( 'two', $this->wrapped->whatSecondArg( 'one', 'two' ) ); + } +} diff --git a/tests/phpunit/includes/TitleMethodsTest.php b/tests/phpunit/includes/TitleMethodsTest.php index 5904facd..e186438b 100644 --- a/tests/phpunit/includes/TitleMethodsTest.php +++ b/tests/phpunit/includes/TitleMethodsTest.php @@ -7,7 +7,7 @@ * @note We don't make assumptions about the main namespace. * But we do expect the Help namespace to contain Wikitext. */ -class TitleMethodsTest extends MediaWikiTestCase { +class TitleMethodsTest extends MediaWikiLangTestCase { protected function setUp() { global $wgContLang; @@ -297,4 +297,43 @@ class TitleMethodsTest extends MediaWikiTestCase { $title = Title::newFromText( $title ); $this->assertEquals( $expectedBool, $title->isWikitextPage() ); } + + public static function provideGetOtherPage() { + return array( + array( 'Main Page', 'Talk:Main Page' ), + array( 'Talk:Main Page', 'Main Page' ), + array( 'Help:Main Page', 'Help talk:Main Page' ), + array( 'Help talk:Main Page', 'Help:Main Page' ), + array( 'Special:FooBar', null ), + ); + } + + /** + * @dataProvider provideGetOtherpage + * @covers Title::getOtherPage + * + * @param string $text + * @param string|null $expected + */ + public function testGetOtherPage( $text, $expected ) { + if ( $expected === null ) { + $this->setExpectedException( 'MWException' ); + } + + $title = Title::newFromText( $text ); + $this->assertEquals( $expected, $title->getOtherPage()->getPrefixedText() ); + } + + public function testClearCaches() { + $linkCache = LinkCache::singleton(); + + $title1 = Title::newFromText( 'Foo' ); + $linkCache->addGoodLinkObj( 23, $title1 ); + + Title::clearCaches(); + + $title2 = Title::newFromText( 'Foo' ); + $this->assertNotSame( $title1, $title2, 'title cache should be empty' ); + $this->assertEquals( 0, $linkCache->getGoodLinkID( 'Foo' ), 'link cache should be empty' ); + } } diff --git a/tests/phpunit/includes/TitlePermissionTest.php b/tests/phpunit/includes/TitlePermissionTest.php index d2400b3f..022c7d53 100644 --- a/tests/phpunit/includes/TitlePermissionTest.php +++ b/tests/phpunit/includes/TitlePermissionTest.php @@ -326,6 +326,10 @@ class TitlePermissionTest extends MediaWikiLangTestCase { $this->setUserPerm( null ); $this->assertEquals( $check[$action][0], $this->title->getUserPermissionsErrors( $action, $this->user, true ) ); + $this->assertEquals( $check[$action][0], + $this->title->getUserPermissionsErrors( $action, $this->user, 'full' ) ); + $this->assertEquals( $check[$action][0], + $this->title->getUserPermissionsErrors( $action, $this->user, 'secure' ) ); global $wgGroupPermissions; $old = $wgGroupPermissions; @@ -333,11 +337,19 @@ class TitlePermissionTest extends MediaWikiLangTestCase { $this->assertEquals( $check[$action][1], $this->title->getUserPermissionsErrors( $action, $this->user, true ) ); + $this->assertEquals( $check[$action][1], + $this->title->getUserPermissionsErrors( $action, $this->user, 'full' ) ); + $this->assertEquals( $check[$action][1], + $this->title->getUserPermissionsErrors( $action, $this->user, 'secure' ) ); $wgGroupPermissions = $old; $this->setUserPerm( $action ); $this->assertEquals( $check[$action][2], $this->title->getUserPermissionsErrors( $action, $this->user, true ) ); + $this->assertEquals( $check[$action][2], + $this->title->getUserPermissionsErrors( $action, $this->user, 'full' ) ); + $this->assertEquals( $check[$action][2], + $this->title->getUserPermissionsErrors( $action, $this->user, 'secure' ) ); $this->setUserPerm( $action ); $this->assertEquals( $check[$action][3], @@ -403,7 +415,8 @@ class TitlePermissionTest extends MediaWikiLangTestCase { $this->setTitle( NS_USER ); $this->setUserPerm( '' ); - $this->assertEquals( array( array( 'badaccess-group0' ), array( 'namespaceprotected', 'User', 'bogus' ) ), + $this->assertEquals( array( array( 'badaccess-group0' ), + array( 'namespaceprotected', 'User', 'bogus' ) ), $this->title->getUserPermissionsErrors( 'bogus', $this->user ) ); $this->setTitle( NS_MEDIAWIKI ); @@ -630,7 +643,8 @@ class TitlePermissionTest extends MediaWikiLangTestCase { $this->assertEquals( false, $this->title->userCan( 'bogus', $this->user ) ); - $this->assertEquals( array( array( "cascadeprotected", 2, "* [[:Bogus]]\n* [[:UnBogus]]\n", 'bogus' ), + $this->assertEquals( array( + array( "cascadeprotected", 2, "* [[:Bogus]]\n* [[:UnBogus]]\n", 'bogus' ), array( "cascadeprotected", 2, "* [[:Bogus]]\n* [[:UnBogus]]\n", 'bogus' ), array( "cascadeprotected", 2, "* [[:Bogus]]\n* [[:UnBogus]]\n", 'bogus' ) ), $this->title->getUserPermissionsErrors( 'bogus', $this->user ) ); @@ -648,10 +662,10 @@ class TitlePermissionTest extends MediaWikiLangTestCase { public function testActionPermissions() { $this->setUserPerm( array( "createpage" ) ); $this->setTitle( NS_MAIN, "test page" ); - $this->title->mTitleProtection['pt_create_perm'] = ''; - $this->title->mTitleProtection['pt_user'] = $this->user->getID(); - $this->title->mTitleProtection['pt_expiry'] = wfGetDB( DB_SLAVE )->getInfinity(); - $this->title->mTitleProtection['pt_reason'] = 'test'; + $this->title->mTitleProtection['permission'] = ''; + $this->title->mTitleProtection['user'] = $this->user->getID(); + $this->title->mTitleProtection['expiry'] = wfGetDB( DB_SLAVE )->getInfinity(); + $this->title->mTitleProtection['reason'] = 'test'; $this->title->mCascadeRestriction = false; $this->assertEquals( array( array( 'titleprotected', 'Useruser', 'test' ) ), @@ -659,7 +673,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase { $this->assertEquals( false, $this->title->userCan( 'create', $this->user ) ); - $this->title->mTitleProtection['pt_create_perm'] = 'sysop'; + $this->title->mTitleProtection['permission'] = 'editprotected'; $this->setUserPerm( array( 'createpage', 'protect' ) ); $this->assertEquals( array( array( 'titleprotected', 'Useruser', 'test' ) ), $this->title->getUserPermissionsErrors( 'create', $this->user ) ); diff --git a/tests/phpunit/includes/TitleTest.php b/tests/phpunit/includes/TitleTest.php index fb58381f..d55f958b 100644 --- a/tests/phpunit/includes/TitleTest.php +++ b/tests/phpunit/includes/TitleTest.php @@ -14,6 +14,7 @@ class TitleTest extends MediaWikiTestCase { 'wgLang' => Language::factory( 'en' ), 'wgAllowUserJs' => false, 'wgDefaultLanguageVariant' => false, + 'wgMetaNamespace' => 'Project', ) ); } @@ -324,36 +325,19 @@ class TitleTest extends MediaWikiTestCase { $whitelistRegexp = array( $whitelistRegexp ); } + $this->setMwGlobals( array( + // So User::isEveryoneAllowed( 'read' ) === false + 'wgGroupPermissions' => array( '*' => array( 'read' => false ) ), + 'wgWhitelistRead' => array( 'some random non sense title' ), + 'wgWhitelistReadRegexp' => $whitelistRegexp, + ) ); + $title = Title::newFromDBkey( $source ); - global $wgGroupPermissions; - $oldPermissions = $wgGroupPermissions; - // Disallow all so we can ensure our regex works - $wgGroupPermissions = array(); - $wgGroupPermissions['*']['read'] = false; - - global $wgWhitelistRead; - $oldWhitelist = $wgWhitelistRead; - // Undo any LocalSettings explicite whitelists so they won't cause a - // failing test to succeed. Set it to some random non sense just - // to make sure we properly test Title::checkReadPermissions() - $wgWhitelistRead = array( 'some random non sense title' ); - - global $wgWhitelistReadRegexp; - $oldWhitelistRegexp = $wgWhitelistReadRegexp; - $wgWhitelistReadRegexp = $whitelistRegexp; - - // Just use $wgUser which in test is a user object for '127.0.0.1' - global $wgUser; - // Invalidate user rights cache to take in account $wgGroupPermissions - // change above. - $wgUser->clearInstanceCache(); - $errors = $title->userCan( $action, $wgUser ); - - // Restore globals - $wgGroupPermissions = $oldPermissions; - $wgWhitelistRead = $oldWhitelist; - $wgWhitelistReadRegexp = $oldWhitelistRegexp; + // New anonymous user with no rights + $user = new User; + $user->mRights = array(); + $errors = $title->userCan( $action, $user ); if ( is_bool( $expected ) ) { # Forge the assertion message depending on the assertion expectation @@ -428,14 +412,14 @@ class TitleTest extends MediaWikiTestCase { public function testGetPageViewLanguage( $expected, $titleText, $contLang, $lang, $variant, $msg = '' ) { - global $wgLanguageCode, $wgContLang, $wgLang, $wgDefaultLanguageVariant, $wgAllowUserJs; - // Setup environnement for this test - $wgLanguageCode = $contLang; - $wgContLang = Language::factory( $contLang ); - $wgLang = Language::factory( $lang ); - $wgDefaultLanguageVariant = $variant; - $wgAllowUserJs = true; + $this->setMwGlobals( array( + 'wgLanguageCode' => $contLang, + 'wgContLang' => Language::factory( $contLang ), + 'wgLang' => Language::factory( $lang ), + 'wgDefaultLanguageVariant' => $variant, + 'wgAllowUserJs' => true, + ) ); $title = Title::newFromText( $titleText ); $this->assertInstanceOf( 'Title', $title, diff --git a/tests/phpunit/includes/UserTest.php b/tests/phpunit/includes/UserTest.php index af95a721..b74a7ead 100644 --- a/tests/phpunit/includes/UserTest.php +++ b/tests/phpunit/includes/UserTest.php @@ -214,8 +214,10 @@ class UserTest extends MediaWikiTestCase { */ public function testEditCount() { $user = User::newFromName( 'UnitTestUser' ); - $user->loadDefaults(); - $user->addToDatabase(); + + if ( !$user->getId() ) { + $user->addToDatabase(); + } // let the user have a few (3) edits $page = WikiPage::factory( Title::newFromText( 'Help:UserTest_EditCount' ) ); @@ -248,14 +250,17 @@ class UserTest extends MediaWikiTestCase { */ public function testOptions() { $user = User::newFromName( 'UnitTestUser' ); - $user->addToDatabase(); - $user->setOption( 'someoption', 'test' ); + if ( !$user->getId() ) { + $user->addToDatabase(); + } + + $user->setOption( 'userjs-someoption', 'test' ); $user->setOption( 'cols', 200 ); $user->saveSettings(); $user = User::newFromName( 'UnitTestUser' ); - $this->assertEquals( 'test', $user->getOption( 'someoption' ) ); + $this->assertEquals( 'test', $user->getOption( 'userjs-someoption' ) ); $this->assertEquals( 200, $user->getOption( 'cols' ) ); } @@ -266,9 +271,9 @@ class UserTest extends MediaWikiTestCase { */ public function testAnonOptions() { global $wgDefaultUserOptions; - $this->user->setOption( 'someoption', 'test' ); + $this->user->setOption( 'userjs-someoption', 'test' ); $this->assertEquals( $wgDefaultUserOptions['cols'], $this->user->getOption( 'cols' ) ); - $this->assertEquals( 'test', $this->user->getOption( 'someoption' ) ); + $this->assertEquals( 'test', $this->user->getOption( 'userjs-someoption' ) ); } /** @@ -276,12 +281,10 @@ class UserTest extends MediaWikiTestCase { * @covers User::getPasswordExpired() */ public function testPasswordExpire() { - global $wgPasswordExpireGrace; - $wgTemp = $wgPasswordExpireGrace; - $wgPasswordExpireGrace = 3600 * 24 * 7; // 7 days + $this->setMwGlobals( 'wgPasswordExpireGrace', 3600 * 24 * 7 ); // 7 days $user = User::newFromName( 'UnitTestUser' ); - $user->loadDefaults(); + $user->loadDefaults( 'UnitTestUser' ); $this->assertEquals( false, $user->getPasswordExpired() ); $ts = time() - ( 3600 * 24 * 1 ); // 1 day ago @@ -291,8 +294,6 @@ class UserTest extends MediaWikiTestCase { $ts = time() - ( 3600 * 24 * 10 ); // 10 days ago $user->expirePassword( $ts ); $this->assertEquals( 'hard', $user->getPasswordExpired() ); - - $wgPasswordExpireGrace = $wgTemp; } /** @@ -343,8 +344,8 @@ class UserTest extends MediaWikiTestCase { public function testGetCanonicalName( $name, $expectedArray, $msg ) { foreach ( $expectedArray as $validate => $expected ) { $this->assertEquals( - User::getCanonicalName( $name, $validate === 'false' ? false : $validate ), $expected, + User::getCanonicalName( $name, $validate === 'false' ? false : $validate ), $msg . ' (' . $validate . ')' ); } @@ -352,8 +353,8 @@ class UserTest extends MediaWikiTestCase { public static function provideGetCanonicalName() { return array( - array( ' trailing space ', array( 'creatable' => 'Trailing space' ), 'Trailing spaces' ), - // @todo FIXME: Maybe the createable name should be 'Talk:Username' or false to reject? + array( ' Trailing space ', array( 'creatable' => 'Trailing space' ), 'Trailing spaces' ), + // @todo FIXME: Maybe the creatable name should be 'Talk:Username' or false to reject? array( 'Talk:Username', array( 'creatable' => 'Username', 'usable' => 'Username', 'valid' => 'Username', 'false' => 'Talk:Username' ), 'Namespace prefix' ), array( ' name with # hash', array( 'creatable' => false, 'usable' => false ), 'With hash' ), @@ -366,4 +367,62 @@ class UserTest extends MediaWikiTestCase { 'false' => 'With / slash' ), 'With slash' ), ); } + + /** + * @covers User::equals + */ + public function testEquals() { + $first = User::newFromName( 'EqualUser' ); + $second = User::newFromName( 'EqualUser' ); + + $this->assertTrue( $first->equals( $first ) ); + $this->assertTrue( $first->equals( $second ) ); + $this->assertTrue( $second->equals( $first ) ); + + $third = User::newFromName( '0' ); + $fourth = User::newFromName( '000' ); + + $this->assertFalse( $third->equals( $fourth ) ); + $this->assertFalse( $fourth->equals( $third ) ); + + // Test users loaded from db with id + $user = User::newFromName( 'EqualUnitTestUser' ); + if ( !$user->getId() ) { + $user->addToDatabase(); + } + + $id = $user->getId(); + + $fifth = User::newFromId( $id ); + $sixth = User::newFromName( 'EqualUnitTestUser' ); + $this->assertTrue( $fifth->equals( $sixth ) ); + } + + /** + * @covers User::getId + */ + public function testGetId() { + $user = User::newFromName( 'UTSysop' ); + $this->assertTrue( $user->getId() > 0 ); + + } + + /** + * @covers User::isLoggedIn + * @covers User::isAnon + */ + public function testLoggedIn() { + $user = User::newFromName( 'UTSysop' ); + $this->assertTrue( $user->isLoggedIn() ); + $this->assertFalse( $user->isAnon() ); + + // Non-existent users are perceived as anonymous + $user = User::newFromName( 'UTNonexistent' ); + $this->assertFalse( $user->isLoggedIn() ); + $this->assertTrue( $user->isAnon() ); + + $user = new User; + $this->assertFalse( $user->isLoggedIn() ); + $this->assertTrue( $user->isAnon() ); + } } diff --git a/tests/phpunit/includes/XmlSelectTest.php b/tests/phpunit/includes/XmlSelectTest.php index 9f154bb7..0e03add4 100644 --- a/tests/phpunit/includes/XmlSelectTest.php +++ b/tests/phpunit/includes/XmlSelectTest.php @@ -166,7 +166,7 @@ class XmlSelectTest extends MediaWikiTestCase { 'razor' ); - # inexistant keys should give us 'null' + # inexistent keys should give us 'null' $this->assertEquals( $this->select->getAttribute( 'I DO NOT EXIT' ), null diff --git a/tests/phpunit/includes/XmlTest.php b/tests/phpunit/includes/XmlTest.php index e6558819..382e3d89 100644 --- a/tests/phpunit/includes/XmlTest.php +++ b/tests/phpunit/includes/XmlTest.php @@ -81,7 +81,7 @@ class XmlTest extends MediaWikiTestCase { */ public function testElementInputCanHaveAValueOfZero() { $this->assertEquals( - '<input name="name" value="0" class="mw-ui-input" />', + '<input name="name" value="0" />', Xml::input( 'name', false, 0 ), 'Input with a value of 0 (bug 23797)' ); @@ -152,7 +152,7 @@ class XmlTest extends MediaWikiTestCase { $this->assertEquals( '<label for="year">From year (and earlier):</label> ' . - '<input id="year" maxlength="4" size="7" type="number" value="2011" name="year" class="mw-ui-input" /> ' . + '<input id="year" maxlength="4" size="7" type="number" value="2011" name="year" /> ' . '<label for="month">From month (and earlier):</label> ' . '<select id="month" name="month" class="mw-month-selector">' . '<option value="-1">all</option>' . "\n" . @@ -173,7 +173,7 @@ class XmlTest extends MediaWikiTestCase { ); $this->assertEquals( '<label for="year">From year (and earlier):</label> ' . - '<input id="year" maxlength="4" size="7" type="number" value="2011" name="year" class="mw-ui-input" /> ' . + '<input id="year" maxlength="4" size="7" type="number" value="2011" name="year" /> ' . '<label for="month">From month (and earlier):</label> ' . '<select id="month" name="month" class="mw-month-selector">' . '<option value="-1">all</option>' . "\n" . @@ -207,7 +207,7 @@ class XmlTest extends MediaWikiTestCase { $this->assertEquals( '<label for="year">From year (and earlier):</label> ' . - '<input id="year" maxlength="4" size="7" type="number" name="year" class="mw-ui-input" /> ' . + '<input id="year" maxlength="4" size="7" type="number" name="year" /> ' . '<label for="month">From month (and earlier):</label> ' . '<select id="month" name="month" class="mw-month-selector">' . '<option value="-1">all</option>' . "\n" . @@ -233,7 +233,7 @@ class XmlTest extends MediaWikiTestCase { */ public function testTextareaNoContent() { $this->assertEquals( - '<textarea name="name" id="name" cols="40" rows="5" class="mw-ui-input"></textarea>', + '<textarea name="name" id="name" cols="40" rows="5"></textarea>', Xml::textarea( 'name', '' ), 'textarea() with not content' ); @@ -244,7 +244,7 @@ class XmlTest extends MediaWikiTestCase { */ public function testTextareaAttribs() { $this->assertEquals( - '<textarea name="name" id="name" cols="20" rows="10" class="mw-ui-input"><txt></textarea>', + '<textarea name="name" id="name" cols="20" rows="10"><txt></textarea>', Xml::textarea( 'name', '<txt>', 20, 10 ), 'textarea() with custom attribs' ); diff --git a/tests/phpunit/includes/actions/ActionTest.php b/tests/phpunit/includes/actions/ActionTest.php index cc6fb11a..3babb97f 100644 --- a/tests/phpunit/includes/actions/ActionTest.php +++ b/tests/phpunit/includes/actions/ActionTest.php @@ -3,7 +3,6 @@ /** * @covers Action * - * @licence GNU GPL v2+ * @author Thiemo Mättig * * @group Action @@ -20,7 +19,7 @@ class ActionTest extends MediaWikiTestCase { 'disabled' => false, 'view' => true, 'edit' => true, - 'revisiondelete' => true, + 'revisiondelete' => 'SpecialPageAction', 'dummy' => true, 'string' => 'NamedDummyAction', 'declared' => 'NonExistingClassName', @@ -117,6 +116,15 @@ class ActionTest extends MediaWikiTestCase { $this->assertEquals( 'revisiondelete', $actionName ); } + public function testGetActionName_whenCanNotUseWikiPage_defaultsToView() { + $request = new FauxRequest( array( 'action' => 'edit' ) ); + $context = new DerivativeContext( RequestContext::getMain() ); + $context->setRequest( $request ); + $actionName = Action::getActionName( $context ); + + $this->assertEquals( 'view', $actionName ); + } + /** * @dataProvider actionProvider * @param string $requestedAction diff --git a/tests/phpunit/includes/api/ApiContinuationManagerTest.php b/tests/phpunit/includes/api/ApiContinuationManagerTest.php new file mode 100644 index 00000000..2edf0c6f --- /dev/null +++ b/tests/phpunit/includes/api/ApiContinuationManagerTest.php @@ -0,0 +1,195 @@ +<?php + +/** + * @covers ApiContinuationManager + * @group API + */ +class ApiContinuationManagerTest extends MediaWikiTestCase { + + private static function getManager( $continue, $allModules, $generatedModules ) { + $context = new DerivativeContext( RequestContext::getMain() ); + $context->setRequest( new FauxRequest( array( 'continue' => $continue ) ) ); + $main = new ApiMain( $context ); + return new ApiContinuationManager( $main, $allModules, $generatedModules ); + } + + public function testContinuation() { + $allModules = array( + new MockApiQueryBase( 'mock1' ), + new MockApiQueryBase( 'mock2' ), + new MockApiQueryBase( 'mocklist' ), + ); + $generator = new MockApiQueryBase( 'generator' ); + + $manager = self::getManager( '', $allModules, array( 'mock1', 'mock2' ) ); + $this->assertSame( 'ApiMain', $manager->getSource() ); + $this->assertSame( false, $manager->isGeneratorDone() ); + $this->assertSame( $allModules, $manager->getRunModules() ); + $manager->addContinueParam( $allModules[0], 'm1continue', array( 1, 2 ) ); + $manager->addContinueParam( $allModules[2], 'mlcontinue', 2 ); + $manager->addGeneratorContinueParam( $generator, 'gcontinue', 3 ); + $this->assertSame( array( array( + 'mlcontinue' => 2, + 'm1continue' => '1|2', + 'continue' => '||mock2', + ), false ), $manager->getContinuation() ); + $this->assertSame( array( + 'mock1' => array( 'm1continue' => '1|2' ), + 'mocklist' => array( 'mlcontinue' => 2 ), + 'generator' => array( 'gcontinue' => 3 ), + ), $manager->getRawContinuation() ); + + $result = new ApiResult( 0 ); + $manager->setContinuationIntoResult( $result ); + $this->assertSame( array( + 'mlcontinue' => 2, + 'm1continue' => '1|2', + 'continue' => '||mock2', + ), $result->getResultData( 'continue' ) ); + $this->assertSame( null, $result->getResultData( 'batchcomplete' ) ); + + $manager = self::getManager( '', $allModules, array( 'mock1', 'mock2' ) ); + $this->assertSame( false, $manager->isGeneratorDone() ); + $this->assertSame( $allModules, $manager->getRunModules() ); + $manager->addContinueParam( $allModules[0], 'm1continue', array( 1, 2 ) ); + $manager->addGeneratorContinueParam( $generator, 'gcontinue', array( 3, 4 ) ); + $this->assertSame( array( array( + 'm1continue' => '1|2', + 'continue' => '||mock2|mocklist', + ), false ), $manager->getContinuation() ); + $this->assertSame( array( + 'mock1' => array( 'm1continue' => '1|2' ), + 'generator' => array( 'gcontinue' => '3|4' ), + ), $manager->getRawContinuation() ); + + $manager = self::getManager( '', $allModules, array( 'mock1', 'mock2' ) ); + $this->assertSame( false, $manager->isGeneratorDone() ); + $this->assertSame( $allModules, $manager->getRunModules() ); + $manager->addContinueParam( $allModules[2], 'mlcontinue', 2 ); + $manager->addGeneratorContinueParam( $generator, 'gcontinue', 3 ); + $this->assertSame( array( array( + 'mlcontinue' => 2, + 'gcontinue' => 3, + 'continue' => 'gcontinue||', + ), true ), $manager->getContinuation() ); + $this->assertSame( array( + 'mocklist' => array( 'mlcontinue' => 2 ), + 'generator' => array( 'gcontinue' => 3 ), + ), $manager->getRawContinuation() ); + + $result = new ApiResult( 0 ); + $manager->setContinuationIntoResult( $result ); + $this->assertSame( array( + 'mlcontinue' => 2, + 'gcontinue' => 3, + 'continue' => 'gcontinue||', + ), $result->getResultData( 'continue' ) ); + $this->assertSame( true, $result->getResultData( 'batchcomplete' ) ); + + $manager = self::getManager( '', $allModules, array( 'mock1', 'mock2' ) ); + $this->assertSame( false, $manager->isGeneratorDone() ); + $this->assertSame( $allModules, $manager->getRunModules() ); + $manager->addGeneratorContinueParam( $generator, 'gcontinue', 3 ); + $this->assertSame( array( array( + 'gcontinue' => 3, + 'continue' => 'gcontinue||mocklist', + ), true ), $manager->getContinuation() ); + $this->assertSame( array( + 'generator' => array( 'gcontinue' => 3 ), + ), $manager->getRawContinuation() ); + + $manager = self::getManager( '', $allModules, array( 'mock1', 'mock2' ) ); + $this->assertSame( false, $manager->isGeneratorDone() ); + $this->assertSame( $allModules, $manager->getRunModules() ); + $manager->addContinueParam( $allModules[0], 'm1continue', array( 1, 2 ) ); + $manager->addContinueParam( $allModules[2], 'mlcontinue', 2 ); + $this->assertSame( array( array( + 'mlcontinue' => 2, + 'm1continue' => '1|2', + 'continue' => '||mock2', + ), false ), $manager->getContinuation() ); + $this->assertSame( array( + 'mock1' => array( 'm1continue' => '1|2' ), + 'mocklist' => array( 'mlcontinue' => 2 ), + ), $manager->getRawContinuation() ); + + $manager = self::getManager( '', $allModules, array( 'mock1', 'mock2' ) ); + $this->assertSame( false, $manager->isGeneratorDone() ); + $this->assertSame( $allModules, $manager->getRunModules() ); + $manager->addContinueParam( $allModules[0], 'm1continue', array( 1, 2 ) ); + $this->assertSame( array( array( + 'm1continue' => '1|2', + 'continue' => '||mock2|mocklist', + ), false ), $manager->getContinuation() ); + $this->assertSame( array( + 'mock1' => array( 'm1continue' => '1|2' ), + ), $manager->getRawContinuation() ); + + $manager = self::getManager( '', $allModules, array( 'mock1', 'mock2' ) ); + $this->assertSame( false, $manager->isGeneratorDone() ); + $this->assertSame( $allModules, $manager->getRunModules() ); + $manager->addContinueParam( $allModules[2], 'mlcontinue', 2 ); + $this->assertSame( array( array( + 'mlcontinue' => 2, + 'continue' => '-||mock1|mock2', + ), true ), $manager->getContinuation() ); + $this->assertSame( array( + 'mocklist' => array( 'mlcontinue' => 2 ), + ), $manager->getRawContinuation() ); + + $manager = self::getManager( '', $allModules, array( 'mock1', 'mock2' ) ); + $this->assertSame( false, $manager->isGeneratorDone() ); + $this->assertSame( $allModules, $manager->getRunModules() ); + $this->assertSame( array( array(), true ), $manager->getContinuation() ); + $this->assertSame( array(), $manager->getRawContinuation() ); + + $manager = self::getManager( '||mock2', $allModules, array( 'mock1', 'mock2' ) ); + $this->assertSame( false, $manager->isGeneratorDone() ); + $this->assertSame( + array_values( array_diff_key( $allModules, array( 1 => 1 ) ) ), + $manager->getRunModules() + ); + + $manager = self::getManager( '-||', $allModules, array( 'mock1', 'mock2' ) ); + $this->assertSame( true, $manager->isGeneratorDone() ); + $this->assertSame( + array_values( array_diff_key( $allModules, array( 0 => 0, 1 => 1 ) ) ), + $manager->getRunModules() + ); + + try { + self::getManager( 'foo', $allModules, array( 'mock1', 'mock2' ) ); + $this->fail( 'Expected exception not thrown' ); + } catch ( UsageException $ex ) { + $this->assertSame( + 'Invalid continue param. You should pass the original value returned by the previous query', + $ex->getMessage(), + 'Expected exception' + ); + } + + $manager = self::getManager( '||mock2', array_slice( $allModules, 0, 2 ), array( 'mock1', 'mock2' ) ); + try { + $manager->addContinueParam( $allModules[1], 'm2continue', 1 ); + $this->fail( 'Expected exception not thrown' ); + } catch ( UnexpectedValueException $ex ) { + $this->assertSame( + 'Module \'mock2\' was not supposed to have been executed, but it was executed anyway', + $ex->getMessage(), + 'Expected exception' + ); + } + try { + $manager->addContinueParam( $allModules[2], 'mlcontinue', 1 ); + $this->fail( 'Expected exception not thrown' ); + } catch ( UnexpectedValueException $ex ) { + $this->assertSame( + 'Module \'mocklist\' called ApiContinuationManager::addContinueParam but was not passed to ApiContinuationManager::__construct', + $ex->getMessage(), + 'Expected exception' + ); + } + + } + +} diff --git a/tests/phpunit/includes/api/ApiErrorFormatterTest.php b/tests/phpunit/includes/api/ApiErrorFormatterTest.php new file mode 100644 index 00000000..8ebdf60f --- /dev/null +++ b/tests/phpunit/includes/api/ApiErrorFormatterTest.php @@ -0,0 +1,351 @@ +<?php + +/** + * @group API + */ +class ApiErrorFormatterTest extends MediaWikiTestCase { + + /** + * @covers ApiErrorFormatter + * @dataProvider provideErrorFormatter + */ + public function testErrorFormatter( $format, $lang, $useDB, + $expect1, $expect2, $expect3 + ) { + $result = new ApiResult( 8388608 ); + $formatter = new ApiErrorFormatter( $result, Language::factory( $lang ), $format, $useDB ); + + // Add default type + $expect1[ApiResult::META_TYPE] = 'assoc'; + $expect2[ApiResult::META_TYPE] = 'assoc'; + $expect3[ApiResult::META_TYPE] = 'assoc'; + + $formatter->addWarning( 'string', 'mainpage' ); + $formatter->addError( 'err', 'mainpage' ); + $this->assertSame( $expect1, $result->getResultData(), 'Simple test' ); + + $result->reset(); + $formatter->addWarning( 'foo', 'mainpage' ); + $formatter->addWarning( 'foo', 'mainpage' ); + $formatter->addWarning( 'foo', array( 'parentheses', 'foobar' ) ); + $msg1 = wfMessage( 'mainpage' ); + $formatter->addWarning( 'message', $msg1 ); + $msg2 = new ApiMessage( 'mainpage', 'overriddenCode', array( 'overriddenData' => true ) ); + $formatter->addWarning( 'messageWithData', $msg2 ); + $formatter->addError( 'errWithData', $msg2 ); + $this->assertSame( $expect2, $result->getResultData(), 'Complex test' ); + + $result->reset(); + $status = Status::newGood(); + $status->warning( 'mainpage' ); + $status->warning( 'parentheses', 'foobar' ); + $status->warning( $msg1 ); + $status->warning( $msg2 ); + $status->error( 'mainpage' ); + $status->error( 'parentheses', 'foobar' ); + $formatter->addMessagesFromStatus( 'status', $status ); + $this->assertSame( $expect3, $result->getResultData(), 'Status test' ); + + $this->assertSame( + $expect3['errors']['status'], + $formatter->arrayFromStatus( $status, 'error' ), + 'arrayFromStatus test for error' + ); + $this->assertSame( + $expect3['warnings']['status'], + $formatter->arrayFromStatus( $status, 'warning' ), + 'arrayFromStatus test for warning' + ); + } + + public static function provideErrorFormatter() { + $mainpagePlain = wfMessage( 'mainpage' )->useDatabase( false )->plain(); + $parensPlain = wfMessage( 'parentheses', 'foobar' )->useDatabase( false )->plain(); + $mainpageText = wfMessage( 'mainpage' )->inLanguage( 'de' )->text(); + $parensText = wfMessage( 'parentheses', 'foobar' )->inLanguage( 'de' )->text(); + $C = ApiResult::META_CONTENT; + $I = ApiResult::META_INDEXED_TAG_NAME; + + return array( + array( 'wikitext', 'de', true, + array( + 'errors' => array( + 'err' => array( + array( 'code' => 'mainpage', 'text' => $mainpageText, $C => 'text' ), + $I => 'error', + ), + ), + 'warnings' => array( + 'string' => array( + array( 'code' => 'mainpage', 'text' => $mainpageText, $C => 'text' ), + $I => 'warning', + ), + ), + ), + array( + 'errors' => array( + 'errWithData' => array( + array( 'code' => 'overriddenCode', 'text' => $mainpageText, + 'overriddenData' => true, $C => 'text' ), + $I => 'error', + ), + ), + 'warnings' => array( + 'messageWithData' => array( + array( 'code' => 'overriddenCode', 'text' => $mainpageText, + 'overriddenData' => true, $C => 'text' ), + $I => 'warning', + ), + 'message' => array( + array( 'code' => 'mainpage', 'text' => $mainpageText, $C => 'text' ), + $I => 'warning', + ), + 'foo' => array( + array( 'code' => 'mainpage', 'text' => $mainpageText, $C => 'text' ), + array( 'code' => 'parentheses', 'text' => $parensText, $C => 'text' ), + $I => 'warning', + ), + ), + ), + array( + 'errors' => array( + 'status' => array( + array( 'code' => 'mainpage', 'text' => $mainpageText, $C => 'text' ), + array( 'code' => 'parentheses', 'text' => $parensText, $C => 'text' ), + $I => 'error', + ), + ), + 'warnings' => array( + 'status' => array( + array( 'code' => 'mainpage', 'text' => $mainpageText, $C => 'text' ), + array( 'code' => 'parentheses', 'text' => $parensText, $C => 'text' ), + array( 'code' => 'overriddenCode', 'text' => $mainpageText, + 'overriddenData' => true, $C => 'text' ), + $I => 'warning', + ), + ), + ), + ), + array( 'raw', 'fr', true, + array( + 'errors' => array( + 'err' => array( + array( 'code' => 'mainpage', 'message' => 'mainpage', 'params' => array( $I => 'param' ) ), + $I => 'error', + ), + ), + 'warnings' => array( + 'string' => array( + array( 'code' => 'mainpage', 'message' => 'mainpage', 'params' => array( $I => 'param' ) ), + $I => 'warning', + ), + ), + ), + array( + 'errors' => array( + 'errWithData' => array( + array( 'code' => 'overriddenCode', 'message' => 'mainpage', 'params' => array( $I => 'param' ), + 'overriddenData' => true ), + $I => 'error', + ), + ), + 'warnings' => array( + 'messageWithData' => array( + array( 'code' => 'overriddenCode', 'message' => 'mainpage', 'params' => array( $I => 'param' ), + 'overriddenData' => true ), + $I => 'warning', + ), + 'message' => array( + array( 'code' => 'mainpage', 'message' => 'mainpage', 'params' => array( $I => 'param' ) ), + $I => 'warning', + ), + 'foo' => array( + array( 'code' => 'mainpage', 'message' => 'mainpage', 'params' => array( $I => 'param' ) ), + array( 'code' => 'parentheses', 'message' => 'parentheses', 'params' => array( 'foobar', $I => 'param' ) ), + $I => 'warning', + ), + ), + ), + array( + 'errors' => array( + 'status' => array( + array( 'code' => 'mainpage', 'message' => 'mainpage', 'params' => array( $I => 'param' ) ), + array( 'code' => 'parentheses', 'message' => 'parentheses', 'params' => array( 'foobar', $I => 'param' ) ), + $I => 'error', + ), + ), + 'warnings' => array( + 'status' => array( + array( 'code' => 'mainpage', 'message' => 'mainpage', 'params' => array( $I => 'param' ) ), + array( 'code' => 'parentheses', 'message' => 'parentheses', 'params' => array( 'foobar', $I => 'param' ) ), + array( 'code' => 'overriddenCode', 'message' => 'mainpage', 'params' => array( $I => 'param' ), + 'overriddenData' => true ), + $I => 'warning', + ), + ), + ), + ), + array( 'none', 'fr', true, + array( + 'errors' => array( + 'err' => array( + array( 'code' => 'mainpage' ), + $I => 'error', + ), + ), + 'warnings' => array( + 'string' => array( + array( 'code' => 'mainpage' ), + $I => 'warning', + ), + ), + ), + array( + 'errors' => array( + 'errWithData' => array( + array( 'code' => 'overriddenCode', 'overriddenData' => true ), + $I => 'error', + ), + ), + 'warnings' => array( + 'messageWithData' => array( + array( 'code' => 'overriddenCode', 'overriddenData' => true ), + $I => 'warning', + ), + 'message' => array( + array( 'code' => 'mainpage' ), + $I => 'warning', + ), + 'foo' => array( + array( 'code' => 'mainpage' ), + array( 'code' => 'parentheses' ), + $I => 'warning', + ), + ), + ), + array( + 'errors' => array( + 'status' => array( + array( 'code' => 'mainpage' ), + array( 'code' => 'parentheses' ), + $I => 'error', + ), + ), + 'warnings' => array( + 'status' => array( + array( 'code' => 'mainpage' ), + array( 'code' => 'parentheses' ), + array( 'code' => 'overriddenCode', 'overriddenData' => true ), + $I => 'warning', + ), + ), + ), + ), + ); + } + + /** + * @covers ApiErrorFormatter_BackCompat + */ + public function testErrorFormatterBC() { + $mainpagePlain = wfMessage( 'mainpage' )->useDatabase( false )->plain(); + $parensPlain = wfMessage( 'parentheses', 'foobar' )->useDatabase( false )->plain(); + + $result = new ApiResult( 8388608 ); + $formatter = new ApiErrorFormatter_BackCompat( $result ); + + $formatter->addWarning( 'string', 'mainpage' ); + $formatter->addError( 'err', 'mainpage' ); + $this->assertSame( array( + 'error' => array( + 'code' => 'mainpage', + 'info' => $mainpagePlain, + ), + 'warnings' => array( + 'string' => array( + 'warnings' => $mainpagePlain, + ApiResult::META_CONTENT => 'warnings', + ), + ), + ApiResult::META_TYPE => 'assoc', + ), $result->getResultData(), 'Simple test' ); + + $result->reset(); + $formatter->addWarning( 'foo', 'mainpage' ); + $formatter->addWarning( 'foo', 'mainpage' ); + $formatter->addWarning( 'foo', array( 'parentheses', 'foobar' ) ); + $msg1 = wfMessage( 'mainpage' ); + $formatter->addWarning( 'message', $msg1 ); + $msg2 = new ApiMessage( 'mainpage', 'overriddenCode', array( 'overriddenData' => true ) ); + $formatter->addWarning( 'messageWithData', $msg2 ); + $formatter->addError( 'errWithData', $msg2 ); + $this->assertSame( array( + 'error' => array( + 'code' => 'overriddenCode', + 'info' => $mainpagePlain, + 'overriddenData' => true, + ), + 'warnings' => array( + 'messageWithData' => array( + 'warnings' => $mainpagePlain, + ApiResult::META_CONTENT => 'warnings', + ), + 'message' => array( + 'warnings' => $mainpagePlain, + ApiResult::META_CONTENT => 'warnings', + ), + 'foo' => array( + 'warnings' => "$mainpagePlain\n$parensPlain", + ApiResult::META_CONTENT => 'warnings', + ), + ), + ApiResult::META_TYPE => 'assoc', + ), $result->getResultData(), 'Complex test' ); + + $result->reset(); + $status = Status::newGood(); + $status->warning( 'mainpage' ); + $status->warning( 'parentheses', 'foobar' ); + $status->warning( $msg1 ); + $status->warning( $msg2 ); + $status->error( 'mainpage' ); + $status->error( 'parentheses', 'foobar' ); + $formatter->addMessagesFromStatus( 'status', $status ); + $this->assertSame( array( + 'error' => array( + 'code' => 'parentheses', + 'info' => $parensPlain, + ), + 'warnings' => array( + 'status' => array( + 'warnings' => "$mainpagePlain\n$parensPlain", + ApiResult::META_CONTENT => 'warnings', + ), + ), + ApiResult::META_TYPE => 'assoc', + ), $result->getResultData(), 'Status test' ); + + $I = ApiResult::META_INDEXED_TAG_NAME; + $this->assertSame( + array( + array( 'type' => 'error', 'message' => 'mainpage', 'params' => array( $I => 'param' ) ), + array( 'type' => 'error', 'message' => 'parentheses', 'params' => array( 'foobar', $I => 'param' ) ), + $I => 'error', + ), + $formatter->arrayFromStatus( $status, 'error' ), + 'arrayFromStatus test for error' + ); + $this->assertSame( + array( + array( 'type' => 'warning', 'message' => 'mainpage', 'params' => array( $I => 'param' ) ), + array( 'type' => 'warning', 'message' => 'parentheses', 'params' => array( 'foobar', $I => 'param' ) ), + array( 'message' => 'mainpage', 'params' => array( $I => 'param' ), 'type' => 'warning' ), + array( 'message' => 'mainpage', 'params' => array( $I => 'param' ), 'type' => 'warning' ), + $I => 'warning', + ), + $formatter->arrayFromStatus( $status, 'warning' ), + 'arrayFromStatus test for warning' + ); + } + +} diff --git a/tests/phpunit/includes/api/ApiLoginTest.php b/tests/phpunit/includes/api/ApiLoginTest.php index 67a75f36..88a99e9b 100644 --- a/tests/phpunit/includes/api/ApiLoginTest.php +++ b/tests/phpunit/includes/api/ApiLoginTest.php @@ -123,7 +123,8 @@ class ApiLoginTest extends ApiTestCase { "lgname" => $user->username, "lgpassword" => $user->password ) - ) + ), + __METHOD__ ); $req->execute(); diff --git a/tests/phpunit/includes/api/ApiMainTest.php b/tests/phpunit/includes/api/ApiMainTest.php index 780cf9ed..e8ef1804 100644 --- a/tests/phpunit/includes/api/ApiMainTest.php +++ b/tests/phpunit/includes/api/ApiMainTest.php @@ -2,7 +2,6 @@ /** * @group API - * @group Database * @group medium * * @covers ApiMain @@ -10,41 +9,25 @@ class ApiMainTest extends ApiTestCase { /** - * Test that the API will accept a FauxRequest and execute. The help action - * (default) throws a UsageException. Just validate we're getting proper XML - * - * @expectedException UsageException + * Test that the API will accept a FauxRequest and execute. */ public function testApi() { $api = new ApiMain( - new FauxRequest( array( 'action' => 'help', 'format' => 'xml' ) ) + new FauxRequest( array( 'action' => 'query', 'meta' => 'siteinfo' ) ) ); $api->execute(); - $api->getPrinter()->setBufferResult( true ); - $api->printResult( false ); - $resp = $api->getPrinter()->getBuffer(); - - libxml_use_internal_errors( true ); - $sxe = simplexml_load_string( $resp ); - $this->assertNotInternalType( "bool", $sxe ); - $this->assertThat( $sxe, $this->isInstanceOf( "SimpleXMLElement" ) ); + $data = $api->getResult()->getResultData(); + $this->assertInternalType( 'array', $data ); + $this->assertArrayHasKey( 'query', $data ); } public static function provideAssert() { - $anon = new User(); - $bot = new User(); - $bot->setName( 'Bot' ); - $bot->addToDatabase(); - $bot->addGroup( 'bot' ); - $user = new User(); - $user->setName( 'User' ); - $user->addToDatabase(); return array( - array( $anon, 'user', 'assertuserfailed' ), - array( $user, 'user', false ), - array( $user, 'bot', 'assertbotfailed' ), - array( $bot, 'user', false ), - array( $bot, 'bot', false ), + array( false, array(), 'user', 'assertuserfailed' ), + array( true, array(), 'user', false ), + array( true, array(), 'bot', 'assertbotfailed' ), + array( true, array( 'bot' ), 'user', false ), + array( true, array( 'bot' ), 'bot', false ), ); } @@ -53,11 +36,17 @@ class ApiMainTest extends ApiTestCase { * * @covers ApiMain::checkAsserts * @dataProvider provideAssert - * @param User $user + * @param bool $registered + * @param array $rights * @param string $assert * @param string|bool $error False if no error expected */ - public function testAssert( $user, $assert, $error ) { + public function testAssert( $registered, $rights, $assert, $error ) { + $user = new User(); + if ( $registered ) { + $user->setId( 1 ); + } + $user->mRights = $rights; try { $this->doApiRequest( array( 'action' => 'query', @@ -69,4 +58,25 @@ class ApiMainTest extends ApiTestCase { } } + /** + * Test if all classes in the main module manager exists + */ + public function testClassNamesInModuleManager() { + global $wgAutoloadLocalClasses, $wgAutoloadClasses; + + // wgAutoloadLocalClasses has precedence, just like in includes/AutoLoader.php + $classes = $wgAutoloadLocalClasses + $wgAutoloadClasses; + + $api = new ApiMain( + new FauxRequest( array( 'action' => 'query', 'meta' => 'siteinfo' ) ) + ); + $modules = $api->getModuleManager()->getNamesWithClasses(); + foreach( $modules as $name => $class ) { + $this->assertArrayHasKey( + $class, + $classes, + 'Class ' . $class . ' for api module ' . $name . ' not in autoloader (with exact case)' + ); + } + } } diff --git a/tests/phpunit/includes/api/ApiMessageTest.php b/tests/phpunit/includes/api/ApiMessageTest.php new file mode 100644 index 00000000..6c3ce60d --- /dev/null +++ b/tests/phpunit/includes/api/ApiMessageTest.php @@ -0,0 +1,103 @@ +<?php + +/** + * @group API + */ +class ApiMessageTest extends MediaWikiTestCase { + + private function compareMessages( $msg, $msg2 ) { + $this->assertSame( $msg->getKey(), $msg2->getKey(), 'getKey' ); + $this->assertSame( $msg->getKeysToTry(), $msg2->getKeysToTry(), 'getKeysToTry' ); + $this->assertSame( $msg->getParams(), $msg2->getParams(), 'getParams' ); + $this->assertSame( $msg->getFormat(), $msg2->getFormat(), 'getFormat' ); + $this->assertSame( $msg->getLanguage(), $msg2->getLanguage(), 'getLanguage' ); + + $msg = TestingAccessWrapper::newFromObject( $msg ); + $msg2 = TestingAccessWrapper::newFromObject( $msg2 ); + foreach ( array( 'interface', 'useDatabase', 'title' ) as $key ) { + $this->assertSame( $msg->$key, $msg2->$key, $key ); + } + } + + /** + * @covers ApiMessage + */ + public function testApiMessage() { + $msg = new Message( array( 'foo', 'bar' ), array( 'baz' ) ); + $msg->inLanguage( 'de' )->title( Title::newMainPage() ); + $msg2 = new ApiMessage( $msg, 'code', array( 'data' ) ); + $this->compareMessages( $msg, $msg2 ); + $this->assertEquals( 'code', $msg2->getApiCode() ); + $this->assertEquals( array( 'data' ), $msg2->getApiData() ); + + $msg = new Message( array( 'foo', 'bar' ), array( 'baz' ) ); + $msg2 = new ApiMessage( array( array( 'foo', 'bar' ), 'baz' ), 'code', array( 'data' ) ); + $this->compareMessages( $msg, $msg2 ); + $this->assertEquals( 'code', $msg2->getApiCode() ); + $this->assertEquals( array( 'data' ), $msg2->getApiData() ); + + $msg = new Message( 'foo' ); + $msg2 = new ApiMessage( 'foo' ); + $this->compareMessages( $msg, $msg2 ); + $this->assertEquals( 'foo', $msg2->getApiCode() ); + $this->assertEquals( array(), $msg2->getApiData() ); + + $msg2->setApiCode( 'code', array( 'data' ) ); + $this->assertEquals( 'code', $msg2->getApiCode() ); + $this->assertEquals( array( 'data' ), $msg2->getApiData() ); + $msg2->setApiCode( null ); + $this->assertEquals( 'foo', $msg2->getApiCode() ); + $this->assertEquals( array( 'data' ), $msg2->getApiData() ); + $msg2->setApiData( array( 'data2' ) ); + $this->assertEquals( array( 'data2' ), $msg2->getApiData() ); + } + + /** + * @covers ApiRawMessage + */ + public function testApiRawMessage() { + $msg = new RawMessage( 'foo', array( 'baz' ) ); + $msg->inLanguage( 'de' )->title( Title::newMainPage() ); + $msg2 = new ApiRawMessage( $msg, 'code', array( 'data' ) ); + $this->compareMessages( $msg, $msg2 ); + $this->assertEquals( 'code', $msg2->getApiCode() ); + $this->assertEquals( array( 'data' ), $msg2->getApiData() ); + + $msg = new RawMessage( 'foo', array( 'baz' ) ); + $msg2 = new ApiRawMessage( array( 'foo', 'baz' ), 'code', array( 'data' ) ); + $this->compareMessages( $msg, $msg2 ); + $this->assertEquals( 'code', $msg2->getApiCode() ); + $this->assertEquals( array( 'data' ), $msg2->getApiData() ); + + $msg = new RawMessage( 'foo' ); + $msg2 = new ApiRawMessage( 'foo', 'code', array( 'data' ) ); + $this->compareMessages( $msg, $msg2 ); + $this->assertEquals( 'code', $msg2->getApiCode() ); + $this->assertEquals( array( 'data' ), $msg2->getApiData() ); + + $msg2->setApiCode( 'code', array( 'data' ) ); + $this->assertEquals( 'code', $msg2->getApiCode() ); + $this->assertEquals( array( 'data' ), $msg2->getApiData() ); + $msg2->setApiCode( null ); + $this->assertEquals( 'foo', $msg2->getApiCode() ); + $this->assertEquals( array( 'data' ), $msg2->getApiData() ); + $msg2->setApiData( array( 'data2' ) ); + $this->assertEquals( array( 'data2' ), $msg2->getApiData() ); + } + + /** + * @covers ApiMessage::create + */ + public function testApiMessageCreate() { + $this->assertInstanceOf( 'ApiMessage', ApiMessage::create( new Message( 'mainpage' ) ) ); + $this->assertInstanceOf( 'ApiRawMessage', ApiMessage::create( new RawMessage( 'mainpage' ) ) ); + $this->assertInstanceOf( 'ApiMessage', ApiMessage::create( 'mainpage' ) ); + + $msg = new ApiMessage( 'mainpage' ); + $this->assertSame( $msg, ApiMessage::create( $msg ) ); + + $msg = new ApiRawMessage( 'mainpage' ); + $this->assertSame( $msg, ApiMessage::create( $msg ) ); + } + +} diff --git a/tests/phpunit/includes/api/ApiOptionsTest.php b/tests/phpunit/includes/api/ApiOptionsTest.php index 5f955bbc..51154ae3 100644 --- a/tests/phpunit/includes/api/ApiOptionsTest.php +++ b/tests/phpunit/includes/api/ApiOptionsTest.php @@ -17,8 +17,6 @@ class ApiOptionsTest extends MediaWikiLangTestCase { /** @var DerivativeContext */ private $mContext; - private $mOldGetPreferencesHooks; - private static $Success = array( 'options' => 'success' ); protected function setUp() { @@ -50,21 +48,11 @@ class ApiOptionsTest extends MediaWikiLangTestCase { $this->mTested = new ApiOptions( $main, 'options' ); - global $wgHooks; - if ( !isset( $wgHooks['GetPreferences'] ) ) { - $wgHooks['GetPreferences'] = array(); - } - $this->mOldGetPreferencesHooks = $wgHooks['GetPreferences']; - $wgHooks['GetPreferences'][] = array( $this, 'hookGetPreferences' ); - } - - protected function tearDown() { - global $wgHooks; - - $wgHooks['GetPreferences'] = $this->mOldGetPreferencesHooks; - $this->mOldGetPreferencesHooks = false; - - parent::tearDown(); + $this->mergeMwGlobalArrayValue( 'wgHooks', array( + 'GetPreferences' => array( + array( $this, 'hookGetPreferences' ) + ) + ) ); } public function hookGetPreferences( $user, &$preferences ) { @@ -150,7 +138,7 @@ class ApiOptionsTest extends MediaWikiLangTestCase { $this->mContext->setRequest( new FauxRequest( $request, true, $this->mSession ) ); $this->mTested->execute(); - return $this->mTested->getResult()->getData(); + return $this->mTested->getResult()->getResultData( null, array( 'Strip' => 'all' ) ); } /** @@ -408,7 +396,7 @@ class ApiOptionsTest extends MediaWikiLangTestCase { 'options' => 'success', 'warnings' => array( 'options' => array( - '*' => "Validation error for 'special': cannot be set by this module" + 'warnings' => "Validation error for 'special': cannot be set by this module" ) ) ), $response ); @@ -431,7 +419,7 @@ class ApiOptionsTest extends MediaWikiLangTestCase { 'options' => 'success', 'warnings' => array( 'options' => array( - '*' => "Validation error for 'unknownOption': not a valid preference" + 'warnings' => "Validation error for 'unknownOption': not a valid preference" ) ) ), $response ); diff --git a/tests/phpunit/includes/api/ApiResultTest.php b/tests/phpunit/includes/api/ApiResultTest.php new file mode 100644 index 00000000..f0d84552 --- /dev/null +++ b/tests/phpunit/includes/api/ApiResultTest.php @@ -0,0 +1,1563 @@ +<?php + +/** + * @covers ApiResult + * @group API + */ +class ApiResultTest extends MediaWikiTestCase { + + /** + * @covers ApiResult + */ + public function testStaticDataMethods() { + $arr = array(); + + ApiResult::setValue( $arr, 'setValue', '1' ); + + ApiResult::setValue( $arr, null, 'unnamed 1' ); + ApiResult::setValue( $arr, null, 'unnamed 2' ); + + ApiResult::setValue( $arr, 'deleteValue', '2' ); + ApiResult::unsetValue( $arr, 'deleteValue' ); + + ApiResult::setContentValue( $arr, 'setContentValue', '3' ); + + $this->assertSame( array( + 'setValue' => '1', + 'unnamed 1', + 'unnamed 2', + ApiResult::META_CONTENT => 'setContentValue', + 'setContentValue' => '3', + ), $arr ); + + try { + ApiResult::setValue( $arr, 'setValue', '99' ); + $this->fail( 'Expected exception not thrown' ); + } catch ( RuntimeException $ex ) { + $this->assertSame( + 'Attempting to add element setValue=99, existing value is 1', + $ex->getMessage(), + 'Expected exception' + ); + } + + try { + ApiResult::setContentValue( $arr, 'setContentValue2', '99' ); + $this->fail( 'Expected exception not thrown' ); + } catch ( RuntimeException $ex ) { + $this->assertSame( + 'Attempting to set content element as setContentValue2 when setContentValue ' . + 'is already set as the content element', + $ex->getMessage(), + 'Expected exception' + ); + } + + ApiResult::setValue( $arr, 'setValue', '99', ApiResult::OVERRIDE ); + $this->assertSame( '99', $arr['setValue'] ); + + ApiResult::setContentValue( $arr, 'setContentValue2', '99', ApiResult::OVERRIDE ); + $this->assertSame( 'setContentValue2', $arr[ApiResult::META_CONTENT] ); + + $arr = array( 'foo' => 1, 'bar' => 1 ); + ApiResult::setValue( $arr, 'top', '2', ApiResult::ADD_ON_TOP ); + ApiResult::setValue( $arr, null, '2', ApiResult::ADD_ON_TOP ); + ApiResult::setValue( $arr, 'bottom', '2' ); + ApiResult::setValue( $arr, 'foo', '2', ApiResult::OVERRIDE ); + ApiResult::setValue( $arr, 'bar', '2', ApiResult::OVERRIDE | ApiResult::ADD_ON_TOP ); + $this->assertSame( array( 0, 'top', 'foo', 'bar', 'bottom' ), array_keys( $arr ) ); + + $arr = array(); + ApiResult::setValue( $arr, 'sub', array( 'foo' => 1 ) ); + ApiResult::setValue( $arr, 'sub', array( 'bar' => 1 ) ); + $this->assertSame( array( 'sub' => array( 'foo' => 1, 'bar' => 1 ) ), $arr ); + + try { + ApiResult::setValue( $arr, 'sub', array( 'foo' => 2, 'baz' => 2 ) ); + $this->fail( 'Expected exception not thrown' ); + } catch ( RuntimeException $ex ) { + $this->assertSame( + 'Conflicting keys (foo) when attempting to merge element sub', + $ex->getMessage(), + 'Expected exception' + ); + } + + $arr = array(); + $title = Title::newFromText( "MediaWiki:Foobar" ); + $obj = new stdClass; + $obj->foo = 1; + $obj->bar = 2; + ApiResult::setValue( $arr, 'title', $title ); + ApiResult::setValue( $arr, 'obj', $obj ); + $this->assertSame( array( + 'title' => (string)$title, + 'obj' => array( 'foo' => 1, 'bar' => 2, ApiResult::META_TYPE => 'assoc' ), + ), $arr ); + + $fh = tmpfile(); + try { + ApiResult::setValue( $arr, 'file', $fh ); + $this->fail( 'Expected exception not thrown' ); + } catch ( InvalidArgumentException $ex ) { + $this->assertSame( + 'Cannot add resource(stream) to ApiResult', + $ex->getMessage(), + 'Expected exception' + ); + } + try { + ApiResult::setValue( $arr, null, $fh ); + $this->fail( 'Expected exception not thrown' ); + } catch ( InvalidArgumentException $ex ) { + $this->assertSame( + 'Cannot add resource(stream) to ApiResult', + $ex->getMessage(), + 'Expected exception' + ); + } + try { + $obj->file = $fh; + ApiResult::setValue( $arr, 'sub', $obj ); + $this->fail( 'Expected exception not thrown' ); + } catch ( InvalidArgumentException $ex ) { + $this->assertSame( + 'Cannot add resource(stream) to ApiResult', + $ex->getMessage(), + 'Expected exception' + ); + } + try { + $obj->file = $fh; + ApiResult::setValue( $arr, null, $obj ); + $this->fail( 'Expected exception not thrown' ); + } catch ( InvalidArgumentException $ex ) { + $this->assertSame( + 'Cannot add resource(stream) to ApiResult', + $ex->getMessage(), + 'Expected exception' + ); + } + fclose( $fh ); + + try { + ApiResult::setValue( $arr, 'inf', INF ); + $this->fail( 'Expected exception not thrown' ); + } catch ( InvalidArgumentException $ex ) { + $this->assertSame( + 'Cannot add non-finite floats to ApiResult', + $ex->getMessage(), + 'Expected exception' + ); + } + try { + ApiResult::setValue( $arr, null, INF ); + $this->fail( 'Expected exception not thrown' ); + } catch ( InvalidArgumentException $ex ) { + $this->assertSame( + 'Cannot add non-finite floats to ApiResult', + $ex->getMessage(), + 'Expected exception' + ); + } + try { + ApiResult::setValue( $arr, 'nan', NAN ); + $this->fail( 'Expected exception not thrown' ); + } catch ( InvalidArgumentException $ex ) { + $this->assertSame( + 'Cannot add non-finite floats to ApiResult', + $ex->getMessage(), + 'Expected exception' + ); + } + try { + ApiResult::setValue( $arr, null, NAN ); + $this->fail( 'Expected exception not thrown' ); + } catch ( InvalidArgumentException $ex ) { + $this->assertSame( + 'Cannot add non-finite floats to ApiResult', + $ex->getMessage(), + 'Expected exception' + ); + } + + $arr = array(); + $result2 = new ApiResult( 8388608 ); + $result2->addValue( null, 'foo', 'bar' ); + ApiResult::setValue( $arr, 'baz', $result2 ); + $this->assertSame( array( + 'baz' => array( + ApiResult::META_TYPE => 'assoc', + 'foo' => 'bar', + ) + ), $arr ); + + $arr = array(); + ApiResult::setValue( $arr, 'foo', "foo\x80bar" ); + ApiResult::setValue( $arr, 'bar', "a\xcc\x81" ); + ApiResult::setValue( $arr, 'baz', 74 ); + ApiResult::setValue( $arr, null, "foo\x80bar" ); + ApiResult::setValue( $arr, null, "a\xcc\x81" ); + $this->assertSame( array( + 'foo' => "foo\xef\xbf\xbdbar", + 'bar' => "\xc3\xa1", + 'baz' => 74, + 0 => "foo\xef\xbf\xbdbar", + 1 => "\xc3\xa1", + ), $arr ); + } + + /** + * @covers ApiResult + */ + public function testInstanceDataMethods() { + $result = new ApiResult( 8388608 ); + + $result->addValue( null, 'setValue', '1' ); + + $result->addValue( null, null, 'unnamed 1' ); + $result->addValue( null, null, 'unnamed 2' ); + + $result->addValue( null, 'deleteValue', '2' ); + $result->removeValue( null, 'deleteValue' ); + + $result->addValue( array( 'a', 'b' ), 'deleteValue', '3' ); + $result->removeValue( array( 'a', 'b', 'deleteValue' ), null, '3' ); + + $result->addContentValue( null, 'setContentValue', '3' ); + + $this->assertSame( array( + 'setValue' => '1', + 'unnamed 1', + 'unnamed 2', + 'a' => array( 'b' => array() ), + 'setContentValue' => '3', + ApiResult::META_TYPE => 'assoc', + ApiResult::META_CONTENT => 'setContentValue', + ), $result->getResultData() ); + $this->assertSame( 20, $result->getSize() ); + + try { + $result->addValue( null, 'setValue', '99' ); + $this->fail( 'Expected exception not thrown' ); + } catch ( RuntimeException $ex ) { + $this->assertSame( + 'Attempting to add element setValue=99, existing value is 1', + $ex->getMessage(), + 'Expected exception' + ); + } + + try { + $result->addContentValue( null, 'setContentValue2', '99' ); + $this->fail( 'Expected exception not thrown' ); + } catch ( RuntimeException $ex ) { + $this->assertSame( + 'Attempting to set content element as setContentValue2 when setContentValue ' . + 'is already set as the content element', + $ex->getMessage(), + 'Expected exception' + ); + } + + $result->addValue( null, 'setValue', '99', ApiResult::OVERRIDE ); + $this->assertSame( '99', $result->getResultData( array( 'setValue' ) ) ); + + $result->addContentValue( null, 'setContentValue2', '99', ApiResult::OVERRIDE ); + $this->assertSame( 'setContentValue2', + $result->getResultData( array( ApiResult::META_CONTENT ) ) ); + + $result->reset(); + $this->assertSame( array( + ApiResult::META_TYPE => 'assoc', + ), $result->getResultData() ); + $this->assertSame( 0, $result->getSize() ); + + $result->addValue( null, 'foo', 1 ); + $result->addValue( null, 'bar', 1 ); + $result->addValue( null, 'top', '2', ApiResult::ADD_ON_TOP ); + $result->addValue( null, null, '2', ApiResult::ADD_ON_TOP ); + $result->addValue( null, 'bottom', '2' ); + $result->addValue( null, 'foo', '2', ApiResult::OVERRIDE ); + $result->addValue( null, 'bar', '2', ApiResult::OVERRIDE | ApiResult::ADD_ON_TOP ); + $this->assertSame( array( 0, 'top', 'foo', 'bar', 'bottom', ApiResult::META_TYPE ), + array_keys( $result->getResultData() ) ); + + $result->reset(); + $result->addValue( null, 'foo', array( 'bar' => 1 ) ); + $result->addValue( array( 'foo', 'top' ), 'x', 2, ApiResult::ADD_ON_TOP ); + $result->addValue( array( 'foo', 'bottom' ), 'x', 2 ); + $this->assertSame( array( 'top', 'bar', 'bottom' ), + array_keys( $result->getResultData( array( 'foo' ) ) ) ); + + $result->reset(); + $result->addValue( null, 'sub', array( 'foo' => 1 ) ); + $result->addValue( null, 'sub', array( 'bar' => 1 ) ); + $this->assertSame( array( + 'sub' => array( 'foo' => 1, 'bar' => 1 ), + ApiResult::META_TYPE => 'assoc', + ), $result->getResultData() ); + + try { + $result->addValue( null, 'sub', array( 'foo' => 2, 'baz' => 2 ) ); + $this->fail( 'Expected exception not thrown' ); + } catch ( RuntimeException $ex ) { + $this->assertSame( + 'Conflicting keys (foo) when attempting to merge element sub', + $ex->getMessage(), + 'Expected exception' + ); + } + + $result->reset(); + $title = Title::newFromText( "MediaWiki:Foobar" ); + $obj = new stdClass; + $obj->foo = 1; + $obj->bar = 2; + $result->addValue( null, 'title', $title ); + $result->addValue( null, 'obj', $obj ); + $this->assertSame( array( + 'title' => (string)$title, + 'obj' => array( 'foo' => 1, 'bar' => 2, ApiResult::META_TYPE => 'assoc' ), + ApiResult::META_TYPE => 'assoc', + ), $result->getResultData() ); + + $fh = tmpfile(); + try { + $result->addValue( null, 'file', $fh ); + $this->fail( 'Expected exception not thrown' ); + } catch ( InvalidArgumentException $ex ) { + $this->assertSame( + 'Cannot add resource(stream) to ApiResult', + $ex->getMessage(), + 'Expected exception' + ); + } + try { + $result->addValue( null, null, $fh ); + $this->fail( 'Expected exception not thrown' ); + } catch ( InvalidArgumentException $ex ) { + $this->assertSame( + 'Cannot add resource(stream) to ApiResult', + $ex->getMessage(), + 'Expected exception' + ); + } + try { + $obj->file = $fh; + $result->addValue( null, 'sub', $obj ); + $this->fail( 'Expected exception not thrown' ); + } catch ( InvalidArgumentException $ex ) { + $this->assertSame( + 'Cannot add resource(stream) to ApiResult', + $ex->getMessage(), + 'Expected exception' + ); + } + try { + $obj->file = $fh; + $result->addValue( null, null, $obj ); + $this->fail( 'Expected exception not thrown' ); + } catch ( InvalidArgumentException $ex ) { + $this->assertSame( + 'Cannot add resource(stream) to ApiResult', + $ex->getMessage(), + 'Expected exception' + ); + } + fclose( $fh ); + + try { + $result->addValue( null, 'inf', INF ); + $this->fail( 'Expected exception not thrown' ); + } catch ( InvalidArgumentException $ex ) { + $this->assertSame( + 'Cannot add non-finite floats to ApiResult', + $ex->getMessage(), + 'Expected exception' + ); + } + try { + $result->addValue( null, null, INF ); + $this->fail( 'Expected exception not thrown' ); + } catch ( InvalidArgumentException $ex ) { + $this->assertSame( + 'Cannot add non-finite floats to ApiResult', + $ex->getMessage(), + 'Expected exception' + ); + } + try { + $result->addValue( null, 'nan', NAN ); + $this->fail( 'Expected exception not thrown' ); + } catch ( InvalidArgumentException $ex ) { + $this->assertSame( + 'Cannot add non-finite floats to ApiResult', + $ex->getMessage(), + 'Expected exception' + ); + } + try { + $result->addValue( null, null, NAN ); + $this->fail( 'Expected exception not thrown' ); + } catch ( InvalidArgumentException $ex ) { + $this->assertSame( + 'Cannot add non-finite floats to ApiResult', + $ex->getMessage(), + 'Expected exception' + ); + } + + $result->reset(); + $result->addParsedLimit( 'foo', 12 ); + $this->assertSame( array( + 'limits' => array( 'foo' => 12 ), + ApiResult::META_TYPE => 'assoc', + ), $result->getResultData() ); + $result->addParsedLimit( 'foo', 13 ); + $this->assertSame( array( + 'limits' => array( 'foo' => 13 ), + ApiResult::META_TYPE => 'assoc', + ), $result->getResultData() ); + $this->assertSame( null, $result->getResultData( array( 'foo', 'bar', 'baz' ) ) ); + $this->assertSame( 13, $result->getResultData( array( 'limits', 'foo' ) ) ); + try { + $result->getResultData( array( 'limits', 'foo', 'bar' ) ); + $this->fail( 'Expected exception not thrown' ); + } catch ( InvalidArgumentException $ex ) { + $this->assertSame( + 'Path limits.foo is not an array', + $ex->getMessage(), + 'Expected exception' + ); + } + + $result = new ApiResult( 10 ); + $formatter = new ApiErrorFormatter( $result, Language::factory( 'en' ), 'none', false ); + $result->setErrorFormatter( $formatter ); + $this->assertFalse( $result->addValue( null, 'foo', '12345678901' ) ); + $this->assertTrue( $result->addValue( null, 'foo', '12345678901', ApiResult::NO_SIZE_CHECK ) ); + $this->assertSame( 0, $result->getSize() ); + $result->reset(); + $this->assertTrue( $result->addValue( null, 'foo', '1234567890' ) ); + $this->assertFalse( $result->addValue( null, 'foo', '1' ) ); + $result->removeValue( null, 'foo' ); + $this->assertTrue( $result->addValue( null, 'foo', '1' ) ); + + $result = new ApiResult( 8388608 ); + $result2 = new ApiResult( 8388608 ); + $result2->addValue( null, 'foo', 'bar' ); + $result->addValue( null, 'baz', $result2 ); + $this->assertSame( array( + 'baz' => array( + 'foo' => 'bar', + ApiResult::META_TYPE => 'assoc', + ), + ApiResult::META_TYPE => 'assoc', + ), $result->getResultData() ); + + $result = new ApiResult( 8388608 ); + $result->addValue( null, 'foo', "foo\x80bar" ); + $result->addValue( null, 'bar', "a\xcc\x81" ); + $result->addValue( null, 'baz', 74 ); + $result->addValue( null, null, "foo\x80bar" ); + $result->addValue( null, null, "a\xcc\x81" ); + $this->assertSame( array( + 'foo' => "foo\xef\xbf\xbdbar", + 'bar' => "\xc3\xa1", + 'baz' => 74, + 0 => "foo\xef\xbf\xbdbar", + 1 => "\xc3\xa1", + ApiResult::META_TYPE => 'assoc', + ), $result->getResultData() ); + } + + /** + * @covers ApiResult + */ + public function testMetadata() { + $arr = array( 'foo' => array( 'bar' => array() ) ); + $result = new ApiResult( 8388608 ); + $result->addValue( null, 'foo', array( 'bar' => array() ) ); + + $expect = array( + 'foo' => array( + 'bar' => array( + ApiResult::META_INDEXED_TAG_NAME => 'ritn', + ApiResult::META_TYPE => 'default', + ), + ApiResult::META_INDEXED_TAG_NAME => 'ritn', + ApiResult::META_TYPE => 'default', + ), + ApiResult::META_SUBELEMENTS => array( 'foo', 'bar' ), + ApiResult::META_INDEXED_TAG_NAME => 'itn', + ApiResult::META_PRESERVE_KEYS => array( 'foo', 'bar' ), + ApiResult::META_TYPE => 'array', + ); + + ApiResult::setSubelementsList( $arr, 'foo' ); + ApiResult::setSubelementsList( $arr, array( 'bar', 'baz' ) ); + ApiResult::unsetSubelementsList( $arr, 'baz' ); + ApiResult::setIndexedTagNameRecursive( $arr, 'ritn' ); + ApiResult::setIndexedTagName( $arr, 'itn' ); + ApiResult::setPreserveKeysList( $arr, 'foo' ); + ApiResult::setPreserveKeysList( $arr, array( 'bar', 'baz' ) ); + ApiResult::unsetPreserveKeysList( $arr, 'baz' ); + ApiResult::setArrayTypeRecursive( $arr, 'default' ); + ApiResult::setArrayType( $arr, 'array' ); + $this->assertSame( $expect, $arr ); + + $result->addSubelementsList( null, 'foo' ); + $result->addSubelementsList( null, array( 'bar', 'baz' ) ); + $result->removeSubelementsList( null, 'baz' ); + $result->addIndexedTagNameRecursive( null, 'ritn' ); + $result->addIndexedTagName( null, 'itn' ); + $result->addPreserveKeysList( null, 'foo' ); + $result->addPreserveKeysList( null, array( 'bar', 'baz' ) ); + $result->removePreserveKeysList( null, 'baz' ); + $result->addArrayTypeRecursive( null, 'default' ); + $result->addArrayType( null, 'array' ); + $this->assertEquals( $expect, $result->getResultData() ); + + $arr = array( 'foo' => array( 'bar' => array() ) ); + $expect = array( + 'foo' => array( + 'bar' => array( + ApiResult::META_TYPE => 'kvp', + ApiResult::META_KVP_KEY_NAME => 'key', + ), + ApiResult::META_TYPE => 'kvp', + ApiResult::META_KVP_KEY_NAME => 'key', + ), + ApiResult::META_TYPE => 'BCkvp', + ApiResult::META_KVP_KEY_NAME => 'bc', + ); + ApiResult::setArrayTypeRecursive( $arr, 'kvp', 'key' ); + ApiResult::setArrayType( $arr, 'BCkvp', 'bc' ); + $this->assertSame( $expect, $arr ); + } + + /** + * @covers ApiResult + */ + public function testUtilityFunctions() { + $arr = array( + 'foo' => array( + 'bar' => array( '_dummy' => 'foobaz' ), + 'bar2' => (object)array( '_dummy' => 'foobaz' ), + 'x' => 'ok', + '_dummy' => 'foobaz', + ), + 'foo2' => (object)array( + 'bar' => array( '_dummy' => 'foobaz' ), + 'bar2' => (object)array( '_dummy' => 'foobaz' ), + 'x' => 'ok', + '_dummy' => 'foobaz', + ), + ApiResult::META_SUBELEMENTS => array( 'foo', 'bar' ), + ApiResult::META_INDEXED_TAG_NAME => 'itn', + ApiResult::META_PRESERVE_KEYS => array( 'foo', 'bar', '_dummy2', 0 ), + ApiResult::META_TYPE => 'array', + '_dummy' => 'foobaz', + '_dummy2' => 'foobaz!', + ); + $this->assertEquals( array( + 'foo' => array( + 'bar' => array(), + 'bar2' => (object)array(), + 'x' => 'ok', + ), + 'foo2' => (object)array( + 'bar' => array(), + 'bar2' => (object)array(), + 'x' => 'ok', + ), + '_dummy2' => 'foobaz!', + ), ApiResult::stripMetadata( $arr ), 'ApiResult::stripMetadata' ); + + $metadata = array(); + $data = ApiResult::stripMetadataNonRecursive( $arr, $metadata ); + $this->assertEquals( array( + 'foo' => array( + 'bar' => array( '_dummy' => 'foobaz' ), + 'bar2' => (object)array( '_dummy' => 'foobaz' ), + 'x' => 'ok', + '_dummy' => 'foobaz', + ), + 'foo2' => (object)array( + 'bar' => array( '_dummy' => 'foobaz' ), + 'bar2' => (object)array( '_dummy' => 'foobaz' ), + 'x' => 'ok', + '_dummy' => 'foobaz', + ), + '_dummy2' => 'foobaz!', + ), $data, 'ApiResult::stripMetadataNonRecursive ($data)' ); + $this->assertEquals( array( + ApiResult::META_SUBELEMENTS => array( 'foo', 'bar' ), + ApiResult::META_INDEXED_TAG_NAME => 'itn', + ApiResult::META_PRESERVE_KEYS => array( 'foo', 'bar', '_dummy2', 0 ), + ApiResult::META_TYPE => 'array', + '_dummy' => 'foobaz', + ), $metadata, 'ApiResult::stripMetadataNonRecursive ($metadata)' ); + + $metadata = null; + $data = ApiResult::stripMetadataNonRecursive( (object)$arr, $metadata ); + $this->assertEquals( (object)array( + 'foo' => array( + 'bar' => array( '_dummy' => 'foobaz' ), + 'bar2' => (object)array( '_dummy' => 'foobaz' ), + 'x' => 'ok', + '_dummy' => 'foobaz', + ), + 'foo2' => (object)array( + 'bar' => array( '_dummy' => 'foobaz' ), + 'bar2' => (object)array( '_dummy' => 'foobaz' ), + 'x' => 'ok', + '_dummy' => 'foobaz', + ), + '_dummy2' => 'foobaz!', + ), $data, 'ApiResult::stripMetadataNonRecursive on object ($data)' ); + $this->assertEquals( array( + ApiResult::META_SUBELEMENTS => array( 'foo', 'bar' ), + ApiResult::META_INDEXED_TAG_NAME => 'itn', + ApiResult::META_PRESERVE_KEYS => array( 'foo', 'bar', '_dummy2', 0 ), + ApiResult::META_TYPE => 'array', + '_dummy' => 'foobaz', + ), $metadata, 'ApiResult::stripMetadataNonRecursive on object ($metadata)' ); + } + + /** + * @covers ApiResult + * @dataProvider provideTransformations + * @param string $label + * @param array $input + * @param array $transforms + * @param array|Exception $expect + */ + public function testTransformations( $label, $input, $transforms, $expect ) { + $result = new ApiResult( false ); + $result->addValue( null, 'test', $input ); + + if ( $expect instanceof Exception ) { + try { + $output = $result->getResultData( 'test', $transforms ); + $this->fail( 'Expected exception not thrown', $label ); + } catch ( Exception $ex ) { + $this->assertEquals( $ex, $expect, $label ); + } + } else { + $output = $result->getResultData( 'test', $transforms ); + $this->assertEquals( $expect, $output, $label ); + } + } + + public function provideTransformations() { + $kvp = function ( $keyKey, $key, $valKey, $value ) { + return array( + $keyKey => $key, + $valKey => $value, + ApiResult::META_PRESERVE_KEYS => array( $keyKey ), + ApiResult::META_CONTENT => $valKey, + ApiResult::META_TYPE => 'assoc', + ); + }; + $typeArr = array( + 'defaultArray' => array( 2 => 'a', 0 => 'b', 1 => 'c' ), + 'defaultAssoc' => array( 'x' => 'a', 1 => 'b', 0 => 'c' ), + 'defaultAssoc2' => array( 2 => 'a', 3 => 'b', 0 => 'c' ), + 'array' => array( 'x' => 'a', 1 => 'b', 0 => 'c', ApiResult::META_TYPE => 'array' ), + 'BCarray' => array( 'x' => 'a', 1 => 'b', 0 => 'c', ApiResult::META_TYPE => 'BCarray' ), + 'BCassoc' => array( 'a', 'b', 'c', ApiResult::META_TYPE => 'BCassoc' ), + 'assoc' => array( 2 => 'a', 0 => 'b', 1 => 'c', ApiResult::META_TYPE => 'assoc' ), + 'kvp' => array( 'x' => 'a', 'y' => 'b', 'z' => array( 'c' ), ApiResult::META_TYPE => 'kvp' ), + 'BCkvp' => array( 'x' => 'a', 'y' => 'b', + ApiResult::META_TYPE => 'BCkvp', + ApiResult::META_KVP_KEY_NAME => 'key', + ), + 'emptyDefault' => array( '_dummy' => 1 ), + 'emptyAssoc' => array( '_dummy' => 1, ApiResult::META_TYPE => 'assoc' ), + '_dummy' => 1, + ApiResult::META_PRESERVE_KEYS => array( '_dummy' ), + ); + $stripArr = array( + 'foo' => array( + 'bar' => array( '_dummy' => 'foobaz' ), + 'baz' => array( + ApiResult::META_SUBELEMENTS => array( 'foo', 'bar' ), + ApiResult::META_INDEXED_TAG_NAME => 'itn', + ApiResult::META_PRESERVE_KEYS => array( 'foo', 'bar', '_dummy2', 0 ), + ApiResult::META_TYPE => 'array', + ), + 'x' => 'ok', + '_dummy' => 'foobaz', + ), + ApiResult::META_SUBELEMENTS => array( 'foo', 'bar' ), + ApiResult::META_INDEXED_TAG_NAME => 'itn', + ApiResult::META_PRESERVE_KEYS => array( 'foo', 'bar', '_dummy2', 0 ), + ApiResult::META_TYPE => 'array', + '_dummy' => 'foobaz', + '_dummy2' => 'foobaz!', + ); + + return array( + array( + 'BC: META_BC_BOOLS', + array( + 'BCtrue' => true, + 'BCfalse' => false, + 'true' => true, + 'false' => false, + ApiResult::META_BC_BOOLS => array( 0, 'true', 'false' ), + ), + array( 'BC' => array() ), + array( + 'BCtrue' => '', + 'true' => true, + 'false' => false, + ApiResult::META_BC_BOOLS => array( 0, 'true', 'false' ), + ) + ), + array( + 'BC: META_BC_SUBELEMENTS', + array( + 'bc' => 'foo', + 'nobc' => 'bar', + ApiResult::META_BC_SUBELEMENTS => array( 'bc' ), + ), + array( 'BC' => array() ), + array( + 'bc' => array( + '*' => 'foo', + ApiResult::META_CONTENT => '*', + ApiResult::META_TYPE => 'assoc', + ), + 'nobc' => 'bar', + ApiResult::META_BC_SUBELEMENTS => array( 'bc' ), + ), + ), + array( + 'BC: META_CONTENT', + array( + 'content' => '!!!', + ApiResult::META_CONTENT => 'content', + ), + array( 'BC' => array() ), + array( + '*' => '!!!', + ApiResult::META_CONTENT => '*', + ), + ), + array( + 'BC: BCkvp type', + array( + 'foo' => 'foo value', + 'bar' => 'bar value', + '_baz' => 'baz value', + ApiResult::META_TYPE => 'BCkvp', + ApiResult::META_KVP_KEY_NAME => 'key', + ApiResult::META_PRESERVE_KEYS => array( '_baz' ), + ), + array( 'BC' => array() ), + array( + $kvp( 'key', 'foo', '*', 'foo value' ), + $kvp( 'key', 'bar', '*', 'bar value' ), + $kvp( 'key', '_baz', '*', 'baz value' ), + ApiResult::META_TYPE => 'array', + ApiResult::META_KVP_KEY_NAME => 'key', + ApiResult::META_PRESERVE_KEYS => array( '_baz' ), + ), + ), + array( + 'BC: BCarray type', + array( + ApiResult::META_TYPE => 'BCarray', + ), + array( 'BC' => array() ), + array( + ApiResult::META_TYPE => 'default', + ), + ), + array( + 'BC: BCassoc type', + array( + ApiResult::META_TYPE => 'BCassoc', + ), + array( 'BC' => array() ), + array( + ApiResult::META_TYPE => 'default', + ), + ), + array( + 'BC: BCkvp exception', + array( + ApiResult::META_TYPE => 'BCkvp', + ), + array( 'BC' => array() ), + new UnexpectedValueException( + 'Type "BCkvp" used without setting ApiResult::META_KVP_KEY_NAME metadata item' + ), + ), + array( + 'BC: nobool, no*, nosub', + array( + 'true' => true, + 'false' => false, + 'content' => 'content', + ApiResult::META_CONTENT => 'content', + 'bc' => 'foo', + ApiResult::META_BC_SUBELEMENTS => array( 'bc' ), + 'BCarray' => array( ApiResult::META_TYPE => 'BCarray' ), + 'BCassoc' => array( ApiResult::META_TYPE => 'BCassoc' ), + 'BCkvp' => array( + 'foo' => 'foo value', + 'bar' => 'bar value', + '_baz' => 'baz value', + ApiResult::META_TYPE => 'BCkvp', + ApiResult::META_KVP_KEY_NAME => 'key', + ApiResult::META_PRESERVE_KEYS => array( '_baz' ), + ), + ), + array( 'BC' => array( 'nobool', 'no*', 'nosub' ) ), + array( + 'true' => true, + 'false' => false, + 'content' => 'content', + 'bc' => 'foo', + 'BCarray' => array( ApiResult::META_TYPE => 'default' ), + 'BCassoc' => array( ApiResult::META_TYPE => 'default' ), + 'BCkvp' => array( + $kvp( 'key', 'foo', '*', 'foo value' ), + $kvp( 'key', 'bar', '*', 'bar value' ), + $kvp( 'key', '_baz', '*', 'baz value' ), + ApiResult::META_TYPE => 'array', + ApiResult::META_KVP_KEY_NAME => 'key', + ApiResult::META_PRESERVE_KEYS => array( '_baz' ), + ), + ApiResult::META_CONTENT => 'content', + ApiResult::META_BC_SUBELEMENTS => array( 'bc' ), + ), + ), + + array( + 'Types: Normal transform', + $typeArr, + array( 'Types' => array() ), + array( + 'defaultArray' => array( 'b', 'c', 'a', ApiResult::META_TYPE => 'array' ), + 'defaultAssoc' => array( 'x' => 'a', 1 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ), + 'defaultAssoc2' => array( 2 => 'a', 3 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ), + 'array' => array( 'a', 'c', 'b', ApiResult::META_TYPE => 'array' ), + 'BCarray' => array( 'a', 'c', 'b', ApiResult::META_TYPE => 'array' ), + 'BCassoc' => array( 'a', 'b', 'c', ApiResult::META_TYPE => 'assoc' ), + 'assoc' => array( 2 => 'a', 0 => 'b', 1 => 'c', ApiResult::META_TYPE => 'assoc' ), + 'kvp' => array( 'x' => 'a', 'y' => 'b', + 'z' => array( 'c', ApiResult::META_TYPE => 'array' ), + ApiResult::META_TYPE => 'assoc' + ), + 'BCkvp' => array( 'x' => 'a', 'y' => 'b', + ApiResult::META_TYPE => 'assoc', + ApiResult::META_KVP_KEY_NAME => 'key', + ), + 'emptyDefault' => array( '_dummy' => 1, ApiResult::META_TYPE => 'array' ), + 'emptyAssoc' => array( '_dummy' => 1, ApiResult::META_TYPE => 'assoc' ), + '_dummy' => 1, + ApiResult::META_PRESERVE_KEYS => array( '_dummy' ), + ApiResult::META_TYPE => 'assoc', + ), + ), + array( + 'Types: AssocAsObject', + $typeArr, + array( 'Types' => array( 'AssocAsObject' => true ) ), + (object)array( + 'defaultArray' => array( 'b', 'c', 'a', ApiResult::META_TYPE => 'array' ), + 'defaultAssoc' => (object)array( 'x' => 'a', 1 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ), + 'defaultAssoc2' => (object)array( 2 => 'a', 3 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ), + 'array' => array( 'a', 'c', 'b', ApiResult::META_TYPE => 'array' ), + 'BCarray' => array( 'a', 'c', 'b', ApiResult::META_TYPE => 'array' ), + 'BCassoc' => (object)array( 'a', 'b', 'c', ApiResult::META_TYPE => 'assoc' ), + 'assoc' => (object)array( 2 => 'a', 0 => 'b', 1 => 'c', ApiResult::META_TYPE => 'assoc' ), + 'kvp' => (object)array( 'x' => 'a', 'y' => 'b', + 'z' => array( 'c', ApiResult::META_TYPE => 'array' ), + ApiResult::META_TYPE => 'assoc' + ), + 'BCkvp' => (object)array( 'x' => 'a', 'y' => 'b', + ApiResult::META_TYPE => 'assoc', + ApiResult::META_KVP_KEY_NAME => 'key', + ), + 'emptyDefault' => array( '_dummy' => 1, ApiResult::META_TYPE => 'array' ), + 'emptyAssoc' => (object)array( '_dummy' => 1, ApiResult::META_TYPE => 'assoc' ), + '_dummy' => 1, + ApiResult::META_PRESERVE_KEYS => array( '_dummy' ), + ApiResult::META_TYPE => 'assoc', + ), + ), + array( + 'Types: ArmorKVP', + $typeArr, + array( 'Types' => array( 'ArmorKVP' => 'name' ) ), + array( + 'defaultArray' => array( 'b', 'c', 'a', ApiResult::META_TYPE => 'array' ), + 'defaultAssoc' => array( 'x' => 'a', 1 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ), + 'defaultAssoc2' => array( 2 => 'a', 3 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ), + 'array' => array( 'a', 'c', 'b', ApiResult::META_TYPE => 'array' ), + 'BCarray' => array( 'a', 'c', 'b', ApiResult::META_TYPE => 'array' ), + 'BCassoc' => array( 'a', 'b', 'c', ApiResult::META_TYPE => 'assoc' ), + 'assoc' => array( 2 => 'a', 0 => 'b', 1 => 'c', ApiResult::META_TYPE => 'assoc' ), + 'kvp' => array( + $kvp( 'name', 'x', 'value', 'a' ), + $kvp( 'name', 'y', 'value', 'b' ), + $kvp( 'name', 'z', 'value', array( 'c', ApiResult::META_TYPE => 'array' ) ), + ApiResult::META_TYPE => 'array' + ), + 'BCkvp' => array( + $kvp( 'key', 'x', 'value', 'a' ), + $kvp( 'key', 'y', 'value', 'b' ), + ApiResult::META_TYPE => 'array', + ApiResult::META_KVP_KEY_NAME => 'key', + ), + 'emptyDefault' => array( '_dummy' => 1, ApiResult::META_TYPE => 'array' ), + 'emptyAssoc' => array( '_dummy' => 1, ApiResult::META_TYPE => 'assoc' ), + '_dummy' => 1, + ApiResult::META_PRESERVE_KEYS => array( '_dummy' ), + ApiResult::META_TYPE => 'assoc', + ), + ), + array( + 'Types: ArmorKVP + BC', + $typeArr, + array( 'BC' => array(), 'Types' => array( 'ArmorKVP' => 'name' ) ), + array( + 'defaultArray' => array( 'b', 'c', 'a', ApiResult::META_TYPE => 'array' ), + 'defaultAssoc' => array( 'x' => 'a', 1 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ), + 'defaultAssoc2' => array( 2 => 'a', 3 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ), + 'array' => array( 'a', 'c', 'b', ApiResult::META_TYPE => 'array' ), + 'BCarray' => array( 'x' => 'a', 1 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ), + 'BCassoc' => array( 'a', 'b', 'c', ApiResult::META_TYPE => 'array' ), + 'assoc' => array( 2 => 'a', 0 => 'b', 1 => 'c', ApiResult::META_TYPE => 'assoc' ), + 'kvp' => array( + $kvp( 'name', 'x', '*', 'a' ), + $kvp( 'name', 'y', '*', 'b' ), + $kvp( 'name', 'z', '*', array( 'c', ApiResult::META_TYPE => 'array' ) ), + ApiResult::META_TYPE => 'array' + ), + 'BCkvp' => array( + $kvp( 'key', 'x', '*', 'a' ), + $kvp( 'key', 'y', '*', 'b' ), + ApiResult::META_TYPE => 'array', + ApiResult::META_KVP_KEY_NAME => 'key', + ), + 'emptyDefault' => array( '_dummy' => 1, ApiResult::META_TYPE => 'array' ), + 'emptyAssoc' => array( '_dummy' => 1, ApiResult::META_TYPE => 'assoc' ), + '_dummy' => 1, + ApiResult::META_PRESERVE_KEYS => array( '_dummy' ), + ApiResult::META_TYPE => 'assoc', + ), + ), + array( + 'Types: ArmorKVP + AssocAsObject', + $typeArr, + array( 'Types' => array( 'ArmorKVP' => 'name', 'AssocAsObject' => true ) ), + (object)array( + 'defaultArray' => array( 'b', 'c', 'a', ApiResult::META_TYPE => 'array' ), + 'defaultAssoc' => (object)array( 'x' => 'a', 1 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ), + 'defaultAssoc2' => (object)array( 2 => 'a', 3 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ), + 'array' => array( 'a', 'c', 'b', ApiResult::META_TYPE => 'array' ), + 'BCarray' => array( 'a', 'c', 'b', ApiResult::META_TYPE => 'array' ), + 'BCassoc' => (object)array( 'a', 'b', 'c', ApiResult::META_TYPE => 'assoc' ), + 'assoc' => (object)array( 2 => 'a', 0 => 'b', 1 => 'c', ApiResult::META_TYPE => 'assoc' ), + 'kvp' => array( + (object)$kvp( 'name', 'x', 'value', 'a' ), + (object)$kvp( 'name', 'y', 'value', 'b' ), + (object)$kvp( 'name', 'z', 'value', array( 'c', ApiResult::META_TYPE => 'array' ) ), + ApiResult::META_TYPE => 'array' + ), + 'BCkvp' => array( + (object)$kvp( 'key', 'x', 'value', 'a' ), + (object)$kvp( 'key', 'y', 'value', 'b' ), + ApiResult::META_TYPE => 'array', + ApiResult::META_KVP_KEY_NAME => 'key', + ), + 'emptyDefault' => array( '_dummy' => 1, ApiResult::META_TYPE => 'array' ), + 'emptyAssoc' => (object)array( '_dummy' => 1, ApiResult::META_TYPE => 'assoc' ), + '_dummy' => 1, + ApiResult::META_PRESERVE_KEYS => array( '_dummy' ), + ApiResult::META_TYPE => 'assoc', + ), + ), + array( + 'Types: BCkvp exception', + array( + ApiResult::META_TYPE => 'BCkvp', + ), + array( 'Types' => array() ), + new UnexpectedValueException( + 'Type "BCkvp" used without setting ApiResult::META_KVP_KEY_NAME metadata item' + ), + ), + + array( + 'Strip: With ArmorKVP + AssocAsObject transforms', + $typeArr, + array( 'Types' => array( 'ArmorKVP' => 'name', 'AssocAsObject' => true ), 'Strip' => 'all' ), + (object)array( + 'defaultArray' => array( 'b', 'c', 'a' ), + 'defaultAssoc' => (object)array( 'x' => 'a', 1 => 'b', 0 => 'c' ), + 'defaultAssoc2' => (object)array( 2 => 'a', 3 => 'b', 0 => 'c' ), + 'array' => array( 'a', 'c', 'b' ), + 'BCarray' => array( 'a', 'c', 'b' ), + 'BCassoc' => (object)array( 'a', 'b', 'c' ), + 'assoc' => (object)array( 2 => 'a', 0 => 'b', 1 => 'c' ), + 'kvp' => array( + (object)array( 'name' => 'x', 'value' => 'a' ), + (object)array( 'name' => 'y', 'value' => 'b' ), + (object)array( 'name' => 'z', 'value' => array( 'c' ) ), + ), + 'BCkvp' => array( + (object)array( 'key' => 'x', 'value' => 'a' ), + (object)array( 'key' => 'y', 'value' => 'b' ), + ), + 'emptyDefault' => array(), + 'emptyAssoc' => (object)array(), + '_dummy' => 1, + ), + ), + + array( + 'Strip: all', + $stripArr, + array( 'Strip' => 'all' ), + array( + 'foo' => array( + 'bar' => array(), + 'baz' => array(), + 'x' => 'ok', + ), + '_dummy2' => 'foobaz!', + ), + ), + array( + 'Strip: base', + $stripArr, + array( 'Strip' => 'base' ), + array( + 'foo' => array( + 'bar' => array( '_dummy' => 'foobaz' ), + 'baz' => array( + ApiResult::META_SUBELEMENTS => array( 'foo', 'bar' ), + ApiResult::META_INDEXED_TAG_NAME => 'itn', + ApiResult::META_PRESERVE_KEYS => array( 'foo', 'bar', '_dummy2', 0 ), + ApiResult::META_TYPE => 'array', + ), + 'x' => 'ok', + '_dummy' => 'foobaz', + ), + '_dummy2' => 'foobaz!', + ), + ), + array( + 'Strip: bc', + $stripArr, + array( 'Strip' => 'bc' ), + array( + 'foo' => array( + 'bar' => array(), + 'baz' => array( + ApiResult::META_SUBELEMENTS => array( 'foo', 'bar' ), + ApiResult::META_INDEXED_TAG_NAME => 'itn', + ), + 'x' => 'ok', + ), + '_dummy2' => 'foobaz!', + ApiResult::META_SUBELEMENTS => array( 'foo', 'bar' ), + ApiResult::META_INDEXED_TAG_NAME => 'itn', + ), + ), + + array( + 'Custom transform', + array( + 'foo' => '?', + 'bar' => '?', + '_dummy' => '?', + '_dummy2' => '?', + '_dummy3' => '?', + ApiResult::META_CONTENT => 'foo', + ApiResult::META_PRESERVE_KEYS => array( '_dummy2', '_dummy3' ), + ), + array( + 'Custom' => array( $this, 'customTransform' ), + 'BC' => array(), + 'Types' => array(), + 'Strip' => 'all' + ), + array( + '*' => 'FOO', + 'bar' => 'BAR', + 'baz' => array( 'a', 'b' ), + '_dummy2' => '_DUMMY2', + '_dummy3' => '_DUMMY3', + ApiResult::META_CONTENT => 'bar', + ), + ), + ); + + } + + /** + * Custom transformer for testTransformations + * @param array &$data + * @param array &$metadata + */ + public function customTransform( &$data, &$metadata ) { + // Prevent recursion + if ( isset( $metadata['_added'] ) ) { + $metadata[ApiResult::META_TYPE] = 'array'; + return; + } + + foreach ( $data as $k => $v ) { + $data[$k] = strtoupper( $k ); + } + $data['baz'] = array( '_added' => 1, 'z' => 'b', 'y' => 'a' ); + $metadata[ApiResult::META_PRESERVE_KEYS][0] = '_dummy'; + $data[ApiResult::META_CONTENT] = 'bar'; + } + + /** + * @covers ApiResult + */ + public function testDeprecatedFunctions() { + // Ignore ApiResult deprecation warnings during this test + set_error_handler( function ( $errno, $errstr ) use ( &$warnings ) { + if ( preg_match( '/Use of ApiResult::\S+ was deprecated in MediaWiki \d+.\d+\./', $errstr ) ) { + return true; + } + if ( preg_match( '/Use of ApiMain to ApiResult::__construct was deprecated in MediaWiki \d+.\d+\./', $errstr ) ) { + return true; + } + return false; + } ); + $reset = new ScopedCallback( 'restore_error_handler' ); + + $context = new DerivativeContext( RequestContext::getMain() ); + $context->setConfig( new HashConfig( array( + 'APIModules' => array(), + 'APIFormatModules' => array(), + 'APIMaxResultSize' => 42, + ) ) ); + $main = new ApiMain( $context ); + $result = TestingAccessWrapper::newFromObject( new ApiResult( $main ) ); + $this->assertSame( 42, $result->maxSize ); + $this->assertSame( $main->getErrorFormatter(), $result->errorFormatter ); + $this->assertSame( $main, $result->mainForContinuation ); + + $result = new ApiResult( 8388608 ); + + $result->addContentValue( null, 'test', 'content' ); + $result->addContentValue( array( 'foo', 'bar' ), 'test', 'content' ); + $result->addIndexedTagName( null, 'itn' ); + $result->addSubelementsList( null, array( 'sub' ) ); + $this->assertSame( array( + 'foo' => array( + 'bar' => array( + '*' => 'content', + ), + ), + '*' => 'content', + ), $result->getData() ); + $result->setRawMode(); + $this->assertSame( array( + 'foo' => array( + 'bar' => array( + '*' => 'content', + ), + ), + '*' => 'content', + '_element' => 'itn', + '_subelements' => array( 'sub' ), + ), $result->getData() ); + + $arr = array(); + ApiResult::setContent( $arr, 'value' ); + ApiResult::setContent( $arr, 'value2', 'foobar' ); + $this->assertSame( array( + ApiResult::META_CONTENT => 'content', + 'content' => 'value', + 'foobar' => array( + ApiResult::META_CONTENT => 'content', + 'content' => 'value2', + ), + ), $arr ); + + $result = new ApiResult( 3 ); + $formatter = new ApiErrorFormatter_BackCompat( $result ); + $result->setErrorFormatter( $formatter ); + $result->disableSizeCheck(); + $this->assertTrue( $result->addValue( null, 'foo', '1234567890' ) ); + $result->enableSizeCheck(); + $this->assertSame( 0, $result->getSize() ); + $this->assertFalse( $result->addValue( null, 'foo', '1234567890' ) ); + + $arr = array( 'foo' => array( 'bar' => 1 ) ); + $result->setIndexedTagName_recursive( $arr, 'itn' ); + $this->assertSame( array( + 'foo' => array( + 'bar' => 1, + ApiResult::META_INDEXED_TAG_NAME => 'itn' + ), + ), $arr ); + + $status = Status::newGood(); + $status->fatal( 'parentheses', '1' ); + $status->fatal( 'parentheses', '2' ); + $status->warning( 'parentheses', '3' ); + $status->warning( 'parentheses', '4' ); + $this->assertSame( array( + array( + 'type' => 'error', + 'message' => 'parentheses', + 'params' => array( + 0 => '1', + ApiResult::META_INDEXED_TAG_NAME => 'param', + ), + ), + array( + 'type' => 'error', + 'message' => 'parentheses', + 'params' => array( + 0 => '2', + ApiResult::META_INDEXED_TAG_NAME => 'param', + ), + ), + ApiResult::META_INDEXED_TAG_NAME => 'error', + ), $result->convertStatusToArray( $status, 'error' ) ); + $this->assertSame( array( + array( + 'type' => 'warning', + 'message' => 'parentheses', + 'params' => array( + 0 => '3', + ApiResult::META_INDEXED_TAG_NAME => 'param', + ), + ), + array( + 'type' => 'warning', + 'message' => 'parentheses', + 'params' => array( + 0 => '4', + ApiResult::META_INDEXED_TAG_NAME => 'param', + ), + ), + ApiResult::META_INDEXED_TAG_NAME => 'warning', + ), $result->convertStatusToArray( $status, 'warning' ) ); + } + + /** + * @covers ApiResult + */ + public function testDeprecatedContinuation() { + // Ignore ApiResult deprecation warnings during this test + set_error_handler( function ( $errno, $errstr ) use ( &$warnings ) { + if ( preg_match( '/Use of ApiResult::\S+ was deprecated in MediaWiki \d+.\d+\./', $errstr ) ) { + return true; + } + return false; + } ); + + $reset = new ScopedCallback( 'restore_error_handler' ); + $allModules = array( + new MockApiQueryBase( 'mock1' ), + new MockApiQueryBase( 'mock2' ), + new MockApiQueryBase( 'mocklist' ), + ); + $generator = new MockApiQueryBase( 'generator' ); + + $main = new ApiMain( RequestContext::getMain() ); + $result = new ApiResult( 8388608 ); + $result->setMainForContinuation( $main ); + $ret = $result->beginContinuation( null, $allModules, array( 'mock1', 'mock2' ) ); + $this->assertSame( array( false, $allModules ), $ret ); + $result->setContinueParam( $allModules[0], 'm1continue', array( 1, 2 ) ); + $result->setContinueParam( $allModules[2], 'mlcontinue', 2 ); + $result->setGeneratorContinueParam( $generator, 'gcontinue', 3 ); + $result->endContinuation( 'raw' ); + $result->endContinuation( 'standard' ); + $this->assertSame( array( + 'mlcontinue' => 2, + 'm1continue' => '1|2', + 'continue' => '||mock2', + ), $result->getResultData( 'continue' ) ); + $this->assertSame( null, $result->getResultData( 'batchcomplete' ) ); + $this->assertSame( array( + 'mock1' => array( 'm1continue' => '1|2' ), + 'mocklist' => array( 'mlcontinue' => 2 ), + 'generator' => array( 'gcontinue' => 3 ), + ), $result->getResultData( 'query-continue' ) ); + $main->setContinuationManager( null ); + + $result = new ApiResult( 8388608 ); + $result->setMainForContinuation( $main ); + $ret = $result->beginContinuation( null, $allModules, array( 'mock1', 'mock2' ) ); + $this->assertSame( array( false, $allModules ), $ret ); + $result->setContinueParam( $allModules[0], 'm1continue', array( 1, 2 ) ); + $result->setGeneratorContinueParam( $generator, 'gcontinue', array( 3, 4 ) ); + $result->endContinuation( 'raw' ); + $result->endContinuation( 'standard' ); + $this->assertSame( array( + 'm1continue' => '1|2', + 'continue' => '||mock2|mocklist', + ), $result->getResultData( 'continue' ) ); + $this->assertSame( null, $result->getResultData( 'batchcomplete' ) ); + $this->assertSame( array( + 'mock1' => array( 'm1continue' => '1|2' ), + 'generator' => array( 'gcontinue' => '3|4' ), + ), $result->getResultData( 'query-continue' ) ); + $main->setContinuationManager( null ); + + $result = new ApiResult( 8388608 ); + $result->setMainForContinuation( $main ); + $ret = $result->beginContinuation( null, $allModules, array( 'mock1', 'mock2' ) ); + $this->assertSame( array( false, $allModules ), $ret ); + $result->setContinueParam( $allModules[2], 'mlcontinue', 2 ); + $result->setGeneratorContinueParam( $generator, 'gcontinue', 3 ); + $result->endContinuation( 'raw' ); + $result->endContinuation( 'standard' ); + $this->assertSame( array( + 'mlcontinue' => 2, + 'gcontinue' => 3, + 'continue' => 'gcontinue||', + ), $result->getResultData( 'continue' ) ); + $this->assertSame( true, $result->getResultData( 'batchcomplete' ) ); + $this->assertSame( array( + 'mocklist' => array( 'mlcontinue' => 2 ), + 'generator' => array( 'gcontinue' => 3 ), + ), $result->getResultData( 'query-continue' ) ); + $main->setContinuationManager( null ); + + $result = new ApiResult( 8388608 ); + $result->setMainForContinuation( $main ); + $ret = $result->beginContinuation( null, $allModules, array( 'mock1', 'mock2' ) ); + $this->assertSame( array( false, $allModules ), $ret ); + $result->setGeneratorContinueParam( $generator, 'gcontinue', 3 ); + $result->endContinuation( 'raw' ); + $result->endContinuation( 'standard' ); + $this->assertSame( array( + 'gcontinue' => 3, + 'continue' => 'gcontinue||mocklist', + ), $result->getResultData( 'continue' ) ); + $this->assertSame( true, $result->getResultData( 'batchcomplete' ) ); + $this->assertSame( array( + 'generator' => array( 'gcontinue' => 3 ), + ), $result->getResultData( 'query-continue' ) ); + $main->setContinuationManager( null ); + + $result = new ApiResult( 8388608 ); + $result->setMainForContinuation( $main ); + $ret = $result->beginContinuation( null, $allModules, array( 'mock1', 'mock2' ) ); + $this->assertSame( array( false, $allModules ), $ret ); + $result->setContinueParam( $allModules[0], 'm1continue', array( 1, 2 ) ); + $result->setContinueParam( $allModules[2], 'mlcontinue', 2 ); + $result->endContinuation( 'raw' ); + $result->endContinuation( 'standard' ); + $this->assertSame( array( + 'mlcontinue' => 2, + 'm1continue' => '1|2', + 'continue' => '||mock2', + ), $result->getResultData( 'continue' ) ); + $this->assertSame( null, $result->getResultData( 'batchcomplete' ) ); + $this->assertSame( array( + 'mock1' => array( 'm1continue' => '1|2' ), + 'mocklist' => array( 'mlcontinue' => 2 ), + ), $result->getResultData( 'query-continue' ) ); + $main->setContinuationManager( null ); + + $result = new ApiResult( 8388608 ); + $result->setMainForContinuation( $main ); + $ret = $result->beginContinuation( null, $allModules, array( 'mock1', 'mock2' ) ); + $this->assertSame( array( false, $allModules ), $ret ); + $result->setContinueParam( $allModules[0], 'm1continue', array( 1, 2 ) ); + $result->endContinuation( 'raw' ); + $result->endContinuation( 'standard' ); + $this->assertSame( array( + 'm1continue' => '1|2', + 'continue' => '||mock2|mocklist', + ), $result->getResultData( 'continue' ) ); + $this->assertSame( null, $result->getResultData( 'batchcomplete' ) ); + $this->assertSame( array( + 'mock1' => array( 'm1continue' => '1|2' ), + ), $result->getResultData( 'query-continue' ) ); + $main->setContinuationManager( null ); + + $result = new ApiResult( 8388608 ); + $result->setMainForContinuation( $main ); + $ret = $result->beginContinuation( null, $allModules, array( 'mock1', 'mock2' ) ); + $this->assertSame( array( false, $allModules ), $ret ); + $result->setContinueParam( $allModules[2], 'mlcontinue', 2 ); + $result->endContinuation( 'raw' ); + $result->endContinuation( 'standard' ); + $this->assertSame( array( + 'mlcontinue' => 2, + 'continue' => '-||mock1|mock2', + ), $result->getResultData( 'continue' ) ); + $this->assertSame( true, $result->getResultData( 'batchcomplete' ) ); + $this->assertSame( array( + 'mocklist' => array( 'mlcontinue' => 2 ), + ), $result->getResultData( 'query-continue' ) ); + $main->setContinuationManager( null ); + + $result = new ApiResult( 8388608 ); + $result->setMainForContinuation( $main ); + $ret = $result->beginContinuation( null, $allModules, array( 'mock1', 'mock2' ) ); + $this->assertSame( array( false, $allModules ), $ret ); + $result->endContinuation( 'raw' ); + $result->endContinuation( 'standard' ); + $this->assertSame( null, $result->getResultData( 'continue' ) ); + $this->assertSame( true, $result->getResultData( 'batchcomplete' ) ); + $this->assertSame( null, $result->getResultData( 'query-continue' ) ); + $main->setContinuationManager( null ); + + $result = new ApiResult( 8388608 ); + $result->setMainForContinuation( $main ); + $ret = $result->beginContinuation( '||mock2', $allModules, array( 'mock1', 'mock2' ) ); + $this->assertSame( + array( false, array_values( array_diff_key( $allModules, array( 1 => 1 ) ) ) ), + $ret + ); + $main->setContinuationManager( null ); + + $result = new ApiResult( 8388608 ); + $result->setMainForContinuation( $main ); + $ret = $result->beginContinuation( '-||', $allModules, array( 'mock1', 'mock2' ) ); + $this->assertSame( + array( true, array_values( array_diff_key( $allModules, array( 0 => 0, 1 => 1 ) ) ) ), + $ret + ); + $main->setContinuationManager( null ); + + $result = new ApiResult( 8388608 ); + $result->setMainForContinuation( $main ); + try { + $result->beginContinuation( 'foo', $allModules, array( 'mock1', 'mock2' ) ); + $this->fail( 'Expected exception not thrown' ); + } catch ( UsageException $ex ) { + $this->assertSame( + 'Invalid continue param. You should pass the original value returned by the previous query', + $ex->getMessage(), + 'Expected exception' + ); + } + $main->setContinuationManager( null ); + + $result = new ApiResult( 8388608 ); + $result->setMainForContinuation( $main ); + $result->beginContinuation( '||mock2', array_slice( $allModules, 0, 2 ), array( 'mock1', 'mock2' ) ); + try { + $result->setContinueParam( $allModules[1], 'm2continue', 1 ); + $this->fail( 'Expected exception not thrown' ); + } catch ( UnexpectedValueException $ex ) { + $this->assertSame( + 'Module \'mock2\' was not supposed to have been executed, but it was executed anyway', + $ex->getMessage(), + 'Expected exception' + ); + } + try { + $result->setContinueParam( $allModules[2], 'mlcontinue', 1 ); + $this->fail( 'Expected exception not thrown' ); + } catch ( UnexpectedValueException $ex ) { + $this->assertSame( + 'Module \'mocklist\' called ApiContinuationManager::addContinueParam but was not passed to ApiContinuationManager::__construct', + $ex->getMessage(), + 'Expected exception' + ); + } + $main->setContinuationManager( null ); + + } + + public function testObjectSerialization() { + $arr = array(); + ApiResult::setValue( $arr, 'foo', (object)array( 'a' => 1, 'b' => 2 ) ); + $this->assertSame( array( + 'a' => 1, + 'b' => 2, + ApiResult::META_TYPE => 'assoc', + ), $arr['foo'] ); + + $arr = array(); + ApiResult::setValue( $arr, 'foo', new ApiResultTestStringifiableObject() ); + $this->assertSame( 'Ok', $arr['foo'] ); + + $arr = array(); + ApiResult::setValue( $arr, 'foo', new ApiResultTestSerializableObject( 'Ok' ) ); + $this->assertSame( 'Ok', $arr['foo'] ); + + try { + $arr = array(); + ApiResult::setValue( $arr, 'foo', new ApiResultTestSerializableObject( + new ApiResultTestStringifiableObject() + ) ); + $this->fail( 'Expected exception not thrown' ); + } catch ( UnexpectedValueException $ex ) { + $this->assertSame( + 'ApiResultTestSerializableObject::serializeForApiResult() returned an object of class ApiResultTestStringifiableObject', + $ex->getMessage(), + 'Expected exception' + ); + } + + try { + $arr = array(); + ApiResult::setValue( $arr, 'foo', new ApiResultTestSerializableObject( NAN ) ); + $this->fail( 'Expected exception not thrown' ); + } catch ( UnexpectedValueException $ex ) { + $this->assertSame( + 'ApiResultTestSerializableObject::serializeForApiResult() returned an invalid value: Cannot add non-finite floats to ApiResult', + $ex->getMessage(), + 'Expected exception' + ); + } + + $arr = array(); + ApiResult::setValue( $arr, 'foo', new ApiResultTestSerializableObject( + array( + 'one' => new ApiResultTestStringifiableObject( '1' ), + 'two' => new ApiResultTestSerializableObject( 2 ), + ) + ) ); + $this->assertSame( array( + 'one' => '1', + 'two' => 2, + ), $arr['foo'] ); + } + +} + +class ApiResultTestStringifiableObject { + private $ret; + + public function __construct( $ret = 'Ok' ) { + $this->ret = $ret; + } + + public function __toString() { + return $this->ret; + } +} + +class ApiResultTestSerializableObject { + private $ret; + + public function __construct( $ret ) { + $this->ret = $ret; + } + + public function __toString() { + return "Fail"; + } + + public function serializeForApiResult() { + return $this->ret; + } +} diff --git a/tests/phpunit/includes/api/ApiTestCase.php b/tests/phpunit/includes/api/ApiTestCase.php index cd141947..da62bb0a 100644 --- a/tests/phpunit/includes/api/ApiTestCase.php +++ b/tests/phpunit/includes/api/ApiTestCase.php @@ -8,6 +8,11 @@ abstract class ApiTestCase extends MediaWikiLangTestCase { */ protected $apiContext; + /** + * @var array + */ + protected $tablesUsed = array( 'user', 'user_groups', 'user_properties' ); + protected function setUp() { global $wgServer; @@ -41,6 +46,17 @@ abstract class ApiTestCase extends MediaWikiLangTestCase { $this->apiContext = new ApiTestContext(); } + protected function tearDown() { + // Avoid leaking session over tests + if ( session_id() != '' ) { + global $wgUser; + $wgUser->logout(); + session_destroy(); + } + + parent::tearDown(); + } + /** * Edits or creates a page/revision * @param string $pageName Page title @@ -100,7 +116,7 @@ abstract class ApiTestCase extends MediaWikiLangTestCase { // construct result $results = array( - $module->getResultData(), + $module->getResult()->getResultData( null, array( 'Strip' => 'all' ) ), $context->getRequest(), $context->getRequest()->getSessionArray() ); @@ -134,10 +150,14 @@ abstract class ApiTestCase extends MediaWikiLangTestCase { } if ( isset( $session['wsToken'] ) && $session['wsToken'] ) { + // @todo Why does this directly mess with the session? Fix that. // add edit token to fake session $session['wsEditToken'] = $session['wsToken']; // add token to request parameters - $params['token'] = md5( $session['wsToken'] ) . User::EDIT_TOKEN_SUFFIX; + $timestamp = wfTimestamp(); + $params['token'] = hash_hmac( 'md5', $timestamp, $session['wsToken'] ) . + dechex( $timestamp ) . + User::EDIT_TOKEN_SUFFIX; return $this->doApiRequest( $params, $session, false, $user ); } else { diff --git a/tests/phpunit/includes/api/ApiTestCaseUpload.php b/tests/phpunit/includes/api/ApiTestCaseUpload.php index 7e513394..87f794c1 100644 --- a/tests/phpunit/includes/api/ApiTestCaseUpload.php +++ b/tests/phpunit/includes/api/ApiTestCaseUpload.php @@ -1,9 +1,8 @@ <?php /** - * * Abstract class to support upload tests + * Abstract class to support upload tests */ - abstract class ApiTestCaseUpload extends ApiTestCase { /** * Fixture -- run before every test @@ -21,12 +20,6 @@ abstract class ApiTestCaseUpload extends ApiTestCase { $this->clearFakeUploads(); } - protected function tearDown() { - $this->clearTempUpload(); - - parent::tearDown(); - } - /** * Helper function -- remove files and associated articles by Title * @@ -105,7 +98,7 @@ abstract class ApiTestCaseUpload extends ApiTestCase { * @return bool */ function fakeUploadFile( $fieldName, $fileName, $type, $filePath ) { - $tmpName = tempnam( wfTempDir(), "" ); + $tmpName = $this->getNewTempFile(); if ( !file_exists( $filePath ) ) { throw new Exception( "$filePath doesn't exist!" ); } @@ -132,7 +125,7 @@ abstract class ApiTestCaseUpload extends ApiTestCase { } function fakeUploadChunk( $fieldName, $fileName, $type, & $chunkData ) { - $tmpName = tempnam( wfTempDir(), "" ); + $tmpName = $this->getNewTempFile(); // copy the chunk data to temp location: if ( !file_put_contents( $tmpName, $chunkData ) ) { throw new Exception( "couldn't copy chunk data to $tmpName" ); @@ -153,15 +146,6 @@ abstract class ApiTestCaseUpload extends ApiTestCase { ); } - function clearTempUpload() { - if ( isset( $_FILES['file']['tmp_name'] ) ) { - $tmp = $_FILES['file']['tmp_name']; - if ( file_exists( $tmp ) ) { - unlink( $tmp ); - } - } - } - /** * Remove traces of previous fake uploads */ diff --git a/tests/phpunit/includes/api/ApiUploadTest.php b/tests/phpunit/includes/api/ApiUploadTest.php index 8ea761f8..f74fc354 100644 --- a/tests/phpunit/includes/api/ApiUploadTest.php +++ b/tests/phpunit/includes/api/ApiUploadTest.php @@ -1,31 +1,24 @@ <?php /** - * @group API - * @group Database - * @group medium - */ - -/** * n.b. Ensure that you can write to the images/ directory as the * user that will run tests. - */ - -// Note for reviewers: this intentionally duplicates functionality already in -// "ApiSetup" and so on. This framework works better IMO and has less -// strangeness (such as test cases inheriting from "ApiSetup"...) (and in the -// case of the other Upload tests, this flat out just actually works... ) - -// @todo Port the other Upload tests, and other API tests to this framework - -require_once 'ApiTestCaseUpload.php'; - -/** - * @group Database - * @group Broken - * Broken test, reports false errors from time to time. + * + * Note for reviewers: this intentionally duplicates functionality already in + * "ApiSetup" and so on. This framework works better IMO and has less + * strangeness (such as test cases inheriting from "ApiSetup"...) (and in the + * case of the other Upload tests, this flat out just actually works... ) + * + * @todo Port the other Upload tests, and other API tests to this framework + * + * @todo Broken test, reports false errors from time to time. * See https://bugzilla.wikimedia.org/26169 * - * This is pretty sucky... needs to be prettified. + * @todo This is pretty sucky... needs to be prettified. + * + * @group API + * @group Database + * @group medium + * @group Broken */ class ApiUploadTest extends ApiTestCaseUpload { /** @@ -105,7 +98,7 @@ class ApiUploadTest extends ApiTestCaseUpload { try { $randomImageGenerator = new RandomImageGenerator(); - $filePaths = $randomImageGenerator->writeImages( 1, $extension, wfTempDir() ); + $filePaths = $randomImageGenerator->writeImages( 1, $extension, $this->getNewTempDirectory() ); } catch ( Exception $e ) { $this->markTestIncomplete( $e->getMessage() ); } @@ -145,7 +138,6 @@ class ApiUploadTest extends ApiTestCaseUpload { // clean up $this->deleteFileByFilename( $fileName ); - unlink( $filePath ); } /** @@ -154,7 +146,7 @@ class ApiUploadTest extends ApiTestCaseUpload { public function testUploadZeroLength( $session ) { $mimeType = 'image/png'; - $filePath = tempnam( wfTempDir(), "" ); + $filePath = $this->getNewTempFile(); $fileName = "apiTestUploadZeroLength.png"; $this->deleteFileByFileName( $fileName ); @@ -182,7 +174,6 @@ class ApiUploadTest extends ApiTestCaseUpload { // clean up $this->deleteFileByFilename( $fileName ); - unlink( $filePath ); } /** @@ -194,7 +185,7 @@ class ApiUploadTest extends ApiTestCaseUpload { try { $randomImageGenerator = new RandomImageGenerator(); - $filePaths = $randomImageGenerator->writeImages( 2, $extension, wfTempDir() ); + $filePaths = $randomImageGenerator->writeImages( 2, $extension, $this->getNewTempDirectory() ); } catch ( Exception $e ) { $this->markTestIncomplete( $e->getMessage() ); } @@ -253,8 +244,6 @@ class ApiUploadTest extends ApiTestCaseUpload { // clean up $this->deleteFileByFilename( $fileName ); - unlink( $filePaths[0] ); - unlink( $filePaths[1] ); } /** @@ -266,7 +255,7 @@ class ApiUploadTest extends ApiTestCaseUpload { try { $randomImageGenerator = new RandomImageGenerator(); - $filePaths = $randomImageGenerator->writeImages( 1, $extension, wfTempDir() ); + $filePaths = $randomImageGenerator->writeImages( 1, $extension, $this->getNewTempDirectory() ); } catch ( Exception $e ) { $this->markTestIncomplete( $e->getMessage() ); } @@ -335,7 +324,6 @@ class ApiUploadTest extends ApiTestCaseUpload { // clean up $this->deleteFileByFilename( $fileNames[0] ); $this->deleteFileByFilename( $fileNames[1] ); - unlink( $filePaths[0] ); } /** @@ -351,7 +339,7 @@ class ApiUploadTest extends ApiTestCaseUpload { try { $randomImageGenerator = new RandomImageGenerator(); - $filePaths = $randomImageGenerator->writeImages( 1, $extension, wfTempDir() ); + $filePaths = $randomImageGenerator->writeImages( 1, $extension, $this->getNewTempDirectory() ); } catch ( Exception $e ) { $this->markTestIncomplete( $e->getMessage() ); } @@ -419,7 +407,6 @@ class ApiUploadTest extends ApiTestCaseUpload { // clean up $this->deleteFileByFilename( $fileName ); - unlink( $filePath ); } /** @@ -433,16 +420,14 @@ class ApiUploadTest extends ApiTestCaseUpload { $chunkSize = 1048576; // Download a large image file - // ( using RandomImageGenerator for large files is not stable ) + // (using RandomImageGenerator for large files is not stable) + // @todo Don't download files from wikimedia.org $mimeType = 'image/jpeg'; $url = 'http://upload.wikimedia.org/wikipedia/commons/' . 'e/ed/Oberaargletscher_from_Oberaar%2C_2010_07.JPG'; - $filePath = wfTempDir() . '/Oberaargletscher_from_Oberaar.jpg'; + $filePath = $this->getNewTempDirectory() . '/Oberaargletscher_from_Oberaar.jpg'; try { - // Only download if the file is not avaliable in the temp location: - if ( !is_file( $filePath ) ) { - copy( $url, $filePath ); - } + copy( $url, $filePath ); } catch ( Exception $e ) { $this->markTestIncomplete( $e->getMessage() ); } @@ -566,7 +551,5 @@ class ApiUploadTest extends ApiTestCaseUpload { // clean up $this->deleteFileByFilename( $fileName ); - // don't remove downloaded temporary file for fast subquent tests. - //unlink( $filePath ); } } diff --git a/tests/phpunit/includes/api/MockApi.php b/tests/phpunit/includes/api/MockApi.php index d94aa2cd..516da0c8 100644 --- a/tests/phpunit/includes/api/MockApi.php +++ b/tests/phpunit/includes/api/MockApi.php @@ -4,9 +4,6 @@ class MockApi extends ApiBase { public function execute() { } - public function getVersion() { - } - public function __construct() { } diff --git a/tests/phpunit/includes/api/MockApiQueryBase.php b/tests/phpunit/includes/api/MockApiQueryBase.php index 4bede519..f5b50e5a 100644 --- a/tests/phpunit/includes/api/MockApiQueryBase.php +++ b/tests/phpunit/includes/api/MockApiQueryBase.php @@ -1,11 +1,15 @@ <?php class MockApiQueryBase extends ApiQueryBase { + private $name; + public function execute() { } - public function getVersion() { + public function __construct( $name = 'mock' ) { + $this->name = $name; } - public function __construct() { + public function getModuleName() { + return $this->name; } } diff --git a/tests/phpunit/includes/api/PrefixUniquenessTest.php b/tests/phpunit/includes/api/PrefixUniquenessTest.php index 13da33c7..d04766be 100644 --- a/tests/phpunit/includes/api/PrefixUniquenessTest.php +++ b/tests/phpunit/includes/api/PrefixUniquenessTest.php @@ -20,7 +20,7 @@ class PrefixUniquenessTest extends MediaWikiTestCase { $class = get_class( $module ); $prefix = $module->getModulePrefix(); - if ( isset( $prefixes[$prefix] ) ) { + if ( $prefix !== '' && isset( $prefixes[$prefix] ) ) { $this->fail( "Module prefix '{$prefix}' is shared between {$class} and {$prefixes[$prefix]}" ); } $prefixes[$module->getModulePrefix()] = $class; diff --git a/tests/phpunit/includes/api/format/ApiFormatDbgTest.php b/tests/phpunit/includes/api/format/ApiFormatDbgTest.php new file mode 100644 index 00000000..3fcfc73f --- /dev/null +++ b/tests/phpunit/includes/api/format/ApiFormatDbgTest.php @@ -0,0 +1,55 @@ +<?php + +/** + * @group API + * @covers ApiFormatDbg + */ +class ApiFormatDbgTest extends ApiFormatTestBase { + + protected $printerName = 'dbg'; + + public static function provideGeneralEncoding() { + $warning = "\n 'warnings' => \n array (\n 'dbg' => \n array (\n" . + " '*' => 'format=dbg has been deprecated. Please use format=json instead.',\n" . + " ),\n ),"; + + return array( + // Basic types + array( array( null ), "array ({$warning}\n 0 => NULL,\n)" ), + array( array( true ), "array ({$warning}\n 0 => '',\n)" ), + array( array( false ), "array ({$warning}\n)" ), + array( array( true, ApiResult::META_BC_BOOLS => array( 0 ) ), + "array ({$warning}\n 0 => true,\n)" ), + array( array( false, ApiResult::META_BC_BOOLS => array( 0 ) ), + "array ({$warning}\n 0 => false,\n)" ), + array( array( 42 ), "array ({$warning}\n 0 => 42,\n)" ), + array( array( 42.5 ), "array ({$warning}\n 0 => 42.5,\n)" ), + array( array( 1e42 ), "array ({$warning}\n 0 => 1.0E+42,\n)" ), + array( array( 'foo' ), "array ({$warning}\n 0 => 'foo',\n)" ), + array( array( 'fóo' ), "array ({$warning}\n 0 => 'fóo',\n)" ), + + // Arrays and objects + array( array( array() ), "array ({$warning}\n 0 => \n array (\n ),\n)" ), + array( array( array( 1 ) ), "array ({$warning}\n 0 => \n array (\n 0 => 1,\n ),\n)" ), + array( array( array( 'x' => 1 ) ), "array ({$warning}\n 0 => \n array (\n 'x' => 1,\n ),\n)" ), + array( array( array( 2 => 1 ) ), "array ({$warning}\n 0 => \n array (\n 2 => 1,\n ),\n)" ), + array( array( (object)array() ), "array ({$warning}\n 0 => \n array (\n ),\n)" ), + array( array( array( 1, ApiResult::META_TYPE => 'assoc' ) ), "array ({$warning}\n 0 => \n array (\n 0 => 1,\n ),\n)" ), + array( array( array( 'x' => 1, ApiResult::META_TYPE => 'array' ) ), "array ({$warning}\n 0 => \n array (\n 0 => 1,\n ),\n)" ), + array( array( array( 'x' => 1, ApiResult::META_TYPE => 'kvp' ) ), "array ({$warning}\n 0 => \n array (\n 'x' => 1,\n ),\n)" ), + array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCkvp', ApiResult::META_KVP_KEY_NAME => 'key' ) ), + "array ({$warning}\n 0 => \n array (\n 0 => \n array (\n 'key' => 'x',\n '*' => 1,\n ),\n ),\n)" ), + array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCarray' ) ), "array ({$warning}\n 0 => \n array (\n 'x' => 1,\n ),\n)" ), + array( array( array( 'a', 'b', ApiResult::META_TYPE => 'BCassoc' ) ), "array ({$warning}\n 0 => \n array (\n 0 => 'a',\n 1 => 'b',\n ),\n)" ), + + // Content + array( array( 'content' => 'foo', ApiResult::META_CONTENT => 'content' ), + "array ({$warning}\n '*' => 'foo',\n)" ), + + // BC Subelements + array( array( 'foo' => 'foo', ApiResult::META_BC_SUBELEMENTS => array( 'foo' ) ), + "array ({$warning}\n 'foo' => \n array (\n '*' => 'foo',\n ),\n)" ), + ); + } + +} diff --git a/tests/phpunit/includes/api/format/ApiFormatDumpTest.php b/tests/phpunit/includes/api/format/ApiFormatDumpTest.php new file mode 100644 index 00000000..c0f67f8d --- /dev/null +++ b/tests/phpunit/includes/api/format/ApiFormatDumpTest.php @@ -0,0 +1,63 @@ +<?php + +/** + * @group API + * @covers ApiFormatDump + */ +class ApiFormatDumpTest extends ApiFormatTestBase { + + protected $printerName = 'dump'; + + public static function provideGeneralEncoding() { + // Sigh. Docs claim it's a boolean, but can have values 0, 1, or 2. + // Fortunately wfIniGetBool does the right thing. + if ( wfIniGetBool( 'xdebug.overload_var_dump' ) ) { + return array( + array( array(), 'Cannot test ApiFormatDump when xDebug overloads var_dump', array( 'SKIP' => true ) ), + ); + } + + $warning = "\n [\"warnings\"]=>\n array(1) {\n [\"dump\"]=>\n array(1) {\n [\"*\"]=>\n" . + " string(64) \"format=dump has been deprecated. Please use format=json instead.\"\n" . + " }\n }"; + + return array( + // Basic types + array( array( null ), "array(2) {{$warning}\n [0]=>\n NULL\n}\n" ), + array( array( true ), "array(2) {{$warning}\n [0]=>\n string(0) \"\"\n}\n" ), + array( array( false ), "array(1) {{$warning}\n}\n" ), + array( array( true, ApiResult::META_BC_BOOLS => array( 0 ) ), + "array(2) {{$warning}\n [0]=>\n bool(true)\n}\n" ), + array( array( false, ApiResult::META_BC_BOOLS => array( 0 ) ), + "array(2) {{$warning}\n [0]=>\n bool(false)\n}\n" ), + array( array( 42 ), "array(2) {{$warning}\n [0]=>\n int(42)\n}\n" ), + array( array( 42.5 ), "array(2) {{$warning}\n [0]=>\n float(42.5)\n}\n" ), + array( array( 1e42 ), "array(2) {{$warning}\n [0]=>\n float(1.0E+42)\n}\n" ), + array( array( 'foo' ), "array(2) {{$warning}\n [0]=>\n string(3) \"foo\"\n}\n" ), + array( array( 'fóo' ), "array(2) {{$warning}\n [0]=>\n string(4) \"fóo\"\n}\n" ), + + // Arrays + array( array( array() ), "array(2) {{$warning}\n [0]=>\n array(0) {\n }\n}\n" ), + array( array( array( 1 ) ), "array(2) {{$warning}\n [0]=>\n array(1) {\n [0]=>\n int(1)\n }\n}\n" ), + array( array( array( 'x' => 1 ) ), "array(2) {{$warning}\n [0]=>\n array(1) {\n [\"x\"]=>\n int(1)\n }\n}\n" ), + array( array( array( 2 => 1 ) ), "array(2) {{$warning}\n [0]=>\n array(1) {\n [2]=>\n int(1)\n }\n}\n" ), + array( array( (object)array() ), "array(2) {{$warning}\n [0]=>\n array(0) {\n }\n}\n" ), + array( array( array( 1, ApiResult::META_TYPE => 'assoc' ) ), "array(2) {{$warning}\n [0]=>\n array(1) {\n [0]=>\n int(1)\n }\n}\n" ), + array( array( array( 'x' => 1, ApiResult::META_TYPE => 'array' ) ), "array(2) {{$warning}\n [0]=>\n array(1) {\n [0]=>\n int(1)\n }\n}\n" ), + array( array( array( 'x' => 1, ApiResult::META_TYPE => 'kvp' ) ), "array(2) {{$warning}\n [0]=>\n array(1) {\n [\"x\"]=>\n int(1)\n }\n}\n" ), + array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCkvp', ApiResult::META_KVP_KEY_NAME => 'key' ) ), + "array(2) {{$warning}\n [0]=>\n array(1) {\n [0]=>\n array(2) {\n [\"key\"]=>\n string(1) \"x\"\n [\"*\"]=>\n int(1)\n }\n }\n}\n" ), + array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCarray' ) ), "array(2) {{$warning}\n [0]=>\n array(1) {\n [\"x\"]=>\n int(1)\n }\n}\n" ), + array( array( array( 'a', 'b', ApiResult::META_TYPE => 'BCassoc' ) ), "array(2) {{$warning}\n [0]=>\n array(2) {\n [0]=>\n string(1) \"a\"\n [1]=>\n string(1) \"b\"\n }\n}\n" ), + + // Content + array( array( 'content' => 'foo', ApiResult::META_CONTENT => 'content' ), + "array(2) {{$warning}\n [\"*\"]=>\n string(3) \"foo\"\n}\n" ), + + // BC Subelements + array( array( 'foo' => 'foo', ApiResult::META_BC_SUBELEMENTS => array( 'foo' ) ), + "array(2) {{$warning}\n [\"foo\"]=>\n array(1) {\n [\"*\"]=>\n string(3) \"foo\"\n }\n}\n" ), + ); + } + +} diff --git a/tests/phpunit/includes/api/format/ApiFormatJsonTest.php b/tests/phpunit/includes/api/format/ApiFormatJsonTest.php index fc1f9021..3dfcaf0f 100644 --- a/tests/phpunit/includes/api/format/ApiFormatJsonTest.php +++ b/tests/phpunit/includes/api/format/ApiFormatJsonTest.php @@ -2,21 +2,109 @@ /** * @group API - * @group Database - * @group medium * @covers ApiFormatJson */ class ApiFormatJsonTest extends ApiFormatTestBase { - public function testValidSyntax( ) { - $data = $this->apiRequest( 'json', array( 'action' => 'query', 'meta' => 'siteinfo' ) ); + protected $printerName = 'json'; - $this->assertInternalType( 'array', json_decode( $data, true ) ); - $this->assertGreaterThan( 0, count( (array)$data ) ); + private static function addFormatVersion( $format, $arr ) { + foreach ( $arr as &$p ) { + if ( !isset( $p[2] ) ) { + $p[2] = array( 'formatversion' => $format ); + } else { + $p[2]['formatversion'] = $format; + } + } + return $arr; } - public function testJsonpInjection( ) { - $data = $this->apiRequest( 'json', array( 'action' => 'query', 'meta' => 'siteinfo', 'callback' => 'myCallback' ) ); - $this->assertEquals( '/**/myCallback(', substr( $data, 0, 15 ) ); + public static function provideGeneralEncoding() { + return array_merge( + self::addFormatVersion( 1, array( + // Basic types + array( array( null ), '[null]' ), + array( array( true ), '[""]' ), + array( array( false ), '[]' ), + array( array( true, ApiResult::META_BC_BOOLS => array( 0 ) ), '[true]' ), + array( array( false, ApiResult::META_BC_BOOLS => array( 0 ) ), '[false]' ), + array( array( 42 ), '[42]' ), + array( array( 42.5 ), '[42.5]' ), + array( array( 1e42 ), '[1.0e+42]' ), + array( array( 'foo' ), '["foo"]' ), + array( array( 'fóo' ), '["f\u00f3o"]' ), + array( array( 'fóo' ), '["fóo"]', array( 'utf8' => 1 ) ), + + // Arrays and objects + array( array( array() ), '[[]]' ), + array( array( array( 1 ) ), '[[1]]' ), + array( array( array( 'x' => 1 ) ), '[{"x":1}]' ), + array( array( array( 2 => 1 ) ), '[{"2":1}]' ), + array( array( (object)array() ), '[{}]' ), + array( array( array( 1, ApiResult::META_TYPE => 'assoc' ) ), '[{"0":1}]' ), + array( array( array( 'x' => 1, ApiResult::META_TYPE => 'array' ) ), '[[1]]' ), + array( array( array( 'x' => 1, ApiResult::META_TYPE => 'kvp' ) ), '[{"x":1}]' ), + array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCkvp', ApiResult::META_KVP_KEY_NAME => 'key' ) ), + '[[{"key":"x","*":1}]]' ), + array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCarray' ) ), '[{"x":1}]' ), + array( array( array( 'a', 'b', ApiResult::META_TYPE => 'BCassoc' ) ), '[["a","b"]]' ), + + // Content + array( array( 'content' => 'foo', ApiResult::META_CONTENT => 'content' ), + '{"*":"foo"}' ), + + // BC Subelements + array( array( 'foo' => 'foo', ApiResult::META_BC_SUBELEMENTS => array( 'foo' ) ), + '{"foo":{"*":"foo"}}' ), + + // Callbacks + array( array( 1 ), '/**/myCallback([1])', array( 'callback' => 'myCallback' ) ), + + // Cross-domain mangling + array( array( '< Cross-Domain-Policy >' ), '["\u003C Cross-Domain-Policy \u003E"]' ), + ) ), + self::addFormatVersion( 2, array( + // Basic types + array( array( null ), '[null]' ), + array( array( true ), '[true]' ), + array( array( false ), '[false]' ), + array( array( true, ApiResult::META_BC_BOOLS => array( 0 ) ), '[true]' ), + array( array( false, ApiResult::META_BC_BOOLS => array( 0 ) ), '[false]' ), + array( array( 42 ), '[42]' ), + array( array( 42.5 ), '[42.5]' ), + array( array( 1e42 ), '[1.0e+42]' ), + array( array( 'foo' ), '["foo"]' ), + array( array( 'fóo' ), '["fóo"]' ), + array( array( 'fóo' ), '["f\u00f3o"]', array( 'ascii' => 1 ) ), + + // Arrays and objects + array( array( array() ), '[[]]' ), + array( array( array( 'x' => 1 ) ), '[{"x":1}]' ), + array( array( array( 2 => 1 ) ), '[{"2":1}]' ), + array( array( (object)array() ), '[{}]' ), + array( array( array( 1, ApiResult::META_TYPE => 'assoc' ) ), '[{"0":1}]' ), + array( array( array( 'x' => 1, ApiResult::META_TYPE => 'array' ) ), '[[1]]' ), + array( array( array( 'x' => 1, ApiResult::META_TYPE => 'kvp' ) ), '[{"x":1}]' ), + array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCkvp', ApiResult::META_KVP_KEY_NAME => 'key' ) ), + '[{"x":1}]' ), + array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCarray' ) ), '[[1]]' ), + array( array( array( 'a', 'b', ApiResult::META_TYPE => 'BCassoc' ) ), '[{"0":"a","1":"b"}]' ), + + // Content + array( array( 'content' => 'foo', ApiResult::META_CONTENT => 'content' ), + '{"content":"foo"}' ), + + // BC Subelements + array( array( 'foo' => 'foo', ApiResult::META_BC_SUBELEMENTS => array( 'foo' ) ), + '{"foo":"foo"}' ), + + // Callbacks + array( array( 1 ), '/**/myCallback([1])', array( 'callback' => 'myCallback' ) ), + + // Cross-domain mangling + array( array( '< Cross-Domain-Policy >' ), '["\u003C Cross-Domain-Policy \u003E"]' ), + ) ) + ); } + } diff --git a/tests/phpunit/includes/api/format/ApiFormatNoneTest.php b/tests/phpunit/includes/api/format/ApiFormatNoneTest.php index cabd750b..8f81a411 100644 --- a/tests/phpunit/includes/api/format/ApiFormatNoneTest.php +++ b/tests/phpunit/includes/api/format/ApiFormatNoneTest.php @@ -2,15 +2,43 @@ /** * @group API - * @group Database - * @group medium * @covers ApiFormatNone */ class ApiFormatNoneTest extends ApiFormatTestBase { - public function testValidSyntax( ) { - $data = $this->apiRequest( 'none', array( 'action' => 'query', 'meta' => 'siteinfo' ) ); + protected $printerName = 'none'; - $this->assertEquals( '', $data ); // No output! + public static function provideGeneralEncoding() { + return array( + // Basic types + array( array( null ), '' ), + array( array( true ), '' ), + array( array( false ), '' ), + array( array( 42 ), '' ), + array( array( 42.5 ), '' ), + array( array( 1e42 ), '' ), + array( array( 'foo' ), '' ), + array( array( 'fóo' ), '' ), + + // Arrays and objects + array( array( array() ), '' ), + array( array( array( 1 ) ), '' ), + array( array( array( 'x' => 1 ) ), '' ), + array( array( array( 2 => 1 ) ), '' ), + array( array( (object)array() ), '' ), + array( array( array( 1, ApiResult::META_TYPE => 'assoc' ) ), '' ), + array( array( array( 'x' => 1, ApiResult::META_TYPE => 'array' ) ), '' ), + array( array( array( 'x' => 1, ApiResult::META_TYPE => 'kvp' ) ), '' ), + array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCkvp', ApiResult::META_KVP_KEY_NAME => 'key' ) ), '' ), + array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCarray' ) ), '' ), + array( array( array( 'a', 'b', ApiResult::META_TYPE => 'BCassoc' ) ), '' ), + + // Content + array( array( '*' => 'foo' ), '' ), + + // BC Subelements + array( array( 'foo' => 'foo', ApiResult::META_BC_SUBELEMENTS => array( 'foo' ) ), '' ), + ); } + } diff --git a/tests/phpunit/includes/api/format/ApiFormatPhpTest.php b/tests/phpunit/includes/api/format/ApiFormatPhpTest.php index 54f447a9..0cb44e92 100644 --- a/tests/phpunit/includes/api/format/ApiFormatPhpTest.php +++ b/tests/phpunit/includes/api/format/ApiFormatPhpTest.php @@ -2,16 +2,143 @@ /** * @group API - * @group Database - * @group medium * @covers ApiFormatPhp */ class ApiFormatPhpTest extends ApiFormatTestBase { - public function testValidSyntax( ) { - $data = $this->apiRequest( 'php', array( 'action' => 'query', 'meta' => 'siteinfo' ) ); + protected $printerName = 'php'; - $this->assertInternalType( 'array', unserialize( $data ) ); - $this->assertGreaterThan( 0, count( (array)$data ) ); + private static function addFormatVersion( $format, $arr ) { + foreach ( $arr as &$p ) { + if ( !isset( $p[2] ) ) { + $p[2] = array( 'formatversion' => $format ); + } else { + $p[2]['formatversion'] = $format; + } + } + return $arr; } + + public static function provideGeneralEncoding() { + return array_merge( + self::addFormatVersion( 1, array( + // Basic types + array( array( null ), 'a:1:{i:0;N;}' ), + array( array( true ), 'a:1:{i:0;s:0:"";}' ), + array( array( false ), 'a:0:{}' ), + array( array( true, ApiResult::META_BC_BOOLS => array( 0 ) ), + 'a:1:{i:0;b:1;}' ), + array( array( false, ApiResult::META_BC_BOOLS => array( 0 ) ), + 'a:1:{i:0;b:0;}' ), + array( array( 42 ), 'a:1:{i:0;i:42;}' ), + array( array( 42.5 ), 'a:1:{i:0;d:42.5;}' ), + array( array( 1e42 ), 'a:1:{i:0;d:1.0E+42;}' ), + array( array( 'foo' ), 'a:1:{i:0;s:3:"foo";}' ), + array( array( 'fóo' ), 'a:1:{i:0;s:4:"fóo";}' ), + + // Arrays and objects + array( array( array() ), 'a:1:{i:0;a:0:{}}' ), + array( array( array( 1 ) ), 'a:1:{i:0;a:1:{i:0;i:1;}}' ), + array( array( array( 'x' => 1 ) ), 'a:1:{i:0;a:1:{s:1:"x";i:1;}}' ), + array( array( array( 2 => 1 ) ), 'a:1:{i:0;a:1:{i:2;i:1;}}' ), + array( array( (object)array() ), 'a:1:{i:0;a:0:{}}' ), + array( array( array( 1, ApiResult::META_TYPE => 'assoc' ) ), 'a:1:{i:0;a:1:{i:0;i:1;}}' ), + array( array( array( 'x' => 1, ApiResult::META_TYPE => 'array' ) ), 'a:1:{i:0;a:1:{i:0;i:1;}}' ), + array( array( array( 'x' => 1, ApiResult::META_TYPE => 'kvp' ) ), 'a:1:{i:0;a:1:{s:1:"x";i:1;}}' ), + array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCkvp', ApiResult::META_KVP_KEY_NAME => 'key' ) ), + 'a:1:{i:0;a:1:{i:0;a:2:{s:3:"key";s:1:"x";s:1:"*";i:1;}}}' ), + array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCarray' ) ), 'a:1:{i:0;a:1:{s:1:"x";i:1;}}' ), + array( array( array( 'a', 'b', ApiResult::META_TYPE => 'BCassoc' ) ), 'a:1:{i:0;a:2:{i:0;s:1:"a";i:1;s:1:"b";}}' ), + + // Content + array( array( 'content' => 'foo', ApiResult::META_CONTENT => 'content' ), + 'a:1:{s:1:"*";s:3:"foo";}' ), + + // BC Subelements + array( array( 'foo' => 'foo', ApiResult::META_BC_SUBELEMENTS => array( 'foo' ) ), + 'a:1:{s:3:"foo";a:1:{s:1:"*";s:3:"foo";}}' ), + ) ), + self::addFormatVersion( 2, array( + // Basic types + array( array( null ), 'a:1:{i:0;N;}' ), + array( array( true ), 'a:1:{i:0;b:1;}' ), + array( array( false ), 'a:1:{i:0;b:0;}' ), + array( array( true, ApiResult::META_BC_BOOLS => array( 0 ) ), + 'a:1:{i:0;b:1;}' ), + array( array( false, ApiResult::META_BC_BOOLS => array( 0 ) ), + 'a:1:{i:0;b:0;}' ), + array( array( 42 ), 'a:1:{i:0;i:42;}' ), + array( array( 42.5 ), 'a:1:{i:0;d:42.5;}' ), + array( array( 1e42 ), 'a:1:{i:0;d:1.0E+42;}' ), + array( array( 'foo' ), 'a:1:{i:0;s:3:"foo";}' ), + array( array( 'fóo' ), 'a:1:{i:0;s:4:"fóo";}' ), + + // Arrays and objects + array( array( array() ), 'a:1:{i:0;a:0:{}}' ), + array( array( array( 1 ) ), 'a:1:{i:0;a:1:{i:0;i:1;}}' ), + array( array( array( 'x' => 1 ) ), 'a:1:{i:0;a:1:{s:1:"x";i:1;}}' ), + array( array( array( 2 => 1 ) ), 'a:1:{i:0;a:1:{i:2;i:1;}}' ), + array( array( (object)array() ), 'a:1:{i:0;a:0:{}}' ), + array( array( array( 1, ApiResult::META_TYPE => 'assoc' ) ), 'a:1:{i:0;a:1:{i:0;i:1;}}' ), + array( array( array( 'x' => 1, ApiResult::META_TYPE => 'array' ) ), 'a:1:{i:0;a:1:{i:0;i:1;}}' ), + array( array( array( 'x' => 1, ApiResult::META_TYPE => 'kvp' ) ), 'a:1:{i:0;a:1:{s:1:"x";i:1;}}' ), + array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCkvp', ApiResult::META_KVP_KEY_NAME => 'key' ) ), + 'a:1:{i:0;a:1:{s:1:"x";i:1;}}' ), + array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCarray' ) ), 'a:1:{i:0;a:1:{i:0;i:1;}}' ), + array( array( array( 'a', 'b', ApiResult::META_TYPE => 'BCassoc' ) ), 'a:1:{i:0;a:2:{i:0;s:1:"a";i:1;s:1:"b";}}' ), + + // Content + array( array( 'content' => 'foo', ApiResult::META_CONTENT => 'content' ), + 'a:1:{s:7:"content";s:3:"foo";}' ), + + // BC Subelements + array( array( 'foo' => 'foo', ApiResult::META_BC_SUBELEMENTS => array( 'foo' ) ), + 'a:1:{s:3:"foo";s:3:"foo";}' ), + ) ) + ); + } + + public function testCrossDomainMangling() { + $config = new HashConfig( array( 'MangleFlashPolicy' => false ) ); + $context = new RequestContext; + $context->setConfig( new MultiConfig( array( + $config, + $context->getConfig(), + ) ) ); + $main = new ApiMain( $context ); + $main->getResult()->addValue( null, null, '< Cross-Domain-Policy >' ); + + if ( !function_exists( 'wfOutputHandler' ) ) { + function wfOutputHandler( $s ) { + return $s; + } + } + + $printer = $main->createPrinterByName( 'php' ); + ob_start( 'wfOutputHandler' ); + $printer->initPrinter(); + $printer->execute(); + $printer->closePrinter(); + $ret = ob_get_clean(); + $this->assertSame( 'a:1:{i:0;s:23:"< Cross-Domain-Policy >";}', $ret ); + + $config->set( 'MangleFlashPolicy', true ); + $printer = $main->createPrinterByName( 'php' ); + ob_start( 'wfOutputHandler' ); + try { + $printer->initPrinter(); + $printer->execute(); + $printer->closePrinter(); + ob_end_clean(); + $this->fail( 'Expected exception not thrown' ); + } catch ( UsageException $ex ) { + ob_end_clean(); + $this->assertSame( + 'This response cannot be represented using format=php. See https://bugzilla.wikimedia.org/show_bug.cgi?id=66776', + $ex->getMessage(), + 'Expected exception' + ); + } + } + } diff --git a/tests/phpunit/includes/api/format/ApiFormatTestBase.php b/tests/phpunit/includes/api/format/ApiFormatTestBase.php index 5f6d53ce..cabf62b1 100644 --- a/tests/phpunit/includes/api/format/ApiFormatTestBase.php +++ b/tests/phpunit/includes/api/format/ApiFormatTestBase.php @@ -1,32 +1,64 @@ <?php -abstract class ApiFormatTestBase extends ApiTestCase { +abstract class ApiFormatTestBase extends MediaWikiTestCase { /** - * @param string $format - * @param array $params - * @param array $data - * - * @return string + * Name of the formatter being tested + * @var string */ - protected function apiRequest( $format, $params, $data = null ) { - $data = parent::doApiRequest( $params, $data, true ); - - /** @var ApiMain $module */ - $module = $data[3]; + protected $printerName; - $printer = $module->createPrinterByName( $format ); - $printer->setUnescapeAmps( false ); + /** + * Return general data to be encoded for testing + * @return array See self::testGeneralEncoding + * @throws Exception + */ + public static function provideGeneralEncoding() { + throw new Exception( 'Subclass must implement ' . __METHOD__ ); + } - $printer->initPrinter( false ); + /** + * Get the formatter output for the given input data + * @param array $params Query parameters + * @param array $data Data to encode + * @param string $class Printer class to use instead of the normal one + * @return string + * @throws Exception + */ + protected function encodeData( array $params, array $data, $class = null ) { + $context = new RequestContext; + $context->setRequest( new FauxRequest( $params, true ) ); + $main = new ApiMain( $context ); + if ( $class !== null ) { + $main->getModuleManager()->addModule( $this->printerName, 'format', $class ); + } + $result = $main->getResult(); + $result->addArrayType( null, 'default' ); + foreach ( $data as $k => $v ) { + $result->addValue( null, $k, $v ); + } - ob_start(); + $printer = $main->createPrinterByName( $this->printerName ); + $printer->initPrinter(); $printer->execute(); - $out = ob_get_clean(); - - $printer->closePrinter(); + ob_start(); + try { + $printer->closePrinter(); + return ob_get_clean(); + } catch ( Exception $ex ) { + ob_end_clean(); + throw $ex; + } + } - return $out; + /** + * @dataProvider provideGeneralEncoding + */ + public function testGeneralEncoding( array $data, $expect, array $params = array() ) { + if ( isset( $params['SKIP'] ) ) { + $this->markTestSkipped( $expect ); + } + $this->assertSame( $expect, $this->encodeData( $params, $data ) ); } } diff --git a/tests/phpunit/includes/api/format/ApiFormatTxtTest.php b/tests/phpunit/includes/api/format/ApiFormatTxtTest.php new file mode 100644 index 00000000..b0a2a960 --- /dev/null +++ b/tests/phpunit/includes/api/format/ApiFormatTxtTest.php @@ -0,0 +1,55 @@ +<?php + +/** + * @group API + * @covers ApiFormatTxt + */ +class ApiFormatTxtTest extends ApiFormatTestBase { + + protected $printerName = 'txt'; + + public static function provideGeneralEncoding() { + $warning = "\n [warnings] => Array\n (\n [txt] => Array\n (\n" . + " [*] => format=txt has been deprecated. Please use format=json instead.\n" . + " )\n\n )\n"; + + return array( + // Basic types + array( array( null ), "Array\n({$warning}\n [0] => \n)\n" ), + array( array( true ), "Array\n({$warning}\n [0] => \n)\n" ), + array( array( false ), "Array\n({$warning}\n)\n" ), + array( array( true, ApiResult::META_BC_BOOLS => array( 0 ) ), + "Array\n({$warning}\n [0] => 1\n)\n" ), + array( array( false, ApiResult::META_BC_BOOLS => array( 0 ) ), + "Array\n({$warning}\n [0] => \n)\n" ), + array( array( 42 ), "Array\n({$warning}\n [0] => 42\n)\n" ), + array( array( 42.5 ), "Array\n({$warning}\n [0] => 42.5\n)\n" ), + array( array( 1e42 ), "Array\n({$warning}\n [0] => 1.0E+42\n)\n" ), + array( array( 'foo' ), "Array\n({$warning}\n [0] => foo\n)\n" ), + array( array( 'fóo' ), "Array\n({$warning}\n [0] => fóo\n)\n" ), + + // Arrays and objects + array( array( array() ), "Array\n({$warning}\n [0] => Array\n (\n )\n\n)\n" ), + array( array( array( 1 ) ), "Array\n({$warning}\n [0] => Array\n (\n [0] => 1\n )\n\n)\n" ), + array( array( array( 'x' => 1 ) ), "Array\n({$warning}\n [0] => Array\n (\n [x] => 1\n )\n\n)\n" ), + array( array( array( 2 => 1 ) ), "Array\n({$warning}\n [0] => Array\n (\n [2] => 1\n )\n\n)\n" ), + array( array( (object)array() ), "Array\n({$warning}\n [0] => Array\n (\n )\n\n)\n" ), + array( array( array( 1, ApiResult::META_TYPE => 'assoc' ) ), "Array\n({$warning}\n [0] => Array\n (\n [0] => 1\n )\n\n)\n" ), + array( array( array( 'x' => 1, ApiResult::META_TYPE => 'array' ) ), "Array\n({$warning}\n [0] => Array\n (\n [0] => 1\n )\n\n)\n" ), + array( array( array( 'x' => 1, ApiResult::META_TYPE => 'kvp' ) ), "Array\n({$warning}\n [0] => Array\n (\n [x] => 1\n )\n\n)\n" ), + array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCkvp', ApiResult::META_KVP_KEY_NAME => 'key' ) ), + "Array\n({$warning}\n [0] => Array\n (\n [0] => Array\n (\n [key] => x\n [*] => 1\n )\n\n )\n\n)\n" ), + array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCarray' ) ), "Array\n({$warning}\n [0] => Array\n (\n [x] => 1\n )\n\n)\n" ), + array( array( array( 'a', 'b', ApiResult::META_TYPE => 'BCassoc' ) ), "Array\n({$warning}\n [0] => Array\n (\n [0] => a\n [1] => b\n )\n\n)\n" ), + + // Content + array( array( 'content' => 'foo', ApiResult::META_CONTENT => 'content' ), + "Array\n({$warning}\n [*] => foo\n)\n" ), + + // BC Subelements + array( array( 'foo' => 'foo', ApiResult::META_BC_SUBELEMENTS => array( 'foo' ) ), + "Array\n({$warning}\n [foo] => Array\n (\n [*] => foo\n )\n\n)\n" ), + ); + } + +} diff --git a/tests/phpunit/includes/api/format/ApiFormatWddxTest.php b/tests/phpunit/includes/api/format/ApiFormatWddxTest.php index d075f547..07111300 100644 --- a/tests/phpunit/includes/api/format/ApiFormatWddxTest.php +++ b/tests/phpunit/includes/api/format/ApiFormatWddxTest.php @@ -2,19 +2,79 @@ /** * @group API - * @group Database - * @group medium * @covers ApiFormatWddx */ class ApiFormatWddxTest extends ApiFormatTestBase { + protected $printerName = 'wddx'; + + public static function provideGeneralEncoding() { + if ( ApiFormatWddx::useSlowPrinter() ) { + return array( + array( array(), 'Fast Wddx printer is unavailable', array( 'SKIP' => true ) ) + ); + } + return self::provideEncoding(); + } + + public static function provideEncoding() { + $p = '<wddxPacket version=\'1.0\'><header/><data><struct><var name=\'warnings\'><struct><var name=\'wddx\'><struct><var name=\'*\'><string>format=wddx has been deprecated. Please use format=json instead.</string></var></struct></var></struct></var>'; + $s = '</struct></data></wddxPacket>'; + + return array( + // Basic types + array( array( null ), "{$p}<var name='0'><null/></var>{$s}" ), + array( array( true ), "{$p}<var name='0'><string></string></var>{$s}" ), + array( array( false ), "{$p}{$s}" ), + array( array( true, ApiResult::META_BC_BOOLS => array( 0 ) ), + "{$p}<var name='0'><boolean value='true'/></var>{$s}" ), + array( array( false, ApiResult::META_BC_BOOLS => array( 0 ) ), + "{$p}<var name='0'><boolean value='false'/></var>{$s}" ), + array( array( 42 ), "{$p}<var name='0'><number>42</number></var>{$s}" ), + array( array( 42.5 ), "{$p}<var name='0'><number>42.5</number></var>{$s}" ), + array( array( 1e42 ), "{$p}<var name='0'><number>1.0E+42</number></var>{$s}" ), + array( array( 'foo' ), "{$p}<var name='0'><string>foo</string></var>{$s}" ), + array( array( 'fóo' ), "{$p}<var name='0'><string>fóo</string></var>{$s}" ), + + // Arrays and objects + array( array( array() ), "{$p}<var name='0'><array length='0'></array></var>{$s}" ), + array( array( array( 1 ) ), "{$p}<var name='0'><array length='1'><number>1</number></array></var>{$s}" ), + array( array( array( 'x' => 1 ) ), "{$p}<var name='0'><struct><var name='x'><number>1</number></var></struct></var>{$s}" ), + array( array( array( 2 => 1 ) ), "{$p}<var name='0'><struct><var name='2'><number>1</number></var></struct></var>{$s}" ), + array( array( (object)array() ), "{$p}<var name='0'><struct></struct></var>{$s}" ), + array( array( array( 1, ApiResult::META_TYPE => 'assoc' ) ), "{$p}<var name='0'><struct><var name='0'><number>1</number></var></struct></var>{$s}" ), + array( array( array( 'x' => 1, ApiResult::META_TYPE => 'array' ) ), "{$p}<var name='0'><array length='1'><number>1</number></array></var>{$s}" ), + array( array( array( 'x' => 1, ApiResult::META_TYPE => 'kvp' ) ), "{$p}<var name='0'><struct><var name='x'><number>1</number></var></struct></var>{$s}" ), + array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCkvp', ApiResult::META_KVP_KEY_NAME => 'key' ) ), + "{$p}<var name='0'><array length='1'><struct><var name='key'><string>x</string></var><var name='*'><number>1</number></var></struct></array></var>{$s}" ), + array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCarray' ) ), "{$p}<var name='0'><struct><var name='x'><number>1</number></var></struct></var>{$s}" ), + array( array( array( 'a', 'b', ApiResult::META_TYPE => 'BCassoc' ) ), "{$p}<var name='0'><array length='2'><string>a</string><string>b</string></array></var>{$s}" ), + + // Content + array( array( 'content' => 'foo', ApiResult::META_CONTENT => 'content' ), + "{$p}<var name='*'><string>foo</string></var>{$s}" ), + + // BC Subelements + array( array( 'foo' => 'foo', ApiResult::META_BC_SUBELEMENTS => array( 'foo' ) ), + "{$p}<var name='foo'><struct><var name='*'><string>foo</string></var></struct></var>{$s}" ), + ); + } + /** - * @requires function wddx_deserialize + * @dataProvider provideEncoding */ - public function testValidSyntax( ) { - $data = $this->apiRequest( 'wddx', array( 'action' => 'query', 'meta' => 'siteinfo' ) ); + public function testSlowEncoding( array $data, $expect, array $params = array() ) { + // Adjust expectation for differences between fast and slow printers. + $expect = str_replace( '\'', '"', $expect ); + $expect = str_replace( '/>', ' />', $expect ); + $expect = '<?xml version="1.0"?>' . $expect; + + $this->assertSame( $expect, $this->encodeData( $params, $data, 'ApiFormatWddxTest_SlowWddx' ) ); + } +} - $this->assertInternalType( 'array', wddx_deserialize( $data ) ); - $this->assertGreaterThan( 0, count( (array)$data ) ); +class ApiFormatWddxTest_SlowWddx extends ApiFormatWddx { + public static function useSlowPrinter() { + return true; } } diff --git a/tests/phpunit/includes/api/format/ApiFormatXmlTest.php b/tests/phpunit/includes/api/format/ApiFormatXmlTest.php new file mode 100644 index 00000000..7babaedb --- /dev/null +++ b/tests/phpunit/includes/api/format/ApiFormatXmlTest.php @@ -0,0 +1,119 @@ +<?php + +/** + * @group API + * @group Database + * @covers ApiFormatXml + */ +class ApiFormatXmlTest extends ApiFormatTestBase { + + protected $printerName = 'xml'; + + public static function setUpBeforeClass() { + parent::setUpBeforeClass(); + $page = WikiPage::factory( Title::newFromText( 'MediaWiki:ApiFormatXmlTest.xsl' ) ); + $page->doEditContent( new WikitextContent( + '<?xml version="1.0"?><xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" />' + ), 'Summary' ); + $page = WikiPage::factory( Title::newFromText( 'MediaWiki:ApiFormatXmlTest' ) ); + $page->doEditContent( new WikitextContent( 'Bogus' ), 'Summary' ); + $page = WikiPage::factory( Title::newFromText( 'ApiFormatXmlTest' ) ); + $page->doEditContent( new WikitextContent( 'Bogus' ), 'Summary' ); + } + + public static function provideGeneralEncoding() { + return array( + // Basic types + array( array( null, 'a' => null ), '<?xml version="1.0"?><api><_v _idx="0" /></api>' ), + array( array( true, 'a' => true ), '<?xml version="1.0"?><api a=""><_v _idx="0">true</_v></api>' ), + array( array( false, 'a' => false ), '<?xml version="1.0"?><api><_v _idx="0">false</_v></api>' ), + array( array( true, 'a' => true, ApiResult::META_BC_BOOLS => array( 0, 'a' ) ), + '<?xml version="1.0"?><api a=""><_v _idx="0">1</_v></api>' ), + array( array( false, 'a' => false, ApiResult::META_BC_BOOLS => array( 0, 'a' ) ), + '<?xml version="1.0"?><api><_v _idx="0"></_v></api>' ), + array( array( 42, 'a' => 42 ), '<?xml version="1.0"?><api a="42"><_v _idx="0">42</_v></api>' ), + array( array( 42.5, 'a' => 42.5 ), '<?xml version="1.0"?><api a="42.5"><_v _idx="0">42.5</_v></api>' ), + array( array( 1e42, 'a' => 1e42 ), '<?xml version="1.0"?><api a="1.0E+42"><_v _idx="0">1.0E+42</_v></api>' ), + array( array( 'foo', 'a' => 'foo' ), '<?xml version="1.0"?><api a="foo"><_v _idx="0">foo</_v></api>' ), + array( array( 'fóo', 'a' => 'fóo' ), '<?xml version="1.0"?><api a="fóo"><_v _idx="0">fóo</_v></api>' ), + + // Arrays and objects + array( array( array() ), '<?xml version="1.0"?><api><_v /></api>' ), + array( array( array( 'x' => 1 ) ), '<?xml version="1.0"?><api><_v x="1" /></api>' ), + array( array( array( 2 => 1 ) ), '<?xml version="1.0"?><api><_v><_v _idx="2">1</_v></_v></api>' ), + array( array( (object)array() ), '<?xml version="1.0"?><api><_v /></api>' ), + array( array( array( 1, ApiResult::META_TYPE => 'assoc' ) ), '<?xml version="1.0"?><api><_v><_v _idx="0">1</_v></_v></api>' ), + array( array( array( 'x' => 1, ApiResult::META_TYPE => 'array' ) ), '<?xml version="1.0"?><api><_v><_v>1</_v></_v></api>' ), + array( array( array( 'x' => 1, 'y' => array( 'z' => 1 ), ApiResult::META_TYPE => 'kvp' ) ), + '<?xml version="1.0"?><api><_v><_v _name="x" xml:space="preserve">1</_v><_v _name="y"><z xml:space="preserve">1</z></_v></_v></api>' ), + array( array( array( 'x' => 1, ApiResult::META_TYPE => 'kvp', ApiResult::META_INDEXED_TAG_NAME => 'i', ApiResult::META_KVP_KEY_NAME => 'key' ) ), + '<?xml version="1.0"?><api><_v><i key="x" xml:space="preserve">1</i></_v></api>' ), + array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCkvp', ApiResult::META_KVP_KEY_NAME => 'key' ) ), + '<?xml version="1.0"?><api><_v><_v key="x" xml:space="preserve">1</_v></_v></api>' ), + array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCarray' ) ), '<?xml version="1.0"?><api><_v x="1" /></api>' ), + array( array( array( 'a', 'b', ApiResult::META_TYPE => 'BCassoc' ) ), '<?xml version="1.0"?><api><_v><_v _idx="0">a</_v><_v _idx="1">b</_v></_v></api>' ), + + // Content + array( array( 'content' => 'foo', ApiResult::META_CONTENT => 'content' ), + '<?xml version="1.0"?><api xml:space="preserve">foo</api>' ), + + // Specified element name + array( array( 'foo', 'bar', ApiResult::META_INDEXED_TAG_NAME => 'itn' ), + '<?xml version="1.0"?><api><itn>foo</itn><itn>bar</itn></api>' ), + + // Subelements + array( array( 'a' => 1, 's' => 1, '_subelements' => array( 's' ) ), + '<?xml version="1.0"?><api a="1"><s xml:space="preserve">1</s></api>' ), + + // Content and subelement + array( array( 'a' => 1, 'content' => 'foo', ApiResult::META_CONTENT => 'content' ), + '<?xml version="1.0"?><api a="1" xml:space="preserve">foo</api>' ), + array( array( 's' => array(), 'content' => 'foo', ApiResult::META_CONTENT => 'content' ), + '<?xml version="1.0"?><api><s /><content xml:space="preserve">foo</content></api>' ), + array( + array( + 's' => 1, + 'content' => 'foo', + ApiResult::META_CONTENT => 'content', + ApiResult::META_SUBELEMENTS => array( 's' ) + ), + '<?xml version="1.0"?><api><s xml:space="preserve">1</s><content xml:space="preserve">foo</content></api>' + ), + + // BC Subelements + array( array( 'foo' => 'foo', ApiResult::META_BC_SUBELEMENTS => array( 'foo' ) ), + '<?xml version="1.0"?><api><foo xml:space="preserve">foo</foo></api>' ), + + // Name mangling + array( array( 'foo.bar' => 1 ), '<?xml version="1.0"?><api foo.bar="1" />' ), + array( array( '' => 1 ), '<?xml version="1.0"?><api _="1" />' ), + array( array( 'foo bar' => 1 ), '<?xml version="1.0"?><api _foo.20.bar="1" />' ), + array( array( 'foo:bar' => 1 ), '<?xml version="1.0"?><api _foo.3A.bar="1" />' ), + array( array( 'foo%.bar' => 1 ), '<?xml version="1.0"?><api _foo.25..2E.bar="1" />' ), + array( array( '4foo' => 1, 'foo4' => 1 ), '<?xml version="1.0"?><api _4foo="1" foo4="1" />' ), + array( array( "foo\xe3\x80\x80bar" => 1 ), '<?xml version="1.0"?><api _foo.3000.bar="1" />' ), + array( array( 'foo:bar' => 1, ApiResult::META_PRESERVE_KEYS => array( 'foo:bar' ) ), + '<?xml version="1.0"?><api foo:bar="1" />' ), + array( array( 'a', 'b', ApiResult::META_INDEXED_TAG_NAME => 'foo bar' ), + '<?xml version="1.0"?><api><_foo.20.bar>a</_foo.20.bar><_foo.20.bar>b</_foo.20.bar></api>' ), + + // includenamespace param + array( array( 'x' => 'foo' ), '<?xml version="1.0"?><api x="foo" xmlns="http://www.mediawiki.org/xml/api/" />', + array( 'includexmlnamespace' => 1 ) ), + + // xslt param + array( array(), '<?xml version="1.0"?><api><warnings><xml xml:space="preserve">Invalid or non-existent stylesheet specified</xml></warnings></api>', + array( 'xslt' => 'DoesNotExist' ) ), + array( array(), '<?xml version="1.0"?><api><warnings><xml xml:space="preserve">Stylesheet should be in the MediaWiki namespace.</xml></warnings></api>', + array( 'xslt' => 'ApiFormatXmlTest' ) ), + array( array(), '<?xml version="1.0"?><api><warnings><xml xml:space="preserve">Stylesheet should have .xsl extension.</xml></warnings></api>', + array( 'xslt' => 'MediaWiki:ApiFormatXmlTest' ) ), + array( array(), + '<?xml version="1.0"?><?xml-stylesheet href="' . + htmlspecialchars( Title::newFromText( 'MediaWiki:ApiFormatXmlTest.xsl' )->getLocalURL( 'action=raw' ) ) . + '" type="text/xsl" ?><api />', + array( 'xslt' => 'MediaWiki:ApiFormatXmlTest.xsl' ) ), + ); + } + +} diff --git a/tests/phpunit/includes/api/query/ApiQueryBasicTest.php b/tests/phpunit/includes/api/query/ApiQueryBasicTest.php index e486c4f4..fa0e4cb5 100644 --- a/tests/phpunit/includes/api/query/ApiQueryBasicTest.php +++ b/tests/phpunit/includes/api/query/ApiQueryBasicTest.php @@ -23,8 +23,6 @@ * @file */ -require_once 'ApiQueryTestBase.php'; - /** * These tests validate basic functionality of the api query module * diff --git a/tests/phpunit/includes/api/query/ApiQueryContinue2Test.php b/tests/phpunit/includes/api/query/ApiQueryContinue2Test.php index 347cd6f8..cd735223 100644 --- a/tests/phpunit/includes/api/query/ApiQueryContinue2Test.php +++ b/tests/phpunit/includes/api/query/ApiQueryContinue2Test.php @@ -18,8 +18,6 @@ * http://www.gnu.org/copyleft/gpl.html */ -require_once 'ApiQueryContinueTestBase.php'; - /** * @group API * @group Database @@ -62,7 +60,8 @@ class ApiQueryContinue2Test extends ApiQueryContinueTestBase { ); }; // generator + 1 prop + 1 list - $data = $this->query( $mk( 99, 99, true ), 1, 'g1p', false ); + $data = $this->query( $mk( 99, 99, true ), 1, 'g1p', false ) + + array( 'batchcomplete' => true ); $this->checkC( $data, $mk( 1, 1, true ), 6, 'g1p-11t' ); $this->checkC( $data, $mk( 2, 2, true ), 3, 'g1p-22t' ); $this->checkC( $data, $mk( 1, 1, false ), 6, 'g1p-11f' ); diff --git a/tests/phpunit/includes/api/query/ApiQueryContinueTest.php b/tests/phpunit/includes/api/query/ApiQueryContinueTest.php index 03797901..d441f4c4 100644 --- a/tests/phpunit/includes/api/query/ApiQueryContinueTest.php +++ b/tests/phpunit/includes/api/query/ApiQueryContinueTest.php @@ -18,8 +18,6 @@ * http://www.gnu.org/copyleft/gpl.html */ -require_once 'ApiQueryContinueTestBase.php'; - /** * These tests validate the new continue functionality of the api query module by * doing multiple requests with varying parameters, merging the results, and checking @@ -68,7 +66,8 @@ class ApiQueryContinueTest extends ApiQueryContinueTestBase { 'aplimit' => "$l", ); }; - $data = $this->query( $mk( 99 ), 1, '1L', false ); + $data = $this->query( $mk( 99 ), 1, '1L', false ) + + array( 'batchcomplete' => true ); // 1 list $this->checkC( $data, $mk( 1 ), 5, '1L-1' ); @@ -95,7 +94,8 @@ class ApiQueryContinueTest extends ApiQueryContinueTestBase { ); }; // 2 lists - $data = $this->query( $mk( 99, 99 ), 1, '2L', false ); + $data = $this->query( $mk( 99, 99 ), 1, '2L', false ) + + array( 'batchcomplete' => true ); $this->checkC( $data, $mk( 1, 1 ), 5, '2L-11' ); $this->checkC( $data, $mk( 2, 2 ), 3, '2L-22' ); $this->checkC( $data, $mk( 3, 3 ), 2, '2L-33' ); @@ -119,7 +119,8 @@ class ApiQueryContinueTest extends ApiQueryContinueTestBase { ); }; // generator + 1 prop - $data = $this->query( $mk( 99, 99 ), 1, 'G1P', false ); + $data = $this->query( $mk( 99, 99 ), 1, 'G1P', false ) + + array( 'batchcomplete' => true ); $this->checkC( $data, $mk( 1, 1 ), 11, 'G1P-11' ); $this->checkC( $data, $mk( 2, 2 ), 6, 'G1P-22' ); $this->checkC( $data, $mk( 3, 3 ), 4, 'G1P-33' ); @@ -144,7 +145,8 @@ class ApiQueryContinueTest extends ApiQueryContinueTestBase { ); }; // generator + 2 props - $data = $this->query( $mk( 99, 99, 99 ), 1, 'G2P', false ); + $data = $this->query( $mk( 99, 99, 99 ), 1, 'G2P', false ) + + array( 'batchcomplete' => true ); $this->checkC( $data, $mk( 1, 1, 1 ), 16, 'G2P-111' ); $this->checkC( $data, $mk( 2, 2, 2 ), 9, 'G2P-222' ); $this->checkC( $data, $mk( 3, 3, 3 ), 6, 'G2P-333' ); @@ -177,7 +179,8 @@ class ApiQueryContinueTest extends ApiQueryContinueTestBase { ); }; // generator + 1 prop + 1 list - $data = $this->query( $mk( 99, 99, 99 ), 1, 'G1P1L', false ); + $data = $this->query( $mk( 99, 99, 99 ), 1, 'G1P1L', false ) + + array( 'batchcomplete' => true ); $this->checkC( $data, $mk( 1, 1, 1 ), 11, 'G1P1L-111' ); $this->checkC( $data, $mk( 2, 2, 2 ), 6, 'G1P1L-222' ); $this->checkC( $data, $mk( 3, 3, 3 ), 4, 'G1P1L-333' ); @@ -214,7 +217,8 @@ class ApiQueryContinueTest extends ApiQueryContinueTestBase { ); }; // generator + 1 prop + 1 list - $data = $this->query( $mk( 99, 99, 99, 99, 99 ), 1, 'G2P2L1M', false ); + $data = $this->query( $mk( 99, 99, 99, 99, 99 ), 1, 'G2P2L1M', false ) + + array( 'batchcomplete' => true ); $this->checkC( $data, $mk( 1, 1, 1, 1, 1 ), 16, 'G2P2L1M-11111' ); $this->checkC( $data, $mk( 2, 2, 2, 2, 2 ), 9, 'G2P2L1M-22222' ); $this->checkC( $data, $mk( 3, 3, 3, 3, 3 ), 6, 'G2P2L1M-33333' ); @@ -244,7 +248,8 @@ class ApiQueryContinueTest extends ApiQueryContinueTestBase { ); }; // generator + 1 prop - $data = $this->query( $mk( 99, true, 99, true ), 1, 'G=P', false ); + $data = $this->query( $mk( 99, true, 99, true ), 1, 'G=P', false ) + + array( 'batchcomplete' => true ); $this->checkC( $data, $mk( 1, true, 1, true ), 4, 'G=P-1t1t' ); $this->checkC( $data, $mk( 2, true, 2, true ), 2, 'G=P-2t2t' ); @@ -290,7 +295,8 @@ class ApiQueryContinueTest extends ApiQueryContinueTestBase { ); }; // generator + 1 list - $data = $this->query( $mk( 99, true, 99, true ), 1, 'G=L', false ); + $data = $this->query( $mk( 99, true, 99, true ), 1, 'G=L', false ) + + array( 'batchcomplete' => true ); $this->checkC( $data, $mk( 1, true, 1, true ), 5, 'G=L-1t1t' ); $this->checkC( $data, $mk( 2, true, 2, true ), 3, 'G=L-2t2t' ); diff --git a/tests/phpunit/includes/api/query/ApiQueryContinueTestBase.php b/tests/phpunit/includes/api/query/ApiQueryContinueTestBase.php index bce62685..ce2f70de 100644 --- a/tests/phpunit/includes/api/query/ApiQueryContinueTestBase.php +++ b/tests/phpunit/includes/api/query/ApiQueryContinueTestBase.php @@ -21,9 +21,6 @@ * * @file */ - -require_once 'ApiQueryTestBase.php'; - abstract class ApiQueryContinueTestBase extends ApiQueryTestBase { /** @@ -62,6 +59,8 @@ abstract class ApiQueryContinueTestBase extends ApiQueryTestBase { } if ( $useContinue && !isset( $params['continue'] ) ) { $params['continue'] = ''; + } else { + $params['rawcontinue'] = '1'; } $count = 0; $result = array(); diff --git a/tests/phpunit/includes/api/query/ApiQueryTest.php b/tests/phpunit/includes/api/query/ApiQueryTest.php index bba22c77..5f061b50 100644 --- a/tests/phpunit/includes/api/query/ApiQueryTest.php +++ b/tests/phpunit/includes/api/query/ApiQueryTest.php @@ -7,32 +7,21 @@ * @covers ApiQuery */ class ApiQueryTest extends ApiTestCase { - /** - * @var array Storage for $wgHooks - */ - protected $hooks; - protected function setUp() { - global $wgHooks; - parent::setUp(); $this->doLogin(); - // Setup en: as interwiki prefix - $this->hooks = $wgHooks; - $wgHooks['InterwikiLoadPrefix'][] = function ( $prefix, &$data ) { - if ( $prefix == 'apiquerytestiw' ) { - $data = array( 'iw_url' => 'wikipedia' ); - } - return false; - }; - } - - protected function tearDown() { - global $wgHooks; - $wgHooks = $this->hooks; - - parent::tearDown(); + // Setup apiquerytestiw: as interwiki prefix + $this->setMwGlobals( 'wgHooks', array( + 'InterwikiLoadPrefix' => array( + function ( $prefix, &$data ) { + if ( $prefix == 'apiquerytestiw' ) { + $data = array( 'iw_url' => 'wikipedia' ); + } + return false; + } + ) + ) ); } public function testTitlesGetNormalized() { @@ -127,4 +116,27 @@ class ApiQueryTest extends ApiTestCase { array( 'apiquerytestiw:foo', NS_MAIN, null, true ), ); } + + /** + * Test if all classes in the query module manager exists + */ + public function testClassNamesInModuleManager() { + global $wgAutoloadLocalClasses, $wgAutoloadClasses; + + // wgAutoloadLocalClasses has precedence, just like in includes/AutoLoader.php + $classes = $wgAutoloadLocalClasses + $wgAutoloadClasses; + + $api = new ApiMain( + new FauxRequest( array( 'action' => 'query', 'meta' => 'siteinfo' ) ) + ); + $queryApi = new ApiQuery( $api, 'query' ); + $modules = $queryApi->getModuleManager()->getNamesWithClasses(); + foreach( $modules as $name => $class ) { + $this->assertArrayHasKey( + $class, + $classes, + 'Class ' . $class . ' for api module ' . $name . ' not in autoloader (with exact case)' + ); + } + } } diff --git a/tests/phpunit/includes/api/query/ApiQueryTestBase.php b/tests/phpunit/includes/api/query/ApiQueryTestBase.php index 56c15b23..dabf72e0 100644 --- a/tests/phpunit/includes/api/query/ApiQueryTestBase.php +++ b/tests/phpunit/includes/api/query/ApiQueryTestBase.php @@ -88,19 +88,26 @@ STR; /** * Checks that the request's result matches the expected results. * @param array $values Array is a two element array( request, expected_results ) - * @throws Exception + * @param array $session + * @param bool $appendModule + * @param User $user */ - protected function check( $values ) { + protected function check( $values, array $session = null, + $appendModule = false, User $user = null + ) { list( $req, $exp ) = $this->validateRequestExpectedPair( $values ); if ( !array_key_exists( 'action', $req ) ) { $req['action'] = 'query'; } + if ( !array_key_exists( 'continue', $req ) ) { + $req['rawcontinue'] = '1'; + } foreach ( $req as &$val ) { if ( is_array( $val ) ) { $val = implode( '|', array_unique( $val ) ); } } - $result = $this->doApiRequest( $req ); + $result = $this->doApiRequest( $req, $session, $appendModule, $user ); $this->assertResult( array( 'query' => $exp ), $result[0], $req ); } @@ -113,9 +120,16 @@ STR; if ( is_array( $message ) ) { $message = http_build_query( $message ); } + + // FIXME: once we migrate to phpunit 4.1+, hardcode ComparisonFailure exception use + $compEx = 'SebastianBergmann\Comparator\ComparisonFailure'; + if ( !class_exists( $compEx ) ) { + $compEx = 'PHPUnit_Framework_ComparisonFailure'; + } + throw new PHPUnit_Framework_ExpectationFailedException( $e->getMessage() . "\nRequest: $message", - new PHPUnit_Framework_ComparisonFailure( + new $compEx( $exp, $result, print_r( $exp, true ), diff --git a/tests/phpunit/includes/cache/GenderCacheTest.php b/tests/phpunit/includes/cache/GenderCacheTest.php index ce2db5d7..04fb00d9 100644 --- a/tests/phpunit/includes/cache/GenderCacheTest.php +++ b/tests/phpunit/includes/cache/GenderCacheTest.php @@ -6,14 +6,10 @@ */ class GenderCacheTest extends MediaWikiLangTestCase { - protected function setUp() { - global $wgDefaultUserOptions; - parent::setUp(); + function addDBData() { //ensure the correct default gender - $wgDefaultUserOptions['gender'] = 'unknown'; - } + $this->mergeMwGlobalArrayValue( 'wgDefaultUserOptions', array( 'gender' => 'unknown' ) ); - function addDBData() { $user = User::newFromName( 'UTMale' ); if ( $user->getID() == 0 ) { $user->addToDatabase(); diff --git a/tests/phpunit/includes/cache/LocalisationCacheTest.php b/tests/phpunit/includes/cache/LocalisationCacheTest.php index fc06a501..a0d308aa 100644 --- a/tests/phpunit/includes/cache/LocalisationCacheTest.php +++ b/tests/phpunit/includes/cache/LocalisationCacheTest.php @@ -7,18 +7,32 @@ */ class LocalisationCacheTest extends MediaWikiTestCase { protected function setUp() { - global $IP; - parent::setUp(); $this->setMwGlobals( array( - 'wgMessagesDirs' => array( "$IP/tests/phpunit/data/localisationcache" ), 'wgExtensionMessagesFiles' => array(), 'wgHooks' => array(), ) ); } + /** + * @return PHPUnit_Framework_MockObject_MockObject|LocalisationCache + */ + protected function getMockLocalisationCache() { + global $IP; + $lc = $this->getMockBuilder( 'LocalisationCache' ) + ->setConstructorArgs( array( array( 'store' => 'detect' ) ) ) + ->setMethods( array( 'getMessagesDirs' ) ) + ->getMock(); + $lc->expects( $this->any() )->method( 'getMessagesDirs' ) + ->will( $this->returnValue( + array( "$IP/tests/phpunit/data/localisationcache" ) + ) ); + + return $lc; + } + public function testPuralRulesFallback() { - $cache = new LocalisationCache( array( 'store' => 'detect' ) ); + $cache = $this->getMockLocalisationCache(); $this->assertEquals( $cache->getItem( 'ar', 'pluralRules' ), @@ -46,7 +60,7 @@ class LocalisationCacheTest extends MediaWikiTestCase { } public function testRecacheFallbacks() { - $lc = new LocalisationCache( array( 'store' => 'detect' ) ); + $lc = $this->getMockLocalisationCache(); $lc->recache( 'uk' ); $this->assertEquals( array( @@ -60,23 +74,25 @@ class LocalisationCacheTest extends MediaWikiTestCase { } public function testRecacheFallbacksWithHooks() { - global $wgHooks; - // Use hook to provide updates for messages. This is what the // LocalisationUpdate extension does. See bug 68781. - $wgHooks['LocalisationCacheRecacheFallback'][] = function ( - LocalisationCache $lc, - $code, - array &$cache - ) { - if ( $code === 'ru' ) { - $cache['messages']['present-uk'] = 'ru-override'; - $cache['messages']['present-ru'] = 'ru-override'; - $cache['messages']['present-en'] = 'ru-override'; - } - }; + $this->mergeMwGlobalArrayValue( 'wgHooks', array( + 'LocalisationCacheRecacheFallback' => array( + function ( + LocalisationCache $lc, + $code, + array &$cache + ) { + if ( $code === 'ru' ) { + $cache['messages']['present-uk'] = 'ru-override'; + $cache['messages']['present-ru'] = 'ru-override'; + $cache['messages']['present-en'] = 'ru-override'; + } + } + ) + ) ); - $lc = new LocalisationCache( array( 'store' => 'detect' ) ); + $lc = $this->getMockLocalisationCache(); $lc->recache( 'uk' ); $this->assertEquals( array( diff --git a/tests/phpunit/includes/cache/RedisBloomCacheTest.php b/tests/phpunit/includes/cache/RedisBloomCacheTest.php deleted file mode 100644 index 3d491e90..00000000 --- a/tests/phpunit/includes/cache/RedisBloomCacheTest.php +++ /dev/null @@ -1,71 +0,0 @@ -<?php - -/** - * Test for BloomCacheRedis class. - * - * @TODO: some generic base "redis test server conf" for all testing? - * - * @covers BloomCacheRedis - * @group Cache - */ -class BloomCacheRedisTest extends MediaWikiTestCase { - private static $suffix; - - protected function setUp() { - parent::setUp(); - - self::$suffix = self::$suffix ? : mt_rand(); - - $fcache = BloomCache::get( 'main' ); - if ( $fcache instanceof BloomCacheRedis ) { - $fcache->delete( "unit-testing-" . self::$suffix ); - } else { - $this->markTestSkipped( 'The main bloom cache is not redis.' ); - } - } - - public function testBloomCache() { - $key = "unit-testing-" . self::$suffix; - $fcache = BloomCache::get( 'main' ); - $count = 1500; - - $this->assertTrue( $fcache->delete( $key ), "OK delete of filter '$key'." ); - $this->assertTrue( $fcache->init( $key, $count, .001 ), "OK init of filter '$key'." ); - - $members = array(); - for ( $i = 0; $i < $count; ++$i ) { - $members[] = "$i-value-$i"; - } - $this->assertTrue( $fcache->add( $key, $members ), "Addition of members to '$key' OK." ); - - for ( $i = 0; $i < $count; ++$i ) { - $this->assertTrue( $fcache->isHit( $key, "$i-value-$i" ), "Hit on member '$i-value-$i'." ); - } - - $falsePositives = array(); - for ( $i = $count; $i < 2 * $count; ++$i ) { - if ( $fcache->isHit( $key, "value$i" ) ) { - $falsePositives[] = "value$i"; - } - } - - $eFalsePositives = array( - 'value1763', - 'value2245', - 'value2353', - 'value2791', - 'value2898', - 'value2975' - ); - $this->assertEquals( $eFalsePositives, $falsePositives, "Correct number of false positives found." ); - } - - protected function tearDown() { - parent::tearDown(); - - $fcache = BloomCache::get( 'main' ); - if ( $fcache instanceof BloomCacheRedis ) { - $fcache->delete( "unit-testing-" . self::$suffix ); - } - } -} diff --git a/tests/phpunit/includes/changes/EnhancedChangesListTest.php b/tests/phpunit/includes/changes/EnhancedChangesListTest.php index 40a11d2d..a14a50d2 100644 --- a/tests/phpunit/includes/changes/EnhancedChangesListTest.php +++ b/tests/phpunit/includes/changes/EnhancedChangesListTest.php @@ -5,7 +5,6 @@ * * @group Database * - * @licence GNU GPL v2+ * @author Katie Filbert < aude.wiki@gmail.com > */ class EnhancedChangesListTest extends MediaWikiLangTestCase { @@ -31,7 +30,7 @@ class EnhancedChangesListTest extends MediaWikiLangTestCase { 'mediawiki.special.changeslist', $styleModules, 'has mediawiki.special.changeslist' - ); + ); $this->assertContains( 'mediawiki.special.changeslist.enhanced', @@ -75,10 +74,10 @@ class EnhancedChangesListTest extends MediaWikiLangTestCase { $this->assertEquals( '', $html ); } - /** - * @todo more tests for actual formatting, this is more of a smoke test - */ - public function testEndRecentChangesList() { + /** + * @todo more tests for actual formatting, this is more of a smoke test + */ + public function testEndRecentChangesList() { $enhancedChangesList = $this->newEnhancedChangesList(); $enhancedChangesList->beginRecentChangesList(); @@ -92,7 +91,7 @@ class EnhancedChangesListTest extends MediaWikiLangTestCase { preg_match_all( '/td class="mw-enhanced-rc-nested"/', $html, $matches ); $this->assertCount( 2, $matches[0] ); - } + } /** * @return EnhancedChangesList diff --git a/tests/phpunit/includes/changes/OldChangesListTest.php b/tests/phpunit/includes/changes/OldChangesListTest.php index 2ea9f33e..311ad89c 100644 --- a/tests/phpunit/includes/changes/OldChangesListTest.php +++ b/tests/phpunit/includes/changes/OldChangesListTest.php @@ -9,7 +9,6 @@ * * @group Database * - * @licence GNU GPL v2+ * @author Katie Filbert < aude.wiki@gmail.com > */ class OldChangesListTest extends MediaWikiLangTestCase { diff --git a/tests/phpunit/includes/changes/RCCacheEntryFactoryTest.php b/tests/phpunit/includes/changes/RCCacheEntryFactoryTest.php index ee1a4d0e..0b877275 100644 --- a/tests/phpunit/includes/changes/RCCacheEntryFactoryTest.php +++ b/tests/phpunit/includes/changes/RCCacheEntryFactoryTest.php @@ -5,7 +5,6 @@ * * @group Database * - * @licence GNU GPL v2+ * @author Katie Filbert < aude.wiki@gmail.com > */ class RCCacheEntryFactoryTest extends MediaWikiLangTestCase { diff --git a/tests/phpunit/includes/changes/RecentChangeTest.php b/tests/phpunit/includes/changes/RecentChangeTest.php index 98903f1e..b3cb7b52 100644 --- a/tests/phpunit/includes/changes/RecentChangeTest.php +++ b/tests/phpunit/includes/changes/RecentChangeTest.php @@ -35,6 +35,7 @@ class RecentChangeTest extends MediaWikiTestCase { * Should cover the following log actions (which are most commonly used by bots): * - block/block * - block/unblock + * - block/reblock * - delete/delete * - delete/restore * - newusers/create @@ -46,6 +47,9 @@ class RecentChangeTest extends MediaWikiTestCase { * - protect/modifyprotect * - protect/unprotect * - upload/upload + * - merge/merge + * - import/upload + * - import/interwiki * * As well as the following Auto Edit Summaries: * - blank @@ -62,9 +66,13 @@ class RecentChangeTest extends MediaWikiTestCase { # block/block $this->assertIRCComment( - $this->context->msg( 'blocklogentry', 'SomeTitle' )->plain() . $sep . $this->user_comment, + $this->context->msg( 'blocklogentry', 'SomeTitle', 'duration', '(flags)' )->plain() + . $sep . $this->user_comment, 'block', 'block', - array(), + array( + '5::duration' => 'duration', + '6::flags' => 'flags', + ), $this->user_comment ); # block/unblock @@ -74,6 +82,17 @@ class RecentChangeTest extends MediaWikiTestCase { array(), $this->user_comment ); + # block/reblock + $this->assertIRCComment( + $this->context->msg( 'reblock-logentry', 'SomeTitle', 'duration', '(flags)' )->plain() + . $sep . $this->user_comment, + 'block', 'reblock', + array( + '5::duration' => 'duration', + '6::flags' => 'flags', + ), + $this->user_comment + ); } /** @@ -230,6 +249,48 @@ class RecentChangeTest extends MediaWikiTestCase { } /** + * @covers LogFormatter::getIRCActionText + */ + public function testIrcMsgForLogTypeMerge() { + $sep = $this->context->msg( 'colon-separator' )->text(); + + # merge/merge + $this->assertIRCComment( + $this->context->msg( 'pagemerge-logentry', 'SomeTitle', 'Dest', 'timestamp' )->plain() + . $sep . $this->user_comment, + 'merge', 'merge', + array( + '4::dest' => 'Dest', + '5::mergepoint' => 'timestamp', + ), + $this->user_comment + ); + } + + /** + * @covers LogFormatter::getIRCActionText + */ + public function testIrcMsgForLogTypeImport() { + $sep = $this->context->msg( 'colon-separator' )->text(); + + # import/upload + $this->assertIRCComment( + $this->context->msg( 'import-logentry-upload', 'SomeTitle' )->plain() . $sep . $this->user_comment, + 'import', 'upload', + array(), + $this->user_comment + ); + + # import/interwiki + $this->assertIRCComment( + $this->context->msg( 'import-logentry-interwiki', 'SomeTitle' )->plain() . $sep . $this->user_comment, + 'import', 'interwiki', + array(), + $this->user_comment + ); + } + + /** * @todo Emulate these edits somehow and extract * raw edit summary from RecentChange object * -- diff --git a/tests/phpunit/includes/changes/TestRecentChangesHelper.php b/tests/phpunit/includes/changes/TestRecentChangesHelper.php index ad643274..2506087b 100644 --- a/tests/phpunit/includes/changes/TestRecentChangesHelper.php +++ b/tests/phpunit/includes/changes/TestRecentChangesHelper.php @@ -3,7 +3,6 @@ /** * Helper for generating test recent changes entries. * - * @licence GNU GPL v2+ * @author Katie Filbert < aude.wiki@gmail.com > */ class TestRecentChangesHelper { diff --git a/tests/phpunit/includes/composer/ComposerVersionNormalizerTest.php b/tests/phpunit/includes/composer/ComposerVersionNormalizerTest.php index 3f887dc0..2fa11eaf 100644 --- a/tests/phpunit/includes/composer/ComposerVersionNormalizerTest.php +++ b/tests/phpunit/includes/composer/ComposerVersionNormalizerTest.php @@ -5,7 +5,6 @@ * * @group ComposerHooks * - * @licence GNU GPL v2+ * @author Jeroen De Dauw < jeroendedauw@gmail.com > */ class ComposerVersionNormalizerTest extends PHPUnit_Framework_TestCase { diff --git a/tests/phpunit/includes/config/GlobalVarConfigTest.php b/tests/phpunit/includes/config/GlobalVarConfigTest.php index 70b9e684..28068d5e 100644 --- a/tests/phpunit/includes/config/GlobalVarConfigTest.php +++ b/tests/phpunit/includes/config/GlobalVarConfigTest.php @@ -87,34 +87,10 @@ class GlobalVarConfigTest extends MediaWikiTestCase { $this->assertEquals( $config->get( $name ), $expected ); } - public static function provideSet() { - return array( - array( 'Foo', 'wg', 'wgFoo' ), - array( 'SomethingRandom', 'wg', 'wgSomethingRandom' ), - array( 'FromAnExtension', 'eg', 'egFromAnExtension' ), - array( 'NoPrefixHere', '', 'NoPrefixHere' ), - ); - } - private function maybeStashGlobal( $var ) { if ( array_key_exists( $var, $GLOBALS ) ) { // Will be reset after this test is over $this->stashMwGlobals( $var ); } } - - /** - * @dataProvider provideSet - * @covers GlobalVarConfig::set - * @covers GlobalVarConfig::setWithPrefix - */ - public function testSet( $name, $prefix, $var ) { - $this->hideDeprecated( 'GlobalVarConfig::set' ); - $this->maybeStashGlobal( $var ); - $config = new GlobalVarConfig( $prefix ); - $random = wfRandomString(); - $config->set( $name, $random ); - $this->assertArrayHasKey( $var, $GLOBALS ); - $this->assertEquals( $random, $GLOBALS[$var] ); - } } diff --git a/tests/phpunit/includes/config/HashConfigTest.php b/tests/phpunit/includes/config/HashConfigTest.php index 3ad3bfbd..06973b09 100644 --- a/tests/phpunit/includes/config/HashConfigTest.php +++ b/tests/phpunit/includes/config/HashConfigTest.php @@ -60,4 +60,4 @@ class HashConfigTest extends MediaWikiTestCase { $conf->set( 'one', '3' ); $this->assertEquals( '3', $conf->get( 'one' ) ); } -}
\ No newline at end of file +} diff --git a/tests/phpunit/includes/content/ContentHandlerTest.php b/tests/phpunit/includes/content/ContentHandlerTest.php index f7449734..988a59ee 100644 --- a/tests/phpunit/includes/content/ContentHandlerTest.php +++ b/tests/phpunit/includes/content/ContentHandlerTest.php @@ -2,11 +2,6 @@ /** * @group ContentHandler - * @group Database - * - * @note Declare that we are using the database, because otherwise we'll fail in - * the "databaseless" test run. This is because the LinkHolderArray used by the - * parser needs database access. */ class ContentHandlerTest extends MediaWikiTestCase { @@ -36,6 +31,8 @@ class ContentHandlerTest extends MediaWikiTestCase { // Reset namespace cache MWNamespace::getCanonicalNamespaces( true ); $wgContLang->resetNamespaces(); + // And LinkCache + LinkCache::destroySingleton(); } protected function tearDown() { @@ -44,6 +41,8 @@ class ContentHandlerTest extends MediaWikiTestCase { // Reset namespace cache MWNamespace::getCanonicalNamespaces( true ); $wgContLang->resetNamespaces(); + // And LinkCache + LinkCache::destroySingleton(); parent::tearDown(); } @@ -83,6 +82,7 @@ class ContentHandlerTest extends MediaWikiTestCase { */ public function testGetForTitle( $title, $expectedContentModel ) { $title = Title::newFromText( $title ); + LinkCache::singleton()->addBadLinkObj( $title ); $handler = ContentHandler::getForTitle( $title ); $this->assertEquals( $expectedContentModel, $handler->getModelID() ); } @@ -139,6 +139,7 @@ class ContentHandlerTest extends MediaWikiTestCase { public function testGetPageLanguage( $title, $expected ) { if ( is_string( $title ) ) { $title = Title::newFromText( $title ); + LinkCache::singleton()->addBadLinkObj( $title ); } $expected = wfGetLangObj( $expected ); @@ -292,7 +293,7 @@ class ContentHandlerTest extends MediaWikiTestCase { $expectedModelId, $expectedNativeData, $shouldFail ) { $title = Title::newFromText( $title ); - + LinkCache::singleton()->addBadLinkObj( $title ); try { $content = ContentHandler::makeContent( $data, $title, $modelId, $format ); @@ -317,6 +318,8 @@ class ContentHandlerTest extends MediaWikiTestCase { * page. */ public function testGetAutosummary() { + $this->setMwGlobals( 'wgContLang', Language::factory( 'en' ) ); + $content = new DummyContentHandlerForTesting( CONTENT_MODEL_WIKITEXT ); $title = Title::newFromText( 'Help:Test' ); // Create a new content object with no content diff --git a/tests/phpunit/includes/content/JsonContentTest.php b/tests/phpunit/includes/content/JsonContentTest.php index 77b542f4..cccfe7b1 100644 --- a/tests/phpunit/includes/content/JsonContentTest.php +++ b/tests/phpunit/includes/content/JsonContentTest.php @@ -6,48 +6,85 @@ */ class JsonContentTest extends MediaWikiLangTestCase { - /** - * @dataProvider provideValidConstruction - */ - public function testValidConstruct( $text, $modelId, $isValid, $expected ) { - $obj = new JsonContent( $text, $modelId ); - $this->assertEquals( $isValid, $obj->isValid() ); - $this->assertEquals( $expected, $obj->getJsonData() ); + protected function setUp() { + parent::setUp(); + + $this->setMwGlobals( 'wgWellFormedXml', true ); } public static function provideValidConstruction() { return array( - array( 'foo', CONTENT_MODEL_JSON, false, null ), - array( FormatJson::encode( array() ), CONTENT_MODEL_JSON, true, array() ), - array( FormatJson::encode( array( 'foo' ) ), CONTENT_MODEL_JSON, true, array( 'foo' ) ), + array( 'foo', false, null ), + array( '[]', true, array() ), + array( '{}', true, (object)array() ), + array( '""', true, '' ), + array( '"0"', true, '0' ), + array( '"bar"', true, 'bar' ), + array( '0', true, '0' ), + array( '{ "0": "bar" }', true, (object)array( 'bar' ) ), ); } /** - * @dataProvider provideDataToEncode + * @dataProvider provideValidConstruction */ - public function testBeautifyUsesFormatJson( $data ) { - $obj = new JsonContent( FormatJson::encode( $data ) ); - $this->assertEquals( FormatJson::encode( $data, true ), $obj->beautifyJSON() ); + public function testIsValid( $text, $isValid, $expected ) { + $obj = new JsonContent( $text, CONTENT_MODEL_JSON ); + $this->assertEquals( $isValid, $obj->isValid() ); + $this->assertEquals( $expected, $obj->getData()->getValue() ); } public static function provideDataToEncode() { return array( - array( array() ), - array( array( 'foo' ) ), - array( array( 'foo', 'bar' ) ), - array( array( 'baz' => 'foo', 'bar' ) ), - array( array( 'baz' => 1000, 'bar' ) ), + array( + // Round-trip empty array + '[]', + '[]', + ), + array( + // Round-trip empty object + '{}', + '{}', + ), + array( + // Round-trip empty array/object (nested) + '{ "foo": {}, "bar": [] }', + "{\n \"foo\": {},\n \"bar\": []\n}", + ), + array( + '{ "foo": "bar" }', + "{\n \"foo\": \"bar\"\n}", + ), + array( + '{ "foo": 1000 }', + "{\n \"foo\": 1000\n}", + ), + array( + '{ "foo": 1000, "0": "bar" }', + "{\n \"foo\": 1000,\n \"0\": \"bar\"\n}", + ), ); } /** * @dataProvider provideDataToEncode */ - public function testPreSaveTransform( $data ) { - $obj = new JsonContent( FormatJson::encode( $data ) ); - $newObj = $obj->preSaveTransform( $this->getMockTitle(), $this->getMockUser(), $this->getMockParserOptions() ); - $this->assertTrue( $newObj->equals( new JsonContent( FormatJson::encode( $data, true ) ) ) ); + public function testBeautifyJson( $input, $beautified ) { + $obj = new JsonContent( $input ); + $this->assertEquals( $beautified, $obj->beautifyJSON() ); + } + + /** + * @dataProvider provideDataToEncode + */ + public function testPreSaveTransform( $input, $transformed ) { + $obj = new JsonContent( $input ); + $newObj = $obj->preSaveTransform( + $this->getMockTitle(), + $this->getMockUser(), + $this->getMockParserOptions() + ); + $this->assertTrue( $newObj->equals( new JsonContent( $transformed ) ) ); } private function getMockTitle() { @@ -67,48 +104,55 @@ class JsonContentTest extends MediaWikiLangTestCase { ->getMock(); } - /** - * @dataProvider provideDataAndParserText - */ - public function testFillParserOutput( $data, $expected ) { - $obj = new JsonContent( FormatJson::encode( $data ) ); - $parserOutput = $obj->getParserOutput( $this->getMockTitle(), null, null, true ); - $this->assertInstanceOf( 'ParserOutput', $parserOutput ); - $this->assertEquals( $expected, $parserOutput->getText() ); - } - public static function provideDataAndParserText() { return array( array( array(), - '<table class="mw-json"><tbody></tbody></table>' + '<table class="mw-json"><tbody><tr><td>' . + '<table class="mw-json"><tbody><tr><td class="mw-json-empty">Empty array</td></tr>' + . '</tbody></table></td></tr></tbody></table>' ), array( - array( 'foo' ), - '<table class="mw-json"><tbody><tr><th>0</th><td class="value">"foo"</td></tr></tbody></table>' + (object)array(), + '<table class="mw-json"><tbody><tr><td class="mw-json-empty">Empty object</td></tr>' . + '</tbody></table>' ), array( - array( 'foo', 'bar' ), - '<table class="mw-json"><tbody><tr><th>0</th><td class="value">"foo"</td></tr>' . - "\n" . - '<tr><th>1</th><td class="value">"bar"</td></tr></tbody></table>' + (object)array( 'foo' ), + '<table class="mw-json"><tbody><tr><th>0</th><td class="value">"foo"</td></tr>' . + '</tbody></table>' ), array( - array( 'baz' => 'foo', 'bar' ), - '<table class="mw-json"><tbody><tr><th>baz</th><td class="value">"foo"</td></tr>' . - "\n" . - '<tr><th>0</th><td class="value">"bar"</td></tr></tbody></table>' + (object)array( 'foo', 'bar' ), + '<table class="mw-json"><tbody><tr><th>0</th><td class="value">"foo"</td></tr>' . + '<tr><th>1</th><td class="value">"bar"</td></tr></tbody></table>' ), array( - array( 'baz' => 1000, 'bar' ), + (object)array( 'baz' => 'foo', 'bar' ), + '<table class="mw-json"><tbody><tr><th>baz</th><td class="value">"foo"</td></tr>' . + '<tr><th>0</th><td class="value">"bar"</td></tr></tbody></table>' + ), + array( + (object)array( 'baz' => 1000, 'bar' ), '<table class="mw-json"><tbody><tr><th>baz</th><td class="value">1000</td></tr>' . - "\n" . - '<tr><th>0</th><td class="value">"bar"</td></tr></tbody></table>' + '<tr><th>0</th><td class="value">"bar"</td></tr></tbody></table>' ), array( - array( '<script>alert("evil!")</script>'), - '<table class="mw-json"><tbody><tr><th>0</th><td class="value">"<script>alert("evil!")</script>"</td></tr></tbody></table>', + (object)array( '<script>alert("evil!")</script>'), + '<table class="mw-json"><tbody><tr><th>0</th><td class="value">"' . + '<script>alert("evil!")</script>"' . + '</td></tr></tbody></table>', ), ); } + + /** + * @dataProvider provideDataAndParserText + */ + public function testFillParserOutput( $data, $expected ) { + $obj = new JsonContent( FormatJson::encode( $data ) ); + $parserOutput = $obj->getParserOutput( $this->getMockTitle(), null, null, true ); + $this->assertInstanceOf( 'ParserOutput', $parserOutput ); + $this->assertEquals( $expected, $parserOutput->getText() ); + } } diff --git a/tests/phpunit/includes/content/TextContentTest.php b/tests/phpunit/includes/content/TextContentTest.php index 2f811094..dd61f85b 100644 --- a/tests/phpunit/includes/content/TextContentTest.php +++ b/tests/phpunit/includes/content/TextContentTest.php @@ -7,11 +7,8 @@ */ class TextContentTest extends MediaWikiLangTestCase { protected $context; - protected $savedContentGetParserOutput; protected function setUp() { - global $wgHooks; - parent::setUp(); // Anon user @@ -32,24 +29,8 @@ class TextContentTest extends MediaWikiLangTestCase { 'wgUseTidy' => false, 'wgAlwaysUseTidy' => false, 'wgCapitalLinks' => true, + 'wgHooks' => array(), // bypass hook ContentGetParserOutput that force custom rendering ) ); - - // bypass hooks that force custom rendering - if ( isset( $wgHooks['ContentGetParserOutput'] ) ) { - $this->savedContentGetParserOutput = $wgHooks['ContentGetParserOutput']; - unset( $wgHooks['ContentGetParserOutput'] ); - } - } - - public function teardown() { - global $wgHooks; - - // restore hooks that force custom rendering - if ( $this->savedContentGetParserOutput !== null ) { - $wgHooks['ContentGetParserOutput'] = $this->savedContentGetParserOutput; - } - - parent::teardown(); } public function newContent( $text ) { diff --git a/tests/phpunit/includes/RequestContextTest.php b/tests/phpunit/includes/context/RequestContextTest.php index cae0e52e..a9e5be24 100644 --- a/tests/phpunit/includes/RequestContextTest.php +++ b/tests/phpunit/includes/context/RequestContextTest.php @@ -88,9 +88,9 @@ class RequestContextTest extends MediaWikiTestCase { unset( $sc ); // restore previous context $info = $context->exportSession(); - $this->assertEquals( $oInfo['ip'], $info['ip'], "Correct initial IP address." ); - $this->assertEquals( $oInfo['headers'], $info['headers'], "Correct initial headers." ); - $this->assertEquals( $oInfo['sessionId'], $info['sessionId'], "Correct initial session ID." ); - $this->assertEquals( $oInfo['userId'], $info['userId'], "Correct initial user ID." ); + $this->assertEquals( $oInfo['ip'], $info['ip'], "Correct restored IP address." ); + $this->assertEquals( $oInfo['headers'], $info['headers'], "Correct restored headers." ); + $this->assertEquals( $oInfo['sessionId'], $info['sessionId'], "Correct restored session ID." ); + $this->assertEquals( $oInfo['userId'], $info['userId'], "Correct restored user ID." ); } } diff --git a/tests/phpunit/includes/db/DatabaseMysqlBaseTest.php b/tests/phpunit/includes/db/DatabaseMysqlBaseTest.php index 55e48d13..b4292a60 100644 --- a/tests/phpunit/includes/db/DatabaseMysqlBaseTest.php +++ b/tests/phpunit/includes/db/DatabaseMysqlBaseTest.php @@ -2,7 +2,6 @@ /** * Holds tests for DatabaseMysqlBase MediaWiki class. * - * @section LICENSE * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or diff --git a/tests/phpunit/includes/db/DatabaseSQLTest.php b/tests/phpunit/includes/db/DatabaseSQLTest.php index 5c2d4b70..b13751f3 100644 --- a/tests/phpunit/includes/db/DatabaseSQLTest.php +++ b/tests/phpunit/includes/db/DatabaseSQLTest.php @@ -722,4 +722,84 @@ class DatabaseSQLTest extends MediaWikiTestCase { $this->database->dropTable( 'non_existing', __METHOD__ ) ); } + + /** + * @dataProvider provideMakeList + * @covers DatabaseBase::makeList + */ + public function testMakeList( $list, $mode, $sqlText ) { + $this->assertEquals( trim( $this->database->makeList( + $list, $mode + ) ), $sqlText ); + } + + public static function provideMakeList() { + return array( + array( + array( 'value', 'value2' ), + LIST_COMMA, + "'value','value2'" + ), + array( + array( 'field', 'field2' ), + LIST_NAMES, + "field,field2" + ), + array( + array( 'field' => 'value', 'field2' => 'value2' ), + LIST_AND, + "field = 'value' AND field2 = 'value2'" + ), + array( + array( 'field' => null, "field2 != 'value2'" ), + LIST_AND, + "field IS NULL AND (field2 != 'value2')" + ), + array( + array( 'field' => array( 'value', null, 'value2' ), 'field2' => 'value2' ), + LIST_AND, + "(field IN ('value','value2') OR field IS NULL) AND field2 = 'value2'" + ), + array( + array( 'field' => array( null ), 'field2' => null ), + LIST_AND, + "field IS NULL AND field2 IS NULL" + ), + array( + array( 'field' => 'value', 'field2' => 'value2' ), + LIST_OR, + "field = 'value' OR field2 = 'value2'" + ), + array( + array( 'field' => 'value', 'field2' => null ), + LIST_OR, + "field = 'value' OR field2 IS NULL" + ), + array( + array( 'field' => array( 'value', 'value2' ), 'field2' => array( 'value' ) ), + LIST_OR, + "field IN ('value','value2') OR field2 = 'value'" + ), + array( + array( 'field' => array( null, 'value', null, 'value2' ), "field2 != 'value2'" ), + LIST_OR, + "(field IN ('value','value2') OR field IS NULL) OR (field2 != 'value2')" + ), + array( + array( 'field' => 'value', 'field2' => 'value2' ), + LIST_SET, + "field = 'value',field2 = 'value2'" + ), + array( + array( 'field' => 'value', 'field2' => null ), + LIST_SET, + "field = 'value',field2 = NULL" + ), + array( + array( 'field' => 'value', "field2 != 'value2'" ), + LIST_SET, + "field = 'value',field2 != 'value2'" + ), + ); + } } diff --git a/tests/phpunit/includes/db/DatabaseSqliteTest.php b/tests/phpunit/includes/db/DatabaseSqliteTest.php index 98b4ca04..645baf1f 100644 --- a/tests/phpunit/includes/db/DatabaseSqliteTest.php +++ b/tests/phpunit/includes/db/DatabaseSqliteTest.php @@ -1,10 +1,12 @@ <?php -class MockDatabaseSqlite extends DatabaseSqliteStandalone { +class MockDatabaseSqlite extends DatabaseSqlite { private $lastQuery; - function __construct() { - parent::__construct( ':memory:' ); + public static function newInstance( array $p = array() ) { + $p['dbFilePath'] = ':memory:'; + + return new self( $p ); } function query( $sql, $fname = '', $tempIgnore = false ) { @@ -36,7 +38,7 @@ class DatabaseSqliteTest extends MediaWikiTestCase { if ( !Sqlite::isPresent() ) { $this->markTestSkipped( 'No SQLite support detected' ); } - $this->db = new MockDatabaseSqlite(); + $this->db = MockDatabaseSqlite::newInstance(); if ( version_compare( $this->db->getServerVersion(), '3.6.0', '<' ) ) { $this->markTestSkipped( "SQLite at least 3.6 required, {$this->db->getServerVersion()} found" ); } @@ -89,7 +91,7 @@ class DatabaseSqliteTest extends MediaWikiTestCase { */ public function testAddQuotes( $value, $expected ) { // check quoting - $db = new DatabaseSqliteStandalone( ':memory:' ); + $db = DatabaseSqlite::newStandaloneInstance( ':memory:' ); $this->assertEquals( $expected, $db->addQuotes( $value ), 'string not quoted as expected' ); // ok, quoting works as expected, now try a round trip. @@ -172,7 +174,7 @@ class DatabaseSqliteTest extends MediaWikiTestCase { */ public function testTableName() { // @todo Moar! - $db = new DatabaseSqliteStandalone( ':memory:' ); + $db = DatabaseSqlite::newStandaloneInstance( ':memory:' ); $this->assertEquals( 'foo', $db->tableName( 'foo' ) ); $this->assertEquals( 'sqlite_master', $db->tableName( 'sqlite_master' ) ); $db->tablePrefix( 'foo' ); @@ -184,7 +186,7 @@ class DatabaseSqliteTest extends MediaWikiTestCase { * @covers DatabaseSqlite::duplicateTableStructure */ public function testDuplicateTableStructure() { - $db = new DatabaseSqliteStandalone( ':memory:' ); + $db = DatabaseSqlite::newStandaloneInstance( ':memory:' ); $db->query( 'CREATE TABLE foo(foo, barfoo)' ); $db->duplicateTableStructure( 'foo', 'bar' ); @@ -208,7 +210,7 @@ class DatabaseSqliteTest extends MediaWikiTestCase { * @covers DatabaseSqlite::duplicateTableStructure */ public function testDuplicateTableStructureVirtual() { - $db = new DatabaseSqliteStandalone( ':memory:' ); + $db = DatabaseSqlite::newStandaloneInstance( ':memory:' ); if ( $db->getFulltextSearchModule() != 'FTS3' ) { $this->markTestSkipped( 'FTS3 not supported, cannot create virtual tables' ); } @@ -231,7 +233,7 @@ class DatabaseSqliteTest extends MediaWikiTestCase { * @covers DatabaseSqlite::deleteJoin */ public function testDeleteJoin() { - $db = new DatabaseSqliteStandalone( ':memory:' ); + $db = DatabaseSqlite::newStandaloneInstance( ':memory:' ); $db->query( 'CREATE TABLE a (a_1)', __METHOD__ ); $db->query( 'CREATE TABLE b (b_1, b_2)', __METHOD__ ); $db->insert( 'a', array( @@ -272,7 +274,7 @@ class DatabaseSqliteTest extends MediaWikiTestCase { * @todo Currently only checks list of tables */ public function testUpgrades() { - global $IP, $wgVersion, $wgProfileToDatabase; + global $IP, $wgVersion, $wgProfiler; // Versions tested $versions = array( @@ -289,9 +291,20 @@ class DatabaseSqliteTest extends MediaWikiTestCase { 'user_newtalk.user_last_timestamp', // r84185 ); - $currentDB = new DatabaseSqliteStandalone( ':memory:' ); + $currentDB = DatabaseSqlite::newStandaloneInstance( ':memory:' ); $currentDB->sourceFile( "$IP/maintenance/tables.sql" ); - if ( $wgProfileToDatabase ) { + + $profileToDb = false; + if ( isset( $wgProfiler['output'] ) ) { + $out = $wgProfiler['output']; + if ( $out === 'db' ) { + $profileToDb = true; + } elseif ( is_array( $out ) && in_array( 'db', $out ) ) { + $profileToDb = true; + } + } + + if ( $profileToDb ) { $currentDB->sourceFile( "$IP/maintenance/sqlite/archives/patch-profiling.sql" ); } $currentTables = $this->getTables( $currentDB ); @@ -346,7 +359,7 @@ class DatabaseSqliteTest extends MediaWikiTestCase { * @covers DatabaseSqlite::insertId */ public function testInsertIdType() { - $db = new DatabaseSqliteStandalone( ':memory:' ); + $db = DatabaseSqlite::newStandaloneInstance( ':memory:' ); $databaseCreation = $db->query( 'CREATE TABLE a ( a_1 )', __METHOD__ ); $this->assertInstanceOf( 'ResultWrapper', $databaseCreation, "Database creation" ); @@ -366,7 +379,7 @@ class DatabaseSqliteTest extends MediaWikiTestCase { } global $IP; - $db = new DatabaseSqliteStandalone( ':memory:' ); + $db = DatabaseSqlite::newStandaloneInstance( ':memory:' ); $db->sourceFile( "$IP/tests/phpunit/data/db/sqlite/tables-$version.sql" ); $updater = DatabaseUpdater::newForDB( $db, false, $maint ); $updater->doUpdates( array( 'core' ) ); @@ -429,7 +442,7 @@ class DatabaseSqliteTest extends MediaWikiTestCase { public function testCaseInsensitiveLike() { // TODO: Test this for all databases - $db = new DatabaseSqliteStandalone( ':memory:' ); + $db = DatabaseSqlite::newStandaloneInstance( ':memory:' ); $res = $db->query( 'SELECT "a" LIKE "A" AS a' ); $row = $res->fetchRow(); $this->assertFalse( (bool)$row['a'] ); @@ -439,7 +452,7 @@ class DatabaseSqliteTest extends MediaWikiTestCase { * @covers DatabaseSqlite::numFields */ public function testNumFields() { - $db = new DatabaseSqliteStandalone( ':memory:' ); + $db = DatabaseSqlite::newStandaloneInstance( ':memory:' ); $databaseCreation = $db->query( 'CREATE TABLE a ( a_1 )', __METHOD__ ); $this->assertInstanceOf( 'ResultWrapper', $databaseCreation, "Failed to create table a" ); diff --git a/tests/phpunit/includes/db/LBFactoryTest.php b/tests/phpunit/includes/db/LBFactoryTest.php index 4c59f474..81d6840b 100644 --- a/tests/phpunit/includes/db/LBFactoryTest.php +++ b/tests/phpunit/includes/db/LBFactoryTest.php @@ -2,7 +2,6 @@ /** * Holds tests for LBFactory abstract MediaWiki class. * - * @section LICENSE * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or diff --git a/tests/phpunit/includes/db/ORMRowTest.php b/tests/phpunit/includes/db/ORMRowTest.php index 447bf219..807bd14e 100644 --- a/tests/phpunit/includes/db/ORMRowTest.php +++ b/tests/phpunit/includes/db/ORMRowTest.php @@ -34,7 +34,6 @@ * that hold the first tests in a pending state awaiting access to the database. * @group medium * - * @licence GNU GPL v2+ * @author Jeroen De Dauw < jeroendedauw@gmail.com > */ abstract class ORMRowTest extends \MediaWikiTestCase { diff --git a/tests/phpunit/includes/db/ORMTableTest.php b/tests/phpunit/includes/db/ORMTableTest.php index 7171ee59..338d931f 100644 --- a/tests/phpunit/includes/db/ORMTableTest.php +++ b/tests/phpunit/includes/db/ORMTableTest.php @@ -25,14 +25,12 @@ * @group ORM * @group Database * - * @licence GNU GPL v2+ + * @covers PageORMTableForTesting + * * @author Jeroen De Dauw < jeroendedauw@gmail.com > * @author Daniel Kinzler */ -/** - * @covers PageORMTableForTesting - */ class ORMTableTest extends MediaWikiTestCase { /** @@ -99,6 +97,10 @@ class ORMTableTest extends MediaWikiTestCase { class PageORMTableForTesting extends ORMTable { + public function __construct() { + $this->fieldPrefix = 'page_'; + } + /** * @see ORMTable::getName * @@ -138,13 +140,4 @@ class PageORMTableForTesting extends ORMTable { 'title' => 'str', ); } - - /** - * @see ORMTable::getFieldPrefix - * - * @return string - */ - protected function getFieldPrefix() { - return 'page_'; - } } diff --git a/tests/phpunit/includes/db/TestORMRowTest.php b/tests/phpunit/includes/db/TestORMRowTest.php index c9459c90..04bb9f38 100644 --- a/tests/phpunit/includes/db/TestORMRowTest.php +++ b/tests/phpunit/includes/db/TestORMRowTest.php @@ -20,27 +20,23 @@ * http://www.gnu.org/copyleft/gpl.html * * @file - * @since 1.20 - * * @ingroup Test - * - * @group ORM - * + * @author Jeroen De Dauw < jeroendedauw@gmail.com > + */ + +/** * The database group has as a side effect that temporal database tables are created. This makes * it possible to test without poisoning a production database. - * @group Database * * Some of the tests takes more time, and needs therefor longer time before they can be aborted * as non-functional. The reason why tests are aborted is assumed to be set up of temporal databases * that hold the first tests in a pending state awaiting access to the database. - * @group medium * - * @licence GNU GPL v2+ - * @author Jeroen De Dauw < jeroendedauw@gmail.com > - */ -require_once __DIR__ . "/ORMRowTest.php"; - -/** + * @since 1.20 + * + * @group ORM + * @group Database + * @group medium * @covers TestORMRow */ class TestORMRowTest extends ORMRowTest { @@ -150,6 +146,10 @@ class TestORMRow extends ORMRow { class TestORMTable extends ORMTable { + public function __construct() { + $this->fieldPrefix = 'test_'; + } + /** * Returns the name of the database table objects of this type are stored in. * @@ -204,15 +204,4 @@ class TestORMTable extends ORMTable { 'time' => 'str', // TS_MW ); } - - /** - * Gets the db field prefix. - * - * @since 1.20 - * - * @return string - */ - protected function getFieldPrefix() { - return 'test_'; - } } diff --git a/tests/phpunit/includes/debug/MWDebugTest.php b/tests/phpunit/includes/debug/MWDebugTest.php index 6e41de75..1abb47e7 100644 --- a/tests/phpunit/includes/debug/MWDebugTest.php +++ b/tests/phpunit/includes/debug/MWDebugTest.php @@ -96,16 +96,15 @@ class MWDebugTest extends MediaWikiTestCase { $apiMain = new ApiMain( $context ); $result = new ApiResult( $apiMain ); - $result->setRawMode( true ); MWDebug::appendDebugInfoToApiResult( $context, $result ); $this->assertInstanceOf( 'ApiResult', $result ); - $data = $result->getData(); + $data = $result->getResultData(); $expectedKeys = array( 'mwVersion', 'phpEngine', 'phpVersion', 'gitRevision', 'gitBranch', 'gitViewUrl', 'time', 'log', 'debugLog', 'queries', 'request', 'memory', - 'memoryPeak', 'includes', 'profile', '_element' ); + 'memoryPeak', 'includes', '_element' ); foreach ( $expectedKeys as $expectedKey ) { $this->assertArrayHasKey( $expectedKey, $data['debuginfo'], "debuginfo has $expectedKey" ); diff --git a/tests/phpunit/includes/debug/logging/LegacyLoggerTest.php b/tests/phpunit/includes/debug/logging/LegacyLoggerTest.php new file mode 100644 index 00000000..415fa045 --- /dev/null +++ b/tests/phpunit/includes/debug/logging/LegacyLoggerTest.php @@ -0,0 +1,122 @@ +<?php +/** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + */ + +namespace MediaWiki\Logger; + +use MediaWikiTestCase; +use Psr\Log\LogLevel; + +class LegacyLoggerTest extends MediaWikiTestCase { + + /** + * @covers LegacyLogger::interpolate + * @dataProvider provideInterpolate + */ + public function testInterpolate( $message, $context, $expect ) { + $this->assertEquals( + $expect, LegacyLogger::interpolate( $message, $context ) ); + } + + public function provideInterpolate() { + return array( + array( + 'no-op', + array(), + 'no-op', + ), + array( + 'Hello {world}!', + array( + 'world' => 'World', + ), + 'Hello World!', + ), + array( + '{greeting} {user}', + array( + 'greeting' => 'Goodnight', + 'user' => 'Moon', + ), + 'Goodnight Moon', + ), + array( + 'Oops {key_not_set}', + array(), + 'Oops {key_not_set}', + ), + array( + '{ not interpolated }', + array( + 'not interpolated' => 'This should NOT show up in the message', + ), + '{ not interpolated }', + ), + ); + } + + /** + * @covers LegacyLogger::shouldEmit + * @dataProvider provideShouldEmit + */ + public function testShouldEmit( $level, $config, $expected ) { + $this->setMwGlobals( 'wgDebugLogGroups', array( 'fakechannel' => $config ) ); + $this->assertEquals( + $expected, + LegacyLogger::shouldEmit( 'fakechannel', 'some message', $level, array() ) + ); + } + + public static function provideShouldEmit() { + $dest = array( 'destination' => 'foobar' ); + $tests = array( + array( + LogLevel::DEBUG, + $dest, + true + ), + array( + LogLevel::WARNING, + $dest + array( 'level' => LogLevel::INFO ), + true, + ), + array( + LogLevel::INFO, + $dest + array( 'level' => LogLevel::CRITICAL ), + false, + ), + ); + + if ( class_exists( '\Monolog\Logger' ) ) { + $tests[] = array( + \Monolog\Logger::INFO, + $dest + array( 'level' => LogLevel::INFO ), + true, + ); + $tests[] = array( + \Monolog\Logger::WARNING, + $dest + array( 'level' => LogLevel::EMERGENCY ), + false, + ); + } + + return $tests; + } + +} diff --git a/tests/phpunit/includes/LinksUpdateTest.php b/tests/phpunit/includes/deferred/LinksUpdateTest.php index 02f6b2ab..02f6b2ab 100644 --- a/tests/phpunit/includes/LinksUpdateTest.php +++ b/tests/phpunit/includes/deferred/LinksUpdateTest.php diff --git a/tests/phpunit/includes/search/SearchUpdateTest.php b/tests/phpunit/includes/deferred/SearchUpdateTest.php index c6275371..90438a04 100644 --- a/tests/phpunit/includes/search/SearchUpdateTest.php +++ b/tests/phpunit/includes/deferred/SearchUpdateTest.php @@ -17,7 +17,6 @@ class MockSearch extends SearchEngine { /** * @group Search - * @group Database */ class SearchUpdateTest extends MediaWikiTestCase { @@ -67,9 +66,10 @@ EOT /** * @covers SearchUpdate::updateText - * @todo give this test a real name explaining what is being tested here + * Test bug 32712 + * Test if unicode quotes in article links make its search index empty */ - public function testBug32712() { + public function testUnicodeLinkSearchIndexError() { $text = "text „http://example.com“ text"; $result = $this->updateText( $text ); $processed = preg_replace( '/Q/u', 'Q', $result ); diff --git a/tests/phpunit/includes/diff/ArrayDiffFormatterTest.php b/tests/phpunit/includes/diff/ArrayDiffFormatterTest.php index 188ad3fd..3bea9b31 100644 --- a/tests/phpunit/includes/diff/ArrayDiffFormatterTest.php +++ b/tests/phpunit/includes/diff/ArrayDiffFormatterTest.php @@ -1,7 +1,6 @@ <?php /** - * @licence GNU GPL v2+ * @author Adam Shorland * * @group Diff diff --git a/tests/phpunit/includes/diff/DiffOpTest.php b/tests/phpunit/includes/diff/DiffOpTest.php index d89b89fe..cbe05732 100644 --- a/tests/phpunit/includes/diff/DiffOpTest.php +++ b/tests/phpunit/includes/diff/DiffOpTest.php @@ -1,10 +1,5 @@ <?php - -//Load our FakeDiffOp -require_once __DIR__ . DIRECTORY_SEPARATOR . 'FakeDiffOp.php'; - /** - * @licence GNU GPL v2+ * @author Adam Shorland * * @group Diff diff --git a/tests/phpunit/includes/diff/DiffTest.php b/tests/phpunit/includes/diff/DiffTest.php index 1911c82a..e0d79157 100644 --- a/tests/phpunit/includes/diff/DiffTest.php +++ b/tests/phpunit/includes/diff/DiffTest.php @@ -1,7 +1,6 @@ <?php /** - * @licence GNU GPL v2+ * @author Adam Shorland * * @group Diff diff --git a/tests/phpunit/includes/diff/DifferenceEngineTest.php b/tests/phpunit/includes/diff/DifferenceEngineTest.php index 5474b963..0f599af1 100644 --- a/tests/phpunit/includes/diff/DifferenceEngineTest.php +++ b/tests/phpunit/includes/diff/DifferenceEngineTest.php @@ -8,7 +8,6 @@ * @group Database * @group Diff * - * @licence GNU GPL v2+ * @author Katie Filbert < aude.wiki@gmail.com > */ class DifferenceEngineTest extends MediaWikiTestCase { diff --git a/tests/phpunit/includes/exception/BadTitleErrorTest.php b/tests/phpunit/includes/exception/BadTitleErrorTest.php index 003efd27..500b7e48 100644 --- a/tests/phpunit/includes/exception/BadTitleErrorTest.php +++ b/tests/phpunit/includes/exception/BadTitleErrorTest.php @@ -5,23 +5,8 @@ */ class BadTitleErrorTest extends MediaWikiTestCase { - protected $wgOut; - - protected function setUp() { - parent::setUp(); - global $wgOut; - $this->wgOut = clone $wgOut; - } - - protected function tearDown() { - parent::tearDown(); - global $wgOut; - $wgOut = $this->wgOut; - } - public function testExceptionSetsStatusCode() { - global $wgOut; - $wgOut = $this->getMockWgOut(); + $this->setMwGlobals( 'wgOut', $this->getMockWgOut() ); try { throw new BadTitleError(); } catch ( BadTitleError $e ) { diff --git a/tests/phpunit/includes/exception/ErrorPageErrorTest.php b/tests/phpunit/includes/exception/ErrorPageErrorTest.php index 13dcf33b..9c4e4a0b 100644 --- a/tests/phpunit/includes/exception/ErrorPageErrorTest.php +++ b/tests/phpunit/includes/exception/ErrorPageErrorTest.php @@ -6,20 +6,6 @@ */ class ErrorPageErrorTest extends MediaWikiTestCase { - private $wgOut; - - protected function setUp() { - parent::setUp(); - global $wgOut; - $this->wgOut = clone $wgOut; - } - - protected function tearDown() { - global $wgOut; - $wgOut = $this->wgOut; - parent::tearDown(); - } - private function getMockMessage() { $mockMessage = $this->getMockBuilder( 'Message' ) ->disableOriginalConstructor() @@ -48,20 +34,18 @@ class ErrorPageErrorTest extends MediaWikiTestCase { $title = 'Foo'; $params = array( 'Baz' ); - global $wgOut; - $wgOut = $this->getMockBuilder( 'OutputPage' ) + $mock = $this->getMockBuilder( 'OutputPage' ) ->disableOriginalConstructor() ->getMock(); - $wgOut->expects( $this->once() ) + $mock->expects( $this->once() ) ->method( 'showErrorPage' ) ->with( $title, $mockMessage, $params ); - $wgOut->expects( $this->once() ) + $mock->expects( $this->once() ) ->method( 'output' ); + $this->setMwGlobals( 'wgOut', $mock ); $e = new ErrorPageError( $title, $mockMessage, $params ); $e->report(); } - - } diff --git a/tests/phpunit/includes/exception/MWExceptionHandlerTest.php b/tests/phpunit/includes/exception/MWExceptionHandlerTest.php index dc5dc6aa..d73f17d9 100644 --- a/tests/phpunit/includes/exception/MWExceptionHandlerTest.php +++ b/tests/phpunit/includes/exception/MWExceptionHandlerTest.php @@ -15,7 +15,7 @@ class MWExceptionHandlerTest extends MediaWikiTestCase { $refvar = 'value'; try { $array = array( 'a', 'b' ); - $object = new StdClass(); + $object = new stdClass(); self::helperThrowAnException( $array, $object, $refvar ); } catch ( Exception $e ) { } diff --git a/tests/phpunit/includes/exception/ThrottledErrorTest.php b/tests/phpunit/includes/exception/ThrottledErrorTest.php index bdb143fa..a1cf84bc 100644 --- a/tests/phpunit/includes/exception/ThrottledErrorTest.php +++ b/tests/phpunit/includes/exception/ThrottledErrorTest.php @@ -6,23 +6,8 @@ */ class ThrottledErrorTest extends MediaWikiTestCase { - protected $wgOut; - - protected function setUp() { - parent::setUp(); - global $wgOut; - $this->wgOut = clone $wgOut; - } - - protected function tearDown() { - parent::tearDown(); - global $wgOut; - $wgOut = $this->wgOut; - } - public function testExceptionSetsStatusCode() { - global $wgOut; - $wgOut = $this->getMockWgOut(); + $this->setMwGlobals( 'wgOut', $this->getMockWgOut() ); try { throw new ThrottledError(); } catch ( ThrottledError $e ) { diff --git a/tests/phpunit/includes/ExternalStoreTest.php b/tests/phpunit/includes/externalstore/ExternalStoreTest.php index 07c2957c..07c2957c 100644 --- a/tests/phpunit/includes/ExternalStoreTest.php +++ b/tests/phpunit/includes/externalstore/ExternalStoreTest.php diff --git a/tests/phpunit/includes/filebackend/FileBackendTest.php b/tests/phpunit/includes/filebackend/FileBackendTest.php index 9558cc7d..bfca75ad 100644 --- a/tests/phpunit/includes/filebackend/FileBackendTest.php +++ b/tests/phpunit/includes/filebackend/FileBackendTest.php @@ -13,14 +13,13 @@ class FileBackendTest extends MediaWikiTestCase { private $multiBackend; /** @var FSFileBackend */ public $singleBackend; - private $filesToPrune = array(); private static $backendToUse; protected function setUp() { global $wgFileBackends; parent::setUp(); $uniqueId = time() . '-' . mt_rand(); - $tmpPrefix = wfTempDir() . '/filebackend-unittest-' . $uniqueId; + $tmpDir = $this->getNewTempDirectory(); if ( $this->getCliArg( 'use-filebackend' ) ) { if ( self::$backendToUse ) { $this->singleBackend = self::$backendToUse; @@ -51,8 +50,8 @@ class FileBackendTest extends MediaWikiTestCase { 'lockManager' => LockManagerGroup::singleton()->get( 'fsLockManager' ), 'wikiId' => wfWikiID(), 'containerPaths' => array( - 'unittest-cont1' => "{$tmpPrefix}-localtesting-cont1", - 'unittest-cont2' => "{$tmpPrefix}-localtesting-cont2" ) + 'unittest-cont1' => "{$tmpDir}/localtesting-cont1", + 'unittest-cont2' => "{$tmpDir}/localtesting-cont2" ) ) ); } $this->multiBackend = new FileBackendMultiWrite( array( @@ -65,21 +64,20 @@ class FileBackendTest extends MediaWikiTestCase { 'name' => 'localmultitesting1', 'class' => 'FSFileBackend', 'containerPaths' => array( - 'unittest-cont1' => "{$tmpPrefix}-localtestingmulti1-cont1", - 'unittest-cont2' => "{$tmpPrefix}-localtestingmulti1-cont2" ), + 'unittest-cont1' => "{$tmpDir}/localtestingmulti1-cont1", + 'unittest-cont2' => "{$tmpDir}/localtestingmulti1-cont2" ), 'isMultiMaster' => false ), array( 'name' => 'localmultitesting2', 'class' => 'FSFileBackend', 'containerPaths' => array( - 'unittest-cont1' => "{$tmpPrefix}-localtestingmulti2-cont1", - 'unittest-cont2' => "{$tmpPrefix}-localtestingmulti2-cont2" ), + 'unittest-cont1' => "{$tmpDir}/localtestingmulti2-cont1", + 'unittest-cont2' => "{$tmpDir}/localtestingmulti2-cont2" ), 'isMultiMaster' => true ) ) ) ); - $this->filesToPrune = array(); } private static function baseStorePath() { @@ -214,7 +212,7 @@ class FileBackendTest extends MediaWikiTestCase { * @dataProvider provider_testStore */ public function testStore( $op ) { - $this->filesToPrune[] = $op['src']; + $this->addTmpFiles( $op['src'] ); $this->backend = $this->singleBackend; $this->tearDownFiles(); @@ -224,7 +222,6 @@ class FileBackendTest extends MediaWikiTestCase { $this->backend = $this->multiBackend; $this->tearDownFiles(); $this->doTestStore( $op ); - $this->filesToPrune[] = $op['src']; # avoid file leaking $this->tearDownFiles(); } @@ -275,27 +272,15 @@ class FileBackendTest extends MediaWikiTestCase { $tmpName = TempFSFile::factory( "unittests_", 'txt' )->getPath(); $toPath = self::baseStorePath() . '/unittest-cont1/e/fun/obj1.txt'; $op = array( 'op' => 'store', 'src' => $tmpName, 'dst' => $toPath ); - $cases[] = array( - $op, // operation - $tmpName, // source - $toPath, // dest - ); + $cases[] = array( $op ); $op2 = $op; $op2['overwrite'] = true; - $cases[] = array( - $op2, // operation - $tmpName, // source - $toPath, // dest - ); + $cases[] = array( $op2 ); - $op2 = $op; - $op2['overwriteSame'] = true; - $cases[] = array( - $op2, // operation - $tmpName, // source - $toPath, // dest - ); + $op3 = $op; + $op3['overwriteSame'] = true; + $cases[] = array( $op3 ); return $cases; } @@ -948,18 +933,14 @@ class FileBackendTest extends MediaWikiTestCase { * @dataProvider provider_testConcatenate */ public function testConcatenate( $op, $srcs, $srcsContent, $alreadyExists, $okStatus ) { - $this->filesToPrune[] = $op['dst']; - $this->backend = $this->singleBackend; $this->tearDownFiles(); $this->doTestConcatenate( $op, $srcs, $srcsContent, $alreadyExists, $okStatus ); - $this->filesToPrune[] = $op['dst']; # avoid file leaking $this->tearDownFiles(); $this->backend = $this->multiBackend; $this->tearDownFiles(); $this->doTestConcatenate( $op, $srcs, $srcsContent, $alreadyExists, $okStatus ); - $this->filesToPrune[] = $op['dst']; # avoid file leaking $this->tearDownFiles(); } @@ -983,7 +964,7 @@ class FileBackendTest extends MediaWikiTestCase { $this->assertGoodStatus( $status, "Creation of source files succeeded ($backendName)." ); - $dest = $params['dst']; + $dest = $params['dst'] = $this->getNewTempFile(); if ( $alreadyExists ) { $ok = file_put_contents( $dest, 'blah...blah...waahwaah' ) !== false; $this->assertEquals( true, $ok, @@ -1029,8 +1010,6 @@ class FileBackendTest extends MediaWikiTestCase { public static function provider_testConcatenate() { $cases = array(); - $rand = mt_rand( 0, 2000000000 ) . time(); - $dest = wfTempDir() . "/randomfile!$rand.txt"; $srcs = array( self::baseStorePath() . '/unittest-cont1/e/file1.txt', self::baseStorePath() . '/unittest-cont1/e/file2.txt', @@ -1055,7 +1034,7 @@ class FileBackendTest extends MediaWikiTestCase { 'lkaem;a', 'legma' ); - $params = array( 'srcs' => $srcs, 'dst' => $dest ); + $params = array( 'srcs' => $srcs ); $cases[] = array( $params, // operation @@ -1499,7 +1478,7 @@ class FileBackendTest extends MediaWikiTestCase { $url = $this->backend->getFileHttpUrl( array( 'src' => $source ) ); if ( $url !== null ) { // supported - $data = Http::request( "GET", $url ); + $data = Http::request( "GET", $url, array(), __METHOD__ ); $this->assertEquals( $content, $data, "HTTP GET of URL has right contents ($backendName)." ); } @@ -1761,16 +1740,13 @@ class FileBackendTest extends MediaWikiTestCase { $fileCContents = 'eigna[ogmewt 3qt g3qg flew[ag'; $tmpNameA = TempFSFile::factory( "unittests_", 'txt' )->getPath(); - file_put_contents( $tmpNameA, $fileAContents ); $tmpNameB = TempFSFile::factory( "unittests_", 'txt' )->getPath(); - file_put_contents( $tmpNameB, $fileBContents ); $tmpNameC = TempFSFile::factory( "unittests_", 'txt' )->getPath(); + $this->addTmpFiles( array( $tmpNameA, $tmpNameB, $tmpNameC ) ); + file_put_contents( $tmpNameA, $fileAContents ); + file_put_contents( $tmpNameB, $fileBContents ); file_put_contents( $tmpNameC, $fileCContents ); - $this->filesToPrune[] = $tmpNameA; # avoid file leaking - $this->filesToPrune[] = $tmpNameB; # avoid file leaking - $this->filesToPrune[] = $tmpNameC; # avoid file leaking - $fileA = "$base/unittest-cont1/e/a/b/fileA.txt"; $fileB = "$base/unittest-cont1/e/a/b/fileB.txt"; $fileC = "$base/unittest-cont1/e/a/b/fileC.txt"; @@ -2434,16 +2410,10 @@ class FileBackendTest extends MediaWikiTestCase { } function tearDownFiles() { - foreach ( $this->filesToPrune as $file ) { - if ( is_file( $file ) ) { - unlink( $file ); - } - } $containers = array( 'unittest-cont1', 'unittest-cont2', 'unittest-cont-bad' ); foreach ( $containers as $container ) { $this->deleteFiles( $container ); } - $this->filesToPrune = array(); } private function deleteFiles( $container ) { diff --git a/tests/phpunit/includes/filerepo/StoreBatchTest.php b/tests/phpunit/includes/filerepo/StoreBatchTest.php index 9cc2efbf..86bfe123 100644 --- a/tests/phpunit/includes/filerepo/StoreBatchTest.php +++ b/tests/phpunit/includes/filerepo/StoreBatchTest.php @@ -16,7 +16,7 @@ class StoreBatchTest extends MediaWikiTestCase { parent::setUp(); # Forge a FSRepo object to not have to rely on local wiki settings - $tmpPrefix = wfTempDir() . '/storebatch-test-' . time() . '-' . mt_rand(); + $tmpPrefix = $this->getNewTempDirectory(); if ( $this->getCliArg( 'use-filebackend' ) ) { $name = $this->getCliArg( 'use-filebackend' ); $useConfig = array(); @@ -35,10 +35,10 @@ class StoreBatchTest extends MediaWikiTestCase { 'name' => 'local-testing', 'wikiId' => wfWikiID(), 'containerPaths' => array( - 'unittests-public' => "{$tmpPrefix}-public", - 'unittests-thumb' => "{$tmpPrefix}-thumb", - 'unittests-temp' => "{$tmpPrefix}-temp", - 'unittests-deleted' => "{$tmpPrefix}-deleted", + 'unittests-public' => "{$tmpPrefix}/public", + 'unittests-thumb' => "{$tmpPrefix}/thumb", + 'unittests-temp' => "{$tmpPrefix}/temp", + 'unittests-deleted' => "{$tmpPrefix}/deleted", ) ) ); } @@ -52,13 +52,8 @@ class StoreBatchTest extends MediaWikiTestCase { } protected function tearDown() { - $this->repo->cleanupBatch( $this->createdFiles ); // delete files - foreach ( $this->createdFiles as $tmp ) { // delete dirs - $tmp = $this->repo->resolveVirtualUrl( $tmp ); - while ( $tmp = FileBackend::parentStoragePath( $tmp ) ) { - $this->repo->getBackend()->clean( array( 'dir' => $tmp ) ); - } - } + // Delete files + $this->repo->cleanupBatch( $this->createdFiles ); parent::tearDown(); } diff --git a/tests/phpunit/includes/LocalFileTest.php b/tests/phpunit/includes/filerepo/file/LocalFileTest.php index 5c5052e4..3c5754bf 100644 --- a/tests/phpunit/includes/LocalFileTest.php +++ b/tests/phpunit/includes/filerepo/file/LocalFileTest.php @@ -2,7 +2,6 @@ /** * These tests should work regardless of $wgCapitalLinks - * @group Database * @todo Split tests into providers and test methods */ diff --git a/tests/phpunit/includes/installer/DatabaseUpdaterTest.php b/tests/phpunit/includes/installer/DatabaseUpdaterTest.php new file mode 100644 index 00000000..abff3e68 --- /dev/null +++ b/tests/phpunit/includes/installer/DatabaseUpdaterTest.php @@ -0,0 +1,279 @@ +<?php + +class DatabaseUpdaterTest extends MediaWikiTestCase { + + public function testSetAppliedUpdates() { + $db = new FakeDatabase(); + $dbu = new FakeDatabaseUpdater( $db ); + $dbu->setAppliedUpdates( "test", array() ); + $expected = "updatelist-test-" . time() . "0"; + $actual = $db->lastInsertData['ul_key']; + $this->assertEquals( $expected, $actual, var_export( $db->lastInsertData, true ) ); + $dbu->setAppliedUpdates( "test", array() ); + $expected = "updatelist-test-" . time() . "1"; + $actual = $db->lastInsertData['ul_key']; + $this->assertEquals( $expected, $actual, var_export( $db->lastInsertData, true ) ); + } +} + +class FakeDatabase extends DatabaseBase { + public $lastInsertTable; + public $lastInsertData; + + function __construct() { + } + + function clearFlag( $arg ) { + } + + function setFlag( $arg ) { + } + + public function insert( $table, $a, $fname = __METHOD__, $options = array() ) { + $this->lastInsertTable = $table; + $this->lastInsertData = $a; + } + + /** + * Get the type of the DBMS, as it appears in $wgDBtype. + * + * @return string + */ + function getType() { + // TODO: Implement getType() method. + } + + /** + * Open a connection to the database. Usually aborts on failure + * + * @param string $server Database server host + * @param string $user Database user name + * @param string $password Database user password + * @param string $dbName Database name + * @return bool + * @throws DBConnectionError + */ + function open( $server, $user, $password, $dbName ) { + // TODO: Implement open() method. + } + + /** + * Fetch the next row from the given result object, in object form. + * Fields can be retrieved with $row->fieldname, with fields acting like + * member variables. + * If no more rows are available, false is returned. + * + * @param ResultWrapper|stdClass $res Object as returned from DatabaseBase::query(), etc. + * @return stdClass|bool + * @throws DBUnexpectedError Thrown if the database returns an error + */ + function fetchObject( $res ) { + // TODO: Implement fetchObject() method. + } + + /** + * Fetch the next row from the given result object, in associative array + * form. Fields are retrieved with $row['fieldname']. + * If no more rows are available, false is returned. + * + * @param ResultWrapper $res Result object as returned from DatabaseBase::query(), etc. + * @return array|bool + * @throws DBUnexpectedError Thrown if the database returns an error + */ + function fetchRow( $res ) { + // TODO: Implement fetchRow() method. + } + + /** + * Get the number of rows in a result object + * + * @param mixed $res A SQL result + * @return int + */ + function numRows( $res ) { + // TODO: Implement numRows() method. + } + + /** + * Get the number of fields in a result object + * @see http://www.php.net/mysql_num_fields + * + * @param mixed $res A SQL result + * @return int + */ + function numFields( $res ) { + // TODO: Implement numFields() method. + } + + /** + * Get a field name in a result object + * @see http://www.php.net/mysql_field_name + * + * @param mixed $res A SQL result + * @param int $n + * @return string + */ + function fieldName( $res, $n ) { + // TODO: Implement fieldName() method. + } + + /** + * Get the inserted value of an auto-increment row + * + * The value inserted should be fetched from nextSequenceValue() + * + * Example: + * $id = $dbw->nextSequenceValue( 'page_page_id_seq' ); + * $dbw->insert( 'page', array( 'page_id' => $id ) ); + * $id = $dbw->insertId(); + * + * @return int + */ + function insertId() { + // TODO: Implement insertId() method. + } + + /** + * Change the position of the cursor in a result object + * @see http://www.php.net/mysql_data_seek + * + * @param mixed $res A SQL result + * @param int $row + */ + function dataSeek( $res, $row ) { + // TODO: Implement dataSeek() method. + } + + /** + * Get the last error number + * @see http://www.php.net/mysql_errno + * + * @return int + */ + function lastErrno() { + // TODO: Implement lastErrno() method. + } + + /** + * Get a description of the last error + * @see http://www.php.net/mysql_error + * + * @return string + */ + function lastError() { + // TODO: Implement lastError() method. + } + + /** + * mysql_fetch_field() wrapper + * Returns false if the field doesn't exist + * + * @param string $table Table name + * @param string $field Field name + * + * @return Field + */ + function fieldInfo( $table, $field ) { + // TODO: Implement fieldInfo() method. + } + + /** + * Get information about an index into an object + * @param string $table Table name + * @param string $index Index name + * @param string $fname Calling function name + * @return mixed Database-specific index description class or false if the index does not exist + */ + function indexInfo( $table, $index, $fname = __METHOD__ ) { + // TODO: Implement indexInfo() method. + } + + /** + * Get the number of rows affected by the last write query + * @see http://www.php.net/mysql_affected_rows + * + * @return int + */ + function affectedRows() { + // TODO: Implement affectedRows() method. + } + + /** + * Wrapper for addslashes() + * + * @param string $s String to be slashed. + * @return string Slashed string. + */ + function strencode( $s ) { + // TODO: Implement strencode() method. + } + + /** + * Returns a wikitext link to the DB's website, e.g., + * return "[http://www.mysql.com/ MySQL]"; + * Should at least contain plain text, if for some reason + * your database has no website. + * + * @return string Wikitext of a link to the server software's web site + */ + function getSoftwareLink() { + // TODO: Implement getSoftwareLink() method. + } + + /** + * A string describing the current software version, like from + * mysql_get_server_info(). + * + * @return string Version information from the database server. + */ + function getServerVersion() { + // TODO: Implement getServerVersion() method. + } + + /** + * Closes underlying database connection + * @since 1.20 + * @return bool Whether connection was closed successfully + */ + protected function closeConnection() { + // TODO: Implement closeConnection() method. + } + + /** + * The DBMS-dependent part of query() + * + * @param string $sql SQL query. + * @return ResultWrapper|bool Result object to feed to fetchObject, + * fetchRow, ...; or false on failure + */ + protected function doQuery( $sql ) { + // TODO: Implement doQuery() method. + } +} + +class FakeDatabaseUpdater extends DatabaseUpdater { + function __construct( $db ) { + $this->db = $db; + self::$updateCounter = 0; + } + + /** + * Get an array of updates to perform on the database. Should return a + * multi-dimensional array. The main key is the MediaWiki version (1.12, + * 1.13...) with the values being arrays of updates, identical to how + * updaters.inc did it (for now) + * + * @return array + */ + protected function getCoreUpdateList() { + return array(); + } + + public function canUseNewUpdatelog() { + return true; + } + + public function setAppliedUpdates( $version, $updates = array() ) { + parent::setAppliedUpdates( $version, $updates ); + } +} diff --git a/tests/phpunit/includes/installer/InstallDocFormatterTest.php b/tests/phpunit/includes/installer/InstallDocFormatterTest.php index 064d5185..724f0c88 100644 --- a/tests/phpunit/includes/installer/InstallDocFormatterTest.php +++ b/tests/phpunit/includes/installer/InstallDocFormatterTest.php @@ -34,6 +34,21 @@ class InstallDocFormatterTest extends MediaWikiTestCase { array( ':One indentation', "\tOne indentation", 'Replacing a single \t' ), array( '::Two indentations', "\t\tTwo indentations", 'Replacing 2 x \t' ), + # Transform 'T123' links + array( + '<span class="config-plainlink">[https://phabricator.wikimedia.org/T123 T123]</span>', + 'T123', 'Testing T123 links' ), + array( + 'bug <span class="config-plainlink">[https://phabricator.wikimedia.org/T123 T123]</span>', + 'bug T123', 'Testing bug T123 links' ), + array( + '(<span class="config-plainlink">[https://phabricator.wikimedia.org/T987654 T987654]</span>)', + '(T987654)', 'Testing (T987654) links' ), + + # "Tabc" shouldn't work + array( 'Tfoobar', 'Tfoobar', "Don't match T followed by non-digits" ), + array( 'T!!fakefake!!', 'T!!fakefake!!', "Don't match T followed by non-digits" ), + # Transform 'bug 123' links array( '<span class="config-plainlink">[https://bugzilla.wikimedia.org/123 bug 123]</span>', diff --git a/tests/phpunit/includes/jobqueue/JobQueueTest.php b/tests/phpunit/includes/jobqueue/JobQueueTest.php index 69e40068..ea1a4f63 100644 --- a/tests/phpunit/includes/jobqueue/JobQueueTest.php +++ b/tests/phpunit/includes/jobqueue/JobQueueTest.php @@ -247,8 +247,13 @@ class JobQueueTest extends MediaWikiTestCase { $this->assertNull( $queue->push( $this->newJob( 0, $root1 ) ), "Push worked ($desc)" ); } $queue->deduplicateRootJob( $this->newJob( 0, $root1 ) ); - sleep( 1 ); // roo job timestamp will increase - $root2 = Job::newRootJobParams( "nulljobspam:$id" ); // task ID/timestamp + + $root2 = $root1; + # Add a second to UNIX epoch and format back to TS_MW + $root2_ts = strtotime( $root2['rootJobTimestamp'] ); + $root2_ts++; + $root2['rootJobTimestamp'] = wfTimestamp( TS_MW, $root2_ts ); + $this->assertNotEquals( $root1['rootJobTimestamp'], $root2['rootJobTimestamp'], "Root job signatures have different timestamps." ); for ( $i = 0; $i < 5; ++$i ) { diff --git a/tests/phpunit/includes/jobqueue/JobTest.php b/tests/phpunit/includes/jobqueue/JobTest.php new file mode 100644 index 00000000..93069d2e --- /dev/null +++ b/tests/phpunit/includes/jobqueue/JobTest.php @@ -0,0 +1,67 @@ +<?php + +/** + * @author Adam Shorland + */ +class JobTest extends MediaWikiTestCase { + + /** + * @dataProvider provideTestToString + * + * @param Job $job + * @param string $expected + * + * @covers Job::toString + */ + public function testToString( $job, $expected ) { + $this->assertEquals( $expected, $job->toString() ); + } + + public function provideTestToString() { + $mockToStringObj = $this->getMock( 'stdClass', array( '__toString' ) ); + $mockToStringObj->expects( $this->any() ) + ->method( '__toString' ) + ->will( $this->returnValue( '{STRING_OBJ_VAL}' ) ); + + return array( + array( + $this->getMockJob( false ), + 'someCommand ' + ), + array( + $this->getMockJob( array( 'key' => 'val' ) ), + 'someCommand key=val' + ), + array( + $this->getMockJob( array( 'key' => array( 'inkey' => 'inval' ) ) ), + 'someCommand key={"inkey":"inval"}' + ), + array( + $this->getMockJob( array( 'val1' ) ), + 'someCommand 0=val1' + ), + array( + $this->getMockJob( array( 'val1', 'val2' ) ), + 'someCommand 0=val1 1=val2' + ), + array( + $this->getMockJob( array( new stdClass() ) ), + 'someCommand 0=object(stdClass)' + ), + array( + $this->getMockJob( array( $mockToStringObj ) ), + 'someCommand 0={STRING_OBJ_VAL}' + ), + ); + } + + public function getMockJob( $params ) { + $mock = $this->getMockForAbstractClass( + 'Job', + array( 'someCommand', new Title(), $params ), + 'SomeJob' + ); + return $mock; + } + +} diff --git a/tests/phpunit/includes/json/FormatJsonTest.php b/tests/phpunit/includes/json/FormatJsonTest.php index af68ab03..f0ac6acc 100644 --- a/tests/phpunit/includes/json/FormatJsonTest.php +++ b/tests/phpunit/includes/json/FormatJsonTest.php @@ -169,12 +169,30 @@ class FormatJsonTest extends MediaWikiTestCase { $this->assertEquals( $value, $st->getValue() ); } + /** + * Test data for testParseTryFixing. + * + * Some PHP interpreters use json-c rather than the JSON.org cannonical + * parser to avoid being encumbered by the "shall be used for Good, not + * Evil" clause of the JSON.org parser's license. By default, json-c + * parses in a non-strict mode which allows trailing commas for array and + * object delarations among other things, so our JSON_ERROR_SYNTAX rescue + * block is not always triggered. It however isn't lenient in exactly the + * same ways as our TRY_FIXING mode, so the assertions in this test are + * a bit more complicated than they ideally would be: + * + * Optional third argument: true if json-c parses the value without + * intervention, false otherwise. Defaults to true. + * + * Optional fourth argument: expected cannonical JSON serialization of + * json-c parsed result. Defaults to the second argument's value. + */ public static function provideParseTryFixing() { return array( - array( "[,]", '[]' ), - array( "[ , ]", '[]' ), + array( "[,]", '[]', false ), + array( "[ , ]", '[]', false ), array( "[ , }", false ), - array( '[1],', false ), + array( '[1],', false, true, '[1]' ), array( "[1,]", '[1]' ), array( "[1\n,]", '[1]' ), array( "[1,\n]", '[1]' ), @@ -182,24 +200,44 @@ class FormatJsonTest extends MediaWikiTestCase { array( "[1\n,\n]\n", '[1]' ), array( '["a,",]', '["a,"]' ), array( "[[1,]\n,[2,\n],[3\n,]]", '[[1],[2],[3]]' ), - array( '[[1,],[2,],[3,]]', false ), // I wish we could parse this, but would need quote parsing - array( '[1,,]', false ), + // I wish we could parse this, but would need quote parsing + array( '[[1,],[2,],[3,]]', false, true, '[[1],[2],[3]]' ), + array( '[1,,]', false, false, '[1]' ), ); } /** * @dataProvider provideParseTryFixing * @param string $value - * @param string|bool $expected + * @param string|bool $expected Expected result with strict parser + * @param bool $jsoncParses Will json-c parse this value without TRY_FIXING? + * @param string|bool $expectedJsonc Expected result with lenient parser + * if different from the strict expectation */ - public function testParseTryFixing( $value, $expected ) { + public function testParseTryFixing( + $value, $expected, + $jsoncParses = true, $expectedJsonc = null + ) { + // PHP5 results are always expected to have isGood() === false + $expectedGoodStatus = false; + + // Check to see if json parser allows trailing commas + if ( json_decode( '[1,]' ) !== null ) { + // Use json-c specific expected result if provided + $expected = ( $expectedJsonc === null ) ? $expected : $expectedJsonc; + // If json-c parses the value natively, expect isGood() === true + $expectedGoodStatus = $jsoncParses; + } + $st = FormatJson::parse( $value, FormatJson::TRY_FIXING ); $this->assertType( 'Status', $st ); if ( $expected === false ) { - $this->assertFalse( $st->isOK() ); + $this->assertFalse( $st->isOK(), 'Expected isOK() == false' ); } else { - $this->assertFalse( $st->isGood() ); - $this->assertTrue( $st->isOK() ); + $this->assertSame( $expectedGoodStatus, $st->isGood(), + 'Expected isGood() == ' . ( $expectedGoodStatus ? 'true' : 'false' ) + ); + $this->assertTrue( $st->isOK(), 'Expected isOK == true' ); $val = FormatJson::encode( $st->getValue(), false, FormatJson::ALL_OK ); $this->assertEquals( $expected, $val ); } @@ -222,6 +260,64 @@ class FormatJsonTest extends MediaWikiTestCase { $this->assertFalse( $st->isOK() ); } + public function provideStripComments() { + return array( + array( '{"a":"b"}', '{"a":"b"}' ), + array( "{\"a\":\"b\"}\n", "{\"a\":\"b\"}\n" ), + array( '/*c*/{"c":"b"}', '{"c":"b"}' ), + array( '{"a":"c"}/*c*/', '{"a":"c"}' ), + array( '/*c//d*/{"c":"b"}', '{"c":"b"}' ), + array( '{/*c*/"c":"b"}', '{"c":"b"}' ), + array( "/*\nc\r\n*/{\"c\":\"b\"}", '{"c":"b"}' ), + array( "//c\n{\"c\":\"b\"}", '{"c":"b"}' ), + array( "//c\r\n{\"c\":\"b\"}", '{"c":"b"}' ), + array( '{"a":"c"}//c', '{"a":"c"}' ), + array( "{\"a-c\"://c\n\"b\"}", '{"a-c":"b"}' ), + array( '{"/*a":"b"}', '{"/*a":"b"}' ), + array( '{"a":"//b"}', '{"a":"//b"}' ), + array( '{"a":"b/*c*/"}', '{"a":"b/*c*/"}' ), + array( "{\"\\\"/*a\":\"b\"}", "{\"\\\"/*a\":\"b\"}" ), + array( '', '' ), + array( '/*c', '' ), + array( '//c', '' ), + array( '"http://example.com"', '"http://example.com"' ), + array( "\0", "\0" ), + array( '"Blåbærsyltetøy"', '"Blåbærsyltetøy"' ), + ); + } + + /** + * @covers FormatJson::stripComments + * @dataProvider provideStripComments + * @param string $json + * @param string $expect + */ + public function testStripComments( $json, $expect ) { + $this->assertSame( $expect, FormatJson::stripComments( $json ) ); + } + + public function provideParseStripComments() { + return array( + array( '/* blah */true', true ), + array( "// blah \ntrue", true ), + array( '[ "a" , /* blah */ "b" ]', array( 'a', 'b' ) ), + ); + } + + /** + * @covers FormatJson::parse + * @covers FormatJson::stripComments + * @dataProvider provideParseStripComments + * @param string $json + * @param mixed $expect + */ + public function testParseStripComments( $json, $expect ) { + $st = FormatJson::parse( $json, FormatJson::STRIP_COMMENTS ); + $this->assertType( 'Status', $st ); + $this->assertTrue( $st->isGood() ); + $this->assertEquals( $expect, $st->getValue() ); + } + /** * Generate a set of test cases for a particular combination of encoder options. * diff --git a/tests/phpunit/includes/ArrayUtilsTest.php b/tests/phpunit/includes/libs/ArrayUtilsTest.php index 7bdb1ca4..b5ea7b72 100644 --- a/tests/phpunit/includes/ArrayUtilsTest.php +++ b/tests/phpunit/includes/libs/ArrayUtilsTest.php @@ -5,7 +5,7 @@ * @group Database */ -class ArrayUtilsTest extends MediaWikiTestCase { +class ArrayUtilsTest extends PHPUnit_Framework_TestCase { private $search; /** diff --git a/tests/phpunit/includes/libs/CSSMinTest.php b/tests/phpunit/includes/libs/CSSMinTest.php index 43c50869..6142f967 100644 --- a/tests/phpunit/includes/libs/CSSMinTest.php +++ b/tests/phpunit/includes/libs/CSSMinTest.php @@ -141,15 +141,57 @@ class CSSMinTest extends MediaWikiTestCase { ); } + public static function provideIsRemoteUrl() { + return array( + array( true, 'http://localhost/w/red.gif?123' ), + array( true, 'https://example.org/x.png' ), + array( true, '//example.org/x.y.z/image.png' ), + array( true, '//localhost/styles.css?query=yes' ), + array( true, 'data:image/gif;base64,R0lGODlhAQABAIAAAP8AADAAACwAAAAAAQABAAACAkQBADs=' ), + array( false, 'x.gif' ), + array( false, '/x.gif' ), + array( false, './x.gif' ), + array( false, '../x.gif' ), + ); + } + + /** + * @dataProvider provideIsRemoteUrl + * @cover CSSMin::isRemoteUrl + */ + public function testIsRemoteUrl( $expect, $url ) { + $this->assertEquals( CSSMin::isRemoteUrl( $url ), $expect ); + } + + public static function provideIsLocalUrls() { + return array( + array( false, 'x.gif' ), + array( true, '/x.gif' ), + array( false, './x.gif' ), + array( false, '../x.gif' ), + ); + } + + /** + * @dataProvider provideIsLocalUrls + * @cover CSSMin::isLocalUrl + */ + public function testIsLocalUrl( $expect, $url ) { + $this->assertEquals( CSSMin::isLocalUrl( $url ), $expect ); + } + public static function provideRemapRemappingCases() { // red.gif and green.gif are one-pixel 35-byte GIFs. // large.png is a 35K PNG that should be non-embeddable. // Full paths start with http://localhost/w/. // Timestamps in output are replaced with 'timestamp'. - // data: URIs for red.gif and green.gif + // data: URIs for red.gif, green.gif, circle.svg $red = 'data:image/gif;base64,R0lGODlhAQABAIAAAP8AADAAACwAAAAAAQABAAACAkQBADs='; $green = 'data:image/gif;base64,R0lGODlhAQABAIAAAACAADAAACwAAAAAAQABAAACAkQBADs='; + $svg = 'data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A' + . '%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%228%22%20height%3D' + . '%228%22%3E%0A%3Ccircle%20cx%3D%224%22%20cy%3D%224%22%20r%3D%222%22%2F%3E%0A%3C%2Fsvg%3E%0A'; return array( array( @@ -234,6 +276,11 @@ class CSSMinTest extends MediaWikiTestCase { "foo { background: url(http://localhost/w/large.png?timestamp); }", ), array( + 'SVG files are embedded without base64 encoding and unnecessary IE 6 and 7 fallback', + 'foo { /* @embed */ background: url(circle.svg); }', + "foo { background: url($svg); }", + ), + array( 'Two regular files in one rule', 'foo { background: url(red.gif), url(green.gif); }', 'foo { background: url(http://localhost/w/red.gif?timestamp), ' diff --git a/tests/phpunit/includes/libs/DeferredStringifierTest.php b/tests/phpunit/includes/libs/DeferredStringifierTest.php new file mode 100644 index 00000000..8b7610ae --- /dev/null +++ b/tests/phpunit/includes/libs/DeferredStringifierTest.php @@ -0,0 +1,50 @@ +<?php + +class DeferredStringifierTest extends PHPUnit_Framework_TestCase { + + /** + * @covers DeferredStringifier + * @dataProvider provideToString + */ + public function testToString( $params, $expected ) { + $class = new ReflectionClass( 'DeferredStringifier' ); + $ds = $class->newInstanceArgs( $params ); + $this->assertEquals( $expected, (string)$ds ); + } + + public static function provideToString() { + return array( + // No args + array( + array( + function() { + return 'foo'; + } + ), + 'foo' + ), + // Has args + array( + array( + function( $i ) { + return $i; + }, + 'bar' + ), + 'bar' + ), + ); + } + + /** + * Verify that the callback is not called if + * it is never converted to a string + */ + public function testCallbackNotCalled() { + $ds = new DeferredStringifier( function() { + throw new Exception( 'This should not be reached!' ); + } ); + // No exception was thrown + $this->assertTrue( true ); + } +} diff --git a/tests/phpunit/includes/libs/GenericArrayObjectTest.php b/tests/phpunit/includes/libs/GenericArrayObjectTest.php index 4911f73a..315bc7ed 100644 --- a/tests/phpunit/includes/libs/GenericArrayObjectTest.php +++ b/tests/phpunit/includes/libs/GenericArrayObjectTest.php @@ -24,10 +24,9 @@ * @ingroup Test * @group GenericArrayObject * - * @licence GNU GPL v2+ * @author Jeroen De Dauw < jeroendedauw@gmail.com > */ -abstract class GenericArrayObjectTest extends MediaWikiTestCase { +abstract class GenericArrayObjectTest extends PHPUnit_Framework_TestCase { /** * Returns objects that can serve as elements in the concrete diff --git a/tests/phpunit/includes/libs/HashRingTest.php b/tests/phpunit/includes/libs/HashRingTest.php index 68dfea1f..b51eb3f4 100644 --- a/tests/phpunit/includes/libs/HashRingTest.php +++ b/tests/phpunit/includes/libs/HashRingTest.php @@ -3,7 +3,7 @@ /** * @group HashRing */ -class HashRingTest extends MediaWikiTestCase { +class HashRingTest extends PHPUnit_Framework_TestCase { /** * @covers HashRing */ diff --git a/tests/phpunit/includes/libs/IEUrlExtensionTest.php b/tests/phpunit/includes/libs/IEUrlExtensionTest.php index b7071230..e96953ee 100644 --- a/tests/phpunit/includes/libs/IEUrlExtensionTest.php +++ b/tests/phpunit/includes/libs/IEUrlExtensionTest.php @@ -5,7 +5,7 @@ * @todo tests below for findIE6Extension should be split into... * ...a dataprovider and test method. */ -class IEUrlExtensionTest extends MediaWikiTestCase { +class IEUrlExtensionTest extends PHPUnit_Framework_TestCase { /** * @covers IEUrlExtension::findIE6Extension */ diff --git a/tests/phpunit/includes/libs/IPSetTest.php b/tests/phpunit/includes/libs/IPSetTest.php index d4e5214a..5bbacef4 100644 --- a/tests/phpunit/includes/libs/IPSetTest.php +++ b/tests/phpunit/includes/libs/IPSetTest.php @@ -3,7 +3,7 @@ /** * @group IPSet */ -class IPSetTest extends MediaWikiTestCase { +class IPSetTest extends PHPUnit_Framework_TestCase { /** * Provides test cases for IPSetTest::testIPSet * diff --git a/tests/phpunit/includes/libs/JavaScriptMinifierTest.php b/tests/phpunit/includes/libs/JavaScriptMinifierTest.php index c8795b2e..149a28c1 100644 --- a/tests/phpunit/includes/libs/JavaScriptMinifierTest.php +++ b/tests/phpunit/includes/libs/JavaScriptMinifierTest.php @@ -1,6 +1,6 @@ <?php -class JavaScriptMinifierTest extends MediaWikiTestCase { +class JavaScriptMinifierTest extends PHPUnit_Framework_TestCase { public static function provideCases() { return array( @@ -164,7 +164,7 @@ class JavaScriptMinifierTest extends MediaWikiTestCase { ); } - public static function provideBug32548() { + public static function provideExponentLineBreaking() { return array( array( // This one gets interpreted all together by the prior code; @@ -183,14 +183,13 @@ class JavaScriptMinifierTest extends MediaWikiTestCase { } /** - * @dataProvider provideBug32548 + * @dataProvider provideExponentLineBreaking * @covers JavaScriptMinifier::minify - * @todo give this test a real name explaining what is being tested here */ - public function testBug32548Exponent( $num ) { + public function testExponentLineBreaking( $num ) { // Long line breaking was being incorrectly done between the base and // exponent part of a number, causing a syntax error. The line should - // instead break at the start of the number. + // instead break at the start of the number. (T34548) $prefix = 'var longVarName' . str_repeat( '_', 973 ) . '='; $suffix = ',shortVarName=0;'; diff --git a/tests/phpunit/includes/libs/MWMessagePackTest.php b/tests/phpunit/includes/libs/MWMessagePackTest.php index f80f78df..ec145836 100644 --- a/tests/phpunit/includes/libs/MWMessagePackTest.php +++ b/tests/phpunit/includes/libs/MWMessagePackTest.php @@ -3,7 +3,7 @@ * PHP Unit tests for MWMessagePack * @covers MWMessagePack */ -class MWMessagePackTest extends MediaWikiTestCase { +class MWMessagePackTest extends PHPUnit_Framework_TestCase { /** * Provides test cases for MWMessagePackTest::testMessagePack diff --git a/tests/phpunit/includes/libs/ObjectFactoryTest.php b/tests/phpunit/includes/libs/ObjectFactoryTest.php new file mode 100644 index 00000000..92207325 --- /dev/null +++ b/tests/phpunit/includes/libs/ObjectFactoryTest.php @@ -0,0 +1,60 @@ +<?php +/** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + */ + +class ObjectFactoryTest extends PHPUnit_Framework_TestCase { + + /** + * @covers ObjectFactory::getObjectFromSpec + */ + public function testClosureExpansionDisabled() { + $obj = ObjectFactory::getObjectFromSpec( array( + 'class' => 'ObjectFactoryTest_Fixture', + 'args' => array( function (){ return 'unwrapped'; }, ), + 'closure_expansion' => false, + ) ); + $this->assertInstanceOf( 'Closure', $obj->args[0] ); + $this->assertSame( 'unwrapped', $obj->args[0]() ); + } + + /** + * @covers ObjectFactory::getObjectFromSpec + */ + public function testClosureExpansionEnabled() { + $obj = ObjectFactory::getObjectFromSpec( array( + 'class' => 'ObjectFactoryTest_Fixture', + 'args' => array( function (){ return 'unwrapped'; }, ), + 'closure_expansion' => true, + ) ); + $this->assertInternalType( 'string', $obj->args[0] ); + $this->assertSame( 'unwrapped', $obj->args[0] ); + + $obj = ObjectFactory::getObjectFromSpec( array( + 'class' => 'ObjectFactoryTest_Fixture', + 'args' => array( function (){ return 'unwrapped'; }, ), + ) ); + $this->assertInternalType( 'string', $obj->args[0] ); + $this->assertSame( 'unwrapped', $obj->args[0] ); + } +} + +class ObjectFactoryTest_Fixture { + public $args; + public function __construct( /*...*/ ) { $this->args = func_get_args(); } +} diff --git a/tests/phpunit/includes/libs/ProcessCacheLRUTest.php b/tests/phpunit/includes/libs/ProcessCacheLRUTest.php index 1a8a1e56..43001979 100644 --- a/tests/phpunit/includes/libs/ProcessCacheLRUTest.php +++ b/tests/phpunit/includes/libs/ProcessCacheLRUTest.php @@ -9,20 +9,20 @@ * * @group Cache */ -class ProcessCacheLRUTest extends MediaWikiTestCase { +class ProcessCacheLRUTest extends PHPUnit_Framework_TestCase { /** * Helper to verify emptiness of a cache object. * Compare against an array so we get the cache content difference. */ - function assertCacheEmpty( $cache, $msg = 'Cache should be empty' ) { + protected function assertCacheEmpty( $cache, $msg = 'Cache should be empty' ) { $this->assertAttributeEquals( array(), 'cache', $cache, $msg ); } /** * Helper to fill a cache object passed by reference */ - function fillCache( &$cache, $numEntries ) { + protected function fillCache( &$cache, $numEntries ) { // Fill cache with three values for ( $i = 1; $i <= $numEntries; $i++ ) { $cache->set( "cache-key-$i", "prop-$i", "value-$i" ); @@ -33,17 +33,17 @@ class ProcessCacheLRUTest extends MediaWikiTestCase { * Generates an array of what would be expected in cache for a given cache * size and a number of entries filled in sequentially */ - function getExpectedCache( $cacheMaxEntries, $entryToFill ) { + protected function getExpectedCache( $cacheMaxEntries, $entryToFill ) { $expected = array(); if ( $entryToFill === 0 ) { - # The cache is empty! + // The cache is empty! return array(); } elseif ( $entryToFill <= $cacheMaxEntries ) { - # Cache is not fully filled + // Cache is not fully filled $firstKey = 1; } else { - # Cache overflowed + // Cache overflowed $firstKey = 1 + $entryToFill - $cacheMaxEntries; } @@ -62,13 +62,16 @@ class ProcessCacheLRUTest extends MediaWikiTestCase { public function testPhpUnitArrayEquality() { $one = array( 'A' => 1, 'B' => 2 ); $two = array( 'B' => 2, 'A' => 1 ); - $this->assertEquals( $one, $two ); // == - $this->assertNotSame( $one, $two ); // === + // == + $this->assertEquals( $one, $two ); + // === + $this->assertNotSame( $one, $two ); } /** * @dataProvider provideInvalidConstructorArg * @expectedException UnexpectedValueException + * @covers ProcessCacheLRU::__construct */ public function testConstructorGivenInvalidValue( $maxSize ) { new ProcessCacheLRUTestable( $maxSize ); @@ -88,6 +91,11 @@ class ProcessCacheLRUTest extends MediaWikiTestCase { ); } + /** + * @covers ProcessCacheLRU::get + * @covers ProcessCacheLRU::set + * @covers ProcessCacheLRU::het + */ public function testAddAndGetAKey() { $oneCache = new ProcessCacheLRUTestable( 1 ); $this->assertCacheEmpty( $oneCache ); @@ -99,6 +107,10 @@ class ProcessCacheLRUTest extends MediaWikiTestCase { $this->assertEquals( 'value1', $oneCache->get( 'cache-key', 'prop1' ) ); } + /** + * @covers ProcessCacheLRU::set + * @covers ProcessCacheLRU::get + */ public function testDeleteOldKey() { $oneCache = new ProcessCacheLRUTestable( 1 ); $this->assertCacheEmpty( $oneCache ); @@ -113,6 +125,7 @@ class ProcessCacheLRUTest extends MediaWikiTestCase { * a sequence of always different cache-keys. Meant to verify we correclty * delete the older key. * + * @covers ProcessCacheLRU::set * @dataProvider provideCacheFilling * @param int $cacheMaxEntries Maximum entry the created cache will hold * @param int $entryToFill Number of entries to insert in the created cache. @@ -136,14 +149,18 @@ class ProcessCacheLRUTest extends MediaWikiTestCase { return array( array( 1, 0 ), array( 1, 1 ), - array( 1, 2 ), # overflow - array( 5, 33 ), # overflow + // overflow + array( 1, 2 ), + // overflow + array( 5, 33 ), ); } /** * Create a cache with only one remaining entry then update * the first inserted entry. Should bump it to the top. + * + * @covers ProcessCacheLRU::set */ public function testReplaceExistingKeyShouldBumpEntryToTop() { $maxEntries = 3; @@ -164,6 +181,11 @@ class ProcessCacheLRUTest extends MediaWikiTestCase { ); } + /** + * @covers ProcessCacheLRU::get + * @covers ProcessCacheLRU::set + * @covers ProcessCacheLRU::het + */ public function testRecentlyAccessedKeyStickIn() { $cache = new ProcessCacheLRUTestable( 2 ); $cache->set( 'first', 'prop1', 'value1' ); @@ -182,6 +204,9 @@ class ProcessCacheLRUTest extends MediaWikiTestCase { * filled entry. * Given a cache having 1,2,3 as key, updating 2 should bump 2 to * the top of the queue with the new value: 1,3,2* (* = updated). + * + * @covers ProcessCacheLRU::set + * @covers ProcessCacheLRU::get */ public function testReplaceExistingKeyInAFullCacheShouldBumpToTop() { $maxEntries = 3; @@ -204,6 +229,9 @@ class ProcessCacheLRUTest extends MediaWikiTestCase { ); } + /** + * @covers ProcessCacheLRU::set + */ public function testBumpExistingKeyToTop() { $cache = new ProcessCacheLRUTestable( 3 ); $this->fillCache( $cache, 3 ); diff --git a/tests/phpunit/includes/libs/RunningStatTest.php b/tests/phpunit/includes/libs/RunningStatTest.php index dc5db82c..edfaf162 100644 --- a/tests/phpunit/includes/libs/RunningStatTest.php +++ b/tests/phpunit/includes/libs/RunningStatTest.php @@ -3,7 +3,7 @@ * PHP Unit tests for RunningStat class. * @covers RunningStat */ -class RunningStatTest extends MediaWikiTestCase { +class RunningStatTest extends PHPUnit_Framework_TestCase { public $points = array( 49.7168, 74.3804, 7.0115, 96.5769, 34.9458, diff --git a/tests/phpunit/includes/utils/StringUtilsTest.php b/tests/phpunit/includes/libs/StringUtilsTest.php index 0fdb8e15..7c24fae6 100644 --- a/tests/phpunit/includes/utils/StringUtilsTest.php +++ b/tests/phpunit/includes/libs/StringUtilsTest.php @@ -1,6 +1,6 @@ <?php -class StringUtilsTest extends MediaWikiTestCase { +class StringUtilsTest extends PHPUnit_Framework_TestCase { /** * This tests StringUtils::isUtf8 whenever we have the mbstring extension diff --git a/tests/phpunit/includes/libs/XhprofTest.php b/tests/phpunit/includes/libs/XhprofTest.php new file mode 100644 index 00000000..2440fc08 --- /dev/null +++ b/tests/phpunit/includes/libs/XhprofTest.php @@ -0,0 +1,320 @@ +<?php +/** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + */ + +/** + * @uses Xhprof + * @uses AutoLoader + * @author Bryan Davis <bd808@wikimedia.org> + * @copyright © 2014 Bryan Davis and Wikimedia Foundation. + * @since 1.25 + */ +class XhprofTest extends PHPUnit_Framework_TestCase { + + public function setUp() { + if ( !function_exists( 'xhprof_enable' ) ) { + $this->markTestSkipped( 'No xhprof support detected.' ); + } + } + + /** + * @covers Xhprof::splitKey + * @dataProvider provideSplitKey + */ + public function testSplitKey( $key, $expect ) { + $this->assertSame( $expect, Xhprof::splitKey( $key ) ); + } + + public function provideSplitKey() { + return array( + array( 'main()', array( null, 'main()' ) ), + array( 'foo==>bar', array( 'foo', 'bar' ) ), + array( 'bar@1==>bar@2', array( 'bar@1', 'bar@2' ) ), + array( 'foo==>bar==>baz', array( 'foo', 'bar==>baz' ) ), + array( '==>bar', array( '', 'bar' ) ), + array( '', array( null, '' ) ), + ); + } + + /** + * @covers Xhprof::__construct + * @covers Xhprof::stop + * @covers Xhprof::getRawData + * @dataProvider provideRawData + */ + public function testRawData( $flags, $keys ) { + $xhprof = new Xhprof( array( 'flags' => $flags ) ); + $raw = $xhprof->getRawData(); + $this->assertArrayHasKey( 'main()', $raw ); + foreach ( $keys as $key ) { + $this->assertArrayHasKey( $key, $raw['main()'] ); + } + } + + public function provideRawData() { + $tests = array( + array( 0, array( 'ct', 'wt' ) ), + ); + + if ( defined( 'XHPROF_FLAGS_CPU' ) && defined( 'XHPROF_FLAGS_CPU' ) ) { + $tests[] = array( XHPROF_FLAGS_MEMORY, array( + 'ct', 'wt', 'mu', 'pmu', + ) ); + $tests[] = array( XHPROF_FLAGS_CPU, array( + 'ct', 'wt', 'cpu', + ) ); + $tests[] = array( XHPROF_FLAGS_MEMORY | XHPROF_FLAGS_CPU, array( + 'ct', 'wt', 'mu', 'pmu', 'cpu', + ) ); + } + + return $tests; + } + + /** + * @covers Xhprof::pruneData + */ + public function testInclude() { + $xhprof = $this->getXhprofFixture( array( + 'include' => array( 'main()' ), + ) ); + $raw = $xhprof->getRawData(); + $this->assertArrayHasKey( 'main()', $raw ); + $this->assertArrayHasKey( 'main()==>foo', $raw ); + $this->assertArrayHasKey( 'main()==>xhprof_disable', $raw ); + $this->assertSame( 3, count( $raw ) ); + } + + /** + * Validate the structure of data returned by + * Xhprof::getInclusiveMetrics(). This acts as a guard against unexpected + * structural changes to the returned data in lieu of using a more heavy + * weight typed response object. + * + * @covers Xhprof::getInclusiveMetrics + */ + public function testInclusiveMetricsStructure() { + $metricStruct = array( + 'ct' => 'int', + 'wt' => 'array', + 'cpu' => 'array', + 'mu' => 'array', + 'pmu' => 'array', + ); + $statStruct = array( + 'total' => 'numeric', + 'min' => 'numeric', + 'mean' => 'numeric', + 'max' => 'numeric', + 'variance' => 'numeric', + 'percent' => 'numeric', + ); + + $xhprof = $this->getXhprofFixture(); + $metrics = $xhprof->getInclusiveMetrics(); + + foreach ( $metrics as $name => $metric ) { + $this->assertArrayStructure( $metricStruct, $metric ); + + foreach ( $metricStruct as $key => $type ) { + if ( $type === 'array' ) { + $this->assertArrayStructure( $statStruct, $metric[$key] ); + if ( $name === 'main()' ) { + $this->assertEquals( 100, $metric[$key]['percent'] ); + } + } + } + } + } + + /** + * Validate the structure of data returned by + * Xhprof::getCompleteMetrics(). This acts as a guard against unexpected + * structural changes to the returned data in lieu of using a more heavy + * weight typed response object. + * + * @covers Xhprof::getCompleteMetrics + */ + public function testCompleteMetricsStructure() { + $metricStruct = array( + 'ct' => 'int', + 'wt' => 'array', + 'cpu' => 'array', + 'mu' => 'array', + 'pmu' => 'array', + 'calls' => 'array', + 'subcalls' => 'array', + ); + $statsMetrics = array( 'wt', 'cpu', 'mu', 'pmu' ); + $statStruct = array( + 'total' => 'numeric', + 'min' => 'numeric', + 'mean' => 'numeric', + 'max' => 'numeric', + 'variance' => 'numeric', + 'percent' => 'numeric', + 'exclusive' => 'numeric', + ); + + $xhprof = $this->getXhprofFixture(); + $metrics = $xhprof->getCompleteMetrics(); + + foreach ( $metrics as $name => $metric ) { + $this->assertArrayStructure( $metricStruct, $metric, $name ); + + foreach ( $metricStruct as $key => $type ) { + if ( in_array( $key, $statsMetrics ) ) { + $this->assertArrayStructure( + $statStruct, $metric[$key], $key + ); + $this->assertLessThanOrEqual( + $metric[$key]['total'], $metric[$key]['exclusive'] + ); + } + } + } + } + + /** + * @covers Xhprof::getCallers + * @covers Xhprof::getCallees + * @uses Xhprof + */ + public function testEdges() { + $xhprof = $this->getXhprofFixture(); + $this->assertSame( array(), $xhprof->getCallers( 'main()' ) ); + $this->assertSame( array( 'foo', 'xhprof_disable' ), + $xhprof->getCallees( 'main()' ) + ); + $this->assertSame( array( 'main()' ), + $xhprof->getCallers( 'foo' ) + ); + $this->assertSame( array(), $xhprof->getCallees( 'strlen' ) ); + } + + /** + * @covers Xhprof::getCriticalPath + * @uses Xhprof + */ + public function testCriticalPath() { + $xhprof = $this->getXhprofFixture(); + $path = $xhprof->getCriticalPath(); + + $last = null; + foreach ( $path as $key => $value ) { + list( $func, $call ) = Xhprof::splitKey( $key ); + $this->assertSame( $last, $func ); + $last = $call; + } + $this->assertSame( $last, 'bar@1' ); + } + + /** + * Get an Xhprof instance that has been primed with a set of known testing + * data. Tests for the Xhprof class should laregly be concerned with + * evaluating the manipulations of the data collected by xhprof rather + * than the data collection process itself. + * + * The returned Xhprof instance primed will be with a data set created by + * running this trivial program using the PECL xhprof implementation: + * @code + * function bar( $x ) { + * if ( $x > 0 ) { + * bar($x - 1); + * } + * } + * function foo() { + * for ( $idx = 0; $idx < 2; $idx++ ) { + * bar( $idx ); + * $x = strlen( 'abc' ); + * } + * } + * xhprof_enable( XHPROF_FLAGS_CPU | XHPROF_FLAGS_MEMORY ); + * foo(); + * $x = xhprof_disable(); + * var_export( $x ); + * @endcode + * + * @return Xhprof + */ + protected function getXhprofFixture( array $opts = array() ) { + $xhprof = new Xhprof( $opts ); + $xhprof->loadRawData( array ( + 'foo==>bar' => array ( + 'ct' => 2, + 'wt' => 57, + 'cpu' => 92, + 'mu' => 1896, + 'pmu' => 0, + ), + 'foo==>strlen' => array ( + 'ct' => 2, + 'wt' => 21, + 'cpu' => 141, + 'mu' => 752, + 'pmu' => 0, + ), + 'bar==>bar@1' => array ( + 'ct' => 1, + 'wt' => 18, + 'cpu' => 19, + 'mu' => 752, + 'pmu' => 0, + ), + 'main()==>foo' => array ( + 'ct' => 1, + 'wt' => 304, + 'cpu' => 307, + 'mu' => 4008, + 'pmu' => 0, + ), + 'main()==>xhprof_disable' => array ( + 'ct' => 1, + 'wt' => 8, + 'cpu' => 10, + 'mu' => 768, + 'pmu' => 392, + ), + 'main()' => array ( + 'ct' => 1, + 'wt' => 353, + 'cpu' => 351, + 'mu' => 6112, + 'pmu' => 1424, + ), + ) ); + return $xhprof; + } + + /** + * Assert that the given array has the described structure. + * + * @param array $struct Array of key => type mappings + * @param array $actual Array to check + * @param string $label + */ + protected function assertArrayStructure( $struct, $actual, $label = null ) { + $this->assertInternalType( 'array', $actual, $label ); + $this->assertCount( count($struct), $actual, $label ); + foreach ( $struct as $key => $type ) { + $this->assertArrayHasKey( $key, $actual ); + $this->assertInternalType( $type, $actual[$key] ); + } + } +} diff --git a/tests/phpunit/includes/XmlTypeCheckTest.php b/tests/phpunit/includes/libs/XmlTypeCheckTest.php index 6ad97fd4..f0ba934e 100644 --- a/tests/phpunit/includes/XmlTypeCheckTest.php +++ b/tests/phpunit/includes/libs/XmlTypeCheckTest.php @@ -5,7 +5,7 @@ * @group Xml * @covers XMLTypeCheck */ -class XmlTypeCheckTest extends MediaWikiTestCase { +class XmlTypeCheckTest extends PHPUnit_Framework_TestCase { const WELL_FORMED_XML = "<root><child /></root>"; const MAL_FORMED_XML = "<root><child /></error>"; const XML_WITH_PIH = '<?xml version="1.0"?><?xml-stylesheet type="text/xsl" href="/w/index.php"?><svg><child /></svg>'; diff --git a/tests/phpunit/includes/libs/composer/ComposerJsonTest.php b/tests/phpunit/includes/libs/composer/ComposerJsonTest.php new file mode 100644 index 00000000..0c58b65a --- /dev/null +++ b/tests/phpunit/includes/libs/composer/ComposerJsonTest.php @@ -0,0 +1,57 @@ +<?php + +class ComposerJsonTest extends MediaWikiTestCase { + + private $json, $json2; + + public function setUp() { + parent::setUp(); + global $IP; + $this->json = "$IP/tests/phpunit/data/composer/composer.json"; + $this->json2 = "$IP/tests/phpunit/data/composer/new-composer.json"; + } + + public static function provideGetHash() { + return array( + array( 'json', 'cc6e7fc565b246cb30b0cac103a2b31e' ), + array( 'json2', '19921dd1fc457f1b00561da932432001' ), + ); + } + + /** + * @dataProvider provideGetHash + * @covers ComposerJson::getHash + */ + public function testIsHashUpToDate( $file, $expected ) { + $json = new ComposerJson( $this->$file ); + $this->assertEquals( $expected, $json->getHash() ); + } + + /** + * @covers ComposerJson::getRequiredDependencies + */ + public function testGetRequiredDependencies() { + $json = new ComposerJson( $this->json ); + $this->assertArrayEquals( array( + 'cdb/cdb' => '1.0.0', + 'cssjanus/cssjanus' => '1.1.1', + 'leafo/lessphp' => '0.5.0', + 'psr/log' => '1.0.0', + ), $json->getRequiredDependencies(), false, true ); + } + + public static function provideNormalizeVersion() { + return array( + array( 'v1.0.0', '1.0.0' ), + array( '0.0.5', '0.0.5' ), + ); + } + + /** + * @dataProvider provideNormalizeVersion + * @covers ComposerJson::normalizeVersion + */ + public function testNormalizeVersion( $input, $expected ) { + $this->assertEquals( $expected, ComposerJson::normalizeVersion( $input ) ); + } +} diff --git a/tests/phpunit/includes/libs/composer/ComposerLockTest.php b/tests/phpunit/includes/libs/composer/ComposerLockTest.php new file mode 100644 index 00000000..b5fd5f6e --- /dev/null +++ b/tests/phpunit/includes/libs/composer/ComposerLockTest.php @@ -0,0 +1,62 @@ +<?php + +class ComposerLockTest extends MediaWikiTestCase { + + private $lock; + + public function setUp() { + parent::setUp(); + global $IP; + $this->lock = "$IP/tests/phpunit/data/composer/composer.lock"; + } + + /** + * @covers ComposerLock::getHash + */ + public function testGetHash() { + $lock = new ComposerLock( $this->lock ); + $this->assertEquals( 'a3bb80b0ac4c4a31e52574d48c032923', $lock->getHash() ); + } + + /** + * @covers ComposerLock::getInstalledDependencies + */ + public function testGetInstalledDependencies() { + $lock = new ComposerLock( $this->lock ); + $this->assertArrayEquals( array( + 'wikimedia/cdb' => array( + 'version' => '1.0.1', + 'type' => 'library', + ), + 'cssjanus/cssjanus' => array( + 'version' => '1.1.1', + 'type' => 'library', + ), + 'leafo/lessphp' => array( + 'version' => '0.5.0', + 'type' => 'library', + ), + 'psr/log' => array( + 'version' => '1.0.0', + 'type' => 'library', + ), + 'oojs/oojs-ui' => array( + 'version' => '0.6.0', + 'type' => 'library', + ), + 'composer/installers' => array( + 'version' => '1.0.19', + 'type' => 'composer-installer', + ), + 'mediawiki/translate' => array( + 'version' => '2014.12', + 'type' => 'mediawiki-extension', + ), + 'mediawiki/universal-language-selector' => array( + 'version' => '2014.12', + 'type' => 'mediawiki-extension', + ), + ), $lock->getInstalledDependencies(), false, true ); + } + +} diff --git a/tests/phpunit/includes/logging/LogFormatterTest.php b/tests/phpunit/includes/logging/LogFormatterTest.php index 6210d098..515990e6 100644 --- a/tests/phpunit/includes/logging/LogFormatterTest.php +++ b/tests/phpunit/includes/logging/LogFormatterTest.php @@ -239,4 +239,57 @@ class LogFormatterTest extends MediaWikiLangTestCase { $this->assertEquals( $comment, $formatter->getComment() ); } + + /** + * @dataProvider provideApiParamFormatting + * @covers LogFormatter::formatParametersForApi + * @covers LogFormatter::formatParameterValueForApi + */ + public function testApiParamFormatting( $key, $value, $expected ) { + $entry = $this->newLogEntry( 'param', array( $key => $value ) ); + $formatter = LogFormatter::newFromEntry( $entry ); + $formatter->setContext( $this->context ); + + ApiResult::setIndexedTagName( $expected, 'param' ); + ApiResult::setArrayType( $expected, 'assoc' ); + + $this->assertEquals( $expected, $formatter->formatParametersForApi() ); + } + + public static function provideApiParamFormatting() { + return array( + array( 0, 'value', array( 'value' ) ), + array( 'named', 'value', array( 'named' => 'value' ) ), + array( '::key', 'value', array( 'key' => 'value' ) ), + array( '4::key', 'value', array( 'key' => 'value' ) ), + array( '4:raw:key', 'value', array( 'key' => 'value' ) ), + array( '4:plain:key', 'value', array( 'key' => 'value' ) ), + array( '4:bool:key', '1', array( 'key' => true ) ), + array( '4:bool:key', '0', array( 'key' => false ) ), + array( '4:number:key', '123', array( 'key' => 123 ) ), + array( '4:number:key', '123.5', array( 'key' => 123.5 ) ), + array( '4:array:key', array(), array( 'key' => array( ApiResult::META_TYPE => 'array' ) ) ), + array( '4:assoc:key', array(), array( 'key' => array( ApiResult::META_TYPE => 'assoc' ) ) ), + array( '4:kvp:key', array(), array( 'key' => array( ApiResult::META_TYPE => 'kvp' ) ) ), + array( '4:timestamp:key', '20150102030405', array( 'key' => '2015-01-02T03:04:05Z' ) ), + array( '4:msg:key', 'parentheses', array( + 'key_key' => 'parentheses', + 'key_text' => wfMessage( 'parentheses' )->text(), + ) ), + array( '4:msg-content:key', 'parentheses', array( + 'key_key' => 'parentheses', + 'key_text' => wfMessage( 'parentheses' )->inContentLanguage()->text(), + ) ), + array( '4:title:key', 'project:foo', array( + 'key_ns' => NS_PROJECT, + 'key_title' => Title::newFromText( 'project:foo' )->getFullText(), + ) ), + array( '4:title-link:key', 'project:foo', array( + 'key_ns' => NS_PROJECT, + 'key_title' => Title::newFromText( 'project:foo' )->getFullText(), + ) ), + array( '4:user:key', 'foo', array( 'key' => 'Foo' ) ), + array( '4:user-link:key', 'foo', array( 'key' => 'Foo' ) ), + ); + } } diff --git a/tests/phpunit/includes/mail/MailAddressTest.php b/tests/phpunit/includes/mail/MailAddressTest.php index 2d078120..18d2acdf 100644 --- a/tests/phpunit/includes/mail/MailAddressTest.php +++ b/tests/phpunit/includes/mail/MailAddressTest.php @@ -14,6 +14,9 @@ class MailAddressTest extends MediaWikiTestCase { * @covers MailAddress::newFromUser */ public function testNewFromUser() { + if ( wfIsWindows() ) { + $this->markTestSkipped( 'This test only works on non-Windows platforms' ); + } $user = $this->getMock( 'User' ); $user->expects( $this->any() )->method( 'getName' )->will( $this->returnValue( 'UserName' ) ); $user->expects( $this->any() )->method( 'getEmail' )->will( $this->returnValue( 'foo@bar.baz' ) ); @@ -49,6 +52,7 @@ class MailAddressTest extends MediaWikiTestCase { array( false, 'foo@bar.baz', 'AUserName', 'Some real name', 'AUserName <foo@bar.baz>' ), array( false, 'foo@bar.baz', '', '', 'foo@bar.baz' ), array( true, 'foo@bar.baz', '', '', 'foo@bar.baz' ), + array( true, '', '', '', '' ), ); } @@ -59,5 +63,4 @@ class MailAddressTest extends MediaWikiTestCase { $ma = new MailAddress( 'some@email.com', 'UserName', 'A real name' ); $this->assertEquals( $ma->toString(), (string)$ma ); } - -}
\ No newline at end of file +} diff --git a/tests/phpunit/includes/media/BitmapScalingTest.php b/tests/phpunit/includes/media/BitmapScalingTest.php index 1972c969..e4415ece 100644 --- a/tests/phpunit/includes/media/BitmapScalingTest.php +++ b/tests/phpunit/includes/media/BitmapScalingTest.php @@ -113,7 +113,7 @@ class BitmapScalingTest extends MediaWikiTestCase { $file = new FakeDimensionFile( array( 4000, 4000 ) ); $handler = new BitmapHandler; $params = array( 'width' => '3700' ); // Still bigger than max size. - $this->assertEquals( 'TransformParameterError', + $this->assertEquals( 'TransformTooBigImageAreaError', get_class( $handler->doTransform( $file, 'dummy path', '', $params ) ) ); } @@ -125,7 +125,7 @@ class BitmapScalingTest extends MediaWikiTestCase { $file->mustRender = true; $handler = new BitmapHandler; $params = array( 'width' => '5000' ); // Still bigger than max size. - $this->assertEquals( 'TransformParameterError', + $this->assertEquals( 'TransformTooBigImageAreaError', get_class( $handler->doTransform( $file, 'dummy path', '', $params ) ) ); } diff --git a/tests/phpunit/includes/media/FormatMetadataTest.php b/tests/phpunit/includes/media/FormatMetadataTest.php index 002e2cb9..54758f94 100644 --- a/tests/phpunit/includes/media/FormatMetadataTest.php +++ b/tests/phpunit/includes/media/FormatMetadataTest.php @@ -68,4 +68,36 @@ class FormatMetadataTest extends MediaWikiMediaTestCase { // TODO: more test cases ); } + + /** + * @param mixed $input + * @param mixed $output + * @dataProvider provideResolveMultivalueValue + * @covers FormatMetadata::resolveMultivalueValue + */ + public function testResolveMultivalueValue( $input, $output ) { + $formatMetadata = new FormatMetadata(); + $class = new ReflectionClass( 'FormatMetadata' ); + $method = $class->getMethod( 'resolveMultivalueValue' ); + $method->setAccessible( true ); + $actualInput = $method->invoke( $formatMetadata, $input ); + $this->assertEquals( $output, $actualInput ); + } + + public function provideResolveMultivalueValue() { + return array( + 'nonArray' => array( 'foo', 'foo' ), + 'multiValue' => array( array( 'first', 'second', 'third', '_type' => 'ol' ), 'first' ), + 'noType' => array( array( 'first', 'second', 'third' ), 'first' ), + 'typeFirst' => array( array( '_type' => 'ol', 'first', 'second', 'third' ), 'first' ), + 'multilang' => array( + array( 'en' => 'first', 'de' => 'Erste', '_type' => 'lang' ), + array( 'en' => 'first', 'de' => 'Erste', '_type' => 'lang' ), + ), + 'multilang-multivalue' => array( + array( 'en' => array( 'first', 'second' ), 'de' => array( 'Erste', 'Zweite' ), '_type' => 'lang' ), + array( 'en' => 'first', 'de' => 'Erste', '_type' => 'lang' ), + ), + ); + } } diff --git a/tests/phpunit/includes/media/MediaHandlerTest.php b/tests/phpunit/includes/media/MediaHandlerTest.php index d8cfcc45..78ea9530 100644 --- a/tests/phpunit/includes/media/MediaHandlerTest.php +++ b/tests/phpunit/includes/media/MediaHandlerTest.php @@ -7,50 +7,62 @@ class MediaHandlerTest extends MediaWikiTestCase { /** * @covers MediaHandler::fitBoxWidth - * @todo split into a dataprovider and test method + * + * @dataProvider provideTestFitBoxWidth */ - public function testFitBoxWidth() { - $vals = array( - array( - 'width' => 50, - 'height' => 50, - 'tests' => array( + public function testFitBoxWidth( $width, $height, $max, $expected ) { + $y = round( $expected * $height / $width ); + $result = MediaHandler::fitBoxWidth( $width, $height, $max ); + $y2 = round( $result * $height / $width ); + $this->assertEquals( $expected, + $result, + "($width, $height, $max) wanted: {$expected}x$y, got: {z$result}x$y2" ); + } + + public static function provideTestFitBoxWidth() { + return array_merge( + static::generateTestFitBoxWidthData( 50, 50, array( 50 => 50, 17 => 17, - 18 => 18 ) ), - array( - 'width' => 366, - 'height' => 300, - 'tests' => array( + 18 => 18 ) + ), + static::generateTestFitBoxWidthData( 366, 300, array( 50 => 61, 17 => 21, - 18 => 22 ) ), - array( - 'width' => 300, - 'height' => 366, - 'tests' => array( + 18 => 22 ) + ), + static::generateTestFitBoxWidthData( 300, 366, array( 50 => 41, 17 => 14, - 18 => 15 ) ), - array( - 'width' => 100, - 'height' => 400, - 'tests' => array( + 18 => 15 ) + ), + static::generateTestFitBoxWidthData( 100, 400, array( 50 => 12, 17 => 4, - 18 => 4 ) ) ); - foreach ( $vals as $row ) { - $tests = $row['tests']; - $height = $row['height']; - $width = $row['width']; - foreach ( $tests as $max => $expected ) { - $y = round( $expected * $height / $width ); - $result = MediaHandler::fitBoxWidth( $width, $height, $max ); - $y2 = round( $result * $height / $width ); - $this->assertEquals( $expected, - $result, - "($width, $height, $max) wanted: {$expected}x$y, got: {$result}x$y2" ); - } + 18 => 4 ) + ) + ); + } + + /** + * Generate single test cases by combining the dimensions and tests contents + * + * It creates: + * [$width, $height, $max, $expected], + * [$width, $height, $max2, $expected2], ... + * out of parameters: + * $width, $height, { $max => $expected, $max2 => $expected2, ... } + * + * @param $width int + * @param $height int + * @param $tests array associative array of $max => $expected values + * @return array + */ + private static function generateTestFitBoxWidthData( $width, $height, $tests ) { + $result = array(); + foreach ( $tests as $max => $expected ) { + $result[] = array( $width, $height, $max, $expected ); } + return $result; } } diff --git a/tests/phpunit/includes/media/SVGMetadataExtractorTest.php b/tests/phpunit/includes/media/SVGMetadataExtractorTest.php index ab33d1c2..0241aec4 100644 --- a/tests/phpunit/includes/media/SVGMetadataExtractorTest.php +++ b/tests/phpunit/includes/media/SVGMetadataExtractorTest.php @@ -6,11 +6,6 @@ */ class SVGMetadataExtractorTest extends MediaWikiTestCase { - protected function setUp() { - parent::setUp(); - AutoLoader::loadClass( 'SVGMetadataExtractorTest' ); - } - /** * @dataProvider provideSvgFiles */ diff --git a/tests/phpunit/includes/normal/CleanUpTest.php b/tests/phpunit/includes/normal/CleanUpTest.php deleted file mode 100644 index f4b469b8..00000000 --- a/tests/phpunit/includes/normal/CleanUpTest.php +++ /dev/null @@ -1,409 +0,0 @@ -<?php -/** - * Tests for UtfNormal::cleanUp() function. - * - * Copyright © 2004 Brion Vibber <brion@pobox.com> - * https://www.mediawiki.org/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * http://www.gnu.org/copyleft/gpl.html - * - * @file - */ - -/** - * Additional tests for UtfNormal::cleanUp() function, inclusion - * regression checks for known problems. - * Requires PHPUnit. - * - * @ingroup UtfNormal - * @group Large - * - * @todo covers tags, will be UtfNormal::cleanUp once the below is resolved - * @todo split me into test methods and providers per the below comment - * - * We ignore code coverage for this test suite until they are rewritten - * to use data providers (bug 46561). - * @codeCoverageIgnore - */ -class CleanUpTest extends MediaWikiTestCase { - /** @todo document */ - public function testAscii() { - $text = 'This is plain ASCII text.'; - $this->assertEquals( $text, UtfNormal::cleanUp( $text ) ); - } - - /** @todo document */ - public function testNull() { - $text = "a \x00 null"; - $expect = "a \xef\xbf\xbd null"; - $this->assertEquals( - bin2hex( $expect ), - bin2hex( UtfNormal::cleanUp( $text ) ) ); - } - - /** @todo document */ - public function testLatin() { - $text = "L'\xc3\xa9cole"; - $this->assertEquals( $text, UtfNormal::cleanUp( $text ) ); - } - - /** @todo document */ - public function testLatinNormal() { - $text = "L'e\xcc\x81cole"; - $expect = "L'\xc3\xa9cole"; - $this->assertEquals( $expect, UtfNormal::cleanUp( $text ) ); - } - - /** - * This test is *very* expensive! - * @todo document - */ - function XtestAllChars() { - $rep = UTF8_REPLACEMENT; - for ( $i = 0x0; $i < UNICODE_MAX; $i++ ) { - $char = codepointToUtf8( $i ); - $clean = UtfNormal::cleanUp( $char ); - $x = sprintf( "%04X", $i ); - - if ( $i % 0x1000 == 0 ) { - echo "U+$x\n"; - } - - if ( $i == 0x0009 || - $i == 0x000a || - $i == 0x000d || - ( $i > 0x001f && $i < UNICODE_SURROGATE_FIRST ) || - ( $i > UNICODE_SURROGATE_LAST && $i < 0xfffe ) || - ( $i > 0xffff && $i <= UNICODE_MAX ) - ) { - if ( isset( UtfNormal::$utfCanonicalComp[$char] ) - || isset( UtfNormal::$utfCanonicalDecomp[$char] ) - ) { - $comp = UtfNormal::NFC( $char ); - $this->assertEquals( - bin2hex( $comp ), - bin2hex( $clean ), - "U+$x should be decomposed" ); - } else { - $this->assertEquals( - bin2hex( $char ), - bin2hex( $clean ), - "U+$x should be intact" ); - } - } else { - $this->assertEquals( bin2hex( $rep ), bin2hex( $clean ), $x ); - } - } - } - - /** @todo document */ - public static function provideAllBytes() { - return array( - array( '', '' ), - array( 'x', '' ), - array( '', 'x' ), - array( 'x', 'x' ), - ); - } - - /** - * @dataProvider provideAllBytes - * @todo document - */ - function testBytes( $head, $tail ) { - for ( $i = 0x0; $i < 256; $i++ ) { - $char = $head . chr( $i ) . $tail; - $clean = UtfNormal::cleanUp( $char ); - $x = sprintf( "%02X", $i ); - - if ( $i == 0x0009 || - $i == 0x000a || - $i == 0x000d || - ( $i > 0x001f && $i < 0x80 ) - ) { - $this->assertEquals( - bin2hex( $char ), - bin2hex( $clean ), - "ASCII byte $x should be intact" ); - if ( $char != $clean ) { - return; - } - } else { - $norm = $head . UTF8_REPLACEMENT . $tail; - $this->assertEquals( - bin2hex( $norm ), - bin2hex( $clean ), - "Forbidden byte $x should be rejected" ); - if ( $norm != $clean ) { - return; - } - } - } - } - - /** - * @dataProvider provideAllBytes - * @todo document - */ - function testDoubleBytes( $head, $tail ) { - for ( $first = 0xc0; $first < 0x100; $first += 2 ) { - for ( $second = 0x80; $second < 0x100; $second += 2 ) { - $char = $head . chr( $first ) . chr( $second ) . $tail; - $clean = UtfNormal::cleanUp( $char ); - $x = sprintf( "%02X,%02X", $first, $second ); - if ( $first > 0xc1 && - $first < 0xe0 && - $second < 0xc0 - ) { - $norm = UtfNormal::NFC( $char ); - $this->assertEquals( - bin2hex( $norm ), - bin2hex( $clean ), - "Pair $x should be intact" ); - if ( $norm != $clean ) { - return; - } - } elseif ( $first > 0xfd || $second > 0xbf ) { - # fe and ff are not legal head bytes -- expect two replacement chars - $norm = $head . UTF8_REPLACEMENT . UTF8_REPLACEMENT . $tail; - $this->assertEquals( - bin2hex( $norm ), - bin2hex( $clean ), - "Forbidden pair $x should be rejected" ); - if ( $norm != $clean ) { - return; - } - } else { - $norm = $head . UTF8_REPLACEMENT . $tail; - $this->assertEquals( - bin2hex( $norm ), - bin2hex( $clean ), - "Forbidden pair $x should be rejected" ); - if ( $norm != $clean ) { - return; - } - } - } - } - } - - /** - * @dataProvider provideAllBytes - * @todo document - */ - function testTripleBytes( $head, $tail ) { - for ( $first = 0xc0; $first < 0x100; $first += 2 ) { - for ( $second = 0x80; $second < 0x100; $second += 2 ) { - #for( $third = 0x80; $third < 0x100; $third++ ) { - for ( $third = 0x80; $third < 0x81; $third++ ) { - $char = $head . chr( $first ) . chr( $second ) . chr( $third ) . $tail; - $clean = UtfNormal::cleanUp( $char ); - $x = sprintf( "%02X,%02X,%02X", $first, $second, $third ); - - if ( $first >= 0xe0 && - $first < 0xf0 && - $second < 0xc0 && - $third < 0xc0 - ) { - if ( $first == 0xe0 && $second < 0xa0 ) { - $this->assertEquals( - bin2hex( $head . UTF8_REPLACEMENT . $tail ), - bin2hex( $clean ), - "Overlong triplet $x should be rejected" ); - } elseif ( $first == 0xed && - ( chr( $first ) . chr( $second ) . chr( $third ) ) >= UTF8_SURROGATE_FIRST - ) { - $this->assertEquals( - bin2hex( $head . UTF8_REPLACEMENT . $tail ), - bin2hex( $clean ), - "Surrogate triplet $x should be rejected" ); - } else { - $this->assertEquals( - bin2hex( UtfNormal::NFC( $char ) ), - bin2hex( $clean ), - "Triplet $x should be intact" ); - } - } elseif ( $first > 0xc1 && $first < 0xe0 && $second < 0xc0 ) { - $this->assertEquals( - bin2hex( UtfNormal::NFC( $head . chr( $first ) . - chr( $second ) ) . UTF8_REPLACEMENT . $tail ), - bin2hex( $clean ), - "Valid 2-byte $x + broken tail" ); - } elseif ( $second > 0xc1 && $second < 0xe0 && $third < 0xc0 ) { - $this->assertEquals( - bin2hex( $head . UTF8_REPLACEMENT . - UtfNormal::NFC( chr( $second ) . chr( $third ) . $tail ) ), - bin2hex( $clean ), - "Broken head + valid 2-byte $x" ); - } elseif ( ( $first > 0xfd || $second > 0xfd ) && - ( ( $second > 0xbf && $third > 0xbf ) || - ( $second < 0xc0 && $third < 0xc0 ) || - ( $second > 0xfd ) || - ( $third > 0xfd ) ) - ) { - # fe and ff are not legal head bytes -- expect three replacement chars - $this->assertEquals( - bin2hex( $head . UTF8_REPLACEMENT . UTF8_REPLACEMENT . UTF8_REPLACEMENT . $tail ), - bin2hex( $clean ), - "Forbidden triplet $x should be rejected" ); - } elseif ( $first > 0xc2 && $second < 0xc0 && $third < 0xc0 ) { - $this->assertEquals( - bin2hex( $head . UTF8_REPLACEMENT . $tail ), - bin2hex( $clean ), - "Forbidden triplet $x should be rejected" ); - } else { - $this->assertEquals( - bin2hex( $head . UTF8_REPLACEMENT . UTF8_REPLACEMENT . $tail ), - bin2hex( $clean ), - "Forbidden triplet $x should be rejected" ); - } - } - } - } - } - - /** @todo document */ - public function testChunkRegression() { - # Check for regression against a chunking bug - $text = "\x46\x55\xb8" . - "\xdc\x96" . - "\xee" . - "\xe7" . - "\x44" . - "\xaa" . - "\x2f\x25"; - $expect = "\x46\x55\xef\xbf\xbd" . - "\xdc\x96" . - "\xef\xbf\xbd" . - "\xef\xbf\xbd" . - "\x44" . - "\xef\xbf\xbd" . - "\x2f\x25"; - - $this->assertEquals( - bin2hex( $expect ), - bin2hex( UtfNormal::cleanUp( $text ) ) ); - } - - /** @todo document */ - public function testInterposeRegression() { - $text = "\x4e\x30" . - "\xb1" . # bad tail - "\x3a" . - "\x92" . # bad tail - "\x62\x3a" . - "\x84" . # bad tail - "\x43" . - "\xc6" . # bad head - "\x3f" . - "\x92" . # bad tail - "\xad" . # bad tail - "\x7d" . - "\xd9\x95"; - - $expect = "\x4e\x30" . - "\xef\xbf\xbd" . - "\x3a" . - "\xef\xbf\xbd" . - "\x62\x3a" . - "\xef\xbf\xbd" . - "\x43" . - "\xef\xbf\xbd" . - "\x3f" . - "\xef\xbf\xbd" . - "\xef\xbf\xbd" . - "\x7d" . - "\xd9\x95"; - - $this->assertEquals( - bin2hex( $expect ), - bin2hex( UtfNormal::cleanUp( $text ) ) ); - } - - /** @todo document */ - public function testOverlongRegression() { - $text = "\x67" . - "\x1a" . # forbidden ascii - "\xea" . # bad head - "\xc1\xa6" . # overlong sequence - "\xad" . # bad tail - "\x1c" . # forbidden ascii - "\xb0" . # bad tail - "\x3c" . - "\x9e"; # bad tail - $expect = "\x67" . - "\xef\xbf\xbd" . - "\xef\xbf\xbd" . - "\xef\xbf\xbd" . - "\xef\xbf\xbd" . - "\xef\xbf\xbd" . - "\xef\xbf\xbd" . - "\x3c" . - "\xef\xbf\xbd"; - $this->assertEquals( - bin2hex( $expect ), - bin2hex( UtfNormal::cleanUp( $text ) ) ); - } - - /** @todo document */ - public function testSurrogateRegression() { - $text = "\xed\xb4\x96" . # surrogate 0xDD16 - "\x83" . # bad tail - "\xb4" . # bad tail - "\xac"; # bad head - $expect = "\xef\xbf\xbd" . - "\xef\xbf\xbd" . - "\xef\xbf\xbd" . - "\xef\xbf\xbd"; - $this->assertEquals( - bin2hex( $expect ), - bin2hex( UtfNormal::cleanUp( $text ) ) ); - } - - /** @todo document */ - public function testBomRegression() { - $text = "\xef\xbf\xbe" . # U+FFFE, illegal char - "\xb2" . # bad tail - "\xef" . # bad head - "\x59"; - $expect = "\xef\xbf\xbd" . - "\xef\xbf\xbd" . - "\xef\xbf\xbd" . - "\x59"; - $this->assertEquals( - bin2hex( $expect ), - bin2hex( UtfNormal::cleanUp( $text ) ) ); - } - - /** @todo document */ - public function testForbiddenRegression() { - $text = "\xef\xbf\xbf"; # U+FFFF, illegal char - $expect = "\xef\xbf\xbd"; - $this->assertEquals( - bin2hex( $expect ), - bin2hex( UtfNormal::cleanUp( $text ) ) ); - } - - /** @todo document */ - public function testHangulRegression() { - $text = "\xed\x9c\xaf" . # Hangul char - "\xe1\x87\x81"; # followed by another final jamo - $expect = $text; # Should *not* change. - $this->assertEquals( - bin2hex( $expect ), - bin2hex( UtfNormal::cleanUp( $text ) ) ); - } -} diff --git a/tests/phpunit/includes/objectcache/BagOStuffTest.php b/tests/phpunit/includes/objectcache/BagOStuffTest.php index 987b6e64..4516bb4e 100644 --- a/tests/phpunit/includes/objectcache/BagOStuffTest.php +++ b/tests/phpunit/includes/objectcache/BagOStuffTest.php @@ -1,8 +1,6 @@ <?php /** - * This class will test BagOStuff. - * - * @author Matthias Mullie <mmullie@wikimedia.org> + * @author Matthias Mullie <mmullie@wikimedia.org> */ class BagOStuffTest extends MediaWikiTestCase { private $cache; @@ -23,6 +21,10 @@ class BagOStuffTest extends MediaWikiTestCase { $this->cache->delete( wfMemcKey( 'test' ) ); } + /** + * @covers BagOStuff::merge + * @covers BagOStuff::mergeViaLock + */ public function testMerge() { $key = wfMemcKey( 'test' ); @@ -100,6 +102,9 @@ class BagOStuffTest extends MediaWikiTestCase { } } + /** + * @covers BagOStuff::add + */ public function testAdd() { $key = wfMemcKey( 'test' ); $this->assertTrue( $this->cache->add( $key, 'test' ) ); @@ -125,6 +130,9 @@ class BagOStuffTest extends MediaWikiTestCase { $this->assertEquals( $expectedValue, $actualValue, 'Value should be 1 after incrementing' ); } + /** + * @covers BagOStuff::getMulti + */ public function testGetMulti() { $value1 = array( 'this' => 'is', 'a' => 'test' ); $value2 = array( 'this' => 'is', 'another' => 'test' ); diff --git a/tests/phpunit/includes/ArticleTablesTest.php b/tests/phpunit/includes/page/ArticleTablesTest.php index 9f2b7a05..9f2b7a05 100644 --- a/tests/phpunit/includes/ArticleTablesTest.php +++ b/tests/phpunit/includes/page/ArticleTablesTest.php diff --git a/tests/phpunit/includes/ArticleTest.php b/tests/phpunit/includes/page/ArticleTest.php index ae069eaf..ae069eaf 100644 --- a/tests/phpunit/includes/ArticleTest.php +++ b/tests/phpunit/includes/page/ArticleTest.php diff --git a/tests/phpunit/includes/ImagePage404Test.php b/tests/phpunit/includes/page/ImagePage404Test.php index 197a2b32..197a2b32 100644 --- a/tests/phpunit/includes/ImagePage404Test.php +++ b/tests/phpunit/includes/page/ImagePage404Test.php diff --git a/tests/phpunit/includes/ImagePageTest.php b/tests/phpunit/includes/page/ImagePageTest.php index 3c255b5f..3c255b5f 100644 --- a/tests/phpunit/includes/ImagePageTest.php +++ b/tests/phpunit/includes/page/ImagePageTest.php diff --git a/tests/phpunit/includes/WikiPageTest.php b/tests/phpunit/includes/page/WikiPageTest.php index 7f7945b8..c011e9a9 100644 --- a/tests/phpunit/includes/WikiPageTest.php +++ b/tests/phpunit/includes/page/WikiPageTest.php @@ -55,8 +55,8 @@ class WikiPageTest extends MediaWikiLangTestCase { } /** - * @param Title $title - * @param string $model + * @param Title|string $title + * @param string|null $model * @return WikiPage */ protected function newPage( $title, $model = null ) { diff --git a/tests/phpunit/includes/WikiPageTestContentHandlerUseDB.php b/tests/phpunit/includes/page/WikiPageTestContentHandlerUseDB.php index 3db76280..3db76280 100644 --- a/tests/phpunit/includes/WikiPageTestContentHandlerUseDB.php +++ b/tests/phpunit/includes/page/WikiPageTestContentHandlerUseDB.php diff --git a/tests/phpunit/includes/parser/NewParserTest.php b/tests/phpunit/includes/parser/NewParserTest.php index 0df52f5e..91aad10c 100644 --- a/tests/phpunit/includes/parser/NewParserTest.php +++ b/tests/phpunit/includes/parser/NewParserTest.php @@ -124,7 +124,7 @@ class NewParserTest extends MediaWikiTestCase { $tmpGlobals['wgFileExtensions'][] = 'svg'; $tmpGlobals['wgSVGConverter'] = 'rsvg'; $tmpGlobals['wgSVGConverters']['rsvg'] = - '$path/rsvg-convert -w $width -h $height $input -o $output'; + '$path/rsvg-convert -w $width -h $height -o $output $input'; if ( $GLOBALS['wgStyleDirectory'] === false ) { $tmpGlobals['wgStyleDirectory'] = "$IP/skins"; @@ -160,9 +160,6 @@ class NewParserTest extends MediaWikiTestCase { $this->djVuSupport = new DjVuSupport(); // Tidy support $this->tidySupport = new TidySupport(); - // We always set 'wgUseTidy' to false when parsing, but certain - // test-running modes still use tidy if available, so ensure - // that the tidy-related options are all set to their defaults. $tmpGlobals['wgUseTidy'] = false; $tmpGlobals['wgAlwaysUseTidy'] = false; $tmpGlobals['wgDebugTidy'] = false; @@ -419,6 +416,7 @@ class NewParserTest extends MediaWikiTestCase { 'wgMathDirectory' => $uploadDir . '/math', 'wgDefaultLanguageVariant' => $variant, 'wgLinkHolderBatchSize' => $linkHolderBatchSize, + 'wgUseTidy' => isset( $opts['tidy'] ), ); if ( $config ) { @@ -434,7 +432,7 @@ class NewParserTest extends MediaWikiTestCase { $this->savedGlobals = array(); /** @since 1.20 */ - wfRunHooks( 'ParserTestGlobals', array( &$settings ) ); + Hooks::run( 'ParserTestGlobals', array( &$settings ) ); $langObj = Language::factory( $lang ); $settings['wgContLang'] = $langObj; @@ -480,16 +478,16 @@ class NewParserTest extends MediaWikiTestCase { */ protected function getUploadDir() { if ( $this->keepUploads ) { + // Don't use getNewTempDirectory() as this is meant to persist $dir = wfTempDir() . '/mwParser-images'; if ( is_dir( $dir ) ) { return $dir; } } else { - $dir = wfTempDir() . "/mwParser-" . mt_rand() . "-images"; + $dir = $this->getNewTempDirectory(); } - // wfDebug( "Creating upload directory $dir\n" ); if ( file_exists( $dir ) ) { wfDebug( "Already exists!\n" ); @@ -727,12 +725,21 @@ class NewParserTest extends MediaWikiTestCase { . "Current configuration is:\n\$wgTexvc = '$wgTexvc'" ); } } + if ( isset( $opts['djvu'] ) ) { if ( !$this->djVuSupport->isEnabled() ) { $this->markTestSkipped( "SKIPPED: djvu binaries do not exist or are not executable.\n" ); } } + if ( isset( $opts['tidy'] ) ) { + if ( !$this->tidySupport->isEnabled() ) { + $this->markTestSkipped( "SKIPPED: tidy extension is not installed.\n" ); + } else { + $options->setTidy( true ); + } + } + if ( isset( $opts['pst'] ) ) { $out = $parser->preSaveTransform( $input, $title, $user, $options ); } elseif ( isset( $opts['msg'] ) ) { @@ -753,12 +760,7 @@ class NewParserTest extends MediaWikiTestCase { $output->setTOCEnabled( !isset( $opts['notoc'] ) ); $out = $output->getText(); if ( isset( $opts['tidy'] ) ) { - if ( !$this->tidySupport->isEnabled() ) { - $this->markTestSkipped( "SKIPPED: tidy extension is not installed.\n" ); - } else { - $out = MWTidy::tidy( $out ); - $out = preg_replace( '/\s+$/', '', $out ); - } + $out = preg_replace( '/\s+$/', '', $out ); } if ( isset( $opts['showtitle'] ) ) { @@ -769,6 +771,14 @@ class NewParserTest extends MediaWikiTestCase { $out = "$title\n$out"; } + if ( isset( $opts['showindicators'] ) ) { + $indicators = ''; + foreach ( $output->getIndicators() as $id => $content ) { + $indicators .= "$id=$content\n"; + } + $out = $indicators . $out; + } + if ( isset( $opts['ill'] ) ) { $out = implode( ' ', $output->getLanguageLinks() ); } elseif ( isset( $opts['cat'] ) ) { @@ -939,7 +949,7 @@ class NewParserTest extends MediaWikiTestCase { $class = $wgParserConf['class']; $parser = new $class( array( 'preprocessorClass' => $preprocessor ) + $wgParserConf ); - wfRunHooks( 'ParserTestParser', array( &$parser ) ); + Hooks::run( 'ParserTestParser', array( &$parser ) ); return $parser; } diff --git a/tests/phpunit/includes/parser/ParserOutputTest.php b/tests/phpunit/includes/parser/ParserOutputTest.php index c024cee5..e660e096 100644 --- a/tests/phpunit/includes/parser/ParserOutputTest.php +++ b/tests/phpunit/includes/parser/ParserOutputTest.php @@ -1,5 +1,9 @@ <?php +/** + * @group Database + * ^--- trigger DB shadowing because we are using Title magic + */ class ParserOutputTest extends MediaWikiTestCase { public static function provideIsLinkInternal() { @@ -84,4 +88,5 @@ class ParserOutputTest extends MediaWikiTestCase { $this->assertEquals( $po->getProperty( 'foo' ), false ); $this->assertArrayNotHasKey( 'foo', $properties ); } + } diff --git a/tests/phpunit/includes/parser/TagHooksTest.php b/tests/phpunit/includes/parser/TagHooksTest.php index e3c4cc84..251da471 100644 --- a/tests/phpunit/includes/parser/TagHooksTest.php +++ b/tests/phpunit/includes/parser/TagHooksTest.php @@ -89,7 +89,7 @@ class TagHookTest extends MediaWikiTestCase { global $wgParserConf, $wgContLang; $parser = new Parser( $wgParserConf ); - $parser->setFunctionTagHook( $tag, array( $this, 'functionTagCallback' ), SFH_OBJECT_ARGS ); + $parser->setFunctionTagHook( $tag, array( $this, 'functionTagCallback' ), Parser::SFH_OBJECT_ARGS ); $parser->parse( "Foo<$tag>Bar</$tag>Baz", Title::newFromText( 'Test' ), diff --git a/tests/phpunit/includes/PasswordTest.php b/tests/phpunit/includes/password/PasswordTest.php index ceb794b5..5ad8aca6 100644 --- a/tests/phpunit/includes/PasswordTest.php +++ b/tests/phpunit/includes/password/PasswordTest.php @@ -30,4 +30,10 @@ class PasswordTest extends MediaWikiTestCase { $this->assertFalse( $invalid1->equals( $invalid2 ) ); } + + public function testInvalidPlaintext() { + $invalid = User::getPasswordFactory()->newFromPlaintext( null ); + + $this->assertInstanceOf( 'InvalidPassword', $invalid ); + } } diff --git a/tests/phpunit/includes/password/PasswordTestCase.php b/tests/phpunit/includes/password/PasswordTestCase.php index ef16f1c4..9a142cbc 100644 --- a/tests/phpunit/includes/password/PasswordTestCase.php +++ b/tests/phpunit/includes/password/PasswordTestCase.php @@ -49,10 +49,13 @@ abstract class PasswordTestCase extends MediaWikiTestCase { * An array of tests in the form of (bool, string, string), where the first * element is whether the second parameter (a password hash) and the third * parameter (a password) should match. - * * @return array + * @throws MWException + * @abstract */ - abstract public static function providePasswordTests(); + public static function providePasswordTests() { + throw new MWException( "Not implemented" ); + } /** * @dataProvider providePasswordTests diff --git a/tests/phpunit/includes/registration/ExtensionProcessorTest.php b/tests/phpunit/includes/registration/ExtensionProcessorTest.php new file mode 100644 index 00000000..8715711f --- /dev/null +++ b/tests/phpunit/includes/registration/ExtensionProcessorTest.php @@ -0,0 +1,374 @@ +<?php + +class ExtensionProcessorTest extends MediaWikiTestCase { + + private $dir; + + public function setUp() { + parent::setUp(); + $this->dir = __DIR__ . '/FooBar/extension.json'; + } + + /** + * 'name' is absolutely required + * + * @var array + */ + static $default = array( + 'name' => 'FooBar', + ); + + /** + * @covers ExtensionProcessor::extractInfo + */ + public function testExtractInfo() { + // Test that attributes that begin with @ are ignored + $processor = new ExtensionProcessor(); + $processor->extractInfo( $this->dir, self::$default + array( + '@metadata' => array( 'foobarbaz' ), + 'AnAttribute' => array( 'omg' ), + 'AutoloadClasses' => array( 'FooBar' => 'includes/FooBar.php' ), + ) ); + + $extracted = $processor->getExtractedInfo(); + $attributes = $extracted['attributes']; + $this->assertArrayHasKey( 'AnAttribute', $attributes ); + $this->assertArrayNotHasKey( '@metadata', $attributes ); + $this->assertArrayNotHasKey( 'AutoloadClasses', $attributes ); + } + + public static function provideRegisterHooks() { + return array( + // No hooks + array( + array(), + self::$default, + array(), + ), + // No current hooks, adding one for "FooBaz" + array( + array(), + array( 'Hooks' => array( 'FooBaz' => 'FooBazCallback' ) ) + self::$default, + array( 'FooBaz' => array( 'FooBazCallback' ) ), + ), + // Hook for "FooBaz", adding another one + array( + array( 'FooBaz' => array( 'PriorCallback' ) ), + array( 'Hooks' => array( 'FooBaz' => 'FooBazCallback' ) ) + self::$default, + array( 'FooBaz' => array( 'PriorCallback', 'FooBazCallback' ) ), + ), + // Hook for "BarBaz", adding one for "FooBaz" + array( + array( 'BarBaz' => array( 'BarBazCallback' ) ), + array( 'Hooks' => array( 'FooBaz' => 'FooBazCallback' ) ) + self::$default, + array( + 'BarBaz' => array( 'BarBazCallback' ), + 'FooBaz' => array( 'FooBazCallback' ), + ), + ), + ); + } + + /** + * @covers ExtensionProcessor::extractHooks + * @dataProvider provideRegisterHooks + */ + public function testRegisterHooks( $pre, $info, $expected ) { + $processor = new MockExtensionProcessor( array( 'wgHooks' => $pre ) ); + $processor->extractInfo( $this->dir, $info ); + $extracted = $processor->getExtractedInfo(); + $this->assertEquals( $expected, $extracted['globals']['wgHooks'] ); + } + + /** + * @covers ExtensionProcessor::extractConfig + */ + public function testExtractConfig() { + $processor = new ExtensionProcessor; + $info = array( + 'config' => array( + 'Bar' => 'somevalue', + 'Foo' => 10, + '@IGNORED' => 'yes', + ), + ) + self::$default; + $processor->extractInfo( $this->dir, $info ); + $extracted = $processor->getExtractedInfo(); + $this->assertEquals( 'somevalue', $extracted['globals']['wgBar'] ); + $this->assertEquals( 10, $extracted['globals']['wgFoo'] ); + $this->assertArrayNotHasKey( 'wg@IGNORED', $extracted['globals'] ); + } + + public static function provideExtracttExtensionMessagesFiles() { + $dir = __DIR__ . '/FooBar/'; + return array( + array( + array( 'ExtensionMessagesFiles' => array( 'FooBarAlias' => 'FooBar.alias.php' ) ), + array( 'wgExtensionMessagesFiles' => array( 'FooBarAlias' => $dir . 'FooBar.alias.php' ) ) + ), + array( + array( + 'ExtensionMessagesFiles' => array( + 'FooBarAlias' => 'FooBar.alias.php', + 'FooBarMagic' => 'FooBar.magic.i18n.php', + ), + ), + array( + 'wgExtensionMessagesFiles' => array( + 'FooBarAlias' => $dir . 'FooBar.alias.php', + 'FooBarMagic' => $dir . 'FooBar.magic.i18n.php', + ), + ), + ), + ); + } + + /** + * @covers ExtensionProcessor::extracttExtensionMessagesFiles + * @dataProvider provideExtracttExtensionMessagesFiles + */ + public function testExtracttExtensionMessagesFiles( $input, $expected ) { + $processor = new ExtensionProcessor(); + $processor->extractInfo( $this->dir, $input + self::$default ); + $out = $processor->getExtractedInfo(); + foreach ( $expected as $key => $value ) { + $this->assertEquals( $value, $out['globals'][$key] ); + } + } + + + public static function provideExtractMessagesDirs() { + $dir = __DIR__ . '/FooBar/'; + return array( + array( + array( 'MessagesDirs' => array( 'VisualEditor' => 'i18n' ) ), + array( 'wgMessagesDirs' => array( 'VisualEditor' => array( $dir . 'i18n' ) ) ) + ), + array( + array( 'MessagesDirs' => array( 'VisualEditor' => array( 'i18n', 'foobar' ) ) ), + array( 'wgMessagesDirs' => array( 'VisualEditor' => array( $dir . 'i18n', $dir . 'foobar' ) ) ) + ), + ); + } + + /** + * @covers ExtensionProcessor::extractMessagesDirs + * @dataProvider provideExtractMessagesDirs + */ + public function testExtractMessagesDirs( $input, $expected ) { + $processor = new ExtensionProcessor(); + $processor->extractInfo( $this->dir, $input + self::$default ); + $out = $processor->getExtractedInfo(); + foreach ( $expected as $key => $value ) { + $this->assertEquals( $value, $out['globals'][$key] ); + } + } + + /** + * @covers ExtensionProcessor::extractResourceLoaderModules + * @dataProvider provideExtractResourceLoaderModules + */ + public function testExtractResourceLoaderModules( $input, $expected ) { + $processor = new ExtensionProcessor(); + $processor->extractInfo( $this->dir, $input + self::$default ); + $out = $processor->getExtractedInfo(); + foreach ( $expected as $key => $value ) { + $this->assertEquals( $value, $out['globals'][$key] ); + } + } + + public static function provideExtractResourceLoaderModules() { + $dir = __DIR__ . '/FooBar/'; + return array( + // Generic module with localBasePath/remoteExtPath specified + array( + // Input + array( + 'ResourceModules' => array( + 'test.foo' => array( + 'styles' => 'foobar.js', + 'localBasePath' => '', + 'remoteExtPath' => 'FooBar', + ), + ), + ), + // Expected + array( + 'wgResourceModules' => array( + 'test.foo' => array( + 'styles' => 'foobar.js', + 'localBasePath' => $dir, + 'remoteExtPath' => 'FooBar', + ), + ), + ), + ), + // ResourceFileModulePaths specified: + array( + // Input + array( + 'ResourceFileModulePaths' => array( + 'localBasePath' => '', + 'remoteExtPath' => 'FooBar', + ), + 'ResourceModules' => array( + // No paths + 'test.foo' => array( + 'styles' => 'foo.js', + ), + // Different paths set + 'test.bar' => array( + 'styles' => 'bar.js', + 'localBasePath' => 'subdir', + 'remoteExtPath' => 'FooBar/subdir', + ), + // Custom class with no paths set + 'test.class' => array( + 'class' => 'FooBarModule', + 'extra' => 'argument', + ), + // Custom class with a localBasePath + 'test.class.with.path' => array( + 'class' => 'FooBarPathModule', + 'extra' => 'argument', + 'localBasePath' => '', + ) + ), + ), + // Expected + array( + 'wgResourceModules' => array( + 'test.foo' => array( + 'styles' => 'foo.js', + 'localBasePath' => $dir, + 'remoteExtPath' => 'FooBar', + ), + 'test.bar' => array( + 'styles' => 'bar.js', + 'localBasePath' => $dir . 'subdir', + 'remoteExtPath' => 'FooBar/subdir', + ), + 'test.class' => array( + 'class' => 'FooBarModule', + 'extra' => 'argument', + 'localBasePath' => $dir, + 'remoteExtPath' => 'FooBar', + ), + 'test.class.with.path' => array( + 'class' => 'FooBarPathModule', + 'extra' => 'argument', + 'localBasePath' => $dir, + 'remoteExtPath' => 'FooBar', + ) + ), + ), + ), + // ResourceModuleSkinStyles with file module paths + array( + // Input + array( + 'ResourceFileModulePaths' => array( + 'localBasePath' => '', + 'remoteSkinPath' => 'FooBar', + ), + 'ResourceModuleSkinStyles' => array( + 'foobar' => array( + 'test.foo' => 'foo.css', + ) + ), + ), + // Expected + array( + 'wgResourceModuleSkinStyles' => array( + 'foobar' => array( + 'test.foo' => 'foo.css', + 'localBasePath' => $dir, + 'remoteSkinPath' => 'FooBar', + ), + ), + ), + ), + // ResourceModuleSkinStyles with file module paths and an override + array( + // Input + array( + 'ResourceFileModulePaths' => array( + 'localBasePath' => '', + 'remoteSkinPath' => 'FooBar', + ), + 'ResourceModuleSkinStyles' => array( + 'foobar' => array( + 'test.foo' => 'foo.css', + 'remoteSkinPath' => 'BarFoo' + ), + ), + ), + // Expected + array( + 'wgResourceModuleSkinStyles' => array( + 'foobar' => array( + 'test.foo' => 'foo.css', + 'localBasePath' => $dir, + 'remoteSkinPath' => 'BarFoo', + ), + ), + ), + ), + ); + } + + public static function provideSetToGlobal() { + return array( + array( + array( 'wgAPIModules', 'wgAvailableRights' ), + array(), + array( + 'APIModules' => array( 'foobar' => 'ApiFooBar' ), + 'AvailableRights' => array( 'foobar', 'unfoobar' ), + ), + array( + 'wgAPIModules' => array( 'foobar' => 'ApiFooBar' ), + 'wgAvailableRights' => array( 'foobar', 'unfoobar' ), + ), + ), + array( + array( 'wgAPIModules', 'wgAvailableRights' ), + array( + 'wgAPIModules' => array( 'barbaz' => 'ApiBarBaz' ), + 'wgAvailableRights' => array( 'barbaz' ) + ), + array( + 'APIModules' => array( 'foobar' => 'ApiFooBar' ), + 'AvailableRights' => array( 'foobar', 'unfoobar' ), + ), + array( + 'wgAPIModules' => array( 'barbaz' => 'ApiBarBaz', 'foobar' => 'ApiFooBar' ), + 'wgAvailableRights' => array( 'barbaz', 'foobar', 'unfoobar' ), + ), + ), + array( + array( 'wgGroupPermissions' ), + array( + 'wgGroupPermissions' => array( 'sysop' => array( 'delete' ) ), + ), + array( + 'GroupPermissions' => array( 'sysop' => array( 'undelete' ), 'user' => array( 'edit' ) ), + ), + array( + 'wgGroupPermissions' => array( 'sysop' => array( 'delete', 'undelete' ), 'user' => array( 'edit' ) ), + ) + ) + ); + } +} + + +/** + * Allow overriding the default value of $this->globals + * so we can test merging + */ +class MockExtensionProcessor extends ExtensionProcessor { + public function __construct( $globals = array() ) { + $this->globals = $globals + $this->globals; + } +} diff --git a/tests/phpunit/includes/registration/ExtensionRegistryTest.php b/tests/phpunit/includes/registration/ExtensionRegistryTest.php new file mode 100644 index 00000000..1b24628c --- /dev/null +++ b/tests/phpunit/includes/registration/ExtensionRegistryTest.php @@ -0,0 +1,195 @@ +<?php + +class ExtensionRegistryTest extends MediaWikiTestCase { + + /** + * @covers ExtensionRegistry::exportExtractedData + * @dataProvider provideExportExtractedDataGlobals + */ + public function testExportExtractedDataGlobals( $desc, $before, $globals, $expected ) { + // Set globals for test + if ( $before ) { + foreach ( $before as $key => $value ) { + // mw prefixed globals does not exist normally + if ( substr( $key, 0, 2 ) == 'mw' ) { + $GLOBALS[$key] = $value; + } else { + $this->setMwGlobals( $key, $value ); + } + } + } + + $info = array( + 'globals' => $globals, + 'callbacks' => array(), + 'defines' => array(), + 'credits' => array(), + 'attributes' => array(), + ); + $registry = new ExtensionRegistry(); + $class = new ReflectionClass( 'ExtensionRegistry' ); + $method = $class->getMethod( 'exportExtractedData' ); + $method->setAccessible( true ); + $method->invokeArgs( $registry, array( $info ) ); + foreach ( $expected as $name => $value ) { + $this->assertArrayHasKey( $name, $GLOBALS, $desc ); + $this->assertEquals( $value, $GLOBALS[$name], $desc ); + } + + // Remove mw prefixed globals + if ( $before ) { + foreach ( $before as $key => $value ) { + if ( substr( $key, 0, 2 ) == 'mw' ) { + unset( $GLOBALS[$key] ); + } + } + } + } + + public static function provideExportExtractedDataGlobals() { + // "mwtest" prefix used instead of "$wg" to avoid potential conflicts + return array( + array( + 'Simple non-array values', + array( + 'mwtestFooBarConfig' => true, + 'mwtestFooBarConfig2' => 'string', + ), + array( + 'mwtestFooBarDefault' => 1234, + 'mwtestFooBarConfig' => false, + ), + array( + 'mwtestFooBarConfig' => true, + 'mwtestFooBarConfig2' => 'string', + 'mwtestFooBarDefault' => 1234, + ), + ), + array( + 'No global already set, simple array', + null, + array( + 'mwtestDefaultOptions' => array( + 'foobar' => true, + ) + ), + array( + 'mwtestDefaultOptions' => array( + 'foobar' => true, + ) + ), + ), + array( + 'Global already set, simple array', + array( + 'mwtestDefaultOptions' => array( + 'foobar' => true, + 'foo' => 'string' + ), + ), + array( + 'mwtestDefaultOptions' => array( + 'barbaz' => 12345, + 'foobar' => false, + ), + ), + array( + 'mwtestDefaultOptions' => array( + 'barbaz' => 12345, + 'foo' => 'string', + 'foobar' => true, + ), + ) + ), + array( + 'No global already set, $wgHooks', + array( + 'wgHooks' => array(), + ), + array( + 'wgHooks' => array( + 'FooBarEvent' => array( + 'FooBarClass::onFooBarEvent' + ), + ), + ), + array( + 'wgHooks' => array( + 'FooBarEvent' => array( + 'FooBarClass::onFooBarEvent' + ), + ), + ), + ), + array( + 'Global already set, $wgHooks', + array( + 'wgHooks' => array( + 'FooBarEvent' => array( + 'FooBarClass::onFooBarEvent' + ), + 'BazBarEvent' => array( + 'FooBarClass::onBazBarEvent', + ), + ), + ), + array( + 'wgHooks' => array( + 'FooBarEvent' => array( + 'BazBarClass::onFooBarEvent', + ), + ), + ), + array( + 'wgHooks' => array( + 'FooBarEvent' => array( + 'FooBarClass::onFooBarEvent', + 'BazBarClass::onFooBarEvent', + ), + 'BazBarEvent' => array( + 'FooBarClass::onBazBarEvent', + ), + ), + ), + ), + array( + 'Global already set, $wgGroupPermissions', + array( + 'wgGroupPermissions' => array( + 'sysop' => array( + 'something' => true, + ), + 'user' => array( + 'somethingtwo' => true, + ) + ), + ), + array( + 'wgGroupPermissions' => array( + 'customgroup' => array( + 'right' => true, + ), + 'user' => array( + 'right' => true, + 'somethingtwo' => false, + ) + ), + ), + array( + 'wgGroupPermissions' => array( + 'customgroup' => array( + 'right' => true, + ), + 'sysop' => array( + 'something' => true, + ), + 'user' => array( + 'somethingtwo' => true, + 'right' => true, + ) + ), + ), + ) + ); + } +} diff --git a/tests/phpunit/includes/resourceloader/ResourceLoaderFileModuleTest.php b/tests/phpunit/includes/resourceloader/ResourceLoaderFileModuleTest.php new file mode 100644 index 00000000..122995a5 --- /dev/null +++ b/tests/phpunit/includes/resourceloader/ResourceLoaderFileModuleTest.php @@ -0,0 +1,247 @@ +<?php + +/** + * @group ResourceLoader + */ +class ResourceLoaderFileModuleTest extends ResourceLoaderTestCase { + + protected function setUp() { + parent::setUp(); + + // The return value of the closure shouldn't matter since this test should + // never call it + SkinFactory::getDefaultInstance()->register( + 'fakeskin', + 'FakeSkin', + function () { + } + ); + } + + private static function getModules() { + $base = array( + 'localBasePath' => realpath( dirname( __FILE__ ) ), + ); + + return array( + 'noTemplateModule' => array(), + + 'htmlTemplateModule' => $base + array( + 'templates' => array( + 'templates/template.html', + 'templates/template2.html', + ) + ), + + 'aliasedHtmlTemplateModule' => $base + array( + 'templates' => array( + 'foo.html' => 'templates/template.html', + 'bar.html' => 'templates/template2.html', + ) + ), + + 'templateModuleHandlebars' => $base + array( + 'templates' => array( + 'templates/template_awesome.handlebars', + ), + ), + + 'aliasFooFromBar' => $base + array( + 'templates' => array( + 'foo.foo' => 'templates/template.bar', + ), + ), + ); + } + + public static function providerTemplateDependencies() { + $modules = self::getModules(); + + return array( + array( + $modules['noTemplateModule'], + array(), + ), + array( + $modules['htmlTemplateModule'], + array( + 'mediawiki.template', + ), + ), + array( + $modules['templateModuleHandlebars'], + array( + 'mediawiki.template', + 'mediawiki.template.handlebars', + ), + ), + array( + $modules['aliasFooFromBar'], + array( + 'mediawiki.template', + 'mediawiki.template.foo', + ), + ), + ); + } + + /** + * @dataProvider providerTemplateDependencies + * @covers ResourceLoaderFileModule::__construct + * @covers ResourceLoaderFileModule::getDependencies + */ + public function testTemplateDependencies( $module, $expected ) { + $rl = new ResourceLoaderFileModule( $module ); + $this->assertEquals( $rl->getDependencies(), $expected ); + } + + /** + * @covers ResourceLoaderFileModule::getAllStyleFiles + * @covers ResourceLoaderFileModule::getAllSkinStyleFiles + * @covers ResourceLoaderFileModule::getSkinStyleFiles + */ + public function testGetAllSkinStyleFiles() { + $baseParams = array( + 'scripts' => array( + 'foo.js', + 'bar.js', + ), + 'styles' => array( + 'foo.css', + 'bar.css' => array( 'media' => 'print' ), + 'screen.less' => array( 'media' => 'screen' ), + 'screen-query.css' => array( 'media' => 'screen and (min-width: 400px)' ), + ), + 'skinStyles' => array( + 'default' => 'quux-fallback.less', + 'fakeskin' => array( + 'baz-vector.css', + 'quux-vector.less', + ), + ), + 'messages' => array( + 'hello', + 'world', + ), + ); + + $module = new ResourceLoaderFileModule( $baseParams ); + + $this->assertEquals( + array( + 'foo.css', + 'baz-vector.css', + 'quux-vector.less', + 'quux-fallback.less', + 'bar.css', + 'screen.less', + 'screen-query.css', + ), + array_map( 'basename', $module->getAllStyleFiles() ) + ); + } + + /** + * Strip @noflip annotations from CSS code. + * @param string $css + * @return string + */ + private static function stripNoflip( $css ) { + return str_replace( '/*@noflip*/ ', '', $css ); + } + + /** + * What happens when you mix @embed and @noflip? + * This really is an integration test, but oh well. + * + * @covers ResourceLoaderFileModule::getStyles + * @covers ResourceLoaderFileModule::getStyleFiles + */ + public function testMixedCssAnnotations( ) { + $basePath = __DIR__ . '/../../data/css'; + $testModule = new ResourceLoaderFileModule( array( + 'localBasePath' => $basePath, + 'styles' => array( 'test.css' ), + ) ); + $expectedModule = new ResourceLoaderFileModule( array( + 'localBasePath' => $basePath, + 'styles' => array( 'expected.css' ), + ) ); + + $contextLtr = $this->getResourceLoaderContext( 'en', 'ltr' ); + $contextRtl = $this->getResourceLoaderContext( 'he', 'rtl' ); + + // Since we want to compare the effect of @noflip+@embed against the effect of just @embed, and + // the @noflip annotations are always preserved, we need to strip them first. + $this->assertEquals( + $expectedModule->getStyles( $contextLtr ), + self::stripNoflip( $testModule->getStyles( $contextLtr ) ), + "/*@noflip*/ with /*@embed*/ gives correct results in LTR mode" + ); + $this->assertEquals( + $expectedModule->getStyles( $contextLtr ), + self::stripNoflip( $testModule->getStyles( $contextRtl ) ), + "/*@noflip*/ with /*@embed*/ gives correct results in RTL mode" + ); + } + + public static function providerGetTemplates() { + $modules = self::getModules(); + + return array( + array( + $modules['noTemplateModule'], + array(), + ), + array( + $modules['templateModuleHandlebars'], + array( + 'templates/template_awesome.handlebars' => "wow\n", + ), + ), + array( + $modules['htmlTemplateModule'], + array( + 'templates/template.html' => "<strong>hello</strong>\n", + 'templates/template2.html' => "<div>goodbye</div>\n", + ), + ), + array( + $modules['aliasedHtmlTemplateModule'], + array( + 'foo.html' => "<strong>hello</strong>\n", + 'bar.html' => "<div>goodbye</div>\n", + ), + ), + ); + } + + /** + * @dataProvider providerGetTemplates + * @covers ResourceLoaderFileModule::getTemplates + */ + public function testGetTemplates( $module, $expected ) { + $rl = new ResourceLoaderFileModule( $module ); + + $this->assertEquals( $rl->getTemplates(), $expected ); + } + + public static function providerGetModifiedTime() { + $modules = self::getModules(); + + return array( + // Check the default value when no templates present in module is 1 + array( $modules['noTemplateModule'], 1 ), + ); + } + + /** + * @dataProvider providerGetModifiedTime + * @covers ResourceLoaderFileModule::getModifiedTime + */ + public function testGetModifiedTime( $module, $expected ) { + $rl = new ResourceLoaderFileModule( $module ); + $ts = $rl->getModifiedTime( $this->getResourceLoaderContext() ); + $this->assertEquals( $ts, $expected ); + } +} diff --git a/tests/phpunit/includes/resourceloader/ResourceLoaderImageModuleTest.php b/tests/phpunit/includes/resourceloader/ResourceLoaderImageModuleTest.php new file mode 100644 index 00000000..d0bc210b --- /dev/null +++ b/tests/phpunit/includes/resourceloader/ResourceLoaderImageModuleTest.php @@ -0,0 +1,162 @@ +<?php + +/** + * @group ResourceLoader + */ +class ResourceLoaderImageModuleTest extends ResourceLoaderTestCase { + + public static $commonImageData = array( + 'add' => 'add.gif', + 'remove' => array( + 'file' => 'remove.svg', + 'variants' => array( 'destructive' ), + ), + 'next' => array( + 'file' => array( + 'ltr' => 'next.svg', + 'rtl' => 'prev.svg' + ), + ), + 'help' => array( + 'file' => array( + 'ltr' => 'help-ltr.svg', + 'rtl' => 'help-rtl.svg', + 'lang' => array( + 'he' => 'help-ltr.svg', + ) + ), + ), + 'bold' => array( + 'file' => array( + 'default' => 'bold-a.svg', + 'lang' => array( + 'en' => 'bold-b.svg', + 'ar,de' => 'bold-f.svg', + ) + ), + ) + ); + + public static $commonImageVariants = array( + 'invert' => array( + 'color' => '#FFFFFF', + 'global' => true, + ), + 'primary' => array( + 'color' => '#598AD1', + ), + 'constructive' => array( + 'color' => '#00C697', + ), + 'destructive' => array( + 'color' => '#E81915', + ), + ); + + public static function providerGetModules() { + return array( + array( + array( + 'class' => 'ResourceLoaderImageModule', + 'prefix' => 'oo-ui-icon', + 'variants' => self::$commonImageVariants, + 'images' => self::$commonImageData, + ), + '.oo-ui-icon-add { + ... +} +.oo-ui-icon-add-invert { + ... +} +.oo-ui-icon-remove { + ... +} +.oo-ui-icon-remove-invert { + ... +} +.oo-ui-icon-remove-destructive { + ... +} +.oo-ui-icon-next { + ... +} +.oo-ui-icon-next-invert { + ... +} +.oo-ui-icon-help { + ... +} +.oo-ui-icon-help-invert { + ... +} +.oo-ui-icon-bold { + ... +} +.oo-ui-icon-bold-invert { + ... +}', + ), + array( + array( + 'class' => 'ResourceLoaderImageModule', + 'selectorWithoutVariant' => '.mw-ui-icon-{name}:after, .mw-ui-icon-{name}:before', + 'selectorWithVariant' => '.mw-ui-icon-{name}-{variant}:after, .mw-ui-icon-{name}-{variant}:before', + 'variants' => self::$commonImageVariants, + 'images' => self::$commonImageData, + ), + '.mw-ui-icon-add:after, .mw-ui-icon-add:before { + ... +} +.mw-ui-icon-add-invert:after, .mw-ui-icon-add-invert:before { + ... +} +.mw-ui-icon-remove:after, .mw-ui-icon-remove:before { + ... +} +.mw-ui-icon-remove-invert:after, .mw-ui-icon-remove-invert:before { + ... +} +.mw-ui-icon-remove-destructive:after, .mw-ui-icon-remove-destructive:before { + ... +} +.mw-ui-icon-next:after, .mw-ui-icon-next:before { + ... +} +.mw-ui-icon-next-invert:after, .mw-ui-icon-next-invert:before { + ... +} +.mw-ui-icon-help:after, .mw-ui-icon-help:before { + ... +} +.mw-ui-icon-help-invert:after, .mw-ui-icon-help-invert:before { + ... +} +.mw-ui-icon-bold:after, .mw-ui-icon-bold:before { + ... +} +.mw-ui-icon-bold-invert:after, .mw-ui-icon-bold-invert:before { + ... +}', + ), + ); + } + + /** + * @dataProvider providerGetModules + * @covers ResourceLoaderImageModule::getStyles + */ + public function testGetStyles( $module, $expected ) { + $module = new ResourceLoaderImageModuleTestable( $module, __DIR__ . '/../../data/resourceloader' ); + $styles = $module->getStyles( $this->getResourceLoaderContext() ); + $this->assertEquals( $expected, $styles['all'] ); + } +} + +class ResourceLoaderImageModuleTestable extends ResourceLoaderImageModule { + /** + * Replace with a stub to make test cases easier to write. + */ + protected function getCssDeclarations( $primary, $fallback ) { + return array( '...' ); + } +} diff --git a/tests/phpunit/includes/resourceloader/ResourceLoaderImageTest.php b/tests/phpunit/includes/resourceloader/ResourceLoaderImageTest.php new file mode 100644 index 00000000..758cfe19 --- /dev/null +++ b/tests/phpunit/includes/resourceloader/ResourceLoaderImageTest.php @@ -0,0 +1,122 @@ +<?php + +/** + * @group ResourceLoader + */ +class ResourceLoaderImageTest extends ResourceLoaderTestCase { + + protected $imagesPath; + + protected function setUp() { + parent::setUp(); + $this->imagesPath = __DIR__ . '/../../data/resourceloader'; + } + + protected function getTestImage( $name ) { + $options = ResourceLoaderImageModuleTest::$commonImageData[$name]; + $fileDescriptor = is_string( $options ) ? $options : $options['file']; + $allowedVariants = is_array( $options ) && isset( $options['variants'] ) ? $options['variants'] : array(); + $variants = array_fill_keys( $allowedVariants, array( 'color' => 'red' ) ); + return new ResourceLoaderImageTestable( $name, 'test', $fileDescriptor, $this->imagesPath, $variants ); + } + + public static function provideGetPath() { + return array( + array( 'add', 'en', 'add.gif' ), + array( 'add', 'he', 'add.gif' ), + array( 'remove', 'en', 'remove.svg' ), + array( 'remove', 'he', 'remove.svg' ), + array( 'next', 'en', 'next.svg' ), + array( 'next', 'he', 'prev.svg' ), + array( 'help', 'en', 'help-ltr.svg' ), + array( 'help', 'ar', 'help-rtl.svg' ), + array( 'help', 'he', 'help-ltr.svg' ), + array( 'bold', 'en', 'bold-b.svg' ), + array( 'bold', 'de', 'bold-f.svg' ), + array( 'bold', 'ar', 'bold-f.svg' ), + array( 'bold', 'fr', 'bold-a.svg' ), + array( 'bold', 'he', 'bold-a.svg' ), + ); + } + + /** + * @covers ResourceLoaderImage::getPath + * @dataProvider provideGetPath + */ + public function testGetPath( $imageName, $languageCode, $path ) { + static $dirMap = array( + 'en' => 'ltr', + 'de' => 'ltr', + 'fr' => 'ltr', + 'he' => 'rtl', + 'ar' => 'rtl', + ); + static $contexts = array(); + + $image = $this->getTestImage( $imageName ); + $context = $this->getResourceLoaderContext( $languageCode, $dirMap[$languageCode] ); + + $this->assertEquals( $image->getPath( $context ), $this->imagesPath . '/' . $path ); + } + + /** + * @covers ResourceLoaderImage::getExtension + * @covers ResourceLoaderImage::getMimeType + */ + public function testGetExtension() { + $image = $this->getTestImage( 'remove' ); + $this->assertEquals( $image->getExtension(), 'svg' ); + $this->assertEquals( $image->getExtension( 'original' ), 'svg' ); + $this->assertEquals( $image->getExtension( 'rasterized' ), 'png' ); + $image = $this->getTestImage( 'add' ); + $this->assertEquals( $image->getExtension(), 'gif' ); + $this->assertEquals( $image->getExtension( 'original' ), 'gif' ); + $this->assertEquals( $image->getExtension( 'rasterized' ), 'gif' ); + } + + /** + * @covers ResourceLoaderImage::getImageData + * @covers ResourceLoaderImage::variantize + * @covers ResourceLoaderImage::massageSvgPathdata + */ + public function testGetImageData() { + $context = $this->getResourceLoaderContext( 'en', 'ltr' ); + + $image = $this->getTestImage( 'remove' ); + $data = file_get_contents( $this->imagesPath . '/remove.svg' ); + $dataConstructive = file_get_contents( $this->imagesPath . '/remove_variantize.svg' ); + $this->assertEquals( $image->getImageData( $context, null, 'original' ), $data ); + $this->assertEquals( $image->getImageData( $context, 'destructive', 'original' ), $dataConstructive ); + // Stub, since we don't know if we even have a SVG handler, much less what exactly it'll output + $this->assertEquals( $image->getImageData( $context, null, 'rasterized' ), 'RASTERIZESTUB' ); + + $image = $this->getTestImage( 'add' ); + $data = file_get_contents( $this->imagesPath . '/add.gif' ); + $this->assertEquals( $image->getImageData( $context, null, 'original' ), $data ); + $this->assertEquals( $image->getImageData( $context, null, 'rasterized' ), $data ); + } + + /** + * @covers ResourceLoaderImage::massageSvgPathdata + */ + public function testMassageSvgPathdata() { + $image = $this->getTestImage( 'next' ); + $data = file_get_contents( $this->imagesPath . '/next.svg' ); + $dataMassaged = file_get_contents( $this->imagesPath . '/next_massage.svg' ); + $this->assertEquals( $image->massageSvgPathdata( $data ), $dataMassaged ); + } +} + +class ResourceLoaderImageTestable extends ResourceLoaderImage { + // Make some protected methods public + public function getPath( ResourceLoaderContext $context ) { + return parent::getPath( $context ); + } + public function massageSvgPathdata( $svg ) { + return parent::massageSvgPathdata( $svg ); + } + // Stub, since we don't know if we even have a SVG handler, much less what exactly it'll output + public function rasterize( $svg ) { + return 'RASTERIZESTUB'; + } +} diff --git a/tests/phpunit/includes/resourceloader/ResourceLoaderModuleTest.php b/tests/phpunit/includes/resourceloader/ResourceLoaderModuleTest.php index b0edaaf7..6d1ed4e0 100644 --- a/tests/phpunit/includes/resourceloader/ResourceLoaderModuleTest.php +++ b/tests/phpunit/includes/resourceloader/ResourceLoaderModuleTest.php @@ -2,71 +2,12 @@ class ResourceLoaderModuleTest extends ResourceLoaderTestCase { - protected function setUp() { - parent::setUp(); - - // The return value of the closure shouldn't matter since this test should - // never call it - SkinFactory::getDefaultInstance()->register( - 'fakeskin', - 'FakeSkin', - function () { - } - ); - } - - /** - * @covers ResourceLoaderFileModule::getAllSkinStyleFiles - */ - public function testGetAllSkinStyleFiles() { - $context = self::getResourceLoaderContext(); - - $baseParams = array( - 'scripts' => array( - 'foo.js', - 'bar.js', - ), - 'styles' => array( - 'foo.css', - 'bar.css' => array( 'media' => 'print' ), - 'screen.less' => array( 'media' => 'screen' ), - 'screen-query.css' => array( 'media' => 'screen and (min-width: 400px)' ), - ), - 'skinStyles' => array( - 'default' => 'quux-fallback.less', - 'fakeskin' => array( - 'baz-vector.css', - 'quux-vector.less', - ), - ), - 'messages' => array( - 'hello', - 'world', - ), - ); - - $module = new ResourceLoaderFileModule( $baseParams ); - - $this->assertEquals( - array( - 'foo.css', - 'baz-vector.css', - 'quux-vector.less', - 'quux-fallback.less', - 'bar.css', - 'screen.less', - 'screen-query.css', - ), - array_map( 'basename', $module->getAllStyleFiles() ) - ); - } - /** * @covers ResourceLoaderModule::getDefinitionSummary * @covers ResourceLoaderFileModule::getDefinitionSummary */ public function testDefinitionSummary() { - $context = self::getResourceLoaderContext(); + $context = $this->getResourceLoaderContext(); $baseParams = array( 'scripts' => array( 'foo.js', 'bar.js' ), diff --git a/tests/phpunit/includes/resourceloader/ResourceLoaderStartupModuleTest.php b/tests/phpunit/includes/resourceloader/ResourceLoaderStartUpModuleTest.php index a1893873..7f3506cc 100644 --- a/tests/phpunit/includes/resourceloader/ResourceLoaderStartupModuleTest.php +++ b/tests/phpunit/includes/resourceloader/ResourceLoaderStartUpModuleTest.php @@ -1,6 +1,6 @@ <?php -class ResourceLoaderStartupModuleTest extends ResourceLoaderTestCase { +class ResourceLoaderStartUpModuleTest extends ResourceLoaderTestCase { public static function provideGetModuleRegistrations() { return array( @@ -23,7 +23,7 @@ mw.loader.addSource( { } );mw.loader.register( [ [ "test.blank", - "1388534400" + 1388534400 ] ] );', ) ), @@ -40,17 +40,17 @@ mw.loader.addSource( { } );mw.loader.register( [ [ "test.blank", - "1388534400" + 1388534400 ], [ "test.group.foo", - "1388534400", + 1388534400, [], "x-foo" ], [ "test.group.bar", - "1388534400", + 1388534400, [], "x-bar" ] @@ -68,7 +68,7 @@ mw.loader.addSource( { } );mw.loader.register( [ [ "test.blank", - "1388534400" + 1388534400 ] ] );' ) ), @@ -90,7 +90,7 @@ mw.loader.addSource( { } );mw.loader.register( [ [ "test.blank", - "1388534400", + 1388534400, [], null, "example" @@ -115,8 +115,8 @@ mw.loader.addSource( { 'test.z.foo' => new ResourceLoaderTestModule( array( 'dependencies' => array( 'test.x.core', - 'test.x.polyfil', - 'test.y.polyfil', + 'test.x.polyfill', + 'test.y.polyfill', ), ) ), ), @@ -126,31 +126,31 @@ mw.loader.addSource( { } );mw.loader.register( [ [ "test.x.core", - "1388534400" + 1388534400 ], [ "test.x.polyfill", - "1388534400", + 1388534400, [], null, - "local", + null, "return true;" ], [ "test.y.polyfill", - "1388534400", + 1388534400, [], null, - "local", + null, "return !!( window.JSON \u0026\u0026 JSON.parse \u0026\u0026 JSON.stringify);" ], [ "test.z.foo", - "1388534400", + 1388534400, [ - "test.x.core", - "test.x.polyfil", - "test.y.polyfil" + 0, + 1, + 2 ] ] ] );', @@ -222,63 +222,63 @@ mw.loader.addSource( { } );mw.loader.register( [ [ "test.blank", - "1388534400" + 1388534400 ], [ "test.x.core", - "1388534400" + 1388534400 ], [ "test.x.util", - "1388534400", + 1388534400, [ - "test.x.core" + 1 ] ], [ "test.x.foo", - "1388534400", + 1388534400, [ - "test.x.core" + 1 ] ], [ "test.x.bar", - "1388534400", + 1388534400, [ - "test.x.util" + 2 ] ], [ "test.x.quux", - "1388534400", + 1388534400, [ - "test.x.foo", - "test.x.bar", + 3, + 4, "test.x.unknown" ] ], [ "test.group.foo.1", - "1388534400", + 1388534400, [], "x-foo" ], [ "test.group.foo.2", - "1388534400", + 1388534400, [], "x-foo" ], [ "test.group.bar.1", - "1388534400", + 1388534400, [], "x-bar" ], [ "test.group.bar.2", - "1388534400", + 1388534400, [], "x-bar", "example" @@ -290,7 +290,7 @@ mw.loader.addSource( { /** * @dataProvider provideGetModuleRegistrations - * @covers ResourceLoaderStartupModule::optimizeDependencies + * @covers ResourceLoaderStartUpModule::compileUnresolvedDependencies * @covers ResourceLoaderStartUpModule::getModuleRegistrations * @covers ResourceLoader::makeLoaderSourcesScript * @covers ResourceLoader::makeLoaderRegisterScript @@ -300,7 +300,7 @@ mw.loader.addSource( { $this->setMwGlobals( 'wgResourceLoaderSources', $case['sources'] ); } - $context = self::getResourceLoaderContext(); + $context = $this->getResourceLoaderContext(); $rl = $context->getResourceLoader(); $rl->register( $case['modules'] ); @@ -337,15 +337,15 @@ mw.loader.addSource( { public function testRegistrationsMinified( $modules ) { $this->setMwGlobals( 'wgResourceLoaderDebug', false ); - $context = self::getResourceLoaderContext(); + $context = $this->getResourceLoaderContext(); $rl = $context->getResourceLoader(); $rl->register( $modules ); $module = new ResourceLoaderStartUpModule(); $this->assertEquals( 'mw.loader.addSource({"local":"/w/load.php"});' . 'mw.loader.register([' -. '["test.blank","1388534400"],' -. '["test.min","1388534400",["test.blank"],null,"local",' +. '["test.blank",1388534400],' +. '["test.min",1388534400,[0],null,null,' . '"return!!(window.JSON\u0026\u0026JSON.parse\u0026\u0026JSON.stringify);"' . ']]);', $module->getModuleRegistrations( $context ), @@ -357,7 +357,7 @@ mw.loader.addSource( { * @dataProvider provideRegistrations */ public function testRegistrationsUnminified( $modules ) { - $context = self::getResourceLoaderContext(); + $context = $this->getResourceLoaderContext(); $rl = $context->getResourceLoader(); $rl->register( $modules ); $module = new ResourceLoaderStartUpModule(); @@ -367,16 +367,16 @@ mw.loader.addSource( { } );mw.loader.register( [ [ "test.blank", - "1388534400" + 1388534400 ], [ "test.min", - "1388534400", + 1388534400, [ - "test.blank" + 0 ], null, - "local", + null, "return !!( window.JSON \u0026\u0026 JSON.parse \u0026\u0026 JSON.stringify);" ] ] );', diff --git a/tests/phpunit/includes/resourceloader/ResourceLoaderTest.php b/tests/phpunit/includes/resourceloader/ResourceLoaderTest.php index f19f6886..ca7307ec 100644 --- a/tests/phpunit/includes/resourceloader/ResourceLoaderTest.php +++ b/tests/phpunit/includes/resourceloader/ResourceLoaderTest.php @@ -2,13 +2,9 @@ class ResourceLoaderTest extends ResourceLoaderTestCase { - protected static $resourceLoaderRegisterModulesHook; - protected function setUp() { parent::setUp(); - // $wgResourceLoaderLESSFunctions, $wgResourceLoaderLESSImportPaths; $wgResourceLoaderLESSVars; - $this->setMwGlobals( array( 'wgResourceLoaderLESSFunctions' => array( 'test-sum' => function ( $frame, $less ) { @@ -30,35 +26,33 @@ class ResourceLoaderTest extends ResourceLoaderTestCase { ) ); } - /* Hook Methods */ - - /** - * ResourceLoaderRegisterModules hook - */ - public static function resourceLoaderRegisterModules( &$resourceLoader ) { - self::$resourceLoaderRegisterModulesHook = true; - - return true; - } - - /* Provider Methods */ public static function provideValidModules() { return array( array( 'TEST.validModule1', new ResourceLoaderTestModule() ), ); } - /* Test Methods */ - /** * Ensures that the ResourceLoaderRegisterModules hook is called when a new * ResourceLoader object is constructed. * @covers ResourceLoader::__construct */ public function testCreatingNewResourceLoaderCallsRegistrationHook() { - self::$resourceLoaderRegisterModulesHook = false; + $resourceLoaderRegisterModulesHook = false; + + $this->setMwGlobals( 'wgHooks', array( + 'ResourceLoaderRegisterModules' => array( + function ( &$resourceLoader ) use ( &$resourceLoaderRegisterModulesHook ) { + $resourceLoaderRegisterModulesHook = true; + } + ) + ) ); + $resourceLoader = new ResourceLoader(); - $this->assertTrue( self::$resourceLoaderRegisterModulesHook ); + $this->assertTrue( + $resourceLoaderRegisterModulesHook, + 'Hook ResourceLoaderRegisterModules called' + ); return $resourceLoader; } @@ -80,7 +74,7 @@ class ResourceLoaderTest extends ResourceLoaderTestCase { * @covers ResourceLoaderFileModule::compileLessFile */ public function testLessFileCompilation() { - $context = self::getResourceLoaderContext(); + $context = $this->getResourceLoaderContext(); $basePath = __DIR__ . '/../../data/less/module'; $module = new ResourceLoaderFileModule( array( 'localBasePath' => $basePath, @@ -96,43 +90,11 @@ class ResourceLoaderTest extends ResourceLoaderTestCase { * @param string $css * @return string */ - private function stripNoflip( $css ) { + private static function stripNoflip( $css ) { return str_replace( '/*@noflip*/ ', '', $css ); } /** - * What happens when you mix @embed and @noflip? - * This really is an integration test, but oh well. - */ - public function testMixedCssAnnotations( ) { - $basePath = __DIR__ . '/../../data/css'; - $testModule = new ResourceLoaderFileModule( array( - 'localBasePath' => $basePath, - 'styles' => array( 'test.css' ), - ) ); - $expectedModule = new ResourceLoaderFileModule( array( - 'localBasePath' => $basePath, - 'styles' => array( 'expected.css' ), - ) ); - - $contextLtr = self::getResourceLoaderContext( 'en' ); - $contextRtl = self::getResourceLoaderContext( 'he' ); - - // Since we want to compare the effect of @noflip+@embed against the effect of just @embed, and - // the @noflip annotations are always preserved, we need to strip them first. - $this->assertEquals( - $expectedModule->getStyles( $contextLtr ), - $this->stripNoflip( $testModule->getStyles( $contextLtr ) ), - "/*@noflip*/ with /*@embed*/ gives correct results in LTR mode" - ); - $this->assertEquals( - $expectedModule->getStyles( $contextLtr ), - $this->stripNoflip( $testModule->getStyles( $contextRtl ) ), - "/*@noflip*/ with /*@embed*/ gives correct results in RTL mode" - ); - } - - /** * @dataProvider providePackedModules * @covers ResourceLoader::makePackedModulesString */ @@ -193,6 +155,7 @@ class ResourceLoaderTest extends ResourceLoaderTestCase { /** * @dataProvider provideAddSource * @covers ResourceLoader::addSource + * @covers ResourceLoader::getSources */ public function testAddSource( $name, $info, $expected ) { $rl = new ResourceLoader; @@ -223,6 +186,106 @@ class ResourceLoaderTest extends ResourceLoaderTestCase { ); } + public static function provideLoaderImplement() { + return array( + array( array( + 'title' => 'Implement scripts, styles and messages', + + 'name' => 'test.example', + 'scripts' => 'mw.example();', + 'styles' => array( 'css' => array( '.mw-example {}' ) ), + 'messages' => array( 'example' => '' ), + 'templates' => array(), + + 'expected' => 'mw.loader.implement( "test.example", function ( $, jQuery ) { +mw.example(); +}, { + "css": [ + ".mw-example {}" + ] +}, { + "example": "" +} );', + ) ), + array( array( + 'title' => 'Implement scripts', + + 'name' => 'test.example', + 'scripts' => 'mw.example();', + 'styles' => array(), + 'messages' => new XmlJsCode( '{}' ), + 'templates' => array(), + 'title' => 'scripts, styles and messags', + + 'expected' => 'mw.loader.implement( "test.example", function ( $, jQuery ) { +mw.example(); +} );', + ) ), + array( array( + 'title' => 'Implement styles', + + 'name' => 'test.example', + 'scripts' => array(), + 'styles' => array( 'css' => array( '.mw-example {}' ) ), + 'messages' => new XmlJsCode( '{}' ), + 'templates' => array(), + + 'expected' => 'mw.loader.implement( "test.example", [], { + "css": [ + ".mw-example {}" + ] +} );', + ) ), + array( array( + 'title' => 'Implement scripts and messages', + + 'name' => 'test.example', + 'scripts' => 'mw.example();', + 'styles' => array(), + 'messages' => array( 'example' => '' ), + 'templates' => array(), + + 'expected' => 'mw.loader.implement( "test.example", function ( $, jQuery ) { +mw.example(); +}, {}, { + "example": "" +} );', + ) ), + array( array( + 'title' => 'Implement scripts and templates', + + 'name' => 'test.example', + 'scripts' => 'mw.example();', + 'styles' => array(), + 'messages' => new XmlJsCode( '{}' ), + 'templates' => array( 'example.html' => '' ), + + 'expected' => 'mw.loader.implement( "test.example", function ( $, jQuery ) { +mw.example(); +}, {}, {}, { + "example.html": "" +} );', + ) ), + ); + } + + /** + * @dataProvider provideLoaderImplement + * @covers ResourceLoader::makeLoaderImplementScript + */ + public function testMakeLoaderImplementScript( $case ) { + $this->assertEquals( + $case['expected'], + ResourceLoader::makeLoaderImplementScript( + $case['name'], + $case['scripts'], + $case['styles'], + $case['messages'], + $case['templates'] + ) + ); + } + /** * @covers ResourceLoader::getLoadScript */ @@ -242,8 +305,14 @@ class ResourceLoaderTest extends ResourceLoaderTestCase { $this->assertTrue( true ); } } -} -/* Hooks */ -global $wgHooks; -$wgHooks['ResourceLoaderRegisterModules'][] = 'ResourceLoaderTest::resourceLoaderRegisterModules'; + /** + * @covers ResourceLoader::isModuleRegistered + */ + public function testIsModuleRegistered() { + $rl = new ResourceLoader(); + $rl->register( 'test.module', new ResourceLoaderTestModule() ); + $this->assertTrue( $rl->isModuleRegistered( 'test.module' ) ); + $this->assertFalse( $rl->isModuleRegistered( 'test.modulenotregistered' ) ); + } +} diff --git a/tests/phpunit/includes/resourceloader/ResourceLoaderWikiModuleTest.php b/tests/phpunit/includes/resourceloader/ResourceLoaderWikiModuleTest.php index 9dc18050..93a3ebba 100644 --- a/tests/phpunit/includes/resourceloader/ResourceLoaderWikiModuleTest.php +++ b/tests/phpunit/includes/resourceloader/ResourceLoaderWikiModuleTest.php @@ -3,11 +3,93 @@ class ResourceLoaderWikiModuleTest extends ResourceLoaderTestCase { /** + * @covers ResourceLoaderWikiModule::__construct + * @dataProvider provideConstructor + */ + public function testConstructor( $params ) { + $module = new ResourceLoaderWikiModule( $params ); + $this->assertInstanceOf( 'ResourceLoaderWikiModule', $module ); + } + + public static function provideConstructor() { + return array( + // Nothing + array( null ), + array( array() ), + // Unrecognized settings + array( array( 'foo' => 'baz' ) ), + // Real settings + array( array( 'scripts' => array( 'MediaWiki:Common.js' ) ) ), + ); + } + + /** + * @dataProvider provideGetPages + * @covers ResourceLoaderWikiModule::getPages + */ + public function testGetPages( $params, Config $config, $expected ) { + $module = new ResourceLoaderWikiModule( $params ); + $module->setConfig( $config ); + + // Use getDefinitionSummary because getPages is protected + $summary = $module->getDefinitionSummary( ResourceLoaderContext::newDummyContext() ); + $this->assertEquals( + $expected, + $summary['pages'] + ); + } + + public static function provideGetPages() { + $settings = array( + 'UseSiteJs' => true, + 'UseSiteCss' => true, + ); + + $params = array( + 'styles' => array( 'MediaWiki:Common.css' ), + 'scripts' => array( 'MediaWiki:Common.js' ), + ); + + return array( + array( array(), new HashConfig( $settings ), array() ), + array( $params, new HashConfig( $settings ), array( + 'MediaWiki:Common.js' => array( 'type' => 'script' ), + 'MediaWiki:Common.css' => array( 'type' => 'style' ) + ) ), + array( $params, new HashConfig( array( 'UseSiteCss' => false ) + $settings ), array( + 'MediaWiki:Common.js' => array( 'type' => 'script' ), + ) ), + array( $params, new HashConfig( array( 'UseSiteJs' => false ) + $settings ), array( + 'MediaWiki:Common.css' => array( 'type' => 'style' ), + ) ), + array( $params, new HashConfig( array( 'UseSiteJs' => false, 'UseSiteCss' => false ) ), array() ), + ); + } + + /** + * @covers ResourceLoaderWikiModule::getGroup + * @dataProvider provideGetGroup + */ + public function testGetGroup( $params, $expected ) { + $module = new ResourceLoaderWikiModule( $params ); + $this->assertEquals( $expected, $module->getGroup() ); + } + + public static function provideGetGroup() { + return array( + // No group specified + array( array(), null ), + // A random group + array( array( 'group' => 'foobar' ), 'foobar' ), + ); + } + + /** * @covers ResourceLoaderWikiModule::isKnownEmpty * @dataProvider provideIsKnownEmpty */ public function testIsKnownEmpty( $titleInfo, $group, $expected ) { - $module = $this->getMockBuilder( 'ResourceLoaderWikiModuleTestModule' ) + $module = $this->getMockBuilder( 'ResourceLoaderWikiModule' ) ->setMethods( array( 'getTitleInfo', 'getGroup' ) ) ->getMock(); $module->expects( $this->any() ) diff --git a/tests/phpunit/includes/resourceloader/templates/template.html b/tests/phpunit/includes/resourceloader/templates/template.html new file mode 100644 index 00000000..1f6a7d22 --- /dev/null +++ b/tests/phpunit/includes/resourceloader/templates/template.html @@ -0,0 +1 @@ +<strong>hello</strong> diff --git a/tests/phpunit/includes/resourceloader/templates/template2.html b/tests/phpunit/includes/resourceloader/templates/template2.html new file mode 100644 index 00000000..a322f67d --- /dev/null +++ b/tests/phpunit/includes/resourceloader/templates/template2.html @@ -0,0 +1 @@ +<div>goodbye</div> diff --git a/tests/phpunit/includes/resourceloader/templates/template_awesome.handlebars b/tests/phpunit/includes/resourceloader/templates/template_awesome.handlebars new file mode 100644 index 00000000..5f5c07d5 --- /dev/null +++ b/tests/phpunit/includes/resourceloader/templates/template_awesome.handlebars @@ -0,0 +1 @@ +wow diff --git a/tests/phpunit/includes/search/SearchEngineTest.php b/tests/phpunit/includes/search/SearchEngineTest.php index 3da13615..d0cbfa0a 100644 --- a/tests/phpunit/includes/search/SearchEngineTest.php +++ b/tests/phpunit/includes/search/SearchEngineTest.php @@ -14,8 +14,6 @@ class SearchEngineTest extends MediaWikiLangTestCase { */ protected $search; - protected $pageList; - /** * Checks for database type & version. * Will skip current test if DB does not support search. @@ -37,10 +35,6 @@ class SearchEngineTest extends MediaWikiLangTestCase { 'wgSearchType' => $searchType ) ); - if ( !isset( self::$pageList ) ) { - $this->addPages(); - } - $this->search = new $searchType( $this->db ); } @@ -50,33 +44,32 @@ class SearchEngineTest extends MediaWikiLangTestCase { parent::tearDown(); } - protected function addPages() { + public function addDBData() { if ( !$this->isWikitextNS( NS_MAIN ) ) { // @todo cover the case of non-wikitext content in the main namespace return; } - $this->insertPage( "Not_Main_Page", "This is not a main page", 0 ); + $this->insertPage( 'Not_Main_Page', 'This is not a main page' ); $this->insertPage( 'Talk:Not_Main_Page', - 'This is not a talk page to the main page, see [[smithee]]', - 1 + 'This is not a talk page to the main page, see [[smithee]]' ); - $this->insertPage( 'Smithee', 'A smithee is one who smiths. See also [[Alan Smithee]]', 0 ); - $this->insertPage( 'Talk:Smithee', 'This article sucks.', 1 ); - $this->insertPage( 'Unrelated_page', 'Nothing in this page is about the S word.', 0 ); - $this->insertPage( 'Another_page', 'This page also is unrelated.', 0 ); - $this->insertPage( 'Help:Help', 'Help me!', 4 ); - $this->insertPage( 'Thppt', 'Blah blah', 0 ); - $this->insertPage( 'Alan_Smithee', 'yum', 0 ); - $this->insertPage( 'Pages', 'are\'food', 0 ); - $this->insertPage( 'HalfOneUp', 'AZ', 0 ); - $this->insertPage( 'FullOneUp', 'AZ', 0 ); - $this->insertPage( 'HalfTwoLow', 'az', 0 ); - $this->insertPage( 'FullTwoLow', 'az', 0 ); - $this->insertPage( 'HalfNumbers', '1234567890', 0 ); - $this->insertPage( 'FullNumbers', '1234567890', 0 ); - $this->insertPage( 'DomainName', 'example.com', 0 ); + $this->insertPage( 'Smithee', 'A smithee is one who smiths. See also [[Alan Smithee]]' ); + $this->insertPage( 'Talk:Smithee', 'This article sucks.' ); + $this->insertPage( 'Unrelated_page', 'Nothing in this page is about the S word.' ); + $this->insertPage( 'Another_page', 'This page also is unrelated.' ); + $this->insertPage( 'Help:Help', 'Help me!' ); + $this->insertPage( 'Thppt', 'Blah blah' ); + $this->insertPage( 'Alan_Smithee', 'yum' ); + $this->insertPage( 'Pages', 'are\'food' ); + $this->insertPage( 'HalfOneUp', 'AZ' ); + $this->insertPage( 'FullOneUp', 'AZ' ); + $this->insertPage( 'HalfTwoLow', 'az' ); + $this->insertPage( 'FullTwoLow', 'az' ); + $this->insertPage( 'HalfNumbers', '1234567890' ); + $this->insertPage( 'FullNumbers', '1234567890' ); + $this->insertPage( 'DomainName', 'example.com' ); } protected function fetchIds( $results ) { @@ -101,30 +94,6 @@ class SearchEngineTest extends MediaWikiLangTestCase { return $matches; } - /** - * Insert a new page - * - * @param string $pageName Page name - * @param string $text Page's content - * @param int $ns Unused - */ - protected function insertPage( $pageName, $text, $ns ) { - $title = Title::newFromText( $pageName, $ns ); - - $user = User::newFromName( 'WikiSysop' ); - $comment = 'Search Test'; - - // avoid memory leak...? - LinkCache::singleton()->clear(); - - $page = WikiPage::factory( $title ); - $page->doEditContent( ContentHandler::makeContent( $text, $title ), $comment, 0, false, $user ); - - $this->pageList[] = array( $title, $page->getId() ); - - return true; - } - public function testFullWidth() { $this->assertEquals( array( 'FullOneUp', 'FullTwoLow', 'HalfOneUp', 'HalfTwoLow' ), diff --git a/tests/phpunit/includes/site/CachingSiteStoreTest.php b/tests/phpunit/includes/site/CachingSiteStoreTest.php new file mode 100644 index 00000000..d0a79803 --- /dev/null +++ b/tests/phpunit/includes/site/CachingSiteStoreTest.php @@ -0,0 +1,161 @@ +<?php + +/** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + * @since 1.25 + * + * @ingroup Site + * @ingroup Test + * + * @group Site + * @group Database + * + * @author Jeroen De Dauw < jeroendedauw@gmail.com > + */ +class CachingSiteStoreTest extends MediaWikiTestCase { + + /** + * @covers CachingSiteStore::getSites + */ + public function testGetSites() { + $testSites = TestSites::getSites(); + + $store = new CachingSiteStore( + $this->getHashSiteStore( $testSites ), + wfGetMainCache() + ); + + $sites = $store->getSites(); + + $this->assertInstanceOf( 'SiteList', $sites ); + + /** + * @var Site $site + */ + foreach ( $sites as $site ) { + $this->assertInstanceOf( 'Site', $site ); + } + + foreach ( $testSites as $site ) { + if ( $site->getGlobalId() !== null ) { + $this->assertTrue( $sites->hasSite( $site->getGlobalId() ) ); + } + } + } + + /** + * @covers CachingSiteStore::saveSites + */ + public function testSaveSites() { + $store = new CachingSiteStore( new HashSiteStore(), wfGetMainCache() ); + + $sites = array(); + + $site = new Site(); + $site->setGlobalId( 'ertrywuutr' ); + $site->setLanguageCode( 'en' ); + $sites[] = $site; + + $site = new MediaWikiSite(); + $site->setGlobalId( 'sdfhxujgkfpth' ); + $site->setLanguageCode( 'nl' ); + $sites[] = $site; + + $this->assertTrue( $store->saveSites( $sites ) ); + + $site = $store->getSite( 'ertrywuutr' ); + $this->assertInstanceOf( 'Site', $site ); + $this->assertEquals( 'en', $site->getLanguageCode() ); + + $site = $store->getSite( 'sdfhxujgkfpth' ); + $this->assertInstanceOf( 'Site', $site ); + $this->assertEquals( 'nl', $site->getLanguageCode() ); + } + + /** + * @covers CachingSiteStore::reset + */ + public function testReset() { + $dbSiteStore = $this->getMockBuilder( 'SiteStore' ) + ->disableOriginalConstructor() + ->getMock(); + + // php 5.3 compatibility! + $self = $this; + + $dbSiteStore->expects( $this->any() ) + ->method( 'getSite' ) + ->will( $this->returnValue( $self->getTestSite() ) ); + + $dbSiteStore->expects( $this->any() ) + ->method( 'getSites' ) + ->will( $this->returnCallback( function() use( $self ) { + $siteList = new SiteList(); + $siteList->setSite( $self->getTestSite() ); + + return $siteList; + } ) ); + + $store = new CachingSiteStore( $dbSiteStore, wfGetMainCache() ); + + // initialize internal cache + $this->assertGreaterThan( 0, $store->getSites()->count(), 'count sites' ); + + $store->getSite( 'enwiki' )->setLanguageCode( 'en-ca' ); + + // sanity check: $store should have the new language code for 'enwiki' + $this->assertEquals( 'en-ca', $store->getSite( 'enwiki' )->getLanguageCode(), 'sanity check' ); + + // purge cache + $store->reset(); + + // the internal cache of $store should be updated, and now pulling + // the site from the 'fallback' DBSiteStore with the original language code. + $this->assertEquals( 'en', $store->getSite( 'enwiki' )->getLanguageCode(), 'reset' ); + } + + public function getTestSite() { + $enwiki = new MediaWikiSite(); + $enwiki->setGlobalId( 'enwiki' ); + $enwiki->setLanguageCode( 'en' ); + + return $enwiki; + } + + /** + * @covers CachingSiteStore::clear + */ + public function testClear() { + $store = new CachingSiteStore( new HashSiteStore(), wfGetMainCache() ); + $this->assertTrue( $store->clear() ); + + $site = $store->getSite( 'enwiki' ); + $this->assertNull( $site ); + + $sites = $store->getSites(); + $this->assertEquals( 0, $sites->count() ); + } + + private function getHashSiteStore( array $sites ) { + $siteStore = new HashSiteStore(); + $siteStore->saveSites( $sites ); + + return $siteStore; + } + +} diff --git a/tests/phpunit/includes/site/DBSiteStoreTest.php b/tests/phpunit/includes/site/DBSiteStoreTest.php new file mode 100644 index 00000000..673ba54d --- /dev/null +++ b/tests/phpunit/includes/site/DBSiteStoreTest.php @@ -0,0 +1,133 @@ +<?php + +/** + * Tests for the DBSiteStore class. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + * @since 1.21 + * + * @ingroup Site + * @ingroup Test + * + * @group Site + * @group Database + * + * @author Jeroen De Dauw < jeroendedauw@gmail.com > + */ +class DBSiteStoreTest extends MediaWikiTestCase { + + /** + * @covers DBSiteStore::getSites + */ + public function testGetSites() { + $expectedSites = TestSites::getSites(); + TestSites::insertIntoDb(); + + $store = new DBSiteStore(); + + $sites = $store->getSites(); + + $this->assertInstanceOf( 'SiteList', $sites ); + + /** + * @var Site $site + */ + foreach ( $sites as $site ) { + $this->assertInstanceOf( 'Site', $site ); + } + + foreach ( $expectedSites as $site ) { + if ( $site->getGlobalId() !== null ) { + $this->assertTrue( $sites->hasSite( $site->getGlobalId() ) ); + } + } + } + + /** + * @covers DBSiteStore::saveSites + */ + public function testSaveSites() { + $store = new DBSiteStore(); + + $sites = array(); + + $site = new Site(); + $site->setGlobalId( 'ertrywuutr' ); + $site->setLanguageCode( 'en' ); + $sites[] = $site; + + $site = new MediaWikiSite(); + $site->setGlobalId( 'sdfhxujgkfpth' ); + $site->setLanguageCode( 'nl' ); + $sites[] = $site; + + $this->assertTrue( $store->saveSites( $sites ) ); + + $site = $store->getSite( 'ertrywuutr' ); + $this->assertInstanceOf( 'Site', $site ); + $this->assertEquals( 'en', $site->getLanguageCode() ); + $this->assertTrue( is_integer( $site->getInternalId() ) ); + $this->assertTrue( $site->getInternalId() >= 0 ); + + $site = $store->getSite( 'sdfhxujgkfpth' ); + $this->assertInstanceOf( 'Site', $site ); + $this->assertEquals( 'nl', $site->getLanguageCode() ); + $this->assertTrue( is_integer( $site->getInternalId() ) ); + $this->assertTrue( $site->getInternalId() >= 0 ); + } + + /** + * @covers DBSiteStore::reset + */ + public function testReset() { + $store1 = new DBSiteStore(); + $store2 = new DBSiteStore(); + + // initialize internal cache + $this->assertGreaterThan( 0, $store1->getSites()->count() ); + $this->assertGreaterThan( 0, $store2->getSites()->count() ); + + // Clear actual data. Will purge the external cache and reset the internal + // cache in $store1, but not the internal cache in store2. + $this->assertTrue( $store1->clear() ); + + // sanity check: $store2 should have a stale cache now + $this->assertNotNull( $store2->getSite( 'enwiki' ) ); + + // purge cache + $store2->reset(); + + // ...now the internal cache of $store2 should be updated and thus empty. + $site = $store2->getSite( 'enwiki' ); + $this->assertNull( $site ); + } + + /** + * @covers DBSiteStore::clear + */ + public function testClear() { + $store = new DBSiteStore(); + $this->assertTrue( $store->clear() ); + + $site = $store->getSite( 'enwiki' ); + $this->assertNull( $site ); + + $sites = $store->getSites(); + $this->assertEquals( 0, $sites->count() ); + } +} diff --git a/tests/phpunit/includes/site/FileBasedSiteLookupTest.php b/tests/phpunit/includes/site/FileBasedSiteLookupTest.php new file mode 100644 index 00000000..90ebe5c4 --- /dev/null +++ b/tests/phpunit/includes/site/FileBasedSiteLookupTest.php @@ -0,0 +1,101 @@ +<?php + +/** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + * @since 1.25 + * + * @ingroup Site + * @ingroup Test + * + * @covers FileBasedSiteLookup + * @group Site + * + * @author Katie Filbert < aude.wiki@gmail.com > + */ +class FileBasedSiteLookupTest extends PHPUnit_Framework_TestCase { + + protected function setUp() { + $this->cacheFile = $this->getCacheFile(); + } + + protected function tearDown() { + unlink( $this->cacheFile ); + } + + public function testGetSites() { + $sites = $this->getSites(); + $cacheBuilder = $this->newSitesCacheFileBuilder( $sites ); + $cacheBuilder->build(); + + $cache = new FileBasedSiteLookup( $this->cacheFile ); + $this->assertEquals( $sites, $cache->getSites() ); + } + + public function testGetSite() { + $sites = $this->getSites(); + $cacheBuilder = $this->newSitesCacheFileBuilder( $sites ); + $cacheBuilder->build(); + + $cache = new FileBasedSiteLookup( $this->cacheFile ); + + $this->assertEquals( $sites->getSite( 'enwiktionary' ), $cache->getSite( 'enwiktionary' ) ); + } + + private function newSitesCacheFileBuilder( SiteList $sites ) { + return new SitesCacheFileBuilder( + $this->getSiteLookup( $sites ), + $this->cacheFile + ); + } + + private function getSiteLookup( SiteList $sites ) { + $siteLookup = $this->getMockBuilder( 'SiteLookup' ) + ->disableOriginalConstructor() + ->getMock(); + + $siteLookup->expects( $this->any() ) + ->method( 'getSites' ) + ->will( $this->returnValue( $sites ) ); + + return $siteLookup; + } + + private function getSites() { + $sites = array(); + + $site = new Site(); + $site->setGlobalId( 'foobar' ); + $sites[] = $site; + + $site = new MediaWikiSite(); + $site->setGlobalId( 'enwiktionary' ); + $site->setGroup( 'wiktionary' ); + $site->setLanguageCode( 'en' ); + $site->addNavigationId( 'enwiktionary' ); + $site->setPath( MediaWikiSite::PATH_PAGE, "https://en.wiktionary.org/wiki/$1" ); + $site->setPath( MediaWikiSite::PATH_FILE, "https://en.wiktionary.org/w/$1" ); + $sites[] = $site; + + return new SiteList( $sites ); + } + + private function getCacheFile() { + return tempnam( sys_get_temp_dir(), 'mw-test-sitelist' ); + } + +} diff --git a/tests/phpunit/includes/site/HashSiteStoreTest.php b/tests/phpunit/includes/site/HashSiteStoreTest.php new file mode 100644 index 00000000..49a96338 --- /dev/null +++ b/tests/phpunit/includes/site/HashSiteStoreTest.php @@ -0,0 +1,105 @@ +<?php + +/** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + * @since 1.25 + * + * @ingroup Site + * @group Site + * + * @author Katie Filbert < aude.wiki@gmail.com > + */ +class HashSiteStoreTest extends MediaWikiTestCase { + + /** + * @covers HashSiteStore::getSites + */ + public function testGetSites() { + $expectedSites = array(); + + foreach( TestSites::getSites() as $testSite ) { + $siteId = $testSite->getGlobalId(); + $expectedSites[$siteId] = $testSite; + } + + $siteStore = new HashSiteStore( $expectedSites ); + + $this->assertEquals( new SiteList( $expectedSites ), $siteStore->getSites() ); + } + + /** + * @covers HashSiteStore::saveSite + * @covers HashSiteStore::getSite + */ + public function testSaveSite() { + $store = new HashSiteStore(); + + $site = new Site(); + $site->setGlobalId( 'dewiki' ); + + $this->assertCount( 0, $store->getSites(), '0 sites in store' ); + + $store->saveSite( $site ); + + $this->assertCount( 1, $store->getSites(), 'Store has 1 sites' ); + $this->assertEquals( $site, $store->getSite( 'dewiki' ), 'Store has dewiki' ); + } + + /** + * @covers HashSiteStore::saveSites + */ + public function testSaveSites() { + $store = new HashSiteStore(); + + $sites = array(); + + $site = new Site(); + $site->setGlobalId( 'enwiki' ); + $site->setLanguageCode( 'en' ); + $sites[] = $site; + + $site = new MediaWikiSite(); + $site->setGlobalId( 'eswiki' ); + $site->setLanguageCode( 'es' ); + $sites[] = $site; + + $this->assertCount( 0, $store->getSites(), '0 sites in store' ); + + $store->saveSites( $sites ); + + $this->assertCount( 2, $store->getSites(), 'Store has 2 sites' ); + $this->assertTrue( $store->getSites()->hasSite( 'enwiki' ), 'Store has enwiki' ); + $this->assertTrue( $store->getSites()->hasSite( 'eswiki' ), 'Store has eswiki' ); + } + + /** + * @covers HashSiteStore::clear + */ + public function testClear() { + $store = new HashSiteStore(); + + $site = new Site(); + $site->setGlobalId( 'arwiki' ); + $store->saveSite( $site ); + + $this->assertCount( 1, $store->getSites(), '1 site in store' ); + + $store->clear(); + $this->assertCount( 0, $store->getSites(), '0 sites in store' ); + } +} diff --git a/tests/phpunit/includes/site/MediaWikiSiteTest.php b/tests/phpunit/includes/site/MediaWikiSiteTest.php index c3fd1557..ef2ccca2 100644 --- a/tests/phpunit/includes/site/MediaWikiSiteTest.php +++ b/tests/phpunit/includes/site/MediaWikiSiteTest.php @@ -26,7 +26,6 @@ * * @group Site * - * @licence GNU GPL v2+ * @author Jeroen De Dauw < jeroendedauw@gmail.com > */ class MediaWikiSiteTest extends SiteTest { diff --git a/tests/phpunit/includes/site/SiteExporterTest.php b/tests/phpunit/includes/site/SiteExporterTest.php new file mode 100644 index 00000000..19dd0aa1 --- /dev/null +++ b/tests/phpunit/includes/site/SiteExporterTest.php @@ -0,0 +1,147 @@ +<?php + +/** + * Tests for the SiteExporter class. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + * + * @ingroup Site + * @ingroup Test + * + * @group Site + * + * @covers SiteExporter + * + * @author Daniel Kinzler + */ +class SiteExporterTest extends PHPUnit_Framework_TestCase { + + public function testConstructor_InvalidArgument() { + $this->setExpectedException( 'InvalidArgumentException' ); + + new SiteExporter( 'Foo' ); + } + + public function testExportSites() { + $foo = Site::newForType( Site::TYPE_UNKNOWN ); + $foo->setGlobalId( 'Foo' ); + + $acme = Site::newForType( Site::TYPE_UNKNOWN ); + $acme->setGlobalId( 'acme.com' ); + $acme->setGroup( 'Test' ); + $acme->addLocalId( Site::ID_INTERWIKI, 'acme' ); + $acme->setPath( Site::PATH_LINK, 'http://acme.com/' ); + + $tmp = tmpfile(); + $exporter = new SiteExporter( $tmp ); + + $exporter->exportSites( array( $foo, $acme ) ); + + fseek( $tmp, 0 ); + $xml = fread( $tmp, 16*1024 ); + + $this->assertContains( '<sites ', $xml ); + $this->assertContains( '<site>', $xml ); + $this->assertContains( '<globalid>Foo</globalid>', $xml ); + $this->assertContains( '</site>', $xml ); + $this->assertContains( '<globalid>acme.com</globalid>', $xml ); + $this->assertContains( '<group>Test</group>', $xml ); + $this->assertContains( '<localid type="interwiki">acme</localid>', $xml ); + $this->assertContains( '<path type="link">http://acme.com/</path>', $xml ); + $this->assertContains( '</sites>', $xml ); + + // NOTE: HHVM (at least on wmf Jenkins) doesn't like file URLs. + $xsdFile = __DIR__ . '/../../../../docs/sitelist-1.0.xsd'; + $xsdData = file_get_contents( $xsdFile ); + + $document = new DOMDocument(); + $document->loadXML( $xml, LIBXML_NONET ); + $document->schemaValidateSource( $xsdData ); + } + + private function newSiteStore( SiteList $sites ) { + $store = $this->getMock( 'SiteStore' ); + + $store->expects( $this->once() ) + ->method( 'saveSites' ) + ->will( $this->returnCallback( function ( $moreSites ) use ( $sites ) { + foreach ( $moreSites as $site ) { + $sites->setSite( $site ); + } + } ) ); + + $store->expects( $this->any() ) + ->method( 'getSites' ) + ->will( $this->returnValue( new SiteList() ) ); + + return $store; + } + + public function provideRoundTrip() { + $foo = Site::newForType( Site::TYPE_UNKNOWN ); + $foo->setGlobalId( 'Foo' ); + + $acme = Site::newForType( Site::TYPE_UNKNOWN ); + $acme->setGlobalId( 'acme.com' ); + $acme->setGroup( 'Test' ); + $acme->addLocalId( Site::ID_INTERWIKI, 'acme' ); + $acme->setPath( Site::PATH_LINK, 'http://acme.com/' ); + + $dewiki = Site::newForType( Site::TYPE_MEDIAWIKI ); + $dewiki->setGlobalId( 'dewiki' ); + $dewiki->setGroup( 'wikipedia' ); + $dewiki->setForward( true ); + $dewiki->addLocalId( Site::ID_INTERWIKI, 'wikipedia' ); + $dewiki->addLocalId( Site::ID_EQUIVALENT, 'de' ); + $dewiki->setPath( Site::PATH_LINK, 'http://de.wikipedia.org/w/' ); + $dewiki->setPath( MediaWikiSite::PATH_PAGE, 'http://de.wikipedia.org/wiki/' ); + $dewiki->setSource( 'meta.wikimedia.org' ); + + return array( + 'empty' => array( + new SiteList() + ), + + 'some' => array( + new SiteList( array( $foo, $acme, $dewiki ) ), + ), + ); + } + + /** + * @dataProvider provideRoundTrip() + */ + public function testRoundTrip( SiteList $sites ) { + $tmp = tmpfile(); + $exporter = new SiteExporter( $tmp ); + + $exporter->exportSites( $sites ); + + fseek( $tmp, 0 ); + $xml = fread( $tmp, 16*1024 ); + + $actualSites = new SiteList(); + $store = $this->newSiteStore( $actualSites ); + + $importer = new SiteImporter( $store ); + $importer->importFromXML( $xml ); + + $this->assertEquals( $sites, $actualSites ); + } + +} diff --git a/tests/phpunit/includes/site/SiteImporterTest.php b/tests/phpunit/includes/site/SiteImporterTest.php new file mode 100644 index 00000000..cb0316ab --- /dev/null +++ b/tests/phpunit/includes/site/SiteImporterTest.php @@ -0,0 +1,200 @@ +<?php + +/** + * Tests for the SiteImporter class. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + * + * @ingroup Site + * @ingroup Test + * + * @group Site + * + * @covers SiteImporter + * + * @author Daniel Kinzler + */ +class SiteImporterTest extends PHPUnit_Framework_TestCase { + + private function newSiteImporter( array $expectedSites, $errorCount ) { + $store = $this->getMock( 'SiteStore' ); + + $self = $this; + $store->expects( $this->once() ) + ->method( 'saveSites' ) + ->will( $this->returnCallback( function ( $sites ) use ( $expectedSites, $self ) { + $self->assertSitesEqual( $expectedSites, $sites ); + } ) ); + + $store->expects( $this->any() ) + ->method( 'getSites' ) + ->will( $this->returnValue( new SiteList() ) ); + + $errorHandler = $this->getMock( 'Psr\Log\LoggerInterface' ); + $errorHandler->expects( $this->exactly( $errorCount ) ) + ->method( 'error' ); + + $importer = new SiteImporter( $store ); + $importer->setExceptionCallback( array( $errorHandler, 'error' ) ); + + return $importer; + } + + public function assertSitesEqual( $expected, $actual, $message = '' ) { + $this->assertEquals( + $this->getSerializedSiteList( $expected ), + $this->getSerializedSiteList( $actual ), + $message + ); + } + + public function provideImportFromXML() { + $foo = Site::newForType( Site::TYPE_UNKNOWN ); + $foo->setGlobalId( 'Foo' ); + + $acme = Site::newForType( Site::TYPE_UNKNOWN ); + $acme->setGlobalId( 'acme.com' ); + $acme->setGroup( 'Test' ); + $acme->addLocalId( Site::ID_INTERWIKI, 'acme' ); + $acme->setPath( Site::PATH_LINK, 'http://acme.com/' ); + + $dewiki = Site::newForType( Site::TYPE_MEDIAWIKI ); + $dewiki->setGlobalId( 'dewiki' ); + $dewiki->setGroup( 'wikipedia' ); + $dewiki->setForward( true ); + $dewiki->addLocalId( Site::ID_INTERWIKI, 'wikipedia' ); + $dewiki->addLocalId( Site::ID_EQUIVALENT, 'de' ); + $dewiki->setPath( Site::PATH_LINK, 'http://de.wikipedia.org/w/' ); + $dewiki->setPath( MediaWikiSite::PATH_PAGE, 'http://de.wikipedia.org/wiki/' ); + $dewiki->setSource( 'meta.wikimedia.org' ); + + return array( + 'empty' => array( + '<sites></sites>', + array(), + ), + 'no sites' => array( + '<sites><Foo><globalid>Foo</globalid></Foo><Bar><quux>Bla</quux></Bar></sites>', + array(), + ), + 'minimal' => array( + '<sites>' . + '<site><globalid>Foo</globalid></site>' . + '</sites>', + array( $foo ), + ), + 'full' => array( + '<sites>' . + '<site><globalid>Foo</globalid></site>' . + '<site>' . + '<globalid>acme.com</globalid>' . + '<localid type="interwiki">acme</localid>' . + '<group>Test</group>' . + '<path type="link">http://acme.com/</path>' . + '</site>' . + '<site type="mediawiki">' . + '<source>meta.wikimedia.org</source>' . + '<globalid>dewiki</globalid>' . + '<localid type="interwiki">wikipedia</localid>' . + '<localid type="equivalent">de</localid>' . + '<group>wikipedia</group>' . + '<forward/>' . + '<path type="link">http://de.wikipedia.org/w/</path>' . + '<path type="page_path">http://de.wikipedia.org/wiki/</path>' . + '</site>' . + '</sites>', + array( $foo, $acme, $dewiki ), + ), + 'skip' => array( + '<sites>' . + '<site><globalid>Foo</globalid></site>' . + '<site><barf>Foo</barf></site>' . + '<site>' . + '<globalid>acme.com</globalid>' . + '<localid type="interwiki">acme</localid>' . + '<silly>boop!</silly>' . + '<group>Test</group>' . + '<path type="link">http://acme.com/</path>' . + '</site>' . + '</sites>', + array( $foo, $acme ), + 1 + ), + ); + } + + /** + * @dataProvider provideImportFromXML + */ + public function testImportFromXML( $xml, array $expectedSites, $errorCount = 0 ) { + $importer = $this->newSiteImporter( $expectedSites, $errorCount ); + $importer->importFromXML( $xml ); + } + + public function testImportFromXML_malformed() { + $this->setExpectedException( 'Exception' ); + + $store = $this->getMock( 'SiteStore' ); + $importer = new SiteImporter( $store ); + $importer->importFromXML( 'THIS IS NOT XML' ); + } + + public function testImportFromFile() { + $foo = Site::newForType( Site::TYPE_UNKNOWN ); + $foo->setGlobalId( 'Foo' ); + + $acme = Site::newForType( Site::TYPE_UNKNOWN ); + $acme->setGlobalId( 'acme.com' ); + $acme->setGroup( 'Test' ); + $acme->addLocalId( Site::ID_INTERWIKI, 'acme' ); + $acme->setPath( Site::PATH_LINK, 'http://acme.com/' ); + + $dewiki = Site::newForType( Site::TYPE_MEDIAWIKI ); + $dewiki->setGlobalId( 'dewiki' ); + $dewiki->setGroup( 'wikipedia' ); + $dewiki->setForward( true ); + $dewiki->addLocalId( Site::ID_INTERWIKI, 'wikipedia' ); + $dewiki->addLocalId( Site::ID_EQUIVALENT, 'de' ); + $dewiki->setPath( Site::PATH_LINK, 'http://de.wikipedia.org/w/' ); + $dewiki->setPath( MediaWikiSite::PATH_PAGE, 'http://de.wikipedia.org/wiki/' ); + $dewiki->setSource( 'meta.wikimedia.org' ); + + $importer = $this->newSiteImporter( array( $foo, $acme, $dewiki ), 0 ); + + $file = __DIR__ . '/SiteImporterTest.xml'; + $importer->importFromFile( $file ); + } + + /** + * @param Site[] $sites + * + * @return array[] + */ + private function getSerializedSiteList( $sites ) { + $serialized = array(); + + foreach ( $sites as $site ) { + $key = $site->getGlobalId(); + $data = unserialize( $site->serialize() ); + + $serialized[$key] = $data; + } + + return $serialized; + } +} diff --git a/tests/phpunit/includes/site/SiteImporterTest.xml b/tests/phpunit/includes/site/SiteImporterTest.xml new file mode 100644 index 00000000..720b1faf --- /dev/null +++ b/tests/phpunit/includes/site/SiteImporterTest.xml @@ -0,0 +1,19 @@ +<sites version="1.0" xmlns="http://www.mediawiki.org/xml/sitelist-1.0/"> + <site><globalid>Foo</globalid></site> + <site> + <globalid>acme.com</globalid> + <localid type="interwiki">acme</localid> + <group>Test</group> + <path type="link">http://acme.com/</path> + </site> + <site type="mediawiki"> + <source>meta.wikimedia.org</source> + <globalid>dewiki</globalid> + <localid type="interwiki">wikipedia</localid> + <localid type="equivalent">de</localid> + <group>wikipedia</group> + <forward/> + <path type="link">http://de.wikipedia.org/w/</path> + <path type="page_path">http://de.wikipedia.org/wiki/</path> + </site> +</sites> diff --git a/tests/phpunit/includes/site/SiteListTest.php b/tests/phpunit/includes/site/SiteListTest.php index 534ed9c9..d6c58cf6 100644 --- a/tests/phpunit/includes/site/SiteListTest.php +++ b/tests/phpunit/includes/site/SiteListTest.php @@ -26,7 +26,6 @@ * * @group Site * - * @licence GNU GPL v2+ * @author Jeroen De Dauw < jeroendedauw@gmail.com > */ class SiteListTest extends MediaWikiTestCase { diff --git a/tests/phpunit/includes/site/SiteSQLStoreTest.php b/tests/phpunit/includes/site/SiteSQLStoreTest.php index 6002c1a1..69088006 100644 --- a/tests/phpunit/includes/site/SiteSQLStoreTest.php +++ b/tests/phpunit/includes/site/SiteSQLStoreTest.php @@ -1,8 +1,6 @@ <?php /** - * Tests for the SiteSQLStore class. - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -19,7 +17,7 @@ * http://www.gnu.org/copyleft/gpl.html * * @file - * @since 1.21 + * @since 1.25 * * @ingroup Site * @ingroup Test @@ -27,108 +25,16 @@ * @group Site * @group Database * - * @licence GNU GPL v2+ - * @author Jeroen De Dauw < jeroendedauw@gmail.com > + * @author Katie Filbert < aude.wiki@gmail.com > */ class SiteSQLStoreTest extends MediaWikiTestCase { /** - * @covers SiteSQLStore::getSites - */ - public function testGetSites() { - $expectedSites = TestSites::getSites(); - TestSites::insertIntoDb(); - - $store = SiteSQLStore::newInstance(); - - $sites = $store->getSites(); - - $this->assertInstanceOf( 'SiteList', $sites ); - - /** - * @var Site $site - */ - foreach ( $sites as $site ) { - $this->assertInstanceOf( 'Site', $site ); - } - - foreach ( $expectedSites as $site ) { - if ( $site->getGlobalId() !== null ) { - $this->assertTrue( $sites->hasSite( $site->getGlobalId() ) ); - } - } - } - - /** - * @covers SiteSQLStore::saveSites - */ - public function testSaveSites() { - $store = SiteSQLStore::newInstance(); - - $sites = array(); - - $site = new Site(); - $site->setGlobalId( 'ertrywuutr' ); - $site->setLanguageCode( 'en' ); - $sites[] = $site; - - $site = new MediaWikiSite(); - $site->setGlobalId( 'sdfhxujgkfpth' ); - $site->setLanguageCode( 'nl' ); - $sites[] = $site; - - $this->assertTrue( $store->saveSites( $sites ) ); - - $site = $store->getSite( 'ertrywuutr' ); - $this->assertInstanceOf( 'Site', $site ); - $this->assertEquals( 'en', $site->getLanguageCode() ); - $this->assertTrue( is_integer( $site->getInternalId() ) ); - $this->assertTrue( $site->getInternalId() >= 0 ); - - $site = $store->getSite( 'sdfhxujgkfpth' ); - $this->assertInstanceOf( 'Site', $site ); - $this->assertEquals( 'nl', $site->getLanguageCode() ); - $this->assertTrue( is_integer( $site->getInternalId() ) ); - $this->assertTrue( $site->getInternalId() >= 0 ); - } - - /** - * @covers SiteSQLStore::reset + * @covers SiteSQLStore::newInstance */ - public function testReset() { - $store1 = SiteSQLStore::newInstance(); - $store2 = SiteSQLStore::newInstance(); - - // initialize internal cache - $this->assertGreaterThan( 0, $store1->getSites()->count() ); - $this->assertGreaterThan( 0, $store2->getSites()->count() ); - - // Clear actual data. Will purge the external cache and reset the internal - // cache in $store1, but not the internal cache in store2. - $this->assertTrue( $store1->clear() ); - - // sanity check: $store2 should have a stale cache now - $this->assertNotNull( $store2->getSite( 'enwiki' ) ); - - // purge cache - $store2->reset(); - - // ...now the internal cache of $store2 should be updated and thus empty. - $site = $store2->getSite( 'enwiki' ); - $this->assertNull( $site ); + public function testNewInstance() { + $siteStore = SiteSQLStore::newInstance(); + $this->assertInstanceOf( 'SiteSQLStore', $siteStore ); } - /** - * @covers SiteSQLStore::clear - */ - public function testClear() { - $store = SiteSQLStore::newInstance(); - $this->assertTrue( $store->clear() ); - - $site = $store->getSite( 'enwiki' ); - $this->assertNull( $site ); - - $sites = $store->getSites(); - $this->assertEquals( 0, $sites->count() ); - } } diff --git a/tests/phpunit/includes/site/SiteTest.php b/tests/phpunit/includes/site/SiteTest.php index 29c1ff33..63d90d2e 100644 --- a/tests/phpunit/includes/site/SiteTest.php +++ b/tests/phpunit/includes/site/SiteTest.php @@ -26,7 +26,6 @@ * * @group Site * - * @licence GNU GPL v2+ * @author Jeroen De Dauw < jeroendedauw@gmail.com > */ class SiteTest extends MediaWikiTestCase { diff --git a/tests/phpunit/includes/site/SitesCacheFileBuilderTest.php b/tests/phpunit/includes/site/SitesCacheFileBuilderTest.php new file mode 100644 index 00000000..087341a0 --- /dev/null +++ b/tests/phpunit/includes/site/SitesCacheFileBuilderTest.php @@ -0,0 +1,135 @@ +<?php + +/** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + * @since 1.25 + * + * @ingroup Site + * @ingroup Test + * + * @covers SitesCacheFileBuilder + * @group Site + * + * @author Katie Filbert < aude.wiki@gmail.com > + */ +class SitesCacheFileBuilderTest extends PHPUnit_Framework_TestCase { + + protected function setUp() { + $this->cacheFile = $this->getCacheFile(); + } + + protected function tearDown() { + unlink( $this->cacheFile ); + } + + public function testBuild() { + $cacheBuilder = $this->newSitesCacheFileBuilder( $this->getSites() ); + $cacheBuilder->build(); + + $contents = file_get_contents( $this->cacheFile ); + $this->assertEquals( json_encode( $this->getExpectedData() ), $contents ); + } + + private function getExpectedData() { + return array( + 'sites' => array( + 'foobar' => array( + 'globalid' => 'foobar', + 'type' => 'unknown', + 'group' => 'none', + 'source' => 'local', + 'language' => null, + 'localids' => array(), + 'config' => array(), + 'data' => array(), + 'forward' => false, + 'internalid' => null, + 'identifiers' => array() + ), + 'enwiktionary' => array( + 'globalid' => 'enwiktionary', + 'type' => 'mediawiki', + 'group' => 'wiktionary', + 'source' => 'local', + 'language' => 'en', + 'localids' => array( + 'equivalent' => array( 'enwiktionary' ) + ), + 'config' => array(), + 'data' => array( + 'paths' => array( + 'page_path' => 'https://en.wiktionary.org/wiki/$1', + 'file_path' => 'https://en.wiktionary.org/w/$1' + ) + ), + 'forward' => false, + 'internalid' => null, + 'identifiers' => array( + array( + 'type' => 'equivalent', + 'key' => 'enwiktionary' + ) + ) + ) + ) + ); + } + + private function newSitesCacheFileBuilder( SiteList $sites ) { + return new SitesCacheFileBuilder( + $this->getSiteLookup( $sites ), + $this->cacheFile + ); + } + + private function getSiteLookup( SiteList $sites ) { + $siteLookup = $this->getMockBuilder( 'SiteLookup' ) + ->disableOriginalConstructor() + ->getMock(); + + $siteLookup->expects( $this->any() ) + ->method( 'getSites' ) + ->will( $this->returnValue( $sites ) ); + + return $siteLookup; + } + + private function getSites() { + $sites = array(); + + $site = new Site(); + $site->setGlobalId( 'foobar' ); + $sites[] = $site; + + $site = new MediaWikiSite(); + $site->setGlobalId( 'enwiktionary' ); + $site->setGroup( 'wiktionary' ); + $site->setLanguageCode( 'en' ); + $site->addNavigationId( 'enwiktionary' ); + $site->setPath( MediaWikiSite::PATH_PAGE, "https://en.wiktionary.org/wiki/$1" ); + $site->setPath( MediaWikiSite::PATH_FILE, "https://en.wiktionary.org/w/$1" ); + $sites[] = $site; + + return new SiteList( $sites ); + } + + private function getCacheFile() { + return tempnam( sys_get_temp_dir(), 'mw-test-sitelist' ); + } + +} diff --git a/tests/phpunit/includes/site/TestSites.php b/tests/phpunit/includes/site/TestSites.php index af314ba2..4c402484 100644 --- a/tests/phpunit/includes/site/TestSites.php +++ b/tests/phpunit/includes/site/TestSites.php @@ -26,7 +26,6 @@ * * @group Site * - * @licence GNU GPL v2+ * @author Jeroen De Dauw < jeroendedauw@gmail.com > */ class TestSites { @@ -108,7 +107,7 @@ class TestSites { * @since 0.1 */ public static function insertIntoDb() { - $sitesTable = SiteSQLStore::newInstance(); + $sitesTable = new DBSiteStore(); $sitesTable->clear(); $sitesTable->saveSites( TestSites::getSites() ); } diff --git a/tests/phpunit/includes/skins/SkinTemplateTest.php b/tests/phpunit/includes/skins/SkinTemplateTest.php index baa995d4..8084a66f 100644 --- a/tests/phpunit/includes/skins/SkinTemplateTest.php +++ b/tests/phpunit/includes/skins/SkinTemplateTest.php @@ -5,7 +5,6 @@ * * @group Output * - * @licence GNU GPL v2+ * @author Bene* < benestar.wikimedia@gmail.com > */ diff --git a/tests/phpunit/includes/specialpage/SpecialPageFactoryTest.php b/tests/phpunit/includes/specialpage/SpecialPageFactoryTest.php index 779fa558..fd6911f6 100644 --- a/tests/phpunit/includes/specialpage/SpecialPageFactoryTest.php +++ b/tests/phpunit/includes/specialpage/SpecialPageFactoryTest.php @@ -28,21 +28,52 @@ class SpecialPageFactoryTest extends MediaWikiTestCase { SpecialPageFactory::resetList(); } + public function testResetList() { + SpecialPageFactory::resetList(); + $this->assertContains( 'Specialpages', SpecialPageFactory::getNames() ); + } + + public function testHookNotCalledTwice() { + $count = 0; + $this->mergeMwGlobalArrayValue( 'wgHooks', array( + 'SpecialPage_initList' => array( + function () use ( &$count ) { + $count++; + } + ) ) ); + SpecialPageFactory::resetList(); + SpecialPageFactory::getNames(); + SpecialPageFactory::getNames(); + $this->assertEquals( 1, $count ); + } + public function newSpecialAllPages() { return new SpecialAllPages(); } public function specialPageProvider() { + $specialPageTestHelper = new SpecialPageTestHelper(); + return array( 'class name' => array( 'SpecialAllPages', false ), - 'closure' => array( function() { + 'closure' => array( function () { return new SpecialAllPages(); }, false ), - 'function' => array( array( $this, 'newSpecialAllPages' ), false ), + 'function' => array( array( $this, 'newSpecialAllPages' ), false ), + 'callback string' => array( 'SpecialPageTestHelper::newSpecialAllPages', false ), + 'callback with object' => array( + array( $specialPageTestHelper, 'newSpecialAllPages' ), + false + ), + 'callback array' => array( + array( 'SpecialPageTestHelper', 'newSpecialAllPages' ), + false + ) ); } /** + * @covers SpecialPageFactory::getPage * @dataProvider specialPageProvider */ public function testGetPage( $spec, $shouldReuseInstance ) { @@ -56,6 +87,9 @@ class SpecialPageFactoryTest extends MediaWikiTestCase { $this->assertEquals( $shouldReuseInstance, $page2 === $page, "Should re-use instance:" ); } + /** + * @covers SpecialPageFactory::getNames + */ public function testGetNames() { $this->mergeMwGlobalArrayValue( 'wgSpecialPages', array( 'testdummy' => 'SpecialAllPages' ) ); SpecialPageFactory::resetList(); @@ -65,6 +99,9 @@ class SpecialPageFactoryTest extends MediaWikiTestCase { $this->assertContains( 'testdummy', $names ); } + /** + * @covers SpecialPageFactory::resolveAlias + */ public function testResolveAlias() { $this->setMwGlobals( 'wgContLang', Language::factory( 'de' ) ); SpecialPageFactory::resetList(); @@ -74,6 +111,9 @@ class SpecialPageFactoryTest extends MediaWikiTestCase { $this->assertEquals( 'Foo', $param ); } + /** + * @covers SpecialPageFactory::getLocalNameFor + */ public function testGetLocalNameFor() { $this->setMwGlobals( 'wgContLang', Language::factory( 'de' ) ); SpecialPageFactory::resetList(); @@ -82,6 +122,9 @@ class SpecialPageFactoryTest extends MediaWikiTestCase { $this->assertEquals( 'Spezialseiten/Foo', $name ); } + /** + * @covers SpecialPageFactory::getTitleForAlias + */ public function testGetTitleForAlias() { $this->setMwGlobals( 'wgContLang', Language::factory( 'de' ) ); SpecialPageFactory::resetList(); @@ -222,4 +265,19 @@ class SpecialPageFactoryTest extends MediaWikiTestCase { ); } + public function testGetAliasListRecursion() { + $called = false; + $this->mergeMwGlobalArrayValue( 'wgHooks', array( + 'SpecialPage_initList' => array( + function () use ( &$called ) { + SpecialPageFactory::getLocalNameFor( 'Specialpages' ); + $called = true; + } + ), + ) ); + SpecialPageFactory::resetList(); + SpecialPageFactory::getLocalNameFor( 'Specialpages' ); + $this->assertTrue( $called, 'Recursive call succeeded' ); + } + } diff --git a/tests/phpunit/includes/SpecialPageTest.php b/tests/phpunit/includes/specialpage/SpecialPageTest.php index 245cdffd..5a0aef97 100644 --- a/tests/phpunit/includes/SpecialPageTest.php +++ b/tests/phpunit/includes/specialpage/SpecialPageTest.php @@ -5,7 +5,6 @@ * * @group Database * - * @licence GNU GPL v2+ * @author Katie Filbert < aude.wiki@gmail.com > */ class SpecialPageTest extends MediaWikiTestCase { diff --git a/tests/phpunit/includes/specialpage/SpecialPageTestHelper.php b/tests/phpunit/includes/specialpage/SpecialPageTestHelper.php new file mode 100644 index 00000000..37e29dcb --- /dev/null +++ b/tests/phpunit/includes/specialpage/SpecialPageTestHelper.php @@ -0,0 +1,24 @@ +<?php +/** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + */ +class SpecialPageTestHelper { + + public static function newSpecialAllPages() { + return new SpecialAllPages(); + } + +} diff --git a/tests/phpunit/includes/specials/SpecialBooksourcesTest.php b/tests/phpunit/includes/specials/SpecialBooksourcesTest.php new file mode 100644 index 00000000..69485a03 --- /dev/null +++ b/tests/phpunit/includes/specials/SpecialBooksourcesTest.php @@ -0,0 +1,36 @@ +<?php +class SpecialBooksourcesTest extends MediaWikiTestCase { + public static function provideISBNs() { + return array( + array( '978-0-300-14424-6', true ), + array( '0-14-020652-3', true ), + array( '020652-3', false ), + array( '9781234567897', true ), + array( '1-4133-0454-0', true ), + array( '978-1413304541', true ), + array( '0136091814', true ), + array( '0136091812', false ), + array( '9780136091813', true ), + array( '9780136091817', false ), + array( '123456789X', true ), + + // Bug 67021 + array( '1413304541', false ), + array( '141330454X', false ), + array( '1413304540', true ), + array( '14133X4540', false ), + array( '97814133X4541', false ), + array( '978035642615X', false ), + array( '9781413304541', true ), + array( '9780356426150', true ), + ); + } + + /** + * @covers SpecialBookSources::isValidISBN + * @dataProvider provideISBNs + */ + public function testIsValidISBN( $isbn, $isValid ) { + $this->assertSame( $isValid, SpecialBookSources::isValidISBN( $isbn ) ); + } +} diff --git a/tests/phpunit/includes/specials/SpecialMIMESearchTest.php b/tests/phpunit/includes/specials/SpecialMIMESearchTest.php index 14d19685..fe1c9e83 100644 --- a/tests/phpunit/includes/specials/SpecialMIMESearchTest.php +++ b/tests/phpunit/includes/specials/SpecialMIMESearchTest.php @@ -5,11 +5,11 @@ class SpecialMIMESearchTest extends MediaWikiTestCase { - /** @var MIMESearchPage */ + /** @var MIMEsearchPage */ private $page; function setUp() { - $this->page = new MIMESearchPage; + $this->page = new MIMEsearchPage; $context = new RequestContext(); $context->setTitle( Title::makeTitle( NS_SPECIAL, 'MIMESearch' ) ); $context->setRequest( new FauxRequest() ); diff --git a/tests/phpunit/includes/title/ForeignTitleTest.php b/tests/phpunit/includes/title/ForeignTitleTest.php new file mode 100644 index 00000000..599d2a33 --- /dev/null +++ b/tests/phpunit/includes/title/ForeignTitleTest.php @@ -0,0 +1,103 @@ +<?php +/** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + * @author This, that and the other + */ + +/** + * @covers ForeignTitle + * + * @group Title + */ +class ForeignTitleTest extends MediaWikiTestCase { + + public function basicProvider() { + return array( + array( + new ForeignTitle( 20, 'Contributor', 'JohnDoe' ), + 20, 'Contributor', 'JohnDoe' + ), + array( + new ForeignTitle( '1', 'Discussion', 'Capital' ), + 1, 'Discussion', 'Capital' + ), + array( + new ForeignTitle( 0, '', 'MainNamespace' ), + 0, '', 'MainNamespace' + ), + array( + new ForeignTitle( 4, 'Some ns', 'Article title with spaces' ), + 4, 'Some_ns', 'Article_title_with_spaces' + ), + ); + } + + /** + * @dataProvider basicProvider + */ + public function testBasic( ForeignTitle $title, $expectedId, $expectedName, + $expectedText ) { + + $this->assertEquals( true, $title->isNamespaceIdKnown() ); + $this->assertEquals( $expectedId, $title->getNamespaceId() ); + $this->assertEquals( $expectedName, $title->getNamespaceName() ); + $this->assertEquals( $expectedText, $title->getText() ); + } + + public function testUnknownNamespaceCheck( ) { + $title = new ForeignTitle( null, 'this', 'that' ); + + $this->assertEquals( false, $title->isNamespaceIdKnown() ); + $this->assertEquals( 'this', $title->getNamespaceName() ); + $this->assertEquals( 'that', $title->getText() ); + } + + public function testUnknownNamespaceError( ) { + $this->setExpectedException( 'MWException' ); + $title = new ForeignTitle( null, 'this', 'that' ); + $title->getNamespaceId(); + } + + public function fullTextProvider() { + return array( + array( + new ForeignTitle( 20, 'Contributor', 'JohnDoe' ), + 'Contributor:JohnDoe' + ), + array( + new ForeignTitle( '1', 'Discussion', 'Capital' ), + 'Discussion:Capital' + ), + array( + new ForeignTitle( 0, '', 'MainNamespace' ), + 'MainNamespace' + ), + array( + new ForeignTitle( 4, 'Some ns', 'Article title with spaces' ), + 'Some_ns:Article_title_with_spaces' + ), + ); + } + + /** + * @dataProvider fullTextProvider + */ + public function testFullText( ForeignTitle $title, $fullText ) { + $this->assertEquals( $fullText, $title->getFullText() ); + } +} diff --git a/tests/phpunit/includes/title/MediaWikiPageLinkRendererTest.php b/tests/phpunit/includes/title/MediaWikiPageLinkRendererTest.php index 4171c10e..cd0d0b1c 100644 --- a/tests/phpunit/includes/title/MediaWikiPageLinkRendererTest.php +++ b/tests/phpunit/includes/title/MediaWikiPageLinkRendererTest.php @@ -16,7 +16,6 @@ * http://www.gnu.org/copyleft/gpl.html * * @file - * @license GPL 2+ * @author Daniel Kinzler */ diff --git a/tests/phpunit/includes/title/MediaWikiTitleCodecTest.php b/tests/phpunit/includes/title/MediaWikiTitleCodecTest.php index f95b3050..78d304c1 100644 --- a/tests/phpunit/includes/title/MediaWikiTitleCodecTest.php +++ b/tests/phpunit/includes/title/MediaWikiTitleCodecTest.php @@ -16,7 +16,6 @@ * http://www.gnu.org/copyleft/gpl.html * * @file - * @license GPL 2+ * @author Daniel Kinzler */ @@ -39,6 +38,7 @@ class MediaWikiTitleCodecTest extends MediaWikiTestCase { 'wgLang' => Language::factory( 'en' ), 'wgAllowUserJs' => false, 'wgDefaultLanguageVariant' => false, + 'wgMetaNamespace' => 'Project', 'wgLocalInterwikis' => array( 'localtestiw' ), 'wgCapitalLinks' => true, @@ -82,6 +82,8 @@ class MediaWikiTitleCodecTest extends MediaWikiTestCase { protected function makeCodec( $lang ) { $gender = $this->getGenderCache(); $lang = Language::factory( $lang ); + // language object can came from cache, which does not respect test settings + $lang->resetNamespaces(); return new MediaWikiTitleCodec( $lang, $gender ); } @@ -367,13 +369,6 @@ class MediaWikiTitleCodecTest extends MediaWikiTestCase { /** * @dataProvider provideGetNamespaceName - * - * @param int $namespace - * @param string $text - * @param string $lang - * @param string $expected - * - * @internal param \TitleValue $title */ public function testGetNamespaceName( $namespace, $text, $lang, $expected ) { $codec = $this->makeCodec( $lang ); diff --git a/tests/phpunit/includes/title/NaiveForeignTitleFactoryTest.php b/tests/phpunit/includes/title/NaiveForeignTitleFactoryTest.php new file mode 100644 index 00000000..504e8712 --- /dev/null +++ b/tests/phpunit/includes/title/NaiveForeignTitleFactoryTest.php @@ -0,0 +1,91 @@ +<?php +/** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + * @author This, that and the other + */ + +/** + * @covers NaiveForeignTitleFactory + * + * @group Title + */ +class NaiveForeignTitleFactoryTest extends MediaWikiTestCase { + + public function basicProvider() { + return array( + array( + 'MainNamespaceArticle', 0, + new ForeignTitle( 0, '', 'MainNamespaceArticle' ), + ), + array( + 'MainNamespaceArticle', null, + new ForeignTitle( null, '', 'MainNamespaceArticle' ), + ), + array( + 'Talk:Nice_talk', 1, + new ForeignTitle( 1, 'Talk', 'Nice_talk' ), + ), + array( + 'Bogus:Nice_talk', 0, + new ForeignTitle( 0, '', 'Bogus:Nice_talk' ), + ), + array( + 'Bogus:Nice_talk', 9000, // non-existent local namespace ID + new ForeignTitle( 9000, 'Bogus', 'Nice_talk' ), + ), + array( + 'Bogus:Nice_talk', 4, // existing local namespace ID + new ForeignTitle( 4, 'Bogus', 'Nice_talk' ), + ), + array( + 'Talk:Extra:Nice_talk', 1, + new ForeignTitle( 1, 'Talk', 'Extra:Nice_talk' ), + ), + array( + 'Talk:Extra:Nice_talk', null, + new ForeignTitle( null, 'Talk', 'Extra:Nice_talk' ), + ), + ); + } + + /** + * @dataProvider basicProvider + */ + public function testBasic( $title, $ns, ForeignTitle $foreignTitle ) { + $factory = new NaiveForeignTitleFactory(); + $testTitle = $factory->createForeignTitle( $title, $ns ); + + $this->assertEquals( $testTitle->isNamespaceIdKnown(), + $foreignTitle->isNamespaceIdKnown() ); + + if ( + $testTitle->isNamespaceIdKnown() && + $foreignTitle->isNamespaceIdKnown() + ) { + $this->assertEquals( $testTitle->getNamespaceId(), + $foreignTitle->getNamespaceId() ); + } + + $this->assertEquals( $testTitle->getNamespaceName(), + $foreignTitle->getNamespaceName() ); + $this->assertEquals( $testTitle->getText(), $foreignTitle->getText() ); + + $this->assertEquals( str_replace( ' ', '_', $title ), + $foreignTitle->getFullText() ); + } +} diff --git a/tests/phpunit/includes/title/NaiveImportTitleFactoryTest.php b/tests/phpunit/includes/title/NaiveImportTitleFactoryTest.php new file mode 100644 index 00000000..98b414e0 --- /dev/null +++ b/tests/phpunit/includes/title/NaiveImportTitleFactoryTest.php @@ -0,0 +1,89 @@ +<?php +/** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + * @author This, that and the other + */ + +/** + * @covers NaiveImportTitleFactory + * + * @group Title + */ +class NaiveImportTitleFactoryTest extends MediaWikiTestCase { + + protected function setUp() { + parent::setUp(); + + $this->setMwGlobals( array( + 'wgLanguageCode' => 'en', + 'wgContLang' => Language::factory( 'en' ), + 'wgExtraNamespaces' => array( 100 => 'Portal' ), + ) ); + } + + public function basicProvider() { + return array( + array( + new ForeignTitle( 0, '', 'MainNamespaceArticle' ), + Title::newFromText( 'MainNamespaceArticle' ) + ), + array( + new ForeignTitle( null, '', 'MainNamespaceArticle' ), + Title::newFromText( 'MainNamespaceArticle' ) + ), + array( + new ForeignTitle( 1, 'Discussion', 'Nice_talk' ), + Title::newFromText( 'Talk:Nice_talk' ) + ), + array( + new ForeignTitle( 0, '', 'Bogus:Nice_talk' ), + Title::newFromText( 'Bogus:Nice_talk' ) + ), + array( + new ForeignTitle( 100, 'Bogus', 'Nice_talk' ), + Title::newFromText( 'Bogus:Nice_talk' ) // not Portal:Nice_talk + ), + array( + new ForeignTitle( 1, 'Bogus', 'Nice_talk' ), + Title::newFromText( 'Talk:Nice_talk' ) // not Bogus:Nice_talk + ), + array( + new ForeignTitle( 100, 'Portal', 'Nice_talk' ), + Title::newFromText( 'Portal:Nice_talk' ) + ), + array( + new ForeignTitle( 724, 'Portal', 'Nice_talk' ), + Title::newFromText( 'Portal:Nice_talk' ) + ), + array( + new ForeignTitle( 2, 'Portal', 'Nice_talk' ), + Title::newFromText( 'User:Nice_talk' ) + ), + ); + } + + /** + * @dataProvider basicProvider + */ + public function testBasic( ForeignTitle $foreignTitle, Title $title ) { + $factory = new NaiveImportTitleFactory(); + $testTitle = $factory->createTitleFromForeignTitle( $foreignTitle ); + + $this->assertTrue( $title->equals( $testTitle ) ); + } +} diff --git a/tests/phpunit/includes/title/NamespaceAwareForeignTitleFactoryTest.php b/tests/phpunit/includes/title/NamespaceAwareForeignTitleFactoryTest.php new file mode 100644 index 00000000..9cb195cc --- /dev/null +++ b/tests/phpunit/includes/title/NamespaceAwareForeignTitleFactoryTest.php @@ -0,0 +1,89 @@ +<?php +/** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + * @author This, that and the other + */ + +/** + * @covers NamespaceAwareForeignTitleFactory + * + * @group Title + */ +class NamespaceAwareForeignTitleFactoryTest extends MediaWikiTestCase { + + public function basicProvider() { + return array( + array( + 'MainNamespaceArticle', 0, + new ForeignTitle( 0, '', 'MainNamespaceArticle' ), + ), + array( + 'MainNamespaceArticle', null, + new ForeignTitle( 0, '', 'MainNamespaceArticle' ), + ), + array( + 'Talk:Nice_talk', 1, + new ForeignTitle( 1, 'Talk', 'Nice_talk' ), + ), + array( + 'Bogus:Nice_talk', 0, + new ForeignTitle( 0, '', 'Bogus:Nice_talk' ), + ), + array( + 'Bogus:Nice_talk', null, + new ForeignTitle( 9000, 'Bogus', 'Nice_talk' ), + ), + array( + 'Bogus:Nice_talk', 4, + new ForeignTitle( 4, 'Bogus', 'Nice_talk' ), + ), + array( + 'Bogus:Nice_talk', 1, + new ForeignTitle( 1, 'Talk', 'Nice_talk' ), + ), + ); + } + + /** + * @dataProvider basicProvider + */ + public function testBasic( $title, $ns, ForeignTitle $foreignTitle ) { + + $foreignNamespaces = array( + 0 => '', 1 => 'Talk', 100 => 'Portal', 9000 => 'Bogus' + ); + + $factory = new NamespaceAwareForeignTitleFactory( $foreignNamespaces ); + $testTitle = $factory->createForeignTitle( $title, $ns ); + + $this->assertEquals( $testTitle->isNamespaceIdKnown(), + $foreignTitle->isNamespaceIdKnown() ); + + if ( + $testTitle->isNamespaceIdKnown() && + $foreignTitle->isNamespaceIdKnown() + ) { + $this->assertEquals( $testTitle->getNamespaceId(), + $foreignTitle->getNamespaceId() ); + } + + $this->assertEquals( $testTitle->getNamespaceName(), + $foreignTitle->getNamespaceName() ); + $this->assertEquals( $testTitle->getText(), $foreignTitle->getText() ); + } +} diff --git a/tests/phpunit/includes/title/NamespaceImportTitleFactoryTest.php b/tests/phpunit/includes/title/NamespaceImportTitleFactoryTest.php new file mode 100644 index 00000000..d6fe6848 --- /dev/null +++ b/tests/phpunit/includes/title/NamespaceImportTitleFactoryTest.php @@ -0,0 +1,77 @@ +<?php +/** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + * @author This, that and the other + */ + +/** + * @covers NamespaceImportTitleFactory + * + * @group Title + */ +class NamespaceImportTitleFactoryTest extends MediaWikiTestCase { + + protected function setUp() { + parent::setUp(); + + $this->setMwGlobals( array( + 'wgLanguageCode' => 'en', + 'wgContLang' => Language::factory( 'en' ), + ) ); + } + + public function basicProvider() { + return array( + array( + new ForeignTitle( 0, '', 'MainNamespaceArticle' ), + 0, + Title::newFromText( 'MainNamespaceArticle' ) + ), + array( + new ForeignTitle( 0, '', 'MainNamespaceArticle' ), + 2, + Title::newFromText( 'User:MainNamespaceArticle' ) + ), + array( + new ForeignTitle( 1, 'Discussion', 'Nice_talk' ), + 0, + Title::newFromText( 'Nice_talk' ) + ), + array( + new ForeignTitle( 0, '', 'Bogus:Nice_talk' ), + 0, + Title::newFromText( 'Bogus:Nice_talk' ) + ), + array( + new ForeignTitle( 0, '', 'Bogus:Nice_talk' ), + 2, + Title::newFromText( 'User:Bogus:Nice_talk' ) + ), + ); + } + + /** + * @dataProvider basicProvider + */ + public function testBasic( ForeignTitle $foreignTitle, $ns, Title $title ) { + $factory = new NamespaceImportTitleFactory( $ns ); + $testTitle = $factory->createTitleFromForeignTitle( $foreignTitle ); + + $this->assertTrue( $title->equals( $testTitle ) ); + } +} diff --git a/tests/phpunit/includes/title/SubpageImportTitleFactoryTest.php b/tests/phpunit/includes/title/SubpageImportTitleFactoryTest.php new file mode 100644 index 00000000..d5c17f3e --- /dev/null +++ b/tests/phpunit/includes/title/SubpageImportTitleFactoryTest.php @@ -0,0 +1,86 @@ +<?php +/** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + * @author This, that and the other + */ + +/** + * @covers SubpageImportTitleFactory + * + * @group Title + */ +class SubpageImportTitleFactoryTest extends MediaWikiTestCase { + + protected function setUp() { + parent::setUp(); + + $this->setMwGlobals( array( + 'wgLanguageCode' => 'en', + 'wgContLang' => Language::factory( 'en' ), + 'wgNamespacesWithSubpages' => array( 0 => false, 2 => true ), + ) ); + } + + public function basicProvider() { + return array( + array( + new ForeignTitle( 0, '', 'MainNamespaceArticle' ), + Title::newFromText( 'User:Graham' ), + Title::newFromText( 'User:Graham/MainNamespaceArticle' ) + ), + array( + new ForeignTitle( 1, 'Discussion', 'Nice_talk' ), + Title::newFromText( 'User:Graham' ), + Title::newFromText( 'User:Graham/Discussion:Nice_talk' ) + ), + array( + new ForeignTitle( 0, '', 'Bogus:Nice_talk' ), + Title::newFromText( 'User:Graham' ), + Title::newFromText( 'User:Graham/Bogus:Nice_talk' ) + ), + ); + } + + /** + * @dataProvider basicProvider + */ + public function testBasic( ForeignTitle $foreignTitle, Title $rootPage, + Title $title ) { + + $factory = new SubpageImportTitleFactory( $rootPage ); + $testTitle = $factory->createTitleFromForeignTitle( $foreignTitle ); + + $this->assertTrue( $testTitle->equals( $title ) ); + } + + public function failureProvider() { + return array( + array( + Title::newFromText( 'Graham' ), + ), + ); + } + + /** + * @dataProvider failureProvider + */ + public function testFailures( Title $rootPage ) { + $this->setExpectedException( 'MWException' ); + new SubpageImportTitleFactory( $rootPage ); + } +} diff --git a/tests/phpunit/includes/title/TitleValueTest.php b/tests/phpunit/includes/title/TitleValueTest.php index 3ba008d6..184198d2 100644 --- a/tests/phpunit/includes/title/TitleValueTest.php +++ b/tests/phpunit/includes/title/TitleValueTest.php @@ -16,7 +16,6 @@ * http://www.gnu.org/copyleft/gpl.html * * @file - * @license GPL 2+ * @author Daniel Kinzler */ diff --git a/tests/phpunit/includes/upload/UploadBaseTest.php b/tests/phpunit/includes/upload/UploadBaseTest.php index 3d3b0068..9441b77f 100644 --- a/tests/phpunit/includes/upload/UploadBaseTest.php +++ b/tests/phpunit/includes/upload/UploadBaseTest.php @@ -9,21 +9,17 @@ class UploadBaseTest extends MediaWikiTestCase { protected $upload; protected function setUp() { - global $wgHooks; parent::setUp(); $this->upload = new UploadTestHandler; - $this->hooks = $wgHooks; - $wgHooks['InterwikiLoadPrefix'][] = function ( $prefix, &$data ) { - return false; - }; - } - - protected function tearDown() { - global $wgHooks; - $wgHooks = $this->hooks; - parent::tearDown(); + $this->setMwGlobals( 'wgHooks', array( + 'InterwikiLoadPrefix' => array( + function ( $prefix, &$data ) { + return false; + } + ), + ) ); } /** @@ -97,7 +93,7 @@ class UploadBaseTest extends MediaWikiTestCase { // Helper used to create an empty file of size $size. private function createFileOfSize( $size ) { - $filename = tempnam( wfTempDir(), "mwuploadtest" ); + $filename = $this->getNewTempFile(); $fh = fopen( $filename, 'w' ); ftruncate( $fh, $size ); @@ -112,22 +108,21 @@ class UploadBaseTest extends MediaWikiTestCase { * This method should be abstracted so we can test different settings. */ public function testMaxUploadSize() { - global $wgMaxUploadSize; - $savedGlobal = $wgMaxUploadSize; // save global - global $wgFileExtensions; - $wgFileExtensions[] = 'txt'; - - $wgMaxUploadSize = 100; + $this->setMwGlobals( array( + 'wgMaxUploadSize' => 100, + 'wgFileExtensions' => array( + 'txt', + ), + ) ); - $filename = $this->createFileOfSize( $wgMaxUploadSize ); + $filename = $this->createFileOfSize( 100 ); $this->upload->initializePathInfo( basename( $filename ) . '.txt', $filename, 100 ); $result = $this->upload->verifyUpload(); - unlink( $filename ); $this->assertEquals( - array( 'status' => UploadBase::OK ), $result ); - - $wgMaxUploadSize = $savedGlobal; // restore global + array( 'status' => UploadBase::OK ), + $result + ); } diff --git a/tests/phpunit/includes/upload/UploadFromUrlTest.php b/tests/phpunit/includes/upload/UploadFromUrlTest.php index ec56b63e..b7496629 100644 --- a/tests/phpunit/includes/upload/UploadFromUrlTest.php +++ b/tests/phpunit/includes/upload/UploadFromUrlTest.php @@ -35,7 +35,10 @@ class UploadFromUrlTest extends ApiTestCase { wfSetupSession( $sessionId ); - return array( $module->getResultData(), $req ); + return array( + $module->getResult()->getResultData( null, array( 'Strip' => 'all' ) ), + $req + ); } /** diff --git a/tests/phpunit/includes/utils/CdbTest.php b/tests/phpunit/includes/utils/CdbTest.php deleted file mode 100644 index 487ee1fc..00000000 --- a/tests/phpunit/includes/utils/CdbTest.php +++ /dev/null @@ -1,90 +0,0 @@ -<?php - -/** - * Test the CDB reader/writer - * @covers CdbWriterPHP - * @covers CdbWriterDBA - */ -class CdbTest extends MediaWikiTestCase { - - protected function setUp() { - parent::setUp(); - if ( !CdbReader::haveExtension() ) { - $this->markTestSkipped( 'Native CDB support is not available' ); - } - } - - /** - * @group medium - */ - public function testCdb() { - $dir = wfTempDir(); - if ( !is_writable( $dir ) ) { - $this->markTestSkipped( "Temp dir isn't writable" ); - } - - $phpcdbfile = $this->getNewTempFile(); - $dbacdbfile = $this->getNewTempFile(); - - $w1 = new CdbWriterPHP( $phpcdbfile ); - $w2 = new CdbWriterDBA( $dbacdbfile ); - - $data = array(); - for ( $i = 0; $i < 1000; $i++ ) { - $key = $this->randomString(); - $value = $this->randomString(); - $w1->set( $key, $value ); - $w2->set( $key, $value ); - - if ( !isset( $data[$key] ) ) { - $data[$key] = $value; - } - } - - $w1->close(); - $w2->close(); - - $this->assertEquals( - md5_file( $phpcdbfile ), - md5_file( $dbacdbfile ), - 'same hash' - ); - - $r1 = new CdbReaderPHP( $phpcdbfile ); - $r2 = new CdbReaderDBA( $dbacdbfile ); - - foreach ( $data as $key => $value ) { - if ( $key === '' ) { - // Known bug - continue; - } - $v1 = $r1->get( $key ); - $v2 = $r2->get( $key ); - - $v1 = $v1 === false ? '(not found)' : $v1; - $v2 = $v2 === false ? '(not found)' : $v2; - - # cdbAssert( 'Mismatch', $key, $v1, $v2 ); - $this->cdbAssert( "PHP error", $key, $v1, $value ); - $this->cdbAssert( "DBA error", $key, $v2, $value ); - } - } - - private function randomString() { - $len = mt_rand( 0, 10 ); - $s = ''; - for ( $j = 0; $j < $len; $j++ ) { - $s .= chr( mt_rand( 0, 255 ) ); - } - - return $s; - } - - private function cdbAssert( $msg, $key, $v1, $v2 ) { - $this->assertEquals( - $v2, - $v1, - $msg . ', k=' . bin2hex( $key ) - ); - } -} diff --git a/tests/phpunit/includes/utils/IPTest.php b/tests/phpunit/includes/utils/IPTest.php index ebe347fd..09c1587d 100644 --- a/tests/phpunit/includes/utils/IPTest.php +++ b/tests/phpunit/includes/utils/IPTest.php @@ -9,7 +9,7 @@ * dataprovider. */ -class IPTest extends MediaWikiTestCase { +class IPTest extends PHPUnit_Framework_TestCase { /** * not sure it should be tested with boolean false. hashar 20100924 * @covers IP::isIPAddress diff --git a/tests/phpunit/includes/utils/MWCryptHKDFTest.php b/tests/phpunit/includes/utils/MWCryptHKDFTest.php index 7e37534a..73e4c1a9 100644 --- a/tests/phpunit/includes/utils/MWCryptHKDFTest.php +++ b/tests/phpunit/includes/utils/MWCryptHKDFTest.php @@ -6,6 +6,12 @@ class MWCryptHKDFTest extends MediaWikiTestCase { + protected function setUp() { + parent::setUp(); + + $this->setMwGlobals( 'wgSecretKey', '5bf1945342e67799cb50704a7fa19ac6' ); + } + /** * Test basic usage works */ diff --git a/tests/phpunit/includes/MWFunctionTest.php b/tests/phpunit/includes/utils/MWFunctionTest.php index f2a720e8..f4d17999 100644 --- a/tests/phpunit/includes/MWFunctionTest.php +++ b/tests/phpunit/includes/utils/MWFunctionTest.php @@ -13,6 +13,7 @@ class MWFunctionTest extends MediaWikiTestCase { $args = array( $arg1, $arg2, $arg3, $arg4 ); $newObject = new MWBlankClass( $arg1, $arg2, $arg3, $arg4 ); + $this->hideDeprecated( 'MWFunction::newObj' ); $this->assertEquals( MWFunction::newObj( 'MWBlankClass', $args )->args, $newObject->args diff --git a/tests/phpunit/includes/utils/UIDGeneratorTest.php b/tests/phpunit/includes/utils/UIDGeneratorTest.php index 50fa3849..0e11ccad 100644 --- a/tests/phpunit/includes/utils/UIDGeneratorTest.php +++ b/tests/phpunit/includes/utils/UIDGeneratorTest.php @@ -35,14 +35,14 @@ class UIDGeneratorTest extends MediaWikiTestCase { $lastId_bin = wfBaseConvert( $lastId, 10, 2 ); $this->assertGreaterThanOrEqual( - substr( $id_bin, 0, $tbits ), substr( $lastId_bin, 0, $tbits ), + substr( $id_bin, 0, $tbits ), "New ID timestamp ($id_bin) >= prior one ($lastId_bin)." ); if ( $hostbits ) { $this->assertEquals( - substr( $id_bin, 0, -$hostbits ), - substr( $lastId_bin, 0, -$hostbits ), + substr( $id_bin, -$hostbits ), + substr( $lastId_bin, -$hostbits ), "Host ID of ($id_bin) is same as prior one ($lastId_bin)." ); } diff --git a/tests/phpunit/includes/utils/ZipDirectoryReaderTest.php b/tests/phpunit/includes/utils/ZipDirectoryReaderTest.php index 34ffb535..05d07d45 100644 --- a/tests/phpunit/includes/utils/ZipDirectoryReaderTest.php +++ b/tests/phpunit/includes/utils/ZipDirectoryReaderTest.php @@ -4,7 +4,7 @@ * @covers ZipDirectoryReader * NOTE: this test is more like an integration test than a unit test */ -class ZipDirectoryReaderTest extends MediaWikiTestCase { +class ZipDirectoryReaderTest extends PHPUnit_Framework_TestCase { protected $zipDir; protected $entries; diff --git a/tests/phpunit/install-phpunit.sh b/tests/phpunit/install-phpunit.sh deleted file mode 100644 index 022f998e..00000000 --- a/tests/phpunit/install-phpunit.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh - -has_binary () { - if [ -z `which $1` ]; then - return 1 - fi - return 0 -} - -if [ `id -u` -ne 0 ]; then - echo '*** ERROR: Must be root to run' - exit 1 -fi - -if ( has_binary phpunit ); then - echo PHPUnit already installed -else if ( has_binary pear ); then - echo Installing phpunit with pear - pear channel-discover pear.phpunit.de - pear channel-discover components.ez.no - pear channel-discover pear.symfony.com - pear update-channels - #Temporary fix for 64597 - pear install --alldeps phpunit/PHPUnit-3.7.35 -else if ( has_binary apt-get ); then - echo Installing phpunit with apt-get - apt-get install phpunit -else if ( has_binary yum ); then - echo Installing phpunit with yum - yum install phpunit -else if ( has_binary port ); then - echo Installing phpunit with macports - port install php5-unit -fi -fi -fi -fi -fi diff --git a/tests/phpunit/includes/LanguageConverterTest.php b/tests/phpunit/languages/LanguageConverterTest.php index d4ccca99..d4ccca99 100644 --- a/tests/phpunit/includes/LanguageConverterTest.php +++ b/tests/phpunit/languages/LanguageConverterTest.php diff --git a/tests/phpunit/languages/SpecialPageAliasTest.php b/tests/phpunit/languages/SpecialPageAliasTest.php index f6d6bc96..a6d9d270 100644 --- a/tests/phpunit/languages/SpecialPageAliasTest.php +++ b/tests/phpunit/languages/SpecialPageAliasTest.php @@ -8,7 +8,6 @@ * @group SystemTest * @group medium * - * @licence GNU GPL v2+ * @author Katie Filbert < aude.wiki@gmail.com > */ class SpecialPageAliasTest extends MediaWikiTestCase { diff --git a/tests/phpunit/languages/LanguageAmTest.php b/tests/phpunit/languages/classes/LanguageAmTest.php index a644f5e0..a644f5e0 100644 --- a/tests/phpunit/languages/LanguageAmTest.php +++ b/tests/phpunit/languages/classes/LanguageAmTest.php diff --git a/tests/phpunit/languages/LanguageArTest.php b/tests/phpunit/languages/classes/LanguageArTest.php index 7b48f236..7b48f236 100644 --- a/tests/phpunit/languages/LanguageArTest.php +++ b/tests/phpunit/languages/classes/LanguageArTest.php diff --git a/tests/phpunit/languages/LanguageArqTest.php b/tests/phpunit/languages/classes/LanguageArqTest.php index 3fa56d78..3fa56d78 100644 --- a/tests/phpunit/languages/LanguageArqTest.php +++ b/tests/phpunit/languages/classes/LanguageArqTest.php diff --git a/tests/phpunit/languages/LanguageBeTest.php b/tests/phpunit/languages/classes/LanguageBeTest.php index 7bd586af..7bd586af 100644 --- a/tests/phpunit/languages/LanguageBeTest.php +++ b/tests/phpunit/languages/classes/LanguageBeTest.php diff --git a/tests/phpunit/languages/LanguageBe_taraskTest.php b/tests/phpunit/languages/classes/LanguageBe_taraskTest.php index 4dd5cdd7..4dd5cdd7 100644 --- a/tests/phpunit/languages/LanguageBe_taraskTest.php +++ b/tests/phpunit/languages/classes/LanguageBe_taraskTest.php diff --git a/tests/phpunit/languages/LanguageBhoTest.php b/tests/phpunit/languages/classes/LanguageBhoTest.php index 187bfbbc..187bfbbc 100644 --- a/tests/phpunit/languages/LanguageBhoTest.php +++ b/tests/phpunit/languages/classes/LanguageBhoTest.php diff --git a/tests/phpunit/languages/LanguageBsTest.php b/tests/phpunit/languages/classes/LanguageBsTest.php index 7aca2ab1..7aca2ab1 100644 --- a/tests/phpunit/languages/LanguageBsTest.php +++ b/tests/phpunit/languages/classes/LanguageBsTest.php diff --git a/tests/phpunit/languages/LanguageCsTest.php b/tests/phpunit/languages/classes/LanguageCsTest.php index da9e6b88..da9e6b88 100644 --- a/tests/phpunit/languages/LanguageCsTest.php +++ b/tests/phpunit/languages/classes/LanguageCsTest.php diff --git a/tests/phpunit/languages/LanguageCuTest.php b/tests/phpunit/languages/classes/LanguageCuTest.php index 07193172..07193172 100644 --- a/tests/phpunit/languages/LanguageCuTest.php +++ b/tests/phpunit/languages/classes/LanguageCuTest.php diff --git a/tests/phpunit/languages/LanguageCyTest.php b/tests/phpunit/languages/classes/LanguageCyTest.php index eaf663a8..eaf663a8 100644 --- a/tests/phpunit/languages/LanguageCyTest.php +++ b/tests/phpunit/languages/classes/LanguageCyTest.php diff --git a/tests/phpunit/languages/LanguageDsbTest.php b/tests/phpunit/languages/classes/LanguageDsbTest.php index 94c11bcc..94c11bcc 100644 --- a/tests/phpunit/languages/LanguageDsbTest.php +++ b/tests/phpunit/languages/classes/LanguageDsbTest.php diff --git a/tests/phpunit/languages/LanguageFrTest.php b/tests/phpunit/languages/classes/LanguageFrTest.php index 46b65011..46b65011 100644 --- a/tests/phpunit/languages/LanguageFrTest.php +++ b/tests/phpunit/languages/classes/LanguageFrTest.php diff --git a/tests/phpunit/languages/LanguageGaTest.php b/tests/phpunit/languages/classes/LanguageGaTest.php index c009f56b..c009f56b 100644 --- a/tests/phpunit/languages/LanguageGaTest.php +++ b/tests/phpunit/languages/classes/LanguageGaTest.php diff --git a/tests/phpunit/languages/LanguageGdTest.php b/tests/phpunit/languages/classes/LanguageGdTest.php index b89b4df9..b89b4df9 100644 --- a/tests/phpunit/languages/LanguageGdTest.php +++ b/tests/phpunit/languages/classes/LanguageGdTest.php diff --git a/tests/phpunit/languages/LanguageGvTest.php b/tests/phpunit/languages/classes/LanguageGvTest.php index fc58022a..e6a0cf07 100644 --- a/tests/phpunit/languages/LanguageGvTest.php +++ b/tests/phpunit/languages/classes/LanguageGvTest.php @@ -37,7 +37,7 @@ class LanguageGvTest extends LanguageClassesTestCase { array( 'other', 23 ), array( 'other', 50 ), array( 'few', 60 ), - array( 'other', 80 ), + array( 'few', 80 ), array( 'few', 100 ) ); } diff --git a/tests/phpunit/languages/LanguageHeTest.php b/tests/phpunit/languages/classes/LanguageHeTest.php index c382244f..c382244f 100644 --- a/tests/phpunit/languages/LanguageHeTest.php +++ b/tests/phpunit/languages/classes/LanguageHeTest.php diff --git a/tests/phpunit/languages/LanguageHiTest.php b/tests/phpunit/languages/classes/LanguageHiTest.php index f6d2c9e9..f6d2c9e9 100644 --- a/tests/phpunit/languages/LanguageHiTest.php +++ b/tests/phpunit/languages/classes/LanguageHiTest.php diff --git a/tests/phpunit/languages/LanguageHrTest.php b/tests/phpunit/languages/classes/LanguageHrTest.php index 644c5255..644c5255 100644 --- a/tests/phpunit/languages/LanguageHrTest.php +++ b/tests/phpunit/languages/classes/LanguageHrTest.php diff --git a/tests/phpunit/languages/LanguageHsbTest.php b/tests/phpunit/languages/classes/LanguageHsbTest.php index f95a43bf..f95a43bf 100644 --- a/tests/phpunit/languages/LanguageHsbTest.php +++ b/tests/phpunit/languages/classes/LanguageHsbTest.php diff --git a/tests/phpunit/languages/LanguageHuTest.php b/tests/phpunit/languages/classes/LanguageHuTest.php index ee9197d7..ee9197d7 100644 --- a/tests/phpunit/languages/LanguageHuTest.php +++ b/tests/phpunit/languages/classes/LanguageHuTest.php diff --git a/tests/phpunit/languages/LanguageHyTest.php b/tests/phpunit/languages/classes/LanguageHyTest.php index 92e0ef94..92e0ef94 100644 --- a/tests/phpunit/languages/LanguageHyTest.php +++ b/tests/phpunit/languages/classes/LanguageHyTest.php diff --git a/tests/phpunit/languages/LanguageKshTest.php b/tests/phpunit/languages/classes/LanguageKshTest.php index 568a3780..568a3780 100644 --- a/tests/phpunit/languages/LanguageKshTest.php +++ b/tests/phpunit/languages/classes/LanguageKshTest.php diff --git a/tests/phpunit/languages/LanguageLnTest.php b/tests/phpunit/languages/classes/LanguageLnTest.php index 10b3234f..10b3234f 100644 --- a/tests/phpunit/languages/LanguageLnTest.php +++ b/tests/phpunit/languages/classes/LanguageLnTest.php diff --git a/tests/phpunit/languages/LanguageLtTest.php b/tests/phpunit/languages/classes/LanguageLtTest.php index 30642f62..30642f62 100644 --- a/tests/phpunit/languages/LanguageLtTest.php +++ b/tests/phpunit/languages/classes/LanguageLtTest.php diff --git a/tests/phpunit/languages/LanguageLvTest.php b/tests/phpunit/languages/classes/LanguageLvTest.php index 7120cfe3..7120cfe3 100644 --- a/tests/phpunit/languages/LanguageLvTest.php +++ b/tests/phpunit/languages/classes/LanguageLvTest.php diff --git a/tests/phpunit/languages/LanguageMgTest.php b/tests/phpunit/languages/classes/LanguageMgTest.php index 65e8fd7b..65e8fd7b 100644 --- a/tests/phpunit/languages/LanguageMgTest.php +++ b/tests/phpunit/languages/classes/LanguageMgTest.php diff --git a/tests/phpunit/languages/LanguageMkTest.php b/tests/phpunit/languages/classes/LanguageMkTest.php index ed155263..ed155263 100644 --- a/tests/phpunit/languages/LanguageMkTest.php +++ b/tests/phpunit/languages/classes/LanguageMkTest.php diff --git a/tests/phpunit/languages/LanguageMlTest.php b/tests/phpunit/languages/classes/LanguageMlTest.php index 4fa45ce3..4fa45ce3 100644 --- a/tests/phpunit/languages/LanguageMlTest.php +++ b/tests/phpunit/languages/classes/LanguageMlTest.php diff --git a/tests/phpunit/languages/LanguageMoTest.php b/tests/phpunit/languages/classes/LanguageMoTest.php index e0e54ca8..e0e54ca8 100644 --- a/tests/phpunit/languages/LanguageMoTest.php +++ b/tests/phpunit/languages/classes/LanguageMoTest.php diff --git a/tests/phpunit/languages/LanguageMtTest.php b/tests/phpunit/languages/classes/LanguageMtTest.php index 96d2bc92..96d2bc92 100644 --- a/tests/phpunit/languages/LanguageMtTest.php +++ b/tests/phpunit/languages/classes/LanguageMtTest.php diff --git a/tests/phpunit/languages/LanguageNlTest.php b/tests/phpunit/languages/classes/LanguageNlTest.php index 26bd691a..26bd691a 100644 --- a/tests/phpunit/languages/LanguageNlTest.php +++ b/tests/phpunit/languages/classes/LanguageNlTest.php diff --git a/tests/phpunit/languages/LanguageNsoTest.php b/tests/phpunit/languages/classes/LanguageNsoTest.php index 18efd736..18efd736 100644 --- a/tests/phpunit/languages/LanguageNsoTest.php +++ b/tests/phpunit/languages/classes/LanguageNsoTest.php diff --git a/tests/phpunit/languages/LanguagePlTest.php b/tests/phpunit/languages/classes/LanguagePlTest.php index d180037b..d180037b 100644 --- a/tests/phpunit/languages/LanguagePlTest.php +++ b/tests/phpunit/languages/classes/LanguagePlTest.php diff --git a/tests/phpunit/languages/LanguageRoTest.php b/tests/phpunit/languages/classes/LanguageRoTest.php index ae7816bc..ae7816bc 100644 --- a/tests/phpunit/languages/LanguageRoTest.php +++ b/tests/phpunit/languages/classes/LanguageRoTest.php diff --git a/tests/phpunit/languages/LanguageRuTest.php b/tests/phpunit/languages/classes/LanguageRuTest.php index f64fc722..1381afbf 100644 --- a/tests/phpunit/languages/LanguageRuTest.php +++ b/tests/phpunit/languages/classes/LanguageRuTest.php @@ -13,7 +13,7 @@ class LanguageRuTest extends LanguageClassesTestCase { * @covers Language::convertPlural */ public function testPlural( $result, $value ) { - $forms = array( 'one', 'many', 'other' ); + $forms = array( 'one', 'few', 'many', 'other' ); $this->assertEquals( $result, $this->getLang()->convertPlural( $value, $forms ) ); } @@ -22,9 +22,9 @@ class LanguageRuTest extends LanguageClassesTestCase { * @covers Language::convertPlural */ public function testExplicitPlural() { - $forms = array( 'one', 'many', 'other', '12=dozen' ); + $forms = array( 'one', 'few', 'many', 'other', '12=dozen' ); $this->assertEquals( 'dozen', $this->getLang()->convertPlural( 12, $forms ) ); - $forms = array( 'one', 'many', '100=hundred', 'other', '12=dozen' ); + $forms = array( 'one', 'few', 'many', '100=hundred', 'other', '12=dozen' ); $this->assertEquals( 'hundred', $this->getLang()->convertPlural( 100, $forms ) ); } @@ -42,10 +42,10 @@ class LanguageRuTest extends LanguageClassesTestCase { array( 'many', 11 ), array( 'one', 91 ), array( 'one', 121 ), - array( 'other', 2 ), - array( 'other', 3 ), - array( 'other', 4 ), - array( 'other', 334 ), + array( 'few', 2 ), + array( 'few', 3 ), + array( 'few', 4 ), + array( 'few', 334 ), array( 'many', 5 ), array( 'many', 15 ), array( 'many', 120 ), diff --git a/tests/phpunit/languages/LanguageSeTest.php b/tests/phpunit/languages/classes/LanguageSeTest.php index 533aa2bc..533aa2bc 100644 --- a/tests/phpunit/languages/LanguageSeTest.php +++ b/tests/phpunit/languages/classes/LanguageSeTest.php diff --git a/tests/phpunit/languages/LanguageSgsTest.php b/tests/phpunit/languages/classes/LanguageSgsTest.php index fa49a4dd..fa49a4dd 100644 --- a/tests/phpunit/languages/LanguageSgsTest.php +++ b/tests/phpunit/languages/classes/LanguageSgsTest.php diff --git a/tests/phpunit/languages/LanguageShTest.php b/tests/phpunit/languages/classes/LanguageShTest.php index 1b390872..1b390872 100644 --- a/tests/phpunit/languages/LanguageShTest.php +++ b/tests/phpunit/languages/classes/LanguageShTest.php diff --git a/tests/phpunit/languages/LanguageSkTest.php b/tests/phpunit/languages/classes/LanguageSkTest.php index cb8a13b8..cb8a13b8 100644 --- a/tests/phpunit/languages/LanguageSkTest.php +++ b/tests/phpunit/languages/classes/LanguageSkTest.php diff --git a/tests/phpunit/languages/LanguageSlTest.php b/tests/phpunit/languages/classes/LanguageSlTest.php index 9783dd80..9783dd80 100644 --- a/tests/phpunit/languages/LanguageSlTest.php +++ b/tests/phpunit/languages/classes/LanguageSlTest.php diff --git a/tests/phpunit/languages/LanguageSmaTest.php b/tests/phpunit/languages/classes/LanguageSmaTest.php index 95cb333c..95cb333c 100644 --- a/tests/phpunit/languages/LanguageSmaTest.php +++ b/tests/phpunit/languages/classes/LanguageSmaTest.php diff --git a/tests/phpunit/languages/LanguageSrTest.php b/tests/phpunit/languages/classes/LanguageSrTest.php index bfb199f3..bfb199f3 100644 --- a/tests/phpunit/languages/LanguageSrTest.php +++ b/tests/phpunit/languages/classes/LanguageSrTest.php diff --git a/tests/phpunit/languages/LanguageTiTest.php b/tests/phpunit/languages/classes/LanguageTiTest.php index e225af97..e225af97 100644 --- a/tests/phpunit/languages/LanguageTiTest.php +++ b/tests/phpunit/languages/classes/LanguageTiTest.php diff --git a/tests/phpunit/languages/LanguageTlTest.php b/tests/phpunit/languages/classes/LanguageTlTest.php index 7ac51c69..20f5bd7f 100644 --- a/tests/phpunit/languages/LanguageTlTest.php +++ b/tests/phpunit/languages/classes/LanguageTlTest.php @@ -28,7 +28,9 @@ class LanguageTlTest extends LanguageClassesTestCase { return array( array( 'one', 0 ), array( 'one', 1 ), - array( 'other', 2 ), + array( 'one', 2 ), + array( 'other', 4 ), + array( 'other', 6 ), ); } } diff --git a/tests/phpunit/languages/LanguageTrTest.php b/tests/phpunit/languages/classes/LanguageTrTest.php index 2c9905f7..2c9905f7 100644 --- a/tests/phpunit/languages/LanguageTrTest.php +++ b/tests/phpunit/languages/classes/LanguageTrTest.php diff --git a/tests/phpunit/languages/LanguageUkTest.php b/tests/phpunit/languages/classes/LanguageUkTest.php index 9051bcff..9051bcff 100644 --- a/tests/phpunit/languages/LanguageUkTest.php +++ b/tests/phpunit/languages/classes/LanguageUkTest.php diff --git a/tests/phpunit/languages/LanguageUzTest.php b/tests/phpunit/languages/classes/LanguageUzTest.php index 4881103f..4881103f 100644 --- a/tests/phpunit/languages/LanguageUzTest.php +++ b/tests/phpunit/languages/classes/LanguageUzTest.php diff --git a/tests/phpunit/languages/LanguageWaTest.php b/tests/phpunit/languages/classes/LanguageWaTest.php index d05196c0..d05196c0 100644 --- a/tests/phpunit/languages/LanguageWaTest.php +++ b/tests/phpunit/languages/classes/LanguageWaTest.php diff --git a/tests/phpunit/maintenance/DumpTestCase.php b/tests/phpunit/maintenance/DumpTestCase.php index 8b6aef53..8c763970 100644 --- a/tests/phpunit/maintenance/DumpTestCase.php +++ b/tests/phpunit/maintenance/DumpTestCase.php @@ -19,7 +19,7 @@ abstract class DumpTestCase extends MediaWikiLangTestCase { protected $exceptionFromAddDBData = null; /** - * Holds the xmlreader used for analyzing an xml dump + * Holds the XMLReader used for analyzing an XML dump * * @var XMLReader|null */ @@ -30,13 +30,15 @@ abstract class DumpTestCase extends MediaWikiLangTestCase { * * @param Page $page Page to add the revision to * @param string $text Revisions text - * @param string $summary Revisions summare - * @return array + * @param string $summary Revisions summary + * @param string $model The model ID (defaults to wikitext) + * * @throws MWException + * @return array */ - protected function addRevision( Page $page, $text, $summary ) { + protected function addRevision( Page $page, $text, $summary, $model = CONTENT_MODEL_WIKITEXT ) { $status = $page->doEditContent( - ContentHandler::makeContent( $text, $page->getTitle() ), + ContentHandler::makeContent( $text, $page->getTitle(), $model ), $summary ); @@ -330,6 +332,12 @@ abstract class DumpTestCase extends MediaWikiLangTestCase { $this->assertTextNode( "comment", $summary ); $this->skipWhitespace(); + $this->assertTextNode( "model", $model ); + $this->skipWhitespace(); + + $this->assertTextNode( "format", $format ); + $this->skipWhitespace(); + if ( $this->xml->name == "text" ) { // note: <text> tag may occur here or at the very end. $text_found = true; @@ -340,12 +348,6 @@ abstract class DumpTestCase extends MediaWikiLangTestCase { $this->assertTextNode( "sha1", $text_sha1 ); - $this->assertTextNode( "model", $model ); - $this->skipWhitespace(); - - $this->assertTextNode( "format", $format ); - $this->skipWhitespace(); - if ( !$text_found ) { $this->assertText( $id, $text_id, $text_bytes, $text ); } diff --git a/tests/phpunit/maintenance/backupTextPassTest.php b/tests/phpunit/maintenance/backupTextPassTest.php index a37a97c7..a5ef7624 100644 --- a/tests/phpunit/maintenance/backupTextPassTest.php +++ b/tests/phpunit/maintenance/backupTextPassTest.php @@ -3,13 +3,13 @@ require_once __DIR__ . "/../../../maintenance/backupTextPass.inc"; /** - * Tests for page dumps of BackupDumper + * Tests for TextPassDumper that rely on the database * * @group Database * @group Dump * @covers TextPassDumper */ -class TextPassDumperTest extends DumpTestCase { +class TextPassDumperDatabaseTest extends DumpTestCase { // We'll add several pages, revision and texts. The following variables hold the // corresponding ids. @@ -27,6 +27,10 @@ class TextPassDumperTest extends DumpTestCase { $this->tablesUsed[] = 'revision'; $this->tablesUsed[] = 'text'; + $this->mergeMwGlobalArrayValue( 'wgContentHandlers', array( + "BackupTextPassTestModel" => "BackupTextPassTestModelHandler" + ) ); + $ns = $this->getDefaultWikitextNS(); try { @@ -61,7 +65,8 @@ class TextPassDumperTest extends DumpTestCase { $this->pageId3 = $page->getId(); $page->doDeleteArticle( "Testing ;)" ); - // Page from non-default namespace + // Page from non-default namespace and model. + // ExportTransform applies. if ( $ns === NS_TALK ) { // @todo work around this. @@ -73,7 +78,8 @@ class TextPassDumperTest extends DumpTestCase { $page = WikiPage::factory( $title ); list( $this->revId4_1, $this->textId4_1 ) = $this->addRevision( $page, "Talk about BackupDumperTestP1 Text1", - "Talk BackupDumperTestP1 Summary1" ); + "Talk BackupDumperTestP1 Summary1", + "BackupTextPassTestModel" ); $this->pageId4 = $page->getId(); } catch ( Exception $e ) { // We'd love to pass $e directly. However, ... see @@ -141,7 +147,10 @@ class TextPassDumperTest extends DumpTestCase { $this->assertPageStart( $this->pageId4, NS_TALK, "Talk:BackupDumperTestP1" ); $this->assertRevision( $this->revId4_1, "Talk BackupDumperTestP1 Summary1", $this->textId4_1, false, "nktofwzd0tl192k3zfepmlzxoax1lpe", - "Talk about BackupDumperTestP1 Text1" ); + "TALK ABOUT BACKUPDUMPERTESTP1 TEXT1", + false, + "BackupTextPassTestModel", + "text/plain" ); $this->assertPageEnd(); $this->assertDumpEnd(); @@ -209,7 +218,10 @@ class TextPassDumperTest extends DumpTestCase { $this->assertPageStart( $this->pageId4, NS_TALK, "Talk:BackupDumperTestP1" ); $this->assertRevision( $this->revId4_1, "Talk BackupDumperTestP1 Summary1", $this->textId4_1, false, "nktofwzd0tl192k3zfepmlzxoax1lpe", - "Talk about BackupDumperTestP1 Text1" ); + "TALK ABOUT BACKUPDUMPERTESTP1 TEXT1", + false, + "BackupTextPassTestModel", + "text/plain" ); $this->assertPageEnd(); $this->assertDumpEnd(); @@ -232,7 +244,9 @@ class TextPassDumperTest extends DumpTestCase { $this->fail( "Could not open stream for stderr" ); } - $iterations = 32; // We'll start with that many iterations of revisions in stub + $iterations = 32; // We'll start with that many iterations of revisions + // in stub. Make sure that the generated volume is above the buffer size + // set below. Otherwise, the checkpointing does not trigger. $lastDuration = 0; $minDuration = 2; // We want the dump to take at least this many seconds $checkpointAfter = 0.5; // Generate checkpoint after this many seconds @@ -250,6 +264,7 @@ class TextPassDumperTest extends DumpTestCase { $dumper = new TextPassDumper( array( "--stub=file:" . $nameStub, "--output=" . $checkpointFormat . ":" . $nameOutputDir . "/full", "--maxtime=1" /*This is in minutes. Fixup is below*/, + "--buffersize=32768", // The default of 32 iterations fill up 32KB about twice "--checkpointfile=checkpoint-%s-%s.xml.gz" ) ); $dumper->setDb( $this->db ); $dumper->maxTimeAllowed = $checkpointAfter; // Patching maxTime from 1 minute @@ -362,7 +377,10 @@ class TextPassDumperTest extends DumpTestCase { $this->assertRevision( $this->revId4_1 + $i * self::$numOfRevs, "Talk BackupDumperTestP1 Summary1", $this->textId4_1, false, "nktofwzd0tl192k3zfepmlzxoax1lpe", - "Talk about BackupDumperTestP1 Text1" ); + "TALK ABOUT BACKUPDUMPERTESTP1 TEXT1", + false, + "BackupTextPassTestModel", + "text/plain" ); $this->assertPageEnd(); $lookingForPage = 1; @@ -440,10 +458,10 @@ class TextPassDumperTest extends DumpTestCase { if ( $fname === null ) { $fname = $this->getNewTempFile(); } - $header = '<mediawiki xmlns="http://www.mediawiki.org/xml/export-0.7/" ' + $header = '<mediawiki xmlns="http://www.mediawiki.org/xml/export-0.10/" ' . 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ' - . 'xsi:schemaLocation="http://www.mediawiki.org/xml/export-0.7/ ' - . 'http://www.mediawiki.org/xml/export-0.7.xsd" version="0.7" xml:lang="en"> + . 'xsi:schemaLocation="http://www.mediawiki.org/xml/export-0.10/ ' + . 'http://www.mediawiki.org/xml/export-0.10.xsd" version="0.10" xml:lang="en"> <siteinfo> <sitename>wikisvn</sitename> <base>http://localhost/wiki-svn/index.php/Main_Page</base> @@ -489,10 +507,10 @@ class TextPassDumperTest extends DumpTestCase { <ip>127.0.0.1</ip> </contributor> <comment>BackupDumperTestP1Summary1</comment> - <sha1>0bolhl6ol7i6x0e7yq91gxgaan39j87</sha1> <model>wikitext</model> <format>text/x-wiki</format> <text id="' . $this->textId1_1 . '" bytes="23" /> + <sha1>0bolhl6ol7i6x0e7yq91gxgaan39j87</sha1> </revision> </page> '; @@ -507,10 +525,10 @@ class TextPassDumperTest extends DumpTestCase { <ip>127.0.0.1</ip> </contributor> <comment>BackupDumperTestP2Summary1</comment> - <sha1>jprywrymfhysqllua29tj3sc7z39dl2</sha1> <model>wikitext</model> <format>text/x-wiki</format> <text id="' . $this->textId2_1 . '" bytes="23" /> + <sha1>jprywrymfhysqllua29tj3sc7z39dl2</sha1> </revision> <revision> <id>' . ( $this->revId2_2 + $i * self::$numOfRevs ) . '</id> @@ -520,10 +538,10 @@ class TextPassDumperTest extends DumpTestCase { <ip>127.0.0.1</ip> </contributor> <comment>BackupDumperTestP2Summary2</comment> - <sha1>b7vj5ks32po5m1z1t1br4o7scdwwy95</sha1> <model>wikitext</model> <format>text/x-wiki</format> <text id="' . $this->textId2_2 . '" bytes="23" /> + <sha1>b7vj5ks32po5m1z1t1br4o7scdwwy95</sha1> </revision> <revision> <id>' . ( $this->revId2_3 + $i * self::$numOfRevs ) . '</id> @@ -533,10 +551,10 @@ class TextPassDumperTest extends DumpTestCase { <ip>127.0.0.1</ip> </contributor> <comment>BackupDumperTestP2Summary3</comment> - <sha1>jfunqmh1ssfb8rs43r19w98k28gg56r</sha1> <model>wikitext</model> <format>text/x-wiki</format> <text id="' . $this->textId2_3 . '" bytes="23" /> + <sha1>jfunqmh1ssfb8rs43r19w98k28gg56r</sha1> </revision> <revision> <id>' . ( $this->revId2_4 + $i * self::$numOfRevs ) . '</id> @@ -546,10 +564,10 @@ class TextPassDumperTest extends DumpTestCase { <ip>127.0.0.1</ip> </contributor> <comment>BackupDumperTestP2Summary4 extra</comment> - <sha1>6o1ciaxa6pybnqprmungwofc4lv00wv</sha1> <model>wikitext</model> <format>text/x-wiki</format> <text id="' . $this->textId2_4 . '" bytes="44" /> + <sha1>6o1ciaxa6pybnqprmungwofc4lv00wv</sha1> </revision> </page> '; @@ -566,10 +584,10 @@ class TextPassDumperTest extends DumpTestCase { <ip>127.0.0.1</ip> </contributor> <comment>Talk BackupDumperTestP1 Summary1</comment> - <sha1>nktofwzd0tl192k3zfepmlzxoax1lpe</sha1> - <model>wikitext</model> - <format>text/x-wiki</format> + <model>BackupTextPassTestModel</model> + <format>text/plain</format> <text id="' . $this->textId4_1 . '" bytes="35" /> + <sha1>nktofwzd0tl192k3zfepmlzxoax1lpe</sha1> </revision> </page> '; @@ -582,3 +600,73 @@ class TextPassDumperTest extends DumpTestCase { return $fname; } } + +class BackupTextPassTestModelHandler extends TextContentHandler { + + public function __construct() { + parent::__construct( 'BackupTextPassTestModel' ); + } + + public function exportTransform( $text, $format = null ) { + return strtoupper( $text ); + } + +} + +/** + * Tests for TextPassDumper that do not rely on the database + * + * (As the Database group is only detected at class level (not method level), we + * cannot bring this test case's tests into the above main test case.) + * + * @group Dump + * @covers TextPassDumper + */ +class TextPassDumperDatabaselessTest extends MediaWikiLangTestCase { + /** + * Ensures that setting the buffer size is effective. + * + * @dataProvider bufferSizeProvider + */ + function testBufferSizeSetting( $expected, $size, $msg ) { + $dumper = new TextPassDumperAccessor( array( "--buffersize=" . $size ) ); + $this->assertEquals( $expected, $dumper->getBufferSize(), $msg); + } + + /** + * Ensures that setting the buffer size is effective. + * + * @dataProvider bufferSizeProvider + */ + function bufferSizeProvider() { + // expected, bufferSize to initialize with, message + return array( + array( 512 * 1024, 512 * 1024, "Setting 512KB is not effective" ), + array( 8192, 8192, "Setting 8KB is not effective" ), + array( 4096, 2048, "Could set buffer size below lower bound" ) + ); + } +} + +/** + * Accessor for internal state of TextPassDumper + * + * Do not warrentless add getters here. + */ +class TextPassDumperAccessor extends TextPassDumper { + /** + * Gets the bufferSize. + * + * If bufferSize setting does not work correctly, testCheckpoint... tests + * fail and point in the wrong direction. To aid in troubleshooting when + * testCheckpoint... tests break at some point in the future, we test the + * bufferSize setting, hence need this accessor. + * + * (Yes, bufferSize is internal state of the TextPassDumper, but aiding + * debugging of testCheckpoint... in the future seems to be worth testing + * against it nonetheless.) + */ + public function getBufferSize() { + return $this->bufferSize; + } +} diff --git a/tests/phpunit/phpunit.php b/tests/phpunit/phpunit.php index 11255043..e59b5063 100644 --- a/tests/phpunit/phpunit.php +++ b/tests/phpunit/phpunit.php @@ -93,6 +93,12 @@ class PHPUnitMaintClass extends Maintenance { public function execute() { global $IP; + // Deregister handler from MWExceptionHandler::installHandle so that PHPUnit's own handler + // stays in tact. + // Has to in execute() instead of finalSetup(), because finalSetup() runs before + // doMaintenance.php includes Setup.php, which calls MWExceptionHandler::installHandle(). + restore_error_handler(); + $this->forceFormatServerArgv(); # Make sure we have --configuration or PHPUnit might complain diff --git a/tests/phpunit/structure/AutoLoaderTest.php b/tests/phpunit/structure/AutoLoaderTest.php index 2bdc9c9a..cde6547a 100644 --- a/tests/phpunit/structure/AutoLoaderTest.php +++ b/tests/phpunit/structure/AutoLoaderTest.php @@ -2,27 +2,22 @@ class AutoLoaderTest extends MediaWikiTestCase { protected function setUp() { - global $wgAutoloadLocalClasses, $wgAutoloadClasses; - parent::setUp(); // Fancy dance to trigger a rebuild of AutoLoader::$autoloadLocalClassesLower - $this->testLocalClasses = array( - 'TestAutoloadedLocalClass' => __DIR__ . '/../data/autoloader/TestAutoloadedLocalClass.php', - 'TestAutoloadedCamlClass' => __DIR__ . '/../data/autoloader/TestAutoloadedCamlClass.php', + $this->mergeMwGlobalArrayValue( 'wgAutoloadLocalClasses', array( + 'TestAutoloadedLocalClass' => + __DIR__ . '/../data/autoloader/TestAutoloadedLocalClass.php', + 'TestAutoloadedCamlClass' => + __DIR__ . '/../data/autoloader/TestAutoloadedCamlClass.php', 'TestAutoloadedSerializedClass' => __DIR__ . '/../data/autoloader/TestAutoloadedSerializedClass.php', - ); - $this->setMwGlobals( - 'wgAutoloadLocalClasses', - $this->testLocalClasses + $wgAutoloadLocalClasses - ); + ) ); AutoLoader::resetAutoloadLocalClassesLower(); - $this->testExtensionClasses = array( + $this->mergeMwGlobalArrayValue( 'wgAutoloadClasses', array( 'TestAutoloadedClass' => __DIR__ . '/../data/autoloader/TestAutoloadedClass.php', - ); - $this->setMwGlobals( 'wgAutoloadClasses', $this->testExtensionClasses + $wgAutoloadClasses ); + ) ); } /** @@ -49,7 +44,7 @@ class AutoLoaderTest extends MediaWikiTestCase { $files = array_unique( $expected ); - foreach ( $files as $file ) { + foreach ( $files as $class => $file ) { // Only prefix $IP if it doesn't have it already. // Generally local classes don't have it, and those from extensions and test suites do. if ( substr( $file, 0, 1 ) != '/' && substr( $file, 1, 1 ) != ':' ) { @@ -58,7 +53,19 @@ class AutoLoaderTest extends MediaWikiTestCase { $filePath = $file; } + if ( !file_exists( $filePath ) ) { + $actual[$class] = "[file '$filePath' does not exist]"; + continue; + } + + wfSuppressWarnings(); $contents = file_get_contents( $filePath ); + wfRestoreWarnings(); + + if ( $contents === false ) { + $actual[$class] = "[couldn't read file '$filePath']"; + continue; + } // We could use token_get_all() here, but this is faster $matches = array(); @@ -123,10 +130,14 @@ class AutoLoaderTest extends MediaWikiTestCase { } function testWrongCaseClass() { + $this->setMwGlobals( 'wgAutoloadAttemptLowercase', true ); + $this->assertTrue( class_exists( 'testautoLoadedcamlCLASS' ) ); } function testWrongCaseSerializedClass() { + $this->setMwGlobals( 'wgAutoloadAttemptLowercase', true ); + $dummyCereal = 'O:29:"testautoloadedserializedclass":0:{}'; $uncerealized = unserialize( $dummyCereal ); $this->assertFalse( $uncerealized instanceof __PHP_Incomplete_Class, diff --git a/tests/phpunit/structure/AvailableRightsTest.php b/tests/phpunit/structure/AvailableRightsTest.php new file mode 100644 index 00000000..51d31aaa --- /dev/null +++ b/tests/phpunit/structure/AvailableRightsTest.php @@ -0,0 +1,51 @@ +<?php + +/** + * Try to make sure that extensions register all rights in $wgAvailableRights + * or via the 'UserGetAllRights' hook. + * + * @author Marius Hoch < hoo@online.de > + */ +class AvailableRightsTest extends PHPUnit_Framework_TestCase { + + /** + * Returns all rights that should be in $wgAvailableRights + all rights + * registered via the 'UserGetAllRights' hook + all "core" rights. + * + * @return string[] + */ + private function getAllVisibleRights() { + global $wgGroupPermissions, $wgRevokePermissions; + + $rights = User::getAllRights(); + + foreach( $wgGroupPermissions as $permissions ) { + $rights = array_merge( $rights, array_keys( $permissions ) ); + } + + foreach( $wgRevokePermissions as $permissions ) { + $rights = array_merge( $rights, array_keys( $permissions ) ); + } + + $rights = array_unique( $rights ); + sort( $rights ); + + return $rights; + } + + public function testAvailableRights() { + $missingRights = array_diff( + $this->getAllVisibleRights(), + User::getAllRights() + ); + + $this->assertEquals( + array(), + // Re-index to produce nicer output, keys are meaningless. + array_values( $missingRights ), + 'Additional user rights need to be added to $wgAvailableRights or ' . + 'via the "UserGetAllRights" hook. See the instructions at: ' . + 'https://www.mediawiki.org/wiki/Manual:User_rights#Adding_new_rights' + ); + } +} diff --git a/tests/phpunit/structure/ResourcesTest.php b/tests/phpunit/structure/ResourcesTest.php index 2396ea29..d2b699d9 100644 --- a/tests/phpunit/structure/ResourcesTest.php +++ b/tests/phpunit/structure/ResourcesTest.php @@ -12,7 +12,6 @@ * @copyright © 2012, Santhosh Thottingal * @copyright © 2012, Timo Tijhof * - * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later */ class ResourcesTest extends MediaWikiTestCase { @@ -91,6 +90,10 @@ class ResourcesTest extends MediaWikiTestCase { foreach ( $data['modules'] as $moduleName => $module ) { $moduleTargets = $module->getTargets(); foreach ( $module->getDependencies() as $dep ) { + if ( !isset( $data['modules'][$dep] ) ) { + // Missing dependencies reported by testMissingDependencies + continue; + } $targets = $data['modules'][$dep]->getTargets(); foreach ( $moduleTargets as $moduleTarget ) { $this->assertContains( diff --git a/tests/phpunit/suite.xml b/tests/phpunit/suite.xml index 574c11e4..1acbc241 100644 --- a/tests/phpunit/suite.xml +++ b/tests/phpunit/suite.xml @@ -39,6 +39,7 @@ phpunit.php enables colors for other OSs at runtime <file>suites/UploadFromUrlTestSuite.php</file> </testsuite> <testsuite name="extensions"> + <directory>structure</directory> <file>suites/ExtensionsTestSuite.php</file> <file>suites/ExtensionsParserTestSuite.php</file> <file>suites/LessTestSuite.php</file> @@ -57,7 +58,6 @@ phpunit.php enables colors for other OSs at runtime <directory suffix=".php">../../includes</directory> <directory suffix=".php">../../languages</directory> <directory suffix=".php">../../maintenance</directory> - <directory suffix=".php">../../resources</directory> <directory suffix=".php">../../skins</directory> </whitelist> </filter> diff --git a/tests/phpunit/suites/ExtensionsTestSuite.php b/tests/phpunit/suites/ExtensionsTestSuite.php index 116065f8..723328e2 100644 --- a/tests/phpunit/suites/ExtensionsTestSuite.php +++ b/tests/phpunit/suites/ExtensionsTestSuite.php @@ -10,7 +10,7 @@ class ExtensionsTestSuite extends PHPUnit_Framework_TestSuite { parent::__construct(); $paths = array(); // Extensions can return a list of files or directories - wfRunHooks( 'UnitTestsList', array( &$paths ) ); + Hooks::run( 'UnitTestsList', array( &$paths ) ); foreach ( $paths as $path ) { if ( is_dir( $path ) ) { // If the path is a directory, search for test cases. diff --git a/tests/qunit/QUnitTestResources.php b/tests/qunit/QUnitTestResources.php index 15c33f64..17b8b632 100644 --- a/tests/qunit/QUnitTestResources.php +++ b/tests/qunit/QUnitTestResources.php @@ -48,7 +48,6 @@ return array( 'tests/qunit/suites/resources/jquery/jquery.autoEllipsis.test.js', 'tests/qunit/suites/resources/jquery/jquery.byteLength.test.js', 'tests/qunit/suites/resources/jquery/jquery.byteLimit.test.js', - 'tests/qunit/suites/resources/jquery/jquery.client.test.js', 'tests/qunit/suites/resources/jquery/jquery.color.test.js', 'tests/qunit/suites/resources/jquery/jquery.colorUtil.test.js', 'tests/qunit/suites/resources/jquery/jquery.getAttrs.test.js', @@ -60,18 +59,24 @@ return array( 'tests/qunit/suites/resources/jquery/jquery.placeholder.test.js', 'tests/qunit/suites/resources/jquery/jquery.tabIndex.test.js', 'tests/qunit/suites/resources/jquery/jquery.tablesorter.test.js', + 'tests/qunit/suites/resources/jquery/jquery.tablesorter.parsers.test.js', 'tests/qunit/suites/resources/jquery/jquery.textSelection.test.js', 'tests/qunit/data/mediawiki.jqueryMsg.data.js', + 'tests/qunit/suites/resources/mediawiki/mediawiki.errorLogger.test.js', 'tests/qunit/suites/resources/mediawiki/mediawiki.jqueryMsg.test.js', 'tests/qunit/suites/resources/mediawiki/mediawiki.jscompat.test.js', + 'tests/qunit/suites/resources/mediawiki/mediawiki.messagePoster.factory.test.js', + 'tests/qunit/suites/resources/mediawiki/mediawiki.template.test.js', 'tests/qunit/suites/resources/mediawiki/mediawiki.test.js', 'tests/qunit/suites/resources/mediawiki/mediawiki.Title.test.js', 'tests/qunit/suites/resources/mediawiki/mediawiki.toc.test.js', + 'tests/qunit/suites/resources/mediawiki/mediawiki.track.test.js', 'tests/qunit/suites/resources/mediawiki/mediawiki.Uri.test.js', 'tests/qunit/suites/resources/mediawiki/mediawiki.user.test.js', 'tests/qunit/suites/resources/mediawiki/mediawiki.util.test.js', 'tests/qunit/suites/resources/mediawiki.api/mediawiki.api.test.js', 'tests/qunit/suites/resources/mediawiki.api/mediawiki.api.category.test.js', + 'tests/qunit/suites/resources/mediawiki.api/mediawiki.api.options.test.js', 'tests/qunit/suites/resources/mediawiki.api/mediawiki.api.parse.test.js', 'tests/qunit/suites/resources/mediawiki.api/mediawiki.api.watch.test.js', 'tests/qunit/suites/resources/mediawiki.special/mediawiki.special.recentchanges.test.js', @@ -84,7 +89,6 @@ return array( 'jquery.autoEllipsis', 'jquery.byteLength', 'jquery.byteLimit', - 'jquery.client', 'jquery.color', 'jquery.colorUtil', 'jquery.getAttrs', @@ -99,13 +103,16 @@ return array( 'jquery.textSelection', 'mediawiki.api', 'mediawiki.api.category', + 'mediawiki.api.options', 'mediawiki.api.parse', 'mediawiki.api.watch', 'mediawiki.jqueryMsg', + 'mediawiki.messagePoster', 'mediawiki.Title', 'mediawiki.toc', 'mediawiki.Uri', 'mediawiki.user', + 'mediawiki.template', 'mediawiki.util', 'mediawiki.special.recentchanges', 'mediawiki.language', diff --git a/tests/qunit/data/testrunner.js b/tests/qunit/data/testrunner.js index db312b21..03aaf4af 100644 --- a/tests/qunit/data/testrunner.js +++ b/tests/qunit/data/testrunner.js @@ -26,32 +26,20 @@ */ // When a test() indicates asynchronicity with stop(), - // allow 10 seconds to pass before killing the test(), + // allow 30 seconds to pass before killing the test(), // and assuming failure. - QUnit.config.testTimeout = 10 * 1000; + QUnit.config.testTimeout = 30 * 1000; + + QUnit.config.requireExpects = true; // Add a checkbox to QUnit header to toggle MediaWiki ResourceLoader debug mode. QUnit.config.urlConfig.push( { id: 'debug', label: 'Enable ResourceLoaderDebug', - tooltip: 'Enable debug mode in ResourceLoader' + tooltip: 'Enable debug mode in ResourceLoader', + value: 'true' } ); - QUnit.config.requireExpects = true; - - /** - * Load TestSwarm agent - */ - // Only if the current url indicates that there is a TestSwarm instance watching us - // (TestSwarm appends swarmURL to the test suites url it loads in iframes). - // Otherwise this is just a simple view of Special:JavaScriptTest/qunit directly, - // no point in loading inject.js in that case. Also, make sure that this instance - // of MediaWiki has actually been configured with the required url to that inject.js - // script. By default it is false. - if ( QUnit.urlParams.swarmURL && mw.config.get( 'QUnitTestSwarmInjectJSPath' ) ) { - jQuery.getScript( QUnit.fixurl( mw.config.get( 'QUnitTestSwarmInjectJSPath' ) ) ); - } - /** * CompletenessTest * @@ -256,6 +244,7 @@ }, teardown: function () { + var timers; log( 'MwEnvironment> TEARDOWN for "' + QUnit.config.current.module + ': ' + QUnit.config.current.testName + '"' ); @@ -272,9 +261,18 @@ // Check for incomplete animations/requests/etc and throw // error if there are any. if ( $.timers && $.timers.length !== 0 ) { - // Test may need to use fake timers, wait for animations or - // call $.fx.stop(). - throw new Error( 'Unfinished animations: ' + $.timers.length ); + timers = $.timers.length; + // Tests shoulld use fake timers or wait for animations to complete + $.each( $.timers, function ( i, timer ) { + var node = timer.elem; + mw.log.warn( 'Unfinished animation #' + i + ' in ' + timer.queue + ' queue on ' + + mw.html.element( node.nodeName.toLowerCase(), $(node).getAttrs() ) + ); + } ); + // Force animations to stop to give the next test a clean start + $.fx.stop(); + + throw new Error( 'Unfinished animations: ' + timers ); } if ( $.active !== undefined && $.active !== 0 ) { // Test may need to use fake XHR, wait for requests or diff --git a/tests/qunit/suites/resources/jquery/jquery.accessKeyLabel.test.js b/tests/qunit/suites/resources/jquery/jquery.accessKeyLabel.test.js index f6ea1b48..4484467d 100644 --- a/tests/qunit/suites/resources/jquery/jquery.accessKeyLabel.test.js +++ b/tests/qunit/suites/resources/jquery/jquery.accessKeyLabel.test.js @@ -7,7 +7,7 @@ } ) ); var getAccessKeyPrefixTestData = [ - //ua string, platform string, expected prefix + // ua string, platform string, expected prefix // Internet Explorer ['Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)', 'Win32', 'alt-'], ['Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)', 'Win32', 'alt-'], @@ -27,11 +27,11 @@ ['Mozilla/5.0 (Macintosh; Intel Mac OS X 10_5_8) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.112 Safari/534.30', 'MacIntel', 'ctrl-option-'], ['Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.68 Safari/534.30', 'Linux i686', 'alt-shift-'] ], - //strings appended to title to make sure updateTooltipAccessKeys handles them correctly + // strings appended to title to make sure updateTooltipAccessKeys handles them correctly updateTooltipAccessKeysTestData = [ '', ' [a]', ' [test-a]', ' [alt-b]' ]; function makeInput( title, accessKey ) { - //The properties aren't escaped, so make sure you don't call this function with values that need to be escaped! + // The properties aren't escaped, so make sure you don't call this function with values that need to be escaped! return '<input title="' + title + '" ' + ( accessKey ? 'accessKey="' + accessKey + '" ' : '' ) + ' />'; } @@ -46,10 +46,10 @@ } ); QUnit.test( 'updateTooltipAccessKeys - current browser', 2, function ( assert ) { - var title = $( makeInput ( 'Title', 'a' ) ).updateTooltipAccessKeys().prop( 'title' ), - //The new title should be something like "Title [alt-a]", but the exact label will depend on the browser. - //The "a" could be capitalized, and the prefix could be anything, e.g. a simple "^" for ctrl- - //(no browser is known using such a short prefix, though) or "Alt+Umschalt+" in German Firefox. + var title = $( makeInput( 'Title', 'a' ) ).updateTooltipAccessKeys().prop( 'title' ), + // The new title should be something like "Title [alt-a]", but the exact label will depend on the browser. + // The "a" could be capitalized, and the prefix could be anything, e.g. a simple "^" for ctrl- + // (no browser is known using such a short prefix, though) or "Alt+Umschalt+" in German Firefox. result = /^Title \[(.+)[aA]\]$/.exec( title ); assert.ok( result, 'title should match expected structure.' ); assert.notEqual( result[1], 'test-', 'Prefix used for testing shouldn\'t be used in production.' ); diff --git a/tests/qunit/suites/resources/jquery/jquery.byteLimit.test.js b/tests/qunit/suites/resources/jquery/jquery.byteLimit.test.js index 22d2af19..0cb9cc81 100644 --- a/tests/qunit/suites/resources/jquery/jquery.byteLimit.test.js +++ b/tests/qunit/suites/resources/jquery/jquery.byteLimit.test.js @@ -60,7 +60,7 @@ ); QUnit.start(); - }, 10 ); + } ); } ); } diff --git a/tests/qunit/suites/resources/jquery/jquery.client.test.js b/tests/qunit/suites/resources/jquery/jquery.client.test.js deleted file mode 100644 index c6dd91c4..00000000 --- a/tests/qunit/suites/resources/jquery/jquery.client.test.js +++ /dev/null @@ -1,638 +0,0 @@ -( function ( $ ) { - - QUnit.module( 'jquery.client', QUnit.newMwEnvironment() ); - - var uacount = 0, - // Object keyed by userAgent. Value is an array (human-readable name, client-profile object, navigator.platform value) - uas = { - // Internet Explorer 6 - // Internet Explorer 7 - 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)': { - title: 'Internet Explorer 7', - platform: 'Win32', - profile: { - name: 'msie', - layout: 'trident', - layoutVersion: 'unknown', - platform: 'win', - version: '7.0', - versionBase: '7', - versionNumber: 7 - }, - wikiEditor: { - ltr: true, - rtl: false - } - }, - // Internet Explorer 8 - // Internet Explorer 9 - // Internet Explorer 10 - 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)': { - title: 'Internet Explorer 10', - platform: 'Win32', - profile: { - name: 'msie', - layout: 'trident', - layoutVersion: 6, - platform: 'win', - version: '10.0', - versionBase: '10', - versionNumber: 10 - }, - wikiEditor: { - ltr: true, - rtl: true - } - }, - // Internet Explorer 11 - 'Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv 11.0) like Gecko': { - title: 'Internet Explorer 11', - platform: 'Win32', - profile: { - name: 'msie', - layout: 'trident', - layoutVersion: 7, - platform: 'win', - version: '11.0', - versionBase: '11', - versionNumber: 11 - }, - wikiEditor: { - ltr: true, - rtl: true - } - }, - // Internet Explorer 11 - Windows 8.1 x64 Modern UI - 'Mozilla/5.0 (Windows NT 6.3; Win64; x64; Trident/7.0; rv:11.0) like Gecko': { - title: 'Internet Explorer 11', - platform: 'Win64', - profile: { - name: 'msie', - layout: 'trident', - layoutVersion: 7, - platform: 'win', - version: '11.0', - versionBase: '11', - versionNumber: 11 - }, - wikiEditor: { - ltr: true, - rtl: true - } - }, - // Internet Explorer 11 - Windows 8.1 x64 desktop UI - 'Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko': { - title: 'Internet Explorer 11', - platform: 'WOW64', - profile: { - name: 'msie', - layout: 'trident', - layoutVersion: 7, - platform: 'win', - version: '11.0', - versionBase: '11', - versionNumber: 11 - }, - wikiEditor: { - ltr: true, - rtl: true - } - }, - // Firefox 2 - // Firefox 3.5 - 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1.19) Gecko/20110420 Firefox/3.5.19': { - title: 'Firefox 3.5', - platform: 'MacIntel', - profile: { - name: 'firefox', - layout: 'gecko', - layoutVersion: 20110420, - platform: 'mac', - version: '3.5.19', - versionBase: '3', - versionNumber: 3.5 - }, - wikiEditor: { - ltr: true, - rtl: true - } - }, - // Firefox 3.6 - 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.17) Gecko/20110422 Ubuntu/10.10 (maverick) Firefox/3.6.17': { - title: 'Firefox 3.6', - platform: 'Linux i686', - profile: { - name: 'firefox', - layout: 'gecko', - layoutVersion: 20110422, - platform: 'linux', - version: '3.6.17', - versionBase: '3', - versionNumber: 3.6 - }, - wikiEditor: { - ltr: true, - rtl: true - } - }, - // Firefox 4 - 'Mozilla/5.0 (Windows NT 6.0; rv:2.0.1) Gecko/20100101 Firefox/4.0.1': { - title: 'Firefox 4', - platform: 'Win32', - profile: { - name: 'firefox', - layout: 'gecko', - layoutVersion: 20100101, - platform: 'win', - version: '4.0.1', - versionBase: '4', - versionNumber: 4 - }, - wikiEditor: { - ltr: true, - rtl: true - } - }, - // Firefox 10 nightly build - 'Mozilla/5.0 (X11; Linux x86_64; rv:10.0a1) Gecko/20111103 Firefox/10.0a1': { - title: 'Firefox 10 nightly', - platform: 'Linux', - profile: { - name: 'firefox', - layout: 'gecko', - layoutVersion: 20111103, - platform: 'linux', - version: '10.0a1', - versionBase: '10', - versionNumber: 10 - }, - wikiEditor: { - ltr: true, - rtl: true - } - }, - // Iceweasel 10.0.6 - 'Mozilla/5.0 (X11; Linux i686; rv:10.0.6) Gecko/20100101 Iceweasel/10.0.6': { - title: 'Iceweasel 10.0.6', - platform: 'Linux', - profile: { - name: 'iceweasel', - layout: 'gecko', - layoutVersion: 20100101, - platform: 'linux', - version: '10.0.6', - versionBase: '10', - versionNumber: 10 - }, - wikiEditor: { - ltr: true, - rtl: true - } - }, - // Iceweasel 15.0.1 - 'Mozilla/5.0 (X11; Linux x86_64; rv:15.0) Gecko/20100101 Firefox/15.0.1 Iceweasel/15.0.1': { - title: 'Iceweasel 15.0.1', - platform: 'Linux', - profile: { - name: 'iceweasel', - layout: 'gecko', - layoutVersion: 20100101, - platform: 'linux', - version: '15.0.1', - versionBase: '15', - versionNumber: 15 - }, - wikiEditor: { - ltr: true, - rtl: true - } - }, - // Firefox 5 - // Safari 3 - // Safari 4 - 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; nl-nl) AppleWebKit/531.22.7 (KHTML, like Gecko) Version/4.0.5 Safari/531.22.7': { - title: 'Safari 4', - platform: 'MacIntel', - profile: { - name: 'safari', - layout: 'webkit', - layoutVersion: 531, - platform: 'mac', - version: '4.0.5', - versionBase: '4', - versionNumber: 4 - }, - wikiEditor: { - ltr: true, - rtl: true - } - }, - 'Mozilla/5.0 (Windows; U; Windows NT 6.0; cs-CZ) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/4.0.5 Safari/531.22.7': { - title: 'Safari 4', - platform: 'Win32', - profile: { - name: 'safari', - layout: 'webkit', - layoutVersion: 533, - platform: 'win', - version: '4.0.5', - versionBase: '4', - versionNumber: 4 - }, - wikiEditor: { - ltr: true, - rtl: true - } - }, - // Safari 5 - // Safari 6 - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/536.29.13 (KHTML, like Gecko) Version/6.0.4 Safari/536.29.13': { - title: 'Safari 6', - platform: 'MacIntel', - profile: { - name: 'safari', - layout: 'webkit', - layoutVersion: 536, - platform: 'mac', - version: '6.0.4', - versionBase: '6', - versionNumber: 6 - }, - wikiEditor: { - ltr: true, - rtl: true - } - }, - // Safari 6.0.5+ (doesn't have the comma in "KHTML, like Gecko") - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 1084) AppleWebKit/536.30.1 (KHTML like Gecko) Version/6.0.5 Safari/536.30.1': { - title: 'Safari 6', - platform: 'MacIntel', - profile: { - name: 'safari', - layout: 'webkit', - layoutVersion: 536, - platform: 'mac', - version: '6.0.5', - versionBase: '6', - versionNumber: 6 - }, - wikiEditor: { - ltr: true, - rtl: true - } - }, - // Opera 10+ - 'Opera/9.80 (Windows NT 5.1)': { - title: 'Opera 10+ (exact version unspecified)', - platform: 'Win32', - profile: { - name: 'opera', - layout: 'presto', - layoutVersion: 'unknown', - platform: 'win', - version: '10', - versionBase: '10', - versionNumber: 10 - }, - wikiEditor: { - ltr: true, - rtl: true - } - }, - // Opera 12 - 'Opera/9.80 (Windows NT 5.1) Presto/2.12.388 Version/12.11': { - title: 'Opera 12', - platform: 'Win32', - profile: { - name: 'opera', - layout: 'presto', - layoutVersion: 'unknown', - platform: 'win', - version: '12.11', - versionBase: '12', - versionNumber: 12.11 - }, - wikiEditor: { - ltr: true, - rtl: true - } - }, - // Opera 15 (WebKit-based) - 'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.52 Safari/537.36 OPR/15.0.1147.130': { - title: 'Opera 15', - platform: 'Win32', - profile: { - name: 'opera', - layout: 'webkit', - layoutVersion: 537, - platform: 'win', - version: '15.0.1147.130', - versionBase: '15', - versionNumber: 15 - }, - wikiEditor: { - ltr: true, - rtl: true - } - }, - // Chrome 5 - // Chrome 6 - // Chrome 7 - // Chrome 8 - // Chrome 9 - // Chrome 10 - // Chrome 11 - // Chrome 12 - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_5_8) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.112 Safari/534.30': { - title: 'Chrome 12', - platform: 'MacIntel', - profile: { - name: 'chrome', - layout: 'webkit', - layoutVersion: 534, - platform: 'mac', - version: '12.0.742.112', - versionBase: '12', - versionNumber: 12 - }, - wikiEditor: { - ltr: true, - rtl: true - } - }, - 'Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.68 Safari/534.30': { - title: 'Chrome 12', - platform: 'Linux i686', - profile: { - name: 'chrome', - layout: 'webkit', - layoutVersion: 534, - platform: 'linux', - version: '12.0.742.68', - versionBase: '12', - versionNumber: 12 - }, - wikiEditor: { - ltr: true, - rtl: true - } - }, - // Android WebKit Browser 2.3 - 'Mozilla/5.0 (Linux; U; Android 2.3.5; en-us; HTC Vision Build/GRI40) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1': { - title: 'Android WebKit Browser 2.3', - platform: 'Linux armv7l', - profile: { - name: 'android', - layout: 'webkit', - layoutVersion: 533, - platform: 'linux', - version: '2.3.5', - versionBase: '2', - versionNumber: 2.3 - }, - wikiEditor: { - ltr: true, - rtl: true - } - }, - // Rekonq (bug 34924) - 'Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.34 (KHTML, like Gecko) rekonq Safari/534.34': { - title: 'Rekonq', - platform: 'Linux i686', - profile: { - name: 'rekonq', - layout: 'webkit', - layoutVersion: 534, - platform: 'linux', - version: '534.34', - versionBase: '534', - versionNumber: 534.34 - }, - wikiEditor: { - ltr: true, - rtl: true - } - }, - // Konqueror - 'Mozilla/5.0 (X11; Linux i686) KHTML/4.9.1 (like Gecko) Konqueror/4.9': { - title: 'Konqueror', - platform: 'Linux i686', - profile: { - name: 'konqueror', - layout: 'khtml', - layoutVersion: 'unknown', - platform: 'linux', - version: '4.9.1', - versionBase: '4', - versionNumber: 4.9 - }, - wikiEditor: { - // '4.9' is less than '4.11'. - ltr: false, - rtl: false - }, - wikiEditorLegacy: { - // The check is missing in legacyTestMap - ltr: true, - rtl: true - } - }, - // Amazon Silk - 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; en-us; Silk/1.0.13.81_10003810) AppleWebKit/533.16 (KHTML, like Gecko) Version/5.0 Safari/533.16 Silk-Accelerated=true': { - title: 'Silk', - platform: 'Desktop', - profile: { - name: 'silk', - layout: 'webkit', - layoutVersion: 533, - platform: 'unknown', - version: '1.0.13.81_10003810', - versionBase: '1', - versionNumber: 1 - }, - wikiEditor: { - ltr: true, - rtl: true - } - }, - 'Mozilla/5.0 (Linux; U; Android 4.0.3; en-us; KFTT Build/IML74K) AppleWebKit/535.19 (KHTML, like Gecko) Silk/2.1 Mobile Safari/535.19 Silk-Accelerated=true': { - title: 'Silk', - platform: 'Mobile', - profile: { - name: 'silk', - layout: 'webkit', - layoutVersion: 535, - platform: 'unknown', - version: '2.1', - versionBase: '2', - versionNumber: 2.1 - }, - wikiEditor: { - ltr: true, - rtl: true - } - } - }, - testMap = { - // Example from WikiEditor, modified to provide version identifiers as strings and with - // Konqueror 4.11 check added. - 'ltr': { - 'msie': [['>=', '7.0']], - 'firefox': [['>=', '2']], - 'opera': [['>=', '9.6']], - 'safari': [['>=', '3']], - 'chrome': [['>=', '3']], - 'netscape': [['>=', '9']], - 'konqueror': [['>=', '4.11']], - 'blackberry': false, - 'ipod': false, - 'iphone': false - }, - 'rtl': { - 'msie': [['>=', '8']], - 'firefox': [['>=', '2']], - 'opera': [['>=', '9.6']], - 'safari': [['>=', '3']], - 'chrome': [['>=', '3']], - 'netscape': [['>=', '9']], - 'konqueror': [['>=', '4.11']], - 'blackberry': false, - 'ipod': false, - 'iphone': false - } - }, - legacyTestMap = { - // Original example from WikiEditor. - // This is using the old, but still supported way of providing version identifiers as numbers - // instead of strings; with this method, 4.9 would be considered larger than 4.11. - 'ltr': { - 'msie': [['>=', 7.0]], - 'firefox': [['>=', 2]], - 'opera': [['>=', 9.6]], - 'safari': [['>=', 3]], - 'chrome': [['>=', 3]], - 'netscape': [['>=', 9]], - 'blackberry': false, - 'ipod': false, - 'iphone': false - }, - 'rtl': { - 'msie': [['>=', 8]], - 'firefox': [['>=', 2]], - 'opera': [['>=', 9.6]], - 'safari': [['>=', 3]], - 'chrome': [['>=', 3]], - 'netscape': [['>=', 9]], - 'blackberry': false, - 'ipod': false, - 'iphone': false - } - } - ; - - // Count test cases - $.each( uas, function () { - uacount++; - } ); - - QUnit.test( 'profile( navObject )', 7, function ( assert ) { - var p = $.client.profile(); - - function unknownOrType( val, type, summary ) { - assert.ok( typeof val === type || val === 'unknown', summary ); - } - - assert.equal( typeof p, 'object', 'profile returns an object' ); - unknownOrType( p.layout, 'string', 'p.layout is a string (or "unknown")' ); - unknownOrType( p.layoutVersion, 'number', 'p.layoutVersion is a number (or "unknown")' ); - unknownOrType( p.platform, 'string', 'p.platform is a string (or "unknown")' ); - unknownOrType( p.version, 'string', 'p.version is a string (or "unknown")' ); - unknownOrType( p.versionBase, 'string', 'p.versionBase is a string (or "unknown")' ); - assert.equal( typeof p.versionNumber, 'number', 'p.versionNumber is a number' ); - } ); - - QUnit.test( 'profile( navObject ) - samples', uacount, function ( assert ) { - // Loop through and run tests - $.each( uas, function ( rawUserAgent, data ) { - // Generate a client profile object and compare recursively - var ret = $.client.profile( { - userAgent: rawUserAgent, - platform: data.platform - } ); - assert.deepEqual( ret, data.profile, 'Client profile support check for ' + data.title + ' (' + data.platform + '): ' + rawUserAgent ); - } ); - } ); - - QUnit.test( 'test( testMap )', 4, function ( assert ) { - // .test() uses eval, make sure no exceptions are thrown - // then do a basic return value type check - var testMatch = $.client.test( testMap ), - ie7Profile = $.client.profile( { - 'userAgent': 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)', - 'platform': '' - } ); - - assert.equal( typeof testMatch, 'boolean', 'map with ltr/rtl split returns a boolean value' ); - - testMatch = $.client.test( testMap.ltr ); - - assert.equal( typeof testMatch, 'boolean', 'simple map (without ltr/rtl split) returns a boolean value' ); - - assert.equal( $.client.test( { - 'msie': null - }, ie7Profile ), true, 'returns true if any version of a browser are allowed (null)' ); - - assert.equal( $.client.test( { - 'msie': false - }, ie7Profile ), false, 'returns false if all versions of a browser are not allowed (false)' ); - } ); - - QUnit.test( 'test( testMap, exactMatchOnly )', 2, function ( assert ) { - var ie7Profile = $.client.profile( { - 'userAgent': 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)', - 'platform': '' - } ); - - assert.equal( $.client.test( { - 'firefox': [['>=', 2]] - }, ie7Profile, false ), true, 'returns true if browser not found and exactMatchOnly not set' ); - - assert.equal( $.client.test( { - 'firefox': [['>=', 2]] - }, ie7Profile, true ), false, 'returns false if browser not found and exactMatchOnly is set' ); - } ); - - QUnit.test( 'test( testMap ), test( legacyTestMap ) - WikiEditor sample', uacount * 2 * 2, function ( assert ) { - var $body = $( 'body' ), - bodyClasses = $body.attr( 'class' ); - - // Loop through and run tests - $.each( uas, function ( agent, data ) { - $.each( ['ltr', 'rtl'], function ( i, dir ) { - var profile, testMatch, legacyTestMatch; - $body.removeClass( 'ltr rtl' ).addClass( dir ); - profile = $.client.profile( { - userAgent: agent, - platform: data.platform - } ); - testMatch = $.client.test( testMap, profile ); - legacyTestMatch = $.client.test( legacyTestMap, profile ); - $body.removeClass( dir ); - - assert.equal( - testMatch, - data.wikiEditor[dir], - 'testing comparison based on ' + dir + ', ' + agent - ); - assert.equal( - legacyTestMatch, - data.wikiEditorLegacy ? data.wikiEditorLegacy[dir] : data.wikiEditor[dir], - 'testing comparison based on ' + dir + ', ' + agent + ' (legacyTestMap)' - ); - } ); - } ); - - // Restore body classes - $body.attr( 'class', bodyClasses ); - } ); -}( jQuery ) ); diff --git a/tests/qunit/suites/resources/jquery/jquery.getAttrs.test.js b/tests/qunit/suites/resources/jquery/jquery.getAttrs.test.js index 0b7e87ee..ca3f418c 100644 --- a/tests/qunit/suites/resources/jquery/jquery.getAttrs.test.js +++ b/tests/qunit/suites/resources/jquery/jquery.getAttrs.test.js @@ -1,13 +1,14 @@ ( function ( $ ) { QUnit.module( 'jquery.getAttrs', QUnit.newMwEnvironment() ); - QUnit.test( 'Check', 1, function ( assert ) { + QUnit.test( 'getAttrs()', 1, function ( assert ) { var attrs = { foo: 'bar', - 'class': 'lorem' + 'class': 'lorem', + 'data-foo': 'data value' }, $el = $( '<div>' ).attr( attrs ); - assert.deepEqual( $el.getAttrs(), attrs, 'getAttrs() return object should match the attributes set, no more, no less' ); + assert.propEqual( $el.getAttrs(), attrs, 'keys and values match' ); } ); }( jQuery ) ); diff --git a/tests/qunit/suites/resources/jquery/jquery.placeholder.test.js b/tests/qunit/suites/resources/jquery/jquery.placeholder.test.js index bbea8297..78c185f1 100644 --- a/tests/qunit/suites/resources/jquery/jquery.placeholder.test.js +++ b/tests/qunit/suites/resources/jquery/jquery.placeholder.test.js @@ -1,10 +1,10 @@ -(function ($) { +( function ($) { QUnit.module('jquery.placeholder', QUnit.newMwEnvironment()); QUnit.test('caches results of feature tests', 2, function (assert) { - assert.strictEqual(typeof $.fn.placeholder.input, 'boolean', '$.fn.placeholder.input'); - assert.strictEqual(typeof $.fn.placeholder.textarea, 'boolean', '$.fn.placeholder.textarea'); + assert.strictEqual( typeof $.fn.placeholder.input, 'boolean', '$.fn.placeholder.input'); + assert.strictEqual( typeof $.fn.placeholder.textarea, 'boolean', '$.fn.placeholder.textarea'); }); if ($.fn.placeholder.input && $.fn.placeholder.textarea) { diff --git a/tests/qunit/suites/resources/jquery/jquery.tablesorter.parsers.test.js b/tests/qunit/suites/resources/jquery/jquery.tablesorter.parsers.test.js new file mode 100644 index 00000000..97a3ae12 --- /dev/null +++ b/tests/qunit/suites/resources/jquery/jquery.tablesorter.parsers.test.js @@ -0,0 +1,223 @@ +( function ( $, mw ) { + /** + * This module tests the input/output capabilities of the parsers of tablesorter. + * It does not test actual sorting. + */ + + var text, ipv4, + simpleMDYDatesInMDY, simpleMDYDatesInDMY, oldMDYDates, complexMDYDates, clobberedDates, MYDates, YDates, + currencyData, transformedCurrencyData; + + QUnit.module( 'jquery.tablesorter.parsers', QUnit.newMwEnvironment( { + setup: function () { + this.liveMonths = mw.language.months; + mw.language.months = { + 'keys': { + 'names': ['january', 'february', 'march', 'april', 'may_long', 'june', + 'july', 'august', 'september', 'october', 'november', 'december'], + 'genitive': ['january-gen', 'february-gen', 'march-gen', 'april-gen', 'may-gen', 'june-gen', + 'july-gen', 'august-gen', 'september-gen', 'october-gen', 'november-gen', 'december-gen'], + 'abbrev': ['jan', 'feb', 'mar', 'apr', 'may', 'jun', + 'jul', 'aug', 'sep', 'oct', 'nov', 'dec'] + }, + 'names': ['January', 'February', 'March', 'April', 'May', 'June', + 'July', 'August', 'September', 'October', 'November', 'December'], + 'genitive': ['January', 'February', 'March', 'April', 'May', 'June', + 'July', 'August', 'September', 'October', 'November', 'December'], + 'abbrev': ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', + 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] + }; + }, + teardown: function () { + mw.language.months = this.liveMonths; + }, + config: { + wgContentLanguage: 'en', + /* default date format of the content language */ + wgDefaultDateFormat: 'dmy', + /* These two are important for numeric interpretations */ + wgSeparatorTransformTable: ['', ''], + wgDigitTransformTable: ['', ''] + } + } ) ); + + /** + * For a value, check if the parser recognizes it and how it transforms it + * + * @param {String} msg text to pass on to qunit describing the test case + * @param {String[]} parserId of the parser that will be tested + * @param {String[][]} data Array of testcases. Each testcase, array of + * inputValue: The string value that we want to test the parser for + * recognized: If we expect that this value's type is detectable by the parser + * outputValue: The value the parser has converted the input to + * msg: describing the testcase + * @param {function($table)} callback something to do before we start the testcase + */ + function parserTest( msg, parserId, data, callback ) { + QUnit.test( msg, data.length * 2, function ( assert ) { + var extractedR, extractedF, parser; + + if (callback !== undefined ) { + callback(); + } + + parser = $.tablesorter.getParser( parserId ); + $.each( data, function ( index, testcase ) { + extractedR = parser.is( testcase[0] ); + extractedF = parser.format( testcase[0] ); + + assert.strictEqual( extractedR, testcase[1], 'Detect: ' + testcase[3] ); + assert.strictEqual( extractedF, testcase[2], 'Sortkey: ' + testcase[3] ); + } ); + + } ); + } + + text = [ + [ 'Mars', true, 'mars', 'Simple text' ], + [ 'Mẘas', true, 'mẘas', 'Non ascii character' ], + [ 'A sentence', true, 'a sentence', 'A sentence with space chars' ] + ]; + parserTest( 'Textual keys', 'text', text ); + + ipv4 = [ + // Some randomly generated fake IPs + ['0.0.0.0', true, 0, 'An IP address' ], + ['255.255.255.255', true, 255255255255, 'An IP address' ], + ['45.238.27.109', true, 45238027109, 'An IP address' ], + ['1.238.27.1', true, 1238027001, 'An IP address with small numbers' ], + ['238.27.1', false, 238027001, 'A malformed IP Address' ], + ['1', false, 1, 'A super malformed IP Address' ], + ['Just text', false, 0, 'A line with just text' ], + ['45.238.27.109Postfix', false, 45238027109, 'An IP address with a connected postfix' ], + ['45.238.27.109 postfix', false, 45238027109, 'An IP address with a seperated postfix' ] + ]; + parserTest( 'IPv4', 'IPAddress', ipv4 ); + + simpleMDYDatesInMDY = [ + ['January 17, 2010', true, 20100117, 'Long middle endian date'], + ['Jan 17, 2010', true, 20100117, 'Short middle endian date'], + ['1/17/2010', true, 20100117, 'Numeric middle endian date'], + ['01/17/2010', true, 20100117, 'Numeric middle endian date with padding on month'], + ['01/07/2010', true, 20100107, 'Numeric middle endian date with padding on day'], + ['01/07/0010', true, 20100107, 'Numeric middle endian date with padding on year'], + ['5.12.1990', true, 19900512, 'Numeric middle endian date with . separator'] + ]; + parserTest( 'MDY Dates using mdy content language', 'date', simpleMDYDatesInMDY ); + + simpleMDYDatesInDMY = [ + ['January 17, 2010', true, 20100117, 'Long middle endian date'], + ['Jan 17, 2010', true, 20100117, 'Short middle endian date'], + ['1/17/2010', true, 20101701, 'Numeric middle endian date'], + ['01/17/2010', true, 20101701, 'Numeric middle endian date with padding on month'], + ['01/07/2010', true, 20100701, 'Numeric middle endian date with padding on day'], + ['01/07/0010', true, 20100701, 'Numeric middle endian date with padding on year'], + ['5.12.1990', true, 19901205, 'Numeric middle endian date with . separator'] + ]; + parserTest( 'MDY Dates using dmy content language', 'date', simpleMDYDatesInDMY, function () { + mw.config.set( { + 'wgDefaultDateFormat': 'dmy', + 'wgContentLanguage': 'de' + } ); + } ); + + oldMDYDates = [ + ['January 19, 1400 BC', false, '99999999', 'BC'], + ['January 19, 1400BC', false, '99999999', 'Connected BC'], + ['January, 19 1400 B.C.', false, '99999999', 'B.C.'], + ['January 19, 1400 AD', false, '99999999', 'AD'], + ['January, 19 10', true, 20100119, 'AD'], + ['January, 19 1', false, '99999999', 'AD'] + ]; + parserTest( 'Very old MDY dates', 'date', oldMDYDates ); + + complexMDYDates = [ + ['January, 19 2010', true, 20100119, 'Comma after month'], + ['January 19, 2010', true, 20100119, 'Comma after day'], + ['January/19/2010', true, 20100119, 'Forward slash separator'], + ['04 22 1991', true, 19910422, 'Month with 0 padding'], + ['April 21 1991', true, 19910421, 'Space separation'], + ['04 22 1991', true, 19910422, 'Month with 0 padding'], + ['December 12 \'10', true, 20101212, ''], + ['Dec 12 \'10', true, 20101212, ''], + ['Dec. 12 \'10', true, 20101212, ''] + ]; + parserTest( 'MDY Dates', 'date', complexMDYDates ); + + clobberedDates = [ + ['January, 19 2010 - January, 20 2010', false, '99999999', 'Date range with hyphen'], + ['January, 19 2010 — January, 20 2010', false, '99999999', 'Date range with mdash'], + ['prefixJanuary, 19 2010', false, '99999999', 'Connected prefix'], + ['prefix January, 19 2010', false, '99999999', 'Prefix'], + ['December 12 2010postfix', false, '99999999', 'ConnectedPostfix'], + ['December 12 2010 postfix', false, '99999999', 'Postfix'], + ['A simple text', false, '99999999', 'Plain text in date sort'], + ['04l22l1991', false, '99999999', 'l char as separator'], + ['January\\19\\2010', false, '99999999', 'backslash as date separator'] + ]; + parserTest( 'Clobbered Dates', 'date', clobberedDates ); + + MYDates = [ + ['December 2010', false, '99999999', 'Plain month year'], + ['Dec 2010', false, '99999999', 'Abreviated month year'], + ['12 2010', false, '99999999', 'Numeric month year'] + ]; + parserTest( 'MY Dates', 'date', MYDates ); + + YDates = [ + ['2010', false, '99999999', 'Plain 4-digit year'], + ['876', false, '99999999', '3-digit year'], + ['76', false, '99999999', '2-digit year'], + ['\'76', false, '99999999', '2-digit millenium bug year'], + ['2010 BC', false, '99999999', '4-digit year BC'] + ]; + parserTest( 'Y Dates', 'date', YDates ); + + currencyData = [ + ['1.02 $', true, 1.02, ''], + ['$ 3.00', true, 3, ''], + ['€ 2,99', true, 299, ''], + ['$ 1.00', true, 1, ''], + ['$3.50', true, 3.50, ''], + ['$ 1.50', true, 1.50, ''], + ['€ 0.99', true, 0.99, ''], + ['$ 299.99', true, 299.99, ''], + ['$ 2,299.99', true, 2299.99, ''], + ['$ 2,989', true, 2989, ''], + ['$ 2 299.99', true, 2299.99, ''], + ['$ 2 989', true, 2989, ''], + ['$ 2.989', true, 2.989, ''] + ]; + parserTest( 'Currency', 'currency', currencyData ); + + transformedCurrencyData = [ + ['1.02 $', true, 102, ''], + ['$ 3.00', true, 300, ''], + ['€ 2,99', true, 2.99, ''], + ['$ 1.00', true, 100, ''], + ['$3.50', true, 350, ''], + ['$ 1.50', true, 150, ''], + ['€ 0.99', true, 99, ''], + ['$ 299.99', true, 29999, ''], + ['$ 2\'299,99', true, 2299.99, ''], + ['$ 2,989', true, 2.989, ''], + ['$ 2 299.99', true, 229999, ''], + ['2 989 $', true, 2989, ''], + ['299.99 $', true, 29999, ''], + ['2\'299,99 $', true, 2299.99, ''], + ['2,989 $', true, 2.989, ''], + ['2 299.99 $', true, 229999, ''], + ['2 989 $', true, 2989, ''] + ]; + parserTest( 'Currency with european separators', 'currency', transformedCurrencyData, function () { + mw.config.set( { + // We expect 22'234.444,22 + // Map from ascii separators => localized separators + wgSeparatorTransformTable: [', . ,', '\' , .'], + wgDigitTransformTable: ['', ''] + } ); + } ); + + // TODO add numbers sorting tests for bug 8115 with a different language + +}( jQuery, mediaWiki ) ); diff --git a/tests/qunit/suites/resources/jquery/jquery.tablesorter.test.js b/tests/qunit/suites/resources/jquery/jquery.tablesorter.test.js index 92dad9ff..f63aa27a 100644 --- a/tests/qunit/suites/resources/jquery/jquery.tablesorter.test.js +++ b/tests/qunit/suites/resources/jquery/jquery.tablesorter.test.js @@ -156,9 +156,29 @@ ]; QUnit.module( 'jquery.tablesorter', QUnit.newMwEnvironment( { + setup: function () { + this.liveMonths = mw.language.months; + mw.language.months = { + 'keys': { + 'names': ['january', 'february', 'march', 'april', 'may_long', 'june', + 'july', 'august', 'september', 'october', 'november', 'december'], + 'genitive': ['january-gen', 'february-gen', 'march-gen', 'april-gen', 'may-gen', 'june-gen', + 'july-gen', 'august-gen', 'september-gen', 'october-gen', 'november-gen', 'december-gen'], + 'abbrev': ['jan', 'feb', 'mar', 'apr', 'may', 'jun', + 'jul', 'aug', 'sep', 'oct', 'nov', 'dec'] + }, + 'names': ['January', 'February', 'March', 'April', 'May', 'June', + 'July', 'August', 'September', 'October', 'November', 'December'], + 'genitive': ['January', 'February', 'March', 'April', 'May', 'June', + 'July', 'August', 'September', 'October', 'November', 'December'], + 'abbrev': ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', + 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] + }; + }, + teardown: function () { + mw.language.months = this.liveMonths; + }, config: { - wgMonthNames: ['', 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], - wgMonthNamesShort: ['', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], wgDefaultDateFormat: 'dmy', wgSeparatorTransformTable: ['', ''], wgDigitTransformTable: ['', ''], @@ -1160,11 +1180,11 @@ '</table>' ); $table.tablesorter(); - assert.equal( $table.find( '#A2' ).prop( 'headerIndex' ), + assert.equal( $table.find( '#A2' ).data( 'headerIndex' ), undefined, 'A2 should not be a sort header' ); - assert.equal( $table.find( '#C1' ).prop( 'headerIndex' ), + assert.equal( $table.find( '#C1' ).data( 'headerIndex' ), 2, 'C1 should be a sort header' ); @@ -1181,11 +1201,11 @@ '</table>' ); $table.tablesorter(); - assert.equal( $table.find( '#C2' ).prop( 'headerIndex' ), + assert.equal( $table.find( '#C2' ).data( 'headerIndex' ), 2, 'C2 should be a sort header' ); - assert.equal( $table.find( '#C1' ).prop( 'headerIndex' ), + assert.equal( $table.find( '#C1' ).data( 'headerIndex' ), undefined, 'C1 should not be a sort header' ); @@ -1209,18 +1229,19 @@ // bug 53211 - exploding rowspans in more complex cases QUnit.test( 'Rowspan exploding with row headers and colspans', 1, function ( assert ) { - var $table = $( '<table class="sortable">' + - '<thead><tr><th rowspan="2">n</th><th colspan="2">foo</th><th rowspan="2">baz</th></tr>' + - '<tr><th>foo</th><th>bar</th></tr></thead>' + - '<tbody>' + - '<tr><td>1</td><td>foo</td><td>bar</td><td>baz</td></tr>' + - '<tr><td>2</td><td>foo</td><td>bar</td><td>baz</td></tr>' + - '</tbody></table>' ); + var $table = $( '<table class="sortable">' + + '<thead><tr><th rowspan="2">n</th><th colspan="2">foo</th><th rowspan="2">baz</th></tr>' + + '<tr><th>foo</th><th>bar</th></tr></thead>' + + '<tbody>' + + '<tr><td>1</td><td>foo</td><td>bar</td><td>baz</td></tr>' + + '<tr><td>2</td><td>foo</td><td>bar</td><td>baz</td></tr>' + + '</tbody></table>' ); $table.tablesorter(); - assert.equal( $table.find( 'tr:eq(1) th:eq(1)').prop('headerIndex'), + assert.equal( $table.find( 'tr:eq(1) th:eq(1)').data('headerIndex'), 2, - 'Incorrect index of sort header' ); + 'Incorrect index of sort header' + ); } ); diff --git a/tests/qunit/suites/resources/mediawiki.api/mediawiki.api.options.test.js b/tests/qunit/suites/resources/mediawiki.api/mediawiki.api.options.test.js new file mode 100644 index 00000000..c0a6585f --- /dev/null +++ b/tests/qunit/suites/resources/mediawiki.api/mediawiki.api.options.test.js @@ -0,0 +1,78 @@ +( function ( mw ) { + QUnit.module( 'mediawiki.api.options', QUnit.newMwEnvironment( { + setup: function () { + this.server = this.sandbox.useFakeServer(); + } + } ) ); + + QUnit.test( 'saveOption', function ( assert ) { + QUnit.expect( 2 ); + + var + api = new mw.Api(), + stub = this.sandbox.stub( mw.Api.prototype, 'saveOptions' ); + + api.saveOption( 'foo', 'bar' ); + + assert.ok( stub.calledOnce, '#saveOptions called once' ); + assert.deepEqual( stub.getCall( 0 ).args, [ { foo: 'bar' } ], '#saveOptions called correctly' ); + } ); + + QUnit.test( 'saveOptions', function ( assert ) { + QUnit.expect( 13 ); + + var api = new mw.Api(); + + // We need to respond to the request for token first, otherwise the other requests won't be sent + // until after the server.respond call, which confuses sinon terribly. This sucks a lot. + api.getToken( 'options' ); + this.server.respond( + /action=tokens.*&type=options/, + [ 200, { 'Content-Type': 'application/json' }, + '{ "tokens": { "optionstoken": "+\\\\" } }' ] + ); + + api.saveOptions( {} ).done( function () { + assert.ok( true, 'Request completed: empty case' ); + } ); + api.saveOptions( { foo: 'bar' } ).done( function () { + assert.ok( true, 'Request completed: simple' ); + } ); + api.saveOptions( { foo: 'bar', baz: 'quux' } ).done( function () { + assert.ok( true, 'Request completed: two options' ); + } ); + api.saveOptions( { foo: 'bar|quux', bar: 'a|b|c', baz: 'quux' } ).done( function () { + assert.ok( true, 'Request completed: not bundleable' ); + } ); + api.saveOptions( { foo: null } ).done( function () { + assert.ok( true, 'Request completed: reset an option' ); + } ); + api.saveOptions( { 'foo|bar=quux': null } ).done( function () { + assert.ok( true, 'Request completed: reset an option, not bundleable' ); + } ); + + // Requests are POST, match requestBody instead of url + this.server.respond( function ( request ) { + switch ( request.requestBody ) { + // simple + case 'action=options&format=json&change=foo%3Dbar&token=%2B%5C': + // two options + case 'action=options&format=json&change=foo%3Dbar%7Cbaz%3Dquux&token=%2B%5C': + // not bundleable + case 'action=options&format=json&optionname=foo&optionvalue=bar%7Cquux&token=%2B%5C': + case 'action=options&format=json&optionname=bar&optionvalue=a%7Cb%7Cc&token=%2B%5C': + case 'action=options&format=json&change=baz%3Dquux&token=%2B%5C': + // reset an option + case 'action=options&format=json&change=foo&token=%2B%5C': + // reset an option, not bundleable + case 'action=options&format=json&optionname=foo%7Cbar%3Dquux&token=%2B%5C': + assert.ok( true, 'Repond to ' + request.requestBody ); + request.respond( 200, { 'Content-Type': 'application/json' }, + '{ "options": "success" }' ); + break; + default: + assert.ok( false, 'Unexpected request:' + request.requestBody ); + } + } ); + } ); +}( mediaWiki ) ); diff --git a/tests/qunit/suites/resources/mediawiki.api/mediawiki.api.test.js b/tests/qunit/suites/resources/mediawiki.api/mediawiki.api.test.js index f156c728..b89526fb 100644 --- a/tests/qunit/suites/resources/mediawiki.api/mediawiki.api.test.js +++ b/tests/qunit/suites/resources/mediawiki.api/mediawiki.api.test.js @@ -51,52 +51,26 @@ this.server.respond( function ( request ) { if ( window.FormData ) { - assert.ok( !request.url.match( /action=/), 'Request has no query string' ); + assert.ok( !request.url.match( /action=/ ), 'Request has no query string' ); assert.ok( request.requestBody instanceof FormData, 'Request uses FormData body' ); } else { - assert.ok( !request.url.match( /action=test/), 'Request has no query string' ); + assert.ok( !request.url.match( /action=test/ ), 'Request has no query string' ); assert.equal( request.requestBody, 'action=test&format=json', 'Request uses query string body' ); } request.respond( 200, { 'Content-Type': 'application/json' }, '[]' ); } ); } ); - QUnit.test( 'Deprecated callback methods', function ( assert ) { - QUnit.expect( 3 ); + QUnit.test( 'Converting arrays to pipe-separated', function ( assert ) { + QUnit.expect( 1 ); var api = new mw.Api(); + api.get( { test: [ 'foo', 'bar', 'baz' ] } ); - this.suppressWarnings(); - - api.get( {}, function () { - assert.ok( true, 'Function argument treated as success callback.' ); - } ); - - api.get( {}, { - ok: function () { - assert.ok( true, '"ok" property treated as success callback.' ); - } - } ); - - api.get( { action: 'doesntexist' }, { - err: function () { - assert.ok( true, '"err" property treated as error callback.' ); - } - } ); - - this.restoreWarnings(); - - this.server.respondWith( /action=query/, function ( request ) { + this.server.respond( function ( request ) { + assert.ok( request.url.match( /test=foo%7Cbar%7Cbaz/ ), 'Pipe-separated value was submitted' ); request.respond( 200, { 'Content-Type': 'application/json' }, '[]' ); } ); - - this.server.respondWith( /action=doesntexist/, function ( request ) { - request.respond( 200, { 'Content-Type': 'application/json' }, - '{ "error": { "code": "unknown_action" } }' - ); - } ); - - this.server.respond(); } ); QUnit.test( 'getToken( pre-populated )', function ( assert ) { @@ -196,6 +170,28 @@ ); } ); + QUnit.test( 'postWithToken( tokenType, params with assert )', function ( assert ) { + QUnit.expect( 2 ); + + var api = new mw.Api( { ajax: { url: '/postWithToken/api.php' } } ); + + api.postWithToken( 'testasserttoken', { action: 'example', key: 'foo', assert: 'user' } ) + .fail( function ( errorCode ) { + assert.equal( errorCode, 'assertuserfailed', 'getToken fails assert' ); + } ); + + assert.equal( this.server.requests.length, 1, 'Request for token made' ); + this.server.respondWith( /assert=user/, function ( request ) { + request.respond( + 200, + { 'Content-Type': 'application/json' }, + '{ "error": { "code": "assertuserfailed", "info": "Assertion failed" } }' + ); + } ); + + this.server.respond(); + } ); + QUnit.test( 'postWithToken( tokenType, params, ajaxOptions )', function ( assert ) { QUnit.expect( 3 ); diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.Title.test.js b/tests/qunit/suites/resources/mediawiki/mediawiki.Title.test.js index 7ab309aa..c0afe07c 100644 --- a/tests/qunit/suites/resources/mediawiki/mediawiki.Title.test.js +++ b/tests/qunit/suites/resources/mediawiki/mediawiki.Title.test.js @@ -46,8 +46,8 @@ // Note: The ones with # are commented out as those are interpreted as fragment and // as such end up being valid. 'A é B', - //'A é B', - //'A é B', + // 'A é B', + // 'A é B', // Subject of NS_TALK does not roundtrip to NS_MAIN 'Talk:File:Example.svg', // Directory navigation @@ -437,33 +437,34 @@ } ); QUnit.test( 'getRelativeText', 5, function ( assert ) { - var cases = [ - { - text: 'asd', - relativeTo: 123, - expectedResult: ':Asd' - }, - { - text: 'dfg', - relativeTo: 0, - expectedResult: 'Dfg' - }, - { - text: 'Template:Ghj', - relativeTo: 0, - expectedResult: 'Template:Ghj' - }, - { - text: 'Template:1', - relativeTo: 10, - expectedResult: '1' - }, - { - text: 'User:Hi', - relativeTo: 10, - expectedResult: 'User:Hi' - } - ], i, thisCase, title; + var i, thisCase, title, + cases = [ + { + text: 'asd', + relativeTo: 123, + expectedResult: ':Asd' + }, + { + text: 'dfg', + relativeTo: 0, + expectedResult: 'Dfg' + }, + { + text: 'Template:Ghj', + relativeTo: 0, + expectedResult: 'Template:Ghj' + }, + { + text: 'Template:1', + relativeTo: 10, + expectedResult: '1' + }, + { + text: 'User:Hi', + relativeTo: 10, + expectedResult: 'User:Hi' + } + ]; for ( i = 0; i < cases.length; i++ ) { thisCase = cases[i]; diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.Uri.test.js b/tests/qunit/suites/resources/mediawiki/mediawiki.Uri.test.js index 7a58d38d..ba366553 100644 --- a/tests/qunit/suites/resources/mediawiki/mediawiki.Uri.test.js +++ b/tests/qunit/suites/resources/mediawiki/mediawiki.Uri.test.js @@ -314,6 +314,66 @@ assert.equal( uri.toString(), 'http://www.example.com/dir/', 'empty array value is ommitted' ); } ); + QUnit.test( 'Variable defaultUri', 2, function ( assert ) { + var uri, + href = 'http://example.org/w/index.php#here', + UriClass = mw.UriRelative( function () { + return href; + } ); + + uri = new UriClass(); + assert.deepEqual( + { + protocol: uri.protocol, + user: uri.user, + password: uri.password, + host: uri.host, + port: uri.port, + path: uri.path, + query: uri.query, + fragment: uri.fragment + }, + { + protocol: 'http', + user: undefined, + password: undefined, + host: 'example.org', + port: undefined, + path: '/w/index.php', + query: {}, + fragment: 'here' + }, + 'basic object properties' + ); + + // Default URI may change, e.g. via history.replaceState, pushState or location.hash (T74334) + href = 'https://example.com/wiki/Foo?v=2'; + uri = new UriClass(); + assert.deepEqual( + { + protocol: uri.protocol, + user: uri.user, + password: uri.password, + host: uri.host, + port: uri.port, + path: uri.path, + query: uri.query, + fragment: uri.fragment + }, + { + protocol: 'https', + user: undefined, + password: undefined, + host: 'example.com', + port: undefined, + path: '/wiki/Foo', + query: { 'v': '2' }, + fragment: undefined + }, + 'basic object properties' + ); + } ); + QUnit.test( 'Advanced URL', 11, function ( assert ) { var uri, queryString, relativePath; @@ -429,6 +489,5 @@ uri = new UriClass( testPath ); href = uri.toString(); assert.equal( href, testProtocol + testServer + ':' + testPort + testPath, 'Root-relative URL gets host, protocol, and port supplied' ); - } ); }( mediaWiki, jQuery ) ); diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.cookie.test.js b/tests/qunit/suites/resources/mediawiki/mediawiki.cookie.test.js index c9653dab..f5f199ea 100644 --- a/tests/qunit/suites/resources/mediawiki/mediawiki.cookie.test.js +++ b/tests/qunit/suites/resources/mediawiki/mediawiki.cookie.test.js @@ -53,7 +53,7 @@ assert.strictEqual( call[ 1 ], '0', '0 is value' ); } ); - QUnit.test( 'set( key, value, expires )', 5, function ( assert ) { + QUnit.test( 'set( key, value, expires )', 6, function ( assert ) { var date, options; date = new Date(); @@ -61,15 +61,22 @@ mw.cookie.set( 'foo', 'bar' ); options = $.cookie.lastCall.args[ 2 ]; - assert.deepEqual( options.expires, expiryDate, 'Default cookie expiration is used' ); + assert.deepEqual( options.expires, expiryDate, 'default expiration' ); mw.cookie.set( 'foo', 'bar', date ); options = $.cookie.lastCall.args[ 2 ]; - assert.strictEqual( options.expires, date, 'Custom expiration date' ); + assert.strictEqual( options.expires, date, 'custom expiration as Date' ); + + date = new Date(); + date.setDate( date.getDate() + 1 ); + + mw.cookie.set( 'foo', 'bar', 86400 ); + options = $.cookie.lastCall.args[ 2 ]; + assert.deepEqual( options.expires, date, 'custom expiration as lifetime in seconds' ); mw.cookie.set( 'foo', 'bar', null ); options = $.cookie.lastCall.args[ 2 ]; - assert.strictEqual( options.expires, undefined, 'Expiry null forces session cookie' ); + assert.strictEqual( options.expires, undefined, 'null forces session cookie' ); // Per DefaultSettings.php, when wgCookieExpiration is 0, the default should // be session cookies @@ -81,7 +88,7 @@ mw.cookie.set( 'foo', 'bar', date ); options = $.cookie.lastCall.args[ 2 ]; - assert.strictEqual( options.expires, date, 'Custom expiration when default is session cookies' ); + assert.strictEqual( options.expires, date, 'custom expiration (with wgCookieExpiration=0)' ); } ); QUnit.test( 'set( key, value, options )', 4, function ( assert ) { @@ -169,4 +176,4 @@ assert.strictEqual( key, 'barfoo' ); } ); -} ( mediaWiki, jQuery ) ); +}( mediaWiki, jQuery ) ); diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.errorLogger.test.js b/tests/qunit/suites/resources/mediawiki/mediawiki.errorLogger.test.js new file mode 100644 index 00000000..7c3f1ecb --- /dev/null +++ b/tests/qunit/suites/resources/mediawiki/mediawiki.errorLogger.test.js @@ -0,0 +1,42 @@ +( function ( $, mw ) { + QUnit.module( 'mediawiki.errorLogger', QUnit.newMwEnvironment() ); + + QUnit.test( 'installGlobalHandler', 7, function ( assert ) { + var w = {}, + errorMessage = 'Foo', + errorUrl = 'http://example.com', + errorLine = '123', + errorColumn = '45', + errorObject = new Error( 'Foo'), + oldHandler = this.sandbox.stub(); + + this.sandbox.stub( mw, 'track' ); + + mw.errorLogger.installGlobalHandler( w ); + + assert.ok( w.onerror, 'Global handler has been installed' ); + assert.strictEqual( w.onerror( errorMessage, errorUrl, errorLine ), false, + 'Global handler returns false when there is no previous handler' ); + sinon.assert.calledWithExactly( mw.track, 'global.error', + sinon.match( { errorMessage: errorMessage, url: errorUrl, lineNumber: errorLine } ) ); + + mw.track.reset(); + w.onerror( errorMessage, errorUrl, errorLine, errorColumn, errorObject ); + sinon.assert.calledWithExactly( mw.track, 'global.error', + sinon.match( { errorMessage: errorMessage, url: errorUrl, lineNumber: errorLine, + columnNumber: errorColumn, errorObject: errorObject } ) ); + + w = { onerror: oldHandler }; + + mw.errorLogger.installGlobalHandler( w ); + w.onerror( errorMessage, errorUrl, errorLine ); + sinon.assert.calledWithExactly( oldHandler, errorMessage, errorUrl, errorLine ); + + oldHandler.returns( false ); + assert.strictEqual( w.onerror( errorMessage, errorUrl, errorLine ), false, + 'Global handler preserves false return from previous handler' ); + oldHandler.returns( true ); + assert.strictEqual( w.onerror( errorMessage, errorUrl, errorLine ), true, + 'Global handler preserves true return from previous handler' ); + } ); +}( jQuery, mediaWiki ) ); diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.jqueryMsg.test.js b/tests/qunit/suites/resources/mediawiki/mediawiki.jqueryMsg.test.js index 6b3be43b..7e23e2ff 100644 --- a/tests/qunit/suites/resources/mediawiki/mediawiki.jqueryMsg.test.js +++ b/tests/qunit/suites/resources/mediawiki/mediawiki.jqueryMsg.test.js @@ -55,7 +55,9 @@ 'jquerymsg-test-version-entrypoints-index-php': '[https://www.mediawiki.org/wiki/Manual:index.php index.php]', - 'external-link-replace': 'Foo [$1 bar]' + 'external-link-replace': 'Foo [$1 bar]', + 'external-link-plural': 'Foo {{PLURAL:$1|is [$2 one]|are [$2 some]|2=[$2 two]|3=three|4=a=b|5=}} things.', + 'plural-only-explicit-forms': 'It is a {{PLURAL:$1|1=single|2=double}} room.' } } ) ); @@ -107,7 +109,7 @@ run(); } - QUnit.test( 'Replace', 9, function ( assert ) { + QUnit.test( 'Replace', 16, function ( assert ) { mw.messages.set( 'simple', 'Foo $1 baz $2' ); assert.equal( formatParse( 'simple' ), 'Foo $1 baz $2', 'Replacements with no substitutes' ); @@ -155,6 +157,41 @@ 'Foo <a href="http://example.org/?x=y&z">bar</a>', 'Href is not double-escaped in wikilink function' ); + assert.equal( + formatParse( 'external-link-plural', 1, 'http://example.org' ), + 'Foo is <a href="http://example.org">one</a> things.', + 'Link is expanded inside plural and is not escaped html' + ); + assert.equal( + formatParse( 'external-link-plural', 2, 'http://example.org' ), + 'Foo <a href=\"http://example.org\">two</a> things.', + 'Link is expanded inside an explicit plural form and is not escaped html' + ); + assert.equal( + formatParse( 'external-link-plural', 3 ), + 'Foo three things.', + 'A simple explicit plural form co-existing with complex explicit plural forms' + ); + assert.equal( + formatParse( 'external-link-plural', 4, 'http://example.org' ), + 'Foo a=b things.', + 'Only first equal sign is used as delimiter for explicit plural form. Repeated equal signs does not create issue' + ); + assert.equal( + formatParse( 'external-link-plural', 5, 'http://example.org' ), + 'Foo are <a href="http://example.org">some</a> things.', + 'Invalid explicit plural form. Plural fallback to the "other" plural form' + ); + assert.equal( + formatParse( 'external-link-plural', 6, 'http://example.org' ), + 'Foo are <a href="http://example.org">some</a> things.', + 'Plural fallback to the "other" plural form' + ); + assert.equal( + formatParse( 'plural-only-explicit-forms', 2 ), + 'It is a double room.', + 'Plural with explicit forms alone.' + ); } ); QUnit.test( 'Plural', 6, function ( assert ) { @@ -505,274 +542,274 @@ mw.jqueryMsg.getMessageFunction = oldGMF; } ); -formatnumTests = [ - { - lang: 'en', - number: 987654321.654321, - result: '987,654,321.654', - description: 'formatnum test for English, decimal seperator' - }, - { - lang: 'ar', - number: 987654321.654321, - result: '٩٨٧٬٦٥٤٬٣٢١٫٦٥٤', - description: 'formatnum test for Arabic, with decimal seperator' - }, - { - lang: 'ar', - number: '٩٨٧٦٥٤٣٢١٫٦٥٤٣٢١', - result: 987654321, - integer: true, - description: 'formatnum test for Arabic, with decimal seperator, reverse' - }, - { - lang: 'ar', - number: -12.89, - result: '-١٢٫٨٩', - description: 'formatnum test for Arabic, negative number' - }, - { - lang: 'ar', - number: '-١٢٫٨٩', - result: -12, - integer: true, - description: 'formatnum test for Arabic, negative number, reverse' - }, - { - lang: 'nl', - number: 987654321.654321, - result: '987.654.321,654', - description: 'formatnum test for Nederlands, decimal seperator' - }, - { - lang: 'nl', - number: -12.89, - result: '-12,89', - description: 'formatnum test for Nederlands, negative number' - }, - { - lang: 'nl', - number: '.89', - result: '0,89', - description: 'formatnum test for Nederlands' - }, - { - lang: 'nl', - number: 'invalidnumber', - result: 'invalidnumber', - description: 'formatnum test for Nederlands, invalid number' - }, - { - lang: 'ml', - number: '1000000000', - result: '1,00,00,00,000', - description: 'formatnum test for Malayalam' - }, - { - lang: 'ml', - number: '-1000000000', - result: '-1,00,00,00,000', - description: 'formatnum test for Malayalam, negative number' - }, - /* - * This will fail because of wrong pattern for ml in MW(different from CLDR) - { - lang: 'ml', - number: '1000000000.000', - result: '1,00,00,00,000.000', - description: 'formatnum test for Malayalam with decimal place' - }, - */ - { - lang: 'hi', - number: '123456789.123456789', - result: '१२,३४,५६,७८९', - description: 'formatnum test for Hindi' - }, - { - lang: 'hi', - number: '१२,३४,५६,७८९', - result: '१२,३४,५६,७८९', - description: 'formatnum test for Hindi, Devanagari digits passed' - }, - { - lang: 'hi', - number: '१२३४५६,७८९', - result: '123456', - integer: true, - description: 'formatnum test for Hindi, Devanagari digits passed to get integer value' - } -]; - -QUnit.test( 'formatnum', formatnumTests.length, function ( assert ) { - mw.messages.set( 'formatnum-msg', '{{formatnum:$1}}' ); - mw.messages.set( 'formatnum-msg-int', '{{formatnum:$1|R}}' ); - var queue = $.map( formatnumTests, function ( test ) { - return function ( next ) { - getMwLanguage( test.lang ) - .done( function ( langClass ) { - mw.config.set( 'wgUserLanguage', test.lang ); - var parser = new mw.jqueryMsg.parser( { language: langClass } ); - assert.equal( - parser.parse( test.integer ? 'formatnum-msg-int' : 'formatnum-msg', - [ test.number ] ).html(), - test.result, - test.description - ); - } ) - .fail( function () { - assert.ok( false, 'Language "' + test.lang + '" failed to load' ); - } ) - .always( next ); - }; + formatnumTests = [ + { + lang: 'en', + number: 987654321.654321, + result: '987,654,321.654', + description: 'formatnum test for English, decimal separator' + }, + { + lang: 'ar', + number: 987654321.654321, + result: '٩٨٧٬٦٥٤٬٣٢١٫٦٥٤', + description: 'formatnum test for Arabic, with decimal separator' + }, + { + lang: 'ar', + number: '٩٨٧٦٥٤٣٢١٫٦٥٤٣٢١', + result: 987654321, + integer: true, + description: 'formatnum test for Arabic, with decimal separator, reverse' + }, + { + lang: 'ar', + number: -12.89, + result: '-١٢٫٨٩', + description: 'formatnum test for Arabic, negative number' + }, + { + lang: 'ar', + number: '-١٢٫٨٩', + result: -12, + integer: true, + description: 'formatnum test for Arabic, negative number, reverse' + }, + { + lang: 'nl', + number: 987654321.654321, + result: '987.654.321,654', + description: 'formatnum test for Nederlands, decimal separator' + }, + { + lang: 'nl', + number: -12.89, + result: '-12,89', + description: 'formatnum test for Nederlands, negative number' + }, + { + lang: 'nl', + number: '.89', + result: '0,89', + description: 'formatnum test for Nederlands' + }, + { + lang: 'nl', + number: 'invalidnumber', + result: 'invalidnumber', + description: 'formatnum test for Nederlands, invalid number' + }, + { + lang: 'ml', + number: '1000000000', + result: '1,00,00,00,000', + description: 'formatnum test for Malayalam' + }, + { + lang: 'ml', + number: '-1000000000', + result: '-1,00,00,00,000', + description: 'formatnum test for Malayalam, negative number' + }, + /* + * This will fail because of wrong pattern for ml in MW(different from CLDR) + { + lang: 'ml', + number: '1000000000.000', + result: '1,00,00,00,000.000', + description: 'formatnum test for Malayalam with decimal place' + }, + */ + { + lang: 'hi', + number: '123456789.123456789', + result: '१२,३४,५६,७८९', + description: 'formatnum test for Hindi' + }, + { + lang: 'hi', + number: '१२,३४,५६,७८९', + result: '१२,३४,५६,७८९', + description: 'formatnum test for Hindi, Devanagari digits passed' + }, + { + lang: 'hi', + number: '१२३४५६,७८९', + result: '123456', + integer: true, + description: 'formatnum test for Hindi, Devanagari digits passed to get integer value' + } + ]; + + QUnit.test( 'formatnum', formatnumTests.length, function ( assert ) { + mw.messages.set( 'formatnum-msg', '{{formatnum:$1}}' ); + mw.messages.set( 'formatnum-msg-int', '{{formatnum:$1|R}}' ); + var queue = $.map( formatnumTests, function ( test ) { + return function ( next ) { + getMwLanguage( test.lang ) + .done( function ( langClass ) { + mw.config.set( 'wgUserLanguage', test.lang ); + var parser = new mw.jqueryMsg.parser( { language: langClass } ); + assert.equal( + parser.parse( test.integer ? 'formatnum-msg-int' : 'formatnum-msg', + [ test.number ] ).html(), + test.result, + test.description + ); + } ) + .fail( function () { + assert.ok( false, 'Language "' + test.lang + '" failed to load' ); + } ) + .always( next ); + }; + } ); + QUnit.stop(); + process( queue, QUnit.start ); + } ); + + // HTML in wikitext + QUnit.test( 'HTML', 26, function ( assert ) { + mw.messages.set( 'jquerymsg-italics-msg', '<i>Very</i> important' ); + + assertBothModes( assert, ['jquerymsg-italics-msg'], mw.messages.get( 'jquerymsg-italics-msg' ), 'Simple italics unchanged' ); + + mw.messages.set( 'jquerymsg-bold-msg', '<b>Strong</b> speaker' ); + assertBothModes( assert, ['jquerymsg-bold-msg'], mw.messages.get( 'jquerymsg-bold-msg' ), 'Simple bold unchanged' ); + + mw.messages.set( 'jquerymsg-bold-italics-msg', 'It is <b><i>key</i></b>' ); + assertBothModes( assert, ['jquerymsg-bold-italics-msg'], mw.messages.get( 'jquerymsg-bold-italics-msg' ), 'Bold and italics nesting order preserved' ); + + mw.messages.set( 'jquerymsg-italics-bold-msg', 'It is <i><b>vital</b></i>' ); + assertBothModes( assert, ['jquerymsg-italics-bold-msg'], mw.messages.get( 'jquerymsg-italics-bold-msg' ), 'Italics and bold nesting order preserved' ); + + mw.messages.set( 'jquerymsg-italics-with-link', 'An <i>italicized [[link|wiki-link]]</i>' ); + + assert.htmlEqual( + formatParse( 'jquerymsg-italics-with-link' ), + 'An <i>italicized <a title="link" href="' + mw.html.escape( mw.util.getUrl( 'link' ) ) + '">wiki-link</i>', + 'Italics with link inside in parse mode' + ); + + assert.equal( + formatText( 'jquerymsg-italics-with-link' ), + mw.messages.get( 'jquerymsg-italics-with-link' ), + 'Italics with link unchanged in text mode' + ); + + mw.messages.set( 'jquerymsg-italics-id-class', '<i id="foo" class="bar">Foo</i>' ); + assert.htmlEqual( + formatParse( 'jquerymsg-italics-id-class' ), + mw.messages.get( 'jquerymsg-italics-id-class' ), + 'ID and class are allowed' + ); + + mw.messages.set( 'jquerymsg-italics-onclick', '<i onclick="alert(\'foo\')">Foo</i>' ); + assert.htmlEqual( + formatParse( 'jquerymsg-italics-onclick' ), + '<i onclick="alert(\'foo\')">Foo</i>', + 'element with onclick is escaped because it is not allowed' + ); + + mw.messages.set( 'jquerymsg-script-msg', '<script >alert( "Who put this tag here?" );</script>' ); + assert.htmlEqual( + formatParse( 'jquerymsg-script-msg' ), + '<script >alert( "Who put this tag here?" );</script>', + 'Tag outside whitelist escaped in parse mode' + ); + + assert.equal( + formatText( 'jquerymsg-script-msg' ), + mw.messages.get( 'jquerymsg-script-msg' ), + 'Tag outside whitelist unchanged in text mode' + ); + + mw.messages.set( 'jquerymsg-script-link-msg', '<script>[[Foo|bar]]</script>' ); + assert.htmlEqual( + formatParse( 'jquerymsg-script-link-msg' ), + '<script><a title="Foo" href="' + mw.html.escape( mw.util.getUrl( 'Foo' ) ) + '">bar</a></script>', + 'Script tag text is escaped because that element is not allowed, but link inside is still HTML' + ); + + mw.messages.set( 'jquerymsg-mismatched-html', '<i class="important">test</b>' ); + assert.htmlEqual( + formatParse( 'jquerymsg-mismatched-html' ), + '<i class="important">test</b>', + 'Mismatched HTML start and end tag treated as text' + ); + + // TODO (mattflaschen, 2013-03-18): It's not a security issue, but there's no real + // reason the htmlEmitter span needs to be here. It's an artifact of how emitting works. + mw.messages.set( 'jquerymsg-script-and-external-link', '<script>alert( "jquerymsg-script-and-external-link test" );</script> [http://example.com <i>Foo</i> bar]' ); + assert.htmlEqual( + formatParse( 'jquerymsg-script-and-external-link' ), + '<script>alert( "jquerymsg-script-and-external-link test" );</script> <a href="http://example.com"><span class="mediaWiki_htmlEmitter"><i>Foo</i> bar</span></a>', + 'HTML tags in external links not interfering with escaping of other tags' + ); + + mw.messages.set( 'jquerymsg-link-script', '[http://example.com <script>alert( "jquerymsg-link-script test" );</script>]' ); + assert.htmlEqual( + formatParse( 'jquerymsg-link-script' ), + '<a href="http://example.com"><span class="mediaWiki_htmlEmitter"><script>alert( "jquerymsg-link-script test" );</script></span></a>', + 'Non-whitelisted HTML tag in external link anchor treated as text' + ); + + // Intentionally not using htmlEqual for the quote tests + mw.messages.set( 'jquerymsg-double-quotes-preserved', '<i id="double">Double</i>' ); + assert.equal( + formatParse( 'jquerymsg-double-quotes-preserved' ), + mw.messages.get( 'jquerymsg-double-quotes-preserved' ), + 'Attributes with double quotes are preserved as such' + ); + + mw.messages.set( 'jquerymsg-single-quotes-normalized-to-double', '<i id=\'single\'>Single</i>' ); + assert.equal( + formatParse( 'jquerymsg-single-quotes-normalized-to-double' ), + '<i id="single">Single</i>', + 'Attributes with single quotes are normalized to double' + ); + + mw.messages.set( 'jquerymsg-escaped-double-quotes-attribute', '<i style="font-family:"Arial"">Styled</i>' ); + assert.htmlEqual( + formatParse( 'jquerymsg-escaped-double-quotes-attribute' ), + mw.messages.get( 'jquerymsg-escaped-double-quotes-attribute' ), + 'Escaped attributes are parsed correctly' + ); + + mw.messages.set( 'jquerymsg-escaped-single-quotes-attribute', '<i style=\'font-family:'Arial'\'>Styled</i>' ); + assert.htmlEqual( + formatParse( 'jquerymsg-escaped-single-quotes-attribute' ), + mw.messages.get( 'jquerymsg-escaped-single-quotes-attribute' ), + 'Escaped attributes are parsed correctly' + ); + + mw.messages.set( 'jquerymsg-wikitext-contents-parsed', '<i>[http://example.com Example]</i>' ); + assert.htmlEqual( + formatParse( 'jquerymsg-wikitext-contents-parsed' ), + '<i><a href="http://example.com">Example</a></i>', + 'Contents of valid tag are treated as wikitext, so external link is parsed' + ); + + mw.messages.set( 'jquerymsg-wikitext-contents-script', '<i><script>Script inside</script></i>' ); + assert.htmlEqual( + formatParse( 'jquerymsg-wikitext-contents-script' ), + '<i><span class="mediaWiki_htmlEmitter"><script>Script inside</script></span></i>', + 'Contents of valid tag are treated as wikitext, so invalid HTML element is treated as text' + ); + + mw.messages.set( 'jquerymsg-unclosed-tag', 'Foo<tag>bar' ); + assert.htmlEqual( + formatParse( 'jquerymsg-unclosed-tag' ), + 'Foo<tag>bar', + 'Nonsupported unclosed tags are escaped' + ); + + mw.messages.set( 'jquerymsg-self-closing-tag', 'Foo<tag/>bar' ); + assert.htmlEqual( + formatParse( 'jquerymsg-self-closing-tag' ), + 'Foo<tag/>bar', + 'Self-closing tags don\'t cause a parse error' + ); } ); - QUnit.stop(); - process( queue, QUnit.start ); -} ); - -// HTML in wikitext -QUnit.test( 'HTML', 26, function ( assert ) { - mw.messages.set( 'jquerymsg-italics-msg', '<i>Very</i> important' ); - - assertBothModes( assert, ['jquerymsg-italics-msg'], mw.messages.get( 'jquerymsg-italics-msg' ), 'Simple italics unchanged' ); - - mw.messages.set( 'jquerymsg-bold-msg', '<b>Strong</b> speaker' ); - assertBothModes( assert, ['jquerymsg-bold-msg'], mw.messages.get( 'jquerymsg-bold-msg' ), 'Simple bold unchanged' ); - - mw.messages.set( 'jquerymsg-bold-italics-msg', 'It is <b><i>key</i></b>' ); - assertBothModes( assert, ['jquerymsg-bold-italics-msg'], mw.messages.get( 'jquerymsg-bold-italics-msg' ), 'Bold and italics nesting order preserved' ); - - mw.messages.set( 'jquerymsg-italics-bold-msg', 'It is <i><b>vital</b></i>' ); - assertBothModes( assert, ['jquerymsg-italics-bold-msg'], mw.messages.get( 'jquerymsg-italics-bold-msg' ), 'Italics and bold nesting order preserved' ); - - mw.messages.set( 'jquerymsg-italics-with-link', 'An <i>italicized [[link|wiki-link]]</i>' ); - - assert.htmlEqual( - formatParse( 'jquerymsg-italics-with-link' ), - 'An <i>italicized <a title="link" href="' + mw.html.escape( mw.util.getUrl( 'link' ) ) + '">wiki-link</i>', - 'Italics with link inside in parse mode' - ); - - assert.equal( - formatText( 'jquerymsg-italics-with-link' ), - mw.messages.get( 'jquerymsg-italics-with-link' ), - 'Italics with link unchanged in text mode' - ); - - mw.messages.set( 'jquerymsg-italics-id-class', '<i id="foo" class="bar">Foo</i>' ); - assert.htmlEqual( - formatParse( 'jquerymsg-italics-id-class' ), - mw.messages.get( 'jquerymsg-italics-id-class' ), - 'ID and class are allowed' - ); - - mw.messages.set( 'jquerymsg-italics-onclick', '<i onclick="alert(\'foo\')">Foo</i>' ); - assert.htmlEqual( - formatParse( 'jquerymsg-italics-onclick' ), - '<i onclick="alert(\'foo\')">Foo</i>', - 'element with onclick is escaped because it is not allowed' - ); - - mw.messages.set( 'jquerymsg-script-msg', '<script >alert( "Who put this tag here?" );</script>' ); - assert.htmlEqual( - formatParse( 'jquerymsg-script-msg' ), - '<script >alert( "Who put this tag here?" );</script>', - 'Tag outside whitelist escaped in parse mode' - ); - - assert.equal( - formatText( 'jquerymsg-script-msg' ), - mw.messages.get( 'jquerymsg-script-msg' ), - 'Tag outside whitelist unchanged in text mode' - ); - - mw.messages.set( 'jquerymsg-script-link-msg', '<script>[[Foo|bar]]</script>' ); - assert.htmlEqual( - formatParse( 'jquerymsg-script-link-msg' ), - '<script><a title="Foo" href="' + mw.html.escape( mw.util.getUrl( 'Foo' ) ) + '">bar</a></script>', - 'Script tag text is escaped because that element is not allowed, but link inside is still HTML' - ); - - mw.messages.set( 'jquerymsg-mismatched-html', '<i class="important">test</b>' ); - assert.htmlEqual( - formatParse( 'jquerymsg-mismatched-html' ), - '<i class="important">test</b>', - 'Mismatched HTML start and end tag treated as text' - ); - - // TODO (mattflaschen, 2013-03-18): It's not a security issue, but there's no real - // reason the htmlEmitter span needs to be here. It's an artifact of how emitting works. - mw.messages.set( 'jquerymsg-script-and-external-link', '<script>alert( "jquerymsg-script-and-external-link test" );</script> [http://example.com <i>Foo</i> bar]' ); - assert.htmlEqual( - formatParse( 'jquerymsg-script-and-external-link' ), - '<script>alert( "jquerymsg-script-and-external-link test" );</script> <a href="http://example.com"><span class="mediaWiki_htmlEmitter"><i>Foo</i> bar</span></a>', - 'HTML tags in external links not interfering with escaping of other tags' - ); - - mw.messages.set( 'jquerymsg-link-script', '[http://example.com <script>alert( "jquerymsg-link-script test" );</script>]' ); - assert.htmlEqual( - formatParse( 'jquerymsg-link-script' ), - '<a href="http://example.com"><span class="mediaWiki_htmlEmitter"><script>alert( "jquerymsg-link-script test" );</script></span></a>', - 'Non-whitelisted HTML tag in external link anchor treated as text' - ); - - // Intentionally not using htmlEqual for the quote tests - mw.messages.set( 'jquerymsg-double-quotes-preserved', '<i id="double">Double</i>' ); - assert.equal( - formatParse( 'jquerymsg-double-quotes-preserved' ), - mw.messages.get( 'jquerymsg-double-quotes-preserved' ), - 'Attributes with double quotes are preserved as such' - ); - - mw.messages.set( 'jquerymsg-single-quotes-normalized-to-double', '<i id=\'single\'>Single</i>' ); - assert.equal( - formatParse( 'jquerymsg-single-quotes-normalized-to-double' ), - '<i id="single">Single</i>', - 'Attributes with single quotes are normalized to double' - ); - - mw.messages.set( 'jquerymsg-escaped-double-quotes-attribute', '<i style="font-family:"Arial"">Styled</i>' ); - assert.htmlEqual( - formatParse( 'jquerymsg-escaped-double-quotes-attribute' ), - mw.messages.get( 'jquerymsg-escaped-double-quotes-attribute' ), - 'Escaped attributes are parsed correctly' - ); - - mw.messages.set( 'jquerymsg-escaped-single-quotes-attribute', '<i style=\'font-family:'Arial'\'>Styled</i>' ); - assert.htmlEqual( - formatParse( 'jquerymsg-escaped-single-quotes-attribute' ), - mw.messages.get( 'jquerymsg-escaped-single-quotes-attribute' ), - 'Escaped attributes are parsed correctly' - ); - - mw.messages.set( 'jquerymsg-wikitext-contents-parsed', '<i>[http://example.com Example]</i>' ); - assert.htmlEqual( - formatParse( 'jquerymsg-wikitext-contents-parsed' ), - '<i><a href="http://example.com">Example</a></i>', - 'Contents of valid tag are treated as wikitext, so external link is parsed' - ); - - mw.messages.set( 'jquerymsg-wikitext-contents-script', '<i><script>Script inside</script></i>' ); - assert.htmlEqual( - formatParse( 'jquerymsg-wikitext-contents-script' ), - '<i><span class="mediaWiki_htmlEmitter"><script>Script inside</script></span></i>', - 'Contents of valid tag are treated as wikitext, so invalid HTML element is treated as text' - ); - - mw.messages.set( 'jquerymsg-unclosed-tag', 'Foo<tag>bar' ); - assert.htmlEqual( - formatParse( 'jquerymsg-unclosed-tag' ), - 'Foo<tag>bar', - 'Nonsupported unclosed tags are escaped' - ); - - mw.messages.set( 'jquerymsg-self-closing-tag', 'Foo<tag/>bar' ); - assert.htmlEqual( - formatParse( 'jquerymsg-self-closing-tag' ), - 'Foo<tag/>bar', - 'Self-closing tags don\'t cause a parse error' - ); -} ); QUnit.test( 'Behavior in case of invalid wikitext', 3, function ( assert ) { mw.messages.set( 'invalid-wikitext', '<b>{{FAIL}}</b>' ); diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.language.test.js b/tests/qunit/suites/resources/mediawiki/mediawiki.language.test.js index 16f90df8..670914eb 100644 --- a/tests/qunit/suites/resources/mediawiki/mediawiki.language.test.js +++ b/tests/qunit/suites/resources/mediawiki/mediawiki.language.test.js @@ -8,19 +8,32 @@ }, teardown: function () { mw.language.data.values = this.liveLangData; + }, + messages: { + // mw.language.listToText test + 'and': ' and', + 'comma-separator': ', ', + 'word-separator': ' ' } } ) ); - QUnit.test( 'mw.language getData and setData', 2, function ( assert ) { + QUnit.test( 'mw.language getData and setData', 3, function ( assert ) { mw.language.setData( 'en', 'testkey', 'testvalue' ); assert.equal( mw.language.getData( 'en', 'testkey' ), 'testvalue', 'Getter setter test for mw.language' ); assert.equal( mw.language.getData( 'en', 'invalidkey' ), undefined, 'Getter setter test for mw.language with invalid key' ); + mw.language.setData( 'en-us', 'testkey', 'testvalue' ); + assert.equal( mw.language.getData( 'en-US', 'testkey' ), 'testvalue', 'Case insensitive test for mw.language' ); } ); QUnit.test( 'mw.language.commafy test', 9, function ( assert ) { + mw.language.setData( 'en', 'digitGroupingPattern', null ); + mw.language.setData( 'en', 'digitTransformTable', null ); + mw.language.setData( 'en', 'separatorTransformTable', null ); + + mw.config.set( 'wgUserLanguage', 'en' ); // Number grouping patterns are as per http://cldr.unicode.org/translation/number-patterns assert.equal( mw.language.commafy( 1234.567, '###0.#####' ), '1234.567', 'Pattern with no digit grouping separator defined' ); - assert.equal( mw.language.commafy( 123456789.567, '###0.#####' ), '123456789.567', 'Pattern with no digit grouping seperator defined, bigger decimal part' ); + assert.equal( mw.language.commafy( 123456789.567, '###0.#####' ), '123456789.567', 'Pattern with no digit grouping separator defined, bigger decimal part' ); assert.equal( mw.language.commafy( 0.567, '###0.#####' ), '0.567', 'Decimal part 0' ); assert.equal( mw.language.commafy( '.567', '###0.#####' ), '0.567', 'Decimal part missing. replace with zero' ); assert.equal( mw.language.commafy( 1234, '##,#0.#####' ), '12,34', 'Pattern with no fractional part' ); diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.messagePoster.factory.test.js b/tests/qunit/suites/resources/mediawiki/mediawiki.messagePoster.factory.test.js new file mode 100644 index 00000000..61bab03f --- /dev/null +++ b/tests/qunit/suites/resources/mediawiki/mediawiki.messagePoster.factory.test.js @@ -0,0 +1,28 @@ +( function ( mw ) { + var TEST_MODEL = 'test-content-model'; + + QUnit.module( 'mediawiki.messagePoster', QUnit.newMwEnvironment( { + teardown: function () { + mw.messagePoster.factory.unregister( TEST_MODEL ); + } + } ) ); + + QUnit.test( 'register', 2, function ( assert ) { + var testMessagePosterConstructor = function () {}; + + mw.messagePoster.factory.register( TEST_MODEL, testMessagePosterConstructor ); + assert.strictEqual( + mw.messagePoster.factory.contentModelToClass[TEST_MODEL], + testMessagePosterConstructor, + 'Constructor is registered' + ); + + assert.throws( + function () { + mw.messagePoster.factory.register( TEST_MODEL, testMessagePosterConstructor ); + }, + new RegExp( 'The content model \'' + TEST_MODEL + '\' is already registered.' ), + 'Throws exception is same model is registered a second time' + ); + } ); +}( mediaWiki ) ); diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.template.test.js b/tests/qunit/suites/resources/mediawiki/mediawiki.template.test.js new file mode 100644 index 00000000..86fd828a --- /dev/null +++ b/tests/qunit/suites/resources/mediawiki/mediawiki.template.test.js @@ -0,0 +1,63 @@ +( function ( mw ) { + + QUnit.module( 'mediawiki.template', { + setup: function () { + var abcCompiler = { + compile: function () { + return 'abc default compiler'; + } + }; + + // Register some template compiler languages + mw.template.registerCompiler( 'abc', abcCompiler ); + mw.template.registerCompiler( 'xyz', { + compile: function () { + return 'xyz compiler'; + } + } ); + + // Stub register some templates + this.sandbox.stub( mw.templates, 'get' ).returns( { + 'test_templates_foo.xyz': 'goodbye', + 'test_templates_foo.abc': 'thankyou' + } ); + } + } ); + + QUnit.test( 'add', 1, function ( assert ) { + assert.throws( + function () { + mw.template.add( 'module', 'test_templates_foo', 'hello' ); + }, + 'When no prefix throw exception' + ); + } ); + + QUnit.test( 'compile', 1, function ( assert ) { + assert.throws( + function () { + mw.template.compile( '{{foo}}', 'rainbow' ); + }, + 'Unknown compiler names throw exceptions' + ); + } ); + + QUnit.test( 'get', 4, function ( assert ) { + assert.strictEqual( mw.template.get( 'test.mediawiki.template', 'test_templates_foo.xyz' ), 'xyz compiler' ); + assert.strictEqual( mw.template.get( 'test.mediawiki.template', 'test_templates_foo.abc' ), 'abc default compiler' ); + assert.throws( + function () { + mw.template.get( 'this.should.not.exist', 'hello' ); + }, + 'When bad module name given throw error.' + ); + + assert.throws( + function () { + mw.template.get( 'mediawiki.template', 'hello' ); + }, + 'The template hello should not exist in the mediawiki.templates module and should throw an exception.' + ); + } ); + +}( mediaWiki ) ); diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.test.js b/tests/qunit/suites/resources/mediawiki/mediawiki.test.js index 7e0ee917..cf36ea82 100644 --- a/tests/qunit/suites/resources/mediawiki/mediawiki.test.js +++ b/tests/qunit/suites/resources/mediawiki/mediawiki.test.js @@ -1,6 +1,8 @@ /*jshint -W024 */ ( function ( mw, $ ) { - var specialCharactersPageName; + var specialCharactersPageName, + // Can't mock SITENAME since jqueryMsg caches it at load + siteName = mw.config.get( 'wgSiteName' ); // Since QUnitTestResources.php loads both mediawiki and mediawiki.jqueryMsg as // dependencies, this only tests the monkey-patched behavior with the two of them combined. @@ -55,7 +57,7 @@ this.restoreWarnings(); } ); - QUnit.test( 'mw.Map', 28, function ( assert ) { + QUnit.test( 'mw.Map', 35, function ( assert ) { var arry, conf, funky, globalConf, nummy, someValues; conf = new mw.Map(); @@ -86,8 +88,10 @@ assert.strictEqual( conf.set( 'constructor', 42 ), true, 'Map.set for key "constructor"' ); assert.strictEqual( conf.get( 'constructor' ), 42, 'Map.get for key "constructor"' ); - assert.strictEqual( conf.set( 'ImUndefined', undefined ), true, 'Map.set allows setting value to `undefined`' ); - assert.equal( conf.get( 'ImUndefined', 'fallback' ), undefined, 'Map.get supports retreiving value of `undefined`' ); + assert.strictEqual( conf.set( 'undef' ), false, 'Map.set requires explicit value (no undefined default)' ); + + assert.strictEqual( conf.set( 'undef', undefined ), true, 'Map.set allows setting value to `undefined`' ); + assert.equal( conf.get( 'undef', 'fallback' ), undefined, 'Map.get supports retreiving value of `undefined`' ); assert.strictEqual( conf.set( funky, 'Funky' ), false, 'Map.set returns boolean false if key was invalid (Function)' ); assert.strictEqual( conf.set( arry, 'Arry' ), false, 'Map.set returns boolean false if key was invalid (Array)' ); @@ -99,7 +103,7 @@ conf.set( String( nummy ), 'I used to be a number' ); assert.strictEqual( conf.exists( 'doesNotExist' ), false, 'Map.exists where property does not exist' ); - assert.strictEqual( conf.exists( 'ImUndefined' ), true, 'Map.exists where value is `undefined`' ); + assert.strictEqual( conf.exists( 'undef' ), true, 'Map.exists where value is `undefined`' ); assert.strictEqual( conf.exists( nummy ), false, 'Map.exists where key is invalid but looks like an existing key' ); // Multiple values at once @@ -126,12 +130,31 @@ conf.set( 'globalMapChecker', 'Hi' ); - assert.ok( 'globalMapChecker' in window === false, 'new mw.Map did not store its values in the global window object by default' ); + assert.ok( ( 'globalMapChecker' in window ) === false, 'Map does not its store values in the window object by default' ); globalConf = new mw.Map( true ); globalConf.set( 'anotherGlobalMapChecker', 'Hello' ); - assert.ok( 'anotherGlobalMapChecker' in window, 'new mw.Map( true ) did store its values in the global window object' ); + assert.ok( 'anotherGlobalMapChecker' in window, 'global Map stores its values in the window object' ); + + assert.equal( globalConf.get( 'anotherGlobalMapChecker' ), 'Hello', 'get value from global Map via get()' ); + this.suppressWarnings(); + assert.equal( window.anotherGlobalMapChecker, 'Hello', 'get value from global Map via window object' ); + this.restoreWarnings(); + + // Change value via global Map + globalConf.set('anotherGlobalMapChecker', 'Again'); + assert.equal( globalConf.get( 'anotherGlobalMapChecker' ), 'Again', 'Change in global Map reflected via get()' ); + this.suppressWarnings(); + assert.equal( window.anotherGlobalMapChecker, 'Again', 'Change in global Map reflected window object' ); + this.restoreWarnings(); + + // Change value via window object + this.suppressWarnings(); + window.anotherGlobalMapChecker = 'World'; + assert.equal( window.anotherGlobalMapChecker, 'World', 'Change in window object works' ); + this.restoreWarnings(); + assert.equal( globalConf.get( 'anotherGlobalMapChecker' ), 'Again', 'Change in window object not reflected in global Map' ); // Whitelist this global variable for QUnit's 'noglobal' mode if ( QUnit.config.noglobals ) { @@ -148,7 +171,9 @@ // Convenience method for asserting the same result for multiple formats function assertMultipleFormats( messageArguments, formats, expectedResult, assertMessage ) { - var len = formats.length, format, i; + var format, i, + len = formats.length; + for ( i = 0; i < len; i++ ) { format = formats[i]; assert.equal( mw.message.apply( null, messageArguments )[format](), expectedResult, assertMessage + ' when format is ' + format ); @@ -178,9 +203,9 @@ assert.equal( hello.format, 'escaped', 'Message.escaped correctly updated the "format" property' ); assert.ok( mw.messages.set( 'multiple-curly-brace', '"{{SITENAME}}" is the home of {{int:other-message}}' ), 'mw.messages.set: Register' ); - assertMultipleFormats( ['multiple-curly-brace'], ['text', 'parse'], '"' + mw.config.get( 'wgSiteName') + '" is the home of Other Message', 'Curly brace format works correctly' ); + assertMultipleFormats( ['multiple-curly-brace'], ['text', 'parse'], '"' + siteName + '" is the home of Other Message', 'Curly brace format works correctly' ); assert.equal( mw.message( 'multiple-curly-brace' ).plain(), mw.messages.get( 'multiple-curly-brace' ), 'Plain format works correctly for curly brace message' ); - assert.equal( mw.message( 'multiple-curly-brace' ).escaped(), mw.html.escape( '"' + mw.config.get( 'wgSiteName') + '" is the home of Other Message' ), 'Escaped format works correctly for curly brace message' ); + assert.equal( mw.message( 'multiple-curly-brace' ).escaped(), mw.html.escape( '"' + siteName + '" is the home of Other Message' ), 'Escaped format works correctly for curly brace message' ); assert.ok( mw.messages.set( 'multiple-square-brackets-and-ampersand', 'Visit the [[Project:Community portal|community portal]] & [[Project:Help desk|help desk]]' ), 'mw.messages.set: Register' ); assertMultipleFormats( ['multiple-square-brackets-and-ampersand'], ['plain', 'text'], mw.messages.get( 'multiple-square-brackets-and-ampersand' ), 'Square bracket message is not processed' ); @@ -243,8 +268,8 @@ assert.equal( mw.message( 'gender-plural-msg', 'male', 1 ).plain(), '{{GENDER:male|he|she|they}} {{PLURAL:1|is|are}} awesome', 'Parameters are substituted, but gender and plural are not resolved in plain mode' ); assert.equal( mw.message( 'grammar-msg' ).plain(), mw.messages.get( 'grammar-msg' ), 'Grammar is not resolved in plain mode' ); - assertMultipleFormats( ['grammar-msg'], ['text', 'parse'], 'Przeszukaj ' + mw.config.get( 'wgSiteName' ), 'Grammar is resolved' ); - assert.equal( mw.message( 'grammar-msg' ).escaped(), 'Przeszukaj ' + mw.html.escape( mw.config.get( 'wgSiteName' ) ), 'Grammar is resolved in escaped mode' ); + assertMultipleFormats( ['grammar-msg'], ['text', 'parse'], 'Przeszukaj ' + siteName, 'Grammar is resolved' ); + assert.equal( mw.message( 'grammar-msg' ).escaped(), 'Przeszukaj ' + siteName, 'Grammar is resolved in escaped mode' ); assertMultipleFormats( ['formatnum-msg', '987654321.654321'], ['text', 'parse', 'escaped'], '987,654,321.654', 'formatnum is resolved' ); assert.equal( mw.message( 'formatnum-msg' ).plain(), mw.messages.get( 'formatnum-msg' ), 'formatnum is not resolved in plain mode' ); @@ -304,7 +329,7 @@ assert.equal( mw.msg( 'gender-plural-msg', 'female', '1' ), 'she is awesome', 'Gender test for female, plural count 1' ); assert.equal( mw.msg( 'gender-plural-msg', 'unknown', 10 ), 'they are awesome', 'Gender test for neutral, plural count 10' ); - assert.equal( mw.msg( 'grammar-msg' ), 'Przeszukaj ' + mw.config.get( 'wgSiteName' ), 'Grammar is resolved' ); + assert.equal( mw.msg( 'grammar-msg' ), 'Przeszukaj ' + siteName, 'Grammar is resolved' ); assert.equal( mw.msg( 'formatnum-msg', '987654321.654321' ), '987,654,321.654', 'formatnum is resolved' ); @@ -352,7 +377,7 @@ return; } // Otherwise, keep polling - setTimeout( styleTestLoop, 150 ); + setTimeout( styleTestLoop ); } // Start the loop @@ -396,6 +421,30 @@ } ); } ); + QUnit.asyncTest( 'mw.loader with Object method as module name', 2, function ( assert ) { + var isAwesomeDone; + + mw.loader.testCallback = function () { + QUnit.start(); + assert.strictEqual( isAwesomeDone, undefined, 'Implementing module hasOwnProperty: isAwesomeDone should still be undefined' ); + isAwesomeDone = true; + }; + + mw.loader.implement( 'hasOwnProperty', [QUnit.fixurl( mw.config.get( 'wgScriptPath' ) + '/tests/qunit/data/callMwLoaderTestCallback.js' )], {}, {} ); + + mw.loader.using( 'hasOwnProperty', function () { + + // /sample/awesome.js declares the "mw.loader.testCallback" function + // which contains a call to start() and ok() + assert.strictEqual( isAwesomeDone, true, 'hasOwnProperty module should\'ve caused isAwesomeDone to be true' ); + delete mw.loader.testCallback; + + }, function () { + QUnit.start(); + assert.ok( false, 'Error callback fired while loader.using "hasOwnProperty" module' ); + } ); + } ); + QUnit.asyncTest( 'mw.loader.using( .. ).promise', 2, function ( assert ) { var isAwesomeDone; @@ -625,6 +674,11 @@ } ); + QUnit.test( 'mw.loader.implement( only scripts )', 1, function ( assert ) { + mw.loader.implement( 'test.onlyscripts', function () {} ); + assert.strictEqual( mw.loader.getState( 'test.onlyscripts' ), 'ready' ); + } ); + QUnit.asyncTest( 'mw.loader.implement( only messages )', 2, function ( assert ) { assert.assertFalse( mw.messages.exists( 'bug_29107' ), 'Verify that the test message doesn\'t exist yet' ); @@ -638,7 +692,10 @@ } ); } ); - QUnit.test( 'mw.loader erroneous indirect dependency', 3, function ( assert ) { + QUnit.test( 'mw.loader erroneous indirect dependency', 4, function ( assert ) { + // don't emit an error event + this.sandbox.stub( mw, 'track' ); + mw.loader.register( [ ['test.module1', '0'], ['test.module2', '0', ['test.module1']], @@ -650,6 +707,8 @@ assert.strictEqual( mw.loader.getState( 'test.module1' ), 'error', 'Expected "error" state for test.module1' ); assert.strictEqual( mw.loader.getState( 'test.module2' ), 'error', 'Expected "error" state for test.module2' ); assert.strictEqual( mw.loader.getState( 'test.module3' ), 'error', 'Expected "error" state for test.module3' ); + + assert.strictEqual( mw.track.callCount, 1 ); } ); QUnit.test( 'mw.loader out-of-order implementation', 9, function ( assert ) { diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.track.test.js b/tests/qunit/suites/resources/mediawiki/mediawiki.track.test.js new file mode 100644 index 00000000..cdb26244 --- /dev/null +++ b/tests/qunit/suites/resources/mediawiki/mediawiki.track.test.js @@ -0,0 +1,42 @@ +( function ( mw ) { + QUnit.module( 'mediawiki.track' ); + + QUnit.test( 'track', 1, function ( assert ) { + var sequence = []; + mw.trackSubscribe( 'simple', function ( topic, data ) { + sequence.push( [ topic, data ] ); + } ); + mw.track( 'simple', { key: 1 } ); + mw.track( 'simple', { key: 2 } ); + + assert.deepEqual( sequence, [ + [ 'simple', { key: 1 } ], + [ 'simple', { key: 2 } ] + ], 'Events after subscribing' ); + } ); + + QUnit.test( 'trackSubscribe', 4, function ( assert ) { + var now, + sequence = []; + mw.track( 'before', { key: 1 } ); + mw.track( 'before', { key: 2 } ); + mw.trackSubscribe( 'before', function ( topic, data ) { + sequence.push( [ topic, data ] ); + } ); + mw.track( 'before', { key: 3 } ); + + assert.deepEqual( sequence, [ + [ 'before', { key: 1 } ], + [ 'before', { key: 2 } ], + [ 'before', { key: 3 } ] + ], 'Replay events from before subscribing' ); + + now = mw.now(); + mw.track( 'context', { key: 0 } ); + mw.trackSubscribe( 'context', function ( topic, data ) { + assert.strictEqual( this.topic, topic, 'thisValue has topic' ); + assert.strictEqual( this.data, data, 'thisValue has data' ); + assert.assertTrue( this.timeStamp >= now, 'thisValue has sane timestamp' ); + } ); + } ); +}( mediaWiki ) ); diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.user.test.js b/tests/qunit/suites/resources/mediawiki/mediawiki.user.test.js index 91321a2f..04e002dd 100644 --- a/tests/qunit/suites/resources/mediawiki/mediawiki.user.test.js +++ b/tests/qunit/suites/resources/mediawiki/mediawiki.user.test.js @@ -1,7 +1,17 @@ -( function ( mw ) { +( function ( mw, $ ) { QUnit.module( 'mediawiki.user', QUnit.newMwEnvironment( { setup: function () { this.server = this.sandbox.useFakeServer(); + this.crypto = window.crypto; + this.msCrypto = window.msCrypto; + }, + teardown: function () { + if ( this.crypto ) { + window.crypto = this.crypto; + } + if ( this.msCrypto ) { + window.msCrypto = this.msCrypto; + } } } ) ); @@ -51,4 +61,38 @@ this.server.respond(); } ); -}( mediaWiki ) ); + + QUnit.test( 'generateRandomSessionId', 4, function ( assert ) { + var result, result2; + + result = mw.user.generateRandomSessionId(); + assert.equal( typeof result, 'string', 'type' ); + assert.equal( $.trim( result ), result, 'no whitespace at beginning or end' ); + assert.equal( result.length, 16, 'size' ); + + result2 = mw.user.generateRandomSessionId(); + assert.notEqual( result, result2, 'different when called multiple times' ); + + } ); + + QUnit.test( 'generateRandomSessionId (fallback)', 4, function ( assert ) { + var result, result2; + + // Pretend crypto API is not there to test the Math.random fallback + if ( window.crypto ) { + window.crypto = undefined; + } + if ( window.msCrypto ) { + window.msCrypto = undefined; + } + + result = mw.user.generateRandomSessionId(); + assert.equal( typeof result, 'string', 'type' ); + assert.equal( $.trim( result ), result, 'no whitespace at beginning or end' ); + assert.equal( result.length, 16, 'size' ); + + result2 = mw.user.generateRandomSessionId(); + assert.notEqual( result, result2, 'different when called multiple times' ); + + } ); +}( mediaWiki, jQuery ) ); diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.util.test.js b/tests/qunit/suites/resources/mediawiki/mediawiki.util.test.js index 4401eadb..0b42af4b 100644 --- a/tests/qunit/suites/resources/mediawiki/mediawiki.util.test.js +++ b/tests/qunit/suites/resources/mediawiki/mediawiki.util.test.js @@ -1,4 +1,79 @@ ( function ( mw, $ ) { + var + // Based on IPTest.php > testisIPv4 + IPV4_CASES = [ + [false, false, 'Boolean false is not an IP'], + [false, true, 'Boolean true is not an IP'], + [false, '', 'Empty string is not an IP'], + [false, 'abc', '"abc" is not an IP'], + [false, ':', 'Colon is not an IP'], + [false, '124.24.52', 'IPv4 not enough quads'], + [false, '24.324.52.13', 'IPv4 out of range'], + [false, '.24.52.13', 'IPv4 starts with period'], + + [true, '124.24.52.13', '124.24.52.134 is a valid IP'], + [true, '1.24.52.13', '1.24.52.13 is a valid IP'], + [false, '74.24.52.13/20', 'IPv4 ranges are not recognized as valid IPs'] + ], + + // Based on IPTest.php > testisIPv6 + IPV6_CASES = [ + [false, ':fc:100::', 'IPv6 starting with lone ":"'], + [false, 'fc:100:::', 'IPv6 ending with a ":::"'], + [false, 'fc:300', 'IPv6 with only 2 words'], + [false, 'fc:100:300', 'IPv6 with only 3 words'], + + [false, 'fc:100:a:d:1:e:ac:0::', 'IPv6 with 8 words ending with "::"'], + [false, 'fc:100:a:d:1:e:ac:0:1::', 'IPv6 with 9 words ending with "::"'], + + [false, ':::'], + [false, '::0:', 'IPv6 ending in a lone ":"'], + + [true, '::', 'IPv6 zero address'], + + [false, '::fc:100:a:d:1:e:ac:0', 'IPv6 with "::" and 8 words'], + [false, '::fc:100:a:d:1:e:ac:0:1', 'IPv6 with 9 words'], + + [false, ':fc::100', 'IPv6 starting with lone ":"'], + [false, 'fc::100:', 'IPv6 ending with lone ":"'], + [false, 'fc:::100', 'IPv6 with ":::" in the middle'], + + [true, 'fc::100', 'IPv6 with "::" and 2 words'], + [true, 'fc::100:a', 'IPv6 with "::" and 3 words'], + [true, 'fc::100:a:d', 'IPv6 with "::" and 4 words'], + [true, 'fc::100:a:d:1', 'IPv6 with "::" and 5 words'], + [true, 'fc::100:a:d:1:e', 'IPv6 with "::" and 6 words'], + [true, 'fc::100:a:d:1:e:ac', 'IPv6 with "::" and 7 words'], + [true, '2001::df', 'IPv6 with "::" and 2 words'], + [true, '2001:5c0:1400:a::df', 'IPv6 with "::" and 5 words'], + [true, '2001:5c0:1400:a::df:2', 'IPv6 with "::" and 6 words'], + + [false, 'fc::100:a:d:1:e:ac:0', 'IPv6 with "::" and 8 words'], + [false, 'fc::100:a:d:1:e:ac:0:1', 'IPv6 with 9 words'] + ]; + + Array.prototype.push.apply( IPV6_CASES, + $.map( [ + 'fc:100::', + 'fc:100:a::', + 'fc:100:a:d::', + 'fc:100:a:d:1::', + 'fc:100:a:d:1:e::', + 'fc:100:a:d:1:e:ac::', + '::0', + '::fc', + '::fc:100', + '::fc:100:a', + '::fc:100:a:d', + '::fc:100:a:d:1', + '::fc:100:a:d:1:e', + '::fc:100:a:d:1:e:ac', + 'fc:100:a:d:1:e:ac:0' + ], function ( el ) { + return [[ true, el, el + ' is a valid IP' ]]; + } ) + ); + QUnit.module( 'mediawiki.util', QUnit.newMwEnvironment( { setup: function () { $.fn.updateTooltipAccessKeys.setTestMode( true ); @@ -35,24 +110,25 @@ } ); } ); - QUnit.test( 'getUrl', 4, function ( assert ) { + QUnit.test( 'getUrl', 5, function ( assert ) { // Not part of startUp module mw.config.set( 'wgArticlePath', '/wiki/$1' ); mw.config.set( 'wgPageName', 'Foobar' ); var href = mw.util.getUrl( 'Sandbox' ); - assert.equal( href, '/wiki/Sandbox', 'Simple title; Get link for "Sandbox"' ); + assert.equal( href, '/wiki/Sandbox', 'simple title' ); - href = mw.util.getUrl( 'Foo:Sandbox ? 5+5=10 ! (test)/subpage' ); - assert.equal( href, '/wiki/Foo:Sandbox_%3F_5%2B5%3D10_!_(test)/subpage', - 'Advanced title; Get link for "Foo:Sandbox ? 5+5=10 ! (test)/subpage"' ); + href = mw.util.getUrl( 'Foo:Sandbox? 5+5=10! (test)/sub ' ); + assert.equal( href, '/wiki/Foo:Sandbox%3F_5%2B5%3D10!_(test)/sub_', 'advanced title' ); href = mw.util.getUrl(); - assert.equal( href, '/wiki/Foobar', 'Default title; Get link for current page ("Foobar")' ); + assert.equal( href, '/wiki/Foobar', 'default title' ); + + href = mw.util.getUrl( null, { action: 'edit' } ); + assert.equal( href, '/wiki/Foobar?action=edit', 'default title with query string' ); href = mw.util.getUrl( 'Sandbox', { action: 'edit' } ); - assert.equal( href, '/wiki/Sandbox?action=edit', - 'Simple title with query string; Get link for "Sandbox" with action=edit' ); + assert.equal( href, '/wiki/Sandbox?action=edit', 'simple title with query string' ); } ); QUnit.test( 'wikiScript', 4, function ( assert ) { @@ -189,7 +265,7 @@ ); assert.equal( $tbMW.closest( '.portlet' ).attr( 'id' ), 'p-test-tb', 'Link was inserted within correct portlet' ); - assert.strictEqual( $tbMW.next()[0], tbRL, 'Link is in the correct position (by passing nextnode)' ); + assert.strictEqual( $tbMW.next()[0], tbRL, 'Link is in the correct position (nextnode as Node object)' ); cuQuux = mw.util.addPortletLink( 'p-test-custom', '#', 'Quux', null, 'Example [shift-x]', 'q' ); $cuQuux = $( cuQuux ); @@ -205,7 +281,7 @@ tbRLDM = mw.util.addPortletLink( 'p-test-tb', '//mediawiki.org/wiki/RL/DM', 'Default modules', 't-rldm', 'List of all default modules ', 'd', '#t-rl' ); - assert.equal( $( tbRLDM ).next().attr( 'id' ), 't-rl', 'Link is in the correct position (by passing CSS selector)' ); + assert.strictEqual( $( tbRLDM ).next()[0], tbRL, 'Link is in the correct position (CSS selector as nextnode)' ); caFoo = mw.util.addPortletLink( 'p-test-views', '#', 'Foo' ); @@ -213,26 +289,19 @@ assert.strictEqual( $( caFoo ).find( 'span' ).length, 1, 'A <span> element should be added for porlets with vectorTabs class.' ); addedAfter = mw.util.addPortletLink( 'p-test-tb', '#', 'After foo', 'post-foo', 'After foo', null, $( tbRL ) ); - assert.strictEqual( $( addedAfter ).next()[0], tbRL, 'Link is in the correct position (by passing a jQuery object as nextnode)' ); + assert.strictEqual( $( addedAfter ).next()[0], tbRL, 'Link is in the correct position (jQuery object as nextnode)' ); // test case - nonexistent id as next node tbRLDMnonexistentid = mw.util.addPortletLink( 'p-test-tb', '//mediawiki.org/wiki/RL/DM', 'Default modules', 't-rldm-nonexistent', 'List of all default modules ', 'd', '#t-rl-nonexistent' ); - assert.equal( tbRLDMnonexistentid, $( '#p-test-tb li:last' )[0], 'Nonexistent id as nextnode adds the portlet at end' ); + assert.equal( tbRLDMnonexistentid, $( '#p-test-tb li:last' )[0], 'Fallback to adding at the end (nextnode non-matching CSS selector)' ); // test case - empty jquery object as next node tbRLDMemptyjquery = mw.util.addPortletLink( 'p-test-tb', '//mediawiki.org/wiki/RL/DM', 'Default modules', 't-rldm-empty-jquery', 'List of all default modules ', 'd', $( '#t-rl-nonexistent' ) ); - assert.equal( tbRLDMemptyjquery, $( '#p-test-tb li:last' )[0], 'Empty jquery as nextnode adds the portlet at end' ); - } ); - - QUnit.test( 'jsMessage', 1, function ( assert ) { - this.suppressWarnings(); - var a = mw.util.jsMessage( 'MediaWiki is <b>Awesome</b>.' ); - this.restoreWarnings(); - assert.ok( a, 'Basic checking of return value' ); + assert.equal( tbRLDMemptyjquery, $( '#p-test-tb li:last' )[0], 'Fallback to adding at the end (nextnode as empty jQuery object)' ); } ); QUnit.test( 'validateEmail', 6, function ( assert ) { @@ -249,95 +318,24 @@ } ); QUnit.test( 'isIPv6Address', 40, function ( assert ) { - // Shortcuts - function assertFalseIPv6( addy, summary ) { - return assert.strictEqual( mw.util.isIPv6Address( addy ), false, summary ); - } - - function assertTrueIPv6( addy, summary ) { - return assert.strictEqual( mw.util.isIPv6Address( addy ), true, summary ); - } - - // Based on IPTest.php > testisIPv6 - assertFalseIPv6( ':fc:100::', 'IPv6 starting with lone ":"' ); - assertFalseIPv6( 'fc:100:::', 'IPv6 ending with a ":::"' ); - assertFalseIPv6( 'fc:300', 'IPv6 with only 2 words' ); - assertFalseIPv6( 'fc:100:300', 'IPv6 with only 3 words' ); - - $.each( - ['fc:100::', - 'fc:100:a::', - 'fc:100:a:d::', - 'fc:100:a:d:1::', - 'fc:100:a:d:1:e::', - 'fc:100:a:d:1:e:ac::'], function ( i, addy ) { - assertTrueIPv6( addy, addy + ' is a valid IP' ); - } ); - - assertFalseIPv6( 'fc:100:a:d:1:e:ac:0::', 'IPv6 with 8 words ending with "::"' ); - assertFalseIPv6( 'fc:100:a:d:1:e:ac:0:1::', 'IPv6 with 9 words ending with "::"' ); - - assertFalseIPv6( ':::' ); - assertFalseIPv6( '::0:', 'IPv6 ending in a lone ":"' ); - - assertTrueIPv6( '::', 'IPv6 zero address' ); - $.each( - ['::0', - '::fc', - '::fc:100', - '::fc:100:a', - '::fc:100:a:d', - '::fc:100:a:d:1', - '::fc:100:a:d:1:e', - '::fc:100:a:d:1:e:ac', - - 'fc:100:a:d:1:e:ac:0'], function ( i, addy ) { - assertTrueIPv6( addy, addy + ' is a valid IP' ); - } ); - - assertFalseIPv6( '::fc:100:a:d:1:e:ac:0', 'IPv6 with "::" and 8 words' ); - assertFalseIPv6( '::fc:100:a:d:1:e:ac:0:1', 'IPv6 with 9 words' ); - - assertFalseIPv6( ':fc::100', 'IPv6 starting with lone ":"' ); - assertFalseIPv6( 'fc::100:', 'IPv6 ending with lone ":"' ); - assertFalseIPv6( 'fc:::100', 'IPv6 with ":::" in the middle' ); - - assertTrueIPv6( 'fc::100', 'IPv6 with "::" and 2 words' ); - assertTrueIPv6( 'fc::100:a', 'IPv6 with "::" and 3 words' ); - assertTrueIPv6( 'fc::100:a:d', 'IPv6 with "::" and 4 words' ); - assertTrueIPv6( 'fc::100:a:d:1', 'IPv6 with "::" and 5 words' ); - assertTrueIPv6( 'fc::100:a:d:1:e', 'IPv6 with "::" and 6 words' ); - assertTrueIPv6( 'fc::100:a:d:1:e:ac', 'IPv6 with "::" and 7 words' ); - assertTrueIPv6( '2001::df', 'IPv6 with "::" and 2 words' ); - assertTrueIPv6( '2001:5c0:1400:a::df', 'IPv6 with "::" and 5 words' ); - assertTrueIPv6( '2001:5c0:1400:a::df:2', 'IPv6 with "::" and 6 words' ); - - assertFalseIPv6( 'fc::100:a:d:1:e:ac:0', 'IPv6 with "::" and 8 words' ); - assertFalseIPv6( 'fc::100:a:d:1:e:ac:0:1', 'IPv6 with 9 words' ); + $.each( IPV6_CASES, function ( i, ipCase ) { + assert.strictEqual( mw.util.isIPv6Address( ipCase[1] ), ipCase[0], ipCase[2] ); + } ); } ); QUnit.test( 'isIPv4Address', 11, function ( assert ) { - // Shortcuts - function assertFalseIPv4( addy, summary ) { - assert.strictEqual( mw.util.isIPv4Address( addy ), false, summary ); - } + $.each( IPV4_CASES, function ( i, ipCase ) { + assert.strictEqual( mw.util.isIPv4Address( ipCase[1] ), ipCase[0], ipCase[2] ); + } ); + } ); - function assertTrueIPv4( addy, summary ) { - assert.strictEqual( mw.util.isIPv4Address( addy ), true, summary ); - } + QUnit.test( 'isIPAddress', 51, function ( assert ) { + $.each( IPV4_CASES, function ( i, ipCase ) { + assert.strictEqual( mw.util.isIPv4Address( ipCase[1] ), ipCase[0], ipCase[2] ); + } ); - // Based on IPTest.php > testisIPv4 - assertFalseIPv4( false, 'Boolean false is not an IP' ); - assertFalseIPv4( true, 'Boolean true is not an IP' ); - assertFalseIPv4( '', 'Empty string is not an IP' ); - assertFalseIPv4( 'abc', '"abc" is not an IP' ); - assertFalseIPv4( ':', 'Colon is not an IP' ); - assertFalseIPv4( '124.24.52', 'IPv4 not enough quads' ); - assertFalseIPv4( '24.324.52.13', 'IPv4 out of range' ); - assertFalseIPv4( '.24.52.13', 'IPv4 starts with period' ); - - assertTrueIPv4( '124.24.52.13', '124.24.52.134 is a valid IP' ); - assertTrueIPv4( '1.24.52.13', '1.24.52.13 is a valid IP' ); - assertFalseIPv4( '74.24.52.13/20', 'IPv4 ranges are not recogzized as valid IPs' ); + $.each( IPV6_CASES, function ( i, ipCase ) { + assert.strictEqual( mw.util.isIPv6Address( ipCase[1] ), ipCase[0], ipCase[2] ); + } ); } ); }( mediaWiki, jQuery ) ); diff --git a/tests/qunit/suites/resources/startup.test.js b/tests/qunit/suites/resources/startup.test.js index ed03418a..6011961a 100644 --- a/tests/qunit/suites/resources/startup.test.js +++ b/tests/qunit/suites/resources/startup.test.js @@ -96,6 +96,7 @@ 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.7) Gecko/20060928 (Debian|Debian-1.8.0.7-1) Epiphany/2.14', 'Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.8.1.6) Gecko/20070817 IceWeasel/2.0.0.6-g2', // KHTML + 'Mozilla/5.0 (compatible; Konqueror/3.5; Linux) KHTML/3.5.4 (like Gecko)', 'Mozilla/5.0 (compatible; Konqueror/4.3; Linux) KHTML/4.3.5 (like Gecko)', // Text browsers 'Links (2.1pre33; Darwin 8.11.0 Power Macintosh; x)', diff --git a/tests/testHelpers.inc b/tests/testHelpers.inc index 62dccbf0..6d3ac2f5 100644 --- a/tests/testHelpers.inc +++ b/tests/testHelpers.inc @@ -471,7 +471,7 @@ class TestFileIterator implements Iterator { $hooksResult = $this->delayedParserTest->unleash( $this->parserTest ); if ( !$hooksResult ) { # Some hook reported an issue. Abort. - throw new MWException( "Problem running hook" ); + throw new MWException( "Problem running requested parser hook from the test file" ); } $this->test = array( @@ -558,7 +558,7 @@ class TestFileIterator implements Iterator { $line = trim( $line ); if ( $line ) { - $delayedParserTest->requireTransparentHook( $line ); + $this->delayedParserTest->requireTransparentHook( $line ); } } @@ -618,6 +618,7 @@ class TestFileIterator implements Iterator { * @param bool $fatal True iff an exception should be thrown if * the section is not found. * @return bool|string + * @throws MWException */ private function checkSection( $tokens, $fatal = true ) { if ( is_null( $this->section ) ) { @@ -691,6 +692,7 @@ class DelayedParserTest { * Should be the case if we found the parserTest is not disabled * @param ParserTest|NewParserTest $parserTest * @return bool + * @throws MWException */ public function unleash( &$parserTest ) { if ( !( $parserTest instanceof ParserTest || $parserTest instanceof NewParserTest ) ) { @@ -805,7 +807,7 @@ class TidySupport { global $wgTidyBin; $this->internalTidy = extension_loaded( 'tidy' ) && - class_exists( 'tidy' ); + class_exists( 'tidy' ) && !wfIsHHVM(); $this->externalTidy = is_executable( $wgTidyBin ) || Installer::locateExecutableInDefaultPaths( array( $wgTidyBin ) ) |