diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
commit | 6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch) | |
tree | a68f146d7fa01f0134297619fbe7e33db084e0aa /layout/style/test/test_computed_style.html | |
parent | Initial commit. (diff) | |
download | thunderbird-upstream.tar.xz thunderbird-upstream.zip |
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'layout/style/test/test_computed_style.html')
-rw-r--r-- | layout/style/test/test_computed_style.html | 664 |
1 files changed, 664 insertions, 0 deletions
diff --git a/layout/style/test/test_computed_style.html b/layout/style/test/test_computed_style.html new file mode 100644 index 0000000000..c2dc667f2f --- /dev/null +++ b/layout/style/test/test_computed_style.html @@ -0,0 +1,664 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for miscellaneous computed style issues</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <style id="style"></style> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=">Mozilla Bug </a> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for miscellaneous computed style issues **/ + +var frame_container = document.getElementById("display"); +var noframe_container = document.getElementById("content"); + +(function test_bug_595650() { + // Test handling of horizontal and vertical percentages for border-radius. + var p = document.createElement("p"); + p.setAttribute("style", "width: 256px; height: 128px"); + p.style.borderTopLeftRadius = "1.5625%"; /* 1/64 == 4px 2px */ + p.style.borderTopRightRadius = "5px"; + p.style.borderBottomRightRadius = "5px 3px"; + p.style.borderBottomLeftRadius = "1.5625% 3.125%" /* 1/64 1/32 == 4px 4px */ + var cs = getComputedStyle(p, ""); + + frame_container.appendChild(p); + is(cs.borderTopLeftRadius, "1.5625%", + "computed value of % border-radius, with frame"); + is(cs.borderTopRightRadius, "5px", + "computed value of px border-radius, with frame"); + is(cs.borderBottomRightRadius, "5px 3px", + "computed value of px border-radius, with frame"); + is(cs.borderBottomLeftRadius, "1.5625% 3.125%", + "computed value of % border-radius, with frame"); + + noframe_container.appendChild(p); + is(cs.borderTopLeftRadius, "1.5625%", + "computed value of % border-radius, without frame"); + is(cs.borderTopRightRadius, "5px", + "computed value of px border-radius, without frame"); + is(cs.borderBottomRightRadius, "5px 3px", + "computed value of px border-radius, without frame"); + is(cs.borderBottomLeftRadius, "1.5625% 3.125%", + "computed value of % border-radius, without frame"); + + p.remove(); +})(); + +(function test_bug_1292447() { + // Was for bug 595651 which tests that clamping of border-radius + // is reflected in computed style. + // For compatibility issue, resolved value is computed value now. + var p = document.createElement("p"); + p.setAttribute("style", "width: 190px; height: 90px; border: 5px solid;"); + p.style.borderRadius = "1000px"; + var cs = getComputedStyle(p, ""); + + frame_container.appendChild(p); + is(cs.borderTopLeftRadius, "1000px", + "computed value of clamped border radius (top left)"); + is(cs.borderTopRightRadius, "1000px", + "computed value of clamped border radius (top right)"); + is(cs.borderBottomRightRadius, "1000px", + "computed value of clamped border radius (bottom right)"); + is(cs.borderBottomLeftRadius, "1000px", + "computed value of clamped border radius (bottom left)"); + + p.style.overflowY = "scroll"; + is(cs.borderTopLeftRadius, "1000px", + "computed value of clamped border radius (top left, overflow-y)"); + // Fennec doesn't have scrollbars for overflow:scroll content + if (p.clientWidth == p.offsetWidth - 10) { + is(cs.borderTopRightRadius, "1000px", + "computed value of border radius (top right, overflow-y)"); + is(cs.borderBottomRightRadius, "1000px", + "computed value of border radius (bottom right, overflow-y)"); + } else { + is(cs.borderTopRightRadius, "1000px", + "computed value of clamped border radius (top right, overflow-y)"); + is(cs.borderBottomRightRadius, "1000px", + "computed value of clamped border radius (bottom right, overflow-y)"); + } + is(cs.borderBottomLeftRadius, "1000px", + "computed value of clamped border radius (bottom left, overflow-y)"); + + p.style.overflowY = "hidden"; + p.style.overflowX = "scroll"; + is(cs.borderTopLeftRadius, "1000px", + "computed value of clamped border radius (top left, overflow-x)"); + is(cs.borderTopRightRadius, "1000px", + "computed value of clamped border radius (top right, overflow-x)"); + // Fennec doesn't have scrollbars for overflow:scroll content + if (p.clientHeight == p.offsetHeight - 10) { + is(cs.borderBottomRightRadius, "1000px", + "computed value of border radius (bottom right, overflow-x)"); + is(cs.borderBottomLeftRadius, "1000px", + "computed value of border radius (bottom left, overflow-x)"); + } else { + is(cs.borderBottomRightRadius, "1000px", + "computed value of clamped border radius (bottom right, overflow-x)"); + is(cs.borderBottomLeftRadius, "1000px", + "computed value of clamped border radius (bottom left, overflow-x)"); + } + + p.remove(); +})(); + +(function test_bug_647885_1() { + // Test that various background-position styles round-trip correctly + var backgroundPositions = [ + [ "0 0", "0px 0px", "unitless 0" ], + [ "0px 0px", "0px 0px", "0 with units" ], + [ "0% 0%", "0% 0%", "0%" ], + [ "calc(0px) 0", "0px 0px", "0 calc with units x" ], + [ "0 calc(0px)", "0px 0px", "0 calc with units y" ], + [ "calc(3px - 3px) 0", "0px 0px", "computed 0 calc with units x" ], + [ "0 calc(3px - 3px)", "0px 0px", "computed 0 calc with units y" ], + [ "calc(0%) 0", "0% 0px", "0% calc x"], + [ "0 calc(0%)", "0px 0%", "0% calc y"], + [ "calc(3px + 2% - 2%) 0", "calc(0% + 3px) 0px", + "computed 0% calc x"], + [ "0 calc(3px + 2% - 2%)", "0px calc(0% + 3px)", + "computed 0% calc y"], + [ "calc(3px - 5px) calc(6px - 7px)", "-2px -1px", + "negative pixel width"], + [ "", "0% 0%", "initial value" ], + ]; + + var p = document.createElement("p"); + var cs = getComputedStyle(p, ""); + frame_container.appendChild(p); + + for (var i = 0; i < backgroundPositions.length; ++i) { + var test = backgroundPositions[i]; + p.style.backgroundPosition = test[0]; + is(cs.backgroundPosition, test[1], "computed value of " + test[2] + " background-position"); + } + + p.remove(); +})(); + +(function test_bug_647885_2() { + // Test that various background-size styles round-trip correctly + var backgroundSizes = [ + [ "0 0", "0px 0px", "unitless 0" ], + [ "0px 0px", "0px 0px", "0 with units" ], + [ "0% 0%", "0% 0%", "0%" ], + [ "calc(0px) 0", "0px 0px", "0 calc with units horizontal" ], + [ "0 calc(0px)", "0px 0px", "0 calc with units vertical" ], + [ "calc(3px - 3px) 0", "0px 0px", "computed 0 calc with units horizontal" ], + [ "0 calc(3px - 3px)", "0px 0px", "computed 0 calc with units vertical" ], + [ "calc(0%) 0", "0% 0px", "0% calc horizontal"], + [ "0 calc(0%)", "0px 0%", "0% calc vertical"], + [ "calc(3px + 2% - 2%) 0", "calc(0% + 3px) 0px", + "computed 0% calc horizontal"], + [ "0 calc(3px + 2% - 2%)", "0px calc(0% + 3px)", + "computed 0% calc vertical"], + [ "calc(3px - 5px) calc(6px - 9px)", "0px 0px", "negative pixel width" ], + [ "", "auto", "initial value" ], + ]; + + var p = document.createElement("p"); + var cs = getComputedStyle(p, ""); + frame_container.appendChild(p); + + for (var i = 0; i < backgroundSizes.length; ++i) { + var test = backgroundSizes[i]; + p.style.backgroundSize = test[0]; + is(cs.backgroundSize, test[1], "computed value of " + test[2] + " background-size"); + } + + p.remove(); +})(); + +(function test_bug_716628() { + // Test that various gradient styles round-trip correctly + var backgroundImages = [ + [ "radial-gradient(at 10% bottom, #ffffff, black)", + "radial-gradient(at 10% 100%, rgb(255, 255, 255), rgb(0, 0, 0))", + "radial gradient 1" ], + [ "radial-gradient(#ffffff, black)", + "radial-gradient(rgb(255, 255, 255), rgb(0, 0, 0))", + "radial gradient 2" ], + [ "radial-gradient(farthest-corner, #ffffff, black)", + "radial-gradient(rgb(255, 255, 255), rgb(0, 0, 0))", + "radial gradient 3" ], + [ "linear-gradient(red, blue)", + "linear-gradient(rgb(255, 0, 0), rgb(0, 0, 255))", + "linear gradient 1" ], + [ "linear-gradient(to bottom, red, blue)", + "linear-gradient(rgb(255, 0, 0), rgb(0, 0, 255))", + "linear gradient 2" ], + [ "linear-gradient(to right, red, blue)", + "linear-gradient(to right, rgb(255, 0, 0), rgb(0, 0, 255))", + "linear gradient 3" ], + [ "linear-gradient(-45deg, red, blue)", + "linear-gradient(-45deg, rgb(255, 0, 0), rgb(0, 0, 255))", + "linear gradient with angle in degrees" ], + [ "linear-gradient(-0.125turn, red, blue)", + "linear-gradient(-45deg, rgb(255, 0, 0), rgb(0, 0, 255))", + "linear gradient with angle in turns" ], + ]; + + var p = document.createElement("p"); + var cs = getComputedStyle(p, ""); + frame_container.appendChild(p); + + for (var i = 0; i < backgroundImages.length; ++i) { + var test = backgroundImages[i]; + p.style.backgroundImage = test[0]; + is(cs.backgroundImage, test[1], "computed value of " + test[2] + " background-image"); + } + + p.remove(); +})(); + +(function test_bug_1363349_linear() { + const specPrefix = "-webkit-gradient(linear, "; + const specSuffix = ", from(blue), to(lime))"; + + const expPrefix = "linear-gradient("; + const expSuffix = "rgb(0, 0, 255) 0%, rgb(0, 255, 0) 100%)"; + + let testcases = [ + [ "calc(5 + 5) top, calc(10 + 10) top", + "to right", + "calc(num+num) in position" + ], + [ "left calc(25% - 10%), right calc(75% + 10%)", + "to right bottom", + "calc(pct+pct) in position " + ] + ]; + + let p = document.createElement("p"); + let cs = getComputedStyle(p, ""); + frame_container.appendChild(p); + + for (let test of testcases) { + let specifiedStyle = specPrefix + test[0] + specSuffix; + let expectedStyle = expPrefix; + if (test[1] != "") { + expectedStyle += test[1] + ", "; + } + expectedStyle += expSuffix; + + p.style.backgroundImage = specifiedStyle; + is(cs.backgroundImage, expectedStyle, + "computed value of -webkit-gradient expression (" + test[2] + ")"); + p.style.backgroundImage = ""; + } + + p.remove(); +})(); + +(function test_bug_1363349_radial() { + const specPrefix = "-webkit-gradient(radial, "; + const specSuffix = ", from(blue), to(lime))"; + + const expPrefix = "radial-gradient("; + const expSuffix = "rgb(0, 0, 255) 0%, rgb(0, 255, 0) 100%)"; + + let testcases = [ + [ "1 2, 0, 3 4, calc(1 + 5)", + "6px at 3px 4px", + "calc(num+num) in radius" + ], + [ "1 2, calc(1 + 2), 3 4, calc(1 + 5)", + "6px at 3px 4px", + "calc(num+num) in radius" + ], + [ "calc(0 + 1) calc(1 + 1), calc(1 + 2), calc(1 + 2) 4, calc(1 + 5)", + "6px at 3px 4px", + "calc(num+num) in position and radius" + ] + ]; + + let p = document.createElement("p"); + let cs = getComputedStyle(p, ""); + frame_container.appendChild(p); + + for (let test of testcases) { + let specifiedStyle = specPrefix + test[0] + specSuffix; + let expectedStyle = expPrefix; + if (test[1] != "") { + expectedStyle += test[1] + ", "; + } + expectedStyle += expSuffix; + + p.style.backgroundImage = specifiedStyle; + is(cs.backgroundImage, expectedStyle, + "computed value of -webkit-gradient expression (" + test[2] + ")"); + p.style.backgroundImage = ""; + } + + p.remove(); +})(); + +(function test_bug_1241623() { + // Test that -webkit-gradient() styles are approximated the way we expect: + + // For compactness, we'll pull out the common prefix & suffix from all of the + // specified & expected styles, and construct the full expression on the fly: + const specPrefix = "-webkit-gradient(linear, "; + const specSuffix = ", from(blue), to(lime))"; + + const expPrefix = "linear-gradient("; + const expSuffix = "rgb(0, 0, 255) 0%, rgb(0, 255, 0) 100%)"; + + let testcases = [ + // + // [ legacyDirection, + // modernDirection, // (empty string means use default direction) + // descriptionOfTestcase ], + + // If start & end are at same point, we just produce a gradient with + // the default direction. + [ "left top, left top", + "", + "start & end point are the same" ], + [ "40 40, 40 40", + "", + "start & end point are the same" ], + [ "center center, center center", + "", + "start & end point are the same" ], + + // If start & end use different units in the same coordinate, we generally + // can't extract a direction (because we can't know whether arbitrary + // percent values are larger or smaller than arbitrary pixel values). So + // we produce a gradient in the default direction. + [ "left top, 30 100%", // (Note: keywords like "left" are really % vals.) + "", + "start & end point have different units" ], + [ "100% 15, right bottom", + "", + "start & end point have different units" ], + [ "0 0%, 20 20", + "", + "start & end point have different units" ], + [ "0 0, 100% 20", + "", + "start & end point have different units" ], + [ "5% 30, 20 50%", + "", + "start & end point have different units" ], + [ "5% 6%, 20 30", + "", + "start & end point have different units" ], + + // Gradient starting/ending somewhere arbitrary in middle: + [ "center center, right top", + "to right top", + "from center to right top" ], + [ "left top, center center", + "to right bottom", + "from left top to center" ], + [ "10 15, 5 20", + "to left bottom", + "from arbitrary point to another point in lower-left direction" ], + + // Gradient using negative coordinates: + [ "-10 -15, 0 0", + "to right bottom", + "from negative point to origin" ], + [ "-100 10, 20 30", + "to right bottom", + "from negative-x point to another point in lower-right direction" ], + [ "10 -100, 5 10", + "to left bottom", + "from negative-y point to another point in lower-left direction" ], + + // Diagonal gradient between sides/corners: + [ "center top, left center", + "to left bottom", + "left/bottom-wards, using edge keywords" ], + [ "left center, center top", + "to right top", + "top/right-wards, using edge keywords" ], + [ "right center, center top", + "to left top", + "top/left-wards, using edge keywords" ], + [ "right top, center bottom", + "to left bottom", + "bottom/left-wards, using edge keywords" ], + [ "left top, right bottom", + "to right bottom", + "bottom/right-wards, using edge keywords" ], + [ "left bottom, right top", + "to right top", + "top/right-wards, using edge keywords" ], + ]; + + let p = document.createElement("p"); + let cs = getComputedStyle(p, ""); + frame_container.appendChild(p); + + for (let test of testcases) { + let specifiedStyle = specPrefix + test[0] + specSuffix; + let expectedStyle = expPrefix; + if (test[1] != "") { + expectedStyle += test[1] + ", "; + } + expectedStyle += expSuffix; + + p.style.backgroundImage = specifiedStyle; + is(cs.backgroundImage, expectedStyle, + "computed value of -webkit-gradient expression (" + test[2] + ")"); + p.style.backgroundImage = ""; + } + + p.remove(); +})(); + +(function test_bug_1293164() { + var p = document.createElement("p"); + var cs = getComputedStyle(p, ""); + frame_container.appendChild(p); + + var docPath = document.URL.substring(0, document.URL.lastIndexOf("/") + 1); + + var localURL = "url(\"#foo\")"; + var nonLocalURL = "url(\"foo.svg#foo\")"; + var resolvedNonLocalURL = "url(\"" + docPath + "foo.svg#foo\")"; + + var testStyles = [ + "maskImage", + "backgroundImage", + "markerStart", + "markerMid", + "markerEnd", + "clipPath", + "filter", + "fill", + "stroke", + ]; + + for (var prop of testStyles) { + p.style[prop] = localURL; + is(cs[prop], localURL, "computed value of " + prop); + p.style[prop] = nonLocalURL; + is(cs[prop], resolvedNonLocalURL, "computed value of " + prop); + } + + p.remove(); +})(); + +(function test_bug_1347164() { + // Test that computed color values are serialized as "rgb()" + // IFF they're fully-opaque (and otherwise as "rgba()"). + var color = [ + ["rgba(0, 0, 0, 1)", "rgb(0, 0, 0)"], + ["rgba(0, 0, 0, 0.5)", "rgba(0, 0, 0, 0.5)"], + ["hsla(0, 0%, 0%, 1)", "rgb(0, 0, 0)"], + ["hsla(0, 0%, 0%, 0.5)", "rgba(0, 0, 0, 0.5)"], + ]; + + var css_color_4 = [ + ["rgba(0 0 0 / 1)", "rgb(0, 0, 0)"], + ["rgba(0 0 0 / 0.1)", "rgba(0, 0, 0, 0.1)"], + ["rgb(0 0 0 / 1)", "rgb(0, 0, 0)"], + ["rgb(0 0 0 / 0.2)", "rgba(0, 0, 0, 0.2)"], + ["hsla(0 0% 0% / 1)", "rgb(0, 0, 0)"], + ["hsla(0deg 0% 0% / 0.3)", "rgba(0, 0, 0, 0.3)"], + ["hsl(0 0% 0% / 1)", "rgb(0, 0, 0)"], + ["hsl(0 0% 0% / 0.4)", "rgba(0, 0, 0, 0.4)"], + ]; + + var p = document.createElement("p"); + var cs = getComputedStyle(p, ""); + frame_container.appendChild(p); + + for (var i = 0; i < color.length; ++i) { + var test = color[i]; + p.style.color = test[0]; + is(cs.color, test[1], "computed value of " + test[0]); + } + for (var i = 0; i < css_color_4.length; ++i) { + var test = css_color_4[i]; + p.style.color = test[0]; + is(cs.color, test[1], "css-color-4 computed value of " + test[0]); + } + + p.remove(); +})(); + +(function test_bug_1357117() { + // Test that vendor-prefixed gradient styles round-trip with the same prefix, + // or with no prefix. + var backgroundImages = [ + // [ specified style, + // expected computed style, + // descriptionOfTestcase ], + // Linear gradient with legacy-gradient-line (needs prefixed syntax): + [ "-webkit-linear-gradient(10deg, red, blue)", + "-webkit-linear-gradient(10deg, rgb(255, 0, 0), rgb(0, 0, 255))", + "-webkit-linear-gradient with angled legacy-gradient-line" ], + + // Linear gradient with box corner (needs prefixed syntax): + [ "-webkit-linear-gradient(top left, red, blue)", + "-webkit-linear-gradient(left top, rgb(255, 0, 0), rgb(0, 0, 255))", + "-webkit-linear-gradient with box corner" ], + + // Linear gradient with default keyword (should be serialized without keyword): + [ "-webkit-linear-gradient(top, red, blue)", + "-webkit-linear-gradient(rgb(255, 0, 0), rgb(0, 0, 255))", + "-webkit-linear-gradient with legacy default direction keyword" ], + + // Radial gradients (should be serialized using modern unprefixed style): + [ "-webkit-radial-gradient(contain, red, blue)", + "-webkit-radial-gradient(closest-side, rgb(255, 0, 0), rgb(0, 0, 255))", + "-webkit-radial-gradient with legacy 'contain' keyword" ], + ]; + + var p = document.createElement("p"); + var cs = getComputedStyle(p, ""); + frame_container.appendChild(p); + + for (var i = 0; i < backgroundImages.length; ++i) { + var test = backgroundImages[i]; + p.style.backgroundImage = test[0]; + is(cs.backgroundImage, test[1], + "computed value of prefixed gradient expression (" + test[2] + ")"); + } + + p.remove(); +})(); + +(function test_bug_1367028() { + const borderImageSubprops = [ + "border-image-slice", + "border-image-outset", + "border-image-width" + ]; + const rectValues = [ + { + values: ["5 5 5 5", "5 5 5", "5 5", "5"], + expected: "5", + desc: "identical four sides", + }, + { + values: ["5 6 5 6", "5 6 5", "5 6"], + expected: "5 6", + desc: "identical values on each axis", + }, + { + values: ["5 6 7 6", "5 6 7"], + expected: "5 6 7", + desc: "identical values on left and right", + }, + { + values: ["5 6 5 7"], + desc: "identical values on top and bottom", + }, + { + values: ["5 5 6 6", "5 6 6 5"], + desc: "identical values on unrelated sides", + }, + { + values: ["5 6 7 8"], + desc: "different values on all sides", + }, + ]; + + let frameContainer = document.getElementById("display"); + let p = document.createElement("p"); + frameContainer.appendChild(p); + let cs = getComputedStyle(p); + + for (let prop of borderImageSubprops) { + for (let {values, expected, desc} of rectValues) { + for (let value of values) { + p.style.setProperty(prop, value); + is(cs.getPropertyValue(prop), + expected ? expected : value, `${desc} for ${prop}`); + p.style.removeProperty(prop); + } + } + } + + p.remove(); +})(); + +(function test_bug_1378368() { + // Test that negative results of calc()s in basic-shapes (e.g. polygon()) should + // not be clamped to 0px. + var clipPaths = [ + // [ specified style, + // expected computed style, + // descriptionOfTestcase ], + // polygon: + [ "polygon(calc(10px - 20px) 0px, 100px 100px, 0px 100px)", + "polygon(-10px 0px, 100px 100px, 0px 100px)", + "polygon with negative calc() coordinates" ], + // inset: + [ "inset(calc(10px - 20px))", + "inset(-10px)", + "inset with negative calc() coordinates" ], + ]; + + var p = document.createElement("p"); + var cs = getComputedStyle(p, ""); + frame_container.appendChild(p); + + for (let test of clipPaths) { + p.style.clipPath = test[0]; + is(cs.clipPath, test[1], + "computed value of clip-path for basic-shapes (" + test[2] + ")"); + } + + p.remove(); +})(); + +(function test_bug_1418433() { + // Test that the style data read through getComputedStyle is always up-to-date, + // even for non-displayed elements. + + var d = document.createElement("div"); + d.setAttribute("id", "nonDisplayedDiv"); + var cs = getComputedStyle(d, null); + noframe_container.appendChild(d); + + // Test for stylesheet change, i.e., added/changed/removed + var style = document.getElementById("style"); + is(cs.height, "auto", + "computed value of display none element (before testing)"); + style.textContent = "#nonDisplayedDiv { height: 100px; }"; + is(cs.height, "100px", + "computed value of display none element (sheet added)"); + style.textContent = "#nonDisplayedDiv { height: 10px; }"; + is(cs.height, "10px", + "computed value of display none element (sheet changed)"); + style.textContent = ""; + is(cs.height, "auto", + "computed value of display none element (sheet removed)"); + + // Test for rule change, i.e., added/changed/removed + var styleSheet = style.sheet; + is(cs.width, "auto", + "computed value of display none element (before testing)"); + styleSheet.insertRule("#nonDisplayedDiv { width: 100px; }", 0); + is(cs.width, "100px", + "computed value of display none element (rule added)"); + styleSheet.deleteRule(0); + styleSheet.insertRule("#nonDisplayedDiv { width: 10px; }", 0); + is(cs.width, "10px", + "computed value of display none element (rule changed)"); + styleSheet.deleteRule(0); + is(cs.width, "auto", + "computed value of display none element (rule removed)"); + + d.remove(); +})(); + +</script> +</pre> +</body> +</html> |