<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[287324] trunk/Source/WebCore</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/287324">287324</a></dd>
<dt>Author</dt> <dd>weinig@apple.com</dd>
<dt>Date</dt> <dd>2021-12-21 11:15:59 -0800 (Tue, 21 Dec 2021)</dd>
</dl>

<h3>Log Message</h3>
<pre>Gradient encode/decode does not validate that the serialized stops were sorted
https://bugs.webkit.org/show_bug.cgi?id=234558

Reviewed by Simon Fraser.

Stop encoding and decoding the stopsSorted bit on Gradient for serialization as
we still need to validate the stops are sorted on deserialization.

While here, optimize things a bit by allowing one to pass all the necessary
parameters to the Gradient create function, which allows us to avoid unnecessary
extra invalidation. Now that the GradientSpreadMethod can be set on construction
there is no need for its setter.

* platform/graphics/Gradient.cpp:
(WebCore::Gradient::create):
(WebCore::Gradient::Gradient):
(WebCore::Gradient::sortStops const):
(WebCore::Gradient::setSpreadMethod): Deleted.
* platform/graphics/Gradient.h:
(WebCore::Gradient::create):
(WebCore::Gradient::stops const):
(WebCore::Gradient::encode const):
(WebCore::Gradient::decode):
* rendering/svg/RenderSVGResourceGradient.cpp:
(WebCore::RenderSVGResourceGradient::stopsByApplyingColorFilter):
(WebCore::RenderSVGResourceGradient::addStops): Deleted.
* rendering/svg/RenderSVGResourceGradient.h:
* rendering/svg/RenderSVGResourceLinearGradient.cpp:
(WebCore::RenderSVGResourceLinearGradient::buildGradient const):
* rendering/svg/RenderSVGResourceRadialGradient.cpp:
(WebCore::RenderSVGResourceRadialGradient::buildGradient const):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsGradientcpp">trunk/Source/WebCore/platform/graphics/Gradient.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsGradienth">trunk/Source/WebCore/platform/graphics/Gradient.h</a></li>
<li><a href="#trunkSourceWebCorerenderingsvgRenderSVGResourceGradientcpp">trunk/Source/WebCore/rendering/svg/RenderSVGResourceGradient.cpp</a></li>
<li><a href="#trunkSourceWebCorerenderingsvgRenderSVGResourceGradienth">trunk/Source/WebCore/rendering/svg/RenderSVGResourceGradient.h</a></li>
<li><a href="#trunkSourceWebCorerenderingsvgRenderSVGResourceLinearGradientcpp">trunk/Source/WebCore/rendering/svg/RenderSVGResourceLinearGradient.cpp</a></li>
<li><a href="#trunkSourceWebCorerenderingsvgRenderSVGResourceRadialGradientcpp">trunk/Source/WebCore/rendering/svg/RenderSVGResourceRadialGradient.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (287323 => 287324)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog   2021-12-21 18:34:35 UTC (rev 287323)
+++ trunk/Source/WebCore/ChangeLog      2021-12-21 19:15:59 UTC (rev 287324)
</span><span class="lines">@@ -1,3 +1,37 @@
</span><ins>+2021-12-21  Sam Weinig  <weinig@apple.com>
+
+        Gradient encode/decode does not validate that the serialized stops were sorted
+        https://bugs.webkit.org/show_bug.cgi?id=234558
+
+        Reviewed by Simon Fraser.
+
+        Stop encoding and decoding the stopsSorted bit on Gradient for serialization as
+        we still need to validate the stops are sorted on deserialization.
+
+        While here, optimize things a bit by allowing one to pass all the necessary
+        parameters to the Gradient create function, which allows us to avoid unnecessary
+        extra invalidation. Now that the GradientSpreadMethod can be set on construction
+        there is no need for its setter.
+
+        * platform/graphics/Gradient.cpp:
+        (WebCore::Gradient::create):
+        (WebCore::Gradient::Gradient):
+        (WebCore::Gradient::sortStops const):
+        (WebCore::Gradient::setSpreadMethod): Deleted.
+        * platform/graphics/Gradient.h:
+        (WebCore::Gradient::create):
+        (WebCore::Gradient::stops const):
+        (WebCore::Gradient::encode const):
+        (WebCore::Gradient::decode):
+        * rendering/svg/RenderSVGResourceGradient.cpp:
+        (WebCore::RenderSVGResourceGradient::stopsByApplyingColorFilter):
+        (WebCore::RenderSVGResourceGradient::addStops): Deleted.
+        * rendering/svg/RenderSVGResourceGradient.h:
+        * rendering/svg/RenderSVGResourceLinearGradient.cpp:
+        (WebCore::RenderSVGResourceLinearGradient::buildGradient const):
+        * rendering/svg/RenderSVGResourceRadialGradient.cpp:
+        (WebCore::RenderSVGResourceRadialGradient::buildGradient const):
+
</ins><span class="cx"> 2021-12-21  Wenson Hsieh  <wenson_hsieh@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Add support for a UI delegate method to decide how to handle detected modal containers
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsGradientcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/Gradient.cpp (287323 => 287324)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/Gradient.cpp      2021-12-21 18:34:35 UTC (rev 287323)
+++ trunk/Source/WebCore/platform/graphics/Gradient.cpp 2021-12-21 19:15:59 UTC (rev 287324)
</span><span class="lines">@@ -27,7 +27,6 @@
</span><span class="cx"> #include "config.h"
</span><span class="cx"> #include "Gradient.h"
</span><span class="cx"> 
</span><del>-#include "Color.h"
</del><span class="cx"> #include "FloatRect.h"
</span><span class="cx"> #include <wtf/HashFunctions.h>
</span><span class="cx"> #include <wtf/Hasher.h>
</span><span class="lines">@@ -34,14 +33,16 @@
</span><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><del>-Ref<Gradient> Gradient::create(Data&& data, ColorInterpolationMethod colorInterpolationMethod)
</del><ins>+Ref<Gradient> Gradient::create(Data&& data, ColorInterpolationMethod colorInterpolationMethod, GradientSpreadMethod spreadMethod, ColorStopVector&& stops)
</ins><span class="cx"> {
</span><del>-    return adoptRef(*new Gradient(WTFMove(data), colorInterpolationMethod));
</del><ins>+    return adoptRef(*new Gradient(WTFMove(data), colorInterpolationMethod, spreadMethod, WTFMove(stops)));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-Gradient::Gradient(Data&& data, ColorInterpolationMethod colorInterpolationMethod)
</del><ins>+Gradient::Gradient(Data&& data, ColorInterpolationMethod colorInterpolationMethod, GradientSpreadMethod spreadMethod, ColorStopVector&& stops)
</ins><span class="cx">     : m_data { WTFMove(data) }
</span><span class="cx">     , m_colorInterpolationMethod { colorInterpolationMethod }
</span><ins>+    , m_spreadMethod { spreadMethod }
+    , m_stops { WTFMove(stops) }
</ins><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -116,14 +117,6 @@
</span><span class="cx">     });
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void Gradient::setSpreadMethod(GradientSpreadMethod spreadMethod)
-{
-    if (m_spreadMethod == spreadMethod)
-        return;
-    m_spreadMethod = spreadMethod;
-    m_cachedHash = 0;
-}
-
</del><span class="cx"> // FIXME: Instead of these add(Hasher) functions, consider using encode functions to compute the hash.
</span><span class="cx"> 
</span><span class="cx"> static void add(Hasher& hasher, const FloatPoint& point)
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsGradienth"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/Gradient.h (287323 => 287324)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/Gradient.h        2021-12-21 18:34:35 UTC (rev 287323)
+++ trunk/Source/WebCore/platform/graphics/Gradient.h   2021-12-21 19:15:59 UTC (rev 287324)
</span><span class="lines">@@ -96,7 +96,7 @@
</span><span class="cx"> 
</span><span class="cx">     using Data = std::variant<LinearData, RadialData, ConicData>;
</span><span class="cx"> 
</span><del>-    WEBCORE_EXPORT static Ref<Gradient> create(Data&&, ColorInterpolationMethod);
</del><ins>+    WEBCORE_EXPORT static Ref<Gradient> create(Data&&, ColorInterpolationMethod, GradientSpreadMethod = GradientSpreadMethod::Pad, ColorStopVector&& = { });
</ins><span class="cx"> 
</span><span class="cx">     bool isZeroSize() const;
</span><span class="cx"> 
</span><span class="lines">@@ -106,8 +106,6 @@
</span><span class="cx">     WEBCORE_EXPORT void setSortedColorStops(ColorStopVector&&);
</span><span class="cx"> 
</span><span class="cx">     const ColorStopVector& stops() const { return m_stops; }
</span><del>-
-    WEBCORE_EXPORT void setSpreadMethod(GradientSpreadMethod);
</del><span class="cx">     GradientSpreadMethod spreadMethod() const { return m_spreadMethod; }
</span><span class="cx"> 
</span><span class="cx">     void fill(GraphicsContext&, const FloatRect&);
</span><span class="lines">@@ -132,7 +130,7 @@
</span><span class="cx">     template<typename Decoder> static std::optional<Ref<Gradient>> decode(Decoder&);
</span><span class="cx"> 
</span><span class="cx"> private:
</span><del>-    explicit Gradient(Data&&, ColorInterpolationMethod);
</del><ins>+    explicit Gradient(Data&&, ColorInterpolationMethod, GradientSpreadMethod, ColorStopVector&&);
</ins><span class="cx"> 
</span><span class="cx">     void sortStops() const;
</span><span class="cx">     void stopsChanged();
</span><span class="lines">@@ -139,9 +137,9 @@
</span><span class="cx"> 
</span><span class="cx">     Data m_data;
</span><span class="cx">     ColorInterpolationMethod m_colorInterpolationMethod;
</span><ins>+    GradientSpreadMethod m_spreadMethod;
</ins><span class="cx">     mutable ColorStopVector m_stops;
</span><span class="cx">     mutable bool m_stopsSorted { false };
</span><del>-    GradientSpreadMethod m_spreadMethod { GradientSpreadMethod::Pad };
</del><span class="cx">     mutable unsigned m_cachedHash { 0 };
</span><span class="cx"> 
</span><span class="cx"> #if USE(CG)
</span><span class="lines">@@ -238,9 +236,8 @@
</span><span class="cx"> {
</span><span class="cx">     encoder << m_data;
</span><span class="cx">     encoder << m_colorInterpolationMethod;
</span><ins>+    encoder << m_spreadMethod;
</ins><span class="cx">     encoder << m_stops;
</span><del>-    encoder << m_stopsSorted;
-    encoder << m_spreadMethod;
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template<typename Decoder> std::optional<Ref<Gradient>> Gradient::decode(Decoder& decoder)
</span><span class="lines">@@ -255,29 +252,17 @@
</span><span class="cx">     if (!colorInterpolationMethod)
</span><span class="cx">         return std::nullopt;
</span><span class="cx"> 
</span><del>-    auto gradient = Gradient::create(WTFMove(*data), *colorInterpolationMethod);
</del><ins>+    std::optional<GradientSpreadMethod> spreadMethod;
+    decoder >> spreadMethod;
+    if (!spreadMethod)
+        return std::nullopt;
</ins><span class="cx"> 
</span><span class="cx">     std::optional<ColorStopVector> stops;
</span><span class="cx">     decoder >> stops;
</span><span class="cx">     if (!stops)
</span><span class="cx">         return std::nullopt;
</span><del>-    std::optional<bool> stopsSorted;
-    decoder >> stopsSorted;
-    if (!stopsSorted.has_value())
-        return std::nullopt;
-    if (*stopsSorted)
-        gradient->setSortedColorStops(WTFMove(*stops));
-    else {
-        for (auto& stop : *stops)
-            gradient->addColorStop(WTFMove(stop));
-    }
</del><span class="cx"> 
</span><del>-    GradientSpreadMethod spreadMethod;
-    if (!decoder.decode(spreadMethod))
-        return std::nullopt;
-    gradient->setSpreadMethod(spreadMethod);
-
-    return gradient;
</del><ins>+    return Gradient::create(WTFMove(*data), *colorInterpolationMethod, *spreadMethod, WTFMove(*stops));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline void add(Hasher& hasher, const Color& color)
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingsvgRenderSVGResourceGradientcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/svg/RenderSVGResourceGradient.cpp (287323 => 287324)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/svg/RenderSVGResourceGradient.cpp 2021-12-21 18:34:35 UTC (rev 287323)
+++ trunk/Source/WebCore/rendering/svg/RenderSVGResourceGradient.cpp    2021-12-21 19:15:59 UTC (rev 287324)
</span><span class="lines">@@ -225,10 +225,13 @@
</span><span class="cx">     context->restore();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void RenderSVGResourceGradient::addStops(Gradient& gradient, const Gradient::ColorStopVector& stops, const RenderStyle& style)
</del><ins>+Gradient::ColorStopVector RenderSVGResourceGradient::stopsByApplyingColorFilter(const Gradient::ColorStopVector& stops, const RenderStyle& style)
</ins><span class="cx"> {
</span><ins>+    Gradient::ColorStopVector result;
+    result.reserveInitialCapacity(stops.size());
</ins><span class="cx">     for (auto& stop : stops)
</span><del>-        gradient.addColorStop({ stop.offset, style.colorByApplyingColorFilter(stop.color) });
</del><ins>+        result.uncheckedAppend({ stop.offset, style.colorByApplyingColorFilter(stop.color) });
+    return result;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> GradientSpreadMethod RenderSVGResourceGradient::platformSpreadMethodFromSVGType(SVGSpreadMethodType method)
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingsvgRenderSVGResourceGradienth"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/svg/RenderSVGResourceGradient.h (287323 => 287324)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/svg/RenderSVGResourceGradient.h   2021-12-21 18:34:35 UTC (rev 287323)
+++ trunk/Source/WebCore/rendering/svg/RenderSVGResourceGradient.h      2021-12-21 19:15:59 UTC (rev 287324)
</span><span class="lines">@@ -46,7 +46,7 @@
</span><span class="cx"> protected:
</span><span class="cx">     RenderSVGResourceGradient(SVGGradientElement&, RenderStyle&&);
</span><span class="cx"> 
</span><del>-    static void addStops(Gradient&, const Gradient::ColorStopVector&, const RenderStyle&);
</del><ins>+    static Gradient::ColorStopVector stopsByApplyingColorFilter(const Gradient::ColorStopVector&, const RenderStyle&);
</ins><span class="cx">     static GradientSpreadMethod platformSpreadMethodFromSVGType(SVGSpreadMethodType);
</span><span class="cx"> 
</span><span class="cx"> private:
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingsvgRenderSVGResourceLinearGradientcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/svg/RenderSVGResourceLinearGradient.cpp (287323 => 287324)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/svg/RenderSVGResourceLinearGradient.cpp   2021-12-21 18:34:35 UTC (rev 287323)
+++ trunk/Source/WebCore/rendering/svg/RenderSVGResourceLinearGradient.cpp      2021-12-21 19:15:59 UTC (rev 287324)
</span><span class="lines">@@ -53,10 +53,12 @@
</span><span class="cx"> 
</span><span class="cx"> Ref<Gradient> RenderSVGResourceLinearGradient::buildGradient(const RenderStyle& style) const
</span><span class="cx"> {
</span><del>-    auto gradient = Gradient::create(Gradient::LinearData { startPoint(m_attributes), endPoint(m_attributes) }, { ColorInterpolationMethod::SRGB { }, AlphaPremultiplication::Unpremultiplied });
-    gradient->setSpreadMethod(platformSpreadMethodFromSVGType(m_attributes.spreadMethod()));
-    addStops(gradient, m_attributes.stops(), style);
-    return gradient;
</del><ins>+    return Gradient::create(
+        Gradient::LinearData { startPoint(m_attributes), endPoint(m_attributes) },
+        ColorInterpolationMethod { ColorInterpolationMethod::SRGB { }, AlphaPremultiplication::Unpremultiplied },
+        platformSpreadMethodFromSVGType(m_attributes.spreadMethod()),
+        stopsByApplyingColorFilter(m_attributes.stops(), style)
+    );
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingsvgRenderSVGResourceRadialGradientcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/svg/RenderSVGResourceRadialGradient.cpp (287323 => 287324)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/svg/RenderSVGResourceRadialGradient.cpp   2021-12-21 18:34:35 UTC (rev 287323)
+++ trunk/Source/WebCore/rendering/svg/RenderSVGResourceRadialGradient.cpp      2021-12-21 19:15:59 UTC (rev 287324)
</span><span class="lines">@@ -64,10 +64,12 @@
</span><span class="cx"> 
</span><span class="cx"> Ref<Gradient> RenderSVGResourceRadialGradient::buildGradient(const RenderStyle& style) const
</span><span class="cx"> {
</span><del>-    auto gradient = Gradient::create(Gradient::RadialData { focalPoint(m_attributes), centerPoint(m_attributes), focalRadius(m_attributes), radius(m_attributes), 1 }, { ColorInterpolationMethod::SRGB { }, AlphaPremultiplication::Unpremultiplied });
-    gradient->setSpreadMethod(platformSpreadMethodFromSVGType(m_attributes.spreadMethod()));
-    addStops(gradient, m_attributes.stops(), style);
-    return gradient;
</del><ins>+    return Gradient::create(
+        Gradient::RadialData { focalPoint(m_attributes), centerPoint(m_attributes), focalRadius(m_attributes), radius(m_attributes), 1 },
+        ColorInterpolationMethod { ColorInterpolationMethod::SRGB { }, AlphaPremultiplication::Unpremultiplied },
+        platformSpreadMethodFromSVGType(m_attributes.spreadMethod()),
+        stopsByApplyingColorFilter(m_attributes.stops(), style)
+    );
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> }
</span></span></pre>
</div>
</div>

</body>
</html>