diff options
Diffstat (limited to '')
-rw-r--r-- | browser/components/touchbar/tests/browser/browser.ini | 11 | ||||
-rw-r--r-- | browser/components/touchbar/tests/browser/browser_touchbar_searchrestrictions.js | 158 | ||||
-rw-r--r-- | browser/components/touchbar/tests/browser/browser_touchbar_tests.js | 148 | ||||
-rw-r--r-- | browser/components/touchbar/tests/browser/readerModeArticle.html | 29 | ||||
-rw-r--r-- | browser/components/touchbar/tests/browser/test-video.mp4 | bin | 0 -> 36502 bytes | |||
-rw-r--r-- | browser/components/touchbar/tests/browser/video_test.html | 32 |
6 files changed, 378 insertions, 0 deletions
diff --git a/browser/components/touchbar/tests/browser/browser.ini b/browser/components/touchbar/tests/browser/browser.ini new file mode 100644 index 0000000000..4356d936f5 --- /dev/null +++ b/browser/components/touchbar/tests/browser/browser.ini @@ -0,0 +1,11 @@ +[DEFAULT] + +[browser_touchbar_searchrestrictions.js] +https_first_disabled = true +skip-if = os != "mac" +[browser_touchbar_tests.js] +skip-if = os != "mac" || verify # Bug 1611300 +support-files = + readerModeArticle.html + test-video.mp4 + video_test.html diff --git a/browser/components/touchbar/tests/browser/browser_touchbar_searchrestrictions.js b/browser/components/touchbar/tests/browser/browser_touchbar_searchrestrictions.js new file mode 100644 index 0000000000..67d4dacb7d --- /dev/null +++ b/browser/components/touchbar/tests/browser/browser_touchbar_searchrestrictions.js @@ -0,0 +1,158 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const { XPCOMUtils } = ChromeUtils.importESModule( + "resource://gre/modules/XPCOMUtils.sys.mjs" +); + +ChromeUtils.defineESModuleGetters(this, { + UrlbarUtils: "resource:///modules/UrlbarUtils.sys.mjs", + UrlbarTestUtils: "resource://testing-common/UrlbarTestUtils.sys.mjs", + UrlbarTokenizer: "resource:///modules/UrlbarTokenizer.sys.mjs", +}); + +XPCOMUtils.defineLazyServiceGetter( + this, + "TouchBarHelper", + "@mozilla.org/widget/touchbarhelper;1", + "nsITouchBarHelper" +); + +/** + * Tests the search restriction buttons in the Touch Bar. + */ + +/** + * @param {string} input + * The value to be inserted in the Urlbar. + * @param {UrlbarTokenizer.RESTRICT} token + * A restriction token corresponding to a Touch Bar button. + */ +async function searchAndCheckState({ input, token }) { + await UrlbarTestUtils.promiseAutocompleteResultPopup({ + window, + value: input, + }); + input = input.trimStart(); + if (Object.values(UrlbarTokenizer.RESTRICT).includes(input[0])) { + input = input.slice(1).trimStart(); + } + let searchMode = UrlbarUtils.searchModeForToken(token); + let expectedValue = searchMode ? input : `${token} ${input}`; + TouchBarHelper.insertRestrictionInUrlbar(token); + + if (searchMode) { + searchMode.entry = "touchbar"; + await UrlbarTestUtils.assertSearchMode(window, searchMode); + } + Assert.equal( + gURLBar.value, + expectedValue, + "The search restriction token should have been entered." + ); + + await UrlbarTestUtils.promisePopupClose(window); +} + +add_setup(async function() { + UrlbarTestUtils.init(this); + registerCleanupFunction(() => { + UrlbarTestUtils.uninit(); + }); +}); + +add_task(async function insertTokens() { + const tests = [ + { + input: "mozilla", + token: UrlbarTokenizer.RESTRICT.HISTORY, + }, + { + input: "mozilla", + token: UrlbarTokenizer.RESTRICT.BOOKMARK, + }, + { + input: "mozilla", + token: UrlbarTokenizer.RESTRICT.TAG, + }, + { + input: "mozilla", + token: UrlbarTokenizer.RESTRICT.OPENPAGE, + }, + ]; + for (let test of tests) { + await searchAndCheckState(test); + } +}); + +add_task(async function existingTokens() { + const tests = [ + { + input: "* mozilla", + token: UrlbarTokenizer.RESTRICT.HISTORY, + }, + { + input: "+ mozilla", + token: UrlbarTokenizer.RESTRICT.BOOKMARK, + }, + { + input: "( $ ^ mozilla", + token: UrlbarTokenizer.RESTRICT.TAG, + }, + { + input: "^*+%?#$ mozilla", + token: UrlbarTokenizer.RESTRICT.TAG, + }, + ]; + for (let test of tests) { + await searchAndCheckState(test); + } +}); + +add_task(async function stripSpaces() { + const tests = [ + { + input: " ^ mozilla", + token: UrlbarTokenizer.RESTRICT.HISTORY, + }, + { + input: " + mozilla ", + token: UrlbarTokenizer.RESTRICT.BOOKMARK, + }, + { + input: " moz illa ", + token: UrlbarTokenizer.RESTRICT.TAG, + }, + ]; + for (let test of tests) { + await searchAndCheckState(test); + } +}); + +add_task(async function clearURLs() { + const tests = [ + { + loadUrl: "http://example.com/", + token: UrlbarTokenizer.RESTRICT.HISTORY, + }, + { + loadUrl: "about:mozilla", + token: UrlbarTokenizer.RESTRICT.BOOKMARK, + }, + ]; + let win = BrowserWindowTracker.getTopWindow(); + await UrlbarTestUtils.promisePopupClose(win); + for (let { loadUrl, token } of tests) { + let browser = win.gBrowser.selectedBrowser; + let loadedPromise = BrowserTestUtils.browserLoaded(browser, false, loadUrl); + BrowserTestUtils.loadURI(browser, loadUrl); + await loadedPromise; + if (win.gURLBar.getAttribute("pageproxystate") != "valid") { + await TestUtils.waitForCondition( + () => win.gURLBar.getAttribute("pageproxystate") == "valid" + ); + } + await searchAndCheckState({ input: "", token }); + } +}); diff --git a/browser/components/touchbar/tests/browser/browser_touchbar_tests.js b/browser/components/touchbar/tests/browser/browser_touchbar_tests.js new file mode 100644 index 0000000000..4ba5d4bfec --- /dev/null +++ b/browser/components/touchbar/tests/browser/browser_touchbar_tests.js @@ -0,0 +1,148 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const { XPCOMUtils } = ChromeUtils.importESModule( + "resource://gre/modules/XPCOMUtils.sys.mjs" +); + +XPCOMUtils.defineLazyServiceGetter( + this, + "TouchBarHelper", + "@mozilla.org/widget/touchbarhelper;1", + "nsITouchBarHelper" +); +XPCOMUtils.defineLazyServiceGetter( + this, + "TouchBarInput", + "@mozilla.org/widget/touchbarinput;1", + "nsITouchBarInput" +); + +const TEST_PATH = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "http://example.com" +); + +function is_element_visible(aElement, aMsg) { + isnot(aElement, null, "Element should not be null when checking visibility"); + ok(!BrowserTestUtils.is_hidden(aElement), aMsg); +} + +function is_element_hidden(aElement, aMsg) { + isnot(aElement, null, "Element should not be null when checking visibility"); + ok(BrowserTestUtils.is_hidden(aElement), aMsg); +} + +/** + * Tests if our bookmark button updates with our event. + */ +add_task(async function updateBookmarkButton() { + // We first check the default state. This also serves the purpose of forcing + // nsITouchBarHelper to load on Macs without Touch Bars so that it will be + // listening for "bookmark-icon-updated". + Assert.equal( + TouchBarHelper.getTouchBarInput("AddBookmark").image.spec, + "chrome://browser/skin/bookmark-hollow.svg", + "AddBookmark image should be unfilled bookmark after event." + ); + + Services.obs.notifyObservers(null, "bookmark-icon-updated", "starred"); + Assert.equal( + TouchBarHelper.getTouchBarInput("AddBookmark").image.spec, + "chrome://browser/skin/bookmark.svg", + "AddBookmark image should be filled bookmark after event." + ); + + Services.obs.notifyObservers(null, "bookmark-icon-updated", "unstarred"); + Assert.equal( + TouchBarHelper.getTouchBarInput("AddBookmark").image.spec, + "chrome://browser/skin/bookmark-hollow.svg", + "AddBookmark image should be unfilled bookmark after event." + ); +}); + +/** + * Tests if our Reader View button updates when a page can be reader viewed. + */ +add_task(async function updateReaderView() { + const PREF_READERMODE = "reader.parse-on-load.enabled"; + await SpecialPowers.pushPrefEnv({ set: [[PREF_READERMODE, true]] }); + + // The page actions reader mode button + var readerButton = document.getElementById("reader-mode-button"); + is_element_hidden(readerButton, "Reader Mode button should be hidden."); + + Assert.equal( + TouchBarHelper.getTouchBarInput("ReaderView").disabled, + true, + "ReaderView Touch Bar button should be disabled by default." + ); + + let url = TEST_PATH + "readerModeArticle.html"; + await BrowserTestUtils.withNewTab(url, async function() { + await BrowserTestUtils.waitForCondition(() => !readerButton.hidden); + + Assert.equal( + TouchBarHelper.getTouchBarInput("ReaderView").disabled, + false, + "ReaderView Touch Bar button should be enabled on reader-able pages." + ); + }); +}); + +add_task(async function updateMainButtonInFullscreen() { + Assert.equal( + TouchBarHelper.getTouchBarInput("OpenLocation").image.spec, + "chrome://global/skin/icons/search-glass.svg", + "OpenLocation should be displaying the search glass icon." + ); + BrowserTestUtils.loadURI( + gBrowser.selectedBrowser, + TEST_PATH + "video_test.html" + ); + await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); + let entered = waitForFullScreenState(gBrowser.selectedBrowser, true); + // Fullscreen video must be triggered from a user input handler so the video + // page contains a script to enter fullscreen on Enter instead of us calling + // requestFullscreen directly here. + EventUtils.synthesizeKey("KEY_Enter"); + await entered; + Assert.equal( + TouchBarHelper.getTouchBarInput("OpenLocation").image.spec, + "chrome://browser/skin/fullscreen-exit.svg", + "OpenLocation should be displaying the exit fullscreen icon." + ); + let exited = waitForFullScreenState(gBrowser.selectedBrowser, false); + EventUtils.synthesizeKey("KEY_Enter"); + await exited; + Assert.equal( + TouchBarHelper.getTouchBarInput("OpenLocation").image.spec, + "chrome://global/skin/icons/search-glass.svg", + "OpenLocation should be displaying the search glass icon." + ); +}); + +function waitForFullScreenState(browser, state) { + info("inside waitforfullscreenstate"); + return new Promise(resolve => { + let eventReceived = false; + + let observe = (subject, topic, data) => { + if (!eventReceived) { + return; + } + Services.obs.removeObserver(observe, "fullscreen-painted"); + resolve(); + }; + Services.obs.addObserver(observe, "fullscreen-painted"); + + window.addEventListener( + `MozDOMFullscreen:${state ? "Entered" : "Exited"}`, + () => { + eventReceived = true; + }, + { once: true } + ); + }); +} diff --git a/browser/components/touchbar/tests/browser/readerModeArticle.html b/browser/components/touchbar/tests/browser/readerModeArticle.html new file mode 100644 index 0000000000..7cb014d2c3 --- /dev/null +++ b/browser/components/touchbar/tests/browser/readerModeArticle.html @@ -0,0 +1,29 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8" /> +<title>Article title</title> +<meta name="description" content="This is the article description." /> +</head> +<body> +<header>Site header</header> +<div> +<h1>Article title</h1> +<ul> + <li><a id="foo-anchor" href="#foo">by John Doe</a></li> +</ul> +<h2 class="author">by Jane Doe</h2> +<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ut gravida lorem. Ut turpis felis, pulvinar a semper sed, adipiscing id dolor. Pellentesque auctor nisi id magna consequat sagittis. Curabitur dapibus enim sit amet elit pharetra tincidunt feugiat nisl imperdiet. Ut convallis libero in urna ultrices accumsan. Donec sed odio eros. Donec viverra mi quis quam pulvinar at malesuada arcu rhoncus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In rutrum accumsan ultricies. Mauris vitae nisi at sem facilisis semper ac in est.</p> +<p>Vivamus fermentum semper porta. Nunc diam velit, adipiscing ut tristique vitae, sagittis vel odio. Maecenas convallis ullamcorper ultricies. Curabitur ornare, ligula semper consectetur sagittis, nisi diam iaculis velit, id fringilla sem nunc vel mi. Nam dictum, odio nec pretium volutpat, arcu ante placerat erat, non tristique elit urna et turpis. Quisque mi metus, ornare sit amet fermentum et, tincidunt et orci. Fusce eget orci a orci congue vestibulum. Ut dolor diam, elementum et vestibulum eu, porttitor vel elit. Curabitur venenatis pulvinar tellus gravida ornare. Sed et erat faucibus nunc euismod ultricies ut id justo. Nullam cursus suscipit nisi, et ultrices justo sodales nec. Fusce venenatis facilisis lectus ac semper. Aliquam at massa ipsum. Quisque bibendum purus convallis nulla ultrices ultricies. Nullam aliquam, mi eu aliquam tincidunt, purus velit laoreet tortor, viverra pretium nisi quam vitae mi. Fusce vel volutpat elit. Nam sagittis nisi dui.</p> +<p>Vivamus fermentum semper porta. Nunc diam velit, adipiscing ut tristique vitae, sagittis vel odio. Maecenas convallis ullamcorper ultricies. Curabitur ornare, ligula semper consectetur sagittis, nisi diam iaculis velit, id fringilla sem nunc vel mi. Nam dictum, odio nec pretium volutpat, arcu ante placerat erat, non tristique elit urna et turpis. Quisque mi metus, ornare sit amet fermentum et, tincidunt et orci. Fusce eget orci a orci congue vestibulum. Ut dolor diam, elementum et vestibulum eu, porttitor vel elit. Curabitur venenatis pulvinar tellus gravida ornare. Sed et erat faucibus nunc euismod ultricies ut id justo. Nullam cursus suscipit nisi, et ultrices justo sodales nec. Fusce venenatis facilisis lectus ac semper. Aliquam at massa ipsum. Quisque bibendum purus convallis nulla ultrices ultricies. Nullam aliquam, mi eu aliquam tincidunt, purus velit laoreet tortor, viverra pretium nisi quam vitae mi. Fusce vel volutpat elit. Nam sagittis nisi dui.</p> +<p>Vivamus fermentum semper porta. Nunc diam velit, adipiscing ut tristique vitae, sagittis vel odio. Maecenas convallis ullamcorper ultricies. Curabitur ornare, ligula semper consectetur sagittis, nisi diam iaculis velit, id fringilla sem nunc vel mi. Nam dictum, odio nec pretium volutpat, arcu ante placerat erat, non tristique elit urna et turpis. Quisque mi metus, ornare sit amet fermentum et, tincidunt et orci. Fusce eget orci a orci congue vestibulum. Ut dolor diam, elementum et vestibulum eu, porttitor vel elit. Curabitur venenatis pulvinar tellus gravida ornare. Sed et erat faucibus nunc euismod ultricies ut id justo. Nullam cursus suscipit nisi, et ultrices justo sodales nec. Fusce venenatis facilisis lectus ac semper. Aliquam at massa ipsum. Quisque bibendum purus convallis nulla ultrices ultricies. Nullam aliquam, mi eu aliquam tincidunt, purus velit laoreet tortor, viverra pretium nisi quam vitae mi. Fusce vel volutpat elit. Nam sagittis nisi dui.</p> +<p>Vivamus fermentum semper porta. Nunc diam velit, adipiscing ut tristique vitae, sagittis vel odio. Maecenas convallis ullamcorper ultricies. Curabitur ornare, ligula semper consectetur sagittis, nisi diam iaculis velit, id fringilla sem nunc vel mi. Nam dictum, odio nec pretium volutpat, arcu ante placerat erat, non tristique elit urna et turpis. Quisque mi metus, ornare sit amet fermentum et, tincidunt et orci. Fusce eget orci a orci congue vestibulum. Ut dolor diam, elementum et vestibulum eu, porttitor vel elit. Curabitur venenatis pulvinar tellus gravida ornare. Sed et erat faucibus nunc euismod ultricies ut id justo. Nullam cursus suscipit nisi, et ultrices justo sodales nec. Fusce venenatis facilisis lectus ac semper. Aliquam at massa ipsum. Quisque bibendum purus convallis nulla ultrices ultricies. Nullam aliquam, mi eu aliquam tincidunt, purus velit laoreet tortor, viverra pretium nisi quam vitae mi. Fusce vel volutpat elit. Nam sagittis nisi dui.</p> +<p id="foo">by John Doe</p> +<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ut gravida lorem. Ut turpis felis, pulvinar a semper sed, adipiscing id dolor. Pellentesque auctor nisi id magna consequat sagittis. Curabitur dapibus enim sit amet elit pharetra tincidunt feugiat nisl imperdiet. Ut convallis libero in urna ultrices accumsan. Donec sed odio eros. Donec viverra mi quis quam pulvinar at malesuada arcu rhoncus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In rutrum accumsan ultricies. Mauris vitae nisi at sem facilisis semper ac in est.</p> +<p>Vivamus fermentum semper porta. Nunc diam velit, adipiscing ut tristique vitae, sagittis vel odio. Maecenas convallis ullamcorper ultricies. Curabitur ornare, ligula semper consectetur sagittis, nisi diam iaculis velit, id fringilla sem nunc vel mi. Nam dictum, odio nec pretium volutpat, arcu ante placerat erat, non tristique elit urna et turpis. Quisque mi metus, ornare sit amet fermentum et, tincidunt et orci. Fusce eget orci a orci congue vestibulum. Ut dolor diam, elementum et vestibulum eu, porttitor vel elit. Curabitur venenatis pulvinar tellus gravida ornare. Sed et erat faucibus nunc euismod ultricies ut id justo. Nullam cursus suscipit nisi, et ultrices justo sodales nec. Fusce venenatis facilisis lectus ac semper. Aliquam at massa ipsum. Quisque bibendum purus convallis nulla ultrices ultricies. Nullam aliquam, mi eu aliquam tincidunt, purus velit laoreet tortor, viverra pretium nisi quam vitae mi. Fusce vel volutpat elit. Nam sagittis nisi dui.</p> +<p>Vivamus fermentum semper porta. Nunc diam velit, adipiscing ut tristique vitae, sagittis vel odio. Maecenas convallis ullamcorper ultricies. Curabitur ornare, ligula semper consectetur sagittis, nisi diam iaculis velit, id fringilla sem nunc vel mi. Nam dictum, odio nec pretium volutpat, arcu ante placerat erat, non tristique elit urna et turpis. Quisque mi metus, ornare sit amet fermentum et, tincidunt et orci. Fusce eget orci a orci congue vestibulum. Ut dolor diam, elementum et vestibulum eu, porttitor vel elit. Curabitur venenatis pulvinar tellus gravida ornare. Sed et erat faucibus nunc euismod ultricies ut id justo. Nullam cursus suscipit nisi, et ultrices justo sodales nec. Fusce venenatis facilisis lectus ac semper. Aliquam at massa ipsum. Quisque bibendum purus convallis nulla ultrices ultricies. Nullam aliquam, mi eu aliquam tincidunt, purus velit laoreet tortor, viverra pretium nisi quam vitae mi. Fusce vel volutpat elit. Nam sagittis nisi dui.</p> +<p>Vivamus fermentum semper porta. Nunc diam velit, adipiscing ut tristique vitae, sagittis vel odio. Maecenas convallis ullamcorper ultricies. Curabitur ornare, ligula semper consectetur sagittis, nisi diam iaculis velit, id fringilla sem nunc vel mi. Nam dictum, odio nec pretium volutpat, arcu ante placerat erat, non tristique elit urna et turpis. Quisque mi metus, ornare sit amet fermentum et, tincidunt et orci. Fusce eget orci a orci congue vestibulum. Ut dolor diam, elementum et vestibulum eu, porttitor vel elit. Curabitur venenatis pulvinar tellus gravida ornare. Sed et erat faucibus nunc euismod ultricies ut id justo. Nullam cursus suscipit nisi, et ultrices justo sodales nec. Fusce venenatis facilisis lectus ac semper. Aliquam at massa ipsum. Quisque bibendum purus convallis nulla ultrices ultricies. Nullam aliquam, mi eu aliquam tincidunt, purus velit laoreet tortor, viverra pretium nisi quam vitae mi. Fusce vel volutpat elit. Nam sagittis nisi dui.</p> +<p>Vivamus fermentum semper porta. Nunc diam velit, adipiscing ut tristique vitae, sagittis vel odio. Maecenas convallis ullamcorper ultricies. Curabitur ornare, ligula semper consectetur sagittis, nisi diam iaculis velit, id fringilla sem nunc vel mi. Nam dictum, odio nec pretium volutpat, arcu ante placerat erat, non tristique elit urna et turpis. Quisque mi metus, ornare sit amet fermentum et, tincidunt et orci. Fusce eget orci a orci congue vestibulum. Ut dolor diam, elementum et vestibulum eu, porttitor vel elit. Curabitur venenatis pulvinar tellus gravida ornare. Sed et erat faucibus nunc euismod ultricies ut id justo. Nullam cursus suscipit nisi, et ultrices justo sodales nec. Fusce venenatis facilisis lectus ac semper. Aliquam at massa ipsum. Quisque bibendum purus convallis nulla ultrices ultricies. Nullam aliquam, mi eu aliquam tincidunt, purus velit laoreet tortor, viverra pretium nisi quam vitae mi. Fusce vel volutpat elit. Nam sagittis nisi dui.</p> +</div> +</body> +</html> diff --git a/browser/components/touchbar/tests/browser/test-video.mp4 b/browser/components/touchbar/tests/browser/test-video.mp4 Binary files differnew file mode 100644 index 0000000000..6ea66eb1fc --- /dev/null +++ b/browser/components/touchbar/tests/browser/test-video.mp4 diff --git a/browser/components/touchbar/tests/browser/video_test.html b/browser/components/touchbar/tests/browser/video_test.html new file mode 100644 index 0000000000..173de35f0e --- /dev/null +++ b/browser/components/touchbar/tests/browser/video_test.html @@ -0,0 +1,32 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Touch Bar Fullscreen Video Test</title> +</head> +<style> + video { + display: block; + border: 1px solid black; + } +</style> +<body> + <video id="test-video" src="test-video.mp4" controls loop="true"></video> +</body> +<script> + let video = document.getElementById("test-video"); + + function toggleFullScreen() { + if (!document.fullscreenElement) { + document.documentElement.requestFullscreen(); + } else if (document.exitFullscreen) { + document.exitFullscreen(); + } + } + document.addEventListener("keydown", function(e) { + if (e.keyCode == 13) { + toggleFullScreen(); + } + }); +</script> +</html> |