From ec48fcb035062c22bf3da61c515c66619c0ecef4 Mon Sep 17 00:00:00 2001 From: Olivier Nizet Date: Sat, 28 Sep 2024 21:42:41 +0200 Subject: [PATCH 01/29] Improve performance by parsing HtmlColor with memory span --- .../Primitives/HtmlColor.Named.cs | 173 ++++++++++++++++++ src/Html2OpenXml/Primitives/HtmlColor.cs | 155 +++++++++------- .../Utilities/HtmlColorTranslator.cs | 168 ----------------- .../Utilities/OpenXmlExtensions.cs | 2 - src/Html2OpenXml/Utilities/Range.cs | 23 +++ src/Html2OpenXml/Utilities/SpanExtensions.cs | 111 +++++++++++ .../Primitives/ColorTests.cs | 21 ++- test/HtmlToOpenXml.Tests/StyleTests.cs | 9 +- 8 files changed, 409 insertions(+), 253 deletions(-) create mode 100755 src/Html2OpenXml/Primitives/HtmlColor.Named.cs delete mode 100755 src/Html2OpenXml/Utilities/HtmlColorTranslator.cs create mode 100644 src/Html2OpenXml/Utilities/Range.cs create mode 100644 src/Html2OpenXml/Utilities/SpanExtensions.cs diff --git a/src/Html2OpenXml/Primitives/HtmlColor.Named.cs b/src/Html2OpenXml/Primitives/HtmlColor.Named.cs new file mode 100755 index 00000000..dff82959 --- /dev/null +++ b/src/Html2OpenXml/Primitives/HtmlColor.Named.cs @@ -0,0 +1,173 @@ +using System; +using System.Collections.Generic; + +namespace HtmlToOpenXml; + +/// +/// Helper class to translate a named color to its ARGB representation. +/// +partial struct HtmlColor +{ + private static readonly Dictionary namedColors = InitKnownColors(); + + private static HtmlColor GetNamedColor (ReadOnlySpan name) + { + // the longest built-in Color's name is much lower than this check, so we should not allocate here in a typical usage + Span loweredValue = name.Length <= 128 ? stackalloc char[name.Length] : new char[name.Length]; + + name.ToLowerInvariant(loweredValue); + + namedColors.TryGetValue(loweredValue.ToString(), out var color); + return color; + } + + private static Dictionary InitKnownColors() + { + var colors = new Dictionary() + { + { "black", Black }, + { "white", FromArgb(255,255,255) }, + { "aliceblue", FromArgb(240, 248, 255) }, + { "lightsalmon", FromArgb(255, 160, 122) }, + { "antiquewhite", FromArgb(250, 235, 215) }, + { "lightseagreen", FromArgb(32, 178, 170) }, + { "aqua", FromArgb(0, 255, 255) }, + { "lightskyblue", FromArgb(135, 206, 250) }, + { "aquamarine", FromArgb(127, 255, 212) }, + { "lightslategray", FromArgb(119, 136, 153) }, + { "azure", FromArgb(240, 255, 255) }, + { "lightsteelblue", FromArgb(176, 196, 222) }, + { "beige", FromArgb(245, 245, 220) }, + { "lightyellow", FromArgb(255, 255, 224) }, + { "bisque", FromArgb(255, 228, 196) }, + { "lime", FromArgb(0, 255, 0) }, + { "limegreen", FromArgb(50, 205, 50) }, + { "blanchedalmond", FromArgb(255, 255, 205) }, + { "linen", FromArgb(250, 240, 230) }, + { "blue", FromArgb(0, 0, 255) }, + { "magenta", FromArgb(255, 0, 255) }, + { "blueviolet", FromArgb(138, 43, 226) }, + { "maroon", FromArgb(128, 0, 0) }, + { "brown", FromArgb(165, 42, 42) }, + { "mediumaquamarine", FromArgb(102, 205, 170) }, + { "burlywood", FromArgb(222, 184, 135) }, + { "mediumblue", FromArgb(0, 0, 205) }, + { "cadetblue", FromArgb(95, 158, 160) }, + { "mediumprchid", FromArgb(186, 85, 211) }, + { "chartreuse", FromArgb(127, 255, 0) }, + { "mediumpurple", FromArgb(147, 112, 219) }, + { "chocolate", FromArgb(210, 105, 30) }, + { "mediumseagreen", FromArgb(60, 179, 113) }, + { "coral", FromArgb(255, 127, 80) }, + { "mediumslateblue", FromArgb(123, 104, 238) }, + { "cornflowerblue", FromArgb(100, 149, 237) }, + { "mediumspringbreen", FromArgb(0, 250, 154) }, + { "cornsilk", FromArgb(255, 248, 220) }, + { "mediumturquoise", FromArgb(72, 209, 204) }, + { "crimson", FromArgb(220, 20, 60) }, + { "mediumvioletred", FromArgb(199, 21, 112) }, + { "cyan", FromArgb(0, 255, 255) }, + { "midnightblue", FromArgb(25, 25, 112) }, + { "darkblue", FromArgb(0, 0, 139) }, + { "mintcream", FromArgb(245, 255, 250) }, + { "darkcyan", FromArgb(0, 139, 139) }, + { "mistyrose", FromArgb(255, 228, 225) }, + { "darkgoldenrod", FromArgb(184, 134, 11) }, + { "moccasin", FromArgb(255, 228, 181) }, + { "darkgray", FromArgb(169, 169, 169) }, + { "navajowhite", FromArgb(255, 222, 173) }, + { "darkgreen", FromArgb(0, 100, 0) }, + { "navy", FromArgb(0, 0, 128) }, + { "darkkhaki", FromArgb(189, 183, 107) }, + { "oldlace", FromArgb(253, 245, 230) }, + { "darkmagenta", FromArgb(139, 0, 139) }, + { "olive", FromArgb(128, 128, 0) }, + { "darkolivegreen", FromArgb(85, 107, 47) }, + { "olivedrab", FromArgb(107, 142, 45) }, + { "darkorange", FromArgb(255, 140, 0) }, + { "orange", FromArgb(255, 165, 0) }, + { "darkorchid", FromArgb(153, 50, 204) }, + { "orangered", FromArgb(255, 69, 0) }, + { "darkred", FromArgb(139, 0, 0) }, + { "orchid", FromArgb(218, 112, 214) }, + { "darksalmon", FromArgb(233, 150, 122) }, + { "palegoldenrod", FromArgb(238, 232, 170) }, + { "darkseagreen", FromArgb(143, 188, 143) }, + { "palegreen", FromArgb(152, 251, 152) }, + { "darkslateblue", FromArgb(72, 61, 139) }, + { "paleturquoise", FromArgb(175, 238, 238) }, + { "darkslategray", FromArgb(40, 79, 79) }, + { "palevioletred", FromArgb(219, 112, 147) }, + { "darkturquoise", FromArgb(0, 206, 209) }, + { "papayawhip", FromArgb(255, 239, 213) }, + { "darkviolet", FromArgb(148, 0, 211) }, + { "peachpuff", FromArgb(255, 218, 155) }, + { "deeppink", FromArgb(255, 20, 147) }, + { "peru", FromArgb(205, 133, 63) }, + { "deepskyblue", FromArgb(0, 191, 255) }, + { "pink", FromArgb(255, 192, 203) }, + { "dimgray", FromArgb(105, 105, 105) }, + { "plum", FromArgb(221, 160, 221) }, + { "dodgerblue", FromArgb(30, 144, 255) }, + { "powderblue", FromArgb(176, 224, 230) }, + { "firebrick", FromArgb(178, 34, 34) }, + { "purple", FromArgb(128, 0, 128) }, + { "floralwhite", FromArgb(255, 250, 240) }, + { "red", FromArgb(255, 0, 0) }, + { "forestgreen", FromArgb(34, 139, 34) }, + { "rosybrown", FromArgb(188, 143, 143) }, + { "fuschia", FromArgb(255, 0, 255) }, + { "royalblue", FromArgb(65, 105, 225) }, + { "gainsboro", FromArgb(220, 220, 220) }, + { "saddlebrown", FromArgb(139, 69, 19) }, + { "ghostwhite", FromArgb(248, 248, 255) }, + { "salmon", FromArgb(250, 128, 114) }, + { "gold", FromArgb(255, 215, 0) }, + { "sandybrown", FromArgb(244, 164, 96) }, + { "goldenrod", FromArgb(218, 165, 32) }, + { "seagreen", FromArgb(46, 139, 87) }, + { "gray", FromArgb(128, 128, 128) }, + { "seashell", FromArgb(255, 245, 238) }, + { "green", FromArgb(0, 128, 0) }, + { "sienna", FromArgb(160, 82, 45) }, + { "greenyellow", FromArgb(173, 255, 47) }, + { "silver", FromArgb(192, 192, 192) }, + { "honeydew", FromArgb(240, 255, 240) }, + { "skyblue", FromArgb(135, 206, 235) }, + { "hotpink", FromArgb(255, 105, 180) }, + { "slateblue", FromArgb(106, 90, 205) }, + { "indianred", FromArgb(205, 92, 92) }, + { "slategray", FromArgb(112, 128, 144) }, + { "indigo", FromArgb(75, 0, 130) }, + { "snow", FromArgb(255, 250, 250) }, + { "ivory", FromArgb(255, 240, 240) }, + { "springgreen", FromArgb(0, 255, 127) }, + { "khaki", FromArgb(240, 230, 140) }, + { "steelblue", FromArgb(70, 130, 180) }, + { "lavender", FromArgb(230, 230, 250) }, + { "tan", FromArgb(210, 180, 140) }, + { "lavenderblush", FromArgb(255, 240, 245) }, + { "teal", FromArgb(0, 128, 128) }, + { "lawngreen", FromArgb(124, 252, 0) }, + { "thistle", FromArgb(216, 191, 216) }, + { "lemonchiffon", FromArgb(255, 250, 205) }, + { "tomato", FromArgb(253, 99, 71) }, + { "lightblue", FromArgb(173, 216, 230) }, + { "turquoise", FromArgb(64, 224, 208) }, + { "lightcoral", FromArgb(240, 128, 128) }, + { "violet", FromArgb(238, 130, 238) }, + { "lightcyan", FromArgb(224, 255, 255) }, + { "wheat", FromArgb(245, 222, 179) }, + { "lightgoldenrodyellow", FromArgb(250, 250, 210) }, + { "lightgreen", FromArgb(144, 238, 144) }, + { "whitesmoke", FromArgb(245, 245, 245) }, + { "lightgray", FromArgb(211, 211, 211) }, + { "yellow", FromArgb(255, 255, 0) }, + { "Lightpink", FromArgb(255, 182, 193) }, + { "yellowgreen", FromArgb(154, 205, 50) }, + { "transparent", FromArgb(0, 0, 0, 0) } + }; + + return colors; + } +} \ No newline at end of file diff --git a/src/Html2OpenXml/Primitives/HtmlColor.cs b/src/Html2OpenXml/Primitives/HtmlColor.cs index 799063a6..213ef362 100755 --- a/src/Html2OpenXml/Primitives/HtmlColor.cs +++ b/src/Html2OpenXml/Primitives/HtmlColor.cs @@ -17,7 +17,7 @@ namespace HtmlToOpenXml; /// /// Represents an ARGB color. /// -readonly struct HtmlColor : IEquatable +readonly partial struct HtmlColor : IEquatable { private static readonly char[] hexDigits = { '0', '1', '2', '3', '4', '5', '6', '7', @@ -44,93 +44,110 @@ public HtmlColor(double alpha, byte red, byte green, byte blue) : this() /// /// Try to parse a value (RGB(A) or HSL(A), hexadecimal, or named color) to its RGB representation. /// - /// The color to parse. + /// The color to parse. /// Returns if parsing failed. - public static HtmlColor Parse(string? htmlColor) + public static HtmlColor Parse(ReadOnlySpan span) { - if (string.IsNullOrEmpty(htmlColor)) - return HtmlColor.Empty; - - // Bug fixed by jairoXXX to support rgb(r,g,b) format - // RGB or RGBA - try + // Is it in hexa? Note: we no more accept hexa value without preceding the '#' + if (span[0] == '#') { - if (htmlColor!.StartsWith("rgb", StringComparison.OrdinalIgnoreCase)) - { - int startIndex = htmlColor.IndexOf('(', 3), endIndex = htmlColor.LastIndexOf(')'); - if (startIndex >= 3 && endIndex > -1) - { - var colorStringArray = htmlColor.Substring(startIndex + 1, endIndex - startIndex - 1).Split(','); - if (colorStringArray.Length < 3) return HtmlColor.Empty; - - return FromArgb( - colorStringArray.Length == 3 ? 1.0: double.Parse(colorStringArray[3], CultureInfo.InvariantCulture), - Byte.Parse(colorStringArray[0], NumberStyles.Integer, CultureInfo.InvariantCulture), - Byte.Parse(colorStringArray[1], NumberStyles.Integer, CultureInfo.InvariantCulture), - Byte.Parse(colorStringArray[2], NumberStyles.Integer, CultureInfo.InvariantCulture) - ); - } - } - - // HSL or HSLA - if (htmlColor.StartsWith("hsl", StringComparison.OrdinalIgnoreCase)) + if (span.Length == 7) { - int startIndex = htmlColor.IndexOf('(', 3), endIndex = htmlColor.LastIndexOf(')'); - if (startIndex >= 3 && endIndex > -1) - { - var colorStringArray = htmlColor.Substring(startIndex + 1, endIndex - startIndex - 1).Split(','); - if (colorStringArray.Length < 3) return HtmlColor.Empty; - - return FromHsl( - colorStringArray.Length == 3 ? 1d: double.Parse(colorStringArray[3], CultureInfo.InvariantCulture), - double.Parse(colorStringArray[0], CultureInfo.InvariantCulture), - ParsePercent(colorStringArray[1]), - ParsePercent(colorStringArray[2]) - ); - } + return FromArgb( + span.Slice(1, 2).AsByte(NumberStyles.HexNumber), + span.Slice(3, 2).AsByte(NumberStyles.HexNumber), + span.Slice(5, 2).AsByte(NumberStyles.HexNumber)); } - - // Is it in hexa? Note: we no more accept hexa value without preceding the '#' - if (htmlColor[0] == '#' && (htmlColor.Length == 7 || htmlColor.Length == 4)) + if (span.Length == 4) { - if (htmlColor.Length == 7) - { - return FromArgb( - Convert.ToByte(htmlColor.Substring(1, 2), 16), - Convert.ToByte(htmlColor.Substring(3, 2), 16), - Convert.ToByte(htmlColor.Substring(5, 2), 16)); - } - // #0FF --> #00FFFF + ReadOnlySpan r = [span[1], span[1]]; + ReadOnlySpan g = [span[2], span[2]]; + ReadOnlySpan b = [span[3], span[3]]; return FromArgb( - Convert.ToByte(new string(htmlColor[1], 2), 16), - Convert.ToByte(new string(htmlColor[2], 2), 16), - Convert.ToByte(new string(htmlColor[3], 2), 16)); + r.AsByte(NumberStyles.HexNumber), + g.AsByte(NumberStyles.HexNumber), + b.AsByte(NumberStyles.HexNumber)); } + return Empty; } - catch (Exception exc) + + // RGB or RGBA + if (span.StartsWith(['r','g','b'], StringComparison.OrdinalIgnoreCase)) { - if (exc is FormatException || exc is OverflowException || exc is ArgumentOutOfRangeException) - return HtmlColor.Empty; - throw; + int startIndex = span.IndexOf('('), endIndex = span.LastIndexOf(')'); + if (startIndex < 3 || endIndex == -1) + return Empty; + + span = span.Slice(startIndex + 1, endIndex - startIndex - 1); + Span tokens = stackalloc Range[5]; + var sep = span.IndexOf(',') > -1? ',' : ' '; + return span.Split(tokens, sep) switch + { + 3 => FromArgb(1.0, + span.Slice(tokens[0]).AsByte(NumberStyles.Integer), + span.Slice(tokens[1]).AsByte(NumberStyles.Integer), + span.Slice(tokens[2]).AsByte(NumberStyles.Integer)), + 4 => FromArgb(span.Slice(tokens[3]).AsDouble(), + span.Slice(tokens[0]).AsByte(NumberStyles.Integer), + span.Slice(tokens[1]).AsByte(NumberStyles.Integer), + span.Slice(tokens[2]).AsByte(NumberStyles.Integer)), + // r g b / a + 5 => FromArgb(span.Slice(tokens[4]).AsDouble(), + span.Slice(tokens[0]).AsByte(NumberStyles.Integer), + span.Slice(tokens[1]).AsByte(NumberStyles.Integer), + span.Slice(tokens[2]).AsByte(NumberStyles.Integer)), + _ => Empty + }; } - return HtmlColorTranslator.FromHtml(htmlColor); + // HSL or HSLA + if (span.StartsWith(['h','s','l'], StringComparison.OrdinalIgnoreCase)) + { + int startIndex = span.IndexOf('('), endIndex = span.LastIndexOf(')'); + if (startIndex < 3 || endIndex == -1) + return Empty; + + span = span.Slice(startIndex + 1, endIndex - startIndex - 1); + Span tokens = stackalloc Range[5]; + var sep = span.IndexOf(',') > -1? ',' : ' '; + return span.Split(tokens, sep) switch + { + 3 => FromHsl(1.0, + span.Slice(tokens[0]).AsDouble(), + span.Slice(tokens[1]).AsPercent(), + span.Slice(tokens[2]).AsPercent()), + 4 => FromHsl(span.Slice(tokens[3]).AsDouble(), + span.Slice(tokens[0]).AsDouble(), + span.Slice(tokens[1]).AsPercent(), + span.Slice(tokens[2]).AsPercent()), + _ => Empty + }; + } + + return GetNamedColor(span); } /// - /// Convert a potential percentage value to its numeric representation. - /// Saturation and Lightness can contains both a percentage value or a value comprised between 0.0 and 1.0. + /// Try to parse a value (RGB(A) or HSL(A), hexadecimal, or named color) to its RGB representation. /// - private static double ParsePercent (string value) + /// The color to parse. + /// Returns if parsing failed. + public static HtmlColor Parse(string? htmlColor) { - double parsedValue; - if (value.IndexOf('%') > -1) - parsedValue = double.Parse(value.Replace('%', ' '), CultureInfo.InvariantCulture) / 100d; - else - parsedValue = double.Parse(value, CultureInfo.InvariantCulture); + if (string.IsNullOrEmpty(htmlColor)) + return Empty; - return Math.Min(1, Math.Max(0, parsedValue)); + try + { + return Parse(htmlColor.AsSpan()); + } + catch (Exception exc) + { + if (exc is FormatException || exc is OverflowException || exc is ArgumentOutOfRangeException) + return Empty; + throw; + } } /// diff --git a/src/Html2OpenXml/Utilities/HtmlColorTranslator.cs b/src/Html2OpenXml/Utilities/HtmlColorTranslator.cs deleted file mode 100755 index ff59cb92..00000000 --- a/src/Html2OpenXml/Utilities/HtmlColorTranslator.cs +++ /dev/null @@ -1,168 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace HtmlToOpenXml; - -/// -/// Helper class to translate a named color to its ARGB representation. -/// -static class HtmlColorTranslator -{ - private static readonly Dictionary namedColors = InitKnownColors(); - - public static HtmlColor FromHtml (string htmlColor) - { - namedColors.TryGetValue(htmlColor, out var color); - return color; - } - - private static Dictionary InitKnownColors() - { - var colors = new Dictionary(StringComparer.OrdinalIgnoreCase) - { - { "Black", HtmlColor.Black }, - { "White", HtmlColor.FromArgb(255,255,255) }, - { "AliceBlue", HtmlColor.FromArgb(240, 248, 255) }, - { "LightSalmon", HtmlColor.FromArgb(255, 160, 122) }, - { "AntiqueWhite", HtmlColor.FromArgb(250, 235, 215) }, - { "LightSeaGreen", HtmlColor.FromArgb(32, 178, 170) }, - { "Aqua", HtmlColor.FromArgb(0, 255, 255) }, - { "LightSkyBlue", HtmlColor.FromArgb(135, 206, 250) }, - { "Aquamarine", HtmlColor.FromArgb(127, 255, 212) }, - { "LightSlateGray", HtmlColor.FromArgb(119, 136, 153) }, - { "Azure", HtmlColor.FromArgb(240, 255, 255) }, - { "LightSteelBlue", HtmlColor.FromArgb(176, 196, 222) }, - { "Beige", HtmlColor.FromArgb(245, 245, 220) }, - { "LightYellow", HtmlColor.FromArgb(255, 255, 224) }, - { "Bisque", HtmlColor.FromArgb(255, 228, 196) }, - { "Lime", HtmlColor.FromArgb(0, 255, 0) }, - { "LimeGreen", HtmlColor.FromArgb(50, 205, 50) }, - { "BlanchedAlmond", HtmlColor.FromArgb(255, 255, 205) }, - { "Linen", HtmlColor.FromArgb(250, 240, 230) }, - { "Blue", HtmlColor.FromArgb(0, 0, 255) }, - { "Magenta", HtmlColor.FromArgb(255, 0, 255) }, - { "BlueViolet", HtmlColor.FromArgb(138, 43, 226) }, - { "Maroon", HtmlColor.FromArgb(128, 0, 0) }, - { "Brown", HtmlColor.FromArgb(165, 42, 42) }, - { "MediumAquamarine", HtmlColor.FromArgb(102, 205, 170) }, - { "BurlyWood", HtmlColor.FromArgb(222, 184, 135) }, - { "MediumBlue", HtmlColor.FromArgb(0, 0, 205) }, - { "CadetBlue", HtmlColor.FromArgb(95, 158, 160) }, - { "MediumOrchid", HtmlColor.FromArgb(186, 85, 211) }, - { "Chartreuse", HtmlColor.FromArgb(127, 255, 0) }, - { "MediumPurple", HtmlColor.FromArgb(147, 112, 219) }, - { "Chocolate", HtmlColor.FromArgb(210, 105, 30) }, - { "MediumSeaGreen", HtmlColor.FromArgb(60, 179, 113) }, - { "Coral", HtmlColor.FromArgb(255, 127, 80) }, - { "MediumSlateBlue", HtmlColor.FromArgb(123, 104, 238) }, - { "CornflowerBlue", HtmlColor.FromArgb(100, 149, 237) }, - { "MediumSpringGreen", HtmlColor.FromArgb(0, 250, 154) }, - { "Cornsilk", HtmlColor.FromArgb(255, 248, 220) }, - { "MediumTurquoise", HtmlColor.FromArgb(72, 209, 204) }, - { "Crimson", HtmlColor.FromArgb(220, 20, 60) }, - { "MediumVioletRed", HtmlColor.FromArgb(199, 21, 112) }, - { "Cyan", HtmlColor.FromArgb(0, 255, 255) }, - { "MidnightBlue", HtmlColor.FromArgb(25, 25, 112) }, - { "DarkBlue", HtmlColor.FromArgb(0, 0, 139) }, - { "MintCream", HtmlColor.FromArgb(245, 255, 250) }, - { "DarkCyan", HtmlColor.FromArgb(0, 139, 139) }, - { "MistyRose", HtmlColor.FromArgb(255, 228, 225) }, - { "DarkGoldenrod", HtmlColor.FromArgb(184, 134, 11) }, - { "Moccasin", HtmlColor.FromArgb(255, 228, 181) }, - { "DarkGray", HtmlColor.FromArgb(169, 169, 169) }, - { "NavajoWhite", HtmlColor.FromArgb(255, 222, 173) }, - { "DarkGreen", HtmlColor.FromArgb(0, 100, 0) }, - { "Navy", HtmlColor.FromArgb(0, 0, 128) }, - { "DarkKhaki", HtmlColor.FromArgb(189, 183, 107) }, - { "OldLace", HtmlColor.FromArgb(253, 245, 230) }, - { "DarkMagenta", HtmlColor.FromArgb(139, 0, 139) }, - { "Olive", HtmlColor.FromArgb(128, 128, 0) }, - { "DarkOliveGreen", HtmlColor.FromArgb(85, 107, 47) }, - { "OliveDrab", HtmlColor.FromArgb(107, 142, 45) }, - { "DarkOrange", HtmlColor.FromArgb(255, 140, 0) }, - { "Orange", HtmlColor.FromArgb(255, 165, 0) }, - { "DarkOrchid", HtmlColor.FromArgb(153, 50, 204) }, - { "OrangeRed", HtmlColor.FromArgb(255, 69, 0) }, - { "DarkRed", HtmlColor.FromArgb(139, 0, 0) }, - { "Orchid", HtmlColor.FromArgb(218, 112, 214) }, - { "DarkSalmon", HtmlColor.FromArgb(233, 150, 122) }, - { "PaleGoldenrod", HtmlColor.FromArgb(238, 232, 170) }, - { "DarkSeaGreen", HtmlColor.FromArgb(143, 188, 143) }, - { "PaleGreen", HtmlColor.FromArgb(152, 251, 152) }, - { "DarkSlateBlue", HtmlColor.FromArgb(72, 61, 139) }, - { "PaleTurquoise", HtmlColor.FromArgb(175, 238, 238) }, - { "DarkSlateGray", HtmlColor.FromArgb(40, 79, 79) }, - { "PaleVioletRed", HtmlColor.FromArgb(219, 112, 147) }, - { "DarkTurquoise", HtmlColor.FromArgb(0, 206, 209) }, - { "PapayaWhip", HtmlColor.FromArgb(255, 239, 213) }, - { "DarkViolet", HtmlColor.FromArgb(148, 0, 211) }, - { "PeachPuff", HtmlColor.FromArgb(255, 218, 155) }, - { "DeepPink", HtmlColor.FromArgb(255, 20, 147) }, - { "Peru", HtmlColor.FromArgb(205, 133, 63) }, - { "DeepSkyBlue", HtmlColor.FromArgb(0, 191, 255) }, - { "Pink", HtmlColor.FromArgb(255, 192, 203) }, - { "DimGray", HtmlColor.FromArgb(105, 105, 105) }, - { "Plum", HtmlColor.FromArgb(221, 160, 221) }, - { "DodgerBlue", HtmlColor.FromArgb(30, 144, 255) }, - { "PowderBlue", HtmlColor.FromArgb(176, 224, 230) }, - { "Firebrick", HtmlColor.FromArgb(178, 34, 34) }, - { "Purple", HtmlColor.FromArgb(128, 0, 128) }, - { "FloralWhite", HtmlColor.FromArgb(255, 250, 240) }, - { "Red", HtmlColor.FromArgb(255, 0, 0) }, - { "ForestGreen", HtmlColor.FromArgb(34, 139, 34) }, - { "RosyBrown", HtmlColor.FromArgb(188, 143, 143) }, - { "Fuschia", HtmlColor.FromArgb(255, 0, 255) }, - { "RoyalBlue", HtmlColor.FromArgb(65, 105, 225) }, - { "Gainsboro", HtmlColor.FromArgb(220, 220, 220) }, - { "SaddleBrown", HtmlColor.FromArgb(139, 69, 19) }, - { "GhostWhite", HtmlColor.FromArgb(248, 248, 255) }, - { "Salmon", HtmlColor.FromArgb(250, 128, 114) }, - { "Gold", HtmlColor.FromArgb(255, 215, 0) }, - { "SandyBrown", HtmlColor.FromArgb(244, 164, 96) }, - { "Goldenrod", HtmlColor.FromArgb(218, 165, 32) }, - { "SeaGreen", HtmlColor.FromArgb(46, 139, 87) }, - { "Gray", HtmlColor.FromArgb(128, 128, 128) }, - { "Seashell", HtmlColor.FromArgb(255, 245, 238) }, - { "Green", HtmlColor.FromArgb(0, 128, 0) }, - { "Sienna", HtmlColor.FromArgb(160, 82, 45) }, - { "GreenYellow", HtmlColor.FromArgb(173, 255, 47) }, - { "Silver", HtmlColor.FromArgb(192, 192, 192) }, - { "Honeydew", HtmlColor.FromArgb(240, 255, 240) }, - { "SkyBlue", HtmlColor.FromArgb(135, 206, 235) }, - { "HotPink", HtmlColor.FromArgb(255, 105, 180) }, - { "SlateBlue", HtmlColor.FromArgb(106, 90, 205) }, - { "IndianRed", HtmlColor.FromArgb(205, 92, 92) }, - { "SlateGray", HtmlColor.FromArgb(112, 128, 144) }, - { "Indigo", HtmlColor.FromArgb(75, 0, 130) }, - { "Snow", HtmlColor.FromArgb(255, 250, 250) }, - { "Ivory", HtmlColor.FromArgb(255, 240, 240) }, - { "SpringGreen", HtmlColor.FromArgb(0, 255, 127) }, - { "Khaki", HtmlColor.FromArgb(240, 230, 140) }, - { "SteelBlue", HtmlColor.FromArgb(70, 130, 180) }, - { "Lavender", HtmlColor.FromArgb(230, 230, 250) }, - { "Tan", HtmlColor.FromArgb(210, 180, 140) }, - { "LavenderBlush", HtmlColor.FromArgb(255, 240, 245) }, - { "Teal", HtmlColor.FromArgb(0, 128, 128) }, - { "LawnGreen", HtmlColor.FromArgb(124, 252, 0) }, - { "Thistle", HtmlColor.FromArgb(216, 191, 216) }, - { "LemonChiffon", HtmlColor.FromArgb(255, 250, 205) }, - { "Tomato", HtmlColor.FromArgb(253, 99, 71) }, - { "LightBlue", HtmlColor.FromArgb(173, 216, 230) }, - { "Turquoise", HtmlColor.FromArgb(64, 224, 208) }, - { "LightCoral", HtmlColor.FromArgb(240, 128, 128) }, - { "Violet", HtmlColor.FromArgb(238, 130, 238) }, - { "LightCyan", HtmlColor.FromArgb(224, 255, 255) }, - { "Wheat", HtmlColor.FromArgb(245, 222, 179) }, - { "LightGoldenrodYellow", HtmlColor.FromArgb(250, 250, 210) }, - { "LightGreen", HtmlColor.FromArgb(144, 238, 144) }, - { "WhiteSmoke", HtmlColor.FromArgb(245, 245, 245) }, - { "LightGray", HtmlColor.FromArgb(211, 211, 211) }, - { "Yellow", HtmlColor.FromArgb(255, 255, 0) }, - { "LightPink", HtmlColor.FromArgb(255, 182, 193) }, - { "YellowGreen", HtmlColor.FromArgb(154, 205, 50) }, - { "Transparent", HtmlColor.FromArgb(0, 0, 0, 0) } - }; - - return colors; - } -} \ No newline at end of file diff --git a/src/Html2OpenXml/Utilities/OpenXmlExtensions.cs b/src/Html2OpenXml/Utilities/OpenXmlExtensions.cs index 5242f49e..905ba21e 100755 --- a/src/Html2OpenXml/Utilities/OpenXmlExtensions.cs +++ b/src/Html2OpenXml/Utilities/OpenXmlExtensions.cs @@ -9,11 +9,9 @@ * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A * PARTICULAR PURPOSE. */ -using System; using System.Runtime.CompilerServices; using DocumentFormat.OpenXml; using DocumentFormat.OpenXml.Wordprocessing; -using DocumentFormat.OpenXml.Drawing.Wordprocessing; namespace HtmlToOpenXml; diff --git a/src/Html2OpenXml/Utilities/Range.cs b/src/Html2OpenXml/Utilities/Range.cs new file mode 100644 index 00000000..e0d8eea9 --- /dev/null +++ b/src/Html2OpenXml/Utilities/Range.cs @@ -0,0 +1,23 @@ +/* Copyright (C) Olivier Nizet https://github.com/onizet/html2openxml - All Rights Reserved + * + * This source is subject to the Microsoft Permissive License. + * Please see the License.txt file for more information. + * All other rights reserved. + * + * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A + * PARTICULAR PURPOSE. + */ +namespace System; + +#if !NET5_0_OR_GREATER +readonly struct Range(int start, int end) +{ + /// Represent the inclusive start index of the Range. + public int Start { get; } = start; + + /// Represent the exclusive end index of the Range. + public int End { get; } = end; +} +#endif \ No newline at end of file diff --git a/src/Html2OpenXml/Utilities/SpanExtensions.cs b/src/Html2OpenXml/Utilities/SpanExtensions.cs new file mode 100644 index 00000000..a4bfc6c6 --- /dev/null +++ b/src/Html2OpenXml/Utilities/SpanExtensions.cs @@ -0,0 +1,111 @@ +/* Copyright (C) Olivier Nizet https://github.com/onizet/html2openxml - All Rights Reserved + * + * This source is subject to the Microsoft Permissive License. + * Please see the License.txt file for more information. + * All other rights reserved. + * + * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A + * PARTICULAR PURPOSE. + */ +using System; +using System.Globalization; +using System.Runtime.CompilerServices; + +namespace HtmlToOpenXml; + +/// +/// Polyfill helper class to provide extension methods for . +/// +static class SpanExtensions +{ + /// + /// Shim method to convert to . + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte AsByte(this ReadOnlySpan span, NumberStyles style) + { +#if NET5_0_OR_GREATER + return byte.Parse(span, style); +#else + return byte.Parse(span.ToString(), style); +#endif + } + + /// + /// Shim method to convert to . + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static double AsDouble(this ReadOnlySpan span) + { +#if NET5_0_OR_GREATER + return double.Parse(span, CultureInfo.InvariantCulture); +#else + return double.Parse(span.ToString(), CultureInfo.InvariantCulture); +#endif + } + + /// + /// Convert a potential percentage value to its numeric representation. + /// Saturation and Lightness can contains both a percentage value or a value comprised between 0.0 and 1.0. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static double AsPercent (this ReadOnlySpan span) + { + int index = span.IndexOf('%'); + if (index > -1) + { + double parsedValue = span.Slice(0, index).AsDouble() / 100d; + return Math.Min(1, Math.Max(0, parsedValue)); + } + + return span.AsDouble(); + } + + /// + /// Shim method to remain compliant with pre-NET 8 framework. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ReadOnlySpan Slice(this ReadOnlySpan span, Range range) + { +#if NET5_0_OR_GREATER + return span[range]; +#else + return span.Slice(range.Start, range.End); +#endif + } + +#if !NET5_0_OR_GREATER + /// + /// Parses the source for the specified , + /// populating the span with instances + /// representing the regions between the separators. + /// + /// The source span to parse. + /// The destination span into which the resulting ranges are written. + /// A character that delimits the regions in this instance. + /// The number of ranges written into . + public static int Split(this ReadOnlySpan span, Span destination, char separator) + { + int matches = 0; + int index = 0; + while (span.Length > 0) + { + int tokenEnd = span.IndexOf(separator); + if (tokenEnd == -1) tokenEnd = span.Length; + + destination[matches] = new Range(index, index + tokenEnd); + matches++; + + // move to next token + span = span.Slice(tokenEnd + 1); + + if (matches > destination.Length) + break; + } + + return matches; + } +#endif +} diff --git a/test/HtmlToOpenXml.Tests/Primitives/ColorTests.cs b/test/HtmlToOpenXml.Tests/Primitives/ColorTests.cs index 2b891847..5b5ff11e 100644 --- a/test/HtmlToOpenXml.Tests/Primitives/ColorTests.cs +++ b/test/HtmlToOpenXml.Tests/Primitives/ColorTests.cs @@ -8,25 +8,23 @@ namespace HtmlToOpenXml.Tests.Primitives [TestFixture] public class ColorTests { - [TestCase("", 0, 0, 0, 0d)] [TestCase("#F00", 255, 0, 0, 1d)] [TestCase("#00FFFF", 0, 255, 255, 1d)] [TestCase("red", 255, 0, 0, 1d)] [TestCase("rgb(106, 90, 205)", 106, 90, 205, 1d)] [TestCase("rgba(106, 90, 205, 0.6)", 106, 90, 205, 0.6d)] + [TestCase("rgb(106 90 205)", 106, 90, 205, 1d)] + [TestCase("rgb(106 90 205 / 0.25)", 106, 90, 205, 0.25d)] [TestCase("hsl(248, 53%, 58%)", 106, 91, 205, 1)] [TestCase("hsla(9, 100%, 64%, 0.6)", 255, 99, 71, 0.6d)] [TestCase("hsl(0, 100%, 50%)", 255, 0, 0, 1)] - // Percentage not respected that should be maxed out - [TestCase("hsl(0, 200%, 150%)", 255, 255, 255, 1)] - // Failure that leads to empty - [TestCase("rgba(1.06, 90, 205, 0.6)", 0, 0, 0, 0.0d)] - [TestCase("rgba(a, r, g, b)", 0, 0, 0, 0.0d)] + [TestCase("hsl(0, 200%, 150%)", 255, 255, 255, 1, Description = "Percentage not respected that should be maxed out")] public void ParseHtmlColor_ShouldSucceed(string htmlColor, byte red, byte green, byte blue, double alpha) { var color = HtmlColor.Parse(htmlColor); Assert.Multiple(() => { + Assert.That(color.IsEmpty, Is.False); Assert.That(color.R, Is.EqualTo(red)); Assert.That(color.B, Is.EqualTo(blue)); Assert.That(color.G, Is.EqualTo(green)); @@ -34,6 +32,17 @@ public void ParseHtmlColor_ShouldSucceed(string htmlColor, byte red, byte green, }); } + // Failure that leads to empty + [TestCase("", 0, 0, 0, 0d)] + [TestCase("rgba(1.06, 90, 205, 0.6)", 0, 0, 0, 0.0d)] + [TestCase("rgba(a, r, g, b)", 0, 0, 0, 0.0d)] + [TestCase("rgb", 0, 0, 0, 0.0d)] + public void ParseInvalidHtmlColor_ReturnsEmpty(string htmlColor, byte red, byte green, byte blue, double alpha) + { + var color = HtmlColor.Parse(htmlColor); + Assert.That(color.IsEmpty, Is.True); + } + [TestCase(255, 0, 0, 0, ExpectedResult = "FF0000")] public string ArgColor_ToHex_ShouldSucceed(byte red, byte green, byte blue, double alpha) { diff --git a/test/HtmlToOpenXml.Tests/StyleTests.cs b/test/HtmlToOpenXml.Tests/StyleTests.cs index 2fb56f51..68f28a7b 100644 --- a/test/HtmlToOpenXml.Tests/StyleTests.cs +++ b/test/HtmlToOpenXml.Tests/StyleTests.cs @@ -25,7 +25,7 @@ public void UseVariantStyle_ReturnsAppliedStyle() Type = args.Type, BasedOn = new BasedOn { Val = "Normal" }, StyleRunProperties = new() { - Color = new() { Val = HtmlColorTranslator.FromHtml("red").ToHexString() } + Color = new() { Val = HtmlColor.Parse("red").ToHexString() } } }); }; @@ -158,12 +158,5 @@ public void ManualAddStyle_ThenRefreshStyles_ShouldSucceed() Assert.That(paragraph.ParagraphProperties, Is.Not.Null); Assert.That(paragraph.ParagraphProperties?.ParagraphStyleId?.Val?.Value, Is.EqualTo("CustomIntenseQuoteStyle")); } - - [Test(Description = "Parser should consider the last occurence of a style")] - public void DuplicateStyle_ReturnsLatter() - { - var styleAttributes = HtmlAttributeCollection.ParseStyle("color:red;color:blue"); - Assert.That(styleAttributes["color"], Is.EqualTo("blue")); - } } } From a5048cd363cf086b4e98618ce04c8452b6672490 Mon Sep 17 00:00:00 2001 From: Olivier Nizet Date: Sat, 28 Sep 2024 22:22:47 +0200 Subject: [PATCH 02/29] Improve regex to avoid a call to HtmlDecode --- .../Collections/HtmlAttributeCollection.cs | 25 ++++++---------- .../Primitives/StyleParserTests.cs | 29 +++++++++++++++++++ 2 files changed, 38 insertions(+), 16 deletions(-) create mode 100644 test/HtmlToOpenXml.Tests/Primitives/StyleParserTests.cs diff --git a/src/Html2OpenXml/Collections/HtmlAttributeCollection.cs b/src/Html2OpenXml/Collections/HtmlAttributeCollection.cs index bdccb5f9..9c4ee2f6 100755 --- a/src/Html2OpenXml/Collections/HtmlAttributeCollection.cs +++ b/src/Html2OpenXml/Collections/HtmlAttributeCollection.cs @@ -9,6 +9,7 @@ * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A * PARTICULAR PURPOSE. */ +using System; using System.Collections.Generic; using System.Text.RegularExpressions; using DocumentFormat.OpenXml.Wordprocessing; @@ -20,32 +21,24 @@ namespace HtmlToOpenXml; /// sealed class HtmlAttributeCollection { - private static readonly Regex stripStyleAttributesRegex = new(@"(?.+?):\s*(?[^;]+);*\s*"); + // Encoded ':' and ';' characters are valid for browser but not handled by the regex (bug #13812 reported by robin391) + // ex= + private static readonly Regex stripStyleAttributesRegex = new(@"(?.+?)(:|&\#58;)\s*(?[^;&]+)(;|&\#59;)*\s*"); private readonly Dictionary attributes = []; - - private HtmlAttributeCollection() { } - public static HtmlAttributeCollection ParseStyle(string? htmlTag) + public static HtmlAttributeCollection ParseStyle(string? htmlStyles) { var collection = new HtmlAttributeCollection(); - if (string.IsNullOrEmpty(htmlTag)) return collection; - - // Encoded ':' and ';' characters are valid for browser but not handled by the regex (bug #13812 reported by robin391) - // ex= - MatchCollection matches = stripStyleAttributesRegex.Matches( -#if NET5_0_OR_GREATER - System.Web.HttpUtility.HtmlDecode(htmlTag) -#else - HttpUtility.HtmlDecode(htmlTag) -#endif - ); + if (string.IsNullOrWhiteSpace(htmlStyles)) return collection; + + MatchCollection matches = stripStyleAttributesRegex.Matches(htmlStyles); foreach (Match m in matches) - collection.attributes[m.Groups["name"].Value] = m.Groups["val"].Value; + collection.attributes[m.Groups["name"].Value] = m.Groups["val"].Value.TrimEnd(); return collection; } diff --git a/test/HtmlToOpenXml.Tests/Primitives/StyleParserTests.cs b/test/HtmlToOpenXml.Tests/Primitives/StyleParserTests.cs new file mode 100644 index 00000000..aa2516bd --- /dev/null +++ b/test/HtmlToOpenXml.Tests/Primitives/StyleParserTests.cs @@ -0,0 +1,29 @@ +using NUnit.Framework; + +namespace HtmlToOpenXml.Tests.Primitives +{ + /// + /// Tests Html color style attribute. + /// + [TestFixture] + public class StyleParserTests + { + [TestCase("text-decoration:underline; color: red ")] + [TestCase("text-decoration:underline;color:red")] + public void ParseStyle_ShouldSucceed(string htmlStyle) + { + var styles = HtmlAttributeCollection.ParseStyle(htmlStyle); + Assert.Multiple(() => { + Assert.That(styles["text-decoration"], Is.EqualTo("underline")); + Assert.That(styles["color"], Is.EqualTo("red")); + }); + } + + [Test(Description = "Parser should consider the last occurence of a style")] + public void DuplicateStyle_ReturnsLatter() + { + var styleAttributes = HtmlAttributeCollection.ParseStyle("color:red;color:blue"); + Assert.That(styleAttributes["color"], Is.EqualTo("blue")); + } + } +} From eabbce6e4c6092d5d51975b8dda8874e72574a38 Mon Sep 17 00:00:00 2001 From: Olivier Nizet Date: Sun, 29 Sep 2024 00:35:23 +0200 Subject: [PATCH 03/29] Unit and Margin also now use memory span --- .../Expressions/BlockElementExpression.cs | 4 +- .../Expressions/Table/TableExpression.cs | 2 +- .../Expressions/Table/TableRowExpression.cs | 2 +- .../{Primitives => IO}/HtmlImageInfo.cs | 0 src/Html2OpenXml/Primitives/HtmlColor.cs | 4 +- src/Html2OpenXml/Primitives/Margin.cs | 42 +++--- src/Html2OpenXml/Primitives/SideBorder.cs | 2 +- src/Html2OpenXml/Primitives/Unit.cs | 130 ++++++++++-------- src/Html2OpenXml/Utilities/Converter.cs | 20 +-- src/Html2OpenXml/Utilities/SpanExtensions.cs | 23 +++- .../Primitives/ColorTests.cs | 12 +- .../Primitives/MarginTests.cs | 17 +-- .../Primitives/UnitTests.cs | 37 +++++ 13 files changed, 177 insertions(+), 118 deletions(-) rename src/Html2OpenXml/{Primitives => IO}/HtmlImageInfo.cs (100%) create mode 100644 test/HtmlToOpenXml.Tests/Primitives/UnitTests.cs diff --git a/src/Html2OpenXml/Expressions/BlockElementExpression.cs b/src/Html2OpenXml/Expressions/BlockElementExpression.cs index e15db508..8b1aecd8 100644 --- a/src/Html2OpenXml/Expressions/BlockElementExpression.cs +++ b/src/Html2OpenXml/Expressions/BlockElementExpression.cs @@ -209,7 +209,7 @@ protected override void ComposeStyles (ParsingContext context) if (lineHeight.IsValid) { - if (lineHeight.Type == UnitMetric.Unitless) + if (lineHeight.Metric == UnitMetric.Unitless) { // auto should be considered as 240ths of a line // https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.wordprocessing.spacingbetweenlines.line?view=openxml-3.0.1 @@ -218,7 +218,7 @@ protected override void ComposeStyles (ParsingContext context) Line = Math.Round(lineHeight.Value * 240).ToString(CultureInfo.InvariantCulture) }; } - else if (lineHeight.Type == UnitMetric.Percent) + else if (lineHeight.Metric == UnitMetric.Percent) { // percentage depends on the font size which is hard to determine here // let's rely this to "auto" behaviour diff --git a/src/Html2OpenXml/Expressions/Table/TableExpression.cs b/src/Html2OpenXml/Expressions/Table/TableExpression.cs index ecb0b9c4..27bcdbb3 100644 --- a/src/Html2OpenXml/Expressions/Table/TableExpression.cs +++ b/src/Html2OpenXml/Expressions/Table/TableExpression.cs @@ -172,7 +172,7 @@ protected override void ComposeStyles (ParsingContext context) if (!width.IsValid) width = Unit.Parse(tableNode.GetAttribute("width"), UnitMetric.Pixel); if (!width.IsValid) width = new Unit(UnitMetric.Percent, 100); - switch (width.Type) + switch (width.Metric) { case UnitMetric.Percent: if (width.Value == 100) diff --git a/src/Html2OpenXml/Expressions/Table/TableRowExpression.cs b/src/Html2OpenXml/Expressions/Table/TableRowExpression.cs index d0f04ff8..1a209dfc 100644 --- a/src/Html2OpenXml/Expressions/Table/TableRowExpression.cs +++ b/src/Html2OpenXml/Expressions/Table/TableRowExpression.cs @@ -105,7 +105,7 @@ protected override void ComposeStyles(ParsingContext context) Unit unit = styleAttributes!.GetUnit("height", UnitMetric.Pixel); if (!unit.IsValid) unit = Unit.Parse(rowNode.GetAttribute("height"), UnitMetric.Pixel); - switch (unit.Type) + switch (unit.Metric) { case UnitMetric.Point: rowProperties.AddChild(new TableRowHeight() { HeightType = HeightRuleValues.AtLeast, Val = (uint) (unit.Value * 20) }); diff --git a/src/Html2OpenXml/Primitives/HtmlImageInfo.cs b/src/Html2OpenXml/IO/HtmlImageInfo.cs similarity index 100% rename from src/Html2OpenXml/Primitives/HtmlImageInfo.cs rename to src/Html2OpenXml/IO/HtmlImageInfo.cs diff --git a/src/Html2OpenXml/Primitives/HtmlColor.cs b/src/Html2OpenXml/Primitives/HtmlColor.cs index 213ef362..975dcf37 100755 --- a/src/Html2OpenXml/Primitives/HtmlColor.cs +++ b/src/Html2OpenXml/Primitives/HtmlColor.cs @@ -82,7 +82,7 @@ public static HtmlColor Parse(ReadOnlySpan span) span = span.Slice(startIndex + 1, endIndex - startIndex - 1); Span tokens = stackalloc Range[5]; var sep = span.IndexOf(',') > -1? ',' : ' '; - return span.Split(tokens, sep) switch + return span.Split(tokens, sep, StringSplitOptions.RemoveEmptyEntries) switch { 3 => FromArgb(1.0, span.Slice(tokens[0]).AsByte(NumberStyles.Integer), @@ -111,7 +111,7 @@ public static HtmlColor Parse(ReadOnlySpan span) span = span.Slice(startIndex + 1, endIndex - startIndex - 1); Span tokens = stackalloc Range[5]; var sep = span.IndexOf(',') > -1? ',' : ' '; - return span.Split(tokens, sep) switch + return span.Split(tokens, sep, StringSplitOptions.RemoveEmptyEntries) switch { 3 => FromHsl(1.0, span.Slice(tokens[0]).AsDouble(), diff --git a/src/Html2OpenXml/Primitives/Margin.cs b/src/Html2OpenXml/Primitives/Margin.cs index c0c48075..8aa962ff 100755 --- a/src/Html2OpenXml/Primitives/Margin.cs +++ b/src/Html2OpenXml/Primitives/Margin.cs @@ -10,13 +10,17 @@ * PARTICULAR PURPOSE. */ +using System; + namespace HtmlToOpenXml; /// -/// Represents a Html Unit (ie: 120px, 10em, ...). +/// Represents a Html Margin. /// struct Margin { + /// Represents an empty margin (not defined). + public static readonly Margin Empty = new(); private Unit[] sides; @@ -50,40 +54,42 @@ public Margin(Unit top, Unit right, Unit bottom, Unit left) /// public static Margin Parse(string? str) { - if (str == null) return new Margin(); + if (string.IsNullOrWhiteSpace(str)) + return Empty; - var parts = str.Split(HttpUtility.WhiteSpaces); - switch (parts.Length) + var span = str!.AsSpan(); + Span tokens = stackalloc Range[5]; + switch (span.Split(tokens, ' ', StringSplitOptions.RemoveEmptyEntries)) { case 1: - { - Unit all = Unit.Parse(parts[0], UnitMetric.Pixel); - return new Margin(all, all, all, all); - } + { + Unit all = Unit.Parse(span.Slice(tokens[0]), UnitMetric.Pixel); + return new Margin(all, all, all, all); + } case 2: { - Unit u1 = Unit.Parse(parts[0], UnitMetric.Pixel); - Unit u2 = Unit.Parse(parts[1], UnitMetric.Pixel); + Unit u1 = Unit.Parse(span.Slice(tokens[0]), UnitMetric.Pixel); + Unit u2 = Unit.Parse(span.Slice(tokens[1]), UnitMetric.Pixel); return new Margin(u1, u2, u1, u2); } case 3: { - Unit u1 = Unit.Parse(parts[0], UnitMetric.Pixel); - Unit u2 = Unit.Parse(parts[1], UnitMetric.Pixel); - Unit u3 = Unit.Parse(parts[2], UnitMetric.Pixel); + Unit u1 = Unit.Parse(span.Slice(tokens[0]), UnitMetric.Pixel); + Unit u2 = Unit.Parse(span.Slice(tokens[1]), UnitMetric.Pixel); + Unit u3 = Unit.Parse(span.Slice(tokens[2]), UnitMetric.Pixel); return new Margin(u1, u2, u3, u2); } case 4: { - Unit u1 = Unit.Parse(parts[0], UnitMetric.Pixel); - Unit u2 = Unit.Parse(parts[1], UnitMetric.Pixel); - Unit u3 = Unit.Parse(parts[2], UnitMetric.Pixel); - Unit u4 = Unit.Parse(parts[3], UnitMetric.Pixel); + Unit u1 = Unit.Parse(span.Slice(tokens[0]), UnitMetric.Pixel); + Unit u2 = Unit.Parse(span.Slice(tokens[1]), UnitMetric.Pixel); + Unit u3 = Unit.Parse(span.Slice(tokens[2]), UnitMetric.Pixel); + Unit u4 = Unit.Parse(span.Slice(tokens[3]), UnitMetric.Pixel); return new Margin(u1, u2, u3, u4); } } - return new Margin(); + return Empty; } private void EnsureSides() diff --git a/src/Html2OpenXml/Primitives/SideBorder.cs b/src/Html2OpenXml/Primitives/SideBorder.cs index 67c5598d..ea268da6 100755 --- a/src/Html2OpenXml/Primitives/SideBorder.cs +++ b/src/Html2OpenXml/Primitives/SideBorder.cs @@ -90,7 +90,7 @@ internal static Unit ParseWidth(string? borderWidth) Unit bu = Unit.Parse(borderWidth, UnitMetric.Pixel); if (bu.IsValid) { - if (bu.Value > 0 && bu.Type == UnitMetric.Pixel) + if (bu.Value > 0 && bu.Metric == UnitMetric.Pixel) return bu; } else diff --git a/src/Html2OpenXml/Primitives/Unit.cs b/src/Html2OpenXml/Primitives/Unit.cs index 938df509..e36e30b8 100755 --- a/src/Html2OpenXml/Primitives/Unit.cs +++ b/src/Html2OpenXml/Primitives/Unit.cs @@ -10,7 +10,6 @@ * PARTICULAR PURPOSE. */ using System; -using System.Globalization; namespace HtmlToOpenXml; @@ -25,85 +24,106 @@ readonly struct Unit /// Represents an Auto unit. public static readonly Unit Auto = new Unit(UnitMetric.Auto, 0L); - private readonly UnitMetric type; + private readonly UnitMetric metric; private readonly double value; private readonly long valueInEmus; - public Unit(UnitMetric type, double value) + public Unit(UnitMetric metric, double value) { - this.type = type; + this.metric = metric; this.value = value; - this.valueInEmus = ComputeInEmus(type, value); + this.valueInEmus = ComputeInEmus(metric, value); } - public static Unit Parse(string? str, UnitMetric defaultMetric = UnitMetric.Unitless) + public static Unit Parse(ReadOnlySpan span, UnitMetric defaultMetric = UnitMetric.Unitless) { - if (str == null) return Unit.Empty; - - str = str.Trim().ToLowerInvariant(); - int length = str.Length; - int digitLength = -1; - for (int i = 0; i < length; i++) + span.Trim(); + if (span.Length <= 1) { - char ch = str[i]; - if ((ch < '0' || ch > '9') && ch != '-' && ch != '.' && ch != ',') - break; - - digitLength = i; + // either this is invalid or this is a single digit + if (span.Length == 0 || !char.IsDigit(span[0])) return Empty; + return new Unit(defaultMetric, span[0] - '0'); } - if (digitLength == -1) + + // guess the unit first than use the native Double parsing + UnitMetric metric; + int metricSize = 2; + if (span[span.Length - 1] == '%') { - // No digits in the width, we ignore this style - return str == "auto"? Unit.Auto : Unit.Empty; + metric = UnitMetric.Percent; + metricSize = 1; } - - UnitMetric type; - if (digitLength < length - 1) - type = Converter.ToUnitMetric(str.Substring(digitLength + 1).Trim()); else - type = defaultMetric; + { + Span loweredValue = span.Length <= 128 ? stackalloc char[span.Length] : new char[span.Length]; + span.ToLowerInvariant(loweredValue); + + var metricSpan = loweredValue.Slice(loweredValue.Length - 2, 2); + metric = metricSpan switch { + "in" => UnitMetric.Inch, + "cm" => UnitMetric.Centimeter, + "mm" => UnitMetric.Millimeter, + "em" => UnitMetric.EM, + "ex" => UnitMetric.Ex, + "pt" => UnitMetric.Point, + "pc" => UnitMetric.Pica, + "px" => UnitMetric.Pixel, + _ => UnitMetric.Unknown, + }; + + // not recognised but maybe this is unitless (only digits) + if (metric == UnitMetric.Unknown && char.IsDigit(metricSpan[0])) + { + metric = UnitMetric.Unitless; + metricSize = 0; + } + } - string v = str.Substring(0, digitLength + 1); double value; try { - value = Convert.ToDouble(v, CultureInfo.InvariantCulture); + value = span.Slice(0, span.Length - metricSize).AsDouble(); if (value < short.MinValue || value > short.MaxValue) - return Unit.Empty; + return Empty; } - catch (FormatException) + catch (Exception) { - return Unit.Empty; - } - catch (ArithmeticException) - { - return Unit.Empty; + // No digits, we ignore this style + return span is "auto"? Auto : Empty; } - return new Unit(type, value); + return new Unit(metric, value); + } + + public static Unit Parse(string? str, UnitMetric defaultMetric = UnitMetric.Unitless) + { + if (string.IsNullOrWhiteSpace(str)) + return Empty; + + return Parse(str.AsSpan(), defaultMetric); } /// /// Gets the value expressed in the English Metrics Units. /// - private static long ComputeInEmus(UnitMetric type, double value) + private static long ComputeInEmus(UnitMetric metric, double value) { /* Compute width and height in English Metrics Units. - * There are 360000 EMUs per centimeter, 914400 EMUs per inch, 12700 EMUs per point - * widthInEmus = widthInPixels / HorizontalResolutionInDPI * 914400 - * heightInEmus = heightInPixels / VerticalResolutionInDPI * 914400 - * - * According to 1 px ~= 9525 EMU -> 914400 EMU per inch / 9525 EMU = 96 dpi - * So Word use 96 DPI printing which seems fair. - * http://hastobe.net/blogs/stevemorgan/archive/2008/09/15/howto-insert-an-image-into-a-word-document-and-display-it-using-openxml.aspx - * http://startbigthinksmall.wordpress.com/2010/01/04/points-inches-and-emus-measuring-units-in-office-open-xml/ - * - * The list of units supported are explained here: http://www.w3schools.com/css/css_units.asp - */ - - switch (type) + * There are 360000 EMUs per centimeter, 914400 EMUs per inch, 12700 EMUs per point + * widthInEmus = widthInPixels / HorizontalResolutionInDPI * 914400 + * heightInEmus = heightInPixels / VerticalResolutionInDPI * 914400 + * + * According to 1 px ~= 9525 EMU -> 914400 EMU per inch / 9525 EMU = 96 dpi + * So Word use 96 DPI printing which seems fair. + * http://hastobe.net/blogs/stevemorgan/archive/2008/09/15/howto-insert-an-image-into-a-word-document-and-display-it-using-openxml.aspx + * http://startbigthinksmall.wordpress.com/2010/01/04/points-inches-and-emus-measuring-units-in-office-open-xml/ + * + * The list of units supported are explained here: http://www.w3schools.com/css/css_units.asp + */ + + switch (metric) { case UnitMetric.Auto: case UnitMetric.Unitless: @@ -130,9 +150,9 @@ private static long ComputeInEmus(UnitMetric type, double value) /// /// Gets the type of unit (pixel, percent, point, ...) /// - public UnitMetric Type + public UnitMetric Metric { - get { return type; } + get { return metric; } } /// @@ -164,7 +184,7 @@ public Int64 ValueInDxa /// public int ValueInPx { - get { return (int) (type == UnitMetric.Pixel ? this.value : (float) valueInEmus / 914400L * 96); } + get { return (int) (metric == UnitMetric.Pixel ? this.value : (float) valueInEmus / 914400L * 96); } } /// @@ -172,7 +192,7 @@ public int ValueInPx /// public double ValueInPoint { - get { return (double) (type == UnitMetric.Point ? this.value : (float) valueInEmus / 12700L); } + get { return (double) (metric == UnitMetric.Point ? this.value : (float) valueInEmus / 12700L); } } /// @@ -190,7 +210,7 @@ public double ValueInEighthPoint /// public bool IsValid { - get { return this.Type != UnitMetric.Unknown; } + get { return this.Metric != UnitMetric.Unknown; } } /// @@ -198,6 +218,6 @@ public bool IsValid /// public bool IsFixed { - get { return IsValid && Type != UnitMetric.Percent && Type != UnitMetric.Auto; } + get { return IsValid && Metric != UnitMetric.Percent && Metric != UnitMetric.Auto; } } } diff --git a/src/Html2OpenXml/Utilities/Converter.cs b/src/Html2OpenXml/Utilities/Converter.cs index 9481fb52..61f899d1 100755 --- a/src/Html2OpenXml/Utilities/Converter.cs +++ b/src/Html2OpenXml/Utilities/Converter.cs @@ -81,7 +81,7 @@ public static Unit ToFontSize(string? htmlSize) return Unit.Empty; // this is a rough conversion to support some percent size, considering 100% = 11 pt - if (unit.Type == UnitMetric.Percent) unit = new Unit(UnitMetric.Point, unit.Value * 0.11); + if (unit.Metric == UnitMetric.Percent) unit = new Unit(UnitMetric.Point, unit.Value * 0.11); return unit; } } @@ -160,24 +160,6 @@ public static BorderValues ToBorderStyle(string? borderStyle) }; } - public static UnitMetric ToUnitMetric(string? type) - { - if (type == null) return UnitMetric.Unitless; - return type.ToLowerInvariant() switch - { - "%" => UnitMetric.Percent, - "in" => UnitMetric.Inch, - "cm" => UnitMetric.Centimeter, - "mm" => UnitMetric.Millimeter, - "em" => UnitMetric.EM, - "ex" => UnitMetric.Ex, - "pt" => UnitMetric.Point, - "pc" => UnitMetric.Pica, - "px" => UnitMetric.Pixel, - _ => UnitMetric.Unknown, - }; - } - public static PageOrientationValues ToPageOrientation(string? orientation) { if ( "landscape".Equals(orientation,StringComparison.OrdinalIgnoreCase)) diff --git a/src/Html2OpenXml/Utilities/SpanExtensions.cs b/src/Html2OpenXml/Utilities/SpanExtensions.cs index a4bfc6c6..5f37a948 100644 --- a/src/Html2OpenXml/Utilities/SpanExtensions.cs +++ b/src/Html2OpenXml/Utilities/SpanExtensions.cs @@ -85,24 +85,37 @@ public static ReadOnlySpan Slice(this ReadOnlySpan span, Range range) /// The source span to parse. /// The destination span into which the resulting ranges are written. /// A character that delimits the regions in this instance. + /// A bitwise combination of the enumeration values that specifies whether to trim whitespace and include empty ranges. /// The number of ranges written into . - public static int Split(this ReadOnlySpan span, Span destination, char separator) + public static int Split(this ReadOnlySpan span, Span destination, + char separator, StringSplitOptions options = StringSplitOptions.None) { + // If the destination is empty, there's nothing to do. + if (destination.IsEmpty) + return 0; + int matches = 0; int index = 0; while (span.Length > 0) { int tokenEnd = span.IndexOf(separator); if (tokenEnd == -1) tokenEnd = span.Length; + if (options == StringSplitOptions.RemoveEmptyEntries && tokenEnd == 0) + { + span = span.Slice(1); + index++; + continue; + } destination[matches] = new Range(index, index + tokenEnd); matches++; - // move to next token - span = span.Slice(tokenEnd + 1); - - if (matches > destination.Length) + if (matches > destination.Length || span.Length <= tokenEnd) break; + + // move to next token + span = span.Slice(tokenEnd ); + index += tokenEnd; } return matches; diff --git a/test/HtmlToOpenXml.Tests/Primitives/ColorTests.cs b/test/HtmlToOpenXml.Tests/Primitives/ColorTests.cs index 5b5ff11e..81f251f0 100644 --- a/test/HtmlToOpenXml.Tests/Primitives/ColorTests.cs +++ b/test/HtmlToOpenXml.Tests/Primitives/ColorTests.cs @@ -11,7 +11,7 @@ public class ColorTests [TestCase("#F00", 255, 0, 0, 1d)] [TestCase("#00FFFF", 0, 255, 255, 1d)] [TestCase("red", 255, 0, 0, 1d)] - [TestCase("rgb(106, 90, 205)", 106, 90, 205, 1d)] + [TestCase("rgb(106, 90, 205)", 106, 90, 205, 1d)] [TestCase("rgba(106, 90, 205, 0.6)", 106, 90, 205, 0.6d)] [TestCase("rgb(106 90 205)", 106, 90, 205, 1d)] [TestCase("rgb(106 90 205 / 0.25)", 106, 90, 205, 0.25d)] @@ -33,11 +33,11 @@ public void ParseHtmlColor_ShouldSucceed(string htmlColor, byte red, byte green, } // Failure that leads to empty - [TestCase("", 0, 0, 0, 0d)] - [TestCase("rgba(1.06, 90, 205, 0.6)", 0, 0, 0, 0.0d)] - [TestCase("rgba(a, r, g, b)", 0, 0, 0, 0.0d)] - [TestCase("rgb", 0, 0, 0, 0.0d)] - public void ParseInvalidHtmlColor_ReturnsEmpty(string htmlColor, byte red, byte green, byte blue, double alpha) + [TestCase("")] + [TestCase("rgba(1.06, 90, 205, 0.6)")] + [TestCase("rgba(a, r, g, b)")] + [TestCase("rgb")] + public void ParseInvalidHtmlColor_ReturnsEmpty(string htmlColor) { var color = HtmlColor.Parse(htmlColor); Assert.That(color.IsEmpty, Is.True); diff --git a/test/HtmlToOpenXml.Tests/Primitives/MarginTests.cs b/test/HtmlToOpenXml.Tests/Primitives/MarginTests.cs index 12bebe28..4db60b8f 100644 --- a/test/HtmlToOpenXml.Tests/Primitives/MarginTests.cs +++ b/test/HtmlToOpenXml.Tests/Primitives/MarginTests.cs @@ -12,6 +12,7 @@ public class MarginTests [TestCase("25px 50px 75px", 25, 50, 75, 50)] [TestCase("25px 50px", 25, 50, 25, 50)] [TestCase("25px", 25, 25, 25, 25)] + [TestCase("25px 75px", 25, 75, 25, 75)] public void ParseHtmlString_ShouldSucceed (string html, int top, int right, int bottom, int left) { var margin = Margin.Parse(html); @@ -34,19 +35,19 @@ public void ParseWithFloat_ShouldSucceed () Assert.That(margin.IsValid, Is.EqualTo(true)); Assert.That(margin.Top.Value, Is.EqualTo(0)); - Assert.That(margin.Top.Type, Is.EqualTo(UnitMetric.Pixel)); + Assert.That(margin.Top.Metric, Is.EqualTo(UnitMetric.Pixel)); Assert.That(margin.Right.Value, Is.EqualTo(50)); - Assert.That(margin.Right.Type, Is.EqualTo(UnitMetric.Percent)); + Assert.That(margin.Right.Metric, Is.EqualTo(UnitMetric.Percent)); Assert.That(margin.Bottom.Value, Is.EqualTo(9.5)); - Assert.That(margin.Bottom.Type, Is.EqualTo(UnitMetric.Point)); + Assert.That(margin.Bottom.Metric, Is.EqualTo(UnitMetric.Point)); Assert.That(margin.Bottom.ValueInPoint, Is.EqualTo(9.5)); //size are half-point font size (OpenXml relies mostly on long value, not on float) Assert.That(Math.Round(margin.Bottom.ValueInPoint * 2).ToString(), Is.EqualTo("19")); Assert.That(margin.Left.Value, Is.EqualTo(.00001)); - Assert.That(margin.Left.Type, Is.EqualTo(UnitMetric.Point)); + Assert.That(margin.Left.Metric, Is.EqualTo(UnitMetric.Point)); // but due to conversion: 0 (OpenXml relies mostly on long value, not on float) Assert.That(Math.Round(margin.Left.ValueInPoint * 2).ToString(), Is.EqualTo("0")); }); @@ -61,13 +62,13 @@ public void ParseWithAuto_ShouldSucceed () Assert.That(margin.IsValid, Is.EqualTo(true)); Assert.That(margin.Top.Value, Is.EqualTo(0)); - Assert.That(margin.Top.Type, Is.EqualTo(UnitMetric.Pixel)); + Assert.That(margin.Top.Metric, Is.EqualTo(UnitMetric.Pixel)); Assert.That(margin.Bottom.Value, Is.EqualTo(0)); - Assert.That(margin.Bottom.Type, Is.EqualTo(UnitMetric.Pixel)); + Assert.That(margin.Bottom.Metric, Is.EqualTo(UnitMetric.Pixel)); - Assert.That(margin.Left.Type, Is.EqualTo(UnitMetric.Auto)); - Assert.That(margin.Right.Type, Is.EqualTo(UnitMetric.Auto)); + Assert.That(margin.Left.Metric, Is.EqualTo(UnitMetric.Auto)); + Assert.That(margin.Right.Metric, Is.EqualTo(UnitMetric.Auto)); }); } } diff --git a/test/HtmlToOpenXml.Tests/Primitives/UnitTests.cs b/test/HtmlToOpenXml.Tests/Primitives/UnitTests.cs new file mode 100644 index 00000000..7df16f32 --- /dev/null +++ b/test/HtmlToOpenXml.Tests/Primitives/UnitTests.cs @@ -0,0 +1,37 @@ +using NUnit.Framework; + +namespace HtmlToOpenXml.Tests.Primitives +{ + /// + /// Tests Html color style attribute. + /// + [TestFixture] + class UnitTests + { + [TestCase("auto", 0, UnitMetric.Auto)] + [TestCase("5%", 5, UnitMetric.Percent)] + [TestCase(" 12 px", 12, UnitMetric.Pixel)] + [TestCase(" 12 ", 12, UnitMetric.Unitless)] + [TestCase("9", 9, UnitMetric.Unitless)] + public void ParseHtmlUnit_ShouldSucceed(string str, double value, UnitMetric metric) + { + var unit = Unit.Parse(str); + + Assert.Multiple(() => { + Assert.That(unit.IsValid, Is.True); + Assert.That(unit.Metric, Is.EqualTo(metric)); + Assert.That(unit.Value, Is.EqualTo(value)); + }); + } + + [TestCase(" ")] + [TestCase("12zz")] + [TestCase("zz")] + [TestCase("%")] + public void ParseInvalidHtmlColor_ReturnsEmpty(string str) + { + var unit = Unit.Parse(str); + Assert.That(unit.IsValid, Is.False); + } + } +} From 1dff57b06055b2a531d9dedfe1a2f0ebca28f674 Mon Sep 17 00:00:00 2001 From: Olivier Nizet Date: Mon, 30 Sep 2024 15:49:55 +0200 Subject: [PATCH 04/29] Bug fix on Span polyfill method --- src/Html2OpenXml/Primitives/Unit.cs | 2 +- src/Html2OpenXml/Utilities/SpanExtensions.cs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Html2OpenXml/Primitives/Unit.cs b/src/Html2OpenXml/Primitives/Unit.cs index e36e30b8..f0690104 100755 --- a/src/Html2OpenXml/Primitives/Unit.cs +++ b/src/Html2OpenXml/Primitives/Unit.cs @@ -73,7 +73,7 @@ public static Unit Parse(ReadOnlySpan span, UnitMetric defaultMetric = Uni }; // not recognised but maybe this is unitless (only digits) - if (metric == UnitMetric.Unknown && char.IsDigit(metricSpan[0])) + if (metric == UnitMetric.Unknown && (char.IsDigit(metricSpan[0]) || metricSpan[0] == '.')) { metric = UnitMetric.Unitless; metricSize = 0; diff --git a/src/Html2OpenXml/Utilities/SpanExtensions.cs b/src/Html2OpenXml/Utilities/SpanExtensions.cs index 5f37a948..75e65162 100644 --- a/src/Html2OpenXml/Utilities/SpanExtensions.cs +++ b/src/Html2OpenXml/Utilities/SpanExtensions.cs @@ -107,15 +107,15 @@ public static int Split(this ReadOnlySpan span, Span destination, continue; } - destination[matches] = new Range(index, index + tokenEnd); + destination[matches] = new Range(index, tokenEnd); matches++; - if (matches > destination.Length || span.Length <= tokenEnd) + if (matches >= destination.Length || span.Length <= tokenEnd) break; // move to next token - span = span.Slice(tokenEnd ); - index += tokenEnd; + span = span.Slice(tokenEnd + 1); + index += tokenEnd + 1; } return matches; From a1cd67e267c1902590ca326b8dc1466833eccb4c Mon Sep 17 00:00:00 2001 From: Olivier Nizet Date: Mon, 30 Sep 2024 15:50:33 +0200 Subject: [PATCH 05/29] Reuse existing .Net framework implementation of HtmlDecode if available --- src/Html2OpenXml/IO/DataUri.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Html2OpenXml/IO/DataUri.cs b/src/Html2OpenXml/IO/DataUri.cs index 8b0736e2..918783fa 100755 --- a/src/Html2OpenXml/IO/DataUri.cs +++ b/src/Html2OpenXml/IO/DataUri.cs @@ -84,7 +84,11 @@ public static bool TryCreate(string uri, out DataUri? result) if (match.Groups["base64"].Length > 0) { // be careful that the raw data is encoded for url (standard %xx hex encoding) +#if NET5_0_OR_GREATER + string base64 = System.Web.HttpUtility.HtmlDecode(match.Groups["data"].Value); +#else string base64 = HttpUtility.HtmlDecode(match.Groups["data"].Value); +#endif try { From b523d8b5c4ea7e061ca8d683098ae360818d6c66 Mon Sep 17 00:00:00 2001 From: Olivier Nizet Date: Mon, 30 Sep 2024 15:51:47 +0200 Subject: [PATCH 06/29] Fix sln markup --- HtmlToOpenXml.sln | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HtmlToOpenXml.sln b/HtmlToOpenXml.sln index 18814542..d702dedb 100644 --- a/HtmlToOpenXml.sln +++ b/HtmlToOpenXml.sln @@ -1,6 +1,6 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 17 +# Visual Studio Version 17 VisualStudioVersion = 17.8.34511.84 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HtmlToOpenXml", "src\Html2OpenXml\HtmlToOpenXml.csproj", "{EF700F30-C9BB-49A6-912C-E3B77857B514}" From e79b024bf2eb025f2ddd5f118e0d6efa74940ba2 Mon Sep 17 00:00:00 2001 From: Olivier Nizet Date: Sat, 5 Oct 2024 13:46:26 +0200 Subject: [PATCH 07/29] Handle case sensitiveness on unit metric --- src/Html2OpenXml/Primitives/Unit.cs | 8 ++++---- test/HtmlToOpenXml.Tests/Primitives/UnitTests.cs | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Html2OpenXml/Primitives/Unit.cs b/src/Html2OpenXml/Primitives/Unit.cs index f0690104..135d88c3 100755 --- a/src/Html2OpenXml/Primitives/Unit.cs +++ b/src/Html2OpenXml/Primitives/Unit.cs @@ -46,6 +46,9 @@ public static Unit Parse(ReadOnlySpan span, UnitMetric defaultMetric = Uni return new Unit(defaultMetric, span[0] - '0'); } + Span loweredValue = span.Length <= 128 ? stackalloc char[span.Length] : new char[span.Length]; + span.ToLowerInvariant(loweredValue); + // guess the unit first than use the native Double parsing UnitMetric metric; int metricSize = 2; @@ -56,9 +59,6 @@ public static Unit Parse(ReadOnlySpan span, UnitMetric defaultMetric = Uni } else { - Span loweredValue = span.Length <= 128 ? stackalloc char[span.Length] : new char[span.Length]; - span.ToLowerInvariant(loweredValue); - var metricSpan = loweredValue.Slice(loweredValue.Length - 2, 2); metric = metricSpan switch { "in" => UnitMetric.Inch, @@ -91,7 +91,7 @@ public static Unit Parse(ReadOnlySpan span, UnitMetric defaultMetric = Uni catch (Exception) { // No digits, we ignore this style - return span is "auto"? Auto : Empty; + return loweredValue is "auto"? Auto : Empty; } return new Unit(metric, value); diff --git a/test/HtmlToOpenXml.Tests/Primitives/UnitTests.cs b/test/HtmlToOpenXml.Tests/Primitives/UnitTests.cs index 7df16f32..ad84ad46 100644 --- a/test/HtmlToOpenXml.Tests/Primitives/UnitTests.cs +++ b/test/HtmlToOpenXml.Tests/Primitives/UnitTests.cs @@ -9,6 +9,7 @@ namespace HtmlToOpenXml.Tests.Primitives class UnitTests { [TestCase("auto", 0, UnitMetric.Auto)] + [TestCase("AUTO", 0, UnitMetric.Auto, Description = "Should be case insensitive")] [TestCase("5%", 5, UnitMetric.Percent)] [TestCase(" 12 px", 12, UnitMetric.Pixel)] [TestCase(" 12 ", 12, UnitMetric.Unitless)] From 8ce2cecc235396395973fe84c02abb97d28c8e76 Mon Sep 17 00:00:00 2001 From: Olivier Nizet Date: Mon, 11 Nov 2024 22:14:34 +0100 Subject: [PATCH 08/29] Use regex compiled for performance boost --- src/Html2OpenXml/Collections/HtmlAttributeCollection.cs | 2 +- src/Html2OpenXml/Expressions/AbbreviationExpression.cs | 3 ++- .../Expressions/Numbering/HeadingElementExpression.cs | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Html2OpenXml/Collections/HtmlAttributeCollection.cs b/src/Html2OpenXml/Collections/HtmlAttributeCollection.cs index 9c4ee2f6..f1297633 100755 --- a/src/Html2OpenXml/Collections/HtmlAttributeCollection.cs +++ b/src/Html2OpenXml/Collections/HtmlAttributeCollection.cs @@ -23,7 +23,7 @@ sealed class HtmlAttributeCollection { // Encoded ':' and ';' characters are valid for browser but not handled by the regex (bug #13812 reported by robin391) // ex= - private static readonly Regex stripStyleAttributesRegex = new(@"(?.+?)(:|&\#58;)\s*(?[^;&]+)(;|&\#59;)*\s*"); + private static readonly Regex stripStyleAttributesRegex = new(@"(?[^;\s]+)\s?(&\#58;|:)\s?(?[^;&]+)\s?(;|&\#59;)*", RegexOptions.Compiled); private readonly Dictionary attributes = []; diff --git a/src/Html2OpenXml/Expressions/AbbreviationExpression.cs b/src/Html2OpenXml/Expressions/AbbreviationExpression.cs index d0dcca86..39f02bed 100644 --- a/src/Html2OpenXml/Expressions/AbbreviationExpression.cs +++ b/src/Html2OpenXml/Expressions/AbbreviationExpression.cs @@ -25,6 +25,8 @@ namespace HtmlToOpenXml.Expressions; /// sealed class AbbreviationExpression(IHtmlElement node) : PhrasingElementExpression(node) { + private static readonly Regex linkRegex = new(@"^((https?|ftps?|mailto|file)://|[\\]{2})(?:[\w][\w.-]?)", RegexOptions.Compiled); + /// public override IEnumerable Interpret(ParsingContext context) @@ -132,7 +134,6 @@ public static long AddFootnoteReference(ParsingContext context, string descripti // Description in footnote reference can be plain text or a web protocols/file share (like \\server01) - Regex linkRegex = new(@"^((https?|ftps?|mailto|file)://|[\\]{2})(?:[\w][\w.-]?)"); if (linkRegex.IsMatch(description) && Uri.TryCreate(description, UriKind.Absolute, out var uriReference)) { // when URI references a network server (ex: \\server01), System.IO.Packaging is not resolving the correct URI and this leads diff --git a/src/Html2OpenXml/Expressions/Numbering/HeadingElementExpression.cs b/src/Html2OpenXml/Expressions/Numbering/HeadingElementExpression.cs index 2c70032c..05c12938 100644 --- a/src/Html2OpenXml/Expressions/Numbering/HeadingElementExpression.cs +++ b/src/Html2OpenXml/Expressions/Numbering/HeadingElementExpression.cs @@ -23,7 +23,7 @@ namespace HtmlToOpenXml.Expressions; /// sealed class HeadingElementExpression(IHtmlElement node) : NumberingExpressionBase(node) { - private static readonly Regex numberingRegex = new(@"^\s*(\d+\.?)*\s*"); + private static readonly Regex numberingRegex = new(@"^\s*(\d+\.?)*\s*", RegexOptions.Compiled); /// public override IEnumerable Interpret (ParsingContext context) From ca5dff9df152556430370c66209a423a56089950 Mon Sep 17 00:00:00 2001 From: Olivier Nizet Date: Tue, 10 Dec 2024 22:03:06 +0100 Subject: [PATCH 09/29] Set a timeout for regex --- src/Html2OpenXml/Expressions/AbbreviationExpression.cs | 2 +- .../Expressions/Numbering/HeadingElementExpression.cs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Html2OpenXml/Expressions/AbbreviationExpression.cs b/src/Html2OpenXml/Expressions/AbbreviationExpression.cs index 39f02bed..eb01be29 100644 --- a/src/Html2OpenXml/Expressions/AbbreviationExpression.cs +++ b/src/Html2OpenXml/Expressions/AbbreviationExpression.cs @@ -25,7 +25,7 @@ namespace HtmlToOpenXml.Expressions; /// sealed class AbbreviationExpression(IHtmlElement node) : PhrasingElementExpression(node) { - private static readonly Regex linkRegex = new(@"^((https?|ftps?|mailto|file)://|[\\]{2})(?:[\w][\w.-]?)", RegexOptions.Compiled); + private static readonly Regex linkRegex = new(@"^((https?|ftps?|mailto|file)://|[\\]{2})(?:[\w][\w.-]?)", RegexOptions.Compiled, TimeSpan.FromMilliseconds(100)); /// diff --git a/src/Html2OpenXml/Expressions/Numbering/HeadingElementExpression.cs b/src/Html2OpenXml/Expressions/Numbering/HeadingElementExpression.cs index 05c12938..b115a6f0 100644 --- a/src/Html2OpenXml/Expressions/Numbering/HeadingElementExpression.cs +++ b/src/Html2OpenXml/Expressions/Numbering/HeadingElementExpression.cs @@ -9,6 +9,7 @@ * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A * PARTICULAR PURPOSE. */ +using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; @@ -23,7 +24,7 @@ namespace HtmlToOpenXml.Expressions; /// sealed class HeadingElementExpression(IHtmlElement node) : NumberingExpressionBase(node) { - private static readonly Regex numberingRegex = new(@"^\s*(\d+\.?)*\s*", RegexOptions.Compiled); + private static readonly Regex numberingRegex = new(@"^\s*(\d+\.?)*\s*", RegexOptions.Compiled, TimeSpan.FromMilliseconds(100)); /// public override IEnumerable Interpret (ParsingContext context) From 129bebbd4e28bab7588b172c09cad7047d63ce97 Mon Sep 17 00:00:00 2001 From: Olivier Nizet Date: Wed, 11 Dec 2024 22:17:54 +0100 Subject: [PATCH 10/29] Optimise parsing of Style attributes --- .../Collections/HtmlAttributeCollection.cs | 149 +++++++++++++++--- .../Expressions/PhrasingElementExpression.cs | 2 +- src/Html2OpenXml/Primitives/Margin.cs | 102 ++++++------ src/Html2OpenXml/Primitives/SideBorder.cs | 60 ++++--- src/Html2OpenXml/Primitives/Unit.cs | 10 +- src/Html2OpenXml/Utilities/Converter.cs | 25 ++- src/Html2OpenXml/Utilities/Range.cs | 16 +- src/Html2OpenXml/Utilities/SpanExtensions.cs | 71 +++++++-- .../HtmlToOpenXml.Tests.csproj | 4 +- .../Primitives/StyleParserTests.cs | 21 ++- 10 files changed, 337 insertions(+), 123 deletions(-) diff --git a/src/Html2OpenXml/Collections/HtmlAttributeCollection.cs b/src/Html2OpenXml/Collections/HtmlAttributeCollection.cs index f1297633..824fdfc1 100755 --- a/src/Html2OpenXml/Collections/HtmlAttributeCollection.cs +++ b/src/Html2OpenXml/Collections/HtmlAttributeCollection.cs @@ -11,7 +11,6 @@ */ using System; using System.Collections.Generic; -using System.Text.RegularExpressions; using DocumentFormat.OpenXml.Wordprocessing; namespace HtmlToOpenXml; @@ -19,26 +18,99 @@ namespace HtmlToOpenXml; /// /// Represents the collection of attributes present in the current html tag. /// -sealed class HtmlAttributeCollection +sealed partial class HtmlAttributeCollection { - // Encoded ':' and ';' characters are valid for browser but not handled by the regex (bug #13812 reported by robin391) - // ex= - private static readonly Regex stripStyleAttributesRegex = new(@"(?[^;\s]+)\s?(&\#58;|:)\s?(?[^;&]+)\s?(;|&\#59;)*", RegexOptions.Compiled); + private readonly string rawValue; + // Style key associated with a pointer to rawValue. + private readonly Dictionary attributes = []; - private readonly Dictionary attributes = []; - - private HtmlAttributeCollection() + private HtmlAttributeCollection(string htmlStyles) { + rawValue = htmlStyles; } + /// + /// Gets a value that indicates whether this collection is empty. + /// + public bool IsEmpty => attributes.Count == 0; + public static HtmlAttributeCollection ParseStyle(string? htmlStyles) { - var collection = new HtmlAttributeCollection(); + var collection = new HtmlAttributeCollection(htmlStyles!); if (string.IsNullOrWhiteSpace(htmlStyles)) return collection; - MatchCollection matches = stripStyleAttributesRegex.Matches(htmlStyles); - foreach (Match m in matches) - collection.attributes[m.Groups["name"].Value] = m.Groups["val"].Value.TrimEnd(); + var span = htmlStyles.AsSpan(); + + // Encoded ':' and ';' characters are valid for browser + // + + int startIndex = 0; + bool foundKey = false; + string? key = null; + while (span.Length > 0) + { + int index = span.IndexOfAny(';', '&', ':'); + if (index == -1) + { + if (!foundKey) break; + index = span.Length; + } + + int separatorSize = 0; + if (!foundKey) + { + if (span.Slice(index).StartsWith(['&','#','5','8',';'])) + { + separatorSize = 5; + } + else if (span[index] == ':') + { + separatorSize = 1; + } + else + { + // unexpected semicolon (ie, key with no value) -> ignore this style + separatorSize = -1; + } + + if (separatorSize > 0 && index > 0) + { + key = span.Slice(0, index).ToString().Trim(); + foundKey = true; + } + } + else + { + if (index < span.Length) + { + if (span.Slice(index).StartsWith(['&','#','5','9',';'])) + { + separatorSize = 5; + } + else if (span[index] == ';') + { + separatorSize = 1; + } + else if (span[index] == ':') + { + // unexpected colon (ie, key:value:value) -> ignore this style + separatorSize = -1; + foundKey = false; + } + } + + if (foundKey) + { + if (index > 0) + collection.attributes[key!] = new Range(startIndex, startIndex + index); + foundKey = false; + } + } + + separatorSize = Math.Abs(separatorSize); + startIndex += index + separatorSize; + span = span.Slice(index + separatorSize); + } return collection; } @@ -48,7 +120,12 @@ public static HtmlAttributeCollection ParseStyle(string? htmlStyles) /// public string? this[string name] { - get => attributes.TryGetValue(name, out var value)? value : null; + get + { + if (attributes.TryGetValue(name, out var range)) + return rawValue.AsSpan().Slice(range).ToString().Trim(); + return null; + } } /// @@ -57,7 +134,9 @@ public string? this[string name] /// public HtmlColor GetColor(string name) { - return HtmlColor.Parse(this[name]); + if (attributes.TryGetValue(name, out var range)) + return HtmlColor.Parse(rawValue.AsSpan().Slice(range)); + return HtmlColor.Empty; } /// @@ -66,7 +145,9 @@ public HtmlColor GetColor(string name) /// If the attribute is misformed, the property is set to false. public Unit GetUnit(string name, UnitMetric defaultMetric = UnitMetric.Unitless) { - return Unit.Parse(this[name], defaultMetric); + if (attributes.TryGetValue(name, out var range)) + return Unit.Parse(rawValue.AsSpan().Slice(range), defaultMetric); + return Unit.Empty; } /// @@ -76,7 +157,10 @@ public Unit GetUnit(string name, UnitMetric defaultMetric = UnitMetric.Unitless) /// If the attribute is misformed, the property is set to false. public Margin GetMargin(string name) { - Margin margin = Margin.Parse(this[name]); + Margin margin = Margin.Empty; + if (attributes.TryGetValue(name, out var range)) + margin = Margin.Parse(rawValue.AsSpan().Slice(range)); + Unit u; u = GetUnit(name + "-top", UnitMetric.Pixel); @@ -120,24 +204,33 @@ public HtmlBorder GetBorders() /// If the attribute is misformed, the property is set to false. public SideBorder GetSideBorder(string name) { - var attrValue = this[name]; - SideBorder border = SideBorder.Parse(attrValue); + SideBorder border = SideBorder.Empty; + if (attributes.TryGetValue(name, out Range range)) + border = SideBorder.Parse(rawValue.AsSpan().Slice(range)); // handle attributes specified individually. - Unit width = SideBorder.ParseWidth(this[name + "-width"]); - if (!width.IsValid) width = border.Width; + Unit width = border.Width; + if (attributes.TryGetValue(name + "-width", out range)) + { + var w = SideBorder.ParseWidth(rawValue.AsSpan().Slice(range)); + if (width.IsValid) width = w; + } var color = GetColor(name + "-color"); if (color.IsEmpty) color = border.Color; - var style = Converter.ToBorderStyle(this[name + "-style"]); - if (style == BorderValues.Nil) style = border.Style; + BorderValues style = border.Style; + if (attributes.TryGetValue(name + "-style", out range)) + { + var s = Converter.ToBorderStyle(rawValue.AsSpan().Slice(range)); + if (s != BorderValues.Nil) style = s; + } return new SideBorder(style, color, width); } /// - /// Gets the font attribute and combine with the style, size and family. + /// Gets the `font` attribute and combine with the style, size and family. /// public HtmlFont GetFont(string name) { @@ -174,4 +267,14 @@ public HtmlFont GetFont(string name) return new HtmlFont(fontStyle, variant, weight, fontSize, family); } + + /// + /// Gets the composite `text-decoration` style. + /// + public IEnumerable GetTextDecorations(string name) + { + if (attributes.TryGetValue(name, out Range range)) + return Converter.ToTextDecoration(rawValue.AsSpan().Slice(range)); + return []; + } } diff --git a/src/Html2OpenXml/Expressions/PhrasingElementExpression.cs b/src/Html2OpenXml/Expressions/PhrasingElementExpression.cs index c7619824..86646fd7 100644 --- a/src/Html2OpenXml/Expressions/PhrasingElementExpression.cs +++ b/src/Html2OpenXml/Expressions/PhrasingElementExpression.cs @@ -131,7 +131,7 @@ protected virtual void ComposeStyles (ParsingContext context) runProperties.Shading = new Shading { Val = ShadingPatternValues.Clear, Fill = bgcolor.ToHexString() }; } - foreach (var decoration in Converter.ToTextDecoration(styleAttributes["text-decoration"])) + foreach (var decoration in styleAttributes.GetTextDecorations("text-decoration")) { switch (decoration) { diff --git a/src/Html2OpenXml/Primitives/Margin.cs b/src/Html2OpenXml/Primitives/Margin.cs index 8aa962ff..21205fbf 100755 --- a/src/Html2OpenXml/Primitives/Margin.cs +++ b/src/Html2OpenXml/Primitives/Margin.cs @@ -20,10 +20,29 @@ namespace HtmlToOpenXml; struct Margin { /// Represents an empty margin (not defined). - public static readonly Margin Empty = new(); + public static readonly Margin Empty = new() { sides = new Unit[4] }; private Unit[] sides; + /// Apply to all four sides. + public Margin(Unit all) + { + this.sides = [all, all, all, all]; + } + + /// Top and bottom | left and right. + public Margin(Unit topAndBottom, Unit leftAndRight) + { + this.sides = [topAndBottom, leftAndRight, topAndBottom, leftAndRight]; + } + + /// Top | left and right | bottom. + public Margin(Unit top, Unit leftAndRight, Unit bottom) + { + this.sides = [top, leftAndRight, bottom, leftAndRight]; + } + + /// Top | right | bottom | left. public Margin(Unit top, Unit right, Unit bottom, Unit left) { this.sides = [top, right, bottom, left]; @@ -54,47 +73,34 @@ public Margin(Unit top, Unit right, Unit bottom, Unit left) /// public static Margin Parse(string? str) { - if (string.IsNullOrWhiteSpace(str)) + if (str == null) return Empty; - - var span = str!.AsSpan(); - Span tokens = stackalloc Range[5]; - switch (span.Split(tokens, ' ', StringSplitOptions.RemoveEmptyEntries)) - { - case 1: - { - Unit all = Unit.Parse(span.Slice(tokens[0]), UnitMetric.Pixel); - return new Margin(all, all, all, all); - } - case 2: - { - Unit u1 = Unit.Parse(span.Slice(tokens[0]), UnitMetric.Pixel); - Unit u2 = Unit.Parse(span.Slice(tokens[1]), UnitMetric.Pixel); - return new Margin(u1, u2, u1, u2); - } - case 3: - { - Unit u1 = Unit.Parse(span.Slice(tokens[0]), UnitMetric.Pixel); - Unit u2 = Unit.Parse(span.Slice(tokens[1]), UnitMetric.Pixel); - Unit u3 = Unit.Parse(span.Slice(tokens[2]), UnitMetric.Pixel); - return new Margin(u1, u2, u3, u2); - } - case 4: - { - Unit u1 = Unit.Parse(span.Slice(tokens[0]), UnitMetric.Pixel); - Unit u2 = Unit.Parse(span.Slice(tokens[1]), UnitMetric.Pixel); - Unit u3 = Unit.Parse(span.Slice(tokens[2]), UnitMetric.Pixel); - Unit u4 = Unit.Parse(span.Slice(tokens[3]), UnitMetric.Pixel); - return new Margin(u1, u2, u3, u4); - } - } - - return Empty; + return Parse(str.AsSpan()); } - private void EnsureSides() + public static Margin Parse(ReadOnlySpan span) { - if (this.sides == null) sides = new Unit[4]; + if (span.Length == 0 || span.IsWhiteSpace()) + return Empty; + + Span tokens = stackalloc Range[5]; + return span.SplitHtmlCompositeAttribute(tokens) switch + { + 1 => new Margin(Unit.Parse(span.Slice(tokens[0]), UnitMetric.Pixel)), + 2 => new Margin( + Unit.Parse(span.Slice(tokens[0]), UnitMetric.Pixel), + Unit.Parse(span.Slice(tokens[1]), UnitMetric.Pixel)), + 3 => new Margin( + Unit.Parse(span.Slice(tokens[0]), UnitMetric.Pixel), + Unit.Parse(span.Slice(tokens[1]), UnitMetric.Pixel), + Unit.Parse(span.Slice(tokens[2]), UnitMetric.Pixel)), + 4 => new Margin( + Unit.Parse(span.Slice(tokens[0]), UnitMetric.Pixel), + Unit.Parse(span.Slice(tokens[1]), UnitMetric.Pixel), + Unit.Parse(span.Slice(tokens[2]), UnitMetric.Pixel), + Unit.Parse(span.Slice(tokens[3]), UnitMetric.Pixel)), + _ => Empty + }; } //____________________________________________________________________ @@ -105,8 +111,8 @@ private void EnsureSides() /// public Unit Bottom { - readonly get { return sides == null ? Unit.Empty : sides[2]; } - set { EnsureSides(); sides[2] = value; } + readonly get => sides[2]; + set { sides[2] = value; } } /// @@ -114,8 +120,8 @@ public Unit Bottom /// public Unit Left { - readonly get { return sides == null ? Unit.Empty : sides[3]; } - set { EnsureSides(); sides[3] = value; } + readonly get => sides[3]; + set { sides[3] = value; } } /// @@ -123,8 +129,8 @@ public Unit Left /// public Unit Top { - readonly get { return sides == null ? Unit.Empty : sides[0]; } - set { EnsureSides(); sides[0] = value; } + readonly get => sides[0]; + set { sides[0] = value; } } /// @@ -132,13 +138,13 @@ public Unit Top /// public Unit Right { - readonly get { return sides == null ? Unit.Empty : sides[1]; } - set { EnsureSides(); sides[1] = value; } + readonly get => sides[1]; + set { sides[1] = value; } } public readonly bool IsValid { - get => sides != null && Left.IsValid && Right.IsValid && Bottom.IsValid && Top.IsValid; + get => Left.IsValid && Right.IsValid && Bottom.IsValid && Top.IsValid; } /// @@ -146,6 +152,6 @@ public readonly bool IsValid /// public readonly bool IsEmpty { - get => sides == null || !(Left.IsValid || Right.IsValid || Bottom.IsValid || Top.IsValid); + get => !(Left.IsValid || Right.IsValid || Bottom.IsValid || Top.IsValid); } } diff --git a/src/Html2OpenXml/Primitives/SideBorder.cs b/src/Html2OpenXml/Primitives/SideBorder.cs index ea268da6..cc852cd0 100755 --- a/src/Html2OpenXml/Primitives/SideBorder.cs +++ b/src/Html2OpenXml/Primitives/SideBorder.cs @@ -11,13 +11,13 @@ */ using System; using System.Collections.Generic; -using System.Text.RegularExpressions; +using System.Linq; using DocumentFormat.OpenXml.Wordprocessing; namespace HtmlToOpenXml; /// -/// Represents a Html Unit (ie: 120px, 10em, ...). +/// Represents a Html border (ie: 1.2px solid blue...). /// readonly struct SideBorder(BorderValues style, HtmlColor color, Unit size) { @@ -30,17 +30,24 @@ readonly struct SideBorder(BorderValues style, HtmlColor color, Unit size) public static SideBorder Parse(string? str) { - if (str == null) return SideBorder.Empty; + if (str == null) return Empty; + return Parse(str.AsSpan()); + } + public static SideBorder Parse(ReadOnlySpan span) + { // The properties of a border that can be set, are (in order): border-width, border-style, and border-color. // It does not matter if one of the values above are missing, e.g. border:solid #ff0000; is allowed. // The main problem for parsing this attribute is that the browsers allow any permutation of the values... meaning more coding :( // http://www.w3schools.com/cssref/pr_border.asp - // Remove the spaces that could appear in the color parameter: rgb(233, 233, 233) -> rgb(233,233,233) - str = Regex.Replace(str, @",\s+?", ","); - var borderParts = new List(str.Split(HttpUtility.WhiteSpaces, StringSplitOptions.RemoveEmptyEntries)); - if (borderParts.Count == 0) return SideBorder.Empty; + if (span.Length < 2) + return Empty; + + Span tokens = stackalloc Range[6]; + var tokenCount = span.SplitHtmlCompositeAttribute(tokens); + if (tokenCount == 0) + return Empty; // Initialize default values Unit borderWidth = Unit.Empty; @@ -48,34 +55,35 @@ public static SideBorder Parse(string? str) BorderValues borderStyle = BorderValues.Nil; // Now try to guess the values with their permutation + var tokenIndexes = new List(Enumerable.Range(0, tokenCount)); // handle border style - for (int i = 0; i < borderParts.Count; i++) + for (int i = 0; i < tokenIndexes.Count; i++) { - borderStyle = Converter.ToBorderStyle(borderParts[i]); + borderStyle = Converter.ToBorderStyle(span.Slice(tokens[tokenIndexes[i]])); if (borderStyle != BorderValues.Nil) { - borderParts.RemoveAt(i); // no need to process this part anymore + tokenIndexes.RemoveAt(i); // no need to process this part anymore break; } } - for (int i = 0; i < borderParts.Count; i++) + for (int i = 0; i < tokenIndexes.Count; i++) { - borderWidth = ParseWidth(borderParts[i]); + borderWidth = ParseWidth(span.Slice(tokens[tokenIndexes[i]])); if (borderWidth.IsValid) { - borderParts.RemoveAt(i); // no need to process this part anymore + tokenIndexes.RemoveAt(i); // no need to process this part anymore break; } } // find width - if(borderParts.Count > 0) - borderColor = HtmlColor.Parse(borderParts[0]); + if(tokenIndexes.Count > 0) + borderColor = HtmlColor.Parse(span.Slice(tokens[tokenIndexes[0]])); if (borderColor.IsEmpty && !borderWidth.IsValid && borderStyle == BorderValues.Nil) - return SideBorder.Empty; + return Empty; // returns the instance with default value if needed. // These value are the ones used by the browser, i.e: solid 3px black @@ -85,25 +93,27 @@ public static SideBorder Parse(string? str) borderWidth.IsFixed? borderWidth : new Unit(UnitMetric.Pixel, 4)); } - internal static Unit ParseWidth(string? borderWidth) + internal static Unit ParseWidth(ReadOnlySpan borderWidth) { Unit bu = Unit.Parse(borderWidth, UnitMetric.Pixel); if (bu.IsValid) { if (bu.Value > 0 && bu.Metric == UnitMetric.Pixel) return bu; + return Unit.Empty; } else { - switch (borderWidth) - { - case "thin": return new Unit(UnitMetric.Pixel, 1); - case "medium": return new Unit(UnitMetric.Pixel, 3); - case "thick": return new Unit(UnitMetric.Pixel, 5); - } + Span loweredValue = borderWidth.Length <= 128 ? stackalloc char[borderWidth.Length] : new char[borderWidth.Length]; + borderWidth.ToLowerInvariant(loweredValue); + + return loweredValue switch { + "thin" => new Unit(UnitMetric.Pixel, 1), + "medium" => new Unit(UnitMetric.Pixel, 3), + "thick" => new Unit(UnitMetric.Pixel, 5), + _ => Unit.Empty, + }; } - - return Unit.Empty; } //____________________________________________________________________ diff --git a/src/Html2OpenXml/Primitives/Unit.cs b/src/Html2OpenXml/Primitives/Unit.cs index 135d88c3..e5d5dc18 100755 --- a/src/Html2OpenXml/Primitives/Unit.cs +++ b/src/Html2OpenXml/Primitives/Unit.cs @@ -16,7 +16,7 @@ namespace HtmlToOpenXml; /// /// Represents a Html Unit (ie: 120px, 10em, ...). /// -[System.Diagnostics.DebuggerDisplay("Unit: {Value} {Type}")] +[System.Diagnostics.DebuggerDisplay("Unit: {Value} {Metric}")] readonly struct Unit { /// Represents an empty unit (not defined). @@ -158,7 +158,7 @@ public UnitMetric Metric /// /// Gets the value of this unit. /// - public Double Value + public double Value { get { return value; } } @@ -166,7 +166,7 @@ public Double Value /// /// Gets the value expressed in English Metrics Unit. /// - public Int64 ValueInEmus + public long ValueInEmus { get { return valueInEmus; } } @@ -174,9 +174,9 @@ public Int64 ValueInEmus /// /// Gets the value expressed in Dxa unit. /// - public Int64 ValueInDxa + public long ValueInDxa { - get { return (long) (((double) valueInEmus / 914400L) * 20 * 72); } + get { return (long) ((double) valueInEmus / 914400L * 20 * 72); } } /// diff --git a/src/Html2OpenXml/Utilities/Converter.cs b/src/Html2OpenXml/Utilities/Converter.cs index 61f899d1..d5c5ef97 100755 --- a/src/Html2OpenXml/Utilities/Converter.cs +++ b/src/Html2OpenXml/Utilities/Converter.cs @@ -144,10 +144,15 @@ public static Unit ToFontSize(string? htmlSize) return null; } - public static BorderValues ToBorderStyle(string? borderStyle) + public static BorderValues ToBorderStyle(ReadOnlySpan borderStyle) { - if (borderStyle == null) return BorderValues.Nil; - return borderStyle.ToLowerInvariant() switch + if (borderStyle.IsEmpty) + return BorderValues.Nil; + + Span loweredValue = borderStyle.Length <= 128 ? stackalloc char[borderStyle.Length] : new char[borderStyle.Length]; + borderStyle.ToLowerInvariant(loweredValue); + + return loweredValue switch { "dotted" => BorderValues.Dotted, "dashed" => BorderValues.Dashed, @@ -168,17 +173,23 @@ public static PageOrientationValues ToPageOrientation(string? orientation) return PageOrientationValues.Portrait; } - public static IEnumerable ToTextDecoration(string? html) + public static ICollection ToTextDecoration(ReadOnlySpan values) { // this style could take multiple values separated by a space // ex: text-decoration: blink underline; var decorations = new List(); + if (values.IsEmpty) return decorations; + + Span loweredValue = values.Length <= 128 ? stackalloc char[values.Length] : new char[values.Length]; + values.ToLowerInvariant(loweredValue); - if (html == null) return decorations; - foreach (string part in html.ToLowerInvariant().Split(' ')) + Span tokens = stackalloc Range[5]; + ReadOnlySpan span = loweredValue; + var tokenCount = span.Split(tokens, ' ', StringSplitOptions.RemoveEmptyEntries); + for (int i = 0; i < tokenCount; i++) { - switch (part) + switch (span.Slice(tokens[i])) { case "underline": decorations.Add(TextDecoration.Underline); break; case "line-through": decorations.Add(TextDecoration.LineThrough); break; diff --git a/src/Html2OpenXml/Utilities/Range.cs b/src/Html2OpenXml/Utilities/Range.cs index e0d8eea9..7d89ba4a 100644 --- a/src/Html2OpenXml/Utilities/Range.cs +++ b/src/Html2OpenXml/Utilities/Range.cs @@ -9,9 +9,11 @@ * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A * PARTICULAR PURPOSE. */ +#if !NET5_0_OR_GREATER namespace System; -#if !NET5_0_OR_GREATER +using System.Runtime.CompilerServices; + readonly struct Range(int start, int end) { /// Represent the inclusive start index of the Range. @@ -19,5 +21,17 @@ readonly struct Range(int start, int end) /// Represent the exclusive end index of the Range. public int End { get; } = end; + + /// Calculate the start offset and length of range object using a collection length. + /// + /// For performance reason, we don't validate the input length parameter against negative values. + /// It is expected Range will be used with collections which always have non negative length/count. + /// We validate the range is inside the length scope though. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public (int Offset, int Length) GetOffsetAndLength(int _) + { + return (Start, End - Start); + } } #endif \ No newline at end of file diff --git a/src/Html2OpenXml/Utilities/SpanExtensions.cs b/src/Html2OpenXml/Utilities/SpanExtensions.cs index 75e65162..97b0ca27 100644 --- a/src/Html2OpenXml/Utilities/SpanExtensions.cs +++ b/src/Html2OpenXml/Utilities/SpanExtensions.cs @@ -72,7 +72,8 @@ public static ReadOnlySpan Slice(this ReadOnlySpan span, Range range) #if NET5_0_OR_GREATER return span[range]; #else - return span.Slice(range.Start, range.End); + var (start, length) = range.GetOffsetAndLength(span.Length); + return span.Slice(start, length); #endif } @@ -95,30 +96,80 @@ public static int Split(this ReadOnlySpan span, Span destination, return 0; int matches = 0; - int index = 0; + int startIndex = 0; while (span.Length > 0) { - int tokenEnd = span.IndexOf(separator); - if (tokenEnd == -1) tokenEnd = span.Length; - if (options == StringSplitOptions.RemoveEmptyEntries && tokenEnd == 0) + int index = span.IndexOf(separator); + if (index == -1) index = span.Length; + if (options == StringSplitOptions.RemoveEmptyEntries && index == 0) { span = span.Slice(1); - index++; + startIndex++; continue; } - destination[matches] = new Range(index, tokenEnd); + destination[matches] = new Range(startIndex, startIndex + index); matches++; - if (matches >= destination.Length || span.Length <= tokenEnd) + if (matches >= destination.Length || span.Length <= index) break; // move to next token - span = span.Slice(tokenEnd + 1); - index += tokenEnd + 1; + span = span.Slice(index + 1); + startIndex += index + 1; } return matches; } #endif + + /// + /// Parses the source for the specified style attribute separators, + /// populating the span with instances + /// representing the regions between the separators. + /// + /// The source span to parse. + /// The destination span into which the resulting ranges are written. + /// The number of ranges written into . + public static int SplitHtmlCompositeAttribute(this ReadOnlySpan span, Span destination) + { + // If the destination is empty, there's nothing to do. + if (destination.IsEmpty) + return 0; + + int matches = 0; + int startIndex = 0; + bool escapeSpace = false; + while (span.Length > 0) + { + // Remove the spaces that could appear in the color parameter: rgb(233, 233, 233) -> rgb(233,233,233) + int index = escapeSpace? span.IndexOf(')') : span.IndexOfAny(' ', '('); + if (index == -1) index = span.Length; + else if (span[index] == '(') + { + escapeSpace = true; + continue; + } + else if (span[index] == ')') + { + escapeSpace = false; + index++; // include that closing parenthesis in the range + } + + if (!escapeSpace && index > 0) + { + destination[matches] = new Range(startIndex, startIndex + index); + matches++; + } + startIndex += index + 1; + + if (matches >= destination.Length || span.Length <= index) + break; + + // move to next token + span = span.Slice(index + 1); + } + + return matches; + } } diff --git a/test/HtmlToOpenXml.Tests/HtmlToOpenXml.Tests.csproj b/test/HtmlToOpenXml.Tests/HtmlToOpenXml.Tests.csproj index e781a424..e47cc14d 100755 --- a/test/HtmlToOpenXml.Tests/HtmlToOpenXml.Tests.csproj +++ b/test/HtmlToOpenXml.Tests/HtmlToOpenXml.Tests.csproj @@ -16,11 +16,11 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - + - + all runtime; build; native; contentfiles; analyzers diff --git a/test/HtmlToOpenXml.Tests/Primitives/StyleParserTests.cs b/test/HtmlToOpenXml.Tests/Primitives/StyleParserTests.cs index aa2516bd..73390e3b 100644 --- a/test/HtmlToOpenXml.Tests/Primitives/StyleParserTests.cs +++ b/test/HtmlToOpenXml.Tests/Primitives/StyleParserTests.cs @@ -3,7 +3,7 @@ namespace HtmlToOpenXml.Tests.Primitives { /// - /// Tests Html color style attribute. + /// Tests parsing the `style` attribute. /// [TestFixture] public class StyleParserTests @@ -25,5 +25,24 @@ public void DuplicateStyle_ReturnsLatter() var styleAttributes = HtmlAttributeCollection.ParseStyle("color:red;color:blue"); Assert.That(styleAttributes["color"], Is.EqualTo("blue")); } + + [TestCase("color;color;")] + [TestCase(":;")] + [TestCase("color:red:red")] + [TestCase("color:;")] + public void InvalidStyle_ShouldBeEmpty(string htmlStyle) + { + var styles = HtmlAttributeCollection.ParseStyle(htmlStyle); + Assert.That(styles.IsEmpty, Is.True); + Assert.That(styles["color"], Is.Null); + } + + [Test] + public void WithMultipleTextDecoration_Should() + { + var styles = HtmlAttributeCollection.ParseStyle("text-decoration:underline dotted wavy"); + var decorations = styles.GetTextDecorations("text-decoration"); + Assert.That(decorations, Is.EquivalentTo(new [] { TextDecoration.Underline, TextDecoration.Dotted, TextDecoration.Wave })); + } } } From 66834d84151528880d0be5bbddac5f9436d63f10 Mon Sep 17 00:00:00 2001 From: Olivier Nizet Date: Thu, 12 Dec 2024 15:54:26 +0100 Subject: [PATCH 11/29] Ensure to catch regex timeout exception --- .../Expressions/AbbreviationExpression.cs | 11 ++++++++++- .../Numbering/HeadingElementExpression.cs | 10 +++++++++- src/Html2OpenXml/IO/DataUri.cs | 18 ++++++++++++------ 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/Html2OpenXml/Expressions/AbbreviationExpression.cs b/src/Html2OpenXml/Expressions/AbbreviationExpression.cs index eb01be29..69815322 100644 --- a/src/Html2OpenXml/Expressions/AbbreviationExpression.cs +++ b/src/Html2OpenXml/Expressions/AbbreviationExpression.cs @@ -134,7 +134,16 @@ public static long AddFootnoteReference(ParsingContext context, string descripti // Description in footnote reference can be plain text or a web protocols/file share (like \\server01) - if (linkRegex.IsMatch(description) && Uri.TryCreate(description, UriKind.Absolute, out var uriReference)) + bool isValidLink; + try + { + isValidLink = linkRegex.IsMatch(description); + } + catch (RegexMatchTimeoutException) + { + isValidLink = false; + } + if (isValidLink && Uri.TryCreate(description, UriKind.Absolute, out var uriReference)) { // when URI references a network server (ex: \\server01), System.IO.Packaging is not resolving the correct URI and this leads // to a bad-formed XML not recognized by Word. To enforce the "original URI", a fresh new instance must be created diff --git a/src/Html2OpenXml/Expressions/Numbering/HeadingElementExpression.cs b/src/Html2OpenXml/Expressions/Numbering/HeadingElementExpression.cs index b115a6f0..94dd83a8 100644 --- a/src/Html2OpenXml/Expressions/Numbering/HeadingElementExpression.cs +++ b/src/Html2OpenXml/Expressions/Numbering/HeadingElementExpression.cs @@ -68,7 +68,15 @@ private static bool IsNumbering(OpenXmlElement runElement) { // Check if the line starts with a number format (1., 1.1., 1.1.1.) // If it does, make sure we make the heading a numbered item - Match regexMatch = numberingRegex.Match(runElement.InnerText ?? string.Empty); + Match regexMatch; + try + { + regexMatch = numberingRegex.Match(runElement.InnerText ?? string.Empty); + } + catch (RegexMatchTimeoutException) + { + return false; + } // Make sure we only grab the heading if it starts with a number if (regexMatch.Groups.Count > 1 && regexMatch.Groups[1].Captures.Count > 0) diff --git a/src/Html2OpenXml/IO/DataUri.cs b/src/Html2OpenXml/IO/DataUri.cs index 918783fa..3128855b 100755 --- a/src/Html2OpenXml/IO/DataUri.cs +++ b/src/Html2OpenXml/IO/DataUri.cs @@ -23,7 +23,8 @@ public sealed class DataUri { private readonly static Regex dataUriRegex = new Regex( @"data\:(?\w+/\w+)?(?:;charset=(?[a-zA-Z_0-9-]+))?(?;base64)?,(?.*)", - RegexOptions.IgnoreCase | RegexOptions.Singleline); + RegexOptions.IgnoreCase | RegexOptions.Singleline, + TimeSpan.FromMilliseconds(200)); private DataUri(string mime, byte[] data) { @@ -50,12 +51,17 @@ public static bool TryCreate(string uri, out DataUri? result) // while Internet Explorer requires that the charset's specification must precede the base64 token. // http://en.wikipedia.org/wiki/Data_URI_scheme - // We will stick for IE compliance for the moment... - - Match match = dataUriRegex.Match(uri); + Match match; result = null; - - if (!match.Success) return false; + try + { + match = dataUriRegex.Match(uri); + if (!match.Success) return false; + } + catch (RegexMatchTimeoutException) + { + return false; + } byte[] rawData; string mime; From 4f516aaa4772c47b419a7f7b185934f7b38b19c3 Mon Sep 17 00:00:00 2001 From: Olivier Nizet Date: Thu, 12 Dec 2024 16:15:59 +0100 Subject: [PATCH 12/29] Prefer usage of await and async method --- examples/Demo/Program.cs | 4 ++-- src/Html2OpenXml/IO/ImagePrefetcher.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/Demo/Program.cs b/examples/Demo/Program.cs index 47c0124b..d026fb8b 100644 --- a/examples/Demo/Program.cs +++ b/examples/Demo/Program.cs @@ -24,7 +24,7 @@ static async Task Main(string[] args) // instead of creating it from scratch. using (var buffer = ResourceHelper.GetStream("Resources.template.docx")) { - buffer.CopyTo(generatedDocument); + await buffer.CopyToAsync(generatedDocument); } generatedDocument.Position = 0L; @@ -48,7 +48,7 @@ static async Task Main(string[] args) AssertThatOpenXmlDocumentIsValid(package); } - File.WriteAllBytes(filename, generatedDocument.ToArray()); + await File.WriteAllBytesAsync(filename, generatedDocument.ToArray()); } Process.Start(new ProcessStartInfo(filename) { UseShellExecute = true }); diff --git a/src/Html2OpenXml/IO/ImagePrefetcher.cs b/src/Html2OpenXml/IO/ImagePrefetcher.cs index 9ff6dfc3..f074358b 100644 --- a/src/Html2OpenXml/IO/ImagePrefetcher.cs +++ b/src/Html2OpenXml/IO/ImagePrefetcher.cs @@ -125,7 +125,7 @@ public ImagePrefetcher(T hostingPart, IWebRequest resourceLoader) Size originalSize; using (var outputStream = ipart.GetStream(FileMode.Create)) { - response.Content.CopyTo(outputStream); + await response.Content.CopyToAsync(outputStream); outputStream.Seek(0L, SeekOrigin.Begin); originalSize = GetImageSize(outputStream); From 19c263fb10ad798caeb04558e822300df2c8db8e Mon Sep 17 00:00:00 2001 From: Olivier Nizet Date: Sat, 14 Dec 2024 14:33:21 +0100 Subject: [PATCH 13/29] Optimise parsing of Style attributes --- .../Collections/HtmlAttributeCollection.cs | 39 +++--- .../Expressions/FontElementExpression.cs | 2 +- src/Html2OpenXml/Primitives/HtmlColor.cs | 22 ++-- src/Html2OpenXml/Primitives/HtmlFont.cs | 112 ++++++++++++----- src/Html2OpenXml/Primitives/Margin.cs | 19 +-- src/Html2OpenXml/Primitives/SideBorder.cs | 2 +- src/Html2OpenXml/Utilities/Converter.cs | 114 +++++++++--------- src/Html2OpenXml/Utilities/SpanExtensions.cs | 69 +++++++++-- .../Primitives/FontTests.cs | 63 ++++++++++ .../Primitives/StyleParserTests.cs | 2 +- 10 files changed, 300 insertions(+), 144 deletions(-) create mode 100644 test/HtmlToOpenXml.Tests/Primitives/FontTests.cs diff --git a/src/Html2OpenXml/Collections/HtmlAttributeCollection.cs b/src/Html2OpenXml/Collections/HtmlAttributeCollection.cs index 824fdfc1..d8f4c1ee 100755 --- a/src/Html2OpenXml/Collections/HtmlAttributeCollection.cs +++ b/src/Html2OpenXml/Collections/HtmlAttributeCollection.cs @@ -20,9 +20,10 @@ namespace HtmlToOpenXml; /// sealed partial class HtmlAttributeCollection { - private readonly string rawValue; // Style key associated with a pointer to rawValue. private readonly Dictionary attributes = []; + private readonly string rawValue; + private HtmlAttributeCollection(string htmlStyles) { @@ -59,6 +60,7 @@ public static HtmlAttributeCollection ParseStyle(string? htmlStyles) int separatorSize = 0; if (!foundKey) { + // html-encoded semicolon if (span.Slice(index).StartsWith(['&','#','5','8',';'])) { separatorSize = 5; @@ -83,6 +85,7 @@ public static HtmlAttributeCollection ParseStyle(string? htmlStyles) { if (index < span.Length) { + // html-encoded colon if (span.Slice(index).StartsWith(['&','#','5','9',';'])) { separatorSize = 5; @@ -234,38 +237,44 @@ public SideBorder GetSideBorder(string name) /// public HtmlFont GetFont(string name) { - HtmlFont font = HtmlFont.Parse(this[name]); + HtmlFont font = HtmlFont.Empty; + if (attributes.TryGetValue(name, out Range range)) + font = HtmlFont.Parse(rawValue.AsSpan().Slice(range)); + FontStyle? fontStyle = font.Style; FontVariant? variant = font.Variant; FontWeight? weight = font.Weight; Unit fontSize = font.Size; string? family = font.Family; - var attrValue = this[name + "-style"]; - if (attrValue != null) + if (attributes.TryGetValue(name + "-style", out range)) { - fontStyle = Converter.ToFontStyle(attrValue) ?? font.Style; + var s = Converter.ToFontStyle(rawValue.AsSpan().Slice(range)); + if (s.HasValue) fontStyle = s; } - attrValue = this[name + "-variant"]; - if (attrValue != null) + + if (attributes.TryGetValue(name + "-variant", out range)) { - variant = Converter.ToFontVariant(attrValue) ?? font.Variant; + var v = Converter.ToFontVariant(rawValue.AsSpan().Slice(range)); + if (v.HasValue) variant = v; } - attrValue = this[name + "-weight"]; - if (attrValue != null) + + if (attributes.TryGetValue(name + "-weight", out range)) { - weight = Converter.ToFontWeight(attrValue) ?? font.Weight; + var w = Converter.ToFontWeight(rawValue.AsSpan().Slice(range)); + if (w.HasValue) weight = w; } - attrValue = this[name + "-family"]; - if (attrValue != null) + + if (attributes.TryGetValue(name + "-family", out range)) { - family = Converter.ToFontFamily(attrValue) ?? font.Family; + var f = Converter.ToFontFamily(rawValue.AsSpan().Slice(range)); + if (f != null) family = f; } Unit unit = this.GetUnit(name + "-size"); if (unit.IsValid) fontSize = unit; - return new HtmlFont(fontStyle, variant, weight, fontSize, family); + return new HtmlFont(fontSize, family, fontStyle, variant, weight); } /// diff --git a/src/Html2OpenXml/Expressions/FontElementExpression.cs b/src/Html2OpenXml/Expressions/FontElementExpression.cs index 88f47b8d..2fc8c285 100644 --- a/src/Html2OpenXml/Expressions/FontElementExpression.cs +++ b/src/Html2OpenXml/Expressions/FontElementExpression.cs @@ -27,7 +27,7 @@ protected override void ComposeStyles(ParsingContext context) string? attrValue = node.GetAttribute("size"); if (!string.IsNullOrEmpty(attrValue)) { - Unit fontSize = Converter.ToFontSize(attrValue); + Unit fontSize = Converter.ToFontSize(attrValue.AsSpan()); if (fontSize.IsFixed) runProperties.FontSize = new() { Val = Math.Round(fontSize.ValueInPoint * 2).ToString(CultureInfo.InvariantCulture) }; diff --git a/src/Html2OpenXml/Primitives/HtmlColor.cs b/src/Html2OpenXml/Primitives/HtmlColor.cs index 975dcf37..b059836f 100755 --- a/src/Html2OpenXml/Primitives/HtmlColor.cs +++ b/src/Html2OpenXml/Primitives/HtmlColor.cs @@ -237,21 +237,15 @@ public static HtmlColor FromHsl(double alpha, double hue, double saturation, dou byte iMid = Convert.ToByte(fMid * 255); byte iMin = Convert.ToByte(fMin * 255); - switch (iSextant) + return iSextant switch { - case 1: - return FromArgb(alpha, iMid, iMax, iMin); - case 2: - return FromArgb(alpha, iMin, iMax, iMid); - case 3: - return FromArgb(alpha, iMin, iMid, iMax); - case 4: - return FromArgb(alpha, iMid, iMin, iMax); - case 5: - return FromArgb(alpha, iMax, iMin, iMid); - default: - return FromArgb(alpha, iMax, iMid, iMin); - } + 1 => FromArgb(alpha, iMid, iMax, iMin), + 2 => FromArgb(alpha, iMin, iMax, iMid), + 3 => FromArgb(alpha, iMin, iMid, iMax), + 4 => FromArgb(alpha, iMid, iMin, iMax), + 5 => FromArgb(alpha, iMax, iMin, iMid), + _ => FromArgb(alpha, iMax, iMid, iMin), + }; } /// diff --git a/src/Html2OpenXml/Primitives/HtmlFont.cs b/src/Html2OpenXml/Primitives/HtmlFont.cs index 87cebc77..ff9eb19f 100755 --- a/src/Html2OpenXml/Primitives/HtmlFont.cs +++ b/src/Html2OpenXml/Primitives/HtmlFont.cs @@ -10,13 +10,15 @@ * PARTICULAR PURPOSE. */ using System; +using System.Collections.Generic; +using System.Linq; namespace HtmlToOpenXml; /// /// Represents a Html font (15px arial,sans-serif). /// -readonly struct HtmlFont(FontStyle? style, FontVariant? variant, FontWeight? weight, Unit? size, string? family) +readonly struct HtmlFont(Unit size, string? family, FontStyle? style, FontVariant? variant, FontWeight? weight) { /// Represents an empty font (not defined). public static readonly HtmlFont Empty = new (); @@ -25,61 +27,107 @@ readonly struct HtmlFont(FontStyle? style, FontVariant? variant, FontWeight? wei private readonly FontVariant? variant = variant; private readonly string? family = family; private readonly FontWeight? weight = weight; - private readonly Unit size = size ?? Unit.Empty; + private readonly Unit size = size; + /// public static HtmlFont Parse(string? str) { - if (str == null) return HtmlFont.Empty; + if (str == null) + return Empty; + return Parse(str.AsSpan()); + } - // The font shorthand property sets all the font properties in one declaration. - // The properties that can be set, are (in order): - // "font-style font-variant font-weight font-size/line-height font-family" - // The font-size and font-family values are required. - // If one of the other values are missing, the default values will be inserted, if any. + /// + /// Parse the font style attribute. + /// + /// + /// The font shorthand property sets all the font properties in one declaration. + /// The properties that can be set, are (in order): + /// "font-style font-variant font-weight font-size/line-height font-family" + /// The font-size and font-family values are required. + /// If one of the other values are missing, the default values will be inserted, if any. + /// /// + public static HtmlFont Parse(ReadOnlySpan span) + { // http://www.w3schools.com/cssref/pr_font_font.asp + if (span.IsEmpty || span.Length < 2) return Empty; + // in order to split by white spaces, we remove any white spaces between 2 family names (ex: Verdana, Arial -> Verdana,Arial) - str = System.Text.RegularExpressions.Regex.Replace(str, @",\s+?", ","); + //str = System.Text.RegularExpressions.Regex.Replace(str, @",\s+?", ","); + + Span tokens = stackalloc Range[6]; + var tokenCount = span.SplitCompositeAttribute(tokens, ' ', skipSeparatorIfPrecededBy: ','); + if (tokenCount == 0) + return Empty; - var fontParts = str.Split(HttpUtility.WhiteSpaces, StringSplitOptions.RemoveEmptyEntries); - if (fontParts.Length < 2) return HtmlFont.Empty; - + // Initialize default values FontStyle? style = null; FontVariant? variant = null; FontWeight? weight = null; // % and ratio font-size/line-height are not supported - Unit fontSize; - string? family; + Unit fontSize = Unit.Empty; + string? family = null; - if (fontParts.Length == 2) // 2=the minimal set of required parameters + if (tokenCount == 2) // 2=the minimal set of required parameters { // should be the size and the family (in that order). Others are set to their default values - fontSize = Converter.ToFontSize(fontParts[0]); + fontSize = Converter.ToFontSize(span.Slice(tokens[0])); if (!fontSize.IsValid) fontSize = Unit.Empty; - family = Converter.ToFontFamily(fontParts[1]); - return new HtmlFont(style, variant, weight, fontSize, family); + family = Converter.ToFontFamily(span.Slice(tokens[1])); + return new HtmlFont(fontSize, family, style, variant, weight); } - int index = 0; + // Now try to guess the values with their permutation + var tokenIndexes = new List(Enumerable.Range(0, tokenCount)); - style = Converter.ToFontStyle(fontParts[index]); - if (style.HasValue) { index++; } + // handle border style + for (int i = 0; i < tokenIndexes.Count; i++) + { + style = Converter.ToFontStyle(span.Slice(tokens[tokenIndexes[i]])); + if (style != null) + { + tokenIndexes.RemoveAt(i); // no need to process this part anymore + break; + } + } - if (index + 2 > fontParts.Length) return HtmlFont.Empty; - variant = Converter.ToFontVariant(fontParts[index]); - if (variant.HasValue) { index++; } + for (int i = 0; i < tokenIndexes.Count; i++) + { + variant = Converter.ToFontVariant(span.Slice(tokens[tokenIndexes[i]])); + if (variant != null) + { + tokenIndexes.RemoveAt(i); // no need to process this part anymore + break; + } + } - if (index + 2 > fontParts.Length) return HtmlFont.Empty; - weight = Converter.ToFontWeight(fontParts[index]); - if (weight.HasValue) { index++; } + for (int i = 0; i < tokenIndexes.Count; i++) + { + weight = Converter.ToFontWeight(span.Slice(tokens[tokenIndexes[i]])); + if (weight != null) + { + tokenIndexes.RemoveAt(i); // no need to process this part anymore + break; + } + } - if (fontParts.Length - index < 2) return HtmlFont.Empty; - fontSize = Converter.ToFontSize(fontParts[fontParts.Length - 2]); - if (!fontSize.IsValid) return HtmlFont.Empty; + for (int i = 0; i < tokenIndexes.Count; i++) + { + fontSize = Unit.Parse(span.Slice(tokens[tokenIndexes[i]])); + if (fontSize.IsValid) + { + tokenIndexes.RemoveAt(i); // no need to process this part anymore + break; + } + } + if (!fontSize.IsValid) fontSize = Unit.Empty; - family = Converter.ToFontFamily(fontParts[fontParts.Length - 1]); + // keep font family as the latest because it is the most permissive + if(tokenIndexes.Count > 0) + family = Converter.ToFontFamily(span.Slice(tokens[tokenIndexes[0]])); - return new HtmlFont(style, variant, weight, fontSize, family); + return new HtmlFont(fontSize, family, style, variant, weight); } //____________________________________________________________________ diff --git a/src/Html2OpenXml/Primitives/Margin.cs b/src/Html2OpenXml/Primitives/Margin.cs index 21205fbf..8cd53161 100755 --- a/src/Html2OpenXml/Primitives/Margin.cs +++ b/src/Html2OpenXml/Primitives/Margin.cs @@ -48,6 +48,14 @@ public Margin(Unit top, Unit right, Unit bottom, Unit left) this.sides = [top, right, bottom, left]; } + /// + public static Margin Parse(string? str) + { + if (str == null) + return Empty; + return Parse(str.AsSpan()); + } + /// /// Parse the margin style attribute. /// @@ -71,20 +79,13 @@ public Margin(Unit top, Unit right, Unit bottom, Unit left) /// margin:25px; /// all four margins are 25px /// - public static Margin Parse(string? str) - { - if (str == null) - return Empty; - return Parse(str.AsSpan()); - } - public static Margin Parse(ReadOnlySpan span) { - if (span.Length == 0 || span.IsWhiteSpace()) + if (span.IsEmpty || span.IsWhiteSpace()) return Empty; Span tokens = stackalloc Range[5]; - return span.SplitHtmlCompositeAttribute(tokens) switch + return span.SplitCompositeAttribute(tokens) switch { 1 => new Margin(Unit.Parse(span.Slice(tokens[0]), UnitMetric.Pixel)), 2 => new Margin( diff --git a/src/Html2OpenXml/Primitives/SideBorder.cs b/src/Html2OpenXml/Primitives/SideBorder.cs index cc852cd0..9b545466 100755 --- a/src/Html2OpenXml/Primitives/SideBorder.cs +++ b/src/Html2OpenXml/Primitives/SideBorder.cs @@ -45,7 +45,7 @@ public static SideBorder Parse(ReadOnlySpan span) return Empty; Span tokens = stackalloc Range[6]; - var tokenCount = span.SplitHtmlCompositeAttribute(tokens); + var tokenCount = span.SplitCompositeAttribute(tokens); if (tokenCount == 0) return Empty; diff --git a/src/Html2OpenXml/Utilities/Converter.cs b/src/Html2OpenXml/Utilities/Converter.cs index d5c5ef97..66ef3deb 100755 --- a/src/Html2OpenXml/Utilities/Converter.cs +++ b/src/Html2OpenXml/Utilities/Converter.cs @@ -55,42 +55,44 @@ static class Converter /// /// Convert Html regular font-size to OpenXml font value (expressed in point). /// - public static Unit ToFontSize(string? htmlSize) + public static Unit ToFontSize(ReadOnlySpan span) { - if (htmlSize == null) return Unit.Empty; - switch (htmlSize.ToLowerInvariant()) + if (span.IsEmpty) return Unit.Empty; + + Span loweredValue = span.Length <= 128 ? stackalloc char[span.Length] : new char[span.Length]; + span.ToLowerInvariant(loweredValue); + var unit = loweredValue switch { - case "1": - case "xx-small": return new Unit(UnitMetric.Point, 10); - case "2": - case "x-small": return new Unit(UnitMetric.Point, 15); - case "3": - case "small": return new Unit(UnitMetric.Point, 20); - case "4": - case "medium": return new Unit(UnitMetric.Point, 27); - case "5": - case "large": return new Unit(UnitMetric.Point, 36); - case "6": - case "x-large": return new Unit(UnitMetric.Point, 48); - case "7": - case "xx-large": return new Unit(UnitMetric.Point, 72); - default: - // the font-size is specified in positive half-points - Unit unit = Unit.Parse(htmlSize, UnitMetric.Pixel); - if (!unit.IsValid || unit.Value <= 0) - return Unit.Empty; - - // this is a rough conversion to support some percent size, considering 100% = 11 pt - if (unit.Metric == UnitMetric.Percent) unit = new Unit(UnitMetric.Point, unit.Value * 0.11); - return unit; + "1" or "xx-small" => new Unit(UnitMetric.Point, 10), + "2" or "x-small" => new Unit(UnitMetric.Point, 15), + "3" or "small" => new Unit(UnitMetric.Point, 20), + "4" or "medium" => new Unit(UnitMetric.Point, 27), + "5" or "large" => new Unit(UnitMetric.Point, 36), + "6" or "x-large" => new Unit(UnitMetric.Point, 48), + "7" or "xx-large" => new Unit(UnitMetric.Point, 72), + _ => Unit.Empty + }; + + if (!unit.IsValid) + { + // the font-size is specified in positive half-points + unit = Unit.Parse(loweredValue, UnitMetric.Pixel); + if (!unit.IsValid || unit.Value <= 0) + return Unit.Empty; + + // this is a rough conversion to support some percent size, considering 100% = 11 pt + if (unit.Metric == UnitMetric.Percent) unit = new Unit(UnitMetric.Point, unit.Value * 0.11); } + return unit; } - public static FontVariant? ToFontVariant(string? html) + public static FontVariant? ToFontVariant(ReadOnlySpan span) { - if (html == null) return null; + if (span.IsEmpty) return null; - return html.ToLowerInvariant() switch + Span loweredValue = span.Length <= 128 ? stackalloc char[span.Length] : new char[span.Length]; + span.ToLowerInvariant(loweredValue); + return loweredValue switch { "small-caps" => FontVariant.SmallCaps, "normal" => FontVariant.Normal, @@ -98,10 +100,13 @@ public static Unit ToFontSize(string? htmlSize) }; } - public static FontStyle? ToFontStyle(string? html) + public static FontStyle? ToFontStyle(ReadOnlySpan span) { - if (html == null) return null; - return html.ToLowerInvariant() switch + if (span.IsEmpty) return null; + + Span loweredValue = span.Length <= 128 ? stackalloc char[span.Length] : new char[span.Length]; + span.ToLowerInvariant(loweredValue); + return loweredValue switch { "italic" or "oblique" => FontStyle.Italic, "normal" => FontStyle.Normal, @@ -109,10 +114,13 @@ public static Unit ToFontSize(string? htmlSize) }; } - public static FontWeight? ToFontWeight(string? html) + public static FontWeight? ToFontWeight(ReadOnlySpan span) { - if (html == null) return null; - return html.ToLowerInvariant() switch + if (span.IsEmpty) return null; + + Span loweredValue = span.Length <= 128 ? stackalloc char[span.Length] : new char[span.Length]; + span.ToLowerInvariant(loweredValue); + return loweredValue switch { "700" or "bold" => FontWeight.Bold, "bolder" => FontWeight.Bolder, @@ -121,37 +129,25 @@ public static Unit ToFontSize(string? htmlSize) }; } - public static string? ToFontFamily(string? str) + public static string? ToFontFamily(ReadOnlySpan span) { - if (str == null) return null; + if (span.IsEmpty) return null; - var names = str.Split(',' ); - for (int i = 0; i < names.Length; i++) - { - string fontName = names[i]; - if (fontName.Length == 0) continue; - try - { - if (fontName[0] == '\'' && fontName[fontName.Length-1] == '\'') fontName = fontName.Substring(1, fontName.Length - 2); - return fontName; - } - catch (ArgumentException) - { - // the name is not a TrueType font or is not a font installed on this computer - } - } - - return null; + // return the first font name + Span tokens = stackalloc Range[1]; + return span.SplitCompositeAttribute(tokens, ',') switch { + 1 => span.Slice(tokens[0]).ToString(), + _ => null + }; } - public static BorderValues ToBorderStyle(ReadOnlySpan borderStyle) + public static BorderValues ToBorderStyle(ReadOnlySpan span) { - if (borderStyle.IsEmpty) + if (span.IsEmpty) return BorderValues.Nil; - Span loweredValue = borderStyle.Length <= 128 ? stackalloc char[borderStyle.Length] : new char[borderStyle.Length]; - borderStyle.ToLowerInvariant(loweredValue); - + Span loweredValue = span.Length <= 128 ? stackalloc char[span.Length] : new char[span.Length]; + span.ToLowerInvariant(loweredValue); return loweredValue switch { "dotted" => BorderValues.Dotted, diff --git a/src/Html2OpenXml/Utilities/SpanExtensions.cs b/src/Html2OpenXml/Utilities/SpanExtensions.cs index 97b0ca27..726547b3 100644 --- a/src/Html2OpenXml/Utilities/SpanExtensions.cs +++ b/src/Html2OpenXml/Utilities/SpanExtensions.cs @@ -130,38 +130,83 @@ public static int Split(this ReadOnlySpan span, Span destination, /// /// The source span to parse. /// The destination span into which the resulting ranges are written. + /// A character that delimits the regions in this instance. + /// If is preceded by this character, the separator will be treated as a normal character. /// The number of ranges written into . - public static int SplitHtmlCompositeAttribute(this ReadOnlySpan span, Span destination) + public static int SplitCompositeAttribute(this ReadOnlySpan span, Span destination, + char separator = ' ', char? skipSeparatorIfPrecededBy = null) { // If the destination is empty, there's nothing to do. if (destination.IsEmpty) return 0; - int matches = 0; - int startIndex = 0; + int matches = 0, startIndex = 0, offsetIndex = 0; bool escapeSpace = false; + char endEscapingChar = '\0'; + +#if NET8_0_OR_GREATER + var searchValues = System.Buffers.SearchValues.Create([separator, '(', '\'', '"']); +#else + ReadOnlySpan searchValues = [separator, '(', '\'', '"']; +#endif + while (span.Length > 0) { - // Remove the spaces that could appear in the color parameter: rgb(233, 233, 233) -> rgb(233,233,233) - int index = escapeSpace? span.IndexOf(')') : span.IndexOfAny(' ', '('); + bool isPositiveMatch = true; + + // Remove the spaces that could appear inside a token. + // Eg: rgb(233, 233, 233) -> rgb(233,233,233) + int index = escapeSpace? + span.IndexOf(endEscapingChar) : + span.IndexOfAny(searchValues); + + // end of span, we take the whole match if (index == -1) index = span.Length; - else if (span[index] == '(') + + // we find the beginning of an escaping sequence + else if (span[index] != separator && !escapeSpace) { + if (span[index] == '(') + { + endEscapingChar = ')'; + offsetIndex += index + 1; + } + else + { + endEscapingChar = span[index]; // ' or " + if (index == 0) startIndex++; // exclude the quote from the captured range + } escapeSpace = true; - continue; + isPositiveMatch = false; } - else if (span[index] == ')') + // end of escaping sequence + else if (span[index] == endEscapingChar) { + if (span[index] == ')') index++; // include that closing parenthesis in the range escapeSpace = false; - index++; // include that closing parenthesis in the range + } + // this is a separator but maybe we will need to skip it + // eg: "Arial, Verdana bold 1em" -> the space after the comma must be skipped + else if (span[index] == separator && index > 1 && + skipSeparatorIfPrecededBy.HasValue && index > 1 && span[index -1] == skipSeparatorIfPrecededBy) + { + offsetIndex += index + 1; + isPositiveMatch = false; + } + else if (index == 0) // empty token + { + startIndex++; + isPositiveMatch = false; } - if (!escapeSpace && index > 0) + // index > 0 to exclude empty entries + if (!escapeSpace && index > 0 && isPositiveMatch) { - destination[matches] = new Range(startIndex, startIndex + index); + destination[matches] = new Range(startIndex, startIndex + offsetIndex + index); matches++; + startIndex += index + offsetIndex + 1; + offsetIndex = 0; } - startIndex += index + 1; if (matches >= destination.Length || span.Length <= index) break; diff --git a/test/HtmlToOpenXml.Tests/Primitives/FontTests.cs b/test/HtmlToOpenXml.Tests/Primitives/FontTests.cs new file mode 100644 index 00000000..70fc618a --- /dev/null +++ b/test/HtmlToOpenXml.Tests/Primitives/FontTests.cs @@ -0,0 +1,63 @@ +using NUnit.Framework; + +namespace HtmlToOpenXml.Tests.Primitives +{ + /// + /// Tests Html font style attribute. + /// + [TestFixture] + public class FontTests + { + [TestCase("1.2em Verdana", ExpectedResult = true)] + [TestCase("Verdana 1.2em", ExpectedResult = false)] + public bool WithMinimal_ReturnsValid (string html) + { + var font = HtmlFont.Parse(html); + Assert.Multiple(() => { + Assert.That(font.Style, Is.Null); + Assert.That(font.Weight, Is.Null); + }); + return font.Size.IsValid; + } + + [TestCase("italic BOLD 1.2em Verdana")] + [TestCase("Verdana 1.2em bold italic ")] + public void WithDisordered_ShouldSucceed (string html) + { + var font = HtmlFont.Parse(html); + Assert.Multiple(() => { + Assert.That(font.Style, Is.EqualTo(FontStyle.Italic)); + Assert.That(font.Weight, Is.EqualTo(FontWeight.Bold)); + Assert.That(font.Family, Is.EqualTo("Verdana")); + Assert.That(font.Size.Metric, Is.EqualTo(UnitMetric.EM)); + Assert.That(font.Size.Value, Is.EqualTo(1.2)); + }); + } + + [Test(Description = "Multiple font families must keep the first one")] + public void WithMultipleFamily_ShouldSucceed () + { + var font = HtmlFont.Parse("Verdana, Arial bolder 1.2em"); + Assert.Multiple(() => { + Assert.That(font.Style, Is.Null); + Assert.That(font.Weight, Is.EqualTo(FontWeight.Bolder)); + Assert.That(font.Family, Is.EqualTo("Verdana")); + Assert.That(font.Size.Metric, Is.EqualTo(UnitMetric.EM)); + Assert.That(font.Size.Value, Is.EqualTo(1.2)); + }); + } + + [Test(Description = "Font families with quotes must unescape the first one")] + public void WithQuotedFamily_ShouldSucceed () + { + var font = HtmlFont.Parse("'Times New Roman', Times, Verdana, Arial bolder 1.2em"); + Assert.Multiple(() => { + Assert.That(font.Style, Is.Null); + Assert.That(font.Weight, Is.EqualTo(FontWeight.Bolder)); + Assert.That(font.Family, Is.EqualTo("Times New Roman")); + Assert.That(font.Size.Metric, Is.EqualTo(UnitMetric.EM)); + Assert.That(font.Size.Value, Is.EqualTo(1.2)); + }); + } + } +} diff --git a/test/HtmlToOpenXml.Tests/Primitives/StyleParserTests.cs b/test/HtmlToOpenXml.Tests/Primitives/StyleParserTests.cs index 73390e3b..1f307fb0 100644 --- a/test/HtmlToOpenXml.Tests/Primitives/StyleParserTests.cs +++ b/test/HtmlToOpenXml.Tests/Primitives/StyleParserTests.cs @@ -38,7 +38,7 @@ public void InvalidStyle_ShouldBeEmpty(string htmlStyle) } [Test] - public void WithMultipleTextDecoration_Should() + public void WithMultipleTextDecoration_ReturnsAllValues() { var styles = HtmlAttributeCollection.ParseStyle("text-decoration:underline dotted wavy"); var decorations = styles.GetTextDecorations("text-decoration"); From 07e3f2ea5e5baabd1da82b31d125c5f4506178f6 Mon Sep 17 00:00:00 2001 From: Olivier Nizet Date: Sat, 14 Dec 2024 17:57:02 +0100 Subject: [PATCH 14/29] Update changelog --- CHANGELOG.md | 5 +++++ src/Html2OpenXml/HtmlToOpenXml.csproj | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a56d874d..eb1f340b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## 3.3.0 + +- Rewriting of parsing to use System.Span instead of Regex +- Set Timeout on remaining Regex to prevent any DoS attack + ## 3.2.0 - Add new public API to allow parsing into Header and Footer #162. Some API methods as been flagged as obsolete with a clear message of what to use instead. diff --git a/src/Html2OpenXml/HtmlToOpenXml.csproj b/src/Html2OpenXml/HtmlToOpenXml.csproj index b9475508..56d34b59 100644 --- a/src/Html2OpenXml/HtmlToOpenXml.csproj +++ b/src/Html2OpenXml/HtmlToOpenXml.csproj @@ -9,13 +9,13 @@ HtmlToOpenXml HtmlToOpenXml HtmlToOpenXml.dll - 3.2.0 + 3.3.0 icon.png Copyright 2009-$([System.DateTime]::Now.Year) Olivier Nizet See changelog https://github.com/onizet/html2openxml/blob/master/CHANGELOG.md README.md office openxml netcore html - 3.2.0 + 3.3.0 MIT https://github.com/onizet/html2openxml https://github.com/onizet/html2openxml From 2bd74d3ffe366e398608bcf21a1785749732848e Mon Sep 17 00:00:00 2001 From: Olivier Nizet Date: Sat, 14 Dec 2024 17:58:11 +0100 Subject: [PATCH 15/29] Add Benchmark project --- examples/Benchmark/Benchmark.csproj | 20 +++++ examples/Benchmark/Benchmarks.cs | 39 +++++++++ examples/Benchmark/Program.cs | 3 + examples/Benchmark/ResourceHelper.cs | 40 +++++++++ examples/Benchmark/benchmark.html | 124 +++++++++++++++++++++++++++ examples/Demo/Demo.csproj | 1 + 6 files changed, 227 insertions(+) create mode 100644 examples/Benchmark/Benchmark.csproj create mode 100644 examples/Benchmark/Benchmarks.cs create mode 100644 examples/Benchmark/Program.cs create mode 100644 examples/Benchmark/ResourceHelper.cs create mode 100644 examples/Benchmark/benchmark.html diff --git a/examples/Benchmark/Benchmark.csproj b/examples/Benchmark/Benchmark.csproj new file mode 100644 index 00000000..de58bd24 --- /dev/null +++ b/examples/Benchmark/Benchmark.csproj @@ -0,0 +1,20 @@ + + + + Exe + net8.0 + enable + enable + true + + + + + + + + + + + + diff --git a/examples/Benchmark/Benchmarks.cs b/examples/Benchmark/Benchmarks.cs new file mode 100644 index 00000000..b126f86a --- /dev/null +++ b/examples/Benchmark/Benchmarks.cs @@ -0,0 +1,39 @@ +using DocumentFormat.OpenXml; +using DocumentFormat.OpenXml.Packaging; +using DocumentFormat.OpenXml.Validation; +using DocumentFormat.OpenXml.Wordprocessing; +using HtmlToOpenXml; +using System.Threading.Tasks; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Jobs; + +[MemoryDiagnoser] +//[SimpleJob(runtimeMoniker: RuntimeMoniker.Net462)] +//[SimpleJob(runtimeMoniker: RuntimeMoniker.Net50)] +[SimpleJob(runtimeMoniker: RuntimeMoniker.Net80)] +public class Benchmarks +{ + [Benchmark] + public async Task ParseWithSpan() + { + string html = ResourceHelper.GetString("benchmark.html"); + + using (MemoryStream generatedDocument = new MemoryStream()) + using (WordprocessingDocument package = WordprocessingDocument.Create(generatedDocument, WordprocessingDocumentType.Document)) + { + MainDocumentPart mainPart = package.MainDocumentPart; + if (mainPart == null) + { + mainPart = package.AddMainDocumentPart(); + new Document(new Body()).Save(mainPart); + } + + HtmlConverter converter = new HtmlConverter(mainPart); + converter.RenderPreAsTable = true; + Body body = mainPart.Document.Body!; + + await converter.ParseBody(html); + mainPart.Document.Save(); + } + } +} \ No newline at end of file diff --git a/examples/Benchmark/Program.cs b/examples/Benchmark/Program.cs new file mode 100644 index 00000000..f49472bf --- /dev/null +++ b/examples/Benchmark/Program.cs @@ -0,0 +1,3 @@ +using BenchmarkDotNet.Running; + +BenchmarkRunner.Run(); \ No newline at end of file diff --git a/examples/Benchmark/ResourceHelper.cs b/examples/Benchmark/ResourceHelper.cs new file mode 100644 index 00000000..c2b14629 --- /dev/null +++ b/examples/Benchmark/ResourceHelper.cs @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2017 Deal Stream sàrl. All rights reserved + */ +using System.IO; +using System.Reflection; +using System.Resources; + +/// +/// Helper class to get an embedded resources. +/// +public static class ResourceHelper +{ + public static string GetString(string resourceName) + { + return GetString(typeof(ResourceHelper).GetTypeInfo().Assembly, resourceName); + } + + public static string GetString(Assembly assembly, string resourceName) + { + using (var stream = GetStream(assembly, resourceName)) + { + using (var reader = new StreamReader(stream)) + return reader.ReadToEnd(); + } + } + + public static Stream GetStream(string resourceName) + { + return GetStream(typeof(ResourceHelper).GetTypeInfo().Assembly, resourceName); + } + + public static Stream GetStream(Assembly assembly, string resourceName) + { + var stream = assembly.GetManifestResourceStream(assembly.GetName().Name + "." + resourceName); + if (stream == null) + throw new MissingManifestResourceException($"Requested resource `{resourceName}` was not found in the assembly `{assembly}`."); + + return stream; + } +} diff --git a/examples/Benchmark/benchmark.html b/examples/Benchmark/benchmark.html new file mode 100644 index 00000000..de904e0c --- /dev/null +++ b/examples/Benchmark/benchmark.html @@ -0,0 +1,124 @@ + + + + + Sample HTML Page + + + + +

Welcome to My Sample Page

+ + +

+ This is a sample paragraph. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. +

+ + +Visit Example + + +Placeholder Image + + +
    +
  • Item 1
  • +
  • Item 2
  • +
  • Item 3
  • +
+ + + + + + + + + + + + + + + +
Header 1Header 2
Cell 1Cell 2
Cell 3Cell 4
+ + +
+ + + + + + + +
+ + + +

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. +

+

+ Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. +

+

+ Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. +

+

+ Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. +

+

+ Curabitur pretium tincidunt lacus. Nulla gravida orci a odio. Nullam varius, turpis et commodo pharetra, est eros bibendum elit, nec luctus magna felis sollicitudin mauris. +

+

+ Integer in mauris eu nibh euismod gravida. Duis ac tellus et risus vulputate vehicula. Donec lobortis risus a elit. Etiam tempor. Ut ullamcorper, ligula eu tempor congue, eros est euismod turpis, id tincidunt sapien risus a quam. +

+

+ Maecenas fermentum consequat mi. Donec fermentum. Pellentesque malesuada nulla a mi. Duis sapien sem, aliquet nec, commodo eget, consequat quis, neque. Aliquam faucibus, elit ut dictum aliquet, felis nisl adipiscing sapien, sed malesuada diam lacus eget erat. +

+

+ Cras mollis scelerisque nunc. Nullam arcu. Aliquam consequat. Curabitur augue lorem, dapibus quis, laoreet et, pretium ac, nisi. Aenean magna nisl, mollis quis, molestie eu, feugiat in, orci. In hac habitasse platea dictumst. +

+

+ Fusce convallis, mauris imperdiet gravida bibendum, nisl turpis suscipit mauris, sed placerat ipsum ligula sed magna. Maecenas nisl est, ultrices nec, congue eget, auctor vitae, massa. +

+

+ Fusce luctus vestibulum augue ut aliquet. Nunc sagittis dictum nisi. Sed id blandit purus. Proin quis orci. Quisque convallis libero in sapien pharetra tincidunt. +

+ + + +

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. +

+

+ Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. +

+

+ Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. +

+

+ Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. +

+

+ Curabitur pretium tincidunt lacus. Nulla gravida orci a odio. Nullam varius, turpis et commodo pharetra, est eros bibendum elit, nec luctus magna felis sollicitudin mauris. +

+

+ Integer in mauris eu nibh euismod gravida. Duis ac tellus et risus vulputate vehicula. Donec lobortis risus a elit. Etiam tempor. Ut ullamcorper, ligula eu tempor congue, eros est euismod turpis, id tincidunt sapien risus a quam. +

+

+ Maecenas fermentum consequat mi. Donec fermentum. Pellentesque malesuada nulla a mi. Duis sapien sem, aliquet nec, commodo eget, consequat quis, neque. Aliquam faucibus, elit ut dictum aliquet, felis nisl adipiscing sapien, sed malesuada diam lacus eget erat. +

+

+ Cras mollis scelerisque nunc. Nullam arcu. Aliquam consequat. Curabitur augue lorem, dapibus quis, laoreet et, pretium ac, nisi. Aenean magna nisl, mollis quis, molestie eu, feugiat in, orci. In hac habitasse platea dictumst. +

+

+ Fusce convallis, mauris imperdiet gravida bibendum, nisl turpis suscipit mauris, sed placerat ipsum ligula sed magna. Maecenas nisl est, ultrices nec, congue eget, auctor vitae, massa. +

+

+ Fusce luctus vestibulum augue ut aliquet. Nunc sagittis dictum nisi. Sed id blandit purus. Proin quis orci. Quisque convallis libero in sapien pharetra tincidunt. +

+ + + diff --git a/examples/Demo/Demo.csproj b/examples/Demo/Demo.csproj index 3e76b9dc..851f0dab 100644 --- a/examples/Demo/Demo.csproj +++ b/examples/Demo/Demo.csproj @@ -3,6 +3,7 @@ net8.0 Exe + true From 83851e948d92a3e5d82d7e4d66ff9e15047a5067 Mon Sep 17 00:00:00 2001 From: Olivier Nizet Date: Sat, 14 Dec 2024 17:59:55 +0100 Subject: [PATCH 16/29] Improve unit tests --- test/HtmlToOpenXml.Tests/ParserTests.cs | 3 ++- test/HtmlToOpenXml.Tests/Primitives/ColorTests.cs | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/test/HtmlToOpenXml.Tests/ParserTests.cs b/test/HtmlToOpenXml.Tests/ParserTests.cs index 9342eff3..670fdbf7 100644 --- a/test/HtmlToOpenXml.Tests/ParserTests.cs +++ b/test/HtmlToOpenXml.Tests/ParserTests.cs @@ -89,7 +89,7 @@ public void ConsecutiveParagraph_WithClosedTags_ShouldNotContinueStyle() Assert.That(elements[1].ChildElements, Has.Count.EqualTo(1)); Assert.That(elements[1].FirstChild, Is.TypeOf(typeof(Run))); - var runProperties = elements[1].FirstChild.GetFirstChild(); + var runProperties = elements[1].FirstChild!.GetFirstChild(); Assert.That(runProperties, Is.Null); } @@ -100,6 +100,7 @@ public void ConsecutiveParagraph_WithClosedTags_ShouldNotContinueStyle() public int Newline_ReturnsRunCount (string html) { var elements = converter.Parse(html); + Assert.That(elements.Count, Is.EqualTo(1)); return elements[0].Count(c => c is Run); } diff --git a/test/HtmlToOpenXml.Tests/Primitives/ColorTests.cs b/test/HtmlToOpenXml.Tests/Primitives/ColorTests.cs index 81f251f0..3848f148 100644 --- a/test/HtmlToOpenXml.Tests/Primitives/ColorTests.cs +++ b/test/HtmlToOpenXml.Tests/Primitives/ColorTests.cs @@ -47,6 +47,7 @@ public void ParseInvalidHtmlColor_ReturnsEmpty(string htmlColor) public string ArgColor_ToHex_ShouldSucceed(byte red, byte green, byte blue, double alpha) { var color = HtmlColor.FromArgb(alpha, red, green, blue); + Assert.That(color.IsEmpty, Is.False); return color.ToHexString(); } @@ -54,6 +55,7 @@ public string ArgColor_ToHex_ShouldSucceed(byte red, byte green, byte blue, doub public string HslColor_ToHex_ShouldSucceed(double alpha, double hue, double saturation, double luminosity) { var color = HtmlColor.FromHsl(alpha, hue, saturation, luminosity); + Assert.That(color.IsEmpty, Is.False); return color.ToHexString(); } } From 7a5322b46a1112cc34e599c5d87865a5a569be98 Mon Sep 17 00:00:00 2001 From: Olivier Nizet Date: Sat, 14 Dec 2024 18:41:00 +0100 Subject: [PATCH 17/29] Allow to run multiple runtimes benchmarks --- examples/Benchmark/Benchmark.csproj | 3 ++- examples/Benchmark/Benchmarks.cs | 11 ++++------- examples/Benchmark/README.md | 7 +++++++ 3 files changed, 13 insertions(+), 8 deletions(-) create mode 100644 examples/Benchmark/README.md diff --git a/examples/Benchmark/Benchmark.csproj b/examples/Benchmark/Benchmark.csproj index de58bd24..71537710 100644 --- a/examples/Benchmark/Benchmark.csproj +++ b/examples/Benchmark/Benchmark.csproj @@ -2,10 +2,11 @@ Exe - net8.0 + net48;net8.0 enable enable true + <latest diff --git a/examples/Benchmark/Benchmarks.cs b/examples/Benchmark/Benchmarks.cs index b126f86a..ade65e6b 100644 --- a/examples/Benchmark/Benchmarks.cs +++ b/examples/Benchmark/Benchmarks.cs @@ -1,16 +1,13 @@ +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Jobs; using DocumentFormat.OpenXml; using DocumentFormat.OpenXml.Packaging; -using DocumentFormat.OpenXml.Validation; using DocumentFormat.OpenXml.Wordprocessing; using HtmlToOpenXml; -using System.Threading.Tasks; -using BenchmarkDotNet.Attributes; -using BenchmarkDotNet.Jobs; [MemoryDiagnoser] -//[SimpleJob(runtimeMoniker: RuntimeMoniker.Net462)] -//[SimpleJob(runtimeMoniker: RuntimeMoniker.Net50)] -[SimpleJob(runtimeMoniker: RuntimeMoniker.Net80)] +[SimpleJob(runtimeMoniker: RuntimeMoniker.Net48)] +[SimpleJob(runtimeMoniker: RuntimeMoniker.Net80, baseline: true)] public class Benchmarks { [Benchmark] diff --git a/examples/Benchmark/README.md b/examples/Benchmark/README.md new file mode 100644 index 00000000..e1576beb --- /dev/null +++ b/examples/Benchmark/README.md @@ -0,0 +1,7 @@ +# Benchmarks + +How to run the benchmark tool. +First build the project: `dotnet build -c Release` + +Then run the performance test targeting multiple runtimes: +`dotnet run -c Release -f net8.0 --runtimes net48 net8.0` From 52a361004acf5d77ffe22e2b18cd691677d1ac48 Mon Sep 17 00:00:00 2001 From: Olivier Nizet Date: Sat, 14 Dec 2024 19:07:29 +0100 Subject: [PATCH 18/29] Include the csproj in the sln --- HtmlToOpenXml.sln | 10 +++++++++- examples/Benchmark/Benchmark.csproj | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/HtmlToOpenXml.sln b/HtmlToOpenXml.sln index d702dedb..99f378a5 100644 --- a/HtmlToOpenXml.sln +++ b/HtmlToOpenXml.sln @@ -13,6 +13,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo", "examples\Demo\Demo. EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HtmlToOpenXml.Tests", "test\HtmlToOpenXml.Tests\HtmlToOpenXml.Tests.csproj", "{CA0A68E0-45A0-4A01-A061-F951D93D6906}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Benchmark", "examples\Benchmark\Benchmark.csproj", "{143A3684-FAEB-43D0-A895-09BE5FDF85F6}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -31,6 +33,10 @@ Global {CA0A68E0-45A0-4A01-A061-F951D93D6906}.Debug|Any CPU.Build.0 = Debug|Any CPU {CA0A68E0-45A0-4A01-A061-F951D93D6906}.Release|Any CPU.ActiveCfg = Release|Any CPU {CA0A68E0-45A0-4A01-A061-F951D93D6906}.Release|Any CPU.Build.0 = Release|Any CPU + {143A3684-FAEB-43D0-A895-09BE5FDF85F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {143A3684-FAEB-43D0-A895-09BE5FDF85F6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {143A3684-FAEB-43D0-A895-09BE5FDF85F6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {143A3684-FAEB-43D0-A895-09BE5FDF85F6}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -39,8 +45,10 @@ Global {EF700F30-C9BB-49A6-912C-E3B77857B514} = {58520A98-BA53-4BA4-AAE3-786AA21331D6} {A1ECC760-B9F7-4A00-AF5F-568B5FD6F09F} = {84EA02ED-2E97-47D2-992E-32CC104A3A7A} {CA0A68E0-45A0-4A01-A061-F951D93D6906} = {84EA02ED-2E97-47D2-992E-32CC104A3A7A} + {143A3684-FAEB-43D0-A895-09BE5FDF85F6} = {84EA02ED-2E97-47D2-992E-32CC104A3A7A} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {14EE1026-6507-4295-9FEE-67A55C3849CE} + SolutionGuid = {194D4CBE-A20A-4E32-967B-E1BBD3922C29} EndGlobalSection -EndGlobal +EndGlobal \ No newline at end of file diff --git a/examples/Benchmark/Benchmark.csproj b/examples/Benchmark/Benchmark.csproj index 71537710..861f5519 100644 --- a/examples/Benchmark/Benchmark.csproj +++ b/examples/Benchmark/Benchmark.csproj @@ -6,7 +6,7 @@ enable enable true - <latest + latest From 04e93026d6078f640373da9d5714a9a76b4240bf Mon Sep 17 00:00:00 2001 From: Olivier Nizet Date: Sat, 14 Dec 2024 20:45:55 +0100 Subject: [PATCH 19/29] Remove neat support for SearchValues as performant is worst than ReadOnlySpan --- src/Html2OpenXml/Utilities/SpanExtensions.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Html2OpenXml/Utilities/SpanExtensions.cs b/src/Html2OpenXml/Utilities/SpanExtensions.cs index 726547b3..d9a6c92c 100644 --- a/src/Html2OpenXml/Utilities/SpanExtensions.cs +++ b/src/Html2OpenXml/Utilities/SpanExtensions.cs @@ -143,12 +143,7 @@ public static int SplitCompositeAttribute(this ReadOnlySpan span, Span searchValues = [separator, '(', '\'', '"']; -#endif while (span.Length > 0) { From 89f4e5fcbce93ee8b77fd9e98474fe52d89a391b Mon Sep 17 00:00:00 2001 From: Olivier Nizet Date: Mon, 16 Dec 2024 14:49:12 +0100 Subject: [PATCH 20/29] Fix compilation error --- src/Html2OpenXml/Expressions/Image/ImageExpressionBase.cs | 4 ++-- src/Html2OpenXml/Expressions/Table/TableCellExpression.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Html2OpenXml/Expressions/Image/ImageExpressionBase.cs b/src/Html2OpenXml/Expressions/Image/ImageExpressionBase.cs index 06fb089a..20b94031 100644 --- a/src/Html2OpenXml/Expressions/Image/ImageExpressionBase.cs +++ b/src/Html2OpenXml/Expressions/Image/ImageExpressionBase.cs @@ -81,8 +81,8 @@ private void ComposeStyles () // if the layout is not inline and both left and right are auto, image appears centered // https://developer.mozilla.org/en-US/docs/Web/CSS/margin-left var margin = styleAttributes.GetMargin("margin"); - if (margin.Left.Type == UnitMetric.Auto - && margin.Right.Type == UnitMetric.Auto + if (margin.Left.Metric == UnitMetric.Auto + && margin.Right.Metric == UnitMetric.Auto && !AngleSharpExtensions.IsInlineLayout(styleAttributes["display"], "inline-block")) { paraProperties.Justification = new() { Val = JustificationValues.Center }; diff --git a/src/Html2OpenXml/Expressions/Table/TableCellExpression.cs b/src/Html2OpenXml/Expressions/Table/TableCellExpression.cs index 4e816f89..815fbdaa 100644 --- a/src/Html2OpenXml/Expressions/Table/TableCellExpression.cs +++ b/src/Html2OpenXml/Expressions/Table/TableCellExpression.cs @@ -74,8 +74,8 @@ protected override void ComposeStyles(ParsingContext context) { cellProperties.TableCellWidth = new TableCellWidth { - Type = width.Type == UnitMetric.Percent ? TableWidthUnitValues.Pct : TableWidthUnitValues.Dxa, - Width = width.Type == UnitMetric.Percent + Type = width.Metric == UnitMetric.Percent ? TableWidthUnitValues.Pct : TableWidthUnitValues.Dxa, + Width = width.Metric == UnitMetric.Percent ? ((int) (width.Value * 50)).ToString(CultureInfo.InvariantCulture) : width.ValueInDxa.ToString(CultureInfo.InvariantCulture) }; From e62d8333a352df483e9d9c38464be9d811cbf3fd Mon Sep 17 00:00:00 2001 From: Olivier Nizet Date: Mon, 16 Dec 2024 14:52:24 +0100 Subject: [PATCH 21/29] Use FrozenDictionary for better performance (thanks Graham!) --- examples/Benchmark/Benchmarks.cs | 2 +- .../Numbering/NumberingExpressionBase.cs | 7 +++--- src/Html2OpenXml/HtmlToOpenXml.csproj | 5 ++++ src/Html2OpenXml/IO/ImageHeader.cs | 25 ++++++++++++------- .../Primitives/HtmlColor.Named.cs | 7 +++--- 5 files changed, 30 insertions(+), 16 deletions(-) diff --git a/examples/Benchmark/Benchmarks.cs b/examples/Benchmark/Benchmarks.cs index ade65e6b..c5425e3c 100644 --- a/examples/Benchmark/Benchmarks.cs +++ b/examples/Benchmark/Benchmarks.cs @@ -18,7 +18,7 @@ public async Task ParseWithSpan() using (MemoryStream generatedDocument = new MemoryStream()) using (WordprocessingDocument package = WordprocessingDocument.Create(generatedDocument, WordprocessingDocumentType.Document)) { - MainDocumentPart mainPart = package.MainDocumentPart; + MainDocumentPart? mainPart = package.MainDocumentPart; if (mainPart == null) { mainPart = package.AddMainDocumentPart(); diff --git a/src/Html2OpenXml/Expressions/Numbering/NumberingExpressionBase.cs b/src/Html2OpenXml/Expressions/Numbering/NumberingExpressionBase.cs index 1e0e1586..1b83ad28 100644 --- a/src/Html2OpenXml/Expressions/Numbering/NumberingExpressionBase.cs +++ b/src/Html2OpenXml/Expressions/Numbering/NumberingExpressionBase.cs @@ -9,6 +9,7 @@ * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A * PARTICULAR PURPOSE. */ +using System.Collections.Frozen; using System.Collections.Generic; using System.Linq; using AngleSharp.Html.Dom; @@ -26,7 +27,7 @@ abstract class NumberingExpressionBase(IHtmlElement node) : BlockElementExpressi public const int MaxLevel = 8; protected const int Indentation = 360; public const string HeadingNumberingName = "decimal-heading-multi"; - private static readonly IDictionary predefinedNumberingLists = InitKnownLists(); + private static readonly IReadOnlyDictionary predefinedNumberingLists = InitKnownLists(); /// Contains the list of templated list along with the AbstractNumbId private Dictionary? knownAbsNumIds; /// Contains the list of numbering instance. @@ -218,7 +219,7 @@ private void InitNumberingIds(ParsingContext context) /// /// Predefined template of lists. /// - private static Dictionary InitKnownLists() + private static IReadOnlyDictionary InitKnownLists() { var knownAbstractNums = new Dictionary(); @@ -292,6 +293,6 @@ private static Dictionary InitKnownLists() knownAbstractNums.Add(listName, abstractNum); } - return knownAbstractNums; + return knownAbstractNums.ToFrozenDictionary(); } } \ No newline at end of file diff --git a/src/Html2OpenXml/HtmlToOpenXml.csproj b/src/Html2OpenXml/HtmlToOpenXml.csproj index a065d37a..ccff1c31 100644 --- a/src/Html2OpenXml/HtmlToOpenXml.csproj +++ b/src/Html2OpenXml/HtmlToOpenXml.csproj @@ -37,6 +37,11 @@ + + + + + diff --git a/src/Html2OpenXml/IO/ImageHeader.cs b/src/Html2OpenXml/IO/ImageHeader.cs index 858a923d..300b10db 100755 --- a/src/Html2OpenXml/IO/ImageHeader.cs +++ b/src/Html2OpenXml/IO/ImageHeader.cs @@ -14,6 +14,7 @@ * EMF Specifications: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-emf/ae7e7437-cfe5-485e-84ea-c74b51b000be */ using System; +using System.Collections.Frozen; using System.Collections.Generic; using System.IO; using System.Linq; @@ -35,16 +36,22 @@ public enum FileType { Unrecognized, Bitmap, Gif, Png, Jpeg, Emf, Xml } private static readonly byte[] pngSignatureBytes = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]; - private static readonly Dictionary imageFormatDecoders = new() + private static readonly IReadOnlyDictionary imageFormatDecoders = InitKnownFormatDecoders(); + + private static IReadOnlyDictionary InitKnownFormatDecoders() { - { new byte[] { 0x42, 0x4D }, FileType.Bitmap }, - { Encoding.UTF8.GetBytes("GIF87a"), FileType.Gif }, - { Encoding.UTF8.GetBytes("GIF89a"), FileType.Gif }, // animated gif - { pngSignatureBytes, FileType.Png }, - { new byte[] { 0xff, 0xd8 }, FileType.Jpeg }, - { new byte[] { 0x1, 0, 0, 0 }, FileType.Emf }, - { Encoding.UTF8.GetBytes("() { + { new byte[] { 0x42, 0x4D }, FileType.Bitmap }, + { Encoding.UTF8.GetBytes("GIF87a"), FileType.Gif }, + { Encoding.UTF8.GetBytes("GIF89a"), FileType.Gif }, // animated gif + { pngSignatureBytes, FileType.Png }, + { new byte[] { 0xff, 0xd8 }, FileType.Jpeg }, + { new byte[] { 0x1, 0, 0, 0 }, FileType.Emf }, + { Encoding.UTF8.GetBytes(" x.Length).First().Length; diff --git a/src/Html2OpenXml/Primitives/HtmlColor.Named.cs b/src/Html2OpenXml/Primitives/HtmlColor.Named.cs index dff82959..c9a786c8 100755 --- a/src/Html2OpenXml/Primitives/HtmlColor.Named.cs +++ b/src/Html2OpenXml/Primitives/HtmlColor.Named.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Frozen; using System.Collections.Generic; namespace HtmlToOpenXml; @@ -8,7 +9,7 @@ namespace HtmlToOpenXml; ///
partial struct HtmlColor { - private static readonly Dictionary namedColors = InitKnownColors(); + private static readonly IReadOnlyDictionary namedColors = InitKnownColors(); private static HtmlColor GetNamedColor (ReadOnlySpan name) { @@ -21,7 +22,7 @@ private static HtmlColor GetNamedColor (ReadOnlySpan name) return color; } - private static Dictionary InitKnownColors() + private static IReadOnlyDictionary InitKnownColors() { var colors = new Dictionary() { @@ -168,6 +169,6 @@ private static Dictionary InitKnownColors() { "transparent", FromArgb(0, 0, 0, 0) } }; - return colors; + return colors.ToFrozenDictionary(); } } \ No newline at end of file From 5dc31f7db5c191e273130cb37a884efebd37c26e Mon Sep 17 00:00:00 2001 From: Olivier Nizet Date: Mon, 16 Dec 2024 15:24:55 +0100 Subject: [PATCH 22/29] Decrease warnings --- examples/Benchmark/Benchmarks.cs | 1 - test/HtmlToOpenXml.Tests/HtmlConverterTestBase.cs | 10 +++++----- test/HtmlToOpenXml.Tests/HtmlToOpenXml.Tests.csproj | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/examples/Benchmark/Benchmarks.cs b/examples/Benchmark/Benchmarks.cs index c5425e3c..786943da 100644 --- a/examples/Benchmark/Benchmarks.cs +++ b/examples/Benchmark/Benchmarks.cs @@ -27,7 +27,6 @@ public async Task ParseWithSpan() HtmlConverter converter = new HtmlConverter(mainPart); converter.RenderPreAsTable = true; - Body body = mainPart.Document.Body!; await converter.ParseBody(html); mainPart.Document.Save(); diff --git a/test/HtmlToOpenXml.Tests/HtmlConverterTestBase.cs b/test/HtmlToOpenXml.Tests/HtmlConverterTestBase.cs index c58459de..2b56cac0 100644 --- a/test/HtmlToOpenXml.Tests/HtmlConverterTestBase.cs +++ b/test/HtmlToOpenXml.Tests/HtmlConverterTestBase.cs @@ -8,17 +8,17 @@ namespace HtmlToOpenXml.Tests { public abstract class HtmlConverterTestBase { - private System.IO.MemoryStream generatedDocument; - private WordprocessingDocument package; + private MemoryStream generatedDocument = default!; + private WordprocessingDocument package = default!; - protected HtmlConverter converter; - protected MainDocumentPart mainPart; + protected HtmlConverter converter = default!; + protected MainDocumentPart mainPart = default!; [SetUp] public void Init () { - generatedDocument = new System.IO.MemoryStream(); + generatedDocument = new MemoryStream(); package = WordprocessingDocument.Create(generatedDocument, WordprocessingDocumentType.Document); mainPart = package.MainDocumentPart!; diff --git a/test/HtmlToOpenXml.Tests/HtmlToOpenXml.Tests.csproj b/test/HtmlToOpenXml.Tests/HtmlToOpenXml.Tests.csproj index e47cc14d..434b85a5 100755 --- a/test/HtmlToOpenXml.Tests/HtmlToOpenXml.Tests.csproj +++ b/test/HtmlToOpenXml.Tests/HtmlToOpenXml.Tests.csproj @@ -18,7 +18,7 @@ - + all From 03bd94df645d74dd1e4c2e950dcf6d3670f85116 Mon Sep 17 00:00:00 2001 From: Olivier Nizet Date: Fri, 20 Dec 2024 17:03:27 +0100 Subject: [PATCH 23/29] Code simplification --- src/Html2OpenXml/Primitives/Unit.cs | 2 +- test/HtmlToOpenXml.Tests/HrTests.cs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Html2OpenXml/Primitives/Unit.cs b/src/Html2OpenXml/Primitives/Unit.cs index e5d5dc18..b994bb2d 100755 --- a/src/Html2OpenXml/Primitives/Unit.cs +++ b/src/Html2OpenXml/Primitives/Unit.cs @@ -192,7 +192,7 @@ public int ValueInPx /// public double ValueInPoint { - get { return (double) (metric == UnitMetric.Point ? this.value : (float) valueInEmus / 12700L); } + get { return metric == UnitMetric.Point ? this.value : (float) valueInEmus / 12700L; } } /// diff --git a/test/HtmlToOpenXml.Tests/HrTests.cs b/test/HtmlToOpenXml.Tests/HrTests.cs index b7fdc1d5..e83d16b8 100644 --- a/test/HtmlToOpenXml.Tests/HrTests.cs +++ b/test/HtmlToOpenXml.Tests/HrTests.cs @@ -14,6 +14,7 @@ public class HrTests : HtmlConverterTestBase public void Standalone_ReturnsWithNoSpacing () { var elements = converter.Parse("
"); + TestContext.Out.WriteLine(elements[0]!.OuterXml); AssertIsHr(elements[0], false); } From 9ec8636871b89ea44f400a53d670c2c02c455102 Mon Sep 17 00:00:00 2001 From: Olivier Nizet Date: Sat, 21 Dec 2024 23:59:27 +0100 Subject: [PATCH 24/29] Rewrite parsing to improve code readability --- .../Collections/HtmlAttributeCollection.cs | 102 +++++++------- src/Html2OpenXml/Primitives/HtmlFont.cs | 126 ++++++++++-------- src/Html2OpenXml/Primitives/Unit.cs | 2 +- src/Html2OpenXml/Utilities/SpanExtensions.cs | 35 +++-- .../Primitives/FontTests.cs | 17 +++ .../Primitives/StyleParserTests.cs | 1 - test/HtmlToOpenXml.Tests/StyleTests.cs | 2 +- 7 files changed, 156 insertions(+), 129 deletions(-) diff --git a/src/Html2OpenXml/Collections/HtmlAttributeCollection.cs b/src/Html2OpenXml/Collections/HtmlAttributeCollection.cs index d8f4c1ee..2de8867e 100755 --- a/src/Html2OpenXml/Collections/HtmlAttributeCollection.cs +++ b/src/Html2OpenXml/Collections/HtmlAttributeCollection.cs @@ -41,78 +41,66 @@ public static HtmlAttributeCollection ParseStyle(string? htmlStyles) if (string.IsNullOrWhiteSpace(htmlStyles)) return collection; var span = htmlStyles.AsSpan(); - - // Encoded ':' and ';' characters are valid for browser - // - int startIndex = 0; bool foundKey = false; string? key = null; + while (span.Length > 0) { + // Encoded ':' and ';' characters are valid for browser + // int index = span.IndexOfAny(';', '&', ':'); if (index == -1) { - if (!foundKey) break; - index = span.Length; - } - - int separatorSize = 0; - if (!foundKey) - { - // html-encoded semicolon - if (span.Slice(index).StartsWith(['&','#','5','8',';'])) - { - separatorSize = 5; - } - else if (span[index] == ':') - { - separatorSize = 1; - } - else + if (foundKey) { - // unexpected semicolon (ie, key with no value) -> ignore this style - separatorSize = -1; + // process the last value + collection.attributes[key!] = new Range(startIndex, startIndex + span.Length); } + break; + } - if (separatorSize > 0 && index > 0) - { - key = span.Slice(0, index).ToString().Trim(); - foundKey = true; - } + var separator = span[index]; + if (separator == ';' && foundKey) + { + if (index > 0) + collection.attributes[key!] = new Range(startIndex, startIndex + index); + foundKey = false; + index++; + } + else if (separator == ';' && !foundKey) + { + // unexpected semicolon (ie, key with no value) -> ignore this style + index++; + } + else if (separator == ':' && !foundKey) + { + key = span.Slice(0, index).Trim().ToString(); + foundKey = true; + index++; + } + // html-encoded semicolon + else if (foundKey && span.Slice(index).StartsWith(['&','#','5','9',';'])) + { + if (index > 0) + collection.attributes[key!] = new Range(startIndex, startIndex + index); + foundKey = false; + index += 5; // length of ":" + } + else if (!foundKey && span.Slice(index).StartsWith(['&','#','5','8',';'])) + { + key = span.Slice(0, index).Trim().ToString(); + foundKey = true; + index += 5; // length of ":" } else { - if (index < span.Length) - { - // html-encoded colon - if (span.Slice(index).StartsWith(['&','#','5','9',';'])) - { - separatorSize = 5; - } - else if (span[index] == ';') - { - separatorSize = 1; - } - else if (span[index] == ':') - { - // unexpected colon (ie, key:value:value) -> ignore this style - separatorSize = -1; - foundKey = false; - } - } - - if (foundKey) - { - if (index > 0) - collection.attributes[key!] = new Range(startIndex, startIndex + index); - foundKey = false; - } + span = span.Slice(index + 1); + continue; } - separatorSize = Math.Abs(separatorSize); - startIndex += index + separatorSize; - span = span.Slice(index + separatorSize); + span = span.Slice(index); + startIndex += index; } return collection; @@ -274,7 +262,7 @@ public HtmlFont GetFont(string name) Unit unit = this.GetUnit(name + "-size"); if (unit.IsValid) fontSize = unit; - return new HtmlFont(fontSize, family, fontStyle, variant, weight); + return new HtmlFont(fontSize, family, fontStyle, variant, weight, Unit.Empty); } /// diff --git a/src/Html2OpenXml/Primitives/HtmlFont.cs b/src/Html2OpenXml/Primitives/HtmlFont.cs index ff9eb19f..05acdbbf 100755 --- a/src/Html2OpenXml/Primitives/HtmlFont.cs +++ b/src/Html2OpenXml/Primitives/HtmlFont.cs @@ -10,15 +10,14 @@ * PARTICULAR PURPOSE. */ using System; -using System.Collections.Generic; -using System.Linq; namespace HtmlToOpenXml; /// /// Represents a Html font (15px arial,sans-serif). /// -readonly struct HtmlFont(Unit size, string? family, FontStyle? style, FontVariant? variant, FontWeight? weight) +readonly struct HtmlFont(Unit size, string? family, FontStyle? style, + FontVariant? variant, FontWeight? weight, Unit lineHeight) { /// Represents an empty font (not defined). public static readonly HtmlFont Empty = new (); @@ -28,6 +27,8 @@ readonly struct HtmlFont(Unit size, string? family, FontStyle? style, FontVarian private readonly string? family = family; private readonly FontWeight? weight = weight; private readonly Unit size = size; + private readonly Unit lineHeight = lineHeight; + /// public static HtmlFont Parse(string? str) @@ -53,9 +54,6 @@ public static HtmlFont Parse(ReadOnlySpan span) if (span.IsEmpty || span.Length < 2) return Empty; - // in order to split by white spaces, we remove any white spaces between 2 family names (ex: Verdana, Arial -> Verdana,Arial) - //str = System.Text.RegularExpressions.Regex.Replace(str, @",\s+?", ","); - Span tokens = stackalloc Range[6]; var tokenCount = span.SplitCompositeAttribute(tokens, ' ', skipSeparatorIfPrecededBy: ','); if (tokenCount == 0) @@ -66,75 +64,85 @@ public static HtmlFont Parse(ReadOnlySpan span) FontVariant? variant = null; FontWeight? weight = null; // % and ratio font-size/line-height are not supported - Unit fontSize = Unit.Empty; - string? family = null; + Unit fontSize = Unit.Empty, lineHeight = Unit.Empty; + string? fontFamily = null; if (tokenCount == 2) // 2=the minimal set of required parameters { // should be the size and the family (in that order). Others are set to their default values fontSize = Converter.ToFontSize(span.Slice(tokens[0])); - if (!fontSize.IsValid) fontSize = Unit.Empty; - family = Converter.ToFontFamily(span.Slice(tokens[1])); - return new HtmlFont(fontSize, family, style, variant, weight); + if (!fontSize.IsValid) return Empty; + fontFamily = Converter.ToFontFamily(span.Slice(tokens[1])); + return new HtmlFont(fontSize, fontFamily, style, variant, weight, lineHeight); } - - // Now try to guess the values with their permutation - var tokenIndexes = new List(Enumerable.Range(0, tokenCount)); - - // handle border style - for (int i = 0; i < tokenIndexes.Count; i++) + else if (tokenCount > 10) { - style = Converter.ToFontStyle(span.Slice(tokens[tokenIndexes[i]])); - if (style != null) - { - tokenIndexes.RemoveAt(i); // no need to process this part anymore - break; - } + // safety check to avoid overflow with stackalloc in a loop + return Empty; } - for (int i = 0; i < tokenIndexes.Count; i++) - { - variant = Converter.ToFontVariant(span.Slice(tokens[tokenIndexes[i]])); - if (variant != null) - { - tokenIndexes.RemoveAt(i); // no need to process this part anymore - break; - } - } - for (int i = 0; i < tokenIndexes.Count; i++) + for (int i = 0; i < tokenCount; i++) { - weight = Converter.ToFontWeight(span.Slice(tokens[tokenIndexes[i]])); - if (weight != null) + var token = span.Slice(tokens[i]).Trim(); + Span loweredValue = token.Length <= 128 ? stackalloc char[token.Length] : new char[token.Length]; + token.ToLowerInvariant(loweredValue); + + switch (loweredValue) { - tokenIndexes.RemoveAt(i); // no need to process this part anymore - break; + case "italic" or "oblique": style = FontStyle.Italic; break; + case "normal": + style ??= FontStyle.Normal; + variant ??= FontVariant.Normal; + weight ??= FontWeight.Normal; + break; + case "small-caps": variant = FontVariant.SmallCaps; break; + case "700" or "bold": weight = FontWeight.Bold; break; + case "bolder": weight = FontWeight.Bolder; break; + case "400": weight = FontWeight.Normal; break; + case "xx-small": fontSize = new Unit(UnitMetric.Point, 10); break; + case "x-small": fontSize = new Unit(UnitMetric.Point, 15); break; + case "small": fontSize = new Unit(UnitMetric.Point, 20); break; + case "medium": fontSize = new Unit(UnitMetric.Point, 27); break; + case "large": fontSize = new Unit(UnitMetric.Point, 36); break; + case "x-large": fontSize = new Unit(UnitMetric.Point, 48); break; + case "xx-large": fontSize = new Unit(UnitMetric.Point, 72); break; + default: + { + if (fontSize.IsValid || !TryParseFontSize (token, out fontSize, out lineHeight)) + { + fontFamily ??= Converter.ToFontFamily(token); + } + + break; + } } } - for (int i = 0; i < tokenIndexes.Count; i++) + return new HtmlFont(fontSize, fontFamily, style, variant, weight, lineHeight); + } + + private static bool TryParseFontSize(ReadOnlySpan token, out Unit fontSize, out Unit lineHeight) + { + // Handle font-size/line-height + var slash = token.IndexOf('/'); + if (slash > 0) { - fontSize = Unit.Parse(span.Slice(tokens[tokenIndexes[i]])); - if (fontSize.IsValid) - { - tokenIndexes.RemoveAt(i); // no need to process this part anymore - break; - } + fontSize = Unit.Parse(token.Slice(0, slash)); + lineHeight = Unit.Parse(token.Slice(slash + 1)); + return fontSize.IsValid; } - if (!fontSize.IsValid) fontSize = Unit.Empty; - - // keep font family as the latest because it is the most permissive - if(tokenIndexes.Count > 0) - family = Converter.ToFontFamily(span.Slice(tokens[tokenIndexes[0]])); - return new HtmlFont(fontSize, family, style, variant, weight); + fontSize = Unit.Parse(token); + lineHeight = Unit.Empty; + return fontSize.IsValid; } //____________________________________________________________________ // /// - /// Gets or sets the name of this font. + /// Gets the name of this font. /// public string? Family { @@ -142,7 +150,7 @@ public string? Family } /// - /// Gest or sets the style for the text. + /// Gest the style for the text. /// public FontStyle? Style { @@ -150,7 +158,7 @@ public FontStyle? Style } /// - /// Gets or sets the variation of the characters. + /// Gets the variation of the characters. /// public FontVariant? Variant { @@ -158,7 +166,7 @@ public FontVariant? Variant } /// - /// Gets or sets the size of the font, expressed in half points. + /// Gets the size of the font, expressed in half points. /// public Unit Size { @@ -166,10 +174,18 @@ public Unit Size } /// - /// Gets or sets the weight of the characters (thin or thick). + /// Gets the weight of the characters (thin or thick). /// public FontWeight? Weight { get { return weight; } } + + /// + /// Gets the height of a line. + /// + public Unit LineHeight + { + get { return lineHeight; } + } } diff --git a/src/Html2OpenXml/Primitives/Unit.cs b/src/Html2OpenXml/Primitives/Unit.cs index b994bb2d..e54768bb 100755 --- a/src/Html2OpenXml/Primitives/Unit.cs +++ b/src/Html2OpenXml/Primitives/Unit.cs @@ -38,7 +38,7 @@ public Unit(UnitMetric metric, double value) public static Unit Parse(ReadOnlySpan span, UnitMetric defaultMetric = UnitMetric.Unitless) { - span.Trim(); + span = span.Trim(); if (span.Length <= 1) { // either this is invalid or this is a single digit diff --git a/src/Html2OpenXml/Utilities/SpanExtensions.cs b/src/Html2OpenXml/Utilities/SpanExtensions.cs index d9a6c92c..03a26d47 100644 --- a/src/Html2OpenXml/Utilities/SpanExtensions.cs +++ b/src/Html2OpenXml/Utilities/SpanExtensions.cs @@ -141,7 +141,7 @@ public static int SplitCompositeAttribute(this ReadOnlySpan span, Span searchValues = [separator, '(', '\'', '"']; @@ -151,40 +151,47 @@ public static int SplitCompositeAttribute(this ReadOnlySpan span, Span rgb(233,233,233) - int index = escapeSpace? + int index = isEscaping? span.IndexOf(endEscapingChar) : span.IndexOfAny(searchValues); - // end of span, we take the whole match - if (index == -1) index = span.Length; + if (index == -1) + { + // process the last match + destination[matches] = new Range(startIndex, startIndex + offsetIndex + span.Length); + matches++; + break; + } // we find the beginning of an escaping sequence - else if (span[index] != separator && !escapeSpace) + var ch = span[index]; + if (ch != separator && !isEscaping) { - if (span[index] == '(') + if (ch == '(') { endEscapingChar = ')'; offsetIndex += index + 1; } else { - endEscapingChar = span[index]; // ' or " + endEscapingChar = ch; // ' or " if (index == 0) startIndex++; // exclude the quote from the captured range } - escapeSpace = true; + isEscaping = true; isPositiveMatch = false; } // end of escaping sequence - else if (span[index] == endEscapingChar) + else if (ch == endEscapingChar) { - if (span[index] == ')') index++; // include that closing parenthesis in the range - escapeSpace = false; + if (ch == ')') index++; // include that closing parenthesis in the range + isEscaping = false; } // this is a separator but maybe we will need to skip it // eg: "Arial, Verdana bold 1em" -> the space after the comma must be skipped - else if (span[index] == separator && index > 1 && - skipSeparatorIfPrecededBy.HasValue && index > 1 && span[index -1] == skipSeparatorIfPrecededBy) + else if (ch == separator && index > 0 && + skipSeparatorIfPrecededBy.HasValue && span[index -1] == skipSeparatorIfPrecededBy) { + index++; offsetIndex += index + 1; isPositiveMatch = false; } @@ -195,7 +202,7 @@ public static int SplitCompositeAttribute(this ReadOnlySpan span, Span 0 to exclude empty entries - if (!escapeSpace && index > 0 && isPositiveMatch) + if (!isEscaping && index > 0 && isPositiveMatch) { destination[matches] = new Range(startIndex, startIndex + offsetIndex + index); matches++; diff --git a/test/HtmlToOpenXml.Tests/Primitives/FontTests.cs b/test/HtmlToOpenXml.Tests/Primitives/FontTests.cs index 70fc618a..1fa1d28a 100644 --- a/test/HtmlToOpenXml.Tests/Primitives/FontTests.cs +++ b/test/HtmlToOpenXml.Tests/Primitives/FontTests.cs @@ -10,6 +10,7 @@ public class FontTests { [TestCase("1.2em Verdana", ExpectedResult = true)] [TestCase("Verdana 1.2em", ExpectedResult = false)] + [TestCase("italic Verdana", ExpectedResult = false)] public bool WithMinimal_ReturnsValid (string html) { var font = HtmlFont.Parse(html); @@ -59,5 +60,21 @@ public void WithQuotedFamily_ShouldSucceed () Assert.That(font.Size.Value, Is.EqualTo(1.2)); }); } + + [Test] + public void WithFontSizeLineHeight_ShouldSucceed() + { + var font = HtmlFont.Parse("italic small-caps bold 12px/30px Georgia, serif"); + Assert.Multiple(() => { + Assert.That(font.Variant, Is.EqualTo(FontVariant.SmallCaps)); + Assert.That(font.Style, Is.EqualTo(FontStyle.Italic)); + Assert.That(font.Weight, Is.EqualTo(FontWeight.Bold)); + Assert.That(font.Family, Is.EqualTo("Georgia")); + Assert.That(font.Size.Metric, Is.EqualTo(UnitMetric.Pixel)); + Assert.That(font.Size.Value, Is.EqualTo(12)); + Assert.That(font.LineHeight.Metric, Is.EqualTo(UnitMetric.Pixel)); + Assert.That(font.LineHeight.Value, Is.EqualTo(30)); + }); + } } } diff --git a/test/HtmlToOpenXml.Tests/Primitives/StyleParserTests.cs b/test/HtmlToOpenXml.Tests/Primitives/StyleParserTests.cs index 1f307fb0..1820a15a 100644 --- a/test/HtmlToOpenXml.Tests/Primitives/StyleParserTests.cs +++ b/test/HtmlToOpenXml.Tests/Primitives/StyleParserTests.cs @@ -28,7 +28,6 @@ public void DuplicateStyle_ReturnsLatter() [TestCase("color;color;")] [TestCase(":;")] - [TestCase("color:red:red")] [TestCase("color:;")] public void InvalidStyle_ShouldBeEmpty(string htmlStyle) { diff --git a/test/HtmlToOpenXml.Tests/StyleTests.cs b/test/HtmlToOpenXml.Tests/StyleTests.cs index d9228a26..beceff96 100644 --- a/test/HtmlToOpenXml.Tests/StyleTests.cs +++ b/test/HtmlToOpenXml.Tests/StyleTests.cs @@ -175,7 +175,7 @@ public void EncodedStyle_ShouldSucceed() } [Test(Description = "Key style with no value should be ignored")] - public void EmptyStyle_ShouldBeIgnoredd() + public void EmptyStyle_ShouldBeIgnored() { var styleAttributes = HtmlAttributeCollection.ParseStyle("text-decoration;color:red"); Assert.That(styleAttributes["text-decoration"], Is.Null); From 935da6c249627c86498918f56eee505a92a4d5a0 Mon Sep 17 00:00:00 2001 From: Olivier Nizet Date: Mon, 6 Jan 2025 21:07:53 +0100 Subject: [PATCH 25/29] Do not allocate new array in a loop --- src/Html2OpenXml/Primitives/HtmlFont.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Html2OpenXml/Primitives/HtmlFont.cs b/src/Html2OpenXml/Primitives/HtmlFont.cs index 05acdbbf..fd8c02de 100755 --- a/src/Html2OpenXml/Primitives/HtmlFont.cs +++ b/src/Html2OpenXml/Primitives/HtmlFont.cs @@ -81,14 +81,13 @@ public static HtmlFont Parse(ReadOnlySpan span) return Empty; } - + Span loweredValue = stackalloc char[128]; for (int i = 0; i < tokenCount; i++) { var token = span.Slice(tokens[i]).Trim(); - Span loweredValue = token.Length <= 128 ? stackalloc char[token.Length] : new char[token.Length]; token.ToLowerInvariant(loweredValue); - switch (loweredValue) + switch (loweredValue.Slice(0, token.Length)) { case "italic" or "oblique": style = FontStyle.Italic; break; case "normal": From af8711efffeca821b9302a2d074e9d6c7d760514 Mon Sep 17 00:00:00 2001 From: Olivier Nizet Date: Mon, 6 Jan 2025 21:08:03 +0100 Subject: [PATCH 26/29] AngleSharp update --- src/Html2OpenXml/HtmlToOpenXml.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Html2OpenXml/HtmlToOpenXml.csproj b/src/Html2OpenXml/HtmlToOpenXml.csproj index ccff1c31..4e8b4814 100644 --- a/src/Html2OpenXml/HtmlToOpenXml.csproj +++ b/src/Html2OpenXml/HtmlToOpenXml.csproj @@ -49,7 +49,7 @@ - + @@ -72,8 +72,8 @@ - - + + @(ReleaseNoteLines, '%0a') From 9b8f2408667a377694061836efc8ac9fc42a8e1c Mon Sep 17 00:00:00 2001 From: Olivier Nizet Date: Fri, 10 Jan 2025 21:49:40 +0100 Subject: [PATCH 27/29] Ensure to trim input before parsing the color --- src/Html2OpenXml/Primitives/HtmlColor.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Html2OpenXml/Primitives/HtmlColor.cs b/src/Html2OpenXml/Primitives/HtmlColor.cs index b059836f..e668a6cf 100755 --- a/src/Html2OpenXml/Primitives/HtmlColor.cs +++ b/src/Html2OpenXml/Primitives/HtmlColor.cs @@ -48,6 +48,8 @@ public HtmlColor(double alpha, byte red, byte green, byte blue) : this() /// Returns if parsing failed. public static HtmlColor Parse(ReadOnlySpan span) { + span = span.Trim(); + // Is it in hexa? Note: we no more accept hexa value without preceding the '#' if (span[0] == '#') { From 436a600db7eb73b3f4c947bf7b93062ca7799ca4 Mon Sep 17 00:00:00 2001 From: Olivier Nizet Date: Fri, 10 Jan 2025 21:53:32 +0100 Subject: [PATCH 28/29] Use benefits of FrozenDictionary only for net8, no cumbersome net462 with an additional package --- .../Numbering/NumberingExpressionBase.cs | 6 +++++ src/Html2OpenXml/HtmlToOpenXml.csproj | 5 ---- src/Html2OpenXml/IO/ImageHeader.cs | 26 +++++++------------ .../Primitives/HtmlColor.Named.cs | 6 +++++ 4 files changed, 22 insertions(+), 21 deletions(-) diff --git a/src/Html2OpenXml/Expressions/Numbering/NumberingExpressionBase.cs b/src/Html2OpenXml/Expressions/Numbering/NumberingExpressionBase.cs index 1b83ad28..059c3e52 100644 --- a/src/Html2OpenXml/Expressions/Numbering/NumberingExpressionBase.cs +++ b/src/Html2OpenXml/Expressions/Numbering/NumberingExpressionBase.cs @@ -9,7 +9,9 @@ * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A * PARTICULAR PURPOSE. */ +#if NET5_0_OR_GREATER using System.Collections.Frozen; +#endif using System.Collections.Generic; using System.Linq; using AngleSharp.Html.Dom; @@ -293,6 +295,10 @@ private static IReadOnlyDictionary InitKnownLists() knownAbstractNums.Add(listName, abstractNum); } +#if NET5_0_OR_GREATER return knownAbstractNums.ToFrozenDictionary(); +#else + return knownAbstractNums; +#endif } } \ No newline at end of file diff --git a/src/Html2OpenXml/HtmlToOpenXml.csproj b/src/Html2OpenXml/HtmlToOpenXml.csproj index 4e8b4814..ba846a90 100644 --- a/src/Html2OpenXml/HtmlToOpenXml.csproj +++ b/src/Html2OpenXml/HtmlToOpenXml.csproj @@ -37,11 +37,6 @@ - - - - - diff --git a/src/Html2OpenXml/IO/ImageHeader.cs b/src/Html2OpenXml/IO/ImageHeader.cs index 300b10db..c65a0b7a 100755 --- a/src/Html2OpenXml/IO/ImageHeader.cs +++ b/src/Html2OpenXml/IO/ImageHeader.cs @@ -14,7 +14,6 @@ * EMF Specifications: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-emf/ae7e7437-cfe5-485e-84ea-c74b51b000be */ using System; -using System.Collections.Frozen; using System.Collections.Generic; using System.IO; using System.Linq; @@ -36,22 +35,17 @@ public enum FileType { Unrecognized, Bitmap, Gif, Png, Jpeg, Emf, Xml } private static readonly byte[] pngSignatureBytes = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]; - private static readonly IReadOnlyDictionary imageFormatDecoders = InitKnownFormatDecoders(); - - private static IReadOnlyDictionary InitKnownFormatDecoders() + private static readonly Dictionary imageFormatDecoders = new() { - var decoders = new Dictionary() { - { new byte[] { 0x42, 0x4D }, FileType.Bitmap }, - { Encoding.UTF8.GetBytes("GIF87a"), FileType.Gif }, - { Encoding.UTF8.GetBytes("GIF89a"), FileType.Gif }, // animated gif - { pngSignatureBytes, FileType.Png }, - { new byte[] { 0xff, 0xd8 }, FileType.Jpeg }, - { new byte[] { 0x1, 0, 0, 0 }, FileType.Emf }, - { Encoding.UTF8.GetBytes(" x.Length).First().Length; diff --git a/src/Html2OpenXml/Primitives/HtmlColor.Named.cs b/src/Html2OpenXml/Primitives/HtmlColor.Named.cs index c9a786c8..2fbec91c 100755 --- a/src/Html2OpenXml/Primitives/HtmlColor.Named.cs +++ b/src/Html2OpenXml/Primitives/HtmlColor.Named.cs @@ -1,5 +1,7 @@ using System; +#if NET5_0_OR_GREATER using System.Collections.Frozen; +#endif using System.Collections.Generic; namespace HtmlToOpenXml; @@ -169,6 +171,10 @@ private static IReadOnlyDictionary InitKnownColors() { "transparent", FromArgb(0, 0, 0, 0) } }; +#if NET5_0_OR_GREATER return colors.ToFrozenDictionary(); +#else + return colors; +#endif } } \ No newline at end of file From 3d9d9b96a9e28c709729c97a8e398617cd4cfee5 Mon Sep 17 00:00:00 2001 From: Olivier Nizet Date: Wed, 12 Nov 2025 22:45:59 +0100 Subject: [PATCH 29/29] Merge develop --- .github/workflows/publish_nuget.yml | 38 +++ .vscode/settings.json | 4 +- CHANGELOG.md | 47 +++- examples/Demo/Demo.csproj | 1 + examples/Demo/Resources/LargeImg.html | 1 + examples/Demo/app.config | 13 - .../Demo/images/The-Song-of-the-World.jpg | Bin 0 -> 259814 bytes src/Html2OpenXml/Configuration enum.cs | 25 +- .../Expressions/BlockElementExpression.cs | 48 +++- .../Expressions/BodyExpression.cs | 21 +- .../Expressions/FigureCaptionExpression.cs | 76 ++++-- .../Expressions/HtmlDomExpression.cs | 13 +- .../Expressions/HyperlinkExpression.cs | 13 +- .../Expressions/Image/ImageExpression.cs | 79 +++++- .../Numbering/HeadingElementExpression.cs | 63 +++-- .../Expressions/Numbering/ListExpression.cs | 60 ++++- .../Expressions/PhrasingElementExpression.cs | 45 +--- .../Expressions/Table/TableCellExpression.cs | 10 +- .../Expressions/Table/TableColExpression.cs | 36 ++- .../Expressions/Table/TableExpression.cs | 29 ++- .../Expressions/TextExpression.cs | 153 +++++++++-- src/Html2OpenXml/HtmlConverter.cs | 69 +++-- src/Html2OpenXml/HtmlToOpenXml.csproj | 4 +- src/Html2OpenXml/IO/DefaultWebRequest.cs | 6 + src/Html2OpenXml/IO/HtmlImageInfo.cs | 6 + src/Html2OpenXml/IO/ImageHeader.cs | 77 +++--- src/Html2OpenXml/IO/ImagePrefetcher.cs | 162 ++++++++---- src/Html2OpenXml/ParsingContext.cs | 6 +- src/Html2OpenXml/Primitives/DefaultStyles.cs | 7 + src/Html2OpenXml/Primitives/HtmlColor.cs | 15 ++ .../Utilities/CollectionExtensions.cs | 2 +- src/Html2OpenXml/Utilities/Converter.cs | 3 +- test/HtmlToOpenXml.Tests/AbbrTests.cs | 3 +- test/HtmlToOpenXml.Tests/ElementTests.cs | 26 +- test/HtmlToOpenXml.Tests/HeaderFooterTests.cs | 14 +- test/HtmlToOpenXml.Tests/HeadingTests.cs | 22 ++ .../HtmlToOpenXml.Tests.csproj | 10 +- .../ImageFormats/ImageHeaderTests.cs | 10 + test/HtmlToOpenXml.Tests/ImgTests.cs | 238 +++++++++++++++++- test/HtmlToOpenXml.Tests/LinkTests.cs | 21 +- test/HtmlToOpenXml.Tests/NumberingTests.cs | 33 ++- test/HtmlToOpenXml.Tests/ParserTests.cs | 23 +- .../Resources/Mozilla_dinosaur_head_logo.svg | 10 + .../Resources/The-Song-of-the-World.jpg | Bin 0 -> 259814 bytes test/HtmlToOpenXml.Tests/Resources/smiley.gif | Bin 0 -> 1595 bytes test/HtmlToOpenXml.Tests/TableTests.cs | 117 ++++++++- .../Utilities/MockHttpMessageHandler.cs | 35 +++ .../Utilities/ProxyHttpMessageHandler.cs | 22 ++ test/HtmlToOpenXml.Tests/WhitespaceTests.cs | 43 +++- 49 files changed, 1410 insertions(+), 349 deletions(-) create mode 100644 .github/workflows/publish_nuget.yml create mode 100644 examples/Demo/Resources/LargeImg.html delete mode 100644 examples/Demo/app.config create mode 100644 examples/Demo/images/The-Song-of-the-World.jpg create mode 100644 test/HtmlToOpenXml.Tests/Resources/Mozilla_dinosaur_head_logo.svg create mode 100644 test/HtmlToOpenXml.Tests/Resources/The-Song-of-the-World.jpg create mode 100644 test/HtmlToOpenXml.Tests/Resources/smiley.gif create mode 100644 test/HtmlToOpenXml.Tests/Utilities/MockHttpMessageHandler.cs create mode 100644 test/HtmlToOpenXml.Tests/Utilities/ProxyHttpMessageHandler.cs diff --git a/.github/workflows/publish_nuget.yml b/.github/workflows/publish_nuget.yml new file mode 100644 index 00000000..02b81d49 --- /dev/null +++ b/.github/workflows/publish_nuget.yml @@ -0,0 +1,38 @@ +# This workflow will build, pack and deploy the solution on Nuget + +name: 'publish_nuget.yml' + +on: + push: + tags: + - '[0-9]+.[0-9]+' + branches: + - master + +jobs: + publish: + if: startsWith(github.ref, 'refs/tags/') && github.ref_type == 'tag' && github.ref_name != '' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Ensure tag is on master + run: | + TAG_COMMIT=$(git rev-list -n 1 ${{ github.ref_name }}) + if ! git merge-base --is-ancestor $TAG_COMMIT origin/master; then + echo "Tag is not on master branch. Skipping publish." + exit 1 + fi + - name: Setup .NET 8. + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '8.0.x' + - name: Build + run: dotnet build --configuration Release + - name: Pack + run: dotnet pack src/Html2OpenXml/HtmlToOpenXml.csproj --configuration Release --output ./nupkg + - name: Push nuget to NuGet.org + run: dotnet nuget push ./nupkg/*.nupkg --api-key $NUGET_API_KEY -s https://api.nuget.org/v3/index.json + env: + NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} + - name: Create Release and Upload Artifact to Release + run: gh release create ${{github.ref_name}} -t "Release ${{github.ref_name}}" *.nupkg --generate-notes --draft diff --git a/.vscode/settings.json b/.vscode/settings.json index e8962d50..9b58ce6b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,9 +1,9 @@ { - "omnisharp.organizeImportsOnFormat": true, "dotnet.completion.showCompletionItemsFromUnimportedNamespaces": false, "coverage-gutters.coverageFileNames":[ "coverage.info" ], "coverage-gutters.showGutterCoverage": false, - "coverage-gutters.showLineCoverage": true + "coverage-gutters.showLineCoverage": true, + "dotnet.formatting.organizeImportsOnFormat": true } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index a2d35708..894c94b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,52 @@ - Rewriting of parsing to use System.Span instead of Regex - Set Timeout on remaining Regex to prevent any DoS attack -======= + +## 3.2.8 + +- Fix a fatal crash when trying to convert multiple images #215 +- New feature to allow to reference external image instead of embedding them #216 +- Fix a potential issue on image streams that are disposed too early. +- Support table col with percentage width #206 + +## 3.2.7 + +- Fix handling Uri with an anchor #209 +- New option DefaultStyles.NumberedHeadingStyle to support an alternate heading style #210 + +## 3.2.6 + +(wrong packaging, same code as 3.2.5) + +## 3.2.5 + +- Fix a crash with the new whitespace handling introduced in 3.2.3 #191 +- Fix crash when the html contains 2 images with identical source path #193 +- Support margin auto for table alignment #194 +- Fix handling whitespace between runs #195 +- Whitelist more mime-types as specified by the IANA standard #196 +- Support EMF file #196 +- Correct handling of `figcaption` (allow nested phrasings) #197 +- Numbering list now supports type attribute `
    ` #198 +- Always restart nested numbering list #198 +- Fix table borders being removed even when the specified word table style has borders #199 +- Defensive code when download image stream is truncated #201 +- Table inside list is constrained to not exceed page margin #202 +- Table now supports width:auto for auto-fit content #202 + +## 3.2.4 + +- Fix a crash with the new whitespace handling introduced in 3.2.3 #191 +- Table inside list must be aligned with the list item #192 + +## 3.2.3 + +- Improve support of table alignment #187 +- Fix a crash if a span is empty +- Heading with only digits should not be considered as a numbering #189 +- Fix whitespaces inserted between spans #179 and #185 +- Support percentage size (typically width:100%) for img node #188 + ## 3.2.2 - Supports a feature to disable heading numbering #175 diff --git a/examples/Demo/Demo.csproj b/examples/Demo/Demo.csproj index 851f0dab..ac505943 100644 --- a/examples/Demo/Demo.csproj +++ b/examples/Demo/Demo.csproj @@ -22,6 +22,7 @@ + \ No newline at end of file diff --git a/examples/Demo/Resources/LargeImg.html b/examples/Demo/Resources/LargeImg.html new file mode 100644 index 00000000..79b187ce --- /dev/null +++ b/examples/Demo/Resources/LargeImg.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/Demo/app.config b/examples/Demo/app.config deleted file mode 100644 index 400b70b3..00000000 --- a/examples/Demo/app.config +++ /dev/null @@ -1,13 +0,0 @@ - - - - \ No newline at end of file diff --git a/examples/Demo/images/The-Song-of-the-World.jpg b/examples/Demo/images/The-Song-of-the-World.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5e1d898328c7e493304fae755ee1e690e40f3273 GIT binary patch literal 259814 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�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
  1. $4h#VHxI4!B%ZXT_d#6^yvN6+|BmLZU9DTm` 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

    ;E))?^KFAr*O_3quu60XdW}MRuft8kt-1At4 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

    5&>e@2i#4KXbj)Gl~S-97hK9( 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

    mD^thfJ2FT@UK6G2AG@UJ^n|MqX-@XH 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

    &NgTvgu3ChN0z+O4z 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 N`eb+iTJo={{{tUUmEiyY literal 0 HcmV?d00001 diff --git a/src/Html2OpenXml/Configuration enum.cs b/src/Html2OpenXml/Configuration enum.cs index e5dc13da..f9b0893f 100755 --- a/src/Html2OpenXml/Configuration enum.cs +++ b/src/Html2OpenXml/Configuration enum.cs @@ -46,4 +46,27 @@ public readonly struct QuoteChars(string begin, string end) internal string Prefix { get; } = begin; internal string Suffix { get; } = end; -} \ No newline at end of file +} + +///

    +/// Specifies how images should be processed during HTML to OpenXML conversion. +/// +public enum ImageProcessingMode +{ + /// + /// Downloads and embeds all images into the document (default behaviour). + /// This creates self-contained documents but may result in large file sizes. + /// + Embed = 0, + /// + /// Links to external images via external relationships instead of downloading them. + /// This keeps document size small but images won't display offline or if URLs become unavailable. + /// Data URI images (base64 encoded) are still embedded. + /// + LinkExternal = 1, + /// + /// Only embeds data URI images (base64 encoded inline images). + /// External images (http/https/file) are skipped entirely. + /// + EmbedDataUriOnly = 2, +} diff --git a/src/Html2OpenXml/Expressions/BlockElementExpression.cs b/src/Html2OpenXml/Expressions/BlockElementExpression.cs index 1e37542c..233fa68c 100644 --- a/src/Html2OpenXml/Expressions/BlockElementExpression.cs +++ b/src/Html2OpenXml/Expressions/BlockElementExpression.cs @@ -27,6 +27,7 @@ class BlockElementExpression: PhrasingElementExpression { private readonly OpenXmlLeafElement[]? defaultStyleProperties; protected readonly ParagraphProperties paraProperties = new(); + protected TableProperties? tableProperties; // some style attributes, such as borders or bgcolor, will convert this node to a framed container protected bool renderAsFramed; private HtmlBorder styleBorder; @@ -115,22 +116,42 @@ protected override IEnumerable Interpret ( public override void CascadeStyles(OpenXmlElement element) { base.CascadeStyles(element); - if (!paraProperties.HasChildren || element is not Paragraph paragraph) + if (!paraProperties.HasChildren) return; - paragraph.ParagraphProperties ??= new ParagraphProperties(); + if (element is Paragraph paragraph) + { + paragraph.ParagraphProperties ??= new ParagraphProperties(); + + var knownTags = new HashSet(); + foreach (var prop in paragraph.ParagraphProperties) + { + if (!knownTags.Contains(prop.LocalName)) + knownTags.Add(prop.LocalName); + } - var knownTags = new HashSet(); - foreach (var prop in paragraph.ParagraphProperties) + foreach (var prop in paraProperties) + { + if (!knownTags.Contains(prop.LocalName)) + paragraph.ParagraphProperties.AddChild(prop.CloneNode(true)); + } + } + else if (tableProperties != null && element is Table table) { - if (!knownTags.Contains(prop.LocalName)) + var props = table.GetFirstChild(); + if (props is null) + return; + + var knownTags = new HashSet(); + foreach (var prop in props.Where(p => !knownTags.Contains(p.LocalName))) + { knownTags.Add(prop.LocalName); - } + } - foreach (var prop in paraProperties) - { - if (!knownTags.Contains(prop.LocalName)) - paragraph.ParagraphProperties.AddChild(prop.CloneNode(true)); + foreach (var prop in tableProperties.Where(p => !knownTags.Contains(p.LocalName))) + { + props.AddChild(prop.CloneNode(true)); + } } } @@ -170,9 +191,12 @@ protected override void ComposeStyles (ParsingContext context) JustificationValues? align = Converter.ToParagraphAlign(styleAttributes!["text-align"]); if (!align.HasValue) align = Converter.ToParagraphAlign(node.GetAttribute("align")); + if (!align.HasValue) align = Converter.ToParagraphAlign(styleAttributes["justify-content"]); if (align.HasValue) { paraProperties.Justification = new() { Val = align }; + tableProperties ??= new(); + tableProperties.TableJustification = new() { Val = align.Value.ToTableRowAlignment() }; } @@ -194,7 +218,7 @@ protected override void ComposeStyles (ParsingContext context) } var margin = styleAttributes.GetMargin("margin"); - Indentation? indentation = null; + Indentation? indentation = null; if (!margin.IsEmpty) { if (margin.Top.IsFixed || margin.Bottom.IsFixed) @@ -345,7 +369,7 @@ private static Paragraph CreateParagraph(ParsingContext context, IList Interpret(ParsingContext context) { MarkAllBookmarks(); + var body = context.MainPart.Document.Body!; + var sectionProperties = body.Descendants().LastOrDefault(); + if (sectionProperties != null) + { + context.IsLandscape = sectionProperties.GetFirstChild()?.Width?.Value >= PortraitPageHeight; + } + var elements = base.Interpret(context); if (shouldRegisterTopBookmark && elements.Any()) { // Check whether it already exists - var body = context.MainPart.Document.Body!; if (body.Descendants().Where(b => b.Name?.Value == "_top").Any()) { return elements; @@ -70,6 +79,7 @@ protected override void ComposeStyles(ParsingContext context) var sectionProperties = mainPart.Document.Body!.GetFirstChild(); if (sectionProperties == null || sectionProperties.GetFirstChild() == null) { + context.IsLandscape = orientation == PageOrientationValues.Landscape; mainPart.Document.Body.Append(ChangePageOrientation(orientation)); } else @@ -80,6 +90,9 @@ protected override void ComposeStyles(ParsingContext context) SectionProperties validSectionProp = ChangePageOrientation(orientation); pageSize?.Remove(); sectionProperties.PrependChild(validSectionProp.GetFirstChild()!.CloneNode(true)); + + overridenContext = context.CreateChild(this); + overridenContext.IsLandscape = orientation == PageOrientationValues.Landscape; } } } @@ -101,14 +114,14 @@ protected override void ComposeStyles(ParsingContext context) ///

private static SectionProperties ChangePageOrientation(PageOrientationValues orientation) { - PageSize pageSize = new() { Width = (UInt32Value) 16838U, Height = (UInt32Value) 11906U }; + PageSize pageSize = new() { Width = PortraitPageWidth, Height = PortraitPageHeight }; if (orientation == PageOrientationValues.Portrait) { - (pageSize.Height, pageSize.Width) = (pageSize.Width, pageSize.Height); + pageSize.Orient = orientation; } else { - pageSize.Orient = orientation; + (pageSize.Height, pageSize.Width) = (pageSize.Width, pageSize.Height); } return new SectionProperties ( diff --git a/src/Html2OpenXml/Expressions/FigureCaptionExpression.cs b/src/Html2OpenXml/Expressions/FigureCaptionExpression.cs index 5e8881fc..912a8c4a 100644 --- a/src/Html2OpenXml/Expressions/FigureCaptionExpression.cs +++ b/src/Html2OpenXml/Expressions/FigureCaptionExpression.cs @@ -1,4 +1,4 @@ -/* Copyright (C) Olivier Nizet https://github.com/onizet/html2openxml - All Rights Reserved +/* Copyright (C) Olivier Nizet https://github.com/onizet/html2openxml - All Rights Reserved * * This source is subject to the Microsoft Permissive License. * Please see the License.txt file for more information. @@ -21,7 +21,7 @@ namespace HtmlToOpenXml.Expressions; /// /// Process the parsing of a figcaption element, which is used to describe an image. /// -sealed class FigureCaptionExpression(IHtmlElement node) : PhrasingElementExpression(node) +sealed class FigureCaptionExpression(IHtmlElement node) : BlockElementExpression(node) { /// @@ -29,10 +29,8 @@ public override IEnumerable Interpret (ParsingContext context) { ComposeStyles(context); var childElements = Interpret(context.CreateChild(this), node.ChildNodes); - if (!childElements.Any()) - return []; - var p = new Paragraph ( + var figNumRef = new List() { new Run( new Text("Figure ") { Space = SpaceProcessingModeValues.Preserve } ), @@ -40,21 +38,53 @@ public override IEnumerable Interpret (ParsingContext context) new Run( new Text(AddFigureCaption(context).ToString(CultureInfo.InvariantCulture))) ) { Instruction = " SEQ Figure \\* ARABIC " } - ) { - ParagraphProperties = new ParagraphProperties { - ParagraphStyleId = context.DocumentStyle.GetParagraphStyle(context.DocumentStyle.DefaultStyles.CaptionStyle), - KeepNext = new KeepNext() - } }; - if (childElements.First() is Run run) // any caption? + + if (!childElements.Any()) + { + return [new Paragraph(figNumRef) { + ParagraphProperties = new ParagraphProperties { + ParagraphStyleId = context.DocumentStyle.GetParagraphStyle(context.DocumentStyle.DefaultStyles.CaptionStyle), + KeepNext = DetermineKeepNext(node), + } + }]; + } + + //Add the figure number references to the start of the first paragraph. + if(childElements.First() is Paragraph p) + { + var properties = p.GetFirstChild(); + p.InsertAfter(new Run( + new Text(" ") { Space = SpaceProcessingModeValues.Preserve } + ), properties); + p.InsertAfter(figNumRef[1], properties); + p.InsertAfter(figNumRef[0], properties); + } + else + { + // The first child of the figure caption is a table or something. + // Just prepend a new paragraph with the figure number reference. + childElements = [ + new Paragraph(figNumRef), + ..childElements + ]; + } + + foreach (var paragraph in childElements.OfType()) + { + paragraph.ParagraphProperties ??= new ParagraphProperties(); + paragraph.ParagraphProperties.ParagraphStyleId ??= context.DocumentStyle.GetParagraphStyle(context.DocumentStyle.DefaultStyles.CaptionStyle); + //Keep caption paragraphs together. + paragraph.ParagraphProperties.KeepNext = new KeepNext(); + } + + if(childElements.OfType().LastOrDefault() is Paragraph lastPara) { - Text? t = run.GetFirstChild(); - if (t != null) - t.Text = " " + t.InnerText; // append a space after the numero of the picture + lastPara.ParagraphProperties!.KeepNext = DetermineKeepNext(node); } - return [p]; + return childElements; } /// @@ -78,4 +108,18 @@ private static int AddFigureCaption(ParsingContext context) context.Properties("figCaptionRef", figCaptionRef); return figCaptionRef.Value; } -} \ No newline at end of file + + /// + /// Determines whether the KeepNext property should apply this this caption. + /// + /// A new or null. + private static KeepNext? DetermineKeepNext(IHtmlElement node) + { + // A caption at the end of a figure will have no next sibling. + if(node.NextElementSibling is null) + { + return null; + } + return new(); + } +} diff --git a/src/Html2OpenXml/Expressions/HtmlDomExpression.cs b/src/Html2OpenXml/Expressions/HtmlDomExpression.cs index 44ec6bc0..3efc82ef 100644 --- a/src/Html2OpenXml/Expressions/HtmlDomExpression.cs +++ b/src/Html2OpenXml/Expressions/HtmlDomExpression.cs @@ -38,9 +38,11 @@ private static Dictionary> InitKnownTa { TagNames.Abbr, el => new AbbreviationExpression((IHtmlElement) el) }, { "acronym", el => new AbbreviationExpression((IHtmlElement) el) }, { TagNames.B, el => new PhrasingElementExpression((IHtmlElement) el, new Bold()) }, + { TagNames.Big, el => new PhrasingElementExpression((IHtmlElement) el, new FontSize() { Val = "36" }) }, { TagNames.BlockQuote, el => new BlockQuoteExpression((IHtmlElement) el) }, { TagNames.Br, _ => new LineBreakExpression() }, { TagNames.Cite, el => new CiteElementExpression((IHtmlElement) el) }, + { TagNames.Code, el => new PhrasingElementExpression((IHtmlElement) el) }, { TagNames.Dd, el => new BlockElementExpression((IHtmlElement) el, new Indentation() { FirstLine = "708" }, new SpacingBetweenLines() { After = "0" }) }, { TagNames.Del, el => new PhrasingElementExpression((IHtmlElement) el, new Strike()) }, { TagNames.Dfn, el => new AbbreviationExpression((IHtmlElement) el) }, @@ -57,10 +59,18 @@ private static Dictionary> InitKnownTa { TagNames.Hr, el => new HorizontalLineExpression((IHtmlElement) el) }, { TagNames.Img, el => new ImageExpression((IHtmlImageElement) el) }, { TagNames.Ins, el => new PhrasingElementExpression((IHtmlElement) el, new Underline() { Val = UnderlineValues.Single }) }, + { TagNames.Kbd, el => new PhrasingElementExpression((IHtmlElement) el) }, + { TagNames.Mark, el => new PhrasingElementExpression((IHtmlElement) el, new Shading { Val = ShadingPatternValues.Clear, Fill = "FFFF00" /* yellow */ }) }, + { TagNames.NoBr, el => new PhrasingElementExpression((IHtmlElement) el) }, { TagNames.Ol, el => new ListExpression((IHtmlElement) el) }, { TagNames.Pre, el => new PreElementExpression((IHtmlElement) el) }, { TagNames.Q, el => new QuoteElementExpression((IHtmlElement) el) }, { TagNames.Quote, el => new QuoteElementExpression((IHtmlElement) el) }, + { TagNames.Rb, el => new PhrasingElementExpression((IHtmlElement) el) }, + { TagNames.Rt, el => new PhrasingElementExpression((IHtmlElement) el) }, + { TagNames.Ruby, el => new BlockElementExpression((IHtmlElement) el) }, + { TagNames.Samp, el => new PhrasingElementExpression((IHtmlElement) el) }, + { TagNames.Small, el => new PhrasingElementExpression((IHtmlElement) el, new FontSize() { Val = "20" }) }, { TagNames.Span, el => new PhrasingElementExpression((IHtmlElement) el) }, { TagNames.S, el => new PhrasingElementExpression((IHtmlElement) el, new Strike()) }, { TagNames.Strike, el => new PhrasingElementExpression((IHtmlElement) el, new Strike()) }, @@ -70,8 +80,10 @@ private static Dictionary> InitKnownTa { TagNames.Svg, el => new SvgExpression((AngleSharp.Svg.Dom.ISvgSvgElement) el) }, { TagNames.Table, el => new TableExpression((IHtmlTableElement) el) }, { TagNames.Time, el => new PhrasingElementExpression((IHtmlElement) el) }, + { TagNames.Tt, el => new PhrasingElementExpression((IHtmlElement) el) }, { TagNames.U, el => new PhrasingElementExpression((IHtmlElement) el, new Underline() { Val = UnderlineValues.Single }) }, { TagNames.Ul, el => new ListExpression((IHtmlElement) el) }, + { TagNames.Var, el => new PhrasingElementExpression((IHtmlElement) el) } }; return knownTags; @@ -83,7 +95,6 @@ private static Dictionary> InitKnownTa /// The parsing context. public abstract IEnumerable Interpret (ParsingContext context); - /// /// Create a new interpreter for the given html tag. /// diff --git a/src/Html2OpenXml/Expressions/HyperlinkExpression.cs b/src/Html2OpenXml/Expressions/HyperlinkExpression.cs index 62221ecd..79fd8bee 100644 --- a/src/Html2OpenXml/Expressions/HyperlinkExpression.cs +++ b/src/Html2OpenXml/Expressions/HyperlinkExpression.cs @@ -112,12 +112,6 @@ public override IEnumerable Interpret (ParsingContext context) { h = new Hyperlink() { History = true, Anchor = "_top" }; } - // is it an anchor? - else if (context.Converter.SupportsAnchorLinks && linkNode.Hash.Length > 1 && linkNode.Hash[0] == '#') - { - h = new Hyperlink( - ) { History = true, Anchor = linkNode.Hash.Substring(1) }; - } // ensure the links does not start with javascript: else if (AngleSharpExtensions.TryParseUrl(att, UriKind.Absolute, out var uri)) { @@ -126,6 +120,13 @@ public override IEnumerable Interpret (ParsingContext context) h = new Hyperlink( ) { History = true, Id = extLink.Id }; } + // is it an anchor? + else if (context.Converter.SupportsAnchorLinks && linkNode.Hash.Length > 1 && linkNode.Hash[0] == '#') + { + h = new Hyperlink( + ) + { History = true, Anchor = linkNode.Hash.Substring(1) }; + } if (h == null) { diff --git a/src/Html2OpenXml/Expressions/Image/ImageExpression.cs b/src/Html2OpenXml/Expressions/Image/ImageExpression.cs index a4b61c30..24907b59 100644 --- a/src/Html2OpenXml/Expressions/Image/ImageExpression.cs +++ b/src/Html2OpenXml/Expressions/Image/ImageExpression.cs @@ -56,9 +56,14 @@ class ImageExpression(IHtmlImageElement node) : ImageExpressionBase(node) } if (imgNode.DisplayHeight > 0) { - // Image perspective skewed. Bug fixed by ddeforge on github.com/onizet/html2openxml/discussions/350500 preferredSize.Height = imgNode.DisplayHeight; } + if (preferredSize.IsEmpty) + { + var styles = imgNode.GetStyles(); + preferredSize.Width = GetDimension(styles, "width", "max-width", 642); + preferredSize.Height = GetDimension(styles, "height", "max-height", 428); + } HtmlImageInfo? iinfo = context.ImageLoader.Download(src, CancellationToken.None) .ConfigureAwait(false).GetAwaiter().GetResult(); @@ -85,9 +90,18 @@ class ImageExpression(IHtmlImageElement node) : ImageExpressionBase(node) else if (preferredSize.Width <= 0 || preferredSize.Height <= 0) { Size actualSize = iinfo.Size; + // Image perspective skewed. Bug fixed by ddeforge on github.com/onizet/html2openxml/discussions/350500 preferredSize = ImageHeader.KeepAspectRatio(actualSize, preferredSize); } + // If size is still empty (e.g., for external linked images), use default dimensions + if (preferredSize.IsEmpty || preferredSize.Width <= 0 || preferredSize.Height <= 0) + { + // Use default size for external images or when size cannot be determined + // Default to a reasonable size (similar to how browsers handle images with unknown dimensions) + preferredSize = new Size(300, 200); + } + long widthInEmus = new Unit(UnitMetric.Pixel, preferredSize.Width).ValueInEmus; long heightInEmus = new Unit(UnitMetric.Pixel, preferredSize.Height).ValueInEmus; @@ -97,22 +111,26 @@ class ImageExpression(IHtmlImageElement node) : ImageExpressionBase(node) new wp.Extent() { Cx = widthInEmus, Cy = heightInEmus }, new wp.EffectExtent() { LeftEdge = 19050L, TopEdge = 0L, RightEdge = 0L, BottomEdge = 0L }, new wp.DocProperties() { Id = drawingObjId, Name = "Picture " + imageObjId, Description = string.Empty }, - new wp.NonVisualGraphicFrameDrawingProperties { + new wp.NonVisualGraphicFrameDrawingProperties + { GraphicFrameLocks = new a.GraphicFrameLocks() { NoChangeAspect = true } }, new a.Graphic( new a.GraphicData( new pic.Picture( - new pic.NonVisualPictureProperties { - NonVisualDrawingProperties = new pic.NonVisualDrawingProperties() { + new pic.NonVisualPictureProperties + { + NonVisualDrawingProperties = new pic.NonVisualDrawingProperties() + { Id = imageObjId, Name = DataUri.IsWellFormed(src) ? string.Empty : src, - Description = alt }, + Description = alt + }, NonVisualPictureDrawingProperties = new pic.NonVisualPictureDrawingProperties( new a.PictureLocks() { NoChangeAspect = true, NoChangeArrowheads = true }) }, new pic.BlipFill( - new a.Blip() { Embed = iinfo.ImagePartId }, + CreateBlip(iinfo), new a.SourceRectangle(), new a.Stretch( new a.FillRectangle())), @@ -122,12 +140,51 @@ class ImageExpression(IHtmlImageElement node) : ImageExpressionBase(node) new a.Extents() { Cx = widthInEmus, Cy = heightInEmus }), new a.PresetGeometry( new a.AdjustValueList() - ) { Preset = a.ShapeTypeValues.Rectangle } - ) { BlackWhiteMode = a.BlackWhiteModeValues.Auto }) - ) { Uri = "http://schemas.openxmlformats.org/drawingml/2006/picture" }) - ) { DistanceFromTop = (UInt32Value) 0U, DistanceFromBottom = (UInt32Value) 0U, DistanceFromLeft = (UInt32Value) 0U, DistanceFromRight = (UInt32Value) 0U } + ) + { Preset = a.ShapeTypeValues.Rectangle } + ) + { BlackWhiteMode = a.BlackWhiteModeValues.Auto }) + ) + { Uri = "http://schemas.openxmlformats.org/drawingml/2006/picture" }) + ) + { DistanceFromTop = (UInt32Value)0U, DistanceFromBottom = (UInt32Value)0U, DistanceFromLeft = (UInt32Value)0U, DistanceFromRight = (UInt32Value)0U } ); return img; } -} \ No newline at end of file + + private static int GetDimension(HtmlAttributeCollection styles, string primaryStyle, string fallbackStyle, int percentageBase) + { + var unit = styles.GetUnit(primaryStyle); + if (!unit.IsValid) + { + unit = styles.GetUnit(fallbackStyle); + } + + if (unit.IsValid) + { + return unit.Metric == UnitMetric.Percent ? + (int)(unit.Value * percentageBase / 100) : + unit.ValueInPx; + } + + return 0; + } + + /// + /// Creates a Blip element with either an embedded or external image reference. + /// + private static a.Blip CreateBlip(HtmlImageInfo iinfo) + { + if (iinfo.IsExternal) + { + // Use Link property for external images + return new a.Blip() { Link = iinfo.ImagePartId }; + } + else + { + // Use Embed property for embedded images (default behaviour) + return new a.Blip() { Embed = iinfo.ImagePartId }; + } + } +} diff --git a/src/Html2OpenXml/Expressions/Numbering/HeadingElementExpression.cs b/src/Html2OpenXml/Expressions/Numbering/HeadingElementExpression.cs index a02e6533..e4c0d71c 100644 --- a/src/Html2OpenXml/Expressions/Numbering/HeadingElementExpression.cs +++ b/src/Html2OpenXml/Expressions/Numbering/HeadingElementExpression.cs @@ -24,7 +24,8 @@ namespace HtmlToOpenXml.Expressions; /// sealed class HeadingElementExpression(IHtmlElement node) : NumberingExpressionBase(node) { - private static readonly Regex numberingRegex = new(@"^\s*(\d+\.?)*\s*", RegexOptions.Compiled, TimeSpan.FromMilliseconds(100)); + private static readonly Regex numberingRegex = new(@"^\s*(?[0-9\.]+\s*)[^0-9]", + RegexOptions.Compiled, TimeSpan.FromMilliseconds(100)); /// public override IEnumerable Interpret (ParsingContext context) @@ -37,28 +38,45 @@ public override IEnumerable Interpret (ParsingContext context) var paragraph = childElements.FirstOrDefault() as Paragraph; - paragraph ??= new Paragraph(childElements); + paragraph ??= new(childElements); paragraph.ParagraphProperties ??= new(); - paragraph.ParagraphProperties.ParagraphStyleId = - context.DocumentStyle.GetParagraphStyle(context.DocumentStyle.DefaultStyles.HeadingStyle + level); - + var runElement = childElements.FirstOrDefault(); if (runElement != null && context.Converter.SupportsHeadingNumbering && IsNumbering(runElement)) { - var abstractNumId = GetOrCreateListTemplate(context, HeadingNumberingName); - var instanceId = GetListInstance(abstractNumId); - if (!instanceId.HasValue) + if (string.Equals(context.DocumentStyle.DefaultStyles.HeadingStyle, context.DocumentStyle.DefaultStyles.NumberedHeadingStyle)) { - instanceId = IncrementInstanceId(context, abstractNumId); + // Only apply the numbering if a custom numbered heading style has not been defined. + // If the user defined a custom numbered heading style (with numbering), Word has + // the numbering automatically done. + // Defining a numbering here messes that up, so we only add the numbering if + // a specific numbering heading style has not been provided + var abstractNumId = GetOrCreateListTemplate(context, HeadingNumberingName); + var instanceId = GetListInstance(abstractNumId); + + if (!instanceId.HasValue) + { + instanceId = IncrementInstanceId(context, abstractNumId); + } + + var numbering = context.MainPart.NumberingDefinitionsPart!.Numbering!; + numbering.Append( + new NumberingInstance( + new AbstractNumId() { Val = abstractNumId } + ) + { NumberID = instanceId }); + SetNumbering(paragraph, level - '0', instanceId.Value); } - var numbering = context.MainPart.NumberingDefinitionsPart!.Numbering!; - numbering.Append( - new NumberingInstance( - new AbstractNumId() { Val = abstractNumId } - ) - { NumberID = instanceId }); - SetNumbering(paragraph, level - '0', instanceId.Value); + // Apply numbered heading style + paragraph.ParagraphProperties.ParagraphStyleId = + context.DocumentStyle.GetParagraphStyle(context.DocumentStyle.DefaultStyles.NumberedHeadingStyle + level); + } + else + { + // Apply normal heading style + paragraph.ParagraphProperties.ParagraphStyleId = + context.DocumentStyle.GetParagraphStyle(context.DocumentStyle.DefaultStyles.HeadingStyle + level); } return [paragraph]; @@ -66,12 +84,16 @@ public override IEnumerable Interpret (ParsingContext context) private static bool IsNumbering(OpenXmlElement runElement) { + if (runElement.InnerText is null) + return false; + // Check if the line starts with a number format (1., 1.1., 1.1.1.) // If it does, make sure we make the heading a numbered item + var headingText = runElement.InnerText; Match regexMatch; try { - regexMatch = numberingRegex.Match(runElement.InnerText ?? string.Empty); + regexMatch = numberingRegex.Match(headingText); } catch (RegexMatchTimeoutException) { @@ -79,11 +101,12 @@ private static bool IsNumbering(OpenXmlElement runElement) } // Make sure we only grab the heading if it starts with a number - if (regexMatch.Groups.Count > 1 && regexMatch.Groups[1].Captures.Count > 0) + if (regexMatch.Success && headingText.Length > regexMatch.Groups["number"].Length) { - // Strip numbers from text + // Strip numbers from text + headingText = headingText.Substring(regexMatch.Groups["number"].Length); runElement.InnerXml = runElement.InnerXml - .Replace(runElement.InnerText!, runElement.InnerText!.Substring(regexMatch.Length)); + .Replace(runElement.InnerText!, headingText); return true; } diff --git a/src/Html2OpenXml/Expressions/Numbering/ListExpression.cs b/src/Html2OpenXml/Expressions/Numbering/ListExpression.cs index 3fa20af3..ed7af86d 100644 --- a/src/Html2OpenXml/Expressions/Numbering/ListExpression.cs +++ b/src/Html2OpenXml/Expressions/Numbering/ListExpression.cs @@ -1,4 +1,4 @@ -/* Copyright (C) Olivier Nizet https://github.com/onizet/html2openxml - All Rights Reserved +/* Copyright (C) Olivier Nizet https://github.com/onizet/html2openxml - All Rights Reserved * * This source is subject to the Microsoft Permissive License. * Please see the License.txt file for more information. @@ -91,6 +91,24 @@ public override IEnumerable Interpret(ParsingContext context) var childElements = expression.Interpret(context); if (!childElements.Any()) continue; + // table must be aligned to the list item + var tables = childElements.OfType(); + var tableIndentation = level * Indentation * 2; + foreach (var table in tables) + { + var tableProperties = table.GetFirstChild(); + if (tableProperties == null) + table.PrependChild(tableProperties = new()); + + tableProperties.TableIndentation ??= new() { Width = tableIndentation }; + // ensure to restrain the table width to the list item + if (tableProperties.TableWidth?.Type?.Value == TableWidthUnitValues.Pct + && tableProperties.TableWidth?.Width?.Value == "5000") + { + tableProperties.TableWidth.Width = (5000 - tableIndentation).ToString(); + } + } + // ensure to filter out any non-paragraph like any nested table var paragraphs = childElements.OfType(); var listItemStyleId = GetStyleIdForListItem(context.DocumentStyle, liNode); @@ -143,7 +161,15 @@ private ListContext ConcretiseInstance(ParsingContext context, int abstractNumId int overrideLevelIndex = 0; var isOrderedTag = node.NodeName.Equals("ol", StringComparison.OrdinalIgnoreCase); var dir = node.GetTextDirection(); - if (!instanceId.HasValue || context.Converter.ContinueNumbering == false) + + // be sure to restart to 1 any nested ordered list + if (currentLevel > 0 && isOrderedTag) + { + instanceId = IncrementInstanceId(context, abstractNumId, isReusable: false); + overrideLevelIndex = currentLevel; + listContext = new ListContext(listStyle, abstractNumId, instanceId.Value, currentLevel + 1, dir); + } + else if (!instanceId.HasValue || context.Converter.ContinueNumbering == false) { // create a new instance of that list template instanceId = IncrementInstanceId(context, abstractNumId, isReusable: context.Converter.ContinueNumbering); @@ -158,13 +184,6 @@ private ListContext ConcretiseInstance(ParsingContext context, int abstractNumId instanceId = IncrementInstanceId(context, abstractNumId, isReusable: false); listContext = new ListContext(listStyle, abstractNumId, instanceId.Value, 1, dir); } - // be sure to restart to 1 any nested ordered list - else if (currentLevel > 0 && isOrderedTag) - { - instanceId = IncrementInstanceId(context, abstractNumId, isReusable: false); - overrideLevelIndex = currentLevel; - listContext = new ListContext(listStyle, abstractNumId, instanceId.Value, currentLevel + 1, dir); - } else { return new ListContext(listStyle, abstractNumId, instanceId.Value, currentLevel + 1, dir); @@ -197,20 +216,39 @@ private ListContext ConcretiseInstance(ParsingContext context, int abstractNumId private static string GetListName(IElement listNode, string? parentName = null) { var styleAttributes = listNode.GetStyles(); + bool orderedList = listNode.NodeName.Equals("ol", StringComparison.OrdinalIgnoreCase); string? type = styleAttributes["list-style-type"]; + if(orderedList && string.IsNullOrEmpty(type)) + { + type = ListTypeToListStyleType(listNode.GetAttribute("type")); + } + if (string.IsNullOrEmpty(type) || !supportedListTypes.Contains(type!)) { if (parentName != null && IsCascadingStyle(parentName)) return parentName!; - bool orderedList = listNode.NodeName.Equals("ol", StringComparison.OrdinalIgnoreCase); type = orderedList? "decimal" : "disc"; } return type!; } + /// + /// Map ordered list style attribute values to css list-style-type. + /// Valid types are "1|a|A|i|I": https://w3schools.com/tags/att_ol_type.asp + /// + private static string? ListTypeToListStyleType(string? type) => type switch + { + "1" => "decimal", + "a" => "lower-alpha", + "A" => "upper-alpha", + "i" => "lower-roman", + "I" => "upper-roman", + _ => null + }; + /// /// Resolve the of a list element node, /// based on its css class if provided and if matching. @@ -238,4 +276,4 @@ private static bool IsCascadingStyle(string styleName) { return styleName == "decimal-tiered"; } -} \ No newline at end of file +} diff --git a/src/Html2OpenXml/Expressions/PhrasingElementExpression.cs b/src/Html2OpenXml/Expressions/PhrasingElementExpression.cs index 86646fd7..61795d93 100644 --- a/src/Html2OpenXml/Expressions/PhrasingElementExpression.cs +++ b/src/Html2OpenXml/Expressions/PhrasingElementExpression.cs @@ -1,4 +1,4 @@ -/* Copyright (C) Olivier Nizet https://github.com/onizet/html2openxml - All Rights Reserved +/* Copyright (C) Olivier Nizet https://github.com/onizet/html2openxml - All Rights Reserved * * This source is subject to the Microsoft Permissive License. * Please see the License.txt file for more information. @@ -12,10 +12,8 @@ using System; using System.Collections.Generic; using System.Globalization; -using System.Linq; using AngleSharp.Dom; using AngleSharp.Html.Dom; -using AngleSharp.Text; using DocumentFormat.OpenXml; using DocumentFormat.OpenXml.Wordprocessing; @@ -56,7 +54,8 @@ protected virtual IEnumerable Interpret ( runs.Add(element); } } - return CombineRuns(runs); + + return runs; } public override void CascadeStyles(OpenXmlElement element) @@ -189,40 +188,4 @@ protected virtual void ComposeStyles (ParsingContext context) if (font.Size.IsFixed) runProperties.FontSize = new FontSize() { Val = Math.Round(font.Size.ValueInPoint * 2).ToString(CultureInfo.InvariantCulture) }; } - - /// - /// Mimics the behaviour of Html rendering when 2 consecutives runs are separated by a space. - /// - protected static IEnumerable CombineRuns(IEnumerable runs) - { - if (runs.Count() == 1) - { - yield return runs.First(); - yield break; - } - - bool endsWithSpace = true; - foreach (var run in runs) - { - var textElement = run.GetFirstChild(); - // run can be also a hyperlink - textElement ??= run.GetFirstChild()?.GetFirstChild(); - - if (textElement != null) // could be null when
- { - var text = textElement.Text; - // we know that the text cannot be empty because we skip them in TextExpression - if (!endsWithSpace && !text[0].IsSpaceCharacter()) - { - yield return new Run(new Text(" ") { Space = SpaceProcessingModeValues.Preserve }); - } - endsWithSpace = text[text.Length - 1].IsSpaceCharacter(); - } - else if (run.LastChild is Break) - { - endsWithSpace = true; - } - yield return run; - } - } -} \ No newline at end of file +} diff --git a/src/Html2OpenXml/Expressions/Table/TableCellExpression.cs b/src/Html2OpenXml/Expressions/Table/TableCellExpression.cs index 815fbdaa..262b2b63 100644 --- a/src/Html2OpenXml/Expressions/Table/TableCellExpression.cs +++ b/src/Html2OpenXml/Expressions/Table/TableCellExpression.cs @@ -31,9 +31,6 @@ public override IEnumerable Interpret (ParsingContext context) { var childElements = base.Interpret (context); - if (!childElements.Any()) // Word requires that the cell is not empty - childElements = [new Paragraph()]; - var cell = new TableCell (cellProperties); if (cellNode.ColumnSpan > 1) @@ -46,6 +43,13 @@ public override IEnumerable Interpret (ParsingContext context) cellProperties.VerticalMerge = new() { Val = MergedCellValues.Restart }; } + // Word requires at least one paragraph in a cell + // OpenXmlValidator does not catch this error + if (!childElements.Any(c => c is Paragraph)) + { + childElements = childElements.Append(new Paragraph()); + } + cell.Append(childElements); return [cell]; } diff --git a/src/Html2OpenXml/Expressions/Table/TableColExpression.cs b/src/Html2OpenXml/Expressions/Table/TableColExpression.cs index 620fddfe..c51269de 100644 --- a/src/Html2OpenXml/Expressions/Table/TableColExpression.cs +++ b/src/Html2OpenXml/Expressions/Table/TableColExpression.cs @@ -23,21 +23,33 @@ namespace HtmlToOpenXml.Expressions; ///
sealed class TableColExpression(IHtmlTableColumnElement node) : TableElementExpressionBase(node) { + private const int MaxTablePortraitWidth = 9622; + private const int MaxTableLandscapeWidth = 12996; private readonly IHtmlTableColumnElement colNode = node; + private double? percentWidth; /// - public override IEnumerable Interpret (ParsingContext context) + public override IEnumerable Interpret(ParsingContext context) { ComposeStyles(context); var column = new GridColumn(); var width = styleAttributes!.GetUnit("width"); - if (width.IsValid && width.IsFixed) + if (width.IsValid) { - // This value is specified in twentieths of a point. - // If this attribute is omitted, then the last saved width of the grid column is assumed to be zero. - column.Width = Math.Round( width.ValueInPoint * 20 ).ToString(CultureInfo.InvariantCulture); + if (width.IsFixed) + { + // This value is specified in twentieths of a point. + // If this attribute is omitted, then the last saved width of the grid column is assumed to be zero. + column.Width = Math.Round(width.ValueInPoint * 20).ToString(CultureInfo.InvariantCulture); + } + else if (width.Metric == UnitMetric.Percent) + { + var maxWidth = context.IsLandscape ? MaxTableLandscapeWidth : MaxTablePortraitWidth; + percentWidth = Math.Max(0, Math.Min(100, width.Value)); + column.Width = Math.Ceiling(maxWidth / 100d * percentWidth.Value).ToString(CultureInfo.InvariantCulture); + } } if (colNode.Span == 0) @@ -51,4 +63,18 @@ public override IEnumerable Interpret (ParsingContext context) return elements; } + + public override void CascadeStyles(OpenXmlElement element) + { + base.CascadeStyles(element); + + if (percentWidth.HasValue && element is TableCell cell && + cell.TableCellProperties?.TableCellWidth is null) + { + cell.TableCellProperties!.TableCellWidth = new() { + Type = TableWidthUnitValues.Pct, + Width = ((int) (percentWidth.Value * 50)).ToString(CultureInfo.InvariantCulture) + }; + } + } } \ No newline at end of file diff --git a/src/Html2OpenXml/Expressions/Table/TableExpression.cs b/src/Html2OpenXml/Expressions/Table/TableExpression.cs index d77d7086..5746d653 100644 --- a/src/Html2OpenXml/Expressions/Table/TableExpression.cs +++ b/src/Html2OpenXml/Expressions/Table/TableExpression.cs @@ -156,7 +156,7 @@ private static int GuessColumnsCount(IHtmlTableElement tableNode) } } - if (rows.Any()) + if (rows.Length > 0) columnCount = Math.Max(rows.Max(), columnCount); } @@ -186,6 +186,9 @@ protected override void ComposeStyles (ParsingContext context) tableProperties.TableWidth = new() { Type = TableWidthUnitValues.Dxa, Width = width.ValueInDxa.ToString(CultureInfo.InvariantCulture) }; break; + case UnitMetric.Auto: + tableProperties.TableWidth = new() { Width = "0", Type = TableWidthUnitValues.Auto }; + break; } foreach (string className in tableNode.ClassList) @@ -198,10 +201,6 @@ protected override void ComposeStyles (ParsingContext context) } } - var align = Converter.ToParagraphAlign(tableNode.GetAttribute("align")); - if (align.HasValue) - tableProperties.TableJustification = new() { Val = align.Value.ToTableRowAlignment() }; - var dir = tableNode.GetTextDirection(); if (dir.HasValue) tableProperties.BiDiVisual = new() { @@ -243,7 +242,8 @@ protected override void ComposeStyles (ParsingContext context) tableProperties.TableBorders = tableBorders; } // is the border=0? If so, we remove the border regardless the style in use - else if (tableNode.Border == 0) + // but only remove border if the html style border was set, otherwise leave the border style as-is. + else if (!styleBorder.IsEmpty && tableNode.Border == 0) { tableProperties.TableBorders = new TableBorders() { TopBorder = new TopBorder { Val = BorderValues.None }, @@ -280,5 +280,22 @@ protected override void ComposeStyles (ParsingContext context) }; } } + + var align = Converter.ToParagraphAlign(tableNode.GetAttribute("align")) + ?? Converter.ToParagraphAlign(styleAttributes["justify-self"]); + if (!align.HasValue) + { + var margin = styleAttributes.GetMargin("margin"); + if (margin.Left.Metric == UnitMetric.Auto) + { + if (margin.Right.Metric == UnitMetric.Auto) + align = JustificationValues.Center; + else + align = JustificationValues.Right; + } + } + + if (align.HasValue) + tableProperties.TableJustification = new() { Val = align.Value.ToTableRowAlignment() }; } } diff --git a/src/Html2OpenXml/Expressions/TextExpression.cs b/src/Html2OpenXml/Expressions/TextExpression.cs index 427e364b..3d09679c 100644 --- a/src/Html2OpenXml/Expressions/TextExpression.cs +++ b/src/Html2OpenXml/Expressions/TextExpression.cs @@ -9,6 +9,10 @@ * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A * PARTICULAR PURPOSE. */ +using System; +#if NET5_0_OR_GREATER +using System.Collections.Frozen; +#endif using System.Collections.Generic; using AngleSharp.Dom; using AngleSharp.Html.Dom; @@ -23,55 +27,158 @@ namespace HtmlToOpenXml.Expressions; /// sealed class TextExpression(INode node) : HtmlDomExpression { + static readonly ISet AllPhrasings = InitPhrasingSets(); private readonly INode node = node; + private static ISet InitPhrasingSets() + { + var sets = new HashSet(StringComparer.InvariantCultureIgnoreCase) { + TagNames.A, TagNames.Abbr, TagNames.B, TagNames.Big, TagNames.Cite, TagNames.Code, + TagNames.Del, TagNames.Dfn, TagNames.Em, TagNames.Font, TagNames.Hr, TagNames.I, + TagNames.Img, TagNames.Ins, TagNames.Kbd, TagNames.Mark, TagNames.NoBr, TagNames.Q, + TagNames.Rp, TagNames.Rt, TagNames.S, TagNames.Samp, TagNames.Small, TagNames.Span, + TagNames.Strike, TagNames.Strong, TagNames.Sub, TagNames.Sup, TagNames.Time, + TagNames.Tt, TagNames.U, TagNames.Var + }; + +#if NET5_0_OR_GREATER + return sets.ToFrozenSet(StringComparer.InvariantCultureIgnoreCase); +#else + return sets; +#endif + } + /// public override IEnumerable Interpret (ParsingContext context) { string text = node.TextContent.Normalize(); - if (text.Trim().Length == 0) return []; + + if (text.Length == 0) + return []; if (!context.PreserveLinebreaks) - text = text.CollapseLineBreaks(); - if (context.CollapseWhitespaces && text[0].IsWhiteSpaceCharacter() && - node.PreviousSibling is IHtmlImageElement) { - text = " " + text.CollapseAndStrip(); + text = text.CollapseLineBreaks(); + if (text.Length == 0) + return []; } - else if (context.CollapseWhitespaces) + + // https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Whitespace + // If there is a space between two phrasing elements, the user agent should collapse it to a single space character. + if (context.CollapseWhitespaces) + { + bool startsWithSpace = text[0].IsWhiteSpaceCharacter(), + endsWithSpace = text[text.Length - 1].IsWhiteSpaceCharacter(), + preserveBorderSpaces = AllPhrasings.Contains(node.Parent!.NodeName), + prevIsPhrasing = node.PreviousSibling is not null && + (AllPhrasings.Contains(node.PreviousSibling.NodeName) || node.PreviousSibling!.NodeType == NodeType.Text), + nextIsPhrasing = node.NextSibling is not null && + (AllPhrasings.Contains(node.NextSibling.NodeName) || node.NextSibling!.NodeType == NodeType.Text); + text = text.CollapseAndStrip(); + // keep a collapsed single space if it stands between 2 phrasings that respect. + // doesn't ends/starts with a whitespace + if (text.Length == 0 && prevIsPhrasing && nextIsPhrasing + && (endsWithSpace || startsWithSpace) + && !(node.PreviousSibling!.TextContent.Length == 0 + || node.NextSibling!.TextContent.Length == 0 + || node.PreviousSibling!.TextContent[node.PreviousSibling!.TextContent.Length - 1].IsWhiteSpaceCharacter() + || node.NextSibling!.TextContent[0].IsWhiteSpaceCharacter() + )) + { + return [new Run(new Text(" ") { Space = SpaceProcessingModeValues.Preserve })]; + } + // we strip out all whitespaces and we stand inside a div. Just skip this text content + if (text.Length == 0 && !preserveBorderSpaces) + { + return []; + } + + // if previous element is an image, append a space separator + if ((startsWithSpace && node.PreviousSibling is IHtmlImageElement) + // if this is a non-empty phrasing element, append a space separator + || (startsWithSpace && prevIsPhrasing + && node.PreviousSibling!.TextContent.Length > 0 + && !node.PreviousSibling!.TextContent[node.PreviousSibling.TextContent.Length - 1].IsWhiteSpaceCharacter())) + { + text = " " + text; + } + + if (endsWithSpace && ( + // next run is not starting with a linebreak + (nextIsPhrasing && node.NextSibling!.TextContent.Length > 0 && + !node.NextSibling!.TextContent[0].IsLineBreak()) || + // if there is no more text element or is empty, eat the trailing space + (preserveBorderSpaces && (node.NextSibling is not null + || node.Parent.NextSibling is not null)))) + { + text += " "; + } + } + + + if (text.Length == 0) + return []; + if (!context.PreserveLinebreaks) - return [new Run(new Text(text))]; + return [new Run(new Text(text) { Space = SpaceProcessingModeValues.Preserve })]; + + Run run = EscapeNewlines(text); + return [run]; + } + /// + /// Convert new lines to . + /// + private static Run EscapeNewlines(string text) + { var run = new Run(); - char[] chars = text.ToCharArray(); - int shift = 0, c = 0; bool wasCR = false; // avoid adding 2 breaks for \r\n - for ( ; c < chars.Length ; c++) + + int startIndex = 0; + for (int i = 0; i < text.Length; i++) { - if (!chars[c].IsLineBreak()) - { - wasCR = false; + if (!IsLineBreak(text[i], ref wasCR)) continue; - } - - if (wasCR) continue; - wasCR = chars[c] == Symbols.CarriageReturn; - if (c > 1) + // Add the text before the newline character + if (i > startIndex) { - run.Append(new Text(new string(chars, shift, c - shift)) + run.Append(new Text(text.Substring(startIndex, i - startIndex)) { Space = SpaceProcessingModeValues.Preserve }); run.Append(new Break()); } - shift = c + 1; + + startIndex = i + 1; } - if (c > shift) - run.Append(new Text(new string(chars, shift, c - shift)) + // Add any remaining text after the last newline character + if (startIndex < text.Length) + { + run.Append(new Text(text.Substring(startIndex)) { Space = SpaceProcessingModeValues.Preserve }); + } - return [run]; + return run; + } + + private static bool IsLineBreak(char ch, ref bool wasCR) + { + if (ch == Symbols.CarriageReturn) + { + wasCR = true; + return true; + } + + if (ch == Symbols.LineFeed && wasCR) + { + // Skip LF character after CR to avoid adding an extra break for CR-LF sequence + wasCR = false; + return false; + } + + wasCR = false; + return ch == Symbols.LineFeed; } } diff --git a/src/Html2OpenXml/HtmlConverter.cs b/src/Html2OpenXml/HtmlConverter.cs index f834ecf2..8e0664ed 100755 --- a/src/Html2OpenXml/HtmlConverter.cs +++ b/src/Html2OpenXml/HtmlConverter.cs @@ -15,6 +15,7 @@ using System.Threading; using System.Threading.Tasks; using AngleSharp; +using AngleSharp.Html.Dom; using DocumentFormat.OpenXml; using DocumentFormat.OpenXml.Packaging; using DocumentFormat.OpenXml.Wordprocessing; @@ -57,20 +58,20 @@ public HtmlConverter(MainDocumentPart mainPart, IWebRequest? webRequester = null } /// - /// Parse some HTML content where the output is intented to be inserted in . + /// Parse some HTML content where the output is intended to be inserted in . /// /// The HTML content to parse /// Returns a list of parsed paragraph. public IList Parse(string html) { - bodyImageLoader ??= new ImagePrefetcher(mainPart, webRequester); + bodyImageLoader ??= new ImagePrefetcher(mainPart, webRequester, ImageProcessing); return ParseCoreAsync(html, mainPart, bodyImageLoader, new ParallelOptions() { CancellationToken = CancellationToken.None }) .ConfigureAwait(false).GetAwaiter().GetResult().ToList(); } /// - /// Start the asynchroneous parse processing where the output is intented to be inserted in . + /// Start the asynchronous parse processing where the output is intended to be inserted in . /// /// The HTML content to parse /// The cancellation token. @@ -83,7 +84,7 @@ public Task> Parse(string html, Cancellatio } /// - /// Start the asynchroneous parse processing where the output is intented to be inserted in . + /// Start the asynchronous parse processing where the output is intended to be inserted in . /// /// The HTML content to parse /// The cancellation token. @@ -94,20 +95,20 @@ public Task> ParseAsync(string html, Cancel } /// - /// Start the asynchroneous parse processing where the output is intented to be inserted in . + /// Start the asynchronous parse processing where the output is intended to be inserted in . /// /// The HTML content to parse /// The configuration of parallelism while downloading the remote resources. /// Returns a list of parsed paragraph. public Task> ParseAsync(string html, ParallelOptions parallelOptions) { - bodyImageLoader ??= new ImagePrefetcher(mainPart, webRequester); + bodyImageLoader ??= new ImagePrefetcher(mainPart, webRequester, ImageProcessing); return ParseCoreAsync(html, mainPart, bodyImageLoader, parallelOptions); } /// - /// Parse asynchroneously the Html and append the output into the Header of the document. + /// Parse asynchronously the Html and append the output into the Header of the document. /// /// The HTML content to parse /// Determines the page(s) on which the current header shall be displayed. @@ -121,17 +122,18 @@ public async Task ParseHeader(string html, HeaderFooterValues? headerType = null var headerPart = ResolveHeaderFooterPart(headerType); headerPart.Header ??= new(); - headerImageLoader ??= new ImagePrefetcher(headerPart, webRequester); + headerImageLoader ??= new ImagePrefetcher(headerPart, webRequester, ImageProcessing); var paragraphs = await ParseCoreAsync(html, headerPart, headerImageLoader, new ParallelOptions() { CancellationToken = cancellationToken }, - htmlStyles.GetParagraphStyle(htmlStyles.DefaultStyles.HeaderStyle)); + htmlStyles.GetParagraphStyle(htmlStyles.DefaultStyles.HeaderStyle)) + .ConfigureAwait(false); headerPart.Header.Append(paragraphs); } /// - /// Parse asynchroneously the Html and append the output into the Footer of the document. + /// Parse asynchronously the Html and append the output into the Footer of the document. /// /// The HTML content to parse /// Determines the page(s) on which the current footer shall be displayed. @@ -145,27 +147,29 @@ public async Task ParseFooter(string html, HeaderFooterValues? footerType = null var footerPart = ResolveHeaderFooterPart(footerType); footerPart.Footer ??= new(); - footerImageLoader ??= new ImagePrefetcher(footerPart, webRequester); + footerImageLoader ??= new ImagePrefetcher(footerPart, webRequester, ImageProcessing); var paragraphs = await ParseCoreAsync(html, footerPart, footerImageLoader, new ParallelOptions() { CancellationToken = cancellationToken }, - htmlStyles.GetParagraphStyle(htmlStyles.DefaultStyles.FooterStyle)); + htmlStyles.GetParagraphStyle(htmlStyles.DefaultStyles.FooterStyle)) + .ConfigureAwait(false); footerPart.Footer.Append(paragraphs); } /// - /// Parse asynchroneously the Html and append the output into the Body of the document. + /// Parse asynchronously the Html and append the output into the Body of the document. /// /// The HTML content to parse /// The cancellation token. /// public async Task ParseBody(string html, CancellationToken cancellationToken = default) { - bodyImageLoader ??= new ImagePrefetcher(mainPart, webRequester); + bodyImageLoader ??= new ImagePrefetcher(mainPart, webRequester, ImageProcessing); var paragraphs = await ParseCoreAsync(html, mainPart, bodyImageLoader, new ParallelOptions() { CancellationToken = cancellationToken }, - htmlStyles.GetParagraphStyle(htmlStyles.DefaultStyles.Paragraph)); + htmlStyles.GetParagraphStyle(htmlStyles.DefaultStyles.Paragraph)) + .ConfigureAwait(false); if (!paragraphs.Any()) return; @@ -197,7 +201,7 @@ public async Task ParseBody(string html, CancellationToken cancellationToken = d } /// - /// Start the asynchroneous parse processing. Use this overload if you want to control the downloading of images. + /// Start the asynchronous parse processing. Use this overload if you want to control the downloading of images. /// /// The HTML content to parse /// The configuration of parallelism while downloading the remote resources. @@ -206,13 +210,13 @@ public async Task ParseBody(string html, CancellationToken cancellationToken = d [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public Task> Parse(string html, ParallelOptions parallelOptions) { - bodyImageLoader ??= new ImagePrefetcher(mainPart, webRequester); + bodyImageLoader ??= new ImagePrefetcher(mainPart, webRequester, ImageProcessing); return ParseCoreAsync(html, mainPart, bodyImageLoader, parallelOptions); } /// - /// Start the asynchroneous parse processing and append the output into the Body of the document. + /// Start the asynchronous parse processing and append the output into the Body of the document. /// /// The HTML content to parse /// The cancellation token. @@ -232,7 +236,7 @@ public void RefreshStyles() } /// - /// Start the asynchroneous parse processing. Use this overload if you want to control the downloading of images. + /// Start the asynchronous parse processing. Use this overload if you want to control the downloading of images. /// /// The HTML content to parse /// The OpenXml container where the content will be inserted into. @@ -274,13 +278,14 @@ private async Task> ParseCoreAsync(string h /// /// Walk through all the img tags and preload all the remote images. /// - private async Task PreloadImages(AngleSharp.Dom.IDocument htmlDocument, + private static async Task PreloadImages(AngleSharp.Dom.IDocument htmlDocument, IImageLoader imageLoader, ParallelOptions parallelOptions) { var imageUris = htmlDocument.QuerySelectorAll("img[src]") - .Cast() + .Cast() .Where(e => AngleSharpExtensions.TryParseUrl(e.GetAttribute("src"), UriKind.RelativeOrAbsolute, out var _)) - .Select(e => e.GetAttribute("src")!); + .Select(e => e.GetAttribute("src")!) + .Distinct(); if (!imageUris.Any()) return; @@ -389,6 +394,26 @@ public WordDocumentStyle HtmlStyles /// The table will contains only one cell. public bool RenderPreAsTable { get; set; } + /// + /// Gets or sets how images should be processed during conversion. + /// + /// + /// + /// Use (default) to download and embed all images, + /// creating self-contained documents but potentially large file sizes. + /// + /// + /// Use to link to external images via relationships, + /// keeping document size small but requiring internet access to view images. + /// Data URI images (base64 encoded) are still embedded. + /// + /// + /// Use to only embed data URI images + /// and skip external images entirely. + /// + /// + public ImageProcessingMode ImageProcessing { get; set; } = ImageProcessingMode.Embed; + /// /// Defines whether ordered lists (ol) continue incrementing existing numbering /// or restarts to 1 (defaults continues numbering). diff --git a/src/Html2OpenXml/HtmlToOpenXml.csproj b/src/Html2OpenXml/HtmlToOpenXml.csproj index ba846a90..c42ae0de 100644 --- a/src/Html2OpenXml/HtmlToOpenXml.csproj +++ b/src/Html2OpenXml/HtmlToOpenXml.csproj @@ -10,12 +10,14 @@ HtmlToOpenXml HtmlToOpenXml.dll 3.3.0 + 3.2.8 icon.png Copyright 2009-$([System.DateTime]::Now.Year) Olivier Nizet - (Please write the package release notes in CHANGELOG.md) + See changelog https://github.com/onizet/html2openxml/blob/master/CHANGELOG.md README.md office openxml netcore html 3.3.0 + 3.2.8 MIT https://github.com/onizet/html2openxml https://github.com/onizet/html2openxml diff --git a/src/Html2OpenXml/IO/DefaultWebRequest.cs b/src/Html2OpenXml/IO/DefaultWebRequest.cs index 9414a02b..9125c7db 100644 --- a/src/Html2OpenXml/IO/DefaultWebRequest.cs +++ b/src/Html2OpenXml/IO/DefaultWebRequest.cs @@ -126,7 +126,13 @@ public DefaultWebRequest(HttpClient httpClient, ILogger? logger = null) resource.StatusCode = response.StatusCode; if (response.IsSuccessStatusCode) + { resource.Content = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + if (response.Content.Headers.TryGetValues("Content-Type", out var mime)) + { + resource.Headers.Add("Content-Type", string.Join(", ", mime)); + } + } foreach (var header in response.Headers) resource.Headers.Add(header.Key, string.Join(", ", header.Value)); diff --git a/src/Html2OpenXml/IO/HtmlImageInfo.cs b/src/Html2OpenXml/IO/HtmlImageInfo.cs index 4ffca088..aacf58c8 100755 --- a/src/Html2OpenXml/IO/HtmlImageInfo.cs +++ b/src/Html2OpenXml/IO/HtmlImageInfo.cs @@ -37,6 +37,12 @@ sealed class HtmlImageInfo(string source, string partId) /// Gets the content type of the image. /// public PartTypeInfo TypeInfo { get; set; } + + /// + /// Gets or sets whether this image is linked externally rather than embedded. + /// When true, contains an external relationship ID instead of an embedded image part ID. + /// + public bool IsExternal { get; set; } } /// diff --git a/src/Html2OpenXml/IO/ImageHeader.cs b/src/Html2OpenXml/IO/ImageHeader.cs index c65a0b7a..6939edb9 100755 --- a/src/Html2OpenXml/IO/ImageHeader.cs +++ b/src/Html2OpenXml/IO/ImageHeader.cs @@ -59,12 +59,10 @@ public enum FileType { Unrecognized, Bitmap, Gif, Png, Jpeg, Emf, Xml } /// Returns true if the detection was successful. public static bool TryDetectFileType(Stream stream, out FileType type) { - using (SequentialBinaryReader reader = new SequentialBinaryReader(stream, leaveOpen: true)) - { - type = DetectFileType(reader); - stream.Seek(0L, SeekOrigin.Begin); - return type != FileType.Unrecognized; - } + using var reader = new SequentialBinaryReader(stream, leaveOpen: true); + type = DetectFileType(reader); + stream.Seek(0L, SeekOrigin.Begin); + return type != FileType.Unrecognized; } /// @@ -75,21 +73,19 @@ public static bool TryDetectFileType(Stream stream, out FileType type) /// The image was of an unrecognised format. public static Size GetDimensions(Stream stream) { - using (SequentialBinaryReader reader = new SequentialBinaryReader(stream, leaveOpen: true)) + using var reader = new SequentialBinaryReader(stream, leaveOpen: true); + FileType type = DetectFileType(reader); + stream.Seek(0L, SeekOrigin.Begin); + return type switch { - FileType type = DetectFileType (reader); - stream.Seek(0L, SeekOrigin.Begin); - switch (type) - { - case FileType.Bitmap: return DecodeBitmap(reader); - case FileType.Gif: return DecodeGif(reader); - case FileType.Jpeg: return DecodeJfif(reader); - case FileType.Png: return DecodePng(reader); - case FileType.Emf: return DecodeEmf(reader); - case FileType.Xml: return DecodeXml(stream); - default: return Size.Empty; - } - } + FileType.Bitmap => DecodeBitmap(reader), + FileType.Gif => DecodeGif(reader), + FileType.Jpeg => DecodeJfif(reader), + FileType.Png => DecodePng(reader), + FileType.Emf => DecodeEmf(reader), + FileType.Xml => DecodeXml(stream), + _ => Size.Empty, + }; } /// @@ -124,36 +120,25 @@ public static Size KeepAspectRatio(Size actualSize, Size preferredSize) private static FileType DetectFileType (SequentialBinaryReader reader) { byte[] magicBytes = new byte[MaxMagicBytesLength]; - for (int i = 0; i < MaxMagicBytesLength; i += 1) - { - magicBytes[i] = reader.ReadByte(); - foreach (var kvPair in imageFormatDecoders) - { - if (StartsWith(magicBytes, kvPair.Key)) - { - return kvPair.Value; - } - } - } + var availableBytes = reader.BaseStream.Length - reader.BaseStream.Position; + // reasonably, we can assume that if we are at the end of the stream and we read the header, + // the image content must be invalid or truncated. + if (availableBytes < MaxMagicBytesLength) + return FileType.Unrecognized; - return FileType.Unrecognized; - } + reader.Read(magicBytes, 0, MaxMagicBytesLength); - /// - /// Determines whether the beginning of this byte array instance matches the specified byte array. - /// - /// Returns true if the first array starts with the bytes of the second array. - private static bool StartsWith(byte[] thisBytes, byte[] thatBytes) - { - for (int i = 0; i < thatBytes.Length; i += 1) + var headerSpan = magicBytes.AsSpan(); + foreach (var kvPair in imageFormatDecoders) { - if (thisBytes[i] != thatBytes[i]) + // Determines whether the beginning of this array matches s known header. + if (headerSpan.StartsWith(kvPair.Key)) { - return false; + return kvPair.Value; } } - return true; + return FileType.Unrecognized; } private static Size DecodeBitmap(SequentialBinaryReader reader) @@ -221,7 +206,7 @@ private static Size DecodeJfif(SequentialBinaryReader reader) return Size.Empty; // next 2-bytes are : [high-byte] [low-byte] - var segmentLength = (int)reader.ReadUInt16(); + int segmentLength = reader.ReadUInt16(); // segment length includes size bytes, so subtract two segmentLength -= 2; @@ -229,8 +214,8 @@ private static Size DecodeJfif(SequentialBinaryReader reader) if (segmentType == 0xC0 || segmentType == 0xC2) { reader.ReadByte(); // bits/sample, usually 8 - int height = (int) reader.ReadUInt16(); - int width = (int) reader.ReadUInt16(); + int height = reader.ReadUInt16(); + int width = reader.ReadUInt16(); return new Size(width, height); } else diff --git a/src/Html2OpenXml/IO/ImagePrefetcher.cs b/src/Html2OpenXml/IO/ImagePrefetcher.cs index f074358b..3beb7bc5 100644 --- a/src/Html2OpenXml/IO/ImagePrefetcher.cs +++ b/src/Html2OpenXml/IO/ImagePrefetcher.cs @@ -52,6 +52,8 @@ sealed class ImagePrefetcher : IImageLoader private readonly T hostingPart; private readonly IWebRequest resourceLoader; private readonly HtmlImageInfoCollection prefetchedImages; + private readonly object lockObject = new(); + private readonly ImageProcessingMode processingMode; /// @@ -60,11 +62,13 @@ sealed class ImagePrefetcher : IImageLoader /// The image will be linked to that hosting part. /// Images are not shared between header, footer and body. /// Service to resolve an image. - public ImagePrefetcher(T hostingPart, IWebRequest resourceLoader) + /// Specifies how images should be processed (embed, link, or data URI only). + public ImagePrefetcher(T hostingPart, IWebRequest resourceLoader, ImageProcessingMode processingMode = ImageProcessingMode.Embed) { this.hostingPart = hostingPart; this.resourceLoader = resourceLoader; - this.prefetchedImages = new HtmlImageInfoCollection(); + this.processingMode = processingMode; + this.prefetchedImages = []; } //____________________________________________________________________ @@ -76,8 +80,12 @@ public ImagePrefetcher(T hostingPart, IWebRequest resourceLoader) /// public async Task Download(string imageUri, CancellationToken cancellationToken) { - if (prefetchedImages.Contains(imageUri)) - return prefetchedImages[imageUri]; + // Check if image is already cached using thread-safe operation + lock (lockObject) + { + if (prefetchedImages.Contains(imageUri)) + return prefetchedImages[imageUri]; + } HtmlImageInfo? iinfo; if (DataUri.IsWellFormed(imageUri)) // data inline, encoded in base64 @@ -86,11 +94,36 @@ public ImagePrefetcher(T hostingPart, IWebRequest resourceLoader) } else { - iinfo = await DownloadRemoteImage(imageUri, cancellationToken); + // Handle external images based on processing mode + if (processingMode == ImageProcessingMode.EmbedDataUriOnly) + { + // Skip external images entirely + return null; + } + else if (processingMode == ImageProcessingMode.LinkExternal) + { + // Create external link without downloading + iinfo = CreateExternalImageLink(imageUri); + } + else + { + // Default: Download and embed + iinfo = await DownloadRemoteImage(imageUri, cancellationToken).ConfigureAwait(false); + } } + // Add to cache using thread-safe operation if (iinfo != null) - prefetchedImages.Add(iinfo); + { + lock (lockObject) + { + // Double-check pattern to prevent duplicate adds during concurrent access + if (!prefetchedImages.Contains(imageUri)) + { + prefetchedImages.Add(iinfo); + } + } + } return iinfo; } @@ -100,42 +133,66 @@ public ImagePrefetcher(T hostingPart, IWebRequest resourceLoader) /// private async Task DownloadRemoteImage(string src, CancellationToken cancellationToken) { - Uri imageUri = new Uri(src, UriKind.RelativeOrAbsolute); + Uri imageUri = new(src, UriKind.RelativeOrAbsolute); if (imageUri.IsAbsoluteUri && !resourceLoader.SupportsProtocol(imageUri.Scheme)) return null; - Resource? response; + using var response = await resourceLoader.FetchAsync(imageUri, cancellationToken).ConfigureAwait(false); + if (response?.Content == null || !response.Content.CanRead) + return null; - response = await resourceLoader.FetchAsync(imageUri, cancellationToken).ConfigureAwait(false); - if (response?.Content == null) + // For requested url with no filename, we need to read the media mime type if provided + response.Headers.TryGetValue("Content-Type", out var mime); + if (!TryInspectMimeType(mime, out PartTypeInfo type) + && !TryGuessTypeFromUri(imageUri, out type) + && !TryGuessTypeFromStream(response.Content, out type) + ) + { return null; + } + + return SaveImageAssert(src, type, response.Content.CopyTo); + } - using (response) + /// + /// Create an external relationship to an image without downloading it. + /// + private HtmlImageInfo? CreateExternalImageLink(string src) + { + Uri imageUri = new(src, UriKind.RelativeOrAbsolute); + + // Resolve relative URIs if possible (only for DefaultWebRequest which has BaseImageUrl) + if (!imageUri.IsAbsoluteUri && resourceLoader is DefaultWebRequest defaultWebRequest + && defaultWebRequest.BaseImageUrl != null) { - // For requested url with no filename, we need to read the media mime type if provided - response.Headers.TryGetValue("Content-Type", out var mime); - if (!TryInspectMimeType(mime, out PartTypeInfo type) - && !TryGuessTypeFromUri(imageUri, out type) - && !TryGuessTypeFromStream(response.Content, out type)) - { - return null; - } + string url1 = defaultWebRequest.BaseImageUrl.AbsoluteUri.TrimEnd('/', '\\'); + string path = src.TrimStart('/', '\\'); + imageUri = new Uri(string.Format("{0}/{1}", url1, path), UriKind.Absolute); + } - var ipart = hostingPart.AddImagePart(type); - Size originalSize; - using (var outputStream = ipart.GetStream(FileMode.Create)) - { - await response.Content.CopyToAsync(outputStream); + // Only create external links for absolute URIs with supported protocols + if (!imageUri.IsAbsoluteUri || !resourceLoader.SupportsProtocol(imageUri.Scheme)) + return null; - outputStream.Seek(0L, SeekOrigin.Begin); - originalSize = GetImageSize(outputStream); - } + // Generate a unique GUID-based relationship ID for the external relationship + string relationshipId = "imgext_" + Guid.NewGuid().ToString("N"); - return new HtmlImageInfo(src, hostingPart.GetIdOfPart(ipart)) { - TypeInfo = type, - Size = originalSize - }; + // Create external relationship + lock (lockObject) + { + hostingPart.AddExternalRelationship( + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", + imageUri, + relationshipId); } + + // Return image info with external flag set + // Note: Size will be empty as we don't download the image + return new HtmlImageInfo(src, relationshipId) { + IsExternal = true, + Size = Size.Empty, + TypeInfo = ImagePartType.Png // Default type, actual type doesn't matter for external links + }; } /// @@ -145,26 +202,39 @@ public ImagePrefetcher(T hostingPart, IWebRequest resourceLoader) { if (DataUri.TryCreate(src, out var dataUri)) { - Size originalSize; knownContentType.TryGetValue(dataUri!.Mime, out PartTypeInfo type); - var ipart = hostingPart.AddImagePart(type); - using (var outputStream = ipart.GetStream(FileMode.Create)) - { - outputStream.Write(dataUri.Data, 0, dataUri.Data.Length); - - outputStream.Seek(0L, SeekOrigin.Begin); - originalSize = GetImageSize(outputStream); - } - return new HtmlImageInfo(src, hostingPart.GetIdOfPart(ipart)) { - TypeInfo = type, - Size = originalSize - }; + return SaveImageAssert(src, type, stream => stream.Write(dataUri.Data, 0, dataUri.Data.Length)); } return null; } + private HtmlImageInfo SaveImageAssert(string src, PartTypeInfo type, Action writeImage) + { + ImagePart ipart; + string relationshipId = "img_" + Guid.NewGuid().ToString("N"); + lock (lockObject) + { + ipart = hostingPart.AddImagePart(type, relationshipId); + } + + Size originalSize; + using (var outputStream = ipart.GetStream(FileMode.Create)) + { + writeImage(outputStream); + outputStream.Seek(0L, SeekOrigin.Begin); + originalSize = GetImageSize(outputStream); + } + + string partId = hostingPart.GetIdOfPart(ipart); + return new HtmlImageInfo(src, partId) + { + TypeInfo = type, + Size = originalSize + }; + } + //____________________________________________________________________ // // Private Implementation @@ -179,6 +249,8 @@ public ImagePrefetcher(T hostingPart, IWebRequest resourceLoader) { "image/x-png", ImagePartType.Png }, { "image/png", ImagePartType.Png }, { "image/tiff", ImagePartType.Tiff }, + { "image/emf", ImagePartType.Emf }, + { "image/x-emf", ImagePartType.Emf }, { "image/vnd.microsoft.icon", ImagePartType.Icon }, // these icons mime type are wrong but we should nevertheless take care (http://en.wikipedia.org/wiki/ICO_%28file_format%29#MIME_type) { "image/x-icon", ImagePartType.Icon }, @@ -256,4 +328,4 @@ private static Size GetImageSize(Stream imageStream) return Size.Empty; } } -} +} \ No newline at end of file diff --git a/src/Html2OpenXml/ParsingContext.cs b/src/Html2OpenXml/ParsingContext.cs index 18dd7657..c75a3a65 100644 --- a/src/Html2OpenXml/ParsingContext.cs +++ b/src/Html2OpenXml/ParsingContext.cs @@ -44,6 +44,9 @@ sealed class ParsingContext(HtmlConverter converter, OpenXmlPartContainer hostin /// Whether the text content should collapse the whitespaces. public bool CollapseWhitespaces { get; set; } = true; + /// Whether the page orientation is portrait or landscape. + public bool IsLandscape { get; set; } + public void CascadeStyles (OpenXmlElement element) @@ -57,7 +60,8 @@ public ParsingContext CreateChild(HtmlElementExpression expression) var childContext = new ParsingContext(Converter, HostingPart, ImageLoader) { propertyBag = propertyBag, parentExpression = expression, - parentContext = this + parentContext = this, + IsLandscape = IsLandscape }; return childContext; } diff --git a/src/Html2OpenXml/Primitives/DefaultStyles.cs b/src/Html2OpenXml/Primitives/DefaultStyles.cs index 013adb3a..3512e68f 100644 --- a/src/Html2OpenXml/Primitives/DefaultStyles.cs +++ b/src/Html2OpenXml/Primitives/DefaultStyles.cs @@ -54,6 +54,13 @@ public class DefaultStyles /// Heading public string HeadingStyle { get; set; } = PredefinedStyles.Heading; + /// + /// Default style for numbered headings + /// Appends the level at the end of the style name + /// + /// Heading + public string NumberedHeadingStyle { get; set; } = PredefinedStyles.Heading; + /// /// Default style for hyperlinks /// diff --git a/src/Html2OpenXml/Primitives/HtmlColor.cs b/src/Html2OpenXml/Primitives/HtmlColor.cs index e668a6cf..493d8a20 100755 --- a/src/Html2OpenXml/Primitives/HtmlColor.cs +++ b/src/Html2OpenXml/Primitives/HtmlColor.cs @@ -152,6 +152,21 @@ public static HtmlColor Parse(string? htmlColor) } } + /// + /// Convert a potential percentage value to its numeric representation. + /// Saturation and Lightness can contains both a percentage value or a value comprised between 0.0 and 1.0. + /// + private static double ParsePercent (string value) + { + double parsedValue; + if (value.IndexOf('%') > -1) + parsedValue = double.Parse(value.Replace('%', ' '), CultureInfo.InvariantCulture) / 100d; + else + parsedValue = double.Parse(value, CultureInfo.InvariantCulture); + + return Math.Min(1, Math.Max(0, parsedValue)); + } + /// /// Creates a structure from the four RGB component values. /// diff --git a/src/Html2OpenXml/Utilities/CollectionExtensions.cs b/src/Html2OpenXml/Utilities/CollectionExtensions.cs index b66fb959..42aa8d2a 100644 --- a/src/Html2OpenXml/Utilities/CollectionExtensions.cs +++ b/src/Html2OpenXml/Utilities/CollectionExtensions.cs @@ -38,7 +38,7 @@ public static Task ForEachAsync(this IEnumerable source, var throttler = new SemaphoreSlim(initialCount: Math.Max(1, parallelOptions.MaxDegreeOfParallelism)); var tasks = System.Linq.Enumerable.Select(source, async item => { - await throttler.WaitAsync(parallelOptions.CancellationToken); + await throttler.WaitAsync(parallelOptions.CancellationToken).ConfigureAwait(false); if (parallelOptions.CancellationToken.IsCancellationRequested) return; try diff --git a/src/Html2OpenXml/Utilities/Converter.cs b/src/Html2OpenXml/Utilities/Converter.cs index 66ef3deb..7b0ece1d 100755 --- a/src/Html2OpenXml/Utilities/Converter.cs +++ b/src/Html2OpenXml/Utilities/Converter.cs @@ -209,8 +209,7 @@ public static ICollection ToTextDecoration(ReadOnlySpan va Color = border.Color.ToHexString(), // according to MSDN, sz=24 = 3 point // https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.wordprocessing.tablecellborders - Size = (uint) Math.Round(border.Width.ValueInPoint * 8), - Space = 1U + Size = (uint) Math.Round(border.Width.ValueInPoint * 8) }; } diff --git a/test/HtmlToOpenXml.Tests/AbbrTests.cs b/test/HtmlToOpenXml.Tests/AbbrTests.cs index 2f65ad1f..7a6cb88d 100644 --- a/test/HtmlToOpenXml.Tests/AbbrTests.cs +++ b/test/HtmlToOpenXml.Tests/AbbrTests.cs @@ -175,8 +175,9 @@ public void InsideParagraph_ReturnsMultipleRuns() Assert.That(elements, Has.Count.EqualTo(1)); Assert.Multiple(() => { Assert.That(elements[0], Is.TypeOf(typeof(Paragraph))); - Assert.That(elements[0].Elements().Count(), Is.EqualTo(6), "3 textual runs + 3 breaks"); + Assert.That(elements[0].Elements().Count(), Is.EqualTo(4), "4 runs: Pre abbr, abbr, quote number, post abbr"); Assert.That(elements[0].Elements().Any(r => r.HasChild()), Is.True); + Assert.That(elements[0].InnerText, Is.EqualTo("The NASA is an independent agency of the U.S. federal government responsible for the civil space program, aeronautics research, and space research.")); }); } diff --git a/test/HtmlToOpenXml.Tests/ElementTests.cs b/test/HtmlToOpenXml.Tests/ElementTests.cs index cb2f55c6..a82685e3 100644 --- a/test/HtmlToOpenXml.Tests/ElementTests.cs +++ b/test/HtmlToOpenXml.Tests/ElementTests.cs @@ -28,7 +28,6 @@ public void PhrasingTag_ReturnsRunWithDefaultStyle (string html) where T : Op [TestCase(@"Superscript", ExpectedResult = "superscript")] public string? SubSup_ReturnsRunWithVerticalAlignment (string html) { - //var val = new VerticalPositionValues(tagName); var textAlign = ParsePhrasing(html); Assert.That(textAlign.Val?.HasValue, Is.True); return textAlign.Val.InnerText; @@ -154,9 +153,32 @@ public void FigCaption_ReturnsRunWithSimpleField() Assert.Multiple(() => { - Assert.That(elements[0].ChildElements, Has.Count.EqualTo(3)); Assert.That(elements[0].HasChild(), Is.True); Assert.That(elements[0].HasChild(), Is.True); + Assert.That(elements[0].Elements().Count(), Is.EqualTo(3)); + Assert.That(elements[0].GetFirstChild()!.KeepNext, Is.Null); + Assert.That(elements[0].GetFirstChild()!.Instruction?.Value, Does.Contain("SEQ Figure \\* ARABIC")); + }); + } + + [Test] + public void FigCaption_WithHeading_ReturnsParagraphWithSimpleField() + { + var elements = converter.Parse(@"
+

Puppy School

+

Championship Class of 2016

+
"); + + Assert.That(elements, Has.Count.EqualTo(2)); + Assert.That(elements, Is.All.TypeOf()); + + Assert.Multiple(() => + { + Assert.That(elements[0].HasChild(), Is.True); + Assert.That(elements[0].HasChild(), Is.True); + Assert.That(elements[0].GetFirstChild()!.KeepNext, Is.Not.Null); + Assert.That(elements[1].HasChild(), Is.True); + Assert.That(elements[1].HasChild(), Is.False); }); } diff --git a/test/HtmlToOpenXml.Tests/HeaderFooterTests.cs b/test/HtmlToOpenXml.Tests/HeaderFooterTests.cs index 8bb71936..c680f685 100644 --- a/test/HtmlToOpenXml.Tests/HeaderFooterTests.cs +++ b/test/HtmlToOpenXml.Tests/HeaderFooterTests.cs @@ -148,9 +148,17 @@ await converter.ParseFooter(@" var footer = mainPart.FooterParts.FirstOrDefault()?.Footer; Assert.That(footer, Is.Not.Null); var paragraphs = footer.Elements(); - Assert.That(paragraphs.Count(), Is.EqualTo(2)); - Assert.That(paragraphs.Select(p => p.ParagraphProperties?.ParagraphStyleId?.Val?.Value), - Has.All.EqualTo(converter.HtmlStyles.DefaultStyles.FooterStyle)); + Assert.That(paragraphs.Count(), Is.EqualTo(1)); + var paragraph = paragraphs.First(); + Assert.Multiple(() => + { + Assert.That(paragraph.Elements().Count, Is.EqualTo(2), "One whitespace and one for "); + Assert.That(paragraph.Elements().Count, Is.EqualTo(1)); + Assert.That(paragraph.GetFirstChild()?.InnerText, Is.EqualTo("Copyrighted but you can use what's here as long as you credit me")); + Assert.That(paragraph.GetLastChild()?.InnerText, Is.EqualTo("© Copyright 2058, Company Inc.")); + Assert.That(paragraphs.Select(p => p.ParagraphProperties?.ParagraphStyleId?.Val?.Value), + Has.All.EqualTo(converter.HtmlStyles.DefaultStyles.FooterStyle)); + }); } } } \ No newline at end of file diff --git a/test/HtmlToOpenXml.Tests/HeadingTests.cs b/test/HtmlToOpenXml.Tests/HeadingTests.cs index b8feed11..532befcd 100644 --- a/test/HtmlToOpenXml.Tests/HeadingTests.cs +++ b/test/HtmlToOpenXml.Tests/HeadingTests.cs @@ -101,5 +101,27 @@ public void MaxLevel_ShouldBeIgnored() Is.Null, $"Only {maxLevel+1} levels of heading supported"); }); } + + [Test(Description = "Heading with number but no text should be ignored (issue #189)")] + public void NumberingWithNoTextPattern_ReturnsSimpleHeading() + { + var elements = converter.Parse("

00

"); + + var absNum = mainPart.NumberingDefinitionsPart?.Numbering + .Elements() + .Where(abs => abs.AbstractNumDefinitionName?.Val == NumberingExpressionBase.HeadingNumberingName) + .SingleOrDefault(); + Assert.That(absNum, Is.Null); + + var paragraphs = elements.Cast(); + Assert.Multiple(() => + { + Assert.That(paragraphs.Count(), Is.EqualTo(1)); + Assert.That(paragraphs.First().InnerText, Is.EqualTo("00")); + Assert.That(paragraphs.First().ParagraphProperties?.NumberingProperties?.NumberingLevelReference?.Val, + Is.Null, + "First paragraph is not a numbering"); + }); + } } } \ No newline at end of file diff --git a/test/HtmlToOpenXml.Tests/HtmlToOpenXml.Tests.csproj b/test/HtmlToOpenXml.Tests/HtmlToOpenXml.Tests.csproj index 434b85a5..31c2bd53 100755 --- a/test/HtmlToOpenXml.Tests/HtmlToOpenXml.Tests.csproj +++ b/test/HtmlToOpenXml.Tests/HtmlToOpenXml.Tests.csproj @@ -12,15 +12,15 @@ en - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + - - - + + + all runtime; build; native; contentfiles; analyzers diff --git a/test/HtmlToOpenXml.Tests/ImageFormats/ImageHeaderTests.cs b/test/HtmlToOpenXml.Tests/ImageFormats/ImageHeaderTests.cs index 8dabcd50..2c197f67 100644 --- a/test/HtmlToOpenXml.Tests/ImageFormats/ImageHeaderTests.cs +++ b/test/HtmlToOpenXml.Tests/ImageFormats/ImageHeaderTests.cs @@ -63,5 +63,15 @@ public ImageHeader.FileType GuessFormat_ReturnsFileType(string resourceName) Assert.That(success, Is.EqualTo(true)); return guessType; } + + [Test(ExpectedResult = ImageHeader.FileType.Unrecognized)] + public ImageHeader.FileType GuessFormat_WithEmpty_ReturnsFileType() + { + using var memoryStream = new MemoryStream(); + bool success = ImageHeader.TryDetectFileType(memoryStream, out var guessType); + + Assert.That(success, Is.EqualTo(false)); + return guessType; + } } } \ No newline at end of file diff --git a/test/HtmlToOpenXml.Tests/ImgTests.cs b/test/HtmlToOpenXml.Tests/ImgTests.cs index 45aa66dd..b52a3d5c 100644 --- a/test/HtmlToOpenXml.Tests/ImgTests.cs +++ b/test/HtmlToOpenXml.Tests/ImgTests.cs @@ -3,6 +3,7 @@ using DocumentFormat.OpenXml.Packaging; using DocumentFormat.OpenXml.Wordprocessing; using Moq; +using System.Net.Http; namespace HtmlToOpenXml.Tests { @@ -16,12 +17,26 @@ namespace HtmlToOpenXml.Tests public class ImgTests : HtmlConverterTestBase { [TestCase("https://www.w3schools.com/tags/smiley.gif", "image/gif")] - [TestCase("https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/helloworld.svg", "image/svg+xml")] - public void AbsoluteUri_ReturnsDrawing_WithDownloadedData(string imageUri, string contentType) + [TestCase("https://upload.wikimedia.org/wikipedia/commons/b/b0/Mozilla_dinosaur_head_logo.svg", "image/svg+xml")] + public async Task AbsoluteUri_ReturnsDrawing_WithDownloadedData(string imageUri, string contentType) { - var elements = converter.Parse(@$"Smiley face"); - Assert.That(elements, Has.Count.EqualTo(1)); - var (_, imagePart) = AssertIsImg(mainPart, elements[0]); + var mockHttp = new ProxyHttpMessageHandler(uri => Task.FromResult(new HttpResponseMessage { + StatusCode = System.Net.HttpStatusCode.OK, + Content = new StreamContent(ResourceHelper.GetStream("Resources." + Path.GetFileName(imageUri))) { + Headers = { { "Content-Type", contentType } } + } + })); + + var webRequest = new IO.DefaultWebRequest(new HttpClient(mockHttp)); + converter = new HtmlConverter(mainPart, webRequest); + + await converter.ParseBody( + @$"", + TestContext.CurrentContext.CancellationToken); + + var paragraphs = mainPart.Document.Body!.Elements(); + Assert.That(paragraphs.Count(), Is.EqualTo(1)); + var (_, imagePart) = AssertIsImg(mainPart, paragraphs.First()); Assert.That(imagePart.ContentType, Is.EqualTo(contentType)); } @@ -36,7 +51,7 @@ public void DataUri_ReturnsDrawing_WithDecryptedData() [Test] public void WithBorder_ReturnsRunWithBorder() { - var elements = converter.Parse(@""); + var elements = converter.Parse(@""); AssertIsImg(mainPart, elements[0]); var run = elements[0].GetFirstChild(); var runProperties = run?.GetFirstChild(); @@ -44,6 +59,16 @@ public void WithBorder_ReturnsRunWithBorder() Assert.That(runProperties.Border, Is.Not.Null); } + [Test] + public void PercentageSize_ReturnsDrawing_WithSizeRelativeToPage() + { + var elements = converter.Parse(@""); + AssertIsImg(mainPart, elements[0]); + var drawing = elements[0].GetFirstChild()!.GetFirstChild()!; + Assert.That(drawing.Inline?.Extent?.Cx?.Value, Is.EqualTo(6115050)); + Assert.That(drawing.Inline?.Extent?.Cy?.Value, Is.EqualTo(6115050)); + } + [Test] public void ManualProvisioning_ReturnsDrawing_WithProvidedData() { @@ -128,7 +153,8 @@ public async Task RemoteImage_WithBaseUri_ShouldSucceed() converter = new HtmlConverter(mainPart, new IO.DefaultWebRequest() { BaseImageUrl = new Uri("http://github.com/onizet/html2openxml") }); - var elements = await converter.ParseAsync($""); + var elements = await converter.ParseAsync($"", + TestContext.CurrentContext.CancellationToken); Assert.That(elements, Is.Not.Empty); AssertIsImg(mainPart, elements.First()); } @@ -235,7 +261,201 @@ public bool CenterImg_ReturnsFramedImg(string displayMode) Justification?.Val?.Value == JustificationValues.Center; } - private static (Drawing, ImagePart) AssertIsImg (OpenXmlPartContainer container, OpenXmlElement paragraph) + [Test] + public async Task DuplicateImgSource__DownloadOnce() + { + var webRequest = new Mock(); + webRequest.Setup(x => x.FetchAsync(It.IsAny(), It.IsAny())) + .Returns(Task.FromResult(new() { + Content = new MemoryStream(Convert.FromBase64String(@"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")), + StatusCode = System.Net.HttpStatusCode.OK + })); + converter = new HtmlConverter(mainPart, webRequest.Object); + + await converter.ParseBody(@" + + + "); + + webRequest.Verify(s => s.FetchAsync( + It.IsAny(), + It.IsAny()), + Times.Once); + Assert.That(mainPart.ImageParts.Count(), Is.EqualTo(1)); + var paragraph = mainPart.Document.Body!.GetFirstChild(); + Assert.That(paragraph, Is.Not.Null); + var runs = paragraph.Elements(); + Assert.That(runs.Count(), Is.EqualTo(2)); + Assert.That(runs.Select(r => r.GetFirstChild()), Has.All.Not.Null); + } + + [Test] + public async Task ExternalLinkMode_RemoteImage_ShouldCreateExternalRelationship() + { + var mockMessageHandler = new MockHttpMessageHandler(); + var webRequest = mockMessageHandler.GetWebRequest(); + converter = new HtmlConverter(mainPart, webRequest) { + ImageProcessing = ImageProcessingMode.LinkExternal + }; + + await converter.ParseBody( + @"", + TestContext.CurrentContext.CancellationToken); + + var paragraphs = mainPart.Document.Body!.Elements(); + Assert.That(paragraphs.Count(), Is.EqualTo(1)); + + var run = paragraphs.First().GetFirstChild(); + Assert.That(run, Is.Not.Null); + var drawing = run.GetFirstChild(); + Assert.That(drawing, Is.Not.Null); + + mockMessageHandler.AssertNeverCalled(); + + var pic = drawing.Inline?.Graphic?.GraphicData?.GetFirstChild(); + using (Assert.EnterMultipleScope()) + { + Assert.That(pic?.BlipFill?.Blip, Is.Not.Null); + + // Verify it's using Link instead of Embed + Assert.That(pic?.BlipFill?.Blip?.Link, Is.Not.Null); + Assert.That(pic?.BlipFill?.Blip?.Embed, Is.Null); + } + + // Verify external relationship was created + var externalRels = mainPart.ExternalRelationships + .Where(r => r.RelationshipType == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"); + Assert.That(externalRels.Count(), Is.EqualTo(1)); + Assert.That(externalRels.First().Uri.ToString(), Is.EqualTo("https://www.example.com/image.gif")); + + // Verify no image parts were created + Assert.That(mainPart.ImageParts.Count(), Is.EqualTo(0)); + } + + [Test] + public async Task ExternalLinkMode_DataUri_ShouldStillEmbed() + { + converter = new HtmlConverter(mainPart) { + ImageProcessing = ImageProcessingMode.LinkExternal + }; + + await converter.ParseBody( + @"", + TestContext.CurrentContext.CancellationToken); + + var paragraphs = mainPart.Document.Body!.Elements(); + Assert.That(paragraphs.Count(), Is.EqualTo(1)); + + var run = paragraphs.First().GetFirstChild(); + var drawing = run?.GetFirstChild(); + var pic = drawing?.Inline?.Graphic?.GraphicData?.GetFirstChild(); + + using (Assert.EnterMultipleScope()) + { + // Data URIs should still be embedded + Assert.That(pic?.BlipFill?.Blip?.Embed, Is.Not.Null); + Assert.That(pic?.BlipFill?.Blip?.Link, Is.Null); + Assert.That(mainPart.ImageParts.Count(), Is.EqualTo(1)); + } + } + + [Test] + public async Task EmbedDataUriOnlyMode_RemoteImage_ShouldBeSkipped() + { + var mockMessageHandler = new MockHttpMessageHandler(); + var webRequest = mockMessageHandler.GetWebRequest(); + converter = new HtmlConverter(mainPart, webRequest) { + ImageProcessing = ImageProcessingMode.EmbedDataUriOnly + }; + + await converter.ParseBody( + @"", + TestContext.CurrentContext.CancellationToken); + + var paragraphs = mainPart.Document.Body!.Elements(); + // Image should be skipped, so paragraph should be empty or not contain drawing + Assert.That(paragraphs.Count(), Is.EqualTo(0)); + Assert.That(mainPart.ImageParts.Count(), Is.EqualTo(0)); + + mockMessageHandler.AssertNeverCalled(); + } + + [Test] + public async Task EmbedDataUriOnlyMode_DataUri_ShouldEmbed() + { + converter = new HtmlConverter(mainPart) { + ImageProcessing = ImageProcessingMode.EmbedDataUriOnly + }; + + await converter.ParseBody( + @"", + TestContext.CurrentContext.CancellationToken); + + var paragraphs = mainPart.Document.Body!.Elements(); + Assert.That(paragraphs.Count(), Is.EqualTo(1)); + AssertIsImg(mainPart, paragraphs.First()); + Assert.That(mainPart.ImageParts.Count(), Is.EqualTo(1)); + } + + [Test] + public async Task EmbedMode_RemoteImage_ShouldDownloadAndEmbed() + { + var mockHttp = new ProxyHttpMessageHandler(uri => Task.FromResult(new HttpResponseMessage { + StatusCode = System.Net.HttpStatusCode.OK, + Content = new StreamContent(ResourceHelper.GetStream("Resources.smiley.gif")) { + Headers = { { "Content-Type", "image/gif" } } + } + })); + + var webRequest = new IO.DefaultWebRequest(new HttpClient(mockHttp)); + converter = new HtmlConverter(mainPart, webRequest) { + ImageProcessing = ImageProcessingMode.Embed // Default behavior + }; + + await converter.ParseBody( + @"", + TestContext.CurrentContext.CancellationToken); + + var paragraphs = mainPart.Document.Body!.Elements(); + Assert.That(paragraphs.Count(), Is.EqualTo(1)); + AssertIsImg(mainPart, paragraphs.First()); + Assert.That(mainPart.ImageParts.Count(), Is.EqualTo(1)); + } + + [Test(Description = "Prevent concurrent access to the OpenXml mainPart")] + public void MultipleImgInTag_ReturnsTwoDistinctImage() + { + var webRequest = new Mock(); + webRequest.Setup(x => x.SupportsProtocol(It.IsAny())).Returns(true); + webRequest.Setup(x => x.FetchAsync(It.IsAny(), It.IsAny())) + .Returns((uri, token) => { + return Task.FromResult(new() { + Content = new MemoryStream(Convert.FromBase64String(@"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")), + StatusCode = System.Net.HttpStatusCode.OK + }); + }); + converter = new HtmlConverter(mainPart, webRequest.Object); + + Assert.DoesNotThrowAsync(async () => { + await converter.ParseBody(@" +
+ + + +
+ + +
"); + }, "Should not raise ObjectDisposedException"); + + webRequest.Verify(s => s.FetchAsync( + It.IsAny(), + It.IsAny()), + Times.Exactly(2)); + Assert.That(mainPart.ImageParts.Count(), Is.EqualTo(2)); + } + + private static (Drawing, ImagePart) AssertIsImg(OpenXmlPartContainer container, OpenXmlElement paragraph) { var run = paragraph.GetFirstChild(); Assert.That(run, Is.Not.Null); @@ -249,7 +469,7 @@ private static (Drawing, ImagePart) AssertIsImg (OpenXmlPartContainer container, Assert.That(imagePartId, Is.Not.Null); var imagePart = container.GetPartById(imagePartId); Assert.That(imagePart, Is.TypeOf(typeof(ImagePart))); - return (drawing, (ImagePart) imagePart); + return (drawing, (ImagePart)imagePart); } } } \ No newline at end of file diff --git a/test/HtmlToOpenXml.Tests/LinkTests.cs b/test/HtmlToOpenXml.Tests/LinkTests.cs index f688bef8..1d122888 100644 --- a/test/HtmlToOpenXml.Tests/LinkTests.cs +++ b/test/HtmlToOpenXml.Tests/LinkTests.cs @@ -16,10 +16,11 @@ public class LinkTests : HtmlConverterTestBase [TestCase("://www.site.com")] [TestCase("www.site.com")] [TestCase("http://www.site.com")] - public void ExternalLink_ShouldSucceed (string link) + [TestCase("http://www.site.com/#anchor1", "http://www.site.com/#anchor1")] + public void ExternalLink_ShouldSucceed(string link, string expectedUri = "http://www.site.com/") { var elements = converter.Parse($@"
Test Caption"); - AssertHyperlink(mainPart, elements); + AssertHyperlink(mainPart, elements, expectedUri); } [TestCase(@"Js")] @@ -61,7 +62,7 @@ public void ImageFigcaptionLink_ReturnsHyperlinkWithTextAndImage () Assert.That(elements[0].FirstChild, Is.TypeOf(typeof(Hyperlink))); var hyperlink = (Hyperlink) elements[0].FirstChild; - Assert.That(hyperlink.ChildElements, Has.Count.EqualTo(4)); + Assert.That(hyperlink.ChildElements, Has.Count.EqualTo(6)); Assert.That(hyperlink.ChildElements, Has.All.TypeOf(typeof(Run)), "Hyperlinks don't accept inner paragraphs"); Assert.That(hyperlink.Descendants(), Is.Not.Null); } @@ -143,16 +144,15 @@ public void InlineWithText_ReturnsMultipleRunsWithHyperlink() Assert.That(elements[0], Is.TypeOf(typeof(Paragraph))); Assert.Multiple(() => { Assert.That(elements[0].ElementAt(0), Is.TypeOf()); - Assert.That(elements[0].ElementAt(1), Is.TypeOf()); - Assert.That(elements[0].ElementAt(2), Is.TypeOf()); - Assert.That(elements[0].ElementAt(3), Is.TypeOf()); + Assert.That(elements[0].ElementAt(1), Is.TypeOf()); + Assert.That(elements[0].ElementAt(2), Is.TypeOf()); }); } [Test(Description = "Many runs inside the link should respect whitespaces")] public void WithMultipleRun_ReturnsHyperlinkWithMultipleRuns() { - var elements = converter.Parse(@"Html to OpenXml!"); + var elements = converter.Parse(@"Html to OpenXml !"); Assert.That(elements, Has.Count.EqualTo(1)); Assert.That(elements[0], Is.TypeOf(typeof(Paragraph))); var h = elements[0].GetFirstChild(); @@ -194,7 +194,7 @@ public async Task ParseIntoDocumentPart_ReturnsHyperlinkParentedToPart (Type ope throw new NotSupportedException($"Test case not supported for {openXmlPartType.FullName}"); } - AssertHyperlink(container, host.ChildElements); + AssertHyperlink(container, host.ChildElements, "http://www.site.com/"); AssertThatOpenXmlDocumentIsValid(); } @@ -250,7 +250,8 @@ await converter.ParseBody(@"Move to top Assert.That(rel.Uri.ToString(), Is.EqualTo("#_top")); } - private static void AssertHyperlink(OpenXmlPartContainer container, IEnumerable elements) + private static void AssertHyperlink(OpenXmlPartContainer container, IEnumerable elements, + string expectedUri) { Assert.That(elements.Count(), Is.EqualTo(1)); Assert.Multiple(() => { @@ -273,7 +274,7 @@ private static void AssertHyperlink(OpenXmlPartContainer container, IEnumerable< var extLink = container.HyperlinkRelationships.FirstOrDefault(r => r.Id == hyperlink.Id); Assert.That(extLink, Is.Not.Null); Assert.That(extLink.IsExternal, Is.EqualTo(true)); - Assert.That(extLink.Uri.AbsoluteUri, Is.EqualTo("http://www.site.com/")); + Assert.That(extLink.Uri.AbsoluteUri, Is.EqualTo(expectedUri)); } } } \ No newline at end of file diff --git a/test/HtmlToOpenXml.Tests/NumberingTests.cs b/test/HtmlToOpenXml.Tests/NumberingTests.cs index c48b6994..bd8f593c 100644 --- a/test/HtmlToOpenXml.Tests/NumberingTests.cs +++ b/test/HtmlToOpenXml.Tests/NumberingTests.cs @@ -549,7 +549,7 @@ await converter.ParseBody(@"
  1. Item1
  2. Item2
    1. Item 2.1
    -
"); + ",TestContext.CurrentContext.CancellationToken); var absNum = mainPart.NumberingDefinitionsPart?.Numbering .Elements() @@ -611,5 +611,36 @@ public void NestedParagraph_ReturnsIndentedItems() "Last standalone paragraph is aligned with the level 1"); }); } + + [Test] + public void NestedTable_ReturnsAlignedTable() + { + var elements = converter.Parse(@"
    +
  1. Item 1 +
    Cell1
    +
      +
    1. Item 1.1 +
      Cell1.1
      +
    2. +
    +
  2. +
"); + + Assert.That(elements, Is.Not.Empty); + var odds = elements.Where((item, index) => index % 2 != 0); + Assert.That(odds, Has.All.TypeOf()); + for (int i = 0; i < 2; i++) + { + var table = (Table) odds.ElementAt(i); + var tableProperties = table.GetFirstChild(); + Assert.That(tableProperties, Is.Not.Null); + Assert.That(tableProperties.TableIndentation, Is.Not.Null); + Assert.That(tableProperties.TableIndentation.Width?.Value, Is.EqualTo(720 * (i+1))); + Assert.That(tableProperties.TableWidth, Is.Not.Null); + Assert.That(tableProperties.TableWidth.Type?.Value, Is.EqualTo(TableWidthUnitValues.Pct)); + Assert.That(tableProperties.TableWidth.Width?.HasValue, Is.True); + Assert.That(Convert.ToInt32(tableProperties.TableWidth.Width.Value), Is.GreaterThan(0).And.LessThan(5000)); + } + } } } \ No newline at end of file diff --git a/test/HtmlToOpenXml.Tests/ParserTests.cs b/test/HtmlToOpenXml.Tests/ParserTests.cs index aa685eff..470338de 100644 --- a/test/HtmlToOpenXml.Tests/ParserTests.cs +++ b/test/HtmlToOpenXml.Tests/ParserTests.cs @@ -39,12 +39,12 @@ public void Paragraph_WithUnclosedTags_ShouldApplyStyle() var runProperties = elements[0].ChildElements[0].GetFirstChild(); Assert.That(runProperties, Is.Null); - runProperties = elements[0].ChildElements[2].GetFirstChild(); + runProperties = elements[0].ChildElements[1].GetFirstChild(); Assert.That(runProperties, Is.Not.Null); Assert.That(runProperties.HasChild(), Is.EqualTo(true)); Assert.That(runProperties.HasChild(), Is.EqualTo(false)); - runProperties = elements[0].ChildElements[4].GetFirstChild(); + runProperties = elements[0].ChildElements[2].GetFirstChild(); Assert.That(runProperties, Is.Not.Null); Assert.That(runProperties.HasChild(), Is.EqualTo(true)); Assert.That(runProperties.HasChild(), Is.EqualTo(true)); @@ -57,14 +57,14 @@ public void ConsecutiveParagraph_WithUnclosedTags_ShouldContinueStyle() Assert.That(elements, Has.Count.EqualTo(2)); Assert.Multiple(() => { - Assert.That(elements[0].ChildElements, Has.Count.EqualTo(3)); - Assert.That(elements[1].ChildElements, Has.Count.EqualTo(3)); + Assert.That(elements[0].Elements().Count, Is.EqualTo(2)); + Assert.That(elements[1].Elements().Count, Is.EqualTo(2)); }); var runProperties = elements[0].ChildElements[0].GetFirstChild(); Assert.That(runProperties, Is.Null); - runProperties = elements[0].ChildElements[2].GetFirstChild(); + runProperties = elements[0].GetLastChild()!.GetFirstChild(); Assert.That(runProperties, Is.Not.Null); Assert.That(runProperties.HasChild(), Is.EqualTo(true)); @@ -73,7 +73,7 @@ public void ConsecutiveParagraph_WithUnclosedTags_ShouldContinueStyle() Assert.That(runProperties.HasChild(), Is.EqualTo(true)); Assert.That(runProperties.HasChild(), Is.EqualTo(false)); - runProperties = elements[1].ChildElements[2].GetFirstChild(); + runProperties = elements[1].GetLastChild()!.GetFirstChild(); Assert.That(runProperties, Is.Not.Null); Assert.That(runProperties.HasChild(), Is.EqualTo(true)); Assert.That(runProperties.HasChild(), Is.EqualTo(true)); @@ -85,8 +85,8 @@ public void ConsecutiveParagraph_WithClosedTags_ShouldNotContinueStyle() // this should generate a new paragraph with its own style var elements = converter.Parse("

First paragraph in italics

Second paragraph not in italic

"); Assert.That(elements, Has.Count.EqualTo(2)); - Assert.That(elements[0].ChildElements, Has.Count.EqualTo(3)); - Assert.That(elements[1].ChildElements, Has.Count.EqualTo(1)); + Assert.That(elements[0].Elements().Count, Is.EqualTo(2)); + Assert.That(elements[1].Elements().Count, Is.EqualTo(1)); Assert.That(elements[1].FirstChild, Is.TypeOf(typeof(Run))); var runProperties = elements[1].FirstChild!.GetFirstChild(); @@ -94,14 +94,13 @@ public void ConsecutiveParagraph_WithClosedTags_ShouldNotContinueStyle() } [TestCase("

Some\ntext

", ExpectedResult = 1)] - [TestCase("

Some bold\ntext

", ExpectedResult = 5)] - [TestCase("\t

Some bold\ntext

", ExpectedResult = 5)] + [TestCase("

Some bold\ntext

", ExpectedResult = 3)] + [TestCase("\t

Some bold\ntext

", ExpectedResult = 3)] [TestCase("

Some text

", ExpectedResult = 1)] public int Newline_ReturnsRunCount (string html) { var elements = converter.Parse(html); - Assert.That(elements.Count, Is.EqualTo(1)); - return elements[0].Count(c => c is Run); + return elements[0].Elements().Count(); } [TestCase(" < b >bold", ExpectedResult = "< b >bold")] diff --git a/test/HtmlToOpenXml.Tests/Resources/Mozilla_dinosaur_head_logo.svg b/test/HtmlToOpenXml.Tests/Resources/Mozilla_dinosaur_head_logo.svg new file mode 100644 index 00000000..7af5bd27 --- /dev/null +++ b/test/HtmlToOpenXml.Tests/Resources/Mozilla_dinosaur_head_logo.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/test/HtmlToOpenXml.Tests/Resources/The-Song-of-the-World.jpg b/test/HtmlToOpenXml.Tests/Resources/The-Song-of-the-World.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5e1d898328c7e493304fae755ee1e690e40f3273 GIT binary patch literal 259814 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�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
  • $4h#VHxI4!B%ZXT_d#6^yvN6+|BmLZU9DTm` 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

    ;E))?^KFAr*O_3quu60XdW}MRuft8kt-1At4 z*+r-5n-SRAHeDA-D>UY*RPyXnOw5tl2%J|sHmwAv@p*((OunanK{~gWXcj#@KsUqv zN;$By4lNNBk(Jaz%xr2dc_H>rA)`%7hUPn?`IKhFk_6T?B@oK zzGqn${1F6}j#Cv+E|)+Si8X{~xkn(O$8v0sn#|`$@Q4F6W@(iN5++Z~u>)S`$O*t@ zl4hx-xu?aUC>x{2v9f{?UeF(%m83(FfgXtP;ezA-lz(_@GfpC|ev0IJrnmfB_k|z5qf&*Rps+S=5 zg4l4qQwIss=op)$LMpTrP9qVd*L9iA@~=eq3RVmri#vvmE)odXqWn0}*!4{yi*@8w z*2kKMeyDsm9Syp!5-&4f;Y}9QNlnfCOACfLvspn0P@f6(d9w7+jjv zB{PK*Hb8Pa``K)zp*pMjWrYc|ws;MHl=ueb7*82XL6u58*XZ zo@F?dDf%o({{T%BMoQH;(A9$I?+KovV1fCM5^+6Il7JuIG)J8K z-6zN>L?VjR-Ay9iq@7A}>vDjZ_gZv7@>G6n{)xvn`w!JQ#wG;aJ1E-aVb(kKluL%7 zTe(9L9Nia)g+yhfr|^mpxmLt!TiMt!!9({YHGiW72d)+KT5>RpTxKNu&$P1;oH^VF9fI36G*_X>_^gR}BY6h)2YS zI9!RW0*MlL7s1k_TBfy8OfiOzH6 z0!^Uo5xEkJjZQ(D09=Qvu6CK~m|E!79w|aTBx?k>qRMd}z1TS*A=Li>WpyN`g5nG; z5bP%aGJzCLdvmugLsK^q)i>b>JAfLWC54bb5W}L1V4!PB`;^e=`Gt=~itHyJ0>*4% zuv+dbG{C9QpaZh;MFRM3ZkHsci(g3>9ab!kc1@_6v~`sBx!Qo78I0cvchXcmi?P=W z4Vg*sxrM-YSXpxTva^TL7H=&jVMAxdaF|5vLZ3C(>8?EVSS8fD!8JV!!EPIiD&bMw zpdQ~e>dj!#1pMYaMMW2j@oJs{=_-`bK66o0CShd1(+#=DuK4QTUKO;#S`BcHesQ^XC>;|RKTDA85BDM1wIAvvZ{mYWm; z6+=Z(FGwWyM~EG$Q$Zeypb6*~w175harKq`Q(axe1jk3^YMJNm!(>!cNla@`Ae`BS zixj*pK;TA-dRbwClxwdbu-ZEhstqTg5TGi#w%H!)N^qT)QBkL=Zm70`mxOd(%7W2% z2|=tABwUVVHL;qnBK^~Yg8_H&G<)jHNVgW!-n4zkI^;xoZcrq00KF& zE=d0X@lSATgt@}*J4$RdqJu>6L=GJZolc3_vbQMI4x9Bw&4Vt)bb#L46+x6_8j-vv zmuH~e0s$OO`*c!f?z}3Nik&&2=*>povWgig`9v2=kupSyAi`-J%@K!USaRKQ*1IUF zm;!^4RD~5ZCs^BckJt~Q!D$!F>YpV!9`H>zLD12yC0S5?o2q%lZX{(6*0nRTYXEQ{ zhR{mP(Geg>j$>ttT*mJoDxd;SQ)KU&qSMY$6(cGQaghM-vbJC}*5yHSS(v)SoocZ& z18G#a9hc15{;Dm-N|b8vH3ljH3TlpLv`}uGCnivKC?AD{bAJ=IKo5xGVKASD-n>ZM z=6XIYdn3R-6JdbKJCrOccHK=y3|nHFejt6XJ068NyA+#g&?6#i74lyw_g*0Z3?1cQ zKP*#9tWf!!?H9w!Y83!74VScGJK5aP1Y8lZP)_KXPjM~eOmslQjmnAGEY5rR)5#Y! zfyY=gvN@OpR>5IrE!e?F6oTB%Cc~7f<~i6m8iWIL%r{Z}6LS5EVfc;p38oF%EI=t?KV?b$ zN;yD;!ENB4u%z@Tn)4~xW~sBtHidgI>gp$9yaxD2mA5sCKqD=JXrO>JLA2IXM*1Qn ztrrj!8plPVaHo(|+u!5gZio_hHS||EMw*g|gLT5tojo-?%BTj2-u+Rgv2|a|`umK> zyF??OHG(McyIa8_)Ag1ev=| z+N=khCqZSX4W$~frwjqkt|X`BW*kI)2RNHw_;zCN71Z8))!tidi4nV~y{TPF?Gbyg zh!wR`lvEYfmY}wZS&Ek0Ri)aZO27R6-~al)_qvkneV>z@b8_A!=RD`RpZlIrm?=A( z@(f%(p!21Q*^Yc_xum5TBNP*uvlrHByE(DdsZEMNny5?@M&%kz%oKy#nSH!TRL@rv zhC|>&W;dk>6&wGL{z+^){dotm6%Qf6L@&bfBjooi>U&20S_82YQ#S|beKuN5X5cwN zw#{R^RJL>NcqQ-6z^>EtZUbj*X!0sQVoGKQi7RYey6WT655feQjag6R(;ijRxlR(Q zC~#YEJ37hsL@*P3`v}d&2>T36WiCd7%MKd*OQLi44y->+>o^!^)}?Gf;;d>*>z6ZY zOi2Z-JXtO552umKubb2ToJ-6i(Zd-I3q6P5rqpn5$h?o>kC!h>GnDPi*lA$w720?8rr|>O@@q)B7#ba<+V* zw7IbS1I#O!MY%m<<44YP=+@!!WnDalP1%gS!Jx{rYX(HF#>h*t$c217$FF__C{e~! zaNxMbW@)bJs5NuR);cO<-9n~cmQFtq@tqzadZz#t;9&4N%L9XtpipQZ(UYjvoea`^ zRr&r$LQ56{UcM{#`T!Z2+90~xN6}Q%NaW_=V2K*i(cW97+tlZJI-fN;Inhx)o=6&r zelz(sLdfK=?Bj0&H^po3I)|3an-yxw6N`p5xn7l!O9`&dkg<^*cd;yg-xm36_Gs$; zqzb*KE9(m;?q;c}HTKGPO*?qsJ3V0}w4$c~;G@ooL|x&DOvc1L-4%bL`jJT(84E2c-tv^2`Fu{nUWJ&3#A1 z1s5CGh|AOmkX=MG{?G6P2(RmUy{bv?@yXHhWKLq`)DBdes79=OcA53$9C?TBH|VKO zJSq6^W>dDsGtbSNYmOTPe;w|aT0QrW4*}7sU=;;-s()_)?Q9Xp)z{;A<)^u9uTPK? z`)Sb!!+{yuVHOvT?rHeRj6?n9?o1N>GRIP z&{wk^hJ&(+xojFHJ}lc+j<0dAO;pa<0)2(t@tp84icW`XG?Q59r;VdVW4+}>eq^99$I8@x^4vy9D({=M%llghN-s-s4ZxJE1Brt5l7St_?+jMERnwchO%0io-4MiL%lh z?l!s0TeAjmN8bG%s23)rB5cOD><)s}|G;2JX{Jd0S0Z?04cs*Ekn#6VQ^qY(Nf=VC zq%cA!2S04pYpi^i-YX7?X@JO1{B-b5dE{%Or*Qa9Wegi~twH(VeX zHxGyF&8S0|WNSW7&(M4R?F)pt^-qQr9`!b8SC%&GorLl-8r*tB|FcU#@v-ga%gPiy*X+cG{~X|hQB(Xdt20YP*+)(C6u$i5R&09f!C`hI&Kk0 z@x?sG`Hx(s;P;qNZGY@xH_@e9-+b5F0W&5P-Uige{4OTd?iv^(%L>$S zNZgRVbK+mIu`2?!>UP2o{%NNIDwT^g!c2c!o$?O zBb!7bu@mWi*eCt~`@t_20=^s8<;pCoSielfhe*{1su?Fc>L^01*H!GGJ0PqXkZqiq zf=2L*LGvAzHN|>`x2)~kp%I8?@58CEZb%dIs+2}%Bz}losI-$DvzJ{(-2DetS6dD+s*Lu+POFLtJs>GbapiiM|)UoVk-UY$I?Swc$e( z{PPye^M_BzN)#O#iRx20K=(j7;_m%~AsGldL{)11&V?1~q+fv~2bqD<;bpd`k3Tqp zVvAlPUxn#3(9%?!YzyrA?xRAG!XS`^B2ZB{1i4-yn_DJRNNAK)Z{H_iOU!7(e^gG}VFxB7Z5T-XC!kBmA?#Egd6?1#jqvK$f$XFC2?3}!rI(4x!u}g1! z)h*{W&`DA;oIL!IvT*s^5Q#(y-!1uHr3XAjhiwf)8kQ2tg7V*HfFrS~JT!J-S;-lF z0x$3Mum5TJrcaJm&Mk`1!Yd(BmI=QhjO+YR+Y54v@wTW591$Z{N^-BIt%_H=O$_}Q zw%hvli0qD1=mmMhfhA;CiLCO%ruA@&&VdsK)Xb)Swd&t0V!ZZsHKn?37d1Q-5G!HE zs;YQ1$-;bfC~~c&^QSaBO&tMnnH@9et9PZ{FFp0Shxge$UJP{&)L2Pi@?a6mbP4Jb z+&-MnK=;pM;(r=aW5`O@#V9L8b6eML3UZo8syG}NXg6#ThC0|KiY=&3i8P~f+8$KBl-H*#`#I{mx^LEWhGmUZSV;D)}u z|KyriO4YwX;)8!;ynr<&jd24$t0dJz$xE*xfg;*s@xdXu4<`x zUUmK+JT$~*pJO<#2L@VYoyo4qhG+8uVqAkq3axqE4#h>nPoTLwcr2KD&T8Ab%=@s$ zbzPpzo{}FVfin7*q32VPBVAhN!LAl&@IdY0<$rt(Pyq;eCJ ziqu&hC?{NZRkKHEgW=ye7IH15oq`+*$#f`!G(d#uZjZ~P49Mj`0=}tJVx)CYficFc zWCC?gX8(n<1xWed0Hv z=Z5-tkioR2$xp|6hf*qf4nq8@t+zvU#BrN0MOe+~nS+jUe>Q54kN3@Q@4Q{+l~fE* z%77>ja^1ZkNm@kTufE(^+rPDQGR$5e>LNf^k>Dru55#M4H)1~kP$2c z?t70>JcBNv{-|PwKsC8@>hwLFGEFkqgcmqU3_gjl$$e1e`tuu>$&?_B=NCY#fu zOSjA3-V19f!LvfOh=N~)@^H|kxuw?_bzA*u7}0=vfoW%~54iRoO`c>}QTSQKi1FCE zt{fJA6+%W39nIc!e7zkjW#iNLB-DL&aCxI z@m&x)mguMoWCH?ND)|1Y8thgXtsws@Yo>(kF85~ZtZ!}AAsNAOtzwc-?E3XscCkSU z0+gj6Mm020-mTELkN-p1c~btUVFc2x&0PnZ{*EJm+$W##sNH`*I8qmI`xi$940?3; z(sdqUyu7(}6zsT7R8T z-gXCdB*Dm(u%ZQz)(0;T5+U*SyvSywn$+u!{>L=kX2W4e7mXTWY z-xyExe~HHPi~Sj&xmhJA^5(A|G^66*{Z+EPQtnNvjU>d35Nb>oec6ufus~7gxoP3^ zWv9x^3Z7=d{bPhIQvnYfZRx+LJP*%DPlg(u8GIDW)ah>EAC;1~H&^~vCkI4r868^h z5w5v0P|i5lr8@1Wa5M9S1~RjZj*O_wS&j}IV=|OIw-|+^?F&ycw+MFl#frzXc52R zf6Ie300e4x@r->KrQELEhZ`kGF=={Y954>8r|YHe>=ssEa$0xgnq z)>b)2KKMT|ort?(^ps<4Ip}hlpLeI?I1KiPEi2rhp`R&R_l%Tk=B16n@miGCCdXh=lZN$K z$n2COIXbW>;7{r|M(YS?@AN@3B3tSL5Z{;w2*RmsS;vX@gO+7B9*7o~)%6aC)Z^oY- zal(?w3YX+njCN8PeJbXWgL=Fat$>hUtA{rjz2`FWLe^CdU?4ct$AAGz+{Rh?<^l! z>x`>w!`>Vys&fn!v!@H~|Ad5&Ik$mUSX$ z*NZUTgt=q8l$oEh%LT21FbtZFYIt?BPoRPT`;CX{lS1ZcNgTO;#ckB(8BYkJ%w`>f z>NqBOAT-WQ9!C|SL@d6bazFC7R0_EnAMr4a(2=hrF{#^}_8%o4!!miYD<$)nxMX4D z>b76e<@8wj_F|p-$Zur@tzzWxb|RwvI|JaE^d@HB&?$vF0ms%Qrtqs~WS4et!dtY~ zt0}7(8}+Vy-^p26d?Pc)bGI+NyT(MXi^FLv(vsk<=ij!epvmbU00K;`gs?OPDGRWB zfG6azN)6(C4`;Th=vlFNVVw&po^t$y)bU-l*6-&F*Z5(1^D$@sDp{a&YsxhKD}4&} zq7u|3PtH_;0&YYo`kr=$>yIUw!EdE*6+Wq8{t?!HfY{)>?8CUU)Z6@ zB<3`iUIpTz-%VF1Rj*1f_9(W>4TbEYSronW((C+Wd1WgVMQ_NXDO`VqSS9$pEsOPQQJ=7D2Ac{Ac{LL#GQyS?HYw8~x3|C#> zGW?3|fIboRW@Z(j1THq^G>EXr+^yapj%Hi2CY!-R>--;~&W+5cH)QSJjXEn?rhpk9z?jQySu{nx_4~(ZM2P;qde-PBMykQMbDl zbmRpTBjbDSETjdN72V4*4JLbXq0A89fB;1ewP%z3!A6>8*=K$fj>pf(SC$yq7o1BU z?DwB$P*9X}>JCZ@{2%e+7vyq=wDTOHvr{SC=G!#W-N(0nzzV{_o?w+5KDQc!*W{?qg^! z+kJA1Y5u-8!Pce_eIyt(U~uBu z`hF=7;P#W1h%MxHfl8*iO7)lQ2utSujkpqf*E^h1;0|epF0q-&`&C$?w!JFlfO>8Pi+2_;RYxtBP>rm3-#N1!A!aULiul9D^W@475!)z>y~TMrAQdCDz!&VkaWI#Sfxl$hm|>KqQ$^W=hg0nWUWLNI%L z99q^BF_TA!3kcc0DdS0^+Bu>09&EQ7&wNBx*u6wWDe!5&wf+m+2(N>u>~oQ#-^PiZ z{i};n>g*v|5LwACOk)38f3 z_>$UPY`WFwQ36Dz*qJb1#*R9zn8U$P>&(ugT6^B$RG#;~jLeEY(Sf9}S2|P_I~|4~ z#7Mb$=UqY5nMEd#wKnNprl|V5eQzag`O^coUQGaNg|n7c;}WI0t*X9^O5KH%3IdMv z3dz%Rw>fZ$HHT9q5*BCloCK&=h1aFpJoOBIY&LhiBPr7s7l+<^%s?%Ud@20$0<3kY zIm?=+MyT>y7|a&y$#B|qB5efpW#avF;wJTmS@eusc1toHEKO^tN4efDra$Jc-y@1X zqA_`HZ@qZ?16BA(sD*WVo&B5XPK`q5nrq;Rd)5)!yD`ZIN8&pclXAAY!vwIDsuDU1 zxX{!uUB*4~*Ed5dz@i1OexCHJhLdyhcOWr@(VFdpUwpP|VXsU~1k$q9(bekp1~3%H z^`T&@s_>ZLPpJL7DEpLt+0M1Cqvy01Rr-dph!))uMe^M=Mc9nlW!|nWEe*$I{||GT=$xg`!Ncfq&H|2+ z{HF1jloZRo*~Fz4kcJ34IvTcOo!f(Sx0J2LZ(67(<~pY)m4(k(ulFvdOuZfqS8lU} zemEME(?wybHM`@cAk0vJ^j;nf{Qem!)u@C zN~FAB$hIa?%T1pl?yS4@M1+Uzh#okE@g6iYAxegv1c-kAfUx3F7gW0y%uAQ*TdW_} z)FA^kD`1Diry?%!G&Er_$3xX0s|0tkVjxNE#`q?qHg_ZyFJ@}V!@ICRp;WFFDBtat z^WwTLJU!XxObtw!9dneQS-1NUHKOucQ7{_md29~$?6r7oy-N)bn!uSpuI|Y4|K{1G zb2^U5^W`|Bh8DBt$4Yn)HN)Y1bu=fbDU3lui3 zUolb>(Wx|py&EU=boLq&FScEHH0Vekh{%&oQPXcwa4{-7uD@O+_k9R8`F#<2L*Lau z((=r4kWwbrQPNMf&6M+jpcxcCPnd7h>QtI&o0bWnpBHp!LOkuCdL(sV@w7^)59O{y zK2ljM=Jt`?{u7lV4YIEYbV7{UrkMP}g{I!&zx| zWAV2k@59Oif|kl^i$v0I`HxGJxzUchXltibgy{0a#I&=6lV*u8=UM^d?xf$PT8$1S;-(t<_UvPB`#;E zwcGNCLb+!zL7lfxsg&LOW<#=;aWmdXVZdrj`UhxcN9bR^Wb!^Ub$6Ad@#E@o2sLD( z@k724sv4KRrg``c*jE2Zaokoz(VFeMAnEc(S^5LCf}yogry5EY=;H4_ko=A>)v@(z z?_?jxb@!z8jd-xiq-QT#V`1H@rsIlHQ#oX72HLVTCa$yx%NTZ(R_QqCp9`x%5djQM ztr)2!I_@5#YIulpiw{d`{DTpz;oueB{CqNnLL+sYoRO1*Cr#p{pJZ&ayhV~P%sd1< zh`S%LZMMD<*arG|J-&r!@N5&Di-z>^3eKFdrA!cfz00g8#VFY*QhPlnCl`SMW!mFURKYTOP|GHY3t_qnx^G{-d1WI)JjZwSUeF zZT<-ZZ?zUfc;!)xoG`#%fBDu|-$S}zdZiX*D>4#L384VV>n^1^?|Y#@Gv*o6M|1^Z zpWoi7z5h{*VZc5t8TXaf+;(S*f3q!SgKM!_HRZzTimR9T-11nD&$ZyQ4eP;W?12_( zJBbz*a>8_cqh=~PyXdlBKDBFfRuFx9o3;%Msn)!J!ZKYY13EwxCfI3ag5J>Abe{>3 zSJ+85jk(u%C?eBD1!^O(4Bm;WtdgsofmL)`fpxC8LvO>nnQKFDn9WXloFAdW7I*9_Umm777iy~p2AA3^2t38oFcU)%%G0g;@BKHJH($&6`0ej!N~`o7c#j_$Fnr3-EXyrvg9!c4TbC}unlgwk_TmB0lkPZvc_Uf zRscv!=7WT=7m@tyCtjol7U8seY;;NCj?t-RIyxU9MDzY%`b4_liWYp4LkX0-6)gCs z>J)nD@d(w>w=dn}&vrR5WhaSXEmMR^vocx@8%=rs2}V#M_83~c3q98tR-sQ152~s2 z3Z6}QrLlrxus%b6ckR%k?^~4Qvjjy>@lzi<*O!;Z)Y4QZM@M{~ZyPCtL-*MTUn(3= z508$HkP>5z$JL<`2N8x_uFppdO{ph;yJgruUxoVIVW5WM$ig*n$>v_tO7x3O@>|w> z^JS^rr||dKRZ={mbI{1mM_(@Am{nI-cM7EH8@COP*SQr?t*hL-vZ~4@{%myefnxJe zEd0YK<0ZGD&;p!=tz33z=l(W8)*IIlvtdhD(eEcM$1=xHmFc0s@gDWtHitu9cwjr@ z%{}I2v36nf>G-rHczqSg&bB12G5Rf7(#XT{-znjch_q~&`L67kyahkVAj$4gA z>zx1(y%Y>RS=bO^*t8bEL&y0KfRbTWdnOOVqVnpwMrD~)MPeUYUclBhE+N`Q&_-=8 zUvo5TKzKs9*Z9O=Ub8?tLN^Q_v2c76h+u}iS^mbdrRU9F#Rl;Xf(VbUrF1sgRxSDR zUABd88j68kx@^nBr`06#L#sZ7i|$^&08r2*#hu_ji=u9U}e$ba}|amkK?c@tmt#!BDqsOCHA9jPUFf%S<=lxkF3cI-|b*hM!-u zDlCe8bzIm1^z0fsBKlTf zL9PD{d~N~VaxG@NMs(J$IX|GaVGBt#OqRzN4eQQqWq|Nr<)n>eK+;T ztisXr{Io&)hkEFEE^hLO{)qXidImgO;O2WQby$%tKFaNNvo-!GT^@4bGI2ai;#Jp) zKp4AB9nUmU-g6lxBZcI(_;{>2m)rv}2Y#Q#qyAFIY(DgsJuMw7#jj1xaZ;&L>tehE5$+i%l;Ge0 zD;ECZMC$KJiP$Y&8*u@%ZTRaI95fL1+Tv;ZUajD|Kzu8%>mzFLOTcBdfXYY4_4;@2 zFyp$ZB_`dv@?2&XU)twwvDL6&zYMVo_DSp55!O>ArH^f2w95yc)@exs-=tzkI2xPB zer^lbbyma#f^2N3RowQ1d4AaWX)lI`i8K1JfvlCue~2V7gd6W9bA5hb9>p54CSY+@3Cnt)i*22S56%_F#-)D4)`>(2h zTl@auEo~Q2qV6^ekY*#&DKh6tHSF&QrQ5{m+j(>F>zDJYK4=m7a0iC2{;G;{YdGrC zb6T?<@e8sQhFefpDA>CLWmKu}q!OHrFMX)2Sxxjlt>oZEy_l3r31WH{4W)m(N>bjL zCuOjO*D$6^{ovxeWX7l2inq=8KXiA0-I2_b9;hv!m@XtGSaAv_yhJFZ zWoOxQo@JA>?%eYKn9X&lpkc+18%@3oWBaA^jmnkPk!|oxN0<;y7KwLaaK`G(ikbm0 zFI>m&GK~FB-(}FolEMSF?Q53*SiYsMd$?_X`TgNLQU?3w1-B8qcL7`;JOSDhO{WjV zfyW7>Gm^>91j&$cO#H9+teMZq<`{V^0;N2h2o1@$Jc+M|X_6f|1b#^KsxgpGpYW;3 z`*w9br#Ih7`UlvlI8XiXzJ$TYAkWJ!)_|p%P_Pc@D)Bn|BX=t27@%lpI%-dFjC`7k zu`a33WejdF9oC}SsN5@hrhHGRJYLHCtUPX-w_-o+N-WEGwfbwOUr#O44dK4M5>4t;EQ&>srvVh`WLt#NZ8(y`Nonqh5`_lm(y(UvSL|gdVIpRa4v|`LX8_Sx z6rzMs5 zF6+Kmus`zs2VTPJ#m$33!O&Np`%#_uTOHt_cA_5;bzT_y%U3T#`-R_}dQWa(DSjr# z2aG=>zx*<=J4j-*+NalczMV?z8cG)zB;dfoq)CP9OXzv~YvPujW@9?r+ePdHTyw=8 z37+c(Ex2~h+OA~7a3PpEx*YsA?n9m&?K);cPbZD)+VqZ)Yoh5289WU11TN)ET@Cmk z5zbSa$@l=VH5@dX{Rni<_!ULMZq9xXS2E~Al7-JsgVTXq~fTk>yF&TYK)Y-Oiez|t2X11?Md;y+R_}q zc>Z66Ztp#(bA&JK_4c(g$1LvPQC5Q90TX2(k!iBO zJ>a6xk)<(AFcrtxhArK}*5)O-tT^|tG@RSh5C4idD;D&Lb_^75t2XF<3r?FpsWL+G zHWc{^0Jr;6IR+OD+NF9s*K-NW4(MdPk~Q#h^TU!_;1wK7@8pRstoMU0hvI0X7oI!< zbwYbsNxT8FOp@0CRjb%%xSWs zgopaY5poVtdoZx1CF`kFn>jgLoXDV?1zqW41vGx&xjPx67S!jAS*Hf^lvq1 z4V2NxqGtaA(l@=7YxoI9>TkYU3l7?>{bUzQ56OMvOg_0Kr$=!wkuSx1S-J~hv7+5Y zu4Xo2??mz{9~=+Te%=aXIOcWwT!`o=&M2peqp64Y?ZB~vN_^jMGncohNRMg>el97A z6A%EK9^mL&)g>QDZfPRXz4o8Ve`$NE@=$u@MeX#Me`$O3IgGv8ikwO-SYh`0Vmw9NC?PBEjOptrDim<`_p=pkXbK{sB02@HjoHeRXe8kD= zDDaJMv!Hw;yxP{OGssAHENv~TfxwH+Qcn7gSV`V#l_a;dagX-_vq1OK3{Imtl_SM- zC1}Bu^UO@8$&b_sns_#1J%2F2>lnABA6H7Wd9Z$$LQz#{mrDK#v6;a?z`DlV)>U!X zOgN#@8q>XI{cQq{L_9hT^rV(-$rhweLZ+Qap|OZuR4?RhzcWzhs8esy-bK-wSu*F7 z5SoRyYEgY`3{^Xg)4!mRaSP`P z+M?*mNh2FK3-dzq#+iL<(Fu27)RFN|G6~tJc2XN=!#bF?;3QRDr76r>8?<$Oomsu$ zpIYoj$uO(RLWX=ESrb`Zvas-*y+n1Ei4mtVRQV)ZqFpIofP!{X$-X`KKBc$eoh-qfdQB^)NjZ)Ohn34gL;pok!yD4d&s~fGv3bVD_ zO$B?o=k#TWYT@*pv%U+BvT0e9N07H9-N5pk%@$h%;ty_LNf@ejv-9(T$mJf>7g0U1 zKCe;y!^@o|ij%kV07QVhO-^Ua3j09`6uilvRhd0-CHlOlE>m<}i0#9z6kcw!<%tIV zsk*ABOhFHs4@LSpMhv!Ua`K>}x{ys!iXKwAu0T#AX417lVON}GyL@?szHwPVeS%TT z`dCSg#+Ye_(BjE*w|$NW+vymYoH(O9AnY|thx`kTb4$+@=Ub3G1sx^I-6BJNX#OdO zS2zYtXIduxU>Nwmwp*m`7>*4VPWCq1RMdZlmC6~`>snRm4e}Kzc3EHPe!10|c*I_s zHLdMEPnNrqLXEiq0iUw==2I68^HdB#TfBtz;nJPw+Cq(EKXPr=IF^-i*tqJwT9{s} zbYnE?i)ifbMeAh&iC@r=yo+*-kx0h$vK&Z`b?;d&{=lu9 zgRZqPl5%U7yeSqXIn0YwcL*`FNK7DU9}1wctR}rxEWnx+uKziyyuxLEZu*W_cvxl8 z>-uMtCqhFsARjw@_;H_h=xY-AFx8+!uYJzYP$+NO!dTR%aYi@fNN05n|2yvTwj<0`g}EGL!QVk<(wfGUJ{2h) zve$s3uR2MsM6H^M-GD^mvIKtaA&$5A2KmD1ZwhKmxwlh4v3%BGI;y%$o~p2{YBKFe z%#YU-woyPm)hXFpk}lIEQ{^4TkhG+JkVA2p@M6boSe*~A@93!9x7K){a!@lyYlFUl z8IfggsEmFAFA~K*JJCGUC)e=~cumpV4{t3Yzxb$7KrN>Ye;{DsqDv5>cC3XSA%Pn% zX(}`LUriwEZDc5xiGfCEjuKsKKH0f>96_7Hrc4k(Pq#p_KzQC%2+_Uu4z}Oh#Dr+q-YE^%~7mmrbLm-DUi6>xt0r zl_q`LBvr9-vd}p}DNssdJX@JLP=h0u{ zo3)?2m{m1<1sDGW+P0WBVXIf}%*TX50e?!oy8GMI#62H9J9^UNHc&n}WWTghnxGoY zEMz>l{?jTNrErAg6t)aLFv=P6H$fZ(5+n*$gX~#+0SvSX28U|r_vN!pSTmm-Vlj#H zDro}lpy;;(SNx_hM2r;S4A`8k;_Z@rtxr7fv)jrI0&TyRE}A8!3}-X{F1BsM(LuUs z(+CJjq`alm2%gb#Scv0Wu%MUUWqU+e$>g1sgAVCzOn{tz&U|#Qq3&~TU%-niw4Q>b z3%C3N{L^iFPg7=Bs`N*Gi^%G^+Rc|om01@rKBvc}Cg~=stnVv_FDvSNx^1~M;+A@8 z#*+io^`ZbRac^*Y2OD+YrNq3b9i5Q~g?_^1=(=87xwT3>(El9B>{%*-tCH_A@=6Y3veDN#*A`^P7@ zxF0)AVE`T%7}-qDFaSFg?x=zEA=Q=gvHs37TaBG_qx}cy`3E>yV`V0C;t6|EJ8;Xo z1Xg0GKA``iJQAOMtFE5^SrFYQhzs8o8qRSg@*iV!!Hn8x zVt4PPo;y0w^ITA@{kVuOCf4+`k24IoOV?sx#!Jif=7`_fuvbi+nDK&aJr&#Tw72t zX5;!^<}>5=iuEQe^P1@I>5qB*V5pAZHo~A~sIQ0-9gef{U z!o>(4fELRrc+!-WRkASbw<@2Z{hHS)`+O(0AmAmUlAw#Q5ih(jJuG8*1D5d4PFGin%@R{Uf+?Ph;G99MqXLaFKB#G+Dqf_Z-yW%V=fdZT+ zy>b?091BA+Op}0Gfz>_ZCC^Kp1y=Ux)+5aG?dVIL!VTF0^b>{jFy;&$)lB=&chL?2 z;A?_AisppWdu`)u4HkS)>3Yt~Mgn!96BRm=0HY)Nt_@|+Y0knydbK5W66J|NlDyNr z*SfJD)Sa6oH@Z_<@8n4sh?4#~HoJyK56H$X{CG36OL~Md&epC;&itlK)xyfA{6f)@ z=yXh{!?qS3#X4HBHw-ohhim+W{@2Y@nJ)D>p5e&A64UGq9@3)Nuglp*zH z@M>LjOk3U7Vo0)j?j88bRhht+H!=^1eF$jY86G*4mzGy+<3X-eQ?8M3y)YS(3S~RQ zgokT1HraFQ>1~(73Asm^gI(du(Xwo^NrV`_{F&K)6qgH+JUc3$H#k^7+PnXkUSj1= zD|$fGA~(X`#;v|neUbU3pJ*$>n@&zFqbMoBAzDTqvezxvZYu zKiS0lKOGrScD6uKXdX!JrO_ZS9${^Nea6E_{ofCM%VLsGQ>krXgn2a(lXq(}lGH9p{cg-t$f3ePcv0H0n@)(7B6xJ`vI{x&aXy z<&^z-VTt&?;F3d2CT=Y7sf2ZlzG4aIvNfM864XAX^4+kt)(uc9#pHQp? zyL*3%IJ%eK2w<-mS?u7`kBNdrh5x_?gdh|uWybl5oK7BE#|1zAd9U@HfgD1^mwG;G$UTJa2weij{gOLbGXL1m81)uK;{K#map3C-e}BZwScbHc zy_NMpm6v%8Mjv9+J>&^?36atDgClh-?lX`QrYjB$%-m*S?<4jr%o%f^4R^4BWb zq3%{NJ0mHPb(AqZx36?KDP37dY0ob6H(}6wfy=6a%Y2?nne%|X?yDXLlw|xqf5I~-_{NwUtUB0=?g7Tc`ZKQ0A=;=wjC|9i zFJE4qtg=~+UkmJ0Q(bo8$ z!eH6rZMCoq0@61-yzVXUUOxeO%F&$_qnc^y;FD2cnx1>tX)(OcI+lL67xs+gwdUdD zDHV|hjhfuezwEv8SAr*&su<0#({9GBR|73Sp@V3PB08%AbKdvge!b2m$tH^7dBg*b zpIOVZ^Owje^rXKiWM>>&r5VR_{pR8d-h!PyH;0<9OU8gWQXzU1JwHOPii$p1+23Z= zjE)H&>Y^rA(X-_L2wCWvNtX&aTM)Yd88srby->WPsW~~nADB0O<{U9Xs z4?tb;PG_R(oXhl%qWH-{>-ueGhm`Pjp1)}xf{1H7$a;=;@*_oX)w?+JXQ&x6n3vv^ z{yU=ZXYy;)+GL14VPBBbGRZd=YZpI^yO4Z#)5x(R%P-#p#H_K0x1Bo%#-cNMFyzuFIbLueFEVelV- zykud#>5ndgGl0xwShR1iO4LBj#)sZgTE3fC=Q52>ivglxYc!y*nkw{=dtE%K8Ra?m z>i}U$n`WdTAW9&rhi>AYh8&_iGQfXdSRF)dqW!DPt!bIR93|~(=?i#Gu{Eh8z)e-h zFKUnL+=t{_Q$=4MrF1;H(4HPSQsa9Nj`pi5Jx;=Vo#R4&=)zS3@8Kf^4EiG1I*%LW zCnX>;8yC%oY;?lYe@X>?)1jo03$>I#W8`oh*Z$1~8N^cGtf`yEmA!&Q()}+{B1x0_ z-4FpY9$%Of4Gzp%QnxLn(l$pkk&f1mLYr2krfgGEW@h*bglS)i7KU=QHp)*1d6lPd`L>Q}hq;(1vya2)dTRbBiDZa9QfK3B- zD3){DW=iAPUL5YiJoa2PVS?sj@7~n8_}g=hXVd=x$FnAXM>nqWYB#uVeDT@`P|2(0 znfkniH`(~6!lsX94|{uduaL#(GD~kOp5ep1nEczH{{SoIfA9>j&TNx^r|%gE)ZDL} zdhkAT*zcL&qjv78b3&~N*`TY;oVRkCpDN}j3Cp4?o^~&EKQG^lvY5HGz<;vZU&66h z6|3>y)OA$}GE2S}4Iiq%?`eFWPWXj)Qu_WIi-uc2{1#urX6=RW%^_Z5M(Y~)53pQ& z(R_oqJL2uXn{QhG0o)VTYJWE0i2eikC#?DWXK_qe%fDSrz!&3?Lge&+~Haujc=%{{M~q&)NUC{qNcOe~nJyyO8kz-ogE+`1T3@))C_egzNjX)^Wyv zcjdRvEFmVY@^R%4x8wK4avwD<-t5Izp7`|D?7kj-2&8%|cTvGmzujmcJ|0a#Wtr%f zX-Z`)6gfV%x ztU0elsbEo)^qv)()rtO$HAy0ex86=NR5lNOX(kiOJ!FLfXNp<3-hbDaaEZ2VwHmNH zYrTKFBtBzODn_KvK&I}=B_^m#ON_s?%PyCqA;0oTGs(!hmEa!bJNuM2)ncM<{WA53 z_$T<;_TSHy_}&bj4iRd~w>Alr%jL+C8@}89l&zSflKVwLE}k|;vP(>`oPZiq3V)f# z@UlGp=d6pm7sWeB_FY54F1z&AsEnLwin6s3OyW}x1+w~^a#Z}5Gz8o)p5 zKNsl;XB)do40WDykGe=X*hg$4kISL|rH}8SL<1^E12CRu_Edrb@;9K$q6fw(j3D{U4&fJ0Pj|`yUk* z9D%sg6bBBRXjT^Pjh2eI&5fp+X%o#Hhy!;juFAc$99d~mF5Hx5wykiNm4T+AqJ4RP zet-Pna{suOdwF>7dCob{d0ww`=CBPI61Qm$7|J3V3sxgrdZ${NbNh?c8yf;<>Q5&^ ztDdo2{O!^2$m*4o+Rvo8N!q%2EyG+SwP=-u`@B%XMSffD*^dG$I#o*rmcP*-==L|?HsXc13`ubUj1HHX4P|=A zk^=bk*+w!1=XuYp|C))VBB}0d)pn@>aYj3WD`mKLkvkNQ)pki7JcCF;dNO;u=2e7q zS||3^li5|zM&26d7-v}xk7hIa`xp?7gf8|5lByA_u`RX&Jealg4*=RI^g|c;vc4ZF zW2&eMfI|j6(;Hpa7u{s+$^7hC`Va#)eZniDRmxJk%#kftc$%%M$X{X8_Ya`VR^foy zNog307WdIgJ)cNnlx@G^@S~BQX$TCC{g-$~-&^z6n%rRsi!J&%+aBE9~aFp9!hmm_V3Q zAPk5AY)#ep7GgBFk67XK`dA5Np|~ZWf4z$_kc~80n*0Y~HYc%X+KsqfbJFtYFX_u67@TLguODBMhqu6w3om|Q88)EWzR9!KkGqCtfmoh$^q zPh^gq0~|M`q%h#*zN{q$`z}R6iHX3#(Tah*rX;>`cZQ9~1INaTdVCyt!j!Os7m2&F zfHhLBapHgGO~6p*$ofe)IEt!ZEOn*@+n0+;;b?8Q^(I0JtSO6J^~Kc|w+5$xUsIM` zGLi|J`mvH3BwET+e#!s-$G*AVLSmxX3!Y#}S8_{KIU}GkqSvp*%Bho>#T9Xj zTfNcfbqc0O&U%XAh6Oxok-0ptKkTflmxtd)5BOE zlyQxc{46G0ahae4!zsko0=cQ?}YliP?*z()T!BtY;&=i{mU z?B*LZIi@70oxyIG{7(RYxXsebX|vqYl^$trPU)dGV8)rV|&}P)^Yy;yl`_gNS}~i zM_4r40Np_Ia&19B!hBt88_6A@9DWQ}0ux}rw+kCEDgKdaDpmgg0AQiRd^7AVm`PHK zIu-?gC=Vhlu3)J;F#Xvkpsn{;00oY|Wrxbo7#@Hu?!y|u`Yfwa0en``u@SLlO(6Ot543tO$d*xc7h38q(ng837z#s0QfneXOAKN44=~u5X8ZpHQf3*~&X8#dm_vFJ z#l_xn8&85csJ_b%HU*?PDn;Lw^36QCLK{1!?6rX{_va-LEpJwY44Q(>oe!W*PumTN z;aBD}t9sK6s$n_aR8MFS8|*hmVRYb6WE6@{swyj)vyPV3>MwNomD2N=0=4zc3S@bQVTu+&;vqZ_ zN-z^{*HYdQyU4(PLIICP3Z)FqCrp`39l%#H4i4;qx9eLaPx-ht%3!7vyv~$Qu&ST4 z577eQ_))S(A(eNyTWZ`5oEqBHZ^U1$vB0n3?q^HGCnCaW8YKN5AD>pfel5{xtVDuz zKJ^};n5wT|_8s4585@W*5-DF+btgwNuyi@Hd>;@&0Q-ae-NlC(`|e0!JELPN)xjl; z0`ttu0b}dLhY4aXh%$#I;kB6U_OhijHwj`#?n#U3ARA?agiywK3czmpR$DM#q((-h z(1^g0lkOgc*k~mVH?SQQVZTI#l9L9vj+_WI% zf|f{73stUtLX}{piF`F-Cy_^{#d=BJjvAlNrwudvc;EZ7(;NvM$2!axwdP=pGRxNAH0O0u%-Y9&(nww zsyBz8x5NBz2##czE@^5|t@wEkdKPIgYjNT&Bx2_jAhl*5bjqcmu)&$6M$|?{k~?!U z6J*O8ydJ)x_>6vkQm6ke>j`O9{iXAlB%u@$jM9YakbI69wN?3^C|f{CE#wRS19HhV zM2Moljw>D%KtC*`$|O`EY#8iTQIyi5r5kQCH0mV6X+l9-k1Z{Ll&Y`|W3~%X7z!64 zbCO8Ue*p44b>?02K+pL}OZC(_61@f6NG<}aGNBggIjq8M42WDvzL0!mNM^#H+>A?c z{S*=oBhFU%%kn80#2>5YB&p*LlAo=|ERn6koi~?W z+%PHX)S*lbi*KBPO~F93&6SqC#uYay{u;p*rviu7UMcc^M!|`oEJc*Jwvw(v4$Zq} zZYm8oz=(Fl>q1MVE<(?aP@SZVWL>8y-Uj~wasjtkK0;8gTjYXa#%egYqGkSbPqqdjVWCicT8JVm?hoyIQB6i4oP>K^BC}ImhbVesb{*pBqL`p2)MO`)?508pcRfA>5mffmb@pW7@#ow z#O3RfA8DoO-US{Ab6|AKD`P-3`$8Is?U|g4Vgg&ru{E4l!BhqgB>+kH!_NCjC_tFz z6b2M-S+L4D>GwI@&6D!(ZS%%VBW8_S<- zIYR(DZn~n@8|NOLDSxLYEdBPJ<>Bg<5wE%^D|xusBb1G}BKV3|h!%8SD`h^Qr(Epm zh#1jl!rM9Bn?0ZSnpdBTjzsGelR(nYK|=9J2aQkLhKJ@1SJ99?6&!;9IpKh7C)SlY zq`50#d4 zNBL_CBM3ogInN7`vHk~8YarkWGhlyUt!HLZCa8VEB`XEVBT<}pknD{RX$j!@FPA-UJ$vIX z`lPUm)3`BE%ts>>cJU6$uT_&x{F-3RZKII-%xU8h6YQ%F2Y_ z6>=@1Xx<;qAkuvoLK6rWG$G3k%9hn8rW-cS79G z3r1Uq3{Pfuq+plWbf_8cL>n12=YVF*sD`JRBol^^+;2Q|BT2?1}o8O{Qah_y*)wmm3tnQZLjwz=d(X?VxYncwSVEcSr&=Ixq|5qAmbRXjfjWJkrsp(^B9G@+pZhY}@Wb1O|(9u1}jw-`m4ez`|* zBpmn9u5$AT9ZA2ki2WlUg)5WeGE!-=8jdv%LS=|$Y(roVzB)GAoo$6;xl0+RRg+ytb1d>R1NHTp zKxOma7a@FyX7z*#gCnkFl5C8J8*f2fvm;WZ45?3Z`rG+*UR%O?@sZX5@q)h;GSlhS z$QK|(Ie@GzL*hriODQv_R0$FIhAX8;GMmzJ>H{lJ5ECP%g`L#T=hj7>Kk^^piGeoA zEL@+rEJw_vhZK-K?3>nIxFmpUGZXIyo(qwOEudl#(Y?s8vNDD4ln*DK!SffszdNeG zZO@!|z^|RwY|BAWEDczLt04@v*g`!qicJZ8KFvz=ieIX1=`g9l)en{j_Xv^VQpozt z>;r~CGElT+X>YQHTo1bLb6(nCv1Pr%HSf|2T9AHNqRa?Tqfe?)#lgYb4_lr>M3k2o zqI%SVIHIy=N?~l%nq1tVe?qWPtAx&nxoJd-yhS-tHKh+aCGhY{O3ct?Adm-ABq82F< zY-b0rY3*Wq!L3>@kI!nbmak|+Dwc;);l*;zok#(?V2ka56CupOAO^I;nyv#;R$_n+ zk=*K%mx4DlA3e!wV_W)4`OP**`WmF9n4Q(`R9?J~^czyp^=5|oY6jcz>IW9tZ%Blh zfo8|GE6G)`Dc~!KNFBmagUNwyzQG0gh9FHj>^8eLadaJuRs?R0Y3qt$sowS@>tB?f zR1EUM+S0P>EqY@0!(vO?Y^9HC>;ITQ@d_V=)@m6{qr$UfOW+@bqx7@zx?|ayQr6Z3 z8YEO!qlhy4%f4jrI%0L{m6sv;ROV}aW43&>$a}|2R+&OUq_;R>wH?w&$3gMoNi|t( zP_peUf=$Q=$z{{%0iBxQ&Y*i&RN9+P6Js`v<4Jv3gAuwuP$V&XGg1< z0`Z_{94m)XnjW$K2}&>~x;#FBH0W3)6+HIvWs0WU%9xP^uTRCoxK;3Ix4#v)JwN0vzLF+KMFqpES4>=d${D**e2Ns@7!Cvq_!n4Y_f`nTnhaEaKc5nO zU@5b6=}a&Jk5@6tyd#;-XzsnLDAF#N2Adv_S(gTfU>A&?0^@#x8eQmO9!daeREP(#!gfA2K4``X2nUpb6mqTP*#eeT>B{q1WDOcm*zE8p^=@Dbii_v1dhe9Y%_(d9|OS9<_FD z^h+-+5U7rGw6Q&xEfF9z`kbJi#k%l*5JVr)&Ab;Tjv<|gNWL=SHIj`A0tjYdY^9}j z{Zw=oyB`c<_y zfZPmMI8u_4$t$F?kdb@;p*yXu$zMCtRooy4ms`j(B_=vRz^a9)I44tO0TCI?0>u-> z%ser^acmuMKze*x>Ea+PO>Ohb#%`lM=*!NGoA3ex%A4)e#JkeHT&^Tf-j68-)z zTuZy$u&yx$8CYVo{!BB4!`IKMJYi}M2O>p2awmQ)k6;T+Yu2IMYj7C-iK)IRJka!D z56i>T#2{a%KUEXknJ6n=*cpmDS3I&q-gUUZ7#8f;CkkjBvrv@~OW~iBW6qvqNXihJ zZ!|iwgJcS~%}4nwH3D^UEK4nHk9M_iubY#UY(!?8gp|N>Ceo*2-c{78Ap8)@Lwktl z;~^L8BK3i&?qC*{_A`raJ9l+nS52bMR5D7PZy?M%^FGQyVC$hW!nhaM zJn4|jv__O46+2e=r_P9yj&87yjt-K;W0)jy&;fUrzeX8ljv^bQ>q}#LNLZxs=8Up2 zwbmuf2?HuO8a!9doWOJ1Ni0vYdR~pl0fo~X-qH|DJ`m5m0^pE2IJ7789lMKpjdW)= zq$SodYm$lR=#3!gV+F?&ZZ3kXLzqQdFH4sj;*?Xt@InC*ba4uc`ee|Y-3RYGm^zby zH+Gg|epH?hdF5m;jiMBt=W}u#pQDZ(DYM>3c_EcxP{n}@3k*6HnhKaGPyi~?&e){| z<2x^~ddtfL2C4kA)}c{nWtuA^#RwLvuh}QqUxaw^;I<~Wg*j(lt-)0fQ_P1bdLyn; zv?MKoH$YEue$rx7a7GMe>lJRs`?5VZ4EF3=wcC8+rvZ@F01}5TWdzm$3(Psd=IYvE z((8UNt6@xz{*cmqy*_C81~<)gFbI-nTZvT9T9-bKZwvwU#!_UPE6vT}=FfzQS|m-{ zl_^QVv_|CtWeoFCiguQpNMj7k$-2dUUW47}ON%KObU=HMfE1QmK3AFaCZ2!Mdp?^W zwj|$HGfG}8Wm5b6dD(&k4h{k0gXOF$aKy#TXSEATj-Jd$)ui(Ot^nx=4wMQgIK%`F zWF#}C^ZJWS;brWkWX^99(4u2C?irP`{rteG6<>*{8t$@(wKY>rX>qDgigQ~h$-nJXMh5kr&Y8s{WK~Gz-eVcK?W^@ud zM+w5PSSKifW7aM0Rf9M+z}`fW`(@3c&3TU`Wj?ng;^{4cjS2<1;o&(KH42rW$rw2L zjZ6^h!a_#6mSpLw>RAxnZfL&zw`>?WLp)vuX)xf3Kc3vj>t6Uyr$-eW>ktMe2?;k_ zNFoBE#RHaBrKP1z6ZqrO65^_lkAnWDmZ`qKXiy@W7wh)i`JgS;>N&a%tv$rH8y(qm z9I$+uGU){0DP4sfs6K@_o?Og?nw5hv`x4D@y-EFG7xb(mpMYLwrd>i>pS0oue~ohG zG(%StmLkt71c#R%0KQKy`$KPuOi)2kkx)|IeD9fdfrzYdrc$pcm~zJiFqldIQhruf~mot#n6z0KlQppD6mcGNAao$)@{Js z+b$}9=-BLDf^CaCK8arnt$MV`+(vnF$ZpjVIpn4QkdCP9~t6*vT4rL4NOaK)Ha1wlM6 zWuhgM5y1%($&?Li5VXzOyx0(kgo;_y>aCH2#QGP0JRlJqrMQ^FG$fcI8rYs}P-V?` z$g(+Qk%Sb?ZG_^{!c3nqP}Zg)BRd&G#f;K|fr3#>eIm)9#deFo=PjS6H?{;}NBjkN zx&-DBI)14kEW)k2E|QWOkAQzNtW6} z*9{ZGd0)sRQTvPg9ik9nz?s<@FHCQQlYnwgW;g_$~;Z z1yp0AHB))F1q`YQkTioYa47KuL4=CFbVCNs2ADS#4o`e=bp$Hkw$3GxU`rEBdV@h@ z%%3Wmr*RGppp1jY_%o`#G*c*Fq$#U!p3<;WvI4X+AiAMpPJ$I$--dQHoc|C}B3M#wiBtkmWU5@Q6Et%+B~}Li=Ahk8 z6|F;FFC-}ctLUwF_a?5QXE;rk$g)TNNj-%56h{x1Ut$9h}I*5V#@8 zMZ07tCnxTAV4rOn9}*caytgO>mPU3wSHz@+8QV^OO|iEpR;0hOdjh~o0{)i!s%g&x z;emni8P*WDS9-Plq1D#2FaW?yo|YGtM%bl&2!?j+&v%oLf)ouM=X|B%F- z)9``ul+}cUM1{zSe*ku_=}vepUyGLsd}rfb3zJ#j#!f;KJv=<@6-C8Th1h+AzZP|hJ6vL1k}Yw?mlxaE z4GQ*xg_3NqcN1az*BrNVmTdYmy1TpO%}O^Zx$R|6WSBKC-!Piu?cn7=Hb^9|W?0t? zVr$pHt4gm-tedP&5XURq`MDp-1R)D{R)UhMI9IEb>;q7NUt_PcKl+Y4oN72;CCeR) zr~1+YfbA`t%#}yu3VB)!g2CIcOuJ%>)id;MHqAX`8ekC|y+4 zv!XduSR+->Gj)19z}G~Nwc3{=SZ|^vm<&CH+0-;OUN2qPK}W_)|6t#uQoE_tM}?oA zahuM#Kiu%q|F%sw$Y0^$1fdnBz2^4NeefC;Jnv!B@)GqYyYw6W#;sopnsMz()U$NN zIgY-nIa->5^>FJ?0w6I-?Cb3p3Jy(N<(UQ6H>Gf#Y#OTBweI2r(y2qie+d+hNki9% z@^Ys}-_g0HzG9-YY--)FlpjNlhb}xG)F`%A?(}a^`DIdbZ8AIiChM#B_sS~qHw*Fq z0F{q!I&`6A)(vH|zF}4=@7R*ROSyyKs@7~6fHWCi`ZW`pPdRBC`^ZuBe$V6T$4S3R?lG)04+STu`fSoi)8!aRu8<%Hx;duKTkNObe@{hU zGstXaB^(*3tLrYhoB8spVl|Jx^=cfy}GOMaC4+9dJpXOsPacP56@Z2$6amE=UK z@bEtX$2`>u*uI*OuXOM1@Eap`V#^y7*HbF>FFH8RQID^ae>vvRCoy=lNf_ChR_pqo zDJaGiV-PU1|9|c6zplWh)WK6F1yRg*tReHI><{D;;!i8i=2ubd2 zC$zwfjNW=)de-(VhkbvUB9zgI`gnciOE|Tshg;BfrN5+PpEu$DVwLJ&)KC0h{MO#& zRXvkJ4nI|B^vQs$b=?Tsa~*-XRX%WdlsPnHlKgXdzf+!hSVo!wqB;*-+f?3DhX zD}4L?x9d}NQk+(vL{6taw{o15y~kv1!Z5Xb;*zNhDaD4rPqKQB+4NTsB~{9BDBr4I zF%vl&u%`fX+qc~4ZaBHlh}@%+Bug|uetBF#4vRDNLW&CeDUQ2^=usrp!cf4gobx6^c;f{Z*?+;8_qb93HH<>L|_?@$$E z{X*l#<0`MR=QdZbcHFwN*jGPwZJpbNaN*N^>y8t97rkBEG)=>==+YIdb0w>QjiFcc zzCkbiUI4DVCgC{+Zhv_H0qlmo=rg=*dH(+W4O45=GG=L8+@qe1Oq0TG$9rM2o<|RL?N?_@e#qE7(EhzLyMA$-RLM79 z-=2A`%6Q{{8@G>HO6|FLJX%w8v0kLDiHk2mryDN($yYTEn5 z851u)vtedo5-|EH9=}<-vN!juDsBUR6+^MCv38aDS$tI^KXl7Ey!+Wy$6=upnA+^(c!9kaTs#aT1aZ1(5*RI}FuTG$&<9J}YD z`r7##?bDpcsT~@>F-|2lk2&diOui?>|0iS47cw474A2B*(1TGw%ide#@5DGJ;q-}E5v zvipHYYw=$PU|_rbS+lLVe}Hzg-&4Ew{{X~{{c*FOMf>qdqt3gbT>h!^F7O|q$9adl zujk^m;uUvazvWE%#20&r{!Y;r7(6?f<_ObCH=DX4unxJ?0^AzNQhS zq^^Y1t`*JDI}R`tmntjGXV|@%83>_r)%V1X3Wx4N~#1dfQnN; zAMw*GZ6?dGGr(oKbop57nff)spcJ*dwL^mZz&$Ro-Ny=s{k@arFSjLDaaodQ@ax5= z-caFftLe8vN%y1{elKj}HLmo#b8OaZk^(#Ff(WzjlbYTR>}ia9{YOPEQ0yrtOJErq zb>zCkqn9eHnUrTr>M5SZinB{;v1G#8#Z2i9m&p?mHHl-DRgX4LKwj;2Jf!%&448?u zOjO~Y`8*$Vo`dA~VG>I3T2#K1n0l4z2R_xg_X2RS>_I35)~@I17NHXxqi}I2FOKGA zZqk!|<D>j)mpvod`k zFAHo}(f@iMb-GGhTvn8cld!%t%P$g)6OnYu4f;hNkmBYV`shdq>0f;s=I(JX!#L$` zknMKH5&s#-uops5MDKTS__cd#n)SB~>{_c}O-FiK%c+o-Y<)kiBRZU}qN>-@ulI^L z$y~gA7w%e7f68~5;_ruuQnLra={_5`_#A%O36-yo|51%T-SEV@Bw=GYHGf}qEBwh0 zOM&*t=}|!aw))VYD#1;NxA)&97ZXl^=cWdWd%KB*fXt*n&ij!8`|AGymWSNlCN|am zA!z&q6fJR_Z?YJhquhn)_&znRV|65HHhk}4JY+d(qwnCQ{fqwqqe+=*T>t*(%AJi2 z<;1a)KGmcT8QJR!KH~u#>$S|1DiS7ti?U?-VYxMN?qx#PMMZjRHbl*CIY|D{PtJtR zi9ydl&;yCaNoyAm*`&@u)R&?(byA$`|Meb2s_VJ z;ni(p>wQD}OJ_UZ7}|HY25pO4dO?sN4i2vU>~7kF^kaG-UueWj14k|tzIxJE2dyu6 zOxtrx<$IvFZgCgz0Hp|ayVQB1nf6&bvG)BRDG1$9@^X(AqQj3r$wV#R-$JoI_6c91 z5C7yHE*m0xpP2u$*WQ1k%n6dL^8E93_FrC}Z|PnI&zm8%Ic#`&a(e>+ zvRGU|Q;9V@(DrVoE_PnpN_nn8W+rdKZN*vKc$oX!zQNP5p?`pzB+F$M0PmRT-EdG?u{@b`e+T~Q z@zqoC;lz;%PT_6XPsLw3&P8yu%OJ5I5H>~GikrwzFxli`2mH_TFrz4{OZdAAy-hch zDUE1;;)~U#9EtdfBW_Qg6U~gNeA6|OH^0NyIX$AHyB>k*tvjP>w-;95>nwX7x4XGh z@bvT3`hG8aF*?KJ1?+SCucfB%W$!wQP zLV2Ea0JCK#zHhx{M*f)udBgL!!}pk4_9%#i=638&V5@i{_Ks$nO(@=LRCvl)v_Kt$FUzN-eesz zTtaYZMEhe;Ro2O8{UZ7le7?76RquhrGgu3M{{afk*hQ|azSSH50K)=a^+PMS54g=c z?wkFV*H3g_)p^hP2cZ7?2bkMHC9(DfO+Q-%>>4zR^?g3jz6KfJg%bkEpZ057#Y7W5 zytu~BGh_vIMg0pJa$~2Co6Fky3M4paR=PhT?c|HHCo9X>93Bh~yXgD_nCDGR2fUW{ zWhZ@cP2?63sY(3defFiSc*CJU^>GAI7(X~WtB`O|i56E(;ZPN55vEYV)XPxc>IjB8@w%r>h($KCv}l zA4?l|RHV&(T{@Q3-DY+V$OZAJIcAUVGy=?A?{gHukNlI)@$8XRQtmHbZn3*rRrs9T zY2$^D*>^2n?>C#ZWf%j@XA{OwJr&W3cS)KMcglA)y zuiMdCfa?hvZz>9fmvFiDh71#zbMNt=I_rTuB8shgecZWrfHV0`b|Q#BW7BLo#tviM zfc%4dtTTLH>_N(W)y?F-1J2U{vNBC(Z)@2ehlTeHDu_$2#p_$3J1Pn(x027>_tC-u z-|B}YOk@#(zO$+g>dMmJE_Z1a{vK9@UhuTQHY83~%?P{ca}+nUZ=J%lTrNmLIUao@ zvagcl^^#JjTln&5H^=a4#w%mfg0?YgTThHVMWOEA!st=az3Mp6j=h^1_Pe>K6T|-j z_-}_VneDW3mE-7>tr~|Pe*RbTz|X>#70oaqV*Wj0fnPrV00rUu zhGx5C?Pjk`Tsq$^xI9zc*!MU3bZz?uC5^h0!q8Gxmzv|x z>~5wBoqu)MV#e55&MKxHJ8JVie`EaBF9)3H?-@anhhO;)y9-<2b8E2h9J?r7)LK!q z`dt6r=sBl^O~5%uwZczY)0xo@6W>Et#LVleXIZ1mcO-#zE!I2y(wewJN>q&wwrm*$Al7OV8sy|#7Tb$W<=cq&ZGf9hF)c~NxvMmXUJ5xLKHM0`$PdnjP zmn*C0)cO7aI>)sh?8T;0*4k+y*UwByZi^L|MPB)2$32y9{Npvz-*dOEDZn%{TIt*H zNz@w^`qC-{yr&%YW3R&}{EQgr?>yr0Bm2&ci>lOV;hhS$fW!v0)#w+vD1Ghyp2gjR zWi){S-$!D5mqRu}@0ec019Sw%+pZt6K)sWz2D>hu2)zgNq8a4}|t@eBKCtrn2e(VIouR%DL+ zn04crPfuM4acL60KEnH0mrEjYjqYoCE9~ zli1BFYwr<+ngs0T54dsYBbDs-nM7xMLxn3kW>0cUkGTYMaPQ4Mmjw<=D);*ghI#eT z%u}UHR;Bn(YWH8yNkB6mY=n8hSa+*W>kAIu0vAhs!z%5s><>Uzd%y25*_i~;`!eRy zig}k4Wq%|p`9G`sxR1DL!7e{xBJ$|!2a^vQ(sP^}NAl@+24J7qFCsZ+v+b!&J1&h$ z=7+$PQ}?;!5=JYBiv8*aIY8Z_pvz)sj?)`Ac6u&Z{{*bfeUPuO%>SzuC+7E#q4>!} zn5A&O-zJi9WK!8C{q@gC)dj5^TXQn|{YSP9^7w+ZitKY6qn_x^K0K5Bl<)6>OATEY ziNm?!YrbdW`<=^AOHnTUX_zrCxHY;c$;bH&P`HQuIw10A%JU*=p^Q%~q->;*fIo;3 zR`OmpJks!~j^D3H2jXVYz|Z>>C)A}s_wjpVS>N64*q>6XzCFjHM6VBJizgrc4XyKi z(A)3|h|o`(6KdrB_YhSjGNDGz}k{3L17QFnTS{{pCQtK)Fc{@DJ} z=ofa2b%x%RqOYa0FNf1l2q6wz=1Wq?{vN`99IJANdZpt+Uc=an6qnTbXW>n<&Zj^g z2eE5?=^7qCeRt|m*q>u*Rn}A<3aYQxJ@7DTcTzxq3bG|KVtKRzvtaE7f3`0mdlU5W z6K90?KFKW1mw1I=Px%0kG$cJ~rWkP9MH=(Qe}7W0p66tTl?woH03>FPiBG=D!(OYL z;yK6V?RvXFzfnXki$O(f+4*?R=o?qhGOF3^i*K2K6f?gR^a_uzHZ>~RZPBIwSiSOZ zntB|mG)fm!{C4Z(?J!zmfOmuE+~Gbz-Y@Z4MP{+}{hj3x&aD*e`qsec&zTYNlb;Oc zub&e8>sI7xp}3hzsCPTPueM@*dsifwC>R0sIEp)_$2c1OJ|tC6SM;i{CM5E$W=i&a zdO=v3;AT>Yq>P{t$k@=r*X$TjQ`|Fl_Qs(Ame|E5o5)`OM)%db+V6Wyj#VSu#LV%f zt~SZl&3a)zJNmWkwDN*ia?`Ea;k>B6hjV{SB+Rr0Pp8~zL`uDO6k0)+LXh`F8>K}b z`62&aCCN0Ma=GN`|KVzC8ad&-eSOW*_>PyZZPKrGpZKEOU%~1%Bafbgyyib%G7$Xd zfHJo7q~1Et-M6#ukG5u?4V;q$rd@U2nssmh2z_WX=~wDm6nx#S@D|X)Y@C0$yxM&B zdPdp6`{s`C-$In-tsmB2<0uGa;ZNbw886f25^yIH3zr8>rM09#7*GIAYWMm2m@HxU z+=xwIq1K`N&!mBH-m;Ra>)6s?WZyQ?uL($jehD6-r@bkTf6nh>=CNJxvQ1gCOCn0b zGt_gbncEX?V?yHZC5D~;xP06Op7d*O-1P3kwYg|qyKr*HN%(e(Qw`;g@1|f|Z6x*D zKR|0>hw1%Qcd1ouEF)mzDYnDd%91~s@tnpEck9d2uhJG%H=?8tl5O&z+GN(Wy0Q^enK$JR)ngP66_dl4%G-7l9b^pV z1?5a~5Sw_N)4iUYA|JlHZf9E8-FDLs-uNJT2CQgdD!nPsK4AK7sCRb1+?_rZ%N?D( zGv71rXuURtCTPxYPT~GoU)F-OY7R(k1hlO0(arw6nEEX__183s@A%CG$9^sS)z_~N zyu4=Uc=gk9c~d-Vdz$B`f|xqydeYBPNQdP~!CK>=36D!8lP2hr=kMH(h!qSd|IKMk zZ*QB3Sy?e22#!tt(NeUh%w2M^h|Xr@Ui6hUI&dST`0mB+GPk9P)1mJ%3a*sunq)o; zVgep<&AIp4$aSh@S!3m(aP=7*8^GI_i@VK#HKZp=f#XY64J}ns@_7o)cFwEEA=V4K za7<6+sRN!v@FDN}yrZ84;}3Mwl*|o8R4yqLK;Anl@_+{;vozO$F^Am$0Xz*Hr9S)t znPm%dIi2@;7q9cmJDeRr3G&F8eCnB*JiPV9kQ~oLtOgRg%)LC@hRE`ulAT#&or3nU z^6*C&z8j6pOlwuw{S4`k)qNSCZ0AyY&B{9$eBJQ@_b251MWSMUzw-d|Vnd2O~o2X18S^j3A_ub(#gR_hjRKy~DNSdgj z*zcrvJ7H1ip*pY!YkWr5B2nN;gSFQyq@?gG>3Hqu5r9t~YkZnUd8{ z%CD(O9-NFCeMCsj*_%+mr2FG(f4>O-{FraJ#=E}~2L={4+-fC|6rPszb=NT9iRo0u zGb1elGhY)f1EY*30%u%D zJUl0|^Y3;a+X=o6N&Nan#Ufm9X3kND=ZiFugS3@?6#<$pvN<~+t%4cZ}+(IlboKClM9z0jgylYCHan7x4eWc9;Bw#UyPNX zbgy7Ox)s=B^QjEOsdjgJ5ctdXgkwZ);)|tx7-sTX>G&ZZvzBvSkvYDrODwFc=*{nV ze%;4cE^5_@2uDHh2F2~YFu{MKaBHVJ24=Tf5apEbj&|d$wL$%VDTqO?e}9k^`YJ8`F7~q~Qh*?ego}*Jmdtyk)=ca_dc8nMkObF}cIi`?R6=_1Ddn z-QqZwi5czBRLl20F2I3DylPN=U)9az*0~nFxrF|mB<*AQpFqMhf)%&F)*e!15EuQw zDc_IqeTaO(<>_68dewY0qdy7=O-bEW}#GI?xO z+`#KIy(NidTZuRJ$<47_{{X52eTd2PG77Ca<46GFBpdmBzl1wEuj5RdP3rZ!`4|w=QtOwtlzXx^13;juZG(kztEnOCN8|o2!w_VX%Q@{A=C-;it!T#>bH(n81 zpf7{+o);o#dq#OcX0{GKI{MFd)7>#EJC0If&+9&v$V$mteG}}-RXSd1h{2@BEV@&M zZUg1{lv%nmS85bWSjUGg6uVR$?jE}`2! zvhYjV{1ZUmx32>Sbt?{;`%4fH!i28fQh5dIG*EJ`eYaGa%SErWOW9QF*{S{R6%PL# z))*ISSyyu2K1<}|w{L^@)aA32cj1paVjw$Kov}E+?_Q0_+Yvh%Jk~syvmeJ~Tc#U* zlp{X)9(h2%2Y*ZZsNHflh1hlJ%iU1TyvWqc$zoj+nh7k2Z35$&WrVPf^U6*$HC7rVihtqCn#&CEpI} zE*jc#azz481=9zY!IJx%gMb)P+3MM360lFG!S#7BXWKIUaG@dc5;CI6VUL{7zM!~% z*y@&!BfXdf2KcU^)NhE-%cxuXN+9)6B0-mh{XZ!!&&dTc6>)SlRSgX8D%2JNs=A4M zS(i*nTxO+?uBLG?={fo!hC2<|`XC~L;duCB00)bTexb2_=#b;XdcKVn5}S z{{YO_{1UDoX)@R3m2zeK{ii}9Q*Yt~8HD($mmsz718!@WO>jpPfG^l4NS#%kI>1h! zy`SuII$yu=o&Ny0`jj^Q)Bgay#CtF0{{S+(zd-)y%AfZtJlFY5c#G*}jz1Cf{DCw_ z*qm2=+(b^?ekD9B;XlMV)HqZKLzD8dkLX1mn_rB+kK7mk0GA8x_^5DK+j8B2iMd~x zuaol5hwI9!J_Gk3c#dJr*WAsEPn-8IaJVLG{e0jH55 z)jDS8>(;(p%{1xEO4n90Kw3mSFd-MReiFE*NlZt!3J|)*^288XsrIE4mLH&;)D%>P zw{Py?({NJ!3S!8n9S+cUeCPq%mvM3{CHzqfnQwoTAmY^qLFjVFjbb*L=Lw2+8yuX} zI}EHt;x|z?t+Ld}%iu>68RIW8w@OqlJwQu=Q&@30RwXj`4C-J-c@S0N8mK*qb%_2Y z7eNJDwjt7b637BWoM~Pjqu6u~QRWn{YlV{WziTF*2|#_alCtdA8rJxjPa7jIZ)dny zOO-A0anZW&=P~~PNhu^QFJ|lFV&0P%_=rZzgKyA{(8yJn)!v}gnKtXyrh_}TuS`PJ z?Fmn$zJhMVaUBxJWgf9EUOetPkLg-~TY`pCDd0J8L~zQ+s<`JBG&9{=9MWB}k)D9B z++}%Xu2ohC>|j=m5diA04YOrS@Fr8};Jp}?*SQDTOkghMOO@}oB^6lUJposSG~`P?vltCYHKhym<5{n1j*0R6bBM7+U6e@TdYZ@8Z&TOV0s z^FK?(QINv^#i($4*gs6%<}GhbO2II^J{Dp~<7oNeF(W9V?xxzdvo>BL9VVV%scpCb zS?e*;5NxvhDS(2b1dd$=qN4M9VITt;bMF|1jizi`V-d#|xYOmXT8mCYwA&AWT?lOo zO67)1^h(-o0@Ty<0Snz#+~1@w^k)A6#}cs?DQdk@mkK}uVEcjp02yEX6XE(w>-+Jq zU%Qvjd-xyakN*Hbp8o*IXQY|`0P8Wzeqr5TnP-&t{*dVXC(rqxC+;1u-1ff^>VAn+ zhEc`+%3t}VJ!i$^mkariuk9??*R%BR2fN;p15 zd*(hz^F2QkE!*|}*~CZSm2f^~SNm7`mFfBq`DL7bg!KK=S;P6BkKDR;GW)-%J)g** z0r@i~>GG*wev5x{*Z4swb#H`!P+#&d`GDB`r}-zN^nax6AB7&5@p)aJllvG83LgIe z#>~0=rz`uX%6b-G5&Ikc!utD&9goZWA;x{b+I%@y!5u*Ro}2K)Kz}LJ2fy^6==+_e z_97R^56oXLrUzH#Omh8hQQ7>$+ewa>@dGVM5w`7SpeD(MW?U{9iuSvLx>c*~AgXXI zOBi2Bg50hPyhlw%d_}0L)~J45M}mTfNGa@Cy=w$EB?l|9%H`S% zvALeRW<*$_=DE360k(|?yNk0nTL$x{VFYZpUs0_fqYhla(e_G~@ncXHEMtQC99J+i zl>h?t1k*B9zoihS<5g??l?|wX1vSRzWwHhR6NpT9;Au9ww5F{im0}+32G-TZR0Q|g z3*lW}Ir^j8wGCv(&U?NqlYu7Emc9UZEQS?ZF(DDT2KkDrb&ch}I1R ztAlobO3IcFw0#tfX(bo*HgPY3MWsi9r^5^kwzYb4u@|v<=N~fRfDNhdk~~*DHa=hh znouXY0%Ks#0ri{_MwEmjxt7&s245!lh0x&0Zn+eVv@A$lUd6bDw^$!b%uhk18|9ZP z8{smNlX#GU?PW_ytZPr8!$xVPIaKp2P%TD>RFsFTXhYhTgH|6Ay`ltk0DX)x$mxZ# z?+IB;EexMLz{{moGu6OxMiX`PMFDpI0Hqkla$V0})7ii?=q15ig?=P!1FZiAL7d z9063|e%1~kgwtrg3){~eeqp9_Koh)^6Whv*lnDS1LG2-_yEV^W>LsbBDqTAcYB`|v zhvZ=Aykx(0McY?trQZr*??P4uZ6i4U0763GMZm~WV5`Pb&}R1>ln8$@FxjR}8(=cH zaR6fK8lbi=KVPt*u=W$Zt}I=@+N{{Tq(KLlU!DivHf0S|97ul^zb0NQ1A z`wZzPw0{uj{FAgkiSYgiL@y`ifAF)r_nw#Y6Q}urO*~(TSx^s`^fB^+s0Dven(4`5 zou)^Rf2jaOQkuf|{eM_c--a;x0; z3;C4r{4&q_Cs9jv`$GJF6#oF}6aN5V2oAp@GyV{tXX1P>>RNO51gAfEXQTME9zRtj z{Qm%TIZXRU^*!hR035J%d}sl#J|EDD*nA|j{{Rf``Y{wg$RayGi+`v-2iY#uK0nD0 z&z_Iyk6r9z_Y~j9FYZ_LLI>(S{$)_+C$j$la6i)suRmY-rVKCt0FA);zFM6hn1>VU zFlT>|mxWQv>+>~~B?Br&mMr>~(x7uq3N>yCR)ZA2;#j)E8;MM50M=PF0<;Vg&;^;$ zuS&)i$HiDvR1jA4l?nq6@1h!Xt--CeFCg@$c8nIIq5^OYT9*qo5E*a4(&r39qU|Df z8UfgZYFDM})g8w~3cG`&glRz;*oq4R4W8x&*5eLeCx34~Z z)C5;7n~tZN(qV2e0RSGU#4MqFsfgA<^iHLdLHS-+6HYOYc3~X=>1{yDP*Bt?KeB|qK3S@U_Q_B7HITh(S}1Ge%#s59Xd8en?GP)@Z&gmBaOu^$k{=CH^hM z3vTx?=2uF9djVQN)7+vj8bfbcnQ!&Ax=LW7o2)G#w^3&=o24Ga&~~9Yvz7{}FIU5w zaTQ*GFDu#Z8srA^$i|Q?-B-2?+*<^+HZ?gR);#c0c^GWEiL!Eum!5)Z(y1sMZW9_d z(Vgg3dW*PiV6URrF!uzoD0M^yBAO{v-LbX0AknZs{{Zh12mGMJ>1IubK$YF+GJ{so zK%5`*{^goa#8>`7J`cvF-M_isKR@bK72f`5y88bBbK`u{P(XSI$(4WUXQ)Ek`~q}a z=qFqG$A98WJ)r78aNz#Y}2>c&4ANkz7 z{y4s`^w0inMd3bWM$hN`QlIK2>G`kimuu^i-M^eW4BhAKxTAu6xA^b(4vIYxr`Y-b z0EmC|AGQI(4kdjPx&HtM`GvS2Kj0^$^BLX!kS%_SA1~DF{{RTLZTbHI6x_Gx{F9~r zzqoV%0Pyrq3+%DyKbwDX!i(>IJrgE#{{Wpcm_4wAA0R_$mAd%hEBzB;_$^=kM`?ff zaSun+6=!I{c<(Wy3E~%gwfjL3s!_snyeL7kQn^kffFfBOHrs0D)k6lixOxS|qAk)7 zawh?NLdO7;;Jc*u51^^4Hq@z?kk~^$-P~!CM8W4rK^IK8Hud{R4b@eOU`*{fu?U5i zcJ`1JL365Apf@Q>7J$^<%nH?FuJVTTp_a&?{9Uo_B=b0fq2-3T0Zffpvou0cp>s*5 zGc99)a?5FX?3lc?g}7MeaQFn<^aNNihzJgp+_Iwx0tER#Y8$xq zEH)7E;6XjRa1L1M+bFzo+YJ}xfe*Ef;_a#IT&I^B6my%amSjR75~9bz)#1!7lE9=H zf#qVwZ4vkgCDQP*a0(hC7o#u0M-13{3N97IMfD_xvxD{!C7l(2VExK2fzo8atEqTa zlm&FUSwI}+ez;8fj<@4tJXXx!CjiAh?}$BkYX`yNSn5hQo`JGeLn(OtF)d0CE=HS& zG~xV8xSm~@F_muXh=c*4eoEZvVxS*K`C#4Dmq6_^5jB|-OLw?UeQvG@bz-1iRpw;& z-^@B}X~um_fftbf0BQ&rVUbb!U}!IR_#qQO36^>xC@y}tv?QZ%GrkJ z?$+*b8W!%+CM!@^irPCFjP>kYz+Bv_d;6Gqu2t*_haJ}ESY}`}AyvOh; z@}*wr!P8i`NccdONxIBa)utxF)Va` zKivF&W_^BV{{S16{{R{Bp9JDw-4{zef1GAe=!DGT(^y$>jvnEvUgf9Xfe~K+0C1n| zpW>8wzj5jN*?zdW!1xIN0HUdPf4Gk?PNs!c7G7pFT}suj4dDKZ}dxb z^pZXA+x*IZ_#h1j%75$$uhqZe4clYHMUcK&RrNpxjU|%ceO;a(bps{9C-NDe`D7OU zbR%!p+3ow{Q@_1%E&XP3 zz$_~8GM%#koVH`0KD8}fm9>tAst#otW3@v#V$!P#v)1V=`tBBMRs~r=sinqCUnT}D zY6Uzc6e{v%Kc)`~J{T!Q!&QN5ahwpnXf`zLG0}jT-<(C9xn+oyaNCyV&Etz0ExS-W!_bw(k(j2%yD>HGv7fo!cyww?$S@Cji( z2H|46<)+vo*C|H88e7?@9sYr2zb8yw8U;%g-d5UM0*Jccw>X5|KoeKYVv_(MpIpW> z>IQ`~B?4tbiVj#j)?EEvIFEs?Dp}C;3{4p)HSpmfd_6urW)*;O-Mez3T$%N$XL&)>|kD;n}& zskB%*Vpzgr3k?HoOI`Xtl&!(BPe8!f;?VH8w5frt@<1jQh3Oed47W~<@c;|_A<`*W zP>Yw|mMtORLmkmLp#Y)ojZ5AHE5A?#VZ|StD-~DkE8BR?VNV6ua?bN46|YNBbeX$P zkPsHfE^XEo8*CfPuW5q?)LR#~63IU83KDJsRSZr60i3PNoXcq>v6)v9m8lsZzf2+2 zW4L>!G%CEXC(i4sT(fFe*EMWb=~}jhYP*%Pxk7>LmJl1&2jGt>U!CXFr*O?toVLOq z(s(dbeh9|Urz5r*lL4)pN>F>N^a*+L#n2E?a2O?<{n(D}pAqv@J^qr8WsezsQsdD4 zAiIJ804jg+RJXVCl>-7wysze1T|c<#E*UR^=i#57=(Z4L`?W zSeER8To1u-sDaK&YP(ZI4iN=p1CATGx-=-wQrObUsGtMC)+OxXbe*F(wHvTbWraUzMtDVzghnP+$9GPuR-W82(q-IegMTg z{l|cR6Q}h?-|;WEM|){j;O{w=nB^f2uo!(!Z#`?rwhAb)U7$)Sp5R6!*S082Fzvie*mA+8nJ-2q#o`NEkX5$h8{gDBipfyIsVjLFNC^@#cgP;=Y zqe_gD`$FtK$1?O-7=g>Cn7fGnL>G0`c2p|eg&NB*Z)F#2>B3kJjEAsY%7bB2fS5}6 z+bO!-VJfvRz1{#iL)eymwG6F$NnpAq>ngqgbi^RStqxAmgjEAn%6rUtp=IR9eISKA z0N=@fsBLCIfsNMKj)(wX@AMEEBBTdy4Kon6G8FgjD7e;zExUzN@s0eLjKR!sd?=Tc z%4z9|dmCN9WGPjQ)X-eUqR=w2%ha*_;ZS;bs7uqSSw@(f77Ju!>Row2Yw@Sa5AJ0R z)SjS{0;PFw!(7J=$X)mCjS79L5NkwAUS2S846@vRLO>$Aii}P9M?$V;xyMn z^d;t*RWG#37g^Yc=S!3xw6}rLU~mb8Ps*Wh%Y*P{I(9{0nT(?0WG_RO2bpEgzAoY% z8%$5qBMxVZxAnL|jJxFakb|RHTXcMwgM71N_C$&nvr@N6GA+LmP0G4e&DVQiU?o8S zIaFr!%nMlNp^#8HNq&YFlWT^*LK;g6{yly_j+KYH1)pAPp&0jIQEM_&q;kQ29 z1wl}YfRVbuR|+z1gKYWCxL#mFuh7)BI2FkQf~qpap+FbMxH?y1nsN6mhDGgOHnmeU z2198CuD7<@Ji)HORhO)~OMsc6onSPV4-7W!-IkQEohV}4rExBoUvRI*+_-FHB^ax` z)E>k~YC~NIH*(PfbS*9FURzn|oYid?*V&cW{Y&@tDega0rr%KDk?TJ&Np-4+wSkAz zVC#0VjJvVkMGXX4RiMST;v1-UslIq6(!eh2sqDbj*^1h_dO)8I08P``j{~wLUt-F* zx;SY8+t})4vrH!=sIoQ^S=A>AK6CxBMQ7Xn({VuAW48il>XbmOwn`_+3a8^R?mq+| z+WmyR3GIU71uCe1E~lwJgZrGO`CsunV0wb`85-e=_v)rbA`r<%DW${%+zgFsY_Q&f zT%nFVLF19xvIGE1;g-S*+gm_=gtH440}$JeAZpqTri+ZYy6Ban#+av|HK*mq2!#jO zejxw`QCy+U;OfN@$mPuvlVOg)4+ie8Br6+~h!+GTSk}N{j!NzxiiLI_1UfV>P9}t3 zQ5xsp0SPNsLf!E)?h0(ibSJiXfqzBLJ0QvEm(MBvFW1Q%~E zGTsJc?~ULyniAF&!dlGxEkq9{hMkb6=yF_fQm5*Qk9Ng%74YQ;>kunn3Q=xi1Z``z zjS^gLLYUO&_IY4~I1X5GN8W$fNzOxU7BJPJD9^$Iutr1(>mD)OA zswz4k0~0`gmBLaUYVxxxhK;2rvRllkO_OQ#OQAz%E*C(ROl7(}5qHEsrwDQnFwg+u zVkSti0}MDZNBfsERJrKf=R~$&h08pbEt!9;HyeM1*E zd4;WmfXm{g@^;Ph2Qjw)03lGgx0)FmrJL;HFrzvgDfJ0gQ};ocU1koe#dAGZ18RGs zXRf#dqbZpEffm@Khi0NfjxHhOL%2hrgDzI719`*}VYXP<_BEM*5!V1NomI?$c_j;> z5~V&%kOLfrH4tF?97oRI6H$3fZK~9aqjKrF{z*V^40z7smZ-&VRUNN)F5RUGTgQT^ zeVMOt6y7h8b*d~8a7EGfUG7mD;RRdaQj9N9F+v6?C~WCO}ub4%+bhTtC7hBZXD}kqjaE*^{j*r4S!t*8oI_X>Q#69^zh1^507MmQYd> zow~j+4610!vh#J!b1BO8V_=!ff>CA`HrZL=%Tc&QObp&p(&FO^5&*eV$ks}{A|Wow zJHs3sW@v0Kwt0lH%5LJf?( zb*jXum4V~o3xlwL6#yegK%-<+jdN+0T`=G)mKW4in!0!z`A0bw9-A#_?$JJn2(?@x z`=|-HUW@G92V_%pU~h=3RLnntt|JR(1C~4tlc;)2^)3yS`A3nL+$i*;ie-sH3WNX_ z3<}8%_g)AMt?RaHFkvGj5gZ}7(qAp1z``BYR3L7#aZV^z6NZJiq9(k|ROlO6Lglo` zHm#%sO|A&#lH7N%Mz2(tMUap)?LJ{*$GBW9B@*Z04ko|A&=6hOY=-S zD`OO13t)yPA^WCX?n1|OfN;vi zz#4U0Mi@hNkJ`WUr!nQR~`jJxIgg21wEG2#LM1@LA2l**H9xFKf+BXq}xs#cX8A2Q5eY7pg# zfss=3x(l!NMP-%+0oG;8!g7EI{H)wnzic2|B|Q3%4j#fF6W#>AmgVZJ#2A$aVPq8v zj&Cc$YU6OGCENH3a$VJPI!0=<69T^Uh;dDCf4QAJXn*Na;dWuC`DI`6P}P>0Iq_t& zeKYDI#9+N$BAwL0Z|Sq*&_-!M%ks4@1O}2w&|uJbgD)wwFD&Ik1R=xzA&B4@17!x1 zQkKw}X;1XSSc571G?lva21!nq`@{N&Py$Oxcibv%5Hb!%^>WZC4TcK$8Y@ij0JH&X z9g)Ol16-n@!mr~kbTdBmDyU-;*$9ZNSPL0Z_8}w&P7PbTq6IX~*zEBr08*uBF8x$I zwBs-YM5Z?NQvR57Xk=54K`6-yVRpN30WkOo3kM5idg59_MK`mJ#%pQFMcR9mx6oPG ztP+u()bAvtq^YqwK`SYei`>8f2Sy_wf_7|?VY4jzGL&;+z%52n zXCG`z7b`h_SRHkDgYJg@Os1bptgm=od#LCdX3p|sv)taVwioY+If2U;!!p{JEkc;h zuGN$nm?fv}34?Hp1G3B++%qmP2sPd_8K|}1Ry{K@{fei!6sd~=-&VJ+OoTEa^D&+Cp`4d35J4GiVvWG zSTsWiD1<;SHR!a!29R9h>n=Iiw4Byid#GKW(BKRZrB{q)^#1@XWk3Sz=)Pb*c2>OC z7f@qi7X#7rGsxyjEac$D%X%Zk;bcI$aW`(&OchhbK70OJ7sz~_>xKT z&sIzn4vi)7`ZNL@9R@|O=dR+bO;UbKV|WI@88)yCO66F55i+VMvY$-rTMK@zh}8o# zNzo-S%N&2m)y;a%4TIB&@*%a``7tSOIX?zSxJznN`eOsVRU>is!CHM=5_YA(kX|Ne zM|J*}DU$Nyej(=hR9Lx>f??kI*)Y3h_Yp!`D5+9Gu-7UuMIKg*v%Mo{! zDG)-6V2=`jOj1LL?#7}>L8tr(p^EKm=HLW>E@B7cfAU()#1#{_N9_SKtW?+}n+7ww zB|x?Nh0j|9_#)TCPe6&36U^sg0=*7CM{Rwzz8GyO*H^z-WoG()2`{)oeK$&^DCR8tHQ4fXAU zw*7hWU;%?`jR&Kx%TYE^Y(dEvL0J29iFHQtQm1)pq3~^} z%u3!$>io+9XfzKc-vw$s5qTJ-*@RLMNLm`S;P%Wlf|$1007J(E4YNhcF|sD7L0h(U z9K{Zx#j6I%LM1CwjnSMT6cQ2&XbbyYB&0wISoSzBIqdb>et#@VsNUEd-=mm_-~kSJ z%@YNiQ0YEM!KQaa%~#fWBDE+tb#n6r2&cnnd_cb5~Q(YNRF4?RKJDt#Ps~c z^i9h5`hx;G0DdKdmG;pR^HS^Cz74UqX_alSGzTnV1+~5EV!8y@A|O=!B8hC5y>U{(6FXyl2x@r6m4jH!w926TLW@mTLuR&mLndgE zL!9>*J=oX6jLm?j&wDvDj9ZALm! zobxl}OZxmXKgGp|-k{u_Wl#vK(~Ez^;upq#?S%G&1?YN}F&zi{BG6}wS@i`hMZ4qe zm`MX6p!`bLW|0NATb#Jj%b#++a!XbS7~CaM)B+EqpWIpbFebHB#=hgUud~ z1B#iA>&jiwnHY&Qhl=U8qT62B13Mp$877e|2%gi^DJ1Q*&sd2a~AeO?&0bYKR zI03uezVE2X*r|g`%euJb>Vn|>@`1LDn08NU^h($4Ej_UW6dGExl-dNb2zio%BWQvm zPoqNX3T!2^;40|#t^z7m2Tm2WZWxhdo#!=o9XefdX_mgVrm0BJaOOeYeh*5Obc#1){)m>XK5Dc)U68r|`v5NI(2}BU5Vz$L}CnON1oy(QEtI8tNQf2)-k>ry{b49Q6WJofm7)cbGg- z+f{qKPNtFPT#Ts-qgRU%22fkT4zIYh6d$N9Mc1xymjINutgYl?vXn%s&8FRuGh@0< z(?@8xstc6*5cUvGVeFo!U7>*ZU~6A*`i@9MX9a2nScL#yA&P*=;NbV%0aQ+f3Mx>u zxsl&Q>GqHJa1Im%AoZ;KuH~5*RCHM1%LqB7zJp(ECqSCOX^BZ-urxB0=BS11RU9xV zf4I0Y4ywlAXHZF|Dz1sVm|;cW zqIKOzBrQgb0XM&G%3WF8)UDxC*Jo_oVPr7*{Zisk#Wug9Qqc7pO># zn22Z%Mw}#&9zq-RVZpoF zR}Aj2c+HElgmJoJ?m0~bMF3VkUK)ov992Jc4+LCUr{_>-1+*Z3j;22jjbFr|^=mhi z)T;Y1eVT??vNBfG&Zeq!_wy=^ z*A!Em@(_^*610GEQ4(6ya!Isu}7uTSG$rmFj5%^j&_rl(l7O zLcc6}2xG2>_4WeT;x`LO+$=FD4e}=Xa{*L`AbzE#Bg2R0Fd^w}I?@n6ok{`YGcoEH z-X&e7^G2dI@dEv#Hj$dV{{V}KqjA>f;Fnt0zGp9RWz4F!%W#Vg8NLr_EMhTOTg}!W z=D~u354cZI#M_$2iM;a#>u96)wG#tJ5>P~dK#QAf46i`%0<*fBSVUi$G!8^8z(w-h5|a zc9)1CqMw`&buOb|S2Ucl>Y|EQO5~`30|eD$M5cu1uj!kQMg~<6&lr@b*lb4kyROM+ zX>VzHD)7`a#ZW0nwm##lhg2iXa-^=BI&oLAnVmYdS}zKQV?bSAN1aN2T`vO}a-n4t zGg*ynP2%VR?4+yF6w`}#wR9>G?;u5HmV^g@H8nR5lo?oV06-NOp$q{mf{tGU6v?8u z%Ntzs84hXG0v0IyIqi2c-mya78_U~ zHXhh66oE*)wBiU{S+_OI?8jfFs{wSrLL<3qDLa$s(KDC;Ra{@1kJ&*S^{UQ&L#~98 z$hznIA#iF`8^}FwY1?`Yo!oaKZFezL?`IBLK_gpeZ9V#6%MFyvSI@+IyEUt=KFn;G zu-dn3oagIW_5*x`#ef2w4*d{ey)ZMZ>@Y1rFbo5t5=i#IIG);tw;w53f*vafSEvra zEhqy+)MJBQY;(jU6C$&ts3w%$rVA!qyKAVesl+ zb#dJ}!6>v4URvUy5mC@YrZ41h$E1kPvr>KnHPVrss8JyT3#znBEUKJ(*UUx?7;?Hl zGLZl)G8d9;<_fR%X3wdl+h{gM+7y=oq<)y468$rqYWoRku-evNJP0t;)(!%jX(I_x z##cPF%5B=~d}a4&6kv=ecFXsO2{#6aH{=6Ft#;AoOqWtl>pE%Am@-#juU{hFvd)`O~Uh* z5dNXJTnkv3#BMs^plqdH399{J8Jeqz9S|nx=!aW(YocFUa0&&ym>R-BOLb#&A-u9Z zthsNrV}1hAejuzgf+m5`OOt9g1^UTx$6DX6uO>5T7M6Dg*f;|Uy@Y4nF#r|cUA2fu z;FF@l)?(9$-XpTyL@{5)56w7~cVP}@Owv9p+^TtaU-^{+*C{a3AEZzj?7Je}QIJ4x z3fpHrZagn$2>$?aX*Dl5#v-1mCYRtKEzt)mQC?ECY%lY*D-Bb)byRsv(8g0@d$4%aWk&O!zb~enM8Ubm$jJ&0;W4i=M6M zh{Z}G7uZ3QV!-`Nxoi>e61)at$mC+ULco&{SS<@oHZhl$V%nJCPc@+|1d(;f4pp=M zgcW>Li` zaEKe~&Ga2dY)vl{ZdFO$*w`Z4 z;$+W3it3QExQ=i^7 ztWehgUg{bFZUMHqSyL*C9Mfv~SS6zmX5WFz#hU`yQ-ls`EmgIefTh$r)FYXz>WS+M zCWA&3$v=Xu;<{x_Om8zHB$`9iV7E+7gN~7ft|1p;6COr1iw=$h>5fmZnny= zWdX-e?6(uk(8kSR#2*%OO>h!rpsSs7C=wAYmoC?|IDm2RsB^fLuodZkQPHV#k0d{1 zoLM%v4pQ3SJ&5!dV{W;?a~aH$?Zc3oH8gpWY6lGRMVn`ctBYO;_=X#I0-XbbVe0Pp zpq4>$*+6$ogAKL<_=U8`I(9Y%&64QDHhMA*vg_)KA(At2EJpQ{i9yDQ2!Wu-j)1Sp zaPVjnsK&7RKSVa0DAD5TtF}I1s+@W&Hw$<_K&LShwyM_hmMSI%!&<)uMMFxFQ;;!n zLE*^B7I2OUe;{pXd=|>L)S(4#$2A4|L|B## z{cvRf%G5yDYM=&PnSvPzcU+K;NC-Y|n9XH7U=^XPOVEd6TNe)fFr&1Foo2FQnEs45 z)3U3HJqR>3Qke3kj`gVI`6Zz%W{^_aZLxp_Xd9*6sjcdBzQn?tsA}%}Af*eXmo}to z0Hj2YRcZ@AAmJ+8eS~pX7i_`_7)`8DR~L=JHiF9-ITWd0@T~H*_(bgyeN^K1BCPTB zROMHHEE>tCfSrM+-9<5pQEfJ4Bk(05V_4(FKWa7yhBpL5*KW^+iq9TEEAY?v(U|8! zzzW|+h^~~?lT6Ji`lzdc$iX6!xB7V@geZFj`Gs^C&Sq3?sAC0I>nGGWilv!+QcAj& zm4SY$F8~-`Pp0Ksn!+WMQ?5#5*60cy|}06ANsbb$L|KeGXDgfPQxQ$WId1Rx(o zBlhP4KZ%ZClB_;p3e;4Rj<0d@0TH!6C?$f9a#kg>D`}F?Ip4TuC}zhWP9k2+^qoN( zfL64gj{t;PpGM&h)6;99ltTt!V%)4`K7_ln>Qo(4?p&!>IG3R%J^176EHEMcZf`nCGDY;L@x!*rE~$3RUFlfp2!lPT=k%*)EEw4;KW! z4j5|sHaXcW<$(!9@H>bXERqTkbjxnnKd`w1nq-($2AU zH6_%{d#p;58*bwHq?BBp5q@etI;gaAKdE2=5gVtoE<1n}h0R6kyG3by)s$8pB9);o z+$r>iOzRBOw4i>OWq(_hSZSg8mEzFQayejkaG`C5v?-y498sgE5CEDKb&UZ}Iiw|s zJB5JTg2}Emk=vam4%uuL>m?QRvi8ehlb;LJzQ-a4X#lc0?MJ4V^&c=LHEgED0djBN zAdHCUJe4Z$AUw*`ed_L6UhPVc2TrO9v|%hSZDTNB32GT?!pfdVZ?t!dS*)=XhdACG z;yRS4NKf!)Ea));_wgG{7F~vaDSx`oqgRIt+^>E1wU8w>h{n1pDU4Pgj^epV02f~@ zwFk>eHICx8!JA!k5W2@hmCY~k>Jp{FfIz%9#ROT8pf}0HG>O{+I!oz=6i9Sp?Fwm5 zS7bzOB2-zHjX=OtbMk2yi-RBms8P+5h~D_U#U-GyREv?8>Djyr;=ok32-w!k3u5Ll zP{RHSs}C@(hLBrtxW(^7N%)lz47%{%Z12=kqEs*gSKAQWDkGX#(Y%ti`Zt54xO`qB z=pZKP$57cTUqS5pWt_^s>;mTB#BR`L{jF;+*@0H-1=6s!ytw^-r8Si~D;4frnFBT7 z%x+g8vwNwg1;;Pkz}96|uN3Ak>Y7|KodW9bzOw>b!N~5~gA`aEQM)Fkl_*URbwU$_ zvDvDi4hZc6w15|)k?bokfuCb3H4I6Me4nVL!(`hFibbtl2{9u;ZUI5L5Lod2U>n^fHDkA8k9`FvqhT zppc3Ss>RX)4v%iiYvU2Va1`k*#?G^Akq*`cwwGRqQh-Pc(8?w0hjInN)lv$~dJPSG z3u-md1z(kVrJ%O1u#7d1a=uI~foi#$c_^x7Ia`p;pdmPMW%b`*X|a%{M?s@JK>9c# zvz|8-fC{sDx|)x(cc#Mgldsx7nB$iVX@B2WJR>7en*$16~57-7^G-nd!cVH zNd`Re1Ca+2=I+q=ONoP{vj|xH0WHi^VHz}c@AA0vjGYa|D(q!S{-+5406CmU?f(GG zXsxD*vmn?@GFyW-4!1i$A!t8l@IOencgH^ghF|{x^2nwW=XK2XK*YA#ZhvWgwdVjI z5m!Tw$cTvg8xLeS6`P^{staJwFZ;Q21C_&Z1S-|_4+isb6+$@L5QD^u*EfKdPOu7o z7SsnlWsCPOMAx$ALAbS`FW@m723jt@qEbcBGOOCM%tgX}!b~i^2kgS&B3gD9+OsHo zf~vkLDOgK92N`9cY#V~oEia-RBnsQ9#S8mpV=cr#f`vsAt$I=-1$Q>CalT?5bFy3Q z{zMvyx#S%0)M&)fbL)n3+*>ZbOkFcrv9q(Zsu>hbm(JjJ&CpZwT-18A{Pqgs@CO8{ zvrh9E3pE0vy@cIpeWOt$5FFo*6%Ac=DE3=_7cNLt8*gQh5CuD)$~m|Ropr5M>K|(o zil`M_cDR(B%DZ2r76omWF081BN^X%Y`MFBrw*x%fM=;4a__0#)D*(&yBNJm5DCZ|7 z*#b4`nPZz0j%G-eNI5F?DK%7x4X8_QA^7CZ(t#gI24#utTIZEawzk6&bOtMe6&6wG zII9I(G-@csEKs?@dV|db*p7Wsm|9jxP1#svBaiaLDit)kWvMd?X|S^IvZaxH$u(7D zqRIyVSgln98Y+AYZmQdPg|}gt2e?qMNoE=bvXOqQVk4ev!x0W#>MKFIgmZc2WTW<2 z*vmDw&2U0qUWS?SuTg2Rq?EAR;O3X;m%q(&wN3_8p^92)?ghv7*5J@GGwC1e;BEN6@zW^-zXeRrJxRYOvR`~?igs| zq2mx*7B8r)Y)Zn3LZyF+V2uJ6p?ks~RCmJhEAmxkvh@t*fK%$(bt+o4oKu^X+=i2r z>qsQPFLY1F=5nJ>m-nex5-7d`>+UYl6dg6GwpB%&m34qiFr3}{je8>VI)!R^KlQm&&AU8N>s{?`vMiC4zjahkZ*hNZA!L zftaWZNs}3_j1a0m&*Tci2r*OhDDlslC5JB74XfOJRn~DXf(F1|eM3?Wj)ePxFsC+J zFs*GHQ>&<>p`2*^kZX}Pz;jp2FRfEVMUo!qcNTO0anR+oB@0G}iitG+S8$j4#aPw7 zD+rn{afNtW=*HYMHFYJTDt=W6-@B>5-7sLgL810@D%czLVm{bersx%LWd}=9(z_5m z04%-GxwdCaAfv9o zZ}SSrGNoU%fYoynPVp^sSzux;s|l(A_lWSM(gMSfP>(=jslnOXI-A1TQs!$(Wl{pr zl`|vu$8x1(CWKtW;E0gpYhyF1hB4>_h+Dm^k725tYXO4`j8Zp^x|9N5bDF+A6KFAG zDZtDRAjNDn8a>O?YfmQqYM(H2mk8cjufZAYv}uCWsW{!G#|tbxfz8V068H>liEN?*-~$(=DkO&qVG9jaW>I=J^2HLu+b=BICkPGR=Fru`V*?&EEk*}Rpn{Ex zT5{YGrFAe4)q0VwGI!j@Q-zy=?jooa^Q^SBjDXbe> zSIIbXzj5CD7%&5dj0* zxMAwMf_6$^xy`s0&arq``FzSXLb7dZpY;V;9IdXuWK3Q~X4e zI0EcwTg5`0R5Wa{mDV7pOVMTcHBz6$QsKbUo9-)u>NS6pGC<^wyy06W!~s?>b;3l5 z*tHjYzv>zTVpyNnBB4UIc9I%`o&99kg11OfW?y3)P&GvP{90 zN>J}Dz%G!rKY?VS(M-|8mkLeT;Nc?PY}0LfvL5&9mpv6ILy8F8-y4})J_WxsCw3PG zIH_M`0hDjtw5He@knFPe?odb=qXxahU=-W_pnCum->a?qC z7H(GJw55zv%Yt<*xW7Udfd*@hzX-Je zmX0wBc$+;>6VXl0)Cm7Rr(2B1$#FGopE;s7#td?ilxzbCP@w;4fAl*ax`QI zEe~)T#5k7pua*GxXfKO_3zH#kkCtcpO({OtGPDkasQkgU;8?Fc%+e~Y(Cu|oDP5aC z=A#_PODy=8!ziOP;h_;MpfZ}#284~hMJ^aCK)+Q1qzeJrt*QVP+?LjJRiYh8Ot#ju zZneeY3v%I5eOZ~u0cGVSvgXpvx)bX$x(@xpy$rD!rZ6p@eqs*Ft-oa{w15nKA4KCxlTrxnB#{)#)iZm zCIYpSPBYzK%&A-zX|8V<^BW)~jw1JznFO$**V+&Y!j=MSfeXng01DGL^Y<9$hw>v~Glm2UX5R~pb@Jvqa0N`OFJ@!bL( zZi2Heo)^_bSM3$YHFr^!g9|i<>;oOM7@%U{nXDE(yNFB04n)HGAu4qOLl#UKmD3tP z0_dqd@XH$lx|w4^xPZzr#)G~EdRcI`HLFv9>NLwQR~K3NmrgBfs@lfkBAtV$I|$t` z6%B-6ZIBcKEndQ!!2^v{pcE?_1<4pJG->Rj<%xuN7NDaDq0U7S^gS?U;Il0YL4pt^&>2}yL6Mr8D4z2kMaPsIQ$v7(V{6W0obtNhO#3v}8%Oson8tyZ zw?4U-_q7z_wUy^B2-96{Vcr0vookBdmJJ0N$(?1EY=UWQVg`Y2lx&zN=G{&@kfYFZ z>L@KiF0~GX;E&6^1Y0cBhIqWe9_!AH;T_W2v!|h#u>cfkxtME53h`3Zt6fTd_btBV zuzg0<;un|bB;g>Z9{m~)34Nf}aqWtSJVmgY1gs};YR6Om0HNWRD%nec_NUaXqOe>$ zHM6^x2x&G&tmGy&y0&YTT>53CF;`Y`d}3TvputyxVm@ufk6l$;7nd#SE&j;aRF;DM z3jrlk-JLwt1Zy<1K(*=Mr@33ig;ZYzc9@y!i>?-H1-<_OscvvF=y0)1pqLdrO2RYM zYZQ@m*H0|^Hy41?8^dys`);AxyI08h0za*~=YYnJ*|p$BKZ7Lj@ivzeXd5h0{NKI3oBCMu^w z9Fwg4f+N#s(De$putck5V!W-a91KN1_=7c666z|bIs?!}0u&e*zGZ%}Zm#=6xgcBs z*(L4jwW-Gd?q#WvbKav6zCj2$rc~Wxi1d>-N~z}@Tn4$pmr&|B7OC;f003d;{Yw2i z4rLvl#nhlIbSxbS$8*Dbzfc z4PvS_VVAgkW>CT>dzNmRS^Y*_7rNZ#5!wF$VRM>Y54b(Q8fp8K<7updK&rtC=0-O0 z1T+^amT#GGf*-8?MW(Al?RLSeXX@5v3(>dnh}bM#nIWoOfXCS?8-Z)l?-AQU>fh8Q zLj=}WDm#rO!i@Z4C}sZfQryAVb5lKmRjs|7SY&G{s!L`pw%UV?p)S#L4_&Zv1Od7N z@cU(GC6q(E1`4gx#btJ|htg5~fyK(|DwLNt*L}jPOF8$q$Wj}rhPNneac^}&eQfaayR(N)b%i*_$= zcZImB_HTo#69CX^x}vK=g{u^{vd(fo+9CzyK|WC0{gBkl#%&zbL|TyE(*j|EeE6uv za!#rQ#mNg}kU(|RjMW@8GTp<)K&l}$Alw58N)D*cS6(vlXRaCa1yz@ufCM{q+%ps?o)6;)W@97E?orZ#hI;mp1P zxQAu|w80l+i$=N0tP^3-4v|9Fh+z2-3%mhJBv3ZFcZrt;u`X)c%ty!uL5m4TfxFMU?b`~RSW?k_ z1PQLq6cu(KsD&1&(6X?U(h8ZIeao7A0a89AW!D-|>HHAr%W~=ZkKhxO=2-i}uf#U&a#Gf_4zMJkwpr8OoW{{T}COc>h+p^3WN5u#PY zV)Z*CnpI?SzM)lW3&i`2N*7sP3W|u+$T@ATU(|->cIU`Jkn{IDie> zePi^7YBgf}3{z|zC;2;>D1xY5+8i)r3KvUmj&GRHrkQK3DJl%&TCEf`q$l0LqFa6f zBjmEHO-2J!)m;J15eYGm&{3l;F~St`f%UYDgx{$3+rc91g-u2F8Zzavp^u`G5J{!} z#bRPlNzL3QA=}GU<)me?d@6m33Y>F_Y59ruQ9*anb2Dmi{0TB8VQW4UQOZjM)hNxyVnjmlR~=GYkfP>TChVS%-q%JN<zKq}Q9GoI6;1_Z8?i)+$ z3Li4)5qYhAOyZeljIdfBi9}(?M6p_ZMw-PeRl@_2tNyhSVD2+9jR8Uuy3`S4_i!f* zP6FoW3iQX;U{)HnKpoMdW!x9BT@tnmsu1;qEX{0G3_dM^a~eZbJp>ACVt{p#)UBX| z8(WUm6W)Q88_t8MSUv&rw{Ti1t4cc#&`R4Vpc)E@3b001>k%3P(q7JEvaG67oJQMT zT8gCZS%p?z4`&2#LJ+P++fY^WtvnTkL}>snoT~^KsvVYH6`gSehRVz*^-u&608}55 zb1qtv39p!8pSs7dlLMAhAupZr_K`l!*1#_K!7zl??f@*HhEc+ssxa;dbvvWN7#D-& zjWD}wN;68;r>M-XAj=Enyt|ACI5!H&v0wBwqM8{#Oybixs=I6mkh(w(DW`IaL=Tk+ zz>09P=!6(5p-I@)4jqI@UdWZ%s)SG_D?(6F+(Gc{Yz5HRZUMkrngCR-Fw_bnOR_jR zrVy)jG!Jxk$ggDL4#}5OEj6W#V1@SIB8O{-Ji&7Tx=7XlGNRstvaBrwg5|R zcMow|v{v(UOrK#EtmsIpiX}?KE*4cIyhDme6F_ZQUuXsNloe9K_OQf9maZH4bPzT6 z9ib}D_bUBhR8h^E9Y-H!J8{!>H53D5?8#|dW0@&oYkrA^muS+9;>k=Ng13hk7S!|{ zw*XrzmMO+|63IbC&U#>0x{AEHLg8SOye4%oIuU6QtD z>JeSnY8hUMk)@wY%K$c2xK^-0$8;Q5ugt2XCE^{M;8s^>!V%>nkQIn8^ibq_QIYmX zJiv*|PET_JG;%bi52h~UH=Q#nB|=rF5SR`FuW4WyirjJTS!YgV+rk&D>bGacq9G5N z%orpS5FAsFnRFTkMlH7xs$u{iqE(&A+Xj<~h=gf0*D;WWAlt5^5da1M0CJ2n%C)_9 zElw)Hv^e-<5u+`te&w+wSz7Ixaq*6q8`Vq0Ia&wQxA#FOvi-vXwg##0q9q0Y0G0Iv z6*4&+%i<8EeFXHC)UH_4$Ap=!XjABwSaslSc%uoR1}Fu!JcM%MPU5x_QrCi>-#)D377L~ z)%GZ?0h&rYI4q(z4RHY|b+Gs#ATAYp3R?(VJ1}2lRAU$QCAuYLuew+F>Q+)3Wbi4h zL~L(X)qOy%7M5N^#I0anItOp`nG(xd1^x90VK(O{iXW+0V-0Q!kWdcK>FyhuoNnKS zJ*&i24vSX)2*wsyF>=YX24H!x&2ETo*9sM^(WoXiqGTAx2q35~*k6E#OLR#6M(VQ7 zi4nzS_QE0yI2X?gMq>a|PDm#g)$VFcPK@PjWre3qQBDKqjtQK&(|HCiqYm~te&D;f zY2_~Fb7rjGW(whmOpSzTXz5=pX|Bd0G0}5H`Y{zxMZprNEwPyiqOFQ^!3P`?q5@lH z^L!D3rt#y+Pjkt?aYji{_PNU|aikcQv8}6tT&=@PE~kr9pNb`Dc3EneT)9gQ zq}Sr+P*e-o(yVBPHLtZ&oVo)H6cvDXb&1Ahc=HMeCSR9{cJXSK8)|G2{N_frZR!f7 zU8$Bqc&K$tUuFwgR2%6ySuXXA)W`O%R_$WkODr}AhjT5o6oq&A?iv~rR;^xKH!XM& zpstu%Pn9?TKky<#(kdJZA+7|qfU$7Jl|UGS%X(QKbp;gFxmBz80$MITtE-mtV6Lov z)-T1umJ+fHc1NKRGTif7h`^oWvuFpUFbASQ>AE?6%PC%gaI@(sjzw3@{MO)n;wC|x zwMCiwZG(Z*HwlH3tO3mtR6A-AUR)7i(5Fie;c~{*Xjyx$5tfpjlZE_6sIUduVuvKm zvw{h(RIIJyCa9o}xZf*mQ#^1S^L1{BZ6~*Yd%orSnpY8m(xi+|%8~}S3k`%&SJv)ZlsIipjK4wyNY-O!LD>c1d z8^Lb*msHTIGTPr~7Yvr==v_jt3VWIS!IOY{W0?5H1O|gv+Z-1qT${sE;o4uW?h7c6 zXDa$-L6Qy`iHu6Sz8I5#65DUYdh&wefb{M)&UlL}(zQ7OmC4t08%n4v(O#p87}Rj@ zf*M(%6Vp!W1t4Zhxi7Bgvy+-AWdJl^5vRFqq1#mf)kfE_)-^Bpc*I-TmL)leFddf* zXbVAP`kK*Th5jmABy-G_7@2avbVMqcZk64!tLnKf`SlPt5$NR*c{mGgV<~*g54O@* z*%Yqc#j@bgeS|ICt+)U#t(L7Yil%7ue|345IxH6b700DfP^tl; z5U*Lo4BZX_U>mYy1yy5@#0xwaMxOKiOQP|-B@RemFpX75aQptUIez7a)m2SZb)n_APvyXFpTCR?ukltSeh9NV1DAJ2#mUHPF6Srf(o_Bu4r)tqjyBSm4WwH4ZHMZ7V58< zl&`YZ0BF5HBmgaBiZ#HHwi-rN0ajh*Y;-hc$io2EDrM^E5iYRdjY>DZDBYamIxB`1 zL+mj=7&LXCkV{jj9OYS~a`8$)(KXVToB*_BG=C8nQXsqukYPhQs!eX`i%pgqP;0yT zEH!XU8LY1KyaGq8$ogOgxS@lE9#Z4U$|}@kSdde!OG`ye+Dgc=8yq`VoQ%}7JqeL; z(L@;1C&unvp!@+gMLNGA%U%qJH%CQ+^MPyvprz{JC1#GBlD3xG1y)HN<$fy8Y zqfQ{_18f?Hbs0fu9bNH}GTdDUFNs7N1k!MTPJ)|j__8z`ZtZ2TdWQtKW5}#`K#S1> zJX*A58|DY*%>d)fS1B{G=5EArx9%;#0|MVgX>}G5T|*YIELGgWpsits>?)OJf|#Nv z&0gog^A*av2DUFh5OG4?8%fjvF?DuI9g@pFy~-7fdoXO+`sviZOwCzCOY+6U#UDwJ@g^W3(lOhHdkvb6jMxtKcz{{Uz(ai+mf za~h|Clvo2w3xkO`3koZ!5E|)dAWj;AEeS}@B{F%EsN($*tk&U^lJ@q-PS%=F#-$Vi zXu|7p=u90)?E^QNZ)7*|7NiR;Tk`QPxe;!~XK9I2FWbA-6&hY#D5C1 zmn9jxH8S#HKt4@~ftus}fJ(?v`aNeoA#%ew)#}xl(+pu{!I^f!++Kf9C1$`V8T73D zz!;_Y3mXszL~vogL*g}3ig1ZYU92j&Mc_I;#5P0PDHMz%3fZKI)PYis6BP*>y5?(QLm-k7TG+0a~ig1QzQUuZ4h)Q1d`h zrvupJW2}TlpvZ%iVY8AoS7qHWvj;1z%Vqw^84yTSnnyQ!V;mk1!=@S=f-L~{8YsZEf;?%W7d`AdtpNuDw7d=}>N*(|CEE|E4%sZW zX8vj=fnvB1_IDSppabYSB^dxV8Yy&2S(Qvz0N{qD&^^7HKJuYZNBLn3W25AQ;5u}K;?Z<(gJ2nl{#)4aadgJSRB+-?gB?R zWSb$>RqLOQqf3%B$Z}w@Pym&=(WdLs3C)@$qJN{92EyjmFlocwy9C6}18Vq=9*n#u z0=rm>JI3m?p{Ej{qOLQ^Jo|*j%h+*GZxKjA#cBOA%RyF-0JyF_#uSUV4|9}S0Xv7E zO~E79wcgf`VnY$G)NOg@WX6W=V_M8Bw6NWJx{C_fnx@#;h%FIrbW!>b@;c;~-4_w= zhOvrb8oRO1mN=Mg<&pB#uU9?i@W4s7jxOq0_@%_7Ug1T+(Rja<>-OI4eVdPa4lLC} zAaZJoc8(zRf%qXrOrWlsD|_rgu^uj^1t&*80|F13ipS9rLckSRa~!+2iog-GC^C(V zTH(sO_}suAB5kp4i{4C=m5c{g-awjeRzP#<-X&UNtT22rz1_8p_)3nvn~&OxVVWV) zN82e#2BlwQVip@^zbvY37h<0^e-NOeozv(+gSHq8G+z&Sg(|S$>~9q@Av6B~!*NTQ zcvfD|2)*DLBOG(L9#?D<&p~+Iz$P&%F9+DL^D&*Sw6#m5{3rvk#sxNo%kBzLncTme z!1u!p)aHh{+xH6)-7ZqB(3>yRe`csR_ArC8{?g*s(W|fQ6A$oiNbMx?gZqF8Z#mD* zT4;Q&^+90Zny6IwXp9uokJ|}Zu1vCE3hveV8j5egX|JiYK5_@-j+738QvpdyHX=P0 za5qM9i}}>sC_ES=!78moF9q$25m(ZGsEq+z60`2*u|2q7(I_`1=x;Hn9-M>wh}iuo z{{T|%9XdPeTp}`F@9CKe^jd)GF$4!TDe46mKz0@Z?X?kG*D~2x&0Rzj>TQb@od)fdRP9#adr7SYtYRPh+RDwr zla|;GnvD{`T3py}W7*k>>ecZsP#_k7yP_jHA(ArNR8wD|h9JCnaImpYQ**|_L1$}h z017KlBN+q}g(_0)-Wq_XlVmHJWNKQpz6ID_Y5)KirJ=iRftN1vzf1PF3q^3ge>1K= z&R=aoY^AdxJ69BzGEik>0>ew^)!cy=s$_u82C3x4N7}uw+a*vy zGF0Hr$(*H%4j&k@P<~T9Baw#O(A&K7u_~)d*c%0KT%?MUZ7#Vk#-Z1eY*m+ykSh|OUG#=iU zadvT_@ZKE9+zqkmQl~Mjg+OT?S23=jFA~OqN=mpn9_hx)Ft`x6>6Q9N5(8zkY=u3< zpf_~<(@?6QTBgxGsjDmSe{8=kn;O52MdLVvjQ3E`R{*g3=_<^(z`ttXTP^WlQP}JT zt#M<5WO}sd{{TC>0xAo$2M{=}<{nEbFt*;R;0VYBfYWU10dHd5r^HmdP-y6m372`7 zA?ac8mY+bV$5|k@iW@c9?l~s1U6TP#Kl9zqJq-cttGy-C2VaD)yl)7Ew;s? zUrNCWm1}0U2peh_o=yBqrPtWKx!=r?LcQ_eL+tQr!PY?P_6(`CAHw{@vy7mZb#rw%Ea;iBS$n6YiT zfpR+l9=j5iOcRUDP25H9z$?3;V@zCC1$>*qG8|L5LCWQ@#?~}){{RGX%*dC)k%*O= zsE&7@Zn>3eje4N`5~ybzD-Wh3EE=G>_9K8exqjZ^TvpB+5>$gxwyTx%6AqdyN2O9+ zpkiDibS<-(uVU0(e&wi3!WhTIq1J$Sg`iVo>6R!V1;|sYfNZbn%|uLq{{WR2Ih<-i z5ANwlRm4?$Ll#SLcPW%nvHcSLK4!rG00gt0Gh!cXF}FIVlkqiLrZ5k-a{EChSRt$k zvGEMM&D`2y?8SPIQQTehI!m&0mRs`b5?HWMA7pv~JMnm2>&HA9^u}f+gj=F%<^n>MwbYztlPm+a&}61%iKq zEWxfTe~8Y56aAADY=!+Bf!Bp)Z>-`RzdVQ2Gu_HP7{&D&->Sq4vn5*o!8Coae_~fY z;0NattQRO~{6&8*O8SeO#mb)}8ml&PLu#gqj>2F>4ZNBqvutBA?TnDdmcE&l&Bj=# zv1_?x_riokZEec?wPnRy-Bdo%)mCZx?jyI;B-8*yF*qocn^?u0GJj~q;KW3vTLuiWe!TB;J>t0R64w>HwJbf zKHAA1{+A<-{&-~rrwo?e8!@efj>@xy&!GY`A(%Pd%8cr)29^5e5m+IIx~9?=| z(5OKw{uZ>_Tsggv83#gR)XBytI_tt&qEblx4Ll@FBS4K z^X-4ef?xQk{t~T(Bg{ zmQ+w(1|<}5j8&GfK5m%zT(%As;uiX70Odx?V_CIK7U{i?YA}WcY-Q-ioW?3iqcx<( zc*krt?tuo%uRKc_J9SFl9m*X|aJL}1uX~9eOsYJIx`}ipp_~^@df6+)xK6Bzgic?r z%OVp< z%KbqpJ#CfCi$aY*@&H38_5gRnPJcZQt_-83MBz=g}7N-!xE>KyNEHU zeXR!1f{1{)%{M`GJH5+1t5Z4-OFOO}VloNRHlGK3FR@z)_Whyt|C5 z*u!gPfSX_7%T`iiABn%FZBUh(PU1eGku0y>34FKK6(ef8D&NzMO-z$n<|{+ zm@uZB4k|XcnH@WYs^f~8PVi>4VWszFT=xLR55>m{S8Qq*SEdianfMhJFqu83%UbEF zPzsmOI~2BCT%*s#TeNdgO;EbC7>=0yh=gn#5?~N%G5SEr?aiV1Ws6mV^6Zp`AZScS zjzkuR)}>0q;cn6BKwd{5gmL?U{@$Smv>6@kR$-K9KLE=iNyyP>+sQl-c*xtSD?* zym%-UaJ|jOXOM%q^P* z^YfEE$YQbaZO7Lv5-N8QU|5v^v84VPe3!?5?<64JuEM_%;8)6hhUL{(c|WDN7&Uj8 zsVOt5|Da>E0wfs;bhda2zEa4EWV1~QAAf6EJzwO0>^xZujG zqB6<$5L2#4s8&=hC=Z~P=?^tJx-O+%F<7SgrF(+hoyQ5fV7pz80qI=CqujMZ-K=_6 zSTewuTT88c;%QSsu05Y}A6;x;DDjw1s)4+5MTvz3ib_F7WK z898!6i~=3H43au;C02WZB7tV*7WOOjN+s2$G$t=NHAH)bKs-gjE=vJOn7m#>k%C^8 z=v7n58a=Ej2?a~f$7yPvQAP6h%d`>}??I$p(w^pOBZWDx6(*Q20q9E;>Dl=v;VEGZgg|`W95jLHW_t#dlNk^vble2G!~8gE$*b4xB05f^SKzS(ZRKn8{0E zE-Wh!V-El~TxG!s22bo3$e^ZLLN5gL!khqHE7~YwQQa}aV>PTp6D?B|^d|u6iirGN=e>H*Rvmvq=YeOLP*BrZDD)bH+G`y_3RPqo`U02lE$X%}3jm*A~nI z(FO}FT&*6Xd?X^v#7SuqroxAza|04#3s@+A5%QyNWk9|Qc18(!bt=mz_=}*WMursT zpoeY6>7E4(_-7VqP}0?S=)(gG5UX4qJwUd24@OKlm9(|2kSm60edZvfMF%CldxygS zEgW*py~qk*=oqhmVMA;H9jYS0cTuIF!Q||L1ty0B(<}yNo6(pG1G-EzD^;*z`5}*~ zl8TS6AU$+$WAV7UJ?z=|nUyBM+U_EZ$XYbkW22S7l%u6-^DI@aAN!3~M`f}3mX1k< z?p(w?CLMKua9YE+P?GG`Y;y^)M|_=p%?WXY{P8b~Mbd?j^(wFpSB|F)E)dbwRhqb0 zZR#dlNvb*DBq(+SGmXV^ioQO>d8mrnxnqXnMA#m_6`8EQ4-a=U_u8+@Iv#wlrXWre zL-5bHrk_gG6ck-NiRqQ1>wwf2X9It1MPm49Uj|hDR#f^VP-l}V+Bz+ms9$@SRnO96 zP(e2;z8%G|<(fSd)i;KRq1}37jn_&)dK-4`hv?YDAT&h$kjwB}6n&EKcV?-lQG?$a%@9|CT0b(tqsHI3GEFk%y;P`k z03W!pja}YDsx%XuYi-(#m;8rox91R;K;T?oyJ6S^tfF~dj9Kx-bW=(StKs)BAiqjY z>)Mp={YrwIWgUk-N6Hci|_qZvP9Sw_@?DG9hwJT zprWvvNnP?V^-XblrXPVBVNbDDQ zeGjRBL{t@A`kY%0Qdx8_J*7)G1P7%GKG-`L?5=AD*NLQVB9r7>3qlI=p?TC`*Q=oT zLEs}R?iCBH^867us1yRe6y5F#48kqT7g23$ja6KaD=d%#j(RR3E%2}%RzvdTWA%!l zK`RzR<~)|IIZCiA0NUk^PA+0jtPl=QeXP2KaD`Kvcb;I>&|G4G9kl`Bp(@<1Vt^TV zAtvR?{DPVw_ZKYNi0bW_IH18)3V16_XVg#c0PI58D2~PowC^<%47de=_ykuf=AUT% zuHdwIEWBP;lh}bLL99?hk}6;;P`#lGqTtr?TH|IGmBexuEUxm!C{uJy8`~I+5-Bw1 z;xA>Fia~NR#HeC~z`CL)cAy4TTs%vpQtei^*?rCC3GV2*VTVCSIy120cPJt?w;n9Z z3r*68qiW+g2oH0Eznq5Pb(wKqy*f%(WS0n5P0^ar#6d1(<27-fJKqC%zonRZkgKPG z=J|!}Nh*phYU))b3JlR{Oz|3l9CQ_h&%HtxW4pMoZd-`su#E;LMuqn;bVV``tAxSG zIT$rUs5xun)Nx|O@%DZue?+*vr^PS`48NjN*gQv*5XUCX6Gio(pNWG<*sG&QawiHS+W@q)UL zb9;mAm!@R#hkVTi7Gb~6=2Q?{ZJ^mAeZdSAl_ZQD(>!(Z#_UF!W1_2{b4#tf2LbDKPw_Ol1 ztu!%x)NVP2#7~ki3z`KRI*mv*c&FkfvTBrZMxfshAYFbcBo!HtDajhfFyva4PJ`M1 z0J63$cYC;Y=WkW%W2)x}{uqP=8_`RNS{_vQ_a9fJF1d!4hh-kR2s;%|*nVK<8`_oi z8UlG5$@s)2v>}=Ce8Og(6=$(Hl*!G-!O9V+LT0H#)bZJ)VY`y)wMLFGBn;DRt=asAP8k%}EV%LP!zGBfHefLp=09}|9zGogusy*c_$ zN|XVUe!7j2$!$~dHL+D|JHEKjjdWe0Xsd1lU_lyV;g^gC@Fpq_);|S)H5jbV064|N zx){e?%~a4;Hw8eBi{?X3Xt-elfyDN~H$dZ>&{e3|I<~E!QRhsLEZsoC7w~<-g%raM z99b0_lGGcZ!3+6YFz%|<2nkjTm~t%=-{l0QIi}xpYDSKj_+XW}Q~*|S-8zOVD!Y=+ z(Z~X#kL<7}z71Z3-U2Qvx0G|}ffRGBDd?)cVySD82OzAZ$R9Lb)`^xZ%CMKVxW0&! zO6$vkVoLbAc~33Z7&8S`xND#WFQI`6>nK#LhHd!7ZEqD?`W*Z)p3$PYO3i?1tP%1C zCBW#~!tns)R|bvQZA39D!Y;CpbSCE;g|J^Ks+3`6c37cHd<-ZCh^;lhP8tZl6{f>? z+P?ZTAmKP@4Wa143O14^YtBb5NPq*49I{>G0}z7bf~;-1Gh1Tk8yID4%mT$TXAOtL zDx#l4m!w5rVC-6ZzP-2X2hxhz#5KGfzn~%QBTE^f?9SFv<^avbWoxeV7Crg zctev#qeeQFt`$MDY>esIw9s_XyIO=GqZKXcv^UDI!*ry?+VFP3Fb1@DQT3*Q#j{Or zU&Oe&6M@6c$_`PbKQGk0^C~f2R%LJz?z|rGs_~WXw+f7`w5FJ|++=7_-HhYhQgLT0 z@uP4(kp{5Z_Y#KK1)K5vmIx`fq;HQ$5OHs?7T&BJv1>+>nXiOKOoU?37VU@_fn|xp z_b;Bvx@IA<-=IrCq)8C8A%s|?)DMYo+d#t2^DaY@E`{IfG`Qz@DhK9bVW4Py1w2bV zD4act)Q&6zianO@)<-Qu~KHE`uOc~XiHHFsb(_iz?3Oz}S- z!Drhv#F(i1n*cWwW(9|nRr-Z{D`MPKWHeS^2`;4uHLtT18hz~1)+b!d{{SJF2)9*l ztCURxKA_azsvn0jTe*iKQabiENEVEWt}2GY;RLC!&VOXw5xReAl&_~T_vu4^!6jtl zGh1z2{ex`Apo?2DtFY?t{oZB>1-SU!QKf!jEBh3F;?SYROL2m5dNU9KYO_P_m-I9P zJZ!|tlOM4gvvgfA2#>B9dtJ@F;2KOW#x+>zLGhx#mwO=Axsajyy~lVaax?WQ3s#U- zKMv-{y;%6_r5!@T%RRFi419w4#ha;-TNUB@V)7*d(EEz}CaGz6Q!MI0LyqWK%!|&3 zDrGS@8V5(Xa3u{KC2m9;#Y_!g#W=ZKy>IXPJt_lw(!T;4MG?uqx^k?`8HV5sIv^c| zDC{k)ZOod+b?*_`0Qe(OHjP=pJ8gzuKyEhJOu8d`Q6O^TEoU(F;3GqIlSmI`*i?$IPeqnJe9MWp zKW7}2L9yZ#tQ$yj!*)387Tyl7*-wfD+LDdLvYZK|ji)g{&uz*kr~rgyv)aUjCXPW( zjk|;yA!Ru(t6j#K6%vDG52Tph6(N%Qac^vB;06OjLIDtC(3(chOLkfZ6%2_eL!U-S zegbE-_KQ{4quf;_0fq~pmzTc$uuEFYY%oRAR05tvU>wxP0d|_q!EY;CSou<*LA9w+ z{N;oZMQ*_xV$|MNUrTG|Ftwgge|choRD#i?xK&_0WFdutxPf6sve7y0H3xvVa`vVQ zG+oAVdp?n-8!pi~50TboR)Sgzdvz2UsBVY~8VrTjnQl=?3q@Olm;J@MX)A;`ckVj4 zf~A9joEo-VptbVAVFgR@`uho4mr~0G@qf6^Dq5FN(1gC0{{W&filN9q$|br5P};v6 zmt`$(!PFb9fx-v+^)8B3gV)43mq2TC3pjpR+3b#lH7z%bsPYqz#1Em5Oe^DR zBDITt-!hGc0CvoC!P+X#)k+dDhTjPOS>r6Fb=j;<&c9YMOX@lNOE|P^WOZa5Tpi(I zmtsYy`hzzW`y?06+c0{CM6&+?jLMI%5E{QEmLXPL6h|RJtl|Q?hR>1#-;@W?W>TkC zqMRz$LdGH%R@L!RidO{vlOImo@>o`mFmK#nfL7c0HpFr!e|$}$R#4Ut@JAdFbgCNeT(qEM#PjyS%{K*q#~S`ei)SL)mTiUL&H&sgb)+Aj<#| z7IJQt%xfyico`{zmQkvT-gm3Z5pro-#3=?j(6&ulaLllkUIcmuNT+xS`?VK2E z7%biY08#GB;O3idHS|qkttAS#v4Y(GX7wg0I>DYVEWMz;9(T8-3H2Ral}VBVBDXkI z&}X&cW+fkZuteML8!i^Pqp0>|Z47aY+T!cuB8dpv3H#?9w!EY=EYE9=g6+l%nS*Si&t6&FC*vK_3dl$13>m*J? zdKmb+Ox2f|rAYXQYOXq-INM?~m`s&}fOi{j-oj*#Vi`~OFt`GiGNjuo$9t$c9+Ip5 zLuWS;9JQk-BjkdY^KL3-AV0EAKRG# zFs(f-B+1n+g=fvfOcKF|)k~Uif1*a{S1bNEmSCisS^f%{70_sZbqv%cYp2`@yr|P$ zHxQpRk@Qb%H&7|}7X#?YA?+d*000NsT9%Y)PJb*Lg_7ZHEeWIx=M6yS-L%{31t@(6 zf2oBTZ7NewbZ2)a8$Mw=*@&z=pl3F+X_Gm)H7VoDR!RQ z>qG>N3Z?$ph(Wunzr3cjI0H7H;x&r|a;2!biQkNp679Gx)A0dIjWT@Ul*QppFGW%I z#KDXzqpWq&L~LENueN_gGoN9o`bB5sx-<1Nu9&vJsCe6}XhV^=9Ye#1CQDx2Lk+Ce zE+0lEF}le@@Nu3AhaK={Gje!K1I-y$8?59?=dGe^?dLo+PLIM2+yiR|4`%Em-KDGX zNoe*PA?uh?Zs{$W0#$zA8C0iTTbp{s$$Q5Wy#CVY?^2`SW)!TvGClMqrwk`P%>%$e z$uk9^@hw1FoW4@33T$G{d8P?rG|^?`uWObOK;T-gbMk>uX6eA8-hs<9;7Jd^d0%qd zN4j}!*?wZhAhm!u$sp^`P6rMM=84gvME40%kWGbbeqG-LK(uo*siD*XD6|zzF|`KC znh8dql9M0`ve}J;GK4KdEmmN2Iv-;6OL_rrRlHv=iA76O@G%jEjI9bOM}UN82&ZD& z&smMf;GDKjh(`WtW@gVQE_p`?a_U{O z8{evTF9QoJhgCM4q03#=y3`=I2K5TY$Pwk354@(SyT#Y)R!*}6N6MwHk=1E;a_P`5 zEZYuXJNgyWYzJ`09{QVyY+WtQ0J}Sgt>#YF3LcmjORZ-I46a?_c3^Iz;qaclolR&# zc+76no+nf3Qw7z9uhQmxc%viGKuS@)7;=2TqsBlRag(`IPMWsdLUgZ6?He-0#&viw z(%o>xEU=LS{XsdV*NTE##o-Ed@IxX5JkwHyH@28lQ$kg;u>@zKn!)>sp;rf1zcS0@ zm6df0kW0PM_j0X4Jp@6tL02BL2hl2}q2aiUMQ(VNt_fb1?eGY-sAznhPE>Y_09_uD zK}L#xwF%qVMb6TzaS1@hV&ABGwm7^ex`ZB%f7b zm)x)jw`rs9HElO?>U+Y#U^`Z;@akpK=R@KcgI8R)tGk1h>zY~fa{Mz*Xxy-&dq-i^ zQd1=$(48d2!V19l#F!1P7nhd=EnE(n`kZiCz;%M^9YEPH*Q$jVJhLyvw!cB92Jq;w z+{0B?G5-K800}@5Phq0dmr+ zkQ#bwEjTi-@iOkKBQ#*P{{Tc4K+fTpI`v3BLIT5LrhUc*Lk3@z1winLRm;);j;*XLLkixbN3Rn%OCQyDXvyuXtywCpXm)W z*^G>af=bl$xG6Cv{+6s*atg?kTq?@t@@B+e&diWGM38cKbu~U5z?{))@O)59c*fhe z1M!a>GuZ3+|j_76Ol?A&Dd3Jcc+yZ5dw~975F5nPq;y`k|nlaSGG7Mr@hv_ww%docCjBSh0I150sln!J) zC($&gECmKITWrb9FsdjAB@&qpau2W!+inJ_MyLVGD*Oa$WcH$$d5RvkNE)cd%w@yG zu~MV4W8*g}!pf}YI>dg~vgjPQT?q=dg$kfwLl!{;Lv99FpHUQW*{3BCx!nH%UBMx& zE~8X%Q^%;&Xq@cFsy8XhJTyJwn1ZFE?XI_#!kh|m@hsruCI0}34qy~;uAb$v-xMxg zd>q8$A#9SB#TmAr8tC{Ltwdx9GEmmZePa#Qy5N;$ak^gFwYwWGbTx zb9h^oqNL{sP_ahVVfA|$m?8iWamwC#xUs2XT=w1e%Lz=v&(ZT7Elpy!R-!67TxaH0 zFc&tf{%#LKt*Y&J1=cTbT8e&<@ak%FalmUhsamQEE{Vmy?xE3EQm)6Y;WHc{Yvp=_ z>b->wG^vVOQ@QMz1+-P-&XBpgkN`2*xeoPno=2xVy$n*;z_`#Yz_X2ruN+qLPM^ za*L?DKFu_T)U?L(SJ@S~ap-M;ThO-N#v)758N-{oN43_Y@)+a?ia@&wbuHRBjlU6@ zlGu{0s-UKy%nJbwp(7h_Ai(=0i=~ve?3n=AO-d%9T3CHBje(T6` zaz(YT&SJ8ycc`zh3yHq*0aQ+yIMidhuA57ns)NiLbqVCLW8|V8iNS&I+YkY#7SdWL zBctoD4+Exmz#JTsOV?-_^MxUSCH#s<3 zs7Fs|4eKSBc&=~d0mEiAeuqXExkpi!8oEWfXy6Sp@vdvS8J(FP*SbMIISH-^ew@iRz67H z12uPF7*3dxBhkFKm$_TYS89WonR&G{t+PpNy&&@A%C6QiftXztMy*2&%ha`nnuWn; zTPPx#tj5HP7m8#tqn14Is9g_bCi7 z8TiGV%#f+|ix235IY$OfK8+U%pv=;iqfKpvAO&R5@YBRZII9nsnm7mwjE!TnEes?C zG{WY_NWyHYCYT6RRRp#cG94VphAy;0#iV9|fH(fe3>lhm=L)AtzajwFca*d+M4&I|sbzBKl0v5|?>7om-s*prRhIT5> z?>L54w;b(5*7AneV?1+OgM%Tb*M=jg_97f8ctgGq;%$rju!ydj3 zf2gwK_L(kh97e^ab>a$0?q~NiYTS$YiU|3+hCp;8!7rNU2Dn0{@xx;*zEJSBBLRK3 z5e+WD+`!6U6n_yNA@suDiC7SVD6GoWcm3Bda~d?j=UZ4g$XX}7VjQH|KyT6pSKC|8 zFIMGKEo&EFlX0vsuru*Pa^zW1O6bZ5I=Iy z6NSN0nOa?DZ{ixOti7ST49Z$wtRneLI8EafHJ!p>A(MYoK!gZBSsq8SxAs-2;fHjZ z_i8QxZpwr<1XQAMSXSn(nFRxmADW*9C6A;FT<(q}bBihqyh&xkm0|aXA`H2}YnP0L`417F7YI3R)ljQ!r=cbTf=F@*y=W z2h89o?iy2VR#5g2Y9+;Jhn%~Ga5&PkIac;Uw4`Y5Vs5o#WChEVgo|A6%rLJc^euNW z1F`~f>}4CE0^qLi^HUozxg4i~;ugw)KFXOL5Hi;9g2zkWa^pMkQ0aS6p|S=#IKjN? zRRvcuZu&b|X+GdM73h@s5O>Qyo0lux=8h>Y7J|A->MJy0QK&i_3q1|W^_pR3tNXvE z1t?nQBqa|!a}s4(#e>yR)X8QFfjnP=56Et;UQ#TyvoK}5D;Ei*cGUd9s-oViOR!R- z$8Z~*;;T4?Wl?lS^_UJ=ZEJF8fQN8u6c!w>G2NX(p^wz1kOuAoRX)u^;*)rVJ6v~t zA;or~D-5{0*PIiYtgtmWRaIatmnA>~fZbfYvcPB^dYD?oau=_0zqq(_pLeoz z%IL|#5%p`OUR0^3Nw)E#GHsy69LqM)#S=WGi*gS0`egvD`EsT1I@UJ!Ef7c-*+Zl2 z+_=jkyp-fCOkc1kjT=VraRRa}BWmvp!RA*oODOlGnXHwtD%yq)qZlPxX~y*dwy7RL zRk>RcMws}E%v1nYco<@}O`6@}fSgFi4DdfB9+6~zhlqgI6fjIwX0{fIRfH*HP#8CL zA7Rr`ldg>)jVe+(q^nX|Hnfv8S8U z2g2(~>|oiNR=cW?EH!Tracjte(Ak#m7Sp1tzN?8{lcQ|nrzERJ0H1uRb}L{Y+fh?sMkO0&3Q9 zUBP0XDnFz%5Yc;n8INe6UzluByf*}*>oUHl5(R;WJ7E|0MW7zg&+0U`=IDsvOS(Wz zI}IZL005%pFdc@-%VTb?4h2SuY%}@pxQM$9Ft59rpgdf|wsJJeWLS1fa)|&6a|K*q zY{wbJ76bBw9d+e@kum*XdP7j8bCJW(%uZBQ`lw=tg=IYitoH?p8oP;Hjzv*lOPPyj z?=PZY{K;?dh6@gbzm=Laps*d+F$}p;Dfe>`(8pYZOS!y92NZm>e0#0Y_ltur)((%7S**5AzY?gtL|QmHd6FJM#*9+M^|iMpF@#%^Mc(at){wfLe*9U`5p@BUdxpt2Uyx zg2-*oxS1{sr>VTH=_*}mZE{<5)K{Out_K{{G}5YprJQ4AMz#b4lRTw2RFeb!kD$yi zYhezfLR)$S5tzHdI+SCF6ed0dWw}pNA+$z{FJRHIt3-mG$jdImTR`r5dI)ZPUAegH5i$5A!b@#@|!(1qOZ! z4uNc>F^z0GZ1`LlOsEYU>hLuIVG;mU;J<=<$}1cenvH(_G(Obb7%o_$SFX{aH03Ia zAQV$meo?JnGEoUeA|Z}dNGu^-iChKK0}v`il2eP-46N0f){zgm7MvFnjpCG;urT&f z?V2IqpMA2RS<2;REf)n@VHhnvM|M54H=GOo$0fN7OEH)C4NRuk-JCycRu=)5AKo2G zjADVrT`%=1)W;2WJeQjoq&5QV+>t&X| zp*QrT&Z?m(^4*>LA|g_T_(H1B4Qex8^u;&KxuyuJ1NHL?*Hoau!Ds*ox|=h$0(vzt zbYPaH6kbddOmw*lpUCr4#+s3Zdi!Detk|SK%X*d^Gp&bFa##g95ba2jLKSK^vMmM8 z;p&EC+Z(Pf+=4o<^3v=WK~~6u(eg#nIG?c;C<2^ok4VwpITUf!xQzT`i>(mN*@-9* z?hGBu00Xf1=ifT}NoJ z1+cwSEWKNh`wb%~O3VPGv9>HlDuW>pfpvxb_bQ{Qk-rIZD-5k~?=dcqEKBjbjm#pP z9?6a+Y=5+&cxBEXGNMqh_M@mR7RaCEhD}SF=2jx(ygjit6{3;;NqaQ3Q;H>(wd!w} zOFM0G%m~*Z#r7@%Og*;r)H<5cs%83sfZ&|R2_dQ$91L%5=Ev6d{aHo&QC2C^Yvii^WJULv_qSHGrfA2pUmqdznSkqbx6Is`bu5Gi+L zKQ@JOL?m;z2z*m?6>)ZVIAwUVfJ0C076`0GbZm~)w7h<6xnN5GRHb{K(l%jk5X==o==;EU^F-k1K$LqR=R;$*~<{N zepNc8fki@zO)4lhIf;2v*aE_iei&c&BbuAXJQ!;P!2Pz6v#6LcSgY=%Qw*TBs=B7p zEgP+?E5X#VEe3M)sD{i~T61*%Sj^}aV5TTI_Lw57QA#Kb_1s1BwKH5PGA**3|@+spvW(9&xh7Hr3hhv*0Uaa0~*b1m3>eQlL)+&tLUe%}zJt36s zh{ixmbx$?Bn2`!tc}BRr+@T9SakVqDn1TVa%BA$^lt)z9`>cK?a01m!FO}h{tA-^c zYC_twzf#Qai_Y5lL9Zz_7FD#}%mKr8rRyiS(jDk+FM}{i71D7Ds`SxD{{Y5SRTzd_ ze$_6JqZOK&dqFsF71^C@7r5mi1PnBftgx2B&&KX(5H_x_4A>$9);mjQQ0DG|aMxT2 zuvLcI>p9pOCP~x-yMNVY8D0#vdM1QnT^uKN!jtB&D67d5C~u)l(iKr=l(@{h<>C>N zP@oh1xu`m{D_ROZ<(%IsVoO}O1wtuabmsLImC; zXUi~yNN`^)2eN)mG~hK2UiQ2(SKMADXhcfn^&D$q+T#9UGk{t%Vi6$Pt#dl=3~ObY z`jkPH+kDA40@USpZ;5py7mnDhm3i&%7-0swoUv3aE#rs?h^{HI{>Eea;B>e`JeB1U z6>cUBt?2G%cDmC;$r~XJVz1Pt9L~^9Fazm0n2cM73fvgfQtJmd15+SoED3a=mZP@J z6Co>d9^{w1sZxX3N>XJgJsbo!4Z*?Vv}$(2Q9#{)eLdT#GjZP35renx{&2A$U0S^)J2fD!K9@gg|VMSk< z;>nk@sH-dy(88yVJyf}}b32Qmg%=2P~fXIo%~ETE&M_%%lEI;R*1H7 z2Q=_Xa(>kgmd6rRy?$TRpbV>I_?^*ae7@5NF`JObnB1Sz9n_#Z%Gk4VpK^U%E@NBN zf`ksoFQ#Z}H=*#5Nuz|NBMWB%#H3s~xaecCh`)o0YO4%V+%OW2*>$qD!6=Mas^hxq z6?R=!neS~4A+=6aAhwj}`z2_mC;SuKtu(i;r<3O-zah*;( zKrhe`!W#%rtYRVE-qoKpT;n%xQUDyy7OYnvlR=FO_i52h8nBx0_WUo*16k7ZL@sE zP)$ZS0O@xI5*z?r16tri!G|cf*1GOAx*DvY_+UK{pJ)LXdgIhzY=Pjuh|N{(UQju$q!fk%%&m+V?Uzo^q%;6iF+!b})6wW7kn-xB+Fl^{Hv~!R zUwdNNxEwx1!7Tp(Az72tL{W@DG=VRZikfS97_W1H)U=06v%^+;P!!ahOA4M zhT`q1Ey3|B+JGy7Ubpirsty%RafoN1K{C1m>JdK577Dh^P>qpY8fW%YIOW`y{)?Dw zQEzMo%r!Wi0^6QlT(}1kg*cxzjHQl{qeXJwsF;68iN4L$AO|&|1~Pu74A-hv(avS@ z%7($$xPEXgWeNh?Y8KbO7XBa#m$VB9A3eiHJZm!d5l*n%bF|yfNlmyO!2U$FSU_^PU&YjL!9*$WAKan};GC6inCQW5 zs;vok*R>6ndW+989v4r%M1z9~}&$8&$lv8T9hjc}Pl4XVGW#cqT*Qp0I1us!!0V5L>lx1<@t`UBwuC;X7`TX0cM zHI$9uWRxtWs^M*_$cs`goAyp&0=czwPBWXFq`KRu4yHQ9Su0)S#s_8@Am~3?pjDc$f&pZJgqZRvWO}`D%fQsFI>)HVrw5V>;uSm9EC@TyIN#{d({B`VletO0IZb{zvhf`^7(olUG zBFQ9xUW?U#YT&7#){mg6d%f%mC21eE{1F>H!2ZJ7W}+po1BHI1xU_=i&!5@1xy!P3+Aj1hBlX)1=3POvI3>&DdJ9yXndoG0< z4T)JaZVbTC##I$eq$h+1usBB+jWHwu;tSmH2J2a^1g#T`i=&&x5m?mP_`N!qJT%EM z$T#Zd4vYZyBbA$NaN03O!-5RxF?4M&n5^(4YGD{`1frJ3v|qbQXe0*jBrZk;XBJGCi%GU?FhG1YQ`I7d;Qh`5{8D&%e(kY>? zmAEom6gsJUy(F)Shf`WR<{}+5xiaPbTyhhbe@Oc@%%!yy!XQAjYPkE9IP7w9ZM?=l zKw4Y;0$Q2|rC4+iz;H*l4N<|Ws%trvDXQo{D~)}jZ@y)krONDS_(tQA1>+6zzU52Y z8HZ_c?89{(p;1(YAX||REht>WfEYa>J9y}dg$xHozFwoHkW&IB-M*sN=AMo!1p;KT zT$Uz6pwp!phStBXwH~`kkeg|VymDfkfWfO)mAtNtmzO1y-4DRIYI`b}8dz|bX%1Mb z?4@E?B2anyvxJEVx+aBfe3(ZJDp4<3q(62;y@6LyUsM|acWSl~c#Ypl3G(P@qS)(>nh4&9L03jUQvoF(!-t)7)Za zpfgPUplgk_VaN&1ktfD!Dwc5kL<5SWg^87M-ixb}$2Uz1#(?3CW_DHIc7y zSriDld{k*3Qky;Ede&)xbe%wD=nE39_W2_NI1WAV#)Vo8o7G{LtqTW);!@HUACM(_ zcB$-F6f%MvA#lQu!7*rPS$)LiWG2Zmf*5HrKdH#RE)%jjj9zd2OJ}i%+t(>S0wzU< z0QiI17MQQ7N-%+w<;UmTuJcI@QCn9=h)o?$tDidYcK|xO~zcC?WL9|)gI^td^ zsEw$=!&1#P}(2AQO*M!_(@aG?%M%sNG|j$_?(BMB&13}Chq zHxDi&DA8sl}GL+1~yv{xmqa8yR=pAS8xhV zeVD{F*|G}J?ue66LT57&m*`vZG%K)DPSuwZ%HDU;XE3M$td#@u%N%PT^bpjI!4|t? zQFn+O0dZ_f2M&k3wxuF8rg2jcQAY>uI%tq=E*)UrZ3q7VCD3N{;a=<9Y)$W=^m8)^ zWrojIvmrzlP0;Z!te5Vp55X(J0WHvsFQ`ls=*|QXTC~1gugt6D$3^_~O!@Sfy-wMb zb7$A6F(nFg8>vNiouS{d@IxtzmIIood2}TiAhSTp5~CojB?GeNo3@~D7iHD2EGKGG z_#B$vC8>ZZNnjztFifuq9jzJ(#SKg?cYJjnEUQ|Y3)i9z@KUe`Cibju#D>Tmiu+X4_a4NIP@v*v*zI`3`9V^iG%#J@j)FkC zdbwGtvJO=L0GRTPaS|<2+Z!rmJd1t?E_Y2QH^w#XhDYFR?XDo`t7UbL3-O6_Sf)2ZAAk;Txw2LUae zvhr<|Vt8WiqNzv*WDqg}%4MhsB9=Kt+mH)I z3aNdIFg)>~AK}1GsCjv8%`HSW>flNDsO6H@XZON=LW4&X1#(+y`g3d7FG*(XPa@gvK zULagL#9Z6E7iuqU;gwumGL8bCxP)9>8nPC=;}lFy>D_DbEGU`A(V8B{8p4v!4#`rA zKC$5D&_W5@Tn^)7T1O4Q9jWbg3RXtZ1=xy#e@J{*oTmB+HJzcm^d==ElB#{?R=PVD z9NhsauoZSy!$yv!c+qi(>rnP^XiyV}8;OECb6=KPPes2Z%wJoeSJ-h-K*e@vrLQTu z7!kVuTZ3U$qURckEfA_`HK%dAB`d#4>*K5B!1yMHk?X=Dq5yg;?Ta|VFntMv$P!l{wa z2dQ#|>A4?gGWxpJy|)xH+a0`UI7W@0W=0m<%yf( zQ5-%5rrz5YyTQ8YVWun&9%y#LP+p>{7AfuGI!ZMzyTBMbK(f?;#=aaR+wzxrezf!@SSIXR860;jaSDWh}zznwzpJ^+Nj4R3&Sa0ONB)A6$} znTo2zSbCX&C=lXzMC78fvJWC%&A;ve>@zv6vh3+>qML6v+Q5}0s?fk6e8bsMJIYX9 zMk=JxHHvg_K`1H))rx}=K&DJGWk?U{2!<#n&4WTo?!vrQc~V3WxfiGipAHUDzk)j zM705FRItV2R`U-9Y}Xydl&p<$?g4W0G_}D66X4*!xRh#AkWylvE}1d316az7SLQj( z1dn3mmT<+C8oS34fKg)9Do9YMRxBz$u9#YQg&E=#sIJ@>TslaJIf^a%msUkvWTwjkA`Asx=5pepuL~)TlH)%yElQ7T`vxp~%HXtoXc^{{T<} zP{>6+Fgv1;gUkbok%A+$rcs}Ywjw1oDEl#I3lh)Bi43O$@U}`>qZEoIWVV7Gdl3c0 zV0?wAsMp)UY#!=$<5f%^o%S%dK(y7w;V}bi?rcl4%OG`YH}HGZ7b|p}8AHIclM>kj zb#;iDeE@#oue$)hqbX53brr2VJxXnk5dqW3e~FG$u$nPkqAt!pZ|Of!1a{Lpfco%nXi3(C0B;2PJCw>M7;&YK!)_Y_iJp zZYd5zg z_?JNKfXp+QGf(-H>ZdgTmP2+Hb&7)!nmtBwP;93C6%}X}ZQM*?8(cG#`&Ij5FphJF z>4Fw~fW<`se~Ep#m0?=THoo4XUV(55!CB9^ATT)p0DZ9Q*}%|ByklN+~ z?X1`IN9$i&q1y!ti(e4BUZW(Xi#3C6Ktq#f%lMa!GjP%ot*3EnSS~<0IgacPVL)(G zz?X_}FH5$yX)X!D>^?vv5sFtOD=f4sup*&E^n+>Z5}k_IfMuP1(=tU|EqySrh5p_f|^YPIK<+6c;=YzI9p){h*0WilR z?Ax}2Ka$Ka1ecN)S}3$QFkQ-~WW%AAz0s*l*6Fb92N7)yP@_8*adZfgFDvq~%gYM} zz$|E?a91;*xK@VTy!Q_mxuwN4s&-4^f%_{p>NTg)W5e2q^I6%*T3Ia!ypBWaIe2C4 z)IhfG6dD1<2ZJ?^VVbs;i%JwU?l23%Zq@J9qFgMuHhZXwNdO0+y!5ebrED_GWUxP$ z5xCq=Q-R&fr1S1NxLE+z;-NHH2>60f3OP_!o9%$;Kqye-8{@`G ztW|SfaRmx=s4SgvMbcxuRdqZvOPUZxlRHSja!czyeM%JGb!Q;2B%H3YdzsaCWK?r0 z(twf>+Nr8a4&XSY>`M^Vd@BT0*{& zbo9$vWq1P?25Ms2(oxA~Nc;B}XRlDefg-&Yz^w;Q#D5d;VT_TqcUr~um z#Hp&h`=0h!Ba$!4a-}1dJLHuCX7nvCxs}0Ub|A~)oMz2`nS1gk0&ux|Non1U)CJmb zuAqzpmc#2%Y5=m`eIiH*JX2pLDhCmB?e>URwsU($80;L%-fof(nMgmRdX(kw1REuy z+bOa7goe9KzcSRY1qJ=H0Em`kaP~1OfUY45{XlRhEA<;2Kv1Hnl~Jm?u~sBxurw;~ z7e~ys%D9KJI$~M7F>Da01AQIE>yv-+L~a99;rp2aF|qy86dCkfoJ&SXfOVbdL8y8S zr7224t>?J>oQ;Q-unm%R7w(bSMvp&v$rf!Zd;o4Y*9CcKMPG1=(65f-HI8i}eIIG9fs#0M5kTLFtx zGlv5yqq4OCkPKaC!^NsTNl7wvB(i#gOcED4!liSkNdbOKshW-Tc$M!bz+x3~sZD{b z%597H`Y~hKq&$5u_ZSR_=~{)WfZOvc`;9Y%tR@1%YR=aNW?LTg{jt5l%&@ zT{z+%r3vPiTLo6a3w@DD)zsU!wVd|CvNsJ{X;suZz*$QSlp}cbN`V+^s+nLeZwXs& zp_J7CnZu#m5!Z#Ntln@@I*>6oZw8hTU15}|N8zYNMNwk)}EQ@O_g38z{xD^MQxkM3dZJ8bvr%~Nkug6OFTp=&7)L3_OaAxTk zuoVwvp&aS07=vtr@dW`euqOLs6CndD8e7aDX(V=Uj>wC;)t@&i5jKm1i~SgZ?Sdy} z7=RKA1xkY#T*^?q31CrsJD1Z4;I3>OYS>BOuYNXlQvBi(LulX;e8wEmg~G{PhE?#2 zw%CT1doOWvfo>1d4k6zUQl1fYwnW`~xV@GwX+gsUO4(k9DjG|Lm&CdS5{E%_Ll|g= z?Car;#;vI17HR6D_|bqHDEp5AXt5#kCUVCouw;l4g0LE`R4Ht9osK?gh$pKRLz7=Z zQ0l2cc4HR`8Xk(oXK7_iCP7zxO9khuE9wth*4(0h?`KAw?0O|0&Mw7%1pmv&+QaFbGk$*?DeoF*%`6Gl%mZ%XK+h{il z9Bd65N(yscy+;C=$w8j449#3`8TY{$N6XyKvsA@>a8fU_S}=c|2O}RWsv@tR2=__C zd&yS;vi737xatRzvsc6dM6etUZc&~@+I>Ss`gWCpfL;8O@z4%TID(XK@~Kc=14uXZ z849^?J<&kRrE5jSf{HJKP3=~wiKFs7_NX0LRU=34L%G? z?#;{TsEtrQa>{%`SzkdMb@9xL3i30cRst=XK>;K10W&DP3Zv|@8QTE>#}pRDlB0&s z(xA}QD9gUkVk5&nh~OAqfI>Y$pz!!yd@91jE_CVv8)p+9igGfGq0lH0VPf!V9Ghs_s)`k@WZl}iCezZU-c+U`?V`hmXt2&Ex>NN^8S88q z_79OfUHAo79cKEk8^>8UU7V-LXdR>q1>}23LLjXFsx8! zq`I)SH~nBv+(hP5K2A%QLZBo7@UEFh0C|>2sI0)L&POAO(f~sK z$r2nK29$7pN{vbbfH{m6p>!4N2PKh#UO<0!4FOMhs^0w&kk@YLgH^Ix%F0JB{%%ny zu<0>t1I^(?SWq%@z@^4fI|DJ8Fp;42a}(W*>V6Qg3yGtk`{oC7ZJu`=A_is6SS96H zfvD|1+`xDcm(k7(#+*#8L&V6TpzG!?WU+iW>L9SjShy34(7)m)QDrR7X6=WQXT&Ng zZ7SW|5MkuI9>a)s^<_Fnjm3mz1(%>;q08$C6XK@-x3;K!MeyjH_;JYwLTX9Zhc^m@7_DiSm%(waKKuM!~!Dl~UN?55IK^t&4EWLA@jpLbU$?Oqp@u8f0I< zB?j$llZ;ZV%3+*^9+1S|#&UNT9VAQ?EgG;z7gl=7xTu?`A7Wjy zGA6*cfnVYR4kB|{=Z>ZL+&9Vi2Ly1vX)613%v2k}+u%2GDopaQZMxFIPhQ6RClI+( z-)=pTmwwo>HH=)DrDxj9Dr+9~*D~yS4GBS7t#qBhFH)cIx<)Uois%LO8;caG$)}yY zbV}TG8CR=gko0#>fP31?fS{-_wX&dmvu4Z_27gnXs1qRAV9Y9H3BuDgeRUG8x67KB zDuW(-DRXU+E^8{?_TIpT>!nKQRh;u=((5i!yrajo4T3s~FcFNm)V-n9u&gVa;w0P> z^XuAJ(zF)I1$x65vLFhSa_AVTOj|tv03fz=D#D|p<$b7vJwQM5VfKk_LmLJaoE1l< zmLr_$Aj=EGM1f@Au)F)czZGe$<6?MoNrumgxfZ2L0{lNTi zI2G9Dat|Rx;=0={a6J?bWmW)Gq?e$_vTMRz640QRyS8&sR}?`$u*zH*cW}1v1%UA- zERvbG!4hPkp<`B@u#Q4)8VXNEh=L^(XATl%i$x-1k-W0P*rz01ZN^}9a9ya)#XR>I zw`Xj~5cs;YaeE6b2Gz&vUu7r))`;N_9pN~QWuV!}2?@^8Ob)A2ez!zlrA{Xr!yOk5 z6fMUA(^|P}dJ_jk2Ar(C2DcANP{(g%!U0W!$4I%|rNQ=#s&IdXvcPWVJ&0Dxe^?PO zKQM0!GJVRHHWwlP05aDV6g!l=iBv3+;`)SgXk7jxECXXFOnk6uQ%4pz;Yb!g$uq=u zMx3}Qm!5)DNt`y2&=d^(nqZroN+U{e;go0#EK}NFGdEMgVd(tII;8@te1h4HOGmuM zR72P(paIa`pb)NZ1c9xgyodNEB#nf2cQ4frB~Hi)8lYQ(Hxis=g4r2e=hUm<@(sm* z>Q;pdTnDBV2-52xGwD0;+_yGdULeA*lPXyf$a%WdMS(O(xveVNQ2HUJDEUY+u`&Kq zklV`KXLLDCWrF%LGS>e9#LQ9nqq%^1h?1sVO^;ZL3GBn-=0@>BMa-(!sD<$kmaJNR zmI0-PiTnvsRt3U9A9CPk=8~W{2%2{Wj);OrjuHU6)d^Mrsf0Vq1Sa{hALxCOR7+SH6Bagi^yVhp00C~wmdjh13r)*F^ER+|l+Ox4WY zE9jNE%AgzjxQ&+V7b-UHIb)~VeEdxn54(iewwg3^`i2zE(JxTJ6e!&q_VGKh3iy?> z_yQ(y%bZNhyyf3Djx?9i`gPxDbRew1-FHK>&WLVy)N&MMYgQ-ps2n0x;);&>Fs2 z1o;H}Z=;z|WvcJsndHzptblM#(>kWsFNIfG5D<3 zcHVJ0ZlRhA+9 zvC2yzE!pdsN2u>}ZqAtQ&V&1t0x0eu z5HP<;8GXheeJoDMme?|t#Gq6=R$16jN@aA3>4EgN@IKWnt(LvPsSz8^wwj%W^a+^V zxEDzoSkoI@(urZRCFgZ1X<9R?<#SfcRm&Iy3bh*4ueohpzyV3X$u{xz#9|n`=1`q6 zdZX$b9J2aWUE$0DU>a?_#h$0f;*sbktSNtFEBhrGdW@qE{-)5HTGa~V;Sb{3hA$f( z#W7D{A4R|{2ey#+1nm0~p5l56fQ($`tM#13?)*%7P>lxcU*@A&*?A)Bg4?i|+BA?- zD6^K>r^wQhk!2kG++gJAAE*}V7ltejG}0rE*2)_q?#e8_Dk_4bckfh1Sc^fbWfa?4 zsDQemrF|VhZU}oGIx?!e89Knh+$z=8hBC==T``A-62gn#PDCO(YQ|U~#&`&p4Rr&= z4q>NCD>qJ{mF*ze3zUmg1w+8+e5!Hw766COaBN1H1ssQN*veXm%~j1^6CpS&4b@{1 zMBBAzs8w?N=9roo3RK zi5_!8f|GW7xIX+1vohc#R545=&z&(#lcLjNt~iasd1Lvqi`!m7-%0RQdrpI zRjyQY7jlXkvj7T)@|u({!q@S$tIf(3$ffGfX@i7D>;(@#*g44ovhi0Gz@lrF&{$cV zpr8vFfIPaKr}xp@+rb(OT41vSHKD6Ay?(PSR@~&R(ajMsuC%7^1_PQP1%xBTVd&yB zs>bc*S5aZFTH~(EqGvn-y1Q`vT)0p*yQ38QBb3U`3gO&hc4p-bTNMwWpkM-0YiPX! z@a|neC=(**s9TT32O^&Vk{O#<5*6ZBxA+ zrmiha)w!ksfE73NCMN)Oi;D1lfq#U=Z|1%uWyriPGXq_1r#A5(5~d~)n5ybE@N3K) z5bjtsfzUqX5CEcoj0)3qKQh|E5InGARVA zaZ;Cw9P{~xDI5f0hENVjVHt7bs@zuntn@Wb?Fa|sk5I3Q`n zu&(9`jYY$5$QlrF`xP?W0lYH+^;IaXHeG(D>Z}C{MH=Ic{{V^9E21ihsMYcre*=)> zWSi55QTPd6?1Z(vpYF_Pa<5li+{{3f$UR(dh_(tIh+kmMgfuB|fwxM;Za7B4+9Kvz zZd&-Mb}anOOLsl*&;J0jlSK)(h&GK`)+^qkGQm|`*AnyG>ADQ0C%PTI#LJ6{&*Cz) zFLL^}S|_Syb(%O4Vk5U?YLA({ZCI_4G}tmgwAZP0QG=n{x4 z!lYnPb~#~cA+=2cUk(tCL6%czDtFYN&`@-VmkAA+41~ zZ0EIvVe;?iSSDK4mFyPK<`R}rIVLWn4NxfSE&4ej6sL~pdL6)#UkhbFVaX|jwEXSN zX9h2Ty?nvKWHK6a?jXgmX+t#*`YbIiYWjmEU}0Cks0JXh*Y-CLV{i)x%n5P8CJ%hT z%om#Chwe38B!#T%b0JV*&WK7}Wh_?z01#}1iG-{H>Lsj=msJJ9+JyU=VVap(04jwL ziX?;_7`plcSczSb*$w?eHhE1e!zr3TVDfrbrT(H@8&9YODw|#cMFS3%?d)#o?{j&9T$c(J(AmbAL+O9z^#xLAA&4!>o z)qn%?M1dDeOiZ{lwVdu7&N$n4*O(^TNl|J5b%&}UldhO=p=0rxauL|7g1QfED8NVh~+4LAVAH# zCuom`6Y|tYyU_rinD!2jNkf{AEel~kLNzz8wFJ`h7?3ohZEJqxc7H&Yb0;8pFPP%p zJv)aC7Y@&&Uxw}bzTlD6WYyyOxUA^uz>3lj{{X3hj>{ZB?lXL~vDeSIc7|6G;#^-9 z+CGa~!sf@f97`@kX@kM8C5SNQ6-E$H%9MCnrElm&N6K};n?hLtvOC>NG?apCy9ERq zQED#>#9;+TwB&nRY$b-lR_rM^NYS*MAeg}~bZAox31>c`Qi~8U(uAv^lIgb=fb-;l zRQX>*IXS^>yj2jf8%P?ot12P9+8tm&xYmGkC|woLND-e}wS69;&eMO$VKZrgX~Ou2 z=(S)LhLL)fSw{Z-!QHsUN*6$H>>;R*b(e4EJ+2c0a;q}RG}%^_@ZKdT&#S6L(Zp(( zQwTxHYa}KiAgBecHdH{gA<6j%s5gbFinUU#2vw#oO9x}j1C1{r!C6#_Vi2{<$oSk? z2L)EPQKnsr$W&Om2AtCz$E6lyB{0itsyZb^uDDTnYlCP7SgipsdQ z7NbMb`%hA%Y6fM4L3pf2cXhR*)~o%l2)c2rVOtoD$Qyyey{@v$JXK`{?)d5!7mpFB zX56H(Qi8W2c~pBZQ|Na0TVPpDdJ6hj!4(3kS*HrW zWWuIlMiZ%Ju5!blx45;lZFZ?vPA5nW)ap3ops`NH(=Bl1XT?lQ+PC%0YT0z*{i53@ zU8t#n6MlBWKJQd^>B!U~$;jU)%@c4j4ns{cjd+>O==rH!)=TCl3hcauX;ETU?qxO^ z8^auXa01UNSdh4(bP2u0W5f3W)m(v!d!64luQ609nC`f?3fA;TY_=U%!o5rJ?Z6(Z zsEHnq$Hha1WS!m@S?*$2j5puJSCY6CKTyRKzyk~>%4W2YtY8%az^K!ZJwT)fbz?Z5RWKzEd z8OoP=2dAiDxb5$6*mCrJU!(6Pz;zkIc7AIbkwRK;jD0tqyD9 zg1`-5F`Ku2p;ifO8&k#o=Q89%B z1wgVKwS4VaS(b9yD?<${xDd*%e_(r2>WUi_wi6G4n+yXjUiK|zlx)_h9R}l`;5RmB z+uBqLww*gz8A=@wSQuB&EJ_hoTk&N5#6qB=@aP)2U2;Z$-|}WND>r*C74fJRQn<%# zwxFavI$BJ~vw_ijs0gb9Y~l<9fnp`wM(l$r3vh>Df(wWMy`}yzs|X>XTq@hCfT|ee z3yNc!0~`sZGlathi8Ctf0=nfg&;k#l(s>oIh*Q`VT09+c?##lwd z%JOkt5*8H{2Xy^_gjOF2RaIn22|2yKR3+5ZFH2+#{n0VNH*7biu-sE>(T4*5Nm&tz zeYrmbJ`SiY3(nfPPu|Y8RUJ4)E!D)TYE`Czq5{HJDGD;U&>m}X94PxzoZc}D_<(BG z5w!}~YM?8sMS#nGWkrz&+cY6n3v*j?tOdwZ?M0Mew;lp*t<=e|X{|Gmu&g~YvAWP| z>*v%EP-&&r#Mmv_Zrahf%f;AL-^9WkntZ}cmp|o&-lSyvQp9dKpKF&cZAeb7eL*>B z-fLXW@XN$-c6(rUX>|g+_;j)7R_$Bx>6dhJjzhW8f!*W!fVsA&o9#w|8b!#AHfV_) z(_M^>dWufar)w~U(Lr@y<}^uXqs7h+^7rl!V4zEnnO)8xi2l&fkTjrGM}W$=~3(A;5jjU2Q?R904b^vts{&A z_Hsu~Kp>^*%oiypwB&+G2-UD)wc+dHFB%35afQOFm_l9=XxZ^Ak_$UXtSGd1U6E3* z*?N7I+F(m4lxK)1oKN2jPST+i0AkpXZ(fjSAm%+GzYAXFZahkC`ktsJIGOyTh+&s@ z`K)##ZLnA)=#;>&f5iyMI=gNHjb!!k#NrcOh#h{h;^7_}CiN7*bb8e@NVqRCnkmRd1EHrsh@cHK+-y-C zQh+UKd46C+r$a03hJ^>zNT}p+znGdyIcK)#IwRm@9n35g3$h&17NlCW0`yE8657W5 zdH9*q%W=otd^>KroM1G9*X~-p8W$gfb0SjYE6^82qhu+9f%}I=IeiA;R95AOwswYZ zZMll=21vC302IMjges~6=$aV*0_|!Q?F(qp7HTFGtMO!`l-FN#ce3oc89*?B$oC1* zL$%M_DwJB$z=qr{^F7k6)MtG_UW72Ew?HY{=k+evg_m(<8nOWE<6sHHYkCATVm4)0 zTgwy*SQY;Of{^1B0TI#|Jq)ZWIlq-~gS2$D7onSD*=3cFfv(Vngt!n#I~ukn3|Rp$ zT{u0#YKsf3Uf6_&q)^$U0Uu;)crD=AF%-OEhvauX=?Cm-%(!yfS8H|gEtAz6Gwakx zhx|LjrE66~0fu`1mTkqf)L$zEP!1>yxqz-}0d%e4U;-pipepIMRbEq72ud;uAY`jT zu*7bLt_nudbBP28Ap3*8_X(2G$f(qmieRH>BwxFiBJ*Q-a5HhtXFePkPgfiXA_z78 zMO8OcTq}msQ$QNrDZp|}4SkOxeWhw{Ev3+TOW7%?G=E2CGKt*O8@-U1_VTrEc~PWq2P4jE6+Q3|ojWaP@Odx)~M+EbZ%M5-yi1+L(z zNU^WDf3joxQ{Qp7=TJb!2O{qjDpGkCQS!3hCJJ|4(Zs1zrXcf6THuEUyctzAX<))i z(g|YhJvPHvMtT7j=1`^5ayYme2;SJ;2f+tZSSyrnHuow%b|4P0z7SQQ*$a%-7fsOy zYO;;1Z3v;ES|B*0j#5YqtOY}8%pF-KUUgO z7mMhI&~1Bt*GDnOD5VHNTw!V2rig35r5UWX)#e2Luyb9-aF7EERIbD!NE1mEqw_4) z0B{{@x|%lqiFqWeFfY0RyAB(MPf7(@^hSmd67Um!OL9QjuwWrOsx}x|X^R* z<5qI^m(@hX-mToG(F7U}t(I$X-4Nku7z7PZ0!y7iK;z~Yv6FQ0!rACnOFbj-s9{Ul zDyI~Ew*q7^dod`61R7UR3!f0^>MS|a7E9R##cz%|k%X}x8Cx*~LRo(}sB-~cHlC++ z*KVne7EC6~VNg1n zQH=980-Q!E4B9+4%>yZ0v|)wTGoK#@Fsr*J3EaOB?SQ_NXM$6o+(#MRI}E164l6mW z%*Z|9K-)kq{$SbcuOcN{x}h5yPU|wl#Cpxc^o!g>vi1I%mKyZS06s!whKR$QDpt4R z5?U(qJ0<1{a%y7HJG@N0#}43Y$I5@G^T(29B=#{P^z|L%eb6EC)P5H|s*WL92S5&A z6Bwe37JYRWyt1QNWmgyKE$P4KV8=G?zZS$RD~^YKur?aWzJxHjK_a|dSEi_HjlS5z zftr`31zfW!nZo5!j5D{B&5iElHQCb|ZPW0$wk(jhF1%%>7i1e0+SQ6|h zB2w7uoJ!FZk7^fn%77tFtW0(C?kx~B6XBVUm=y^}0dSzMFF^1OTurS=9d`PNsDWYi z1@+v$3(ipD>36k+-S&fg5PetRCaW5?#B67*z&3&m27n4E;*KD~atqBqpuFTsylz&2 z>2iyq6~gi~GT6>_H0jT}hEjnRnN)8jxnl8IE3&yN*u$k0e6O$?vX%lBX@*H_;xbsH zMXGRm4W|&XOYy8km=rQLP|Na56px8)ZtflU6q&tVXplrd!%aKeJG8L0JlJlvUtPCgmK_nUNDJ zj~3IVr^GyQ za;QmJN1f+Y6>=Ji7}qweOpWeg5a96>}cn635qSg%|N3y`dLY#H*&8= z6_!ZaX_l;8fCyfLp2U9%vj^P9J530N&zLL3TN8*G3!#`FOahM~&s|FCVz$nd#s~t8 z40vEZ$l=Pp62bEf=wv!NJgtS)8^EW2-x7%$t!I42%P9s@f;ovQ4^=F^Sa-@w6bV%H z>5e4aIJNFw%|_{fB7!(I2KHRyYIGJFi+cSq9#OTQ$u)%N=tB=$uLK1E_pv%*tj(rD ziqgWJRB~!qe38W|$0#d6Z7G?mhH3|rXjRz;u{YWQHNsk;mZNIb@UaE=81uu#MHp#K0YwDT|JjyeyV${S*> z7>4nXB&4Olt`(N+5!FT3tvR$HCXjAB1v17i2$B2%?mJl$ttvE@3AKWvimKKU`e&9P zHE;+8kN7HB!D1BJhaWl;samvF~z20mlqx~Qt#7*#{VDa6=Vh`OkeH=7k57`RRJ zaA4gVRX~KAzzh1xR_MV8ut`KOjBl0~!)Ah2BE6V!3Zj_zV98RM$)#y71vgUlI}3cZS%pKmn{{EwOPJungbBwldmbgr-rSR%1;962hwV1|{E(6-~S0?n`Kd zG}WqR3gu+4 z%>xrzZh)I%p#T6J5KD}}P^#3y4~P{PxHn(zi8U6ilz&Db&IT8<#aq1b0XNxptIWWc zUf@oF!E~9?h(1YZe3aA?i*2!>Wc+NU-K z)uo`UTeAy^Lp|0dWwjtui070l7@g2Z5q~fZv{*H_Knkv_(B4f2;^PjXCSRyej>sEe zg8`}KHMc>FkGK;@T+kOSJ^Xu@=t4P-jpcl-3)Zk#(t&rCv<>yQB+BQjc>9JI7aBFN zX4CTw2yjhM)g->SDw5mKVhvqcSt|(ngA~5G+Rl z-nfLRO0LXT35XKNKsp%#4d5QctEM8!1hsL5@RHyn};2Bjp zhCv#kC)D8wRq!In$5QKckyyB2Yo_ksiCkT;V}UBhi|>`e(jd2yjAf>c9*n}nSqo92 zD$kE{n6+x97HURnDzFeaPio(YUxq1QiAwlMZ+zk*9orsUQ__e4a@q#sjJ+|zz}TKaje5LYR%WNE5xAN zKGC`~5!D%`dGB1shnbD?!TVsqst_1DJQFX`O2FMKre)n{HoIT308GP%9?z`xJs)bh3)3_} zbuOBVJJ`4m#b`p0=uImbiLfmdTzq0=4Y6Cg8^hy$MDa{3nrTn2V|9+eQ1PE~ql1RN z)};aX!6n^wEQnlDwUrdM5DW8v*g}#lfO0Cj`Cz~RsSxw6{7M)mPTO-~>Y@c1TPpy! zm&Ch(q%Oc~A&bmYP&zz@K9MReB}x=Odgc?p^Ne+7%3#69RbFfi)4`cd zC~PZ!Mfrt8;Ed72<0H=EyJCgf(*bzuC6QJ0VM|d6E(7$;d}2{8c;oargaiyO0z+Ze zo;YAnkDx9807T4DT-DHh6FE1#O`Yp8DFLx(I@<9F2@S^no}ep5&~1M87I+haVu@cc zAXsF->Sc1v1c7(@lcRV-p7KB0uozJ&^BFi^K z%&OYIGWl4=OrD!%%CQz)%;UIX9DE=j<`KDffnMqsvaO{%8e>3*U7OYVnL5F}uK@~* z2;@24#}H5`H88rwh!C^=KBAp9p;)r(-Lp-`H6`kVrn5vINp9<~)-DKxCo7~ljyjAz zX>pXA5V?5YvT*ZGIlvk2suQnke} zco@z%9^~#XahT|7m;y5+?`9#m62dh(r6EPsow=JnW153f!P!i#^n#qm%U9DZ23(kB z1~=1%fnQ+D*Bc2_UIz>ct}&dF#({wfun_i+{x>K9e}d(SwYA8437F|EF+3*&(;sE0 zl`HBcdiiuP@lB;S@N+IOC?=QcVNiZ*lpAqI{9t1Ri=jGp%W%QH2tmN-`~nk%x>exe zfWqD4SKQx9t*`_Ph{2Q>(=aNq#J~|?j!wuGZ&H-T7XQz5(L_?R}*t&3{eUZq-U z`L9s)RIbBB8Ys3_RZWT+=pa~gX6io21O1BN#Q_Is+mjDz^oE8|WheBQJFEcupoWB$ z2IQ7!-wc1OQ@$@Ht~=7=gOY8Rv;{*65*F#~ztj8W5WMq3R=~ML=jH zs8$PrmXClym`7yzxwNT)V*m}?>%QSK?6nNHkSueqd4)J@m2k z&fh*>GXyEA5!SI$sVglxWWgF6cScTFLq37Ad)1vXwnA#euxn(eLOO6O?1LpZ+wpC7 zaSP@!OD~&t!CK4!+2*f)=QM?Ntmop1?lj(m)oNS$mK;0> zATVu>GaO~wxLHapK>|R%{{U>M6^gBACL!Vm z;t#1RIY@fCnsd)7wp`oYkS)vr%q`;tK1ODR`!Pz zA&pT*A%MU*2z&`Zj$JT5v?CW=X|vG@lgQ+xXodT*+(qhU;1pesJuXqeXy|W}Bxt!8Sd@m^6|6Hm z0TrhG#I{kPV%x)}0>weRehx`p=(nUPtKk{NxI*BuijA#i8qoVPaem2> z*2-+*_<#YWV7(IODe|uf{E>-`xvL&=5>8=mp5odD>M5*M4X)wJU<{-61s2Pn*$ueD zZghz%KHltTl*#=<6M4YLWg)rpat%+E|3-0Cd4IYGOk{~iGm<8c~BaQSYh`DQ+&Nd_?c$Y zD_(P{q)rB~a0Fn81MZdIJe>Ln2Of$87^XqwN}IYL4z>2D*IQtfUI+~^h%nrW`|dO zLe*@}nCyb9vK=$S^VCSD_O6FSvbiSPmlbFYCNmj9!jM|pUFIATDFpB>vYR5z1-Rfx zEWVpc#tinm2R7OyZ#GS(!UfQDOA2O|+Ge;WCn^n!&6$2Q-IUQ_-)QwP@)S552H5ea zVFPC?$q190)wh*~uxg@;!9{5zUCJEpwLZx3wJnA+dj8b42QW)lY71^Ys5Tg0E*n+U zGQA5lJpfuOfV{t3f&vYX(dmem=+JO_o{&z5RuaHn^M9meqU2khW)x1lvY}|zu&yY2 zHp+H@6ydc)mKGWs?ZQ91RK9}@g}rJlMjq3uZa$(g4PCB}^1z#2=CZmNmB=_&E@GpU z4BPtdxQ=A9g?eW3%wEg5g*yp`BNPKp-RV~z;05O4cxbt0t)3Qa<}Kn}Zm$LN%(oXn zpF~@}>k|WMC|dG|1DpwUmRdxXz)Kd?RAiz_Be6dI+Crhs}g9zj;?IFw%>>fyg zMQF^sbC)4TA!oLlyr&LjB3oYtB(JMw*Jxh!Q0C6Ta9(*1YRc4IG|3)T+YYQAO0Kq%yjJ`Z&GahqvZ&~WkkdWVsbm+jD>tDsDa$l z`;SChz(j_EOguAdmvBTVY6KX1jNocEQXO*-CRviSIjH`rdxkLkR0Ldjtwew>#knlz zo!+GZR&h{679GsI<0@2aQ&NRa-IDcN_-4Jq2ByN=uR8Vf4bla6hvni88*{mF6ywFm z&n!iSUJbk%!w#-VTWqKN$Gw3=D43+SAf|g!-!Y_BaltIh4vmfgTLB{lN&=$IlAZeH!(SzfdrrIkBlE5p_g0^7Q?e4U)g7%A}Mp3GP2s*SMJFvqtQS6xd zVAdhpD=I%-#1u^kzyPeP2L%DjS#ZZ^EVZl}P^j9tH*9)A7gkvpYDmZGU8;pr=yrq? z+|aof1$8d-f&P~=ac0|~fw1Jz60`^{FlV=xQm+cCvCuy;$!{@mhQ7WG%b~U$F3Bqn z9lf{~;RhjS_ACA+4}z>v9IyE9QlNm?I8|Q4U5=VmtUXt3P!*x8ve6c;!%{tq%MjC= z-vqRs(Yb}S-enG&rna)u9U4r++Is3J3Q@iJ+8nOC!YyyEq9hXWux({q9Y$mh)V^gw zV64g&*_3w$=T;*q+fMg_EE=>%g?KTkiDm?)@U!1*Ds8A2skOA@iJ4+TC=x!;8!CqGNzl3_%?gFXlIjIyl*><` zlx?D|1LEbfU8Rs>ZViYdbtuFoP`3p?p(}M6$fj6iGCj6H%>@K%Qxc?fjnFP_=(rSY zRWRAq0r*g(${0&PTo=N`us>msP9`u|s8fkA9)fnEN~Ms2oekZ@vtpb>MzdVdSAhQj zh~Kc8jtTyFi3`=gxkE`Q*jWfFaJ@^hQ<|Ol!7aZ}`iW2$ zwM1k>@}SA54508aj&0OjT*-a-X8TeY^Q~)g_l$zT?Uz3IfoOq*)xjhG0Ao;yD$7

    5&>e@2i#4KXbj)Gl~S-97hK9( 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

    mD^thfJ2FT@UK6G2AG@UJ^n|MqX-@XH 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

    &NgTvgu3ChN0z+O4z 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 N`eb+iTJo={{{tUUmEiyY literal 0 HcmV?d00001 diff --git a/test/HtmlToOpenXml.Tests/Resources/smiley.gif b/test/HtmlToOpenXml.Tests/Resources/smiley.gif new file mode 100644 index 0000000000000000000000000000000000000000..0719d8e216b4711e73219977d6b5327da5146bd9 GIT binary patch literal 1595 zcmajc|5wuY0>|<92R;xAa!@`g1SS}kdaFU~Iy6flboAv2?#L=ae2@hXX|&DCTfFM@Gh+PM32G8yg!N zclgG~yT>OcE?x4DyR5E>8J7!pVWTdu3**qR@gU|J#aw=`cLKw_7#7BSqfKt}~r2 zjoS7CjlQ5*quE-$wY|}F_EO6(yZP%1fcNz9*Ui*QYhEM<*L?Y}IQFi_?`dcGfKCHKz2Y{Kp`oNI8<-OHy z-Hp`jvlTzx*Zn|2+wRIO!qZ9X4$rwQ_p7U}XV-iVXtkAa;ztgnVXoeT#nVBOZO4}S zs;d&Z<;vE5031)**k+Q9PicqNf3G%z0VSN0lb|PWHt| z*OL-?1Q_7P1%Fg`9QtNvX?VGhOG)00)ai{+q-#xwJZ`Ogw9|B6caJz<7 zDJ3;bXYjZ>K{U1P?f+2Z)N-aXNC6if?&Q~ic{bm7#FoYX{O_X9_du=oYGQH!Jx_xE z^lv{W|8nGx?x4KKgCeCOGnG4X3Ylkbl;x3W9pBVZkAmlptas>HCMpDr+-6PLjGZFg zE$V2Z0k!ary_F(u^KjjbjJ118OFMw3OP2`Z70JD7dd`jkcg;g)Vb8GfvT!~B;_Tid*EBevo*AcWBpTdnfKht}u#aCF=E?&TAo{GktMWU6vmp0jfyg&QHo0pH9?0 zI!B%Qy=tuY<8t}rmiU~ncYM6(0LP6jfA<39SwU5o7!7IcfQ4abmDw^4wi{O{ux(VN z)rkYmDQ_N~lylVgkKRr$IyDcciblpkisq@AR4ntMSluD3M1G3AfSed^;8sBKGSlMq zTn%fGM2Rg!A*L8L;dYNLCwwq6$Kk`MxPO^3~F6TS_by5HG zg{#XlZb+{ggcFG)d;jZHfj(;H)6Glk_J~Sg`f8Q9ovb`xSN5Z^w1hRa@|L-&u>a}4 zqE`zpTNug!llRlUm5|L%Rhk=9pAXOt=T#5X3Q>9sW7!&(C0-6l%yIyy$e}o!xp8Gh zrJ`GwmeqZ4 expectedBorderValue, IEnumerable expectedBorderWidth) + public void HtmlBorders_ShouldSucceed(string borderAtrribute, IEnumerable? expectedBorderValue, IEnumerable? expectedBorderWidth) { // we specify a style which doesn't handle borders converter.HtmlStyles.AddStyle(new Style { @@ -260,6 +260,12 @@ public void HtmlBorders_ShouldSucceed(string borderAtrribute, IEnumerable()); var borders = elements[0].GetFirstChild()?.TableBorders; + if (expectedBorderValue is null) + { + Assert.That(borders, Is.Null); + return; + } + Assert.That(borders, Is.Not.Null); Assert.That(borders.HasChild(), Is.True); Assert.That(new string?[] { borders.TopBorder?.Val?.InnerText, @@ -289,8 +295,8 @@ public void HtmlBorders_ShouldSucceed(string borderAtrribute, IEnumerable

  • @@ -341,7 +347,35 @@ public void TableCaptionAlign_ReturnsPositionedParagraph_AlignedWithTable(string Assert.That(elements, Has.Count.EqualTo(2)); var caption = (Paragraph) elements[1]; - Assert.That(caption.ParagraphProperties?.Justification?.Val?.ToString(), Is.EqualTo(expectedAlign)); + return caption.ParagraphProperties?.Justification?.Val?.ToString(); + } + + [TestCase("align='right'", ExpectedResult = "right")] + [TestCase("style='justify-self:center'", ExpectedResult = "center")] + [TestCase("style='margin-left:auto'", ExpectedResult = "right")] + [TestCase("style='margin-left:auto;margin-right:auto'", ExpectedResult = "center")] + public string? TableAlign_ReturnsTableJustification(string style) + { + var elements = converter.Parse(@$"
    Some table caption
    + +
    Cell 1.1
    "); + + Assert.That(elements, Has.Count.EqualTo(1)); + return elements[0].GetFirstChild()?.TableJustification?.Val?.ToString(); + } + + [TestCase("", ExpectedResult = "right")] + [TestCase("justify-self:center", ExpectedResult = "center")] + public string? NestedTableAlign_ReturnsTableOrParentJustification(string tableStyle) + { + var elements = converter.Parse(@$"
    + + +
    Cell 1.1
    +
    "); + + Assert.That(elements, Has.Count.EqualTo(1)); + return elements[0].GetFirstChild()?.TableJustification?.Val?.ToString(); } [Test] @@ -467,6 +501,7 @@ public void NestedTable_ReturnsTableInsideTable() var cell = elements[0].GetFirstChild()?.GetFirstChild(); Assert.That(cell, Is.Not.Null); Assert.That(cell.HasChild(), Is.True); + Assert.That(cell.HasChild(), Is.True, "Word requires at least a paragraph"); } [Test] @@ -487,8 +522,8 @@ public void Colstyle_ReturnsStyleAppliedOnCell() Assert.Multiple(() => { Assert.That(columns.Count(), Is.EqualTo(2)); - //Assert.That(columns.First().Width?.Value, Is.EqualTo("1500")); - //Assert.That(columns.Last().Width?.Value, Is.EqualTo("750")); + Assert.That(columns.First().Width?.Value, Is.EqualTo("1500")); + Assert.That(columns.Last().Width?.Value, Is.EqualTo("750")); }); var cells = elements[0].GetFirstChild()?.Elements(); @@ -627,5 +662,69 @@ public void CellBorders_ShouldNotPropagate_OnRuns() Assert.That(runs.Count(), Is.EqualTo(1)); Assert.That(runs.First().RunProperties?.Border, Is.Null); } + + [TestCase("100%", "pct", "5000")] + [TestCase("auto", "auto", "0")] + [TestCase("120px", "dxa", "1800")] + [TestCase("", "pct", "5000", Description = "Defaults to 100%")] + public void Width_ReturnsRefineTableWidth(string width, string expectedUnit, string expectedValue) + { + var elements = converter.Parse(@$"
    + +
    Placeholder
    "); + + Assert.That(elements, Has.Count.EqualTo(1)); + Assert.That(elements, Has.All.TypeOf()); + var tableWidth = elements[0].GetFirstChild()?.TableWidth; + Assert.That(tableWidth, Is.Not.Null); + Assert.Multiple(() => + { + Assert.That(tableWidth?.Type?.Value, Is.EqualTo(new TableWidthUnitValues(expectedUnit))); + Assert.That(tableWidth?.Width?.Value, Is.EqualTo(expectedValue)); + }); + } + + [Test] + public void ColWithPercentWidth_ReturnsRefineTableWidth() + { + var elements = converter.Parse(@"
    + + + + + + + +
    Cell 1Cell 2
    "); + + Assert.That(elements, Has.Count.EqualTo(1)); + Assert.That(elements, Has.All.TypeOf()); + var tableWidth = elements[0].GetFirstChild()?.TableWidth; + Assert.That(tableWidth, Is.Not.Null); + Assert.Multiple(() => + { + Assert.That(tableWidth?.Type?.Value, Is.EqualTo(TableWidthUnitValues.Pct)); + Assert.That(tableWidth?.Width?.Value, Is.EqualTo("3750")); + }); + + var columns = elements[0].GetFirstChild()?.Elements(); + Assert.That(columns, Is.Not.Null); + Assert.Multiple(() => + { + Assert.That(columns.Count(), Is.EqualTo(2)); + Assert.That(columns.First().Width?.Value, Is.EqualTo("1269")); + Assert.That(columns.Last().Width?.Value, Is.EqualTo("8365")); + }); + + var cells = elements[0].GetFirstChild()?.Elements(); + Assert.That(cells, Is.Not.Null); + Assert.Multiple(() => + { + Assert.That(cells.Count(), Is.EqualTo(2)); + // width on cell are on 5000 basis + Assert.That(cells.First().TableCellProperties?.TableCellWidth?.Width?.Value, Is.EqualTo("659")); + Assert.That(cells.Last().TableCellProperties?.TableCellWidth?.Width?.Value, Is.EqualTo("4346")); + }); + } } } \ No newline at end of file diff --git a/test/HtmlToOpenXml.Tests/Utilities/MockHttpMessageHandler.cs b/test/HtmlToOpenXml.Tests/Utilities/MockHttpMessageHandler.cs new file mode 100644 index 00000000..f964b44c --- /dev/null +++ b/test/HtmlToOpenXml.Tests/Utilities/MockHttpMessageHandler.cs @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2017 Deal Stream sàrl. All rights reserved + */ +using Moq; +using Moq.Protected; +using System.Net.Http; + +namespace HtmlToOpenXml.Tests +{ + public class MockHttpMessageHandler + { + private readonly Mock mockMessageHandler; + + + public MockHttpMessageHandler() + { + mockMessageHandler = new Mock(); + mockMessageHandler.Protected() + .Setup>("SendAsync", ItExpr.IsAny(), ItExpr.IsAny()) + .ReturnsAsync(new HttpResponseMessage()); + } + + public IO.IWebRequest GetWebRequest() + { + return new IO.DefaultWebRequest(new HttpClient(mockMessageHandler.Object)); + } + + public void AssertNeverCalled() + { + mockMessageHandler.Protected() + .Verify("SendAsync", Times.Never(), + ItExpr.IsAny(), ItExpr.IsAny()); + } + } +} \ No newline at end of file diff --git a/test/HtmlToOpenXml.Tests/Utilities/ProxyHttpMessageHandler.cs b/test/HtmlToOpenXml.Tests/Utilities/ProxyHttpMessageHandler.cs new file mode 100644 index 00000000..fdd08bf6 --- /dev/null +++ b/test/HtmlToOpenXml.Tests/Utilities/ProxyHttpMessageHandler.cs @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2017 Deal Stream sàrl. All rights reserved + */ +using System.Net.Http; + +namespace HtmlToOpenXml.Tests +{ + public class ProxyHttpMessageHandler : HttpMessageHandler + { + private readonly Func> _getResponseFunc; + + public ProxyHttpMessageHandler(Func> getResponseFunc) + { + _getResponseFunc = getResponseFunc; + } + + protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + return await _getResponseFunc(request.RequestUri!); + } + } +} \ No newline at end of file diff --git a/test/HtmlToOpenXml.Tests/WhitespaceTests.cs b/test/HtmlToOpenXml.Tests/WhitespaceTests.cs index 4a33b15c..7389c59f 100644 --- a/test/HtmlToOpenXml.Tests/WhitespaceTests.cs +++ b/test/HtmlToOpenXml.Tests/WhitespaceTests.cs @@ -14,7 +14,7 @@ public class WhitespaceTests : HtmlConverterTestBase public void ConsecutivePhrasing_ReturnsOneParagraphWithMulitpleRuns () { // the new line should generate a space between "bold" and "text" - var elements = converter.Parse("This is a bold\ntext"); + var elements = converter.Parse("This is a bold\ntext"); Assert.That(elements, Has.Count.EqualTo(1)); Assert.That(elements, Has.All.TypeOf()); Assert.That(elements[0].ChildElements, Is.All.TypeOf()); @@ -32,15 +32,21 @@ public void ConsecutiveDivs_ReturnsMultipleParagraphs () Assert.That(elements[1].InnerText, Is.EqualTo("World")); } + [TestCase("

    Hello \n World!

    ")] + [TestCase("

    Hello World!

    ")] + [TestCase("Hello World!")] [TestCase("

    Hello\r\n World!

    ")] [TestCase(" Hello \r\n World! ")] [TestCase(" Hello\r\n\r\nWorld! ")] + [TestCase("
    Hello World!
    ")] + [TestCase("
    \n Hello World!")] + [TestCase("

    Hello World!

    ")] public void Multiline_ReturnsCollapsedText (string html) { var elements = converter.Parse(html); - Assert.That(elements, Has.Count.EqualTo(1)); + Assert.That(elements, Has.Count.GreaterThanOrEqualTo(1)); Assert.That(elements, Has.All.TypeOf()); - Assert.That(elements[0].InnerText, Is.EqualTo("Hello World!")); + Assert.That(elements.Last().InnerText, Is.EqualTo("Hello World!")); } [TestCase("h1")] @@ -97,5 +103,36 @@ public void ConsecutivePhrasingWithBreak_ReturnsSecondLineWithNoSpaces() }); Assert.That(((Text)runs.ElementAt(2).FirstChild).Text, Is.EqualTo("World")); } + + [Test] + public void NoTextPhrasing_ShouldBeIgnored() + { + var elements = converter.Parse("

    Texte
    "); + Assert.That(elements, Has.Count.GreaterThanOrEqualTo(2)); + Assert.Multiple(() => + { + Assert.That(elements[0].GetFirstChild()?.HasChild(), Is.False, "Standalone line break is replaced with an empty paragraph"); + Assert.That(elements.Last().InnerText, Is.EqualTo("Texte")); + Assert.That(elements.Select(e => e.Elements().Count()), Has.All.EqualTo(1)); + }); + } + + [Test] + public void ConsecutiveSpans_WithNoSpace_ReturnsOneParagraphWithNoSpace () + { + var elements = converter.Parse("HelloWorld"); + Assert.That(elements, Has.Count.EqualTo(1)); + Assert.That(elements, Is.All.TypeOf()); + Assert.That(elements[0].InnerText, Is.EqualTo("HelloWorld")); + } + + [Test] + public void ConsecutiveSpans_WithSpaces_ReturnsOneParagraphWithNoSpace () + { + var elements = converter.Parse("Hello World"); + Assert.That(elements, Has.Count.EqualTo(1)); + Assert.That(elements, Is.All.TypeOf()); + Assert.That(elements[0].InnerText, Is.EqualTo("Hello World")); + } } } \ No newline at end of file