diff --git a/.gitignore b/.gitignore index 084d94fe1ac592b7dea47fd9b22a5626a3203721..c9cc0d5b020607eec9f53b5d87ac85c65f18cd0a 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ Source/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache Samples/SVGViewer/obj/ Samples/SVGViewer/bin/ Samples/SVGViewer/SVGViewer.OpenCover.Settings +*.dll +*.pdb diff --git a/Source/Css/CssQuery.cs b/Source/Css/CssQuery.cs new file mode 100644 index 0000000000000000000000000000000000000000..911125c9ad0cb72ebe4d27c3c66bfc715b672d1d --- /dev/null +++ b/Source/Css/CssQuery.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Fizzler; +using ExCSS; + +namespace Svg.Css +{ + internal static class CssQuery + { + public static IEnumerable QuerySelectorAll(this SvgElement elem, string selector) + { + var generator = new SelectorGenerator(new SvgElementOps()); + Fizzler.Parser.Parse(selector, generator); + return generator.Selector(Enumerable.Repeat(elem, 1)); + } + + public static int GetSpecificity(this BaseSelector selector) + { + if (selector is SimpleSelector) + { + var simpleCode = selector.ToString(); + if (simpleCode.StartsWith("#")) + { + return 1 << 12; + } + else if (simpleCode.StartsWith(".")) + { + return 1 << 8; + } + else + { + return 1 << 4; + } + } + return 0; + } + } +} diff --git a/Source/Css/SvgElementOps.cs b/Source/Css/SvgElementOps.cs new file mode 100644 index 0000000000000000000000000000000000000000..8928d4be5610104f2fa19385199748ea82959817 --- /dev/null +++ b/Source/Css/SvgElementOps.cs @@ -0,0 +1,186 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Fizzler; + +namespace Svg.Css +{ + internal class SvgElementOps : IElementOps + { + public Selector Type(NamespacePrefix prefix, string name) + { + var type = SvgElementFactory.AvailableElements.SingleOrDefault(e => e.ElementName == name); + return nodes => nodes.Where(n => n.GetType() == type.ElementType); + } + + public Selector Universal(NamespacePrefix prefix) + { + return nodes => nodes; + } + + public Selector Id(string id) + { + return nodes => nodes.Where(n => n.ID == id); + } + + public Selector Class(string clazz) + { + return AttributeIncludes(NamespacePrefix.None, "class", clazz); + } + + public Selector AttributeExists(NamespacePrefix prefix, string name) + { + return nodes => nodes.Where(n => n.Attributes.ContainsKey(name) || n.CustomAttributes.ContainsKey(name)); + } + + public Selector AttributeExact(NamespacePrefix prefix, string name, string value) + { + return nodes => nodes.Where(n => + { + string val = null; + object oval = null; + return (n.CustomAttributes.TryGetValue(name, out val) && val == value) || + (n.Attributes.TryGetValue(name, out oval) && oval.ToString() == value); + }); + } + + public Selector AttributeIncludes(NamespacePrefix prefix, string name, string value) + { + return nodes => nodes.Where(n => + { + string val = null; + object oval = null; + return (n.CustomAttributes.TryGetValue(name, out val) && val.Split(' ').Contains(value)) || + (n.Attributes.TryGetValue(name, out oval) && oval.ToString().Split(' ').Contains(value)); + }); + } + + public Selector AttributeDashMatch(NamespacePrefix prefix, string name, string value) + { + return string.IsNullOrEmpty(value) + ? (Selector)(nodes => Enumerable.Empty()) + : (nodes => nodes.Where(n => + { + string val = null; + object oval = null; + return (n.CustomAttributes.TryGetValue(name, out val) && val.Split('-').Contains(value)) || + (n.Attributes.TryGetValue(name, out oval) && oval.ToString().Split('-').Contains(value)); + })); + } + + public Selector AttributePrefixMatch(NamespacePrefix prefix, string name, string value) + { + return string.IsNullOrEmpty(value) + ? (Selector)(nodes => Enumerable.Empty()) + : (nodes => nodes.Where(n => + { + string val = null; + object oval = null; + return (n.CustomAttributes.TryGetValue(name, out val) && val.StartsWith(value)) || + (n.Attributes.TryGetValue(name, out oval) && oval.ToString().StartsWith(value)); + })); + } + + public Selector AttributeSuffixMatch(NamespacePrefix prefix, string name, string value) + { + return string.IsNullOrEmpty(value) + ? (Selector)(nodes => Enumerable.Empty()) + : (nodes => nodes.Where(n => + { + string val = null; + object oval = null; + return (n.CustomAttributes.TryGetValue(name, out val) && val.EndsWith(value)) || + (n.Attributes.TryGetValue(name, out oval) && oval.ToString().EndsWith(value)); + })); + } + + public Selector AttributeSubstring(NamespacePrefix prefix, string name, string value) + { + return string.IsNullOrEmpty(value) + ? (Selector)(nodes => Enumerable.Empty()) + : (nodes => nodes.Where(n => + { + string val = null; + object oval = null; + return (n.CustomAttributes.TryGetValue(name, out val) && val.Contains(value)) || + (n.Attributes.TryGetValue(name, out oval) && oval.ToString().Contains(value)); + })); + } + + public Selector FirstChild() + { + return nodes => nodes.Where(n => n.Parent == null || n.Parent.Children.First() == n); + } + + public Selector LastChild() + { + return nodes => nodes.Where(n => n.Parent == null || n.Parent.Children.Last() == n); + } + + private IEnumerable GetByIds(IList items, IEnumerable indices) + { + foreach (var i in indices) + { + if (i >= 0 && i < items.Count) yield return items[i]; + } + } + + public Selector NthChild(int a, int b) + { + return nodes => nodes.Where(n => n.Parent != null && GetByIds(n.Parent.Children, (from i in Enumerable.Range(0, n.Parent.Children.Count / a) select a * i + b)).Contains(n)); + } + + public Selector OnlyChild() + { + return nodes => nodes.Where(n => n.Parent == null || n.Parent.Children.Count == 1); + } + + public Selector Empty() + { + return nodes => nodes.Where(n => n.Children.Count == 0); + } + + public Selector Child() + { + return nodes => nodes.SelectMany(n => n.Children); + } + + public Selector Descendant() + { + return nodes => nodes.SelectMany(n => Descendants(n)); + } + + private IEnumerable Descendants(SvgElement elem) + { + foreach (var child in elem.Children) + { + yield return child; + foreach (var descendant in child.Descendants()) + { + yield return descendant; + } + } + } + + public Selector Adjacent() + { + return nodes => nodes.SelectMany(n => ElementsAfterSelf(n).Take(1)); + } + + public Selector GeneralSibling() + { + return nodes => nodes.SelectMany(n => ElementsAfterSelf(n)); + } + + private IEnumerable ElementsAfterSelf(SvgElement self) + { + return (self.Parent == null ? Enumerable.Empty() : self.Parent.Children.Skip(self.Parent.Children.IndexOf(self) + 1)); + } + + public Selector NthLastChild(int a, int b) + { + throw new NotImplementedException(); + } + } +} diff --git a/Source/External/ExCSS/IToString.cs b/Source/External/ExCSS/IToString.cs new file mode 100644 index 0000000000000000000000000000000000000000..778aea745f239238ad08c3e53afd8afdf3a16f99 --- /dev/null +++ b/Source/External/ExCSS/IToString.cs @@ -0,0 +1,7 @@ +namespace ExCSS +{ + public interface IToString + { + string ToString(bool friendlyFormat, int indentation = 0); + } +} \ No newline at end of file diff --git a/Source/External/ExCSS/Lexer.cs b/Source/External/ExCSS/Lexer.cs new file mode 100644 index 0000000000000000000000000000000000000000..6d81d2186e62171910143e3fe7156413171c4dde --- /dev/null +++ b/Source/External/ExCSS/Lexer.cs @@ -0,0 +1,1223 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text; +using ExCSS.Model; +using ExCSS.Model.TextBlocks; + +// ReSharper disable once CheckNamespace +namespace ExCSS +{ + sealed class Lexer + { + private readonly StringBuilder _buffer; + private readonly StylesheetReader _stylesheetReader; + private bool _ignoreWhitespace; + private bool _ignoreComments; + internal Action ErrorHandler { get; set; } + + internal Lexer(StylesheetReader source) + { + _buffer = new StringBuilder(); + _stylesheetReader = source; + + ErrorHandler = (err, msg) => { }; + } + + private Block DataBlock(char current) + { + switch (current) + { + case Specification.LineFeed: + case Specification.CarriageReturn: + case Specification.Tab: + case Specification.Space: + do + { + current = _stylesheetReader.Next; + } + while (current.IsSpaceCharacter()); + + if (_ignoreWhitespace) + { + return DataBlock(current); + } + + _stylesheetReader.Back(); + return SpecialCharacter.Whitespace; + + case Specification.DoubleQuote: + return DoubleQuoteString(_stylesheetReader.Next); + + case Specification.Hash: + return HashStart(_stylesheetReader.Next); + + case Specification.DollarSign: + current = _stylesheetReader.Next; + + return current == Specification.EqualSign + ? MatchBlock.Suffix + : Block.Delim(_stylesheetReader.Previous); + + case Specification.SingleQuote: + return SingleQuoteString(_stylesheetReader.Next); + + case Specification.ParenOpen: + return BracketBlock.OpenRound; + + case Specification.ParenClose: + return BracketBlock.CloseRound; + + case Specification.Asterisk: + current = _stylesheetReader.Next; + + return current == Specification.EqualSign + ? MatchBlock.Substring + : Block.Delim(_stylesheetReader.Previous); + + case Specification.PlusSign: + { + var nextFirst = _stylesheetReader.Next; + + if (nextFirst == Specification.EndOfFile) + { + _stylesheetReader.Back(); + } + else + { + var nextSEcond = _stylesheetReader.Next; + _stylesheetReader.Back(2); + + if (nextFirst.IsDigit() || (nextFirst == Specification.Period && nextSEcond.IsDigit())) + { + return NumberStart(current); + } + } + + return Block.Delim(current); + } + + case Specification.Comma: + return SpecialCharacter.Comma; + + case Specification.Period: + { + var c = _stylesheetReader.Next; + + return c.IsDigit() + ? NumberStart(_stylesheetReader.Previous) + : Block.Delim(_stylesheetReader.Previous); + } + + case Specification.MinusSign: + { + var nextFirst = _stylesheetReader.Next; + + if (nextFirst == Specification.EndOfFile) + { + _stylesheetReader.Back(); + } + else + { + var nextSecond = _stylesheetReader.Next; + _stylesheetReader.Back(2); + + if (nextFirst.IsDigit() || (nextFirst == Specification.Period && nextSecond.IsDigit())) + { + return NumberStart(current); + } + if (nextFirst.IsNameStart()) + { + return IdentStart(current); + } + if (nextFirst == Specification.ReverseSolidus && !nextSecond.IsLineBreak() && nextSecond != Specification.EndOfFile) + { + return IdentStart(current); + } + + if (nextFirst != Specification.MinusSign || nextSecond != Specification.GreaterThan) + { + return Block.Delim(current); + } + _stylesheetReader.Advance(2); + + return _ignoreComments + ? DataBlock(_stylesheetReader.Next) + : CommentBlock.Close; + } + + return Block.Delim(current); + } + + case Specification.Solidus: + + current = _stylesheetReader.Next; + + return current == Specification.Asterisk + ? Comment(_stylesheetReader.Next) + : Block.Delim(_stylesheetReader.Previous); + + case Specification.ReverseSolidus: + current = _stylesheetReader.Next; + + if (current.IsLineBreak() || current == Specification.EndOfFile) + { + ErrorHandler(current == Specification.EndOfFile + ? ParserError.EndOfFile + : ParserError.UnexpectedLineBreak, + ErrorMessages.LineBreakEof); + + return Block.Delim(_stylesheetReader.Previous); + } + + return IdentStart(_stylesheetReader.Previous); + + case Specification.Colon: + return SpecialCharacter.Colon; + + case Specification.Simicolon: + return SpecialCharacter.Semicolon; + + case Specification.LessThan: + current = _stylesheetReader.Next; + + if (current == Specification.Em) + { + current = _stylesheetReader.Next; + + if (current == Specification.MinusSign) + { + current = _stylesheetReader.Next; + + if (current == Specification.MinusSign) + { + return _ignoreComments + ? DataBlock(_stylesheetReader.Next) + : CommentBlock.Open; + } + + current = _stylesheetReader.Previous; + } + + current = _stylesheetReader.Previous; + } + + return Block.Delim(_stylesheetReader.Previous); + + case Specification.At: + return AtKeywordStart(_stylesheetReader.Next); + + case Specification.SquareBracketOpen: + return BracketBlock.OpenSquare; + + case Specification.SquareBracketClose: + return BracketBlock.CloseSquare; + + case Specification.Accent: + current = _stylesheetReader.Next; + + return current == Specification.EqualSign + ? MatchBlock.Prefix + : Block.Delim(_stylesheetReader.Previous); + + case Specification.CurlyBraceOpen: + return BracketBlock.OpenCurly; + + case Specification.CurlyBraceClose: + return BracketBlock.CloseCurly; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return NumberStart(current); + + case 'U': + case 'u': + current = _stylesheetReader.Next; + + if (current == Specification.PlusSign) + { + current = _stylesheetReader.Next; + + if (current.IsHex() || current == Specification.QuestionMark) + return UnicodeRange(current); + + current = _stylesheetReader.Previous; + } + + return IdentStart(_stylesheetReader.Previous); + + case Specification.Pipe: + current = _stylesheetReader.Next; + + if (current == Specification.EqualSign) + { + return MatchBlock.Dash; + } + if (current == Specification.Pipe) + { + return Block.Column; + } + + return Block.Delim(_stylesheetReader.Previous); + + case Specification.Tilde: + current = _stylesheetReader.Next; + + if (current == Specification.EqualSign) + { + return MatchBlock.Include; + } + + return Block.Delim(_stylesheetReader.Previous); + + case Specification.EndOfFile: + return null; + + case Specification.Em: + current = _stylesheetReader.Next; + + return current == Specification.EqualSign + ? MatchBlock.Not + : Block.Delim(_stylesheetReader.Previous); + + default: + return current.IsNameStart() + ? IdentStart(current) + : Block.Delim(current); + } + } + + private Block DoubleQuoteString(char current) + { + while (true) + { + switch (current) + { + case Specification.DoubleQuote: + case Specification.EndOfFile: + return StringBlock.Plain(FlushBuffer()); + + case Specification.FormFeed: + case Specification.LineFeed: + ErrorHandler(ParserError.UnexpectedLineBreak, ErrorMessages.DoubleQuotedString); + _stylesheetReader.Back(); + return StringBlock.Plain(FlushBuffer(), true); + + case Specification.ReverseSolidus: + current = _stylesheetReader.Next; + + if (current.IsLineBreak()) + { + _buffer.AppendLine(); + } + else if (current != Specification.EndOfFile) + { + _buffer.Append(ConsumeEscape(current)); + } + else + { + ErrorHandler(ParserError.EndOfFile, ErrorMessages.DoubleQuotedStringEof); + _stylesheetReader.Back(); + return StringBlock.Plain(FlushBuffer(), true); + } + + break; + + default: + _buffer.Append(current); + break; + } + + current = _stylesheetReader.Next; + } + } + + private Block SingleQuoteString(char current) + { + while (true) + { + switch (current) + { + case Specification.SingleQuote: + case Specification.EndOfFile: + return StringBlock.Plain(FlushBuffer()); + + case Specification.FormFeed: + case Specification.LineFeed: + ErrorHandler(ParserError.UnexpectedLineBreak, ErrorMessages.SingleQuotedString); + _stylesheetReader.Back(); + return (StringBlock.Plain(FlushBuffer(), true)); + + case Specification.ReverseSolidus: + current = _stylesheetReader.Next; + + if (current.IsLineBreak()) + { + _buffer.AppendLine(); + } + else if (current != Specification.EndOfFile) + { + _buffer.Append(ConsumeEscape(current)); + } + else + { + ErrorHandler(ParserError.EndOfFile, ErrorMessages.SingleQuotedStringEof); + _stylesheetReader.Back(); + return (StringBlock.Plain(FlushBuffer(), true)); + } + + break; + + default: + _buffer.Append(current); + break; + } + + current = _stylesheetReader.Next; + } + } + + private Block HashStart(char current) + { + if (current.IsNameStart()) + { + _buffer.Append(current); + return HashRest(_stylesheetReader.Next); + } + + if (IsValidEscape(current)) + { + current = _stylesheetReader.Next; + _buffer.Append(ConsumeEscape(current)); + return HashRest(_stylesheetReader.Next); + } + + if (current != Specification.ReverseSolidus) + { + _stylesheetReader.Back(); + return Block.Delim(Specification.Hash); + } + + ErrorHandler(ParserError.InvalidCharacter, ErrorMessages.InvalidCharacterAfterHash); + return Block.Delim(Specification.Hash); + } + + private Block HashRest(char current) + { + while (true) + { + if (current.IsName()) + { + _buffer.Append(current); + } + else if (IsValidEscape(current)) + { + current = _stylesheetReader.Next; + _buffer.Append(ConsumeEscape(current)); + } + else if (current == Specification.ReverseSolidus) + { + ErrorHandler(ParserError.InvalidCharacter, ErrorMessages.InvalidCharacterAfterHash); + + _stylesheetReader.Back(); + return SymbolBlock.Hash(FlushBuffer()); + } + else + { + _stylesheetReader.Back(); + return SymbolBlock.Hash(FlushBuffer()); + } + + current = _stylesheetReader.Next; + } + } + + private Block Comment(char current) + { + while (true) + { + switch (current) + { + case Specification.Asterisk: + current = _stylesheetReader.Next; + if (current == Specification.Solidus) + { + return DataBlock(_stylesheetReader.Next); + } + break; + case Specification.Solidus: + { + if (_stylesheetReader.Previous == Specification.Asterisk) + { + return DataBlock(_stylesheetReader.Next); + } + current = _stylesheetReader.Next; + break; + } + case Specification.EndOfFile: + + ErrorHandler(ParserError.EndOfFile, ErrorMessages.ExpectedCommentEnd); + + return DataBlock(current); + } + + current = _stylesheetReader.Next; + } + } + + private Block AtKeywordStart(char current) + { + if (current == Specification.MinusSign) + { + current = _stylesheetReader.Next; + + if (current.IsNameStart() || IsValidEscape(current)) + { + _buffer.Append(Specification.MinusSign); + return AtKeywordRest(current); + } + + _stylesheetReader.Back(2); + + return Block.Delim(Specification.At); + } + + if (current.IsNameStart()) + { + _buffer.Append(current); + return AtKeywordRest(_stylesheetReader.Next); + } + + if (IsValidEscape(current)) + { + current = _stylesheetReader.Next; + _buffer.Append(ConsumeEscape(current)); + return AtKeywordRest(_stylesheetReader.Next); + } + + _stylesheetReader.Back(); + return Block.Delim(Specification.At); + + } + + private Block AtKeywordRest(char current) + { + while (true) + { + if (current.IsName()) + { + _buffer.Append(current); + } + else if (IsValidEscape(current)) + { + current = _stylesheetReader.Next; + _buffer.Append(ConsumeEscape(current)); + } + else + { + _stylesheetReader.Back(); + return SymbolBlock.At(FlushBuffer()); + } + + current = _stylesheetReader.Next; + } + } + + private Block IdentStart(char current) + { + if (current == Specification.MinusSign) + { + current = _stylesheetReader.Next; + + if (current.IsNameStart() || IsValidEscape(current)) + { + _buffer.Append(Specification.MinusSign); + return IdentRest(current); + } + + _stylesheetReader.Back(); + return Block.Delim(Specification.MinusSign); + } + + if (current.IsNameStart()) + { + _buffer.Append(current); + return IdentRest(_stylesheetReader.Next); + } + + if (current != Specification.ReverseSolidus) + { + return DataBlock(current); + } + + if (!IsValidEscape(current)) + { + return DataBlock(current); + } + + current = _stylesheetReader.Next; + _buffer.Append(ConsumeEscape(current)); + return IdentRest(_stylesheetReader.Next); + } + + private Block IdentRest(char current) + { + while (true) + { + if (current.IsName()) + { + _buffer.Append(current); + } + else if (IsValidEscape(current)) + { + current = _stylesheetReader.Next; + _buffer.Append(ConsumeEscape(current)); + } + else if (current == Specification.ParenOpen) + { + switch (_buffer.ToString().ToLower()) + { + case "url": + _buffer.Length = 0; + return UrlStart(_stylesheetReader.Next);//, GrammarSegment.Url); + + case "domain": + _buffer.Length = 0; + return UrlStart(_stylesheetReader.Next);//, GrammarSegment.Domain); + + case "url-prefix": + _buffer.Length = 0; + return UrlStart(_stylesheetReader.Next);//, GrammarSegment.UrlPrefix); + + default: + return SymbolBlock.Function(FlushBuffer()); + } + + } + else + { + _stylesheetReader.Back(); + return SymbolBlock.Ident(FlushBuffer()); + } + + current = _stylesheetReader.Next; + } + } + + private Block NumberStart(char current) + { + while (true) + { + switch (current) + { + case Specification.MinusSign: + case Specification.PlusSign: + _buffer.Append(current); + current = _stylesheetReader.Next; + if (current == Specification.Period) + { + _buffer.Append(current); + _buffer.Append(_stylesheetReader.Next); + + return NumberFraction(_stylesheetReader.Next); + } + _buffer.Append(current); + return NumberRest(_stylesheetReader.Next); + + case Specification.Period: + _buffer.Append(current); + _buffer.Append(_stylesheetReader.Next); + return NumberFraction(_stylesheetReader.Next); + + default: + if (current.IsDigit()) + { + _buffer.Append(current); + return NumberRest(_stylesheetReader.Next); + } + break; + } + + current = _stylesheetReader.Next; + } + } + + private Block NumberRest(char current) + { + while (true) + { + if (current.IsDigit()) + { + _buffer.Append(current); + } + else if (current.IsNameStart()) + { + var number = FlushBuffer(); + _buffer.Append(current); + return Dimension(_stylesheetReader.Next, number); + } + else if (IsValidEscape(current)) + { + current = _stylesheetReader.Next; + var number = FlushBuffer(); + _buffer.Append(ConsumeEscape(current)); + return Dimension(_stylesheetReader.Next, number); + } + else + { + break; + } + + current = _stylesheetReader.Next; + } + + switch (current) + { + case Specification.Period: + current = _stylesheetReader.Next; + + if (current.IsDigit()) + { + _buffer.Append(Specification.Period).Append(current); + return NumberFraction(_stylesheetReader.Next); + } + + _stylesheetReader.Back(); + return Block.Number(FlushBuffer()); + + case '%': + return UnitBlock.Percentage(FlushBuffer()); + + case 'e': + case 'E': + return NumberExponential(current); + + case Specification.MinusSign: + return NumberDash(current); + + default: + _stylesheetReader.Back(); + return Block.Number(FlushBuffer()); + } + } + + private Block NumberFraction(char current) + { + while (true) + { + if (current.IsDigit()) + { + _buffer.Append(current); + } + else if (current.IsNameStart()) + { + var number = FlushBuffer(); + _buffer.Append(current); + + return Dimension(_stylesheetReader.Next, number); + } + else if (IsValidEscape(current)) + { + current = _stylesheetReader.Next; + var number = FlushBuffer(); + _buffer.Append(ConsumeEscape(current)); + + return Dimension(_stylesheetReader.Next, number); + } + else + { + break; + } + + current = _stylesheetReader.Next; + } + + switch (current) + { + case 'e': + case 'E': + return NumberExponential(current); + + case '%': + return UnitBlock.Percentage(FlushBuffer()); + + case Specification.MinusSign: + return NumberDash(current); + + default: + _stylesheetReader.Back(); + return Block.Number(FlushBuffer()); + } + } + + private Block Dimension(char current, string number) + { + while (true) + { + if (current.IsName()) + { + _buffer.Append(current); + } + else if (IsValidEscape(current)) + { + current = _stylesheetReader.Next; + _buffer.Append(ConsumeEscape(current)); + } + else + { + _stylesheetReader.Back(); + return UnitBlock.Dimension(number, FlushBuffer()); + } + + current = _stylesheetReader.Next; + } + } + + private Block SciNotation(char current) + { + while (true) + { + if (current.IsDigit()) + { + _buffer.Append(current); + } + else + { + _stylesheetReader.Back(); + return Block.Number(FlushBuffer()); + } + + current = _stylesheetReader.Next; + } + } + + private Block UrlStart(char current) + { + while (current.IsSpaceCharacter()) + { + current = _stylesheetReader.Next; + } + + switch (current) + { + case Specification.EndOfFile: + ErrorHandler(ParserError.EndOfFile, ErrorMessages.InvalidUrlEnd); + return StringBlock.Url(string.Empty, true); + + case Specification.DoubleQuote: + return DoubleQuotedUrl(_stylesheetReader.Next); + + case Specification.SingleQuote: + return SingleQuoteUrl(_stylesheetReader.Next); + + case ')': + return StringBlock.Url(string.Empty); + + default: + return UnquotedUrl(current); + } + } + + private Block DoubleQuotedUrl(char current) + { + while (true) + { + if (current.IsLineBreak()) + { + ErrorHandler(ParserError.UnexpectedLineBreak, ErrorMessages.InvalidUrlEnd); + return BadUrl(_stylesheetReader.Next); + } + + if (Specification.EndOfFile == current) + { + return StringBlock.Url(FlushBuffer()); + } + + if (current == Specification.DoubleQuote) + { + return UrlEnd(_stylesheetReader.Next); + } + + if (current == Specification.ReverseSolidus) + { + current = _stylesheetReader.Next; + + if (current == Specification.EndOfFile) + { + _stylesheetReader.Back(2); + ErrorHandler(ParserError.EndOfFile, ErrorMessages.InvalidUrlEnd); + return StringBlock.Url(FlushBuffer(), true); + } + + if (current.IsLineBreak()) + { + _buffer.AppendLine(); + } + else + { + _buffer.Append(ConsumeEscape(current)); + } + } + else + { + _buffer.Append(current); + } + + current = _stylesheetReader.Next; + } + } + + private Block SingleQuoteUrl(char current) + { + while (true) + { + if (current.IsLineBreak()) + { + ErrorHandler(ParserError.UnexpectedLineBreak, ErrorMessages.SingleQuotedString); + return BadUrl(_stylesheetReader.Next); + } + + if (Specification.EndOfFile == current) + { + return StringBlock.Url(FlushBuffer()); + } + + if (current == Specification.SingleQuote) + { + return UrlEnd(_stylesheetReader.Next); + } + + if (current == Specification.ReverseSolidus) + { + current = _stylesheetReader.Next; + + if (current == Specification.EndOfFile) + { + _stylesheetReader.Back(2); + ErrorHandler(ParserError.EndOfFile, ErrorMessages.SingleQuotedString); + return StringBlock.Url(FlushBuffer(), true); + } + + if (current.IsLineBreak()) + { + _buffer.AppendLine(); + } + else + { + _buffer.Append(ConsumeEscape(current)); + } + } + else + { + _buffer.Append(current); + } + + current = _stylesheetReader.Next; + } + } + + private Block UnquotedUrl(char current) + { + while (true) + { + if (current.IsSpaceCharacter()) + { + return UrlEnd(_stylesheetReader.Next); + } + + if (current == Specification.ParenClose || current == Specification.EndOfFile) + { + return StringBlock.Url(FlushBuffer()); + } + + if (current == Specification.DoubleQuote || current == Specification.SingleQuote || + current == Specification.ParenOpen || current.IsNonPrintable()) + { + ErrorHandler(ParserError.InvalidCharacter, ErrorMessages.InvalidUrlQuote); + return BadUrl(_stylesheetReader.Next); + } + + if (current == Specification.ReverseSolidus) + { + if (IsValidEscape(current)) + { + current = _stylesheetReader.Next; + _buffer.Append(ConsumeEscape(current)); + } + else + { + ErrorHandler(ParserError.InvalidCharacter, ErrorMessages.InvalidUrlCharacter); + return BadUrl(_stylesheetReader.Next); + } + } + else + { + _buffer.Append(current); + } + + current = _stylesheetReader.Next; + } + } + + private Block UrlEnd(char current) + { + while (true) + { + if (current == Specification.ParenClose) + { + return StringBlock.Url(FlushBuffer()); + } + + if (!current.IsSpaceCharacter()) + { + ErrorHandler(ParserError.InvalidCharacter, ErrorMessages.InvalidUrlCharacter); + return BadUrl(current); + } + + current = _stylesheetReader.Next; + } + } + + private Block BadUrl(char current) + { + while (true) + { + if (current == Specification.EndOfFile) + { + ErrorHandler(ParserError.EndOfFile, ErrorMessages.InvalidUrlEnd); + + return StringBlock.Url(FlushBuffer(), true); + } + + if (current == Specification.ParenClose) + { + return StringBlock.Url(FlushBuffer(), true); + } + + if (IsValidEscape(current)) + { + current = _stylesheetReader.Next; + _buffer.Append(ConsumeEscape(current)); + } + + current = _stylesheetReader.Next; + } + } + + private Block UnicodeRange(char current) + { + for (var i = 0; i < 6; i++) + { + if (!current.IsHex()) + { + break; + } + + _buffer.Append(current); + current = _stylesheetReader.Next; + } + + if (_buffer.Length != 6) + { + for (var i = 0; i < 6 - _buffer.Length; i++) + { + if (current != Specification.QuestionMark) + { + current = _stylesheetReader.Previous; + break; + } + + _buffer.Append(current); + current = _stylesheetReader.Next; + } + + var range = FlushBuffer(); + var start = range.Replace(Specification.QuestionMark, '0'); + var end = range.Replace(Specification.QuestionMark, 'F'); + return Block.Range(start, end); + } + + if (current == Specification.MinusSign) + { + current = _stylesheetReader.Next; + + if (current.IsHex()) + { + var start = _buffer.ToString(); + _buffer.Length = 0; + + for (var i = 0; i < 6; i++) + { + if (!current.IsHex()) + { + current = _stylesheetReader.Previous; + break; + } + + _buffer.Append(current); + current = _stylesheetReader.Next; + } + + var end = FlushBuffer(); + return Block.Range(start, end); + } + + _stylesheetReader.Back(2); + return Block.Range(FlushBuffer(), null); + + } + + _stylesheetReader.Back(); + return Block.Range(FlushBuffer(), null); + } + + private string FlushBuffer() + { + var value = _buffer.ToString(); + _buffer.Length = 0; + return value; + } + + private Block NumberExponential(char current) + { + current = _stylesheetReader.Next; + + if (current.IsDigit()) + { + _buffer.Append('e').Append(current); + return SciNotation(_stylesheetReader.Next); + } + + if (current == Specification.PlusSign || current == Specification.MinusSign) + { + var op = current; + current = _stylesheetReader.Next; + + if (current.IsDigit()) + { + _buffer.Append('e').Append(op).Append(current); + return SciNotation(_stylesheetReader.Next); + } + + _stylesheetReader.Back(); + } + + current = _stylesheetReader.Previous; + var number = FlushBuffer(); + _buffer.Append(current); + + return Dimension(_stylesheetReader.Next, number); + } + + private Block NumberDash(char current) + { + current = _stylesheetReader.Next; + + if (current.IsNameStart()) + { + var number = FlushBuffer(); + _buffer.Append(Specification.MinusSign).Append(current); + return Dimension(_stylesheetReader.Next, number); + } + + if (IsValidEscape(current)) + { + current = _stylesheetReader.Next; + var number = FlushBuffer(); + _buffer.Append(Specification.MinusSign).Append(ConsumeEscape(current)); + return Dimension(_stylesheetReader.Next, number); + } + + _stylesheetReader.Back(2); + return Block.Number(FlushBuffer()); + } + + private string ConsumeEscape(char current) + { + if (!current.IsHex()) + { + return current.ToString(CultureInfo.InvariantCulture); + } + + var escape = new List(); + + for (var i = 0; i < 6; i++) + { + escape.Add(current); + current = _stylesheetReader.Next; + + if (!current.IsHex()) + { + break; + } + } + + current = _stylesheetReader.Previous; + var code = int.Parse(new string(escape.ToArray()), NumberStyles.HexNumber); + return Char.ConvertFromUtf32(code); + } + + private bool IsValidEscape(char current) + { + if (current != Specification.ReverseSolidus) + { + return false; + } + + current = _stylesheetReader.Next; + _stylesheetReader.Back(); + + if (current == Specification.EndOfFile) + { + return false; + } + + return !current.IsLineBreak(); + } + + internal bool IgnoreWhitespace + { + get { return _ignoreWhitespace; } + set { _ignoreWhitespace = value; } + } + + internal bool IgnoreComments + { + get { return _ignoreComments; } + set { _ignoreComments = value; } + } + + internal StylesheetReader Stream + { + get { return _stylesheetReader; } + } + + internal IEnumerable Tokens + { + get + { + while (true) + { + var token = DataBlock(_stylesheetReader.Current); + + if (token == null) + { + yield break; + } + + _stylesheetReader.Advance(); + + yield return token; + } + } + } + } +} diff --git a/Source/External/ExCSS/Model/Enumerations.cs b/Source/External/ExCSS/Model/Enumerations.cs new file mode 100644 index 0000000000000000000000000000000000000000..347565fe92db6d9cb23e26a80a0c6e77fa2ed72b --- /dev/null +++ b/Source/External/ExCSS/Model/Enumerations.cs @@ -0,0 +1,257 @@ + +// ReSharper disable once CheckNamespace +namespace ExCSS +{ + internal static class RuleTypes + { + internal const string CharacterSet = "charset"; + internal const string Keyframes = "keyframes"; + internal const string Media = "media"; + internal const string Page = "page"; + internal const string Import = "import"; + internal const string FontFace = "font-face"; + internal const string Namespace = "namespace"; + internal const string Supports = "supports"; + internal const string Document = "document"; + } + + internal static class PseudoSelectorPrefix + { + internal const string NthChildOdd = "odd"; + internal const string NthChildEven = "even"; + internal const string NthChildN = "n"; + internal const string PseudoFunctionNthchild = "nth-child"; + internal const string PseudoFunctionNthlastchild = "nth-last-child"; + internal const string PseudoFunctionNthOfType = "nth-of-type"; + internal const string PseudoFunctionNthLastOfType = "nth-last-of-type"; + internal const string PseudoRoot = "root"; + internal const string PseudoFirstOfType = "first-of-type"; + internal const string PseudoLastoftype = "last-of-type"; + internal const string PseudoOnlychild = "only-child"; + internal const string PseudoOnlyOfType = "only-of-type"; + internal const string PseudoFirstchild = "first-child"; + internal const string PseudoLastchild = "last-child"; + internal const string PseudoEmpty = "empty"; + internal const string PseudoLink = "link"; + internal const string PseudoVisited = "visited"; + internal const string PseudoActive = "active"; + internal const string PseudoHover = "hover"; + internal const string PseudoFocus = "focus"; + internal const string PseudoTarget = "target"; + internal const string PseudoEnabled = "enabled"; + internal const string PseudoDisabled = "disabled"; + internal const string PseudoChecked = "checked"; + internal const string PseudoUnchecked = "unchecked"; + internal const string PseudoIndeterminate = "indeterminate"; + internal const string PseudoDefault = "default"; + internal const string PseudoValid = "valid"; + internal const string PseudoInvalid = "invalid"; + internal const string PseudoRequired = "required"; + internal const string PseudoInrange = "in-range"; + internal const string PseudoOutofrange = "out-of-range"; + internal const string PseudoOptional = "optional"; + internal const string PseudoReadonly = "read-only"; + internal const string PseudoReadwrite = "read-write"; + internal const string PseudoFunctionDir = "dir"; + + internal const string PseudoFunctionNot = "not"; + internal const string PseudoFunctionLang = "lang"; + internal const string PseudoFunctionContains = "contains"; + internal const string PseudoElementBefore = "before"; + internal const string PseudoElementAfter = "after"; + internal const string PseudoElementSelection = "selection"; + internal const string PseudoElementFirstline = "first-line"; + internal const string PseudoElementFirstletter = "first-letter"; + } + + internal static class ErrorMessages + { + internal const string InvalidCharacter = "Invalid character detected."; + internal const string LineBreakEof = "Unexpected line break or EOF."; + internal const string UnexpectedCommentToken = "The input element is unexpected and has been ignored."; + internal const string DoubleQuotedString = "Expected double quoted string to terminate before form feed or line feed."; + internal const string DoubleQuotedStringEof = "Expected double quoted string to terminate before end of file."; + internal const string SingleQuotedString = "Expected single quoted string to terminate before form feed or line feed."; + internal const string SingleQuotedStringEof = "Expected single quoted string to terminate before end of file."; + internal const string InvalidCharacterAfterHash = "Invalid character after #."; + internal const string InvalidIdentAfterHash = "Invalid character after #."; + internal const string InvalidUrlEnd = "Expected URL to terminate before line break or end of file."; + internal const string InvalidUrlQuote = "Expected quotation or open paren in URL."; + internal const string InvalidUrlCharacter = "Invalid character in URL."; + internal const string ExpectedCommentEnd = "Expected comment to close before end of file."; + internal const string Default = "An unexpected error occurred."; + } + + public enum Combinator + { + Child, + Descendent, + AdjacentSibling, + Sibling, + Namespace + } + + internal enum GrammarSegment + { + String, + Url, + UrlPrefix, + Domain, + Hash, //# + AtRule, //@ + Ident, + Function, + Number, + Percentage, + Dimension, + Range, + CommentOpen, + CommentClose, + Column, + Delimiter, + IncludeMatch, //~= + DashMatch, // |= + PrefixMatch, // ^= + SuffixMatch, // $= + SubstringMatch, // *= + NegationMatch, // != + ParenOpen, + ParenClose, + CurlyBraceOpen, + CurlyBracketClose, + SquareBraceOpen, + SquareBracketClose, + Colon, + Comma, + Semicolon, + Whitespace + } + + public enum RuleType + { + Unknown = 0, + Style = 1, + Charset = 2, + Import = 3, + Media = 4, + FontFace = 5, + Page = 6, + Keyframes = 7, + Keyframe = 8, + Namespace = 10, + CounterStyle = 11, + Supports = 12, + Document = 13, + FontFeatureValues = 14, + Viewport = 15, + RegionStyle = 16 + } + + public enum UnitType + { + Unknown = 0, + Number = 1, + Percentage = 2, + Ems = 3, + Exs = 4, + Pixel = 5, + Centimeter = 6, + Millimeter = 7, + Inch = 8, + Point = 9, + Percent = 10, + Degree = 11, + Radian = 12, + Grad = 13, + Millisecond = 14, + Second = 15, + Hertz = 16, + KiloHertz = 17, + Dimension = 18, + String = 19, + Uri = 20, + Ident = 21, + Attribute = 22, + Counter = 23, + Rect = 24, + RGB = 25, + ViewportWidth = 26, + ViewportHeight = 28, + ViewportMin = 29, + ViewportMax = 30, + Turn = 31, + } + + public enum DocumentFunction + { + Url, + UrlPrefix, + Domain, + RegExp + } + + public enum DirectionMode + { + LeftToRight, + RightToLeft + } + + public enum ParserError + { + EndOfFile, + UnexpectedLineBreak, + InvalidCharacter, + UnexpectedCommentToken + } + + internal enum SelectorOperation + { + Data, + Attribute, + AttributeOperator, + AttributeValue, + AttributeEnd, + Class, + PseudoClass, + PseudoClassFunction, + PseudoClassFunctionEnd, + PseudoElement + } + + internal enum ParsingContext + { + DataBlock, + InSelector, + InDeclaration, + AfterProperty, + BeforeValue, + InValuePool, + InValueList, + InSingleValue, + InMediaList, + InMediaValue, + BeforeImport, + BeforeCharset, + BeforeNamespacePrefix, + AfterNamespacePrefix, + BeforeFontFace, + FontfaceData, + FontfaceProperty, + AfterInstruction, + InCondition, + BeforeKeyframesName, + BeforeKeyframesData, + KeyframesData, + InKeyframeText, + BeforePageSelector, + BeforeDocumentFunction, + InDocumentFunction, + AfterDocumentFunction, + BetweenDocumentFunctions, + InUnknown, + ValueImportant, + AfterValue, + InHexValue, + InFunction + } +} diff --git a/Source/External/ExCSS/Model/Extensions/CharacterExtensions.cs b/Source/External/ExCSS/Model/Extensions/CharacterExtensions.cs new file mode 100644 index 0000000000000000000000000000000000000000..dba314f3546906954e2e8c8cb072065900da4b6f --- /dev/null +++ b/Source/External/ExCSS/Model/Extensions/CharacterExtensions.cs @@ -0,0 +1,80 @@ +using System.Collections.Generic; + +namespace ExCSS.Model.Extensions +{ + static class CharacterExtensions + { + public static int FromHex(this char character) + { + return character.IsDigit() ? character - 0x30 : character - (character.IsLowercaseAscii() ? 0x57 : 0x37); + } + + public static string TrimArray(this char[] array) + { + var start = 0; + var end = array.Length - 1; + + while (start < array.Length && array[start].IsSpaceCharacter()) + { + start++; + } + + while (end > start && array[end].IsSpaceCharacter()) + { + end--; + } + + return new string(array, start, 1 + end - start); + } + + public static string[] SplitOnCommas(this string value) + { + var list = new List(); + var buffer = new List(); + var chars = value.ToCharArray(); + + for (var i = 0; i <= chars.Length; i++) + { + if (i == chars.Length || chars[i] == ',') + { + if (buffer.Count <= 0) + { + continue; + } + var token = buffer.ToArray().TrimArray(); + + if (token.Length != 0) + { + list.Add(token); + } + + buffer.Clear(); + } + else + { + buffer.Add(chars[i]); + } + } + + return list.ToArray(); + } + + public static string ToHex(this byte num) + { + var characters = new char[2]; + var rem = num >> 4; + + characters[0] = (char)(rem + (rem < 10 ? 48 : 55)); + rem = num - 16 * rem; + characters[1] = (char)(rem + (rem < 10 ? 48 : 55)); + + return new string(characters); + } + + public static char ToHexChar(this byte num) + { + var rem = num & 0x0F; + return (char)(rem + (rem < 10 ? 48 : 55)); + } + } +} \ No newline at end of file diff --git a/Source/External/ExCSS/Model/Extensions/StringExtensions.cs b/Source/External/ExCSS/Model/Extensions/StringExtensions.cs new file mode 100644 index 0000000000000000000000000000000000000000..76eb2eecc2869bc90b9a614ea5b6dfd769e6e454 --- /dev/null +++ b/Source/External/ExCSS/Model/Extensions/StringExtensions.cs @@ -0,0 +1,59 @@ +using System; +using System.Text; + +namespace ExCSS.Model.Extensions +{ + public static class StringExtensions + { + public static string Indent(this string value, bool friendlyForamt, int indentation) + { + if (!friendlyForamt) + { + return value; + } + + var tabs = new StringBuilder(); + for (var i = 0; i < indentation; i++) + { + tabs.Append("\t"); + } + + return string.Format("{0}{1}", tabs, value); + } + + public static string NewLineIndent(this string value, bool friendlyFormat, int indentation) + { + if (!friendlyFormat) + { + return value; + } + + return Environment.NewLine + value.Indent(true, indentation); + } + + public static string TrimFirstLine(this string value) + { + return new StringBuilder(value).TrimFirstLine().ToString(); + } + + public static StringBuilder TrimLastLine(this StringBuilder builder) + { + while (builder[builder.Length-1] == '\r' || builder[builder.Length-1] == '\n' || builder[builder.Length-1] == '\t') + { + builder.Remove(builder.Length - 1, 1); + } + + return builder; + } + + public static StringBuilder TrimFirstLine(this StringBuilder builder) + { + while (builder[0] == '\r' || builder[0] == '\n' || builder[0] == '\t') + { + builder.Remove(0, 1); + } + + return builder; + } + } +} diff --git a/Source/External/ExCSS/Model/FunctionBuffer.cs b/Source/External/ExCSS/Model/FunctionBuffer.cs new file mode 100644 index 0000000000000000000000000000000000000000..cdc9f070a4b03488ae3a36fec7490ad3f03ba6b5 --- /dev/null +++ b/Source/External/ExCSS/Model/FunctionBuffer.cs @@ -0,0 +1,137 @@ +using System; +using System.Collections.Generic; + +namespace ExCSS.Model +{ + internal class FunctionBuffer + { + private readonly string _function; + private readonly List _termList; + private Term _term; + + internal FunctionBuffer(string function) + { + _termList = new List(); + _function = function; + } + + public List TermList + { + get { return _termList; } + } + + public Term Term + { + get { return _term; } + set { _term = value; } + } + + public void Include() + { + if (_term != null) + { + _termList.Add(_term); + } + + _term = null; + } + + public Term Done() + { + Include(); + return BuildFunctionTerm(_function, _termList); + } + + private Term BuildFunctionTerm(string name, List terms) + { + switch (name) + { + case "rgb": + { + if (terms.Count == 3) + { + if (CheckNumber(terms[0]) && + CheckNumber(terms[1]) && + CheckNumber(terms[2])) + { + return HtmlColor.FromRgb( + ToByte(terms[0]), + ToByte(terms[1]), + ToByte(terms[2])); + } + } + + break; + } + case "rgba": + { + if (terms.Count == 4) + { + if (CheckNumber(terms[0]) && + CheckNumber(terms[1]) && + CheckNumber(terms[2]) && + CheckNumber(terms[3])) + { + return HtmlColor.FromRgba( + ToByte(terms[0]), + ToByte(terms[1]), + ToByte(terms[2]), + ToSingle(terms[3])); + } + } + + break; + } + case "hsl": + { + if (_termList.Count == 3) + { + if (CheckNumber(terms[0]) && + CheckNumber(terms[1]) && + CheckNumber(terms[2])) + { + return HtmlColor.FromHsl( + ToSingle(terms[0]), + ToSingle(terms[1]), + ToSingle(terms[2])); + } + } + + break; + } + } + + return new GenericFunction(name, terms); + } + + private static bool CheckNumber(Term cssValue) + { + return (cssValue is PrimitiveTerm && + ((PrimitiveTerm)cssValue).PrimitiveType == UnitType.Number); + } + + private static Single ToSingle(Term cssValue) + { + var value = ((PrimitiveTerm)cssValue).GetFloatValue(UnitType.Number); + + return value.HasValue + ? value.Value + : 0f; + } + + private static byte ToByte(Single? value) + { + if (value.HasValue) + { + return (byte)Math.Min(Math.Max(value.Value, 0), 255); + } + + return 0; + } + + private static byte ToByte(Term cssValue) + { + return ToByte(((PrimitiveTerm)cssValue).GetFloatValue(UnitType.Number)); + } + } +} \ No newline at end of file diff --git a/Source/External/ExCSS/Model/HtmlEncoding.cs b/Source/External/ExCSS/Model/HtmlEncoding.cs new file mode 100644 index 0000000000000000000000000000000000000000..bf04f2bd0cd346c661f7dba161d244746525ce95 --- /dev/null +++ b/Source/External/ExCSS/Model/HtmlEncoding.cs @@ -0,0 +1,459 @@ +using System; +using System.Text; + +namespace ExCSS.Model +{ + internal static class HtmlEncoding + { + internal static string Extract(string content) + { + var position = 0; + content = content.ToLower(); + + for (var i = position; i < content.Length - 7; i++) + { + if (!content.Substring(i).StartsWith("charset")) + { + continue; + } + + position = i + 7; + break; + } + + if (position <= 0 || position >= content.Length) + { + return string.Empty; + } + + for (var i = position; i < content.Length - 1; i++) + { + if (content[i].IsSpaceCharacter()) + { + position++; + } + else + { + break; + } + } + + if (content[position] != Specification.EqualSign) + { + return Extract(content.Substring(position)); + } + + position++; + + for (var i = position; i < content.Length; i++) + { + if (content[i].IsSpaceCharacter()) + { + position++; + } + else + { + break; + } + } + + if (position >= content.Length) + { + return string.Empty; + } + + switch (content[position]) + { + case Specification.DoubleQuote: + { + content = content.Substring(position + 1); + var index = content.IndexOf(Specification.DoubleQuote); + + if (index != -1) + { + return content.Substring(0, index); + } + } + break; + + case Specification.SingleQuote: + { + content = content.Substring(position + 1); + var index = content.IndexOf(Specification.SingleQuote); + + if (index != -1) + { + return content.Substring(0, index); + } + } + break; + + default: + { + content = content.Substring(position); + var index = 0; + + for (var i = 0; i < content.Length; i++) + { + if (content[i].IsSpaceCharacter()) + { + break; + } + + if (content[i] == ';') + { + break; + } + + index++; + } + + return content.Substring(0, index); + } + } + + return string.Empty; + } + + internal static bool IsSupported(string charset) + { + return Resolve(charset) != null; + } + + internal static Encoding Resolve(string charset) + { + charset = charset.ToLower(); + + switch (charset) + { + case "unicode-1-1-utf-8": + case "utf-8": + case "utf8": + return Encoding.UTF8; + + case "utf-16be": + return Encoding.BigEndianUnicode; + + case "utf-16": + case "utf-16le": + return Encoding.Unicode; + + case "dos-874": + case "iso-8859-11": + case "iso8859-11": + case "iso885911": + case "tis-620": + case "windows-874": + return Encoding.GetEncoding("windows-874"); + + case "cp1250": + case "windows-1250": + case "x-cp1250": + return Encoding.GetEncoding("windows-1250"); + + case "cp1251": + case "windows-1251": + case "x-cp1251": + return Encoding.GetEncoding("windows-1251"); + + case "ansi_x3.4-1968": + case "ascii": + case "cp1252": + case "cp819": + case "csisolatin1": + case "ibm819": + case "iso-8859-1": + case "iso-ir-100": + case "iso8859-1": + case "iso88591": + case "iso_8859-1": + case "iso_8859-1:1987": + case "l1": + case "latin1": + case "us-ascii": + case "windows-1252": + case "x-cp1252": + return Encoding.GetEncoding("windows-1252"); + + case "cp1253": + case "windows-1253": + case "x-cp1253": + return Encoding.GetEncoding("windows-1253"); + + case "cp1254": + case "csisolatin5": + case "iso-8859-9": + case "iso-ir-148": + case "iso8859-9": + case "iso88599": + case "iso_8859-9": + case "iso_8859-9:1989": + case "l5": + case "latin5": + case "windows-1254": + case "x-cp1254": + return Encoding.GetEncoding("windows-1254"); + + case "cp1255": + case "windows-1255": + case "x-cp1255": + return Encoding.GetEncoding("windows-1255"); + + case "cp1256": + case "windows-1256": + case "x-cp1256": + return Encoding.GetEncoding("windows-1256"); + + case "cp1257": + case "windows-1257": + case "x-cp1257": + return Encoding.GetEncoding("windows-1257"); + + case "cp1258": + case "windows-1258": + case "x-cp1258": + return Encoding.GetEncoding("windows-1258"); + + case "csmacintosh": + case "mac": + case "macintosh": + case "x-mac-roman": + return Encoding.GetEncoding("macintosh"); + + case "x-mac-cyrillic": + case "x-mac-ukrainian": + return Encoding.GetEncoding("x-mac-cyrillic"); + + case "866": + case "cp866": + case "csibm866": + case "ibm866": + return Encoding.GetEncoding("cp866"); + + case "csisolatin2": + case "iso-8859-2": + case "iso-ir-101": + case "iso8859-2": + case "iso88592": + case "iso_8859-2": + case "iso_8859-2:1987": + case "l2": + case "latin2": + return Encoding.GetEncoding("iso-8859-2"); + + case "csisolatin3": + case "iso-8859-3": + case "iso-ir-109": + case "iso8859-3": + case "iso88593": + case "iso_8859-3": + case "iso_8859-3:1988": + case "l3": + case "latin3": + return Encoding.GetEncoding("iso-8859-3"); + + case "csisolatin4": + case "iso-8859-4": + case "iso-ir-110": + case "iso8859-4": + case "iso88594": + case "iso_8859-4": + case "iso_8859-4:1988": + case "l4": + case "latin4": + return Encoding.GetEncoding("iso-8859-4"); + + case "csisolatincyrillic": + case "cyrillic": + case "iso-8859-5": + case "iso-ir-144": + case "iso8859-5": + case "iso88595": + case "iso_8859-5": + case "iso_8859-5:1988": + return Encoding.GetEncoding("iso-8859-5"); + + case "arabic": + case "asmo-708": + case "csiso88596e": + case "csiso88596i": + case "csisolatinarabic": + case "ecma-114": + case "iso-8859-6": + case "iso-8859-6-e": + case "iso-8859-6-i": + case "iso-ir-127": + case "iso8859-6": + case "iso88596": + case "iso_8859-6": + case "iso_8859-6:1987": + return Encoding.GetEncoding("iso-8859-6"); + + case "csisolatingreek": + case "ecma-118": + case "elot_928": + case "greek": + case "greek8": + case "iso-8859-7": + case "iso-ir-126": + case "iso8859-7": + case "iso88597": + case "iso_8859-7": + case "iso_8859-7:1987": + case "sun_eu_greek": + return Encoding.GetEncoding("iso-8859-7"); + + case "csiso88598e": + case "csisolatinhebrew": + case "hebrew": + case "iso-8859-8": + case "iso-8859-8-e": + case "iso-ir-138": + case "iso8859-8": + case "iso88598": + case "iso_8859-8": + case "iso_8859-8:1988": + case "visual": + return Encoding.GetEncoding("iso-8859-8"); + + case "csiso88598i": + case "iso-8859-8-i": + case "logical": + return Encoding.GetEncoding("iso-8859-8-i"); + + case "iso-8859-13": + case "iso8859-13": + case "iso885913": + return Encoding.GetEncoding("iso-8859-13"); + + case "csisolatin9": + case "iso-8859-15": + case "iso8859-15": + case "iso885915": + case "iso_8859-15": + case "l9": + return Encoding.GetEncoding("iso-8859-15"); + + case "cskoi8r": + case "koi": + case "koi8": + case "koi8-r": + case "koi8_r": + return Encoding.GetEncoding("koi8-r"); + + case "koi8-u": + return Encoding.GetEncoding("koi8-u"); + + case "chinese": + case "csgb2312": + case "csiso58gb231280": + case "gb2312": + case "gb_2312": + case "gb_2312-80": + case "gbk": + case "iso-ir-58": + case "x-gbk": + return Encoding.GetEncoding("x-cp20936"); + + case "hz-gb-2312": + return Encoding.GetEncoding("hz-gb-2312"); + + case "gb18030": + return Encoding.GetEncoding("GB18030"); + + case "big5": + case "big5-hkscs": + case "cn-big5": + case "csbig5": + case "x-x-big5": + return Encoding.GetEncoding("big5"); + + case "csiso2022jp": + case "iso-2022-jp": + return Encoding.GetEncoding("iso-2022-jp"); + + case "csiso2022kr": + case "iso-2022-kr": + return Encoding.GetEncoding("iso-2022-kr"); + + case "iso-2022-cn": + case "iso-2022-cn-ext": + return Encoding.GetEncoding("iso-2022-jp"); + + default: + return null; + } + } + + internal static Encoding Suggest(string local) + { + if (local.Length < 2) + return Encoding.UTF8; + + var firstTwo = local.Substring(0, 2).ToLower(); + + switch (firstTwo) + { + case "ar": + case "cy": + case "fa": + case "hr": + case "kk": + case "mk": + case "or": + case "ro": + case "sr": + case "vi": + return Encoding.UTF8; + + case "be": + return Encoding.GetEncoding("iso-8859-5"); + + case "bg": + case "ru": + case "uk": + return Encoding.GetEncoding("windows-1251"); + + case "cs": + case "hu": + case "pl": + case "sl": + return Encoding.GetEncoding("iso-8859-2"); + + case "tr": + case "ku": + return Encoding.GetEncoding("windows-1254"); + + case "he": + return Encoding.GetEncoding("windows-1255"); + + case "lv": + return Encoding.GetEncoding("iso-8859-13"); + + case "ja":// Windows-31J ???? Replaced by something better anyway + return Encoding.UTF8; + + case "ko": + return Encoding.GetEncoding("ks_c_5601-1987"); + + case "lt": + return Encoding.GetEncoding("windows-1257"); + + case "sk": + return Encoding.GetEncoding("windows-1250"); + + case "th": + return Encoding.GetEncoding("windows-874"); + } + + if (local.Equals("zh-CN", StringComparison.OrdinalIgnoreCase)) + { + return Encoding.GetEncoding("GB18030"); + } + + return Encoding.GetEncoding(local.Equals("zh-TW", StringComparison.OrdinalIgnoreCase) + ? "big5" + : "windows-1252"); + } + } +} \ No newline at end of file diff --git a/Source/External/ExCSS/Model/ICssRules.cs b/Source/External/ExCSS/Model/ICssRules.cs new file mode 100644 index 0000000000000000000000000000000000000000..9c303c2f860f33f0022efa99441cb42ae7d37146 --- /dev/null +++ b/Source/External/ExCSS/Model/ICssRules.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; + +namespace ExCSS.Model +{ + interface ISupportsRuleSets + { + List RuleSets { get; } + } +} \ No newline at end of file diff --git a/Source/External/ExCSS/Model/ICssSelector.cs b/Source/External/ExCSS/Model/ICssSelector.cs new file mode 100644 index 0000000000000000000000000000000000000000..62d57a4e425deee978f035ff46afdffc51a2c790 --- /dev/null +++ b/Source/External/ExCSS/Model/ICssSelector.cs @@ -0,0 +1,7 @@ +namespace ExCSS.Model +{ + interface ISupportsSelector + { + BaseSelector Selector { get; set; } + } +} \ No newline at end of file diff --git a/Source/External/ExCSS/Model/IStyleDeclaration.cs b/Source/External/ExCSS/Model/IStyleDeclaration.cs new file mode 100644 index 0000000000000000000000000000000000000000..38f0d690cc17ed241529c8088e6778abb737f32d --- /dev/null +++ b/Source/External/ExCSS/Model/IStyleDeclaration.cs @@ -0,0 +1,7 @@ +namespace ExCSS.Model +{ + interface ISupportsDeclarations + { + StyleDeclaration Declarations { get; } + } +} \ No newline at end of file diff --git a/Source/External/ExCSS/Model/ISupportsMedia.cs b/Source/External/ExCSS/Model/ISupportsMedia.cs new file mode 100644 index 0000000000000000000000000000000000000000..fa81faf84921e192f15129785eb602ba8a340488 --- /dev/null +++ b/Source/External/ExCSS/Model/ISupportsMedia.cs @@ -0,0 +1,7 @@ +namespace ExCSS.Model +{ + interface ISupportsMedia + { + MediaTypeList Media { get; } + } +} \ No newline at end of file diff --git a/Source/External/ExCSS/Model/MediaTypeList.cs b/Source/External/ExCSS/Model/MediaTypeList.cs new file mode 100644 index 0000000000000000000000000000000000000000..f8f8cd3ac603a60bb9fac834e7a81d94ce1f886e --- /dev/null +++ b/Source/External/ExCSS/Model/MediaTypeList.cs @@ -0,0 +1,98 @@ +using System.Collections; +using System.Collections.Generic; +using ExCSS.Model.Extensions; + +// ReSharper disable once CheckNamespace +namespace ExCSS +{ + public class MediaTypeList : IEnumerable + { + private readonly List _media; + private string _buffer; + + internal MediaTypeList() + { + _buffer = string.Empty; + _media = new List(); + } + + public string this[int index] + { + get + { + if (index < 0 || index >= _media.Count) + { + return null; + } + + return _media[index]; + } + set + { + _media[index] = value; + } + } + + public int Count + { + get { return _media.Count; } + } + + public string MediaType + { + get { return _buffer; } + set + { + _buffer = string.Empty; + _media.Clear(); + + if (string.IsNullOrEmpty(value)) + { + return; + } + + var entries = value.SplitOnCommas(); + + foreach (var t in entries) + { + AppendMedium(t); + } + } + } + + internal MediaTypeList AppendMedium(string newMedium) + { + if (_media.Contains(newMedium)) + { + return this; + } + + _media.Add(newMedium); + _buffer += (string.IsNullOrEmpty(_buffer) ? string.Empty : ",") + newMedium; + + return this; + } + + public override string ToString() + { + return ToString(false); + } + + public string ToString(bool friendlyFormat, int indentation = 0) + { + return friendlyFormat + ? string.Join(", ", _media.ToArray()) + : string.Join(",", _media.ToArray()); + } + + public IEnumerator GetEnumerator() + { + return ((IEnumerable) _media).GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } +} \ No newline at end of file diff --git a/Source/External/ExCSS/Model/Rules/AggregateRule.cs b/Source/External/ExCSS/Model/Rules/AggregateRule.cs new file mode 100644 index 0000000000000000000000000000000000000000..c70d60c68915284774e5f9f1fcb4bd6029b827a1 --- /dev/null +++ b/Source/External/ExCSS/Model/Rules/AggregateRule.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using ExCSS.Model; + +// ReSharper disable once CheckNamespace +namespace ExCSS +{ + public abstract class AggregateRule : RuleSet, ISupportsRuleSets + { + protected AggregateRule() + { + RuleSets = new List(); + } + + public List RuleSets { get; private set; } + } +} diff --git a/Source/External/ExCSS/Model/Rules/CharacterSetRule.cs b/Source/External/ExCSS/Model/Rules/CharacterSetRule.cs new file mode 100644 index 0000000000000000000000000000000000000000..a12e3b3298c393cf68067981b7c24404a68c0441 --- /dev/null +++ b/Source/External/ExCSS/Model/Rules/CharacterSetRule.cs @@ -0,0 +1,25 @@ +using ExCSS.Model.Extensions; + +// ReSharper disable once CheckNamespace +namespace ExCSS +{ + public class CharacterSetRule : RuleSet + { + public CharacterSetRule() + { + RuleType = RuleType.Charset; + } + + public string Encoding { get; internal set; } + + public override string ToString() + { + return ToString(false); + } + + public override string ToString(bool friendlyFormat, int indentation = 0) + { + return string.Format("@charset '{0}';", Encoding).NewLineIndent(friendlyFormat, indentation); + } + } +} diff --git a/Source/External/ExCSS/Model/Rules/ConditionalRule.cs b/Source/External/ExCSS/Model/Rules/ConditionalRule.cs new file mode 100644 index 0000000000000000000000000000000000000000..f51c38d500ad733d610f3b4ec19ef9385dd44102 --- /dev/null +++ b/Source/External/ExCSS/Model/Rules/ConditionalRule.cs @@ -0,0 +1,13 @@ + +// ReSharper disable once CheckNamespace +namespace ExCSS +{ + public abstract class ConditionalRule : AggregateRule + { + public virtual string Condition + { + get { return string.Empty; } + set { } + } + } +} diff --git a/Source/External/ExCSS/Model/Rules/DocumentRule.cs b/Source/External/ExCSS/Model/Rules/DocumentRule.cs new file mode 100644 index 0000000000000000000000000000000000000000..b9853730e2fcda1bfb3eb7511f84e00cdeef459d --- /dev/null +++ b/Source/External/ExCSS/Model/Rules/DocumentRule.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.Text; +using ExCSS.Model; +using ExCSS.Model.Extensions; + +// ReSharper disable once CheckNamespace +namespace ExCSS +{ + public sealed class DocumentRule : AggregateRule + { + readonly List> _conditions; + + internal DocumentRule() + { + RuleType = RuleType.Document; + _conditions = new List>(); + } + + public string ConditionText + { + get + { + var builder = new StringBuilder(); + var concat = false; + + foreach (var condition in _conditions) + { + if (concat) + { + builder.Append(','); + } + + switch (condition.Key) + { + case DocumentFunction.Url: + builder.Append("url"); + break; + + case DocumentFunction.UrlPrefix: + builder.Append("url-prefix"); + break; + + case DocumentFunction.Domain: + builder.Append("domain"); + break; + + case DocumentFunction.RegExp: + builder.Append("regexp"); + break; + } + + builder.Append(Specification.ParenOpen); + builder.Append(Specification.DoubleQuote); + builder.Append(condition.Value); + builder.Append(Specification.DoubleQuote); + builder.Append(Specification.ParenClose); + concat = true; + } + + return builder.ToString(); + } + } + + internal List> Conditions + { + get { return _conditions; } + } + + public override string ToString() + { + return ToString(false); + } + + public override string ToString(bool friendlyFormat, int indentation = 0) + { + return "@document " + ConditionText + " {" + + RuleSets + + "}".NewLineIndent(friendlyFormat, indentation); + } + } +} diff --git a/Source/External/ExCSS/Model/Rules/FontFaceRule.cs b/Source/External/ExCSS/Model/Rules/FontFaceRule.cs new file mode 100644 index 0000000000000000000000000000000000000000..0d933d065a7efa9d150954fd899c9999404df343 --- /dev/null +++ b/Source/External/ExCSS/Model/Rules/FontFaceRule.cs @@ -0,0 +1,88 @@ +using ExCSS.Model; +using ExCSS.Model.Extensions; + +// ReSharper disable once CheckNamespace +namespace ExCSS +{ + public class FontFaceRule : RuleSet, ISupportsDeclarations + { + private readonly StyleDeclaration _declarations; + + public FontFaceRule() + { + _declarations = new StyleDeclaration(); + RuleType = RuleType.FontFace; + } + + internal FontFaceRule AppendRule(Property rule) + { + _declarations.Properties.Add(rule); + return this; + } + + public StyleDeclaration Declarations + { + get { return _declarations; } + } + + public string FontFamily + { + get { return _declarations.GetPropertyValue("font-family"); } + set { _declarations.SetProperty("font-family", value); } + } + + public string Src + { + get { return _declarations.GetPropertyValue("src"); } + set { _declarations.SetProperty("src", value); } + } + + public string FontStyle + { + get { return _declarations.GetPropertyValue("font-style"); } + set { _declarations.SetProperty("font-style", value); } + } + + public string FontWeight + { + get { return _declarations.GetPropertyValue("font-weight"); } + set { _declarations.SetProperty("font-weight", value); } + } + + public string Stretch + { + get { return _declarations.GetPropertyValue("stretch"); } + set { _declarations.SetProperty("stretch", value); } + } + + public string UnicodeRange + { + get { return _declarations.GetPropertyValue("unicode-range"); } + set { _declarations.SetProperty("unicode-range", value); } + } + + public string FontVariant + { + get { return _declarations.GetPropertyValue("font-variant"); } + set { _declarations.SetProperty("font-variant", value); } + } + + public string FeatureSettings + { + get { return _declarations.GetPropertyValue("font-feature-settings"); } + set { _declarations.SetProperty("font-feature-settings", value); } + } + + public override string ToString() + { + return ToString(false); + } + + public override string ToString(bool friendlyFormat, int indentation = 0) + { + return "@font-face{".NewLineIndent(friendlyFormat, indentation) + + _declarations.ToString(friendlyFormat, indentation) + + "}".NewLineIndent(friendlyFormat, indentation); + } + } +} diff --git a/Source/External/ExCSS/Model/Rules/GenericRule.cs b/Source/External/ExCSS/Model/Rules/GenericRule.cs new file mode 100644 index 0000000000000000000000000000000000000000..a1d85d9e7116ed750700e0ebb3527583fd28e749 --- /dev/null +++ b/Source/External/ExCSS/Model/Rules/GenericRule.cs @@ -0,0 +1,36 @@ +// ReSharper disable once CheckNamespace +namespace ExCSS +{ + public class GenericRule : AggregateRule + { + private string _text; + private bool _stopped; + + internal void SetInstruction(string text) + { + _text = text; + _stopped = true; + } + + internal void SetCondition(string text) + { + _text = text; + _stopped = false; + } + + public override string ToString() + { + return ToString(false); + } + + public override string ToString(bool friendlyFormat, int indentation = 0) + { + if (_stopped) + { + return _text + ";"; + } + + return _text + "{" + RuleSets + "}"; + } + } +} diff --git a/Source/External/ExCSS/Model/Rules/IRuleContainer.cs b/Source/External/ExCSS/Model/Rules/IRuleContainer.cs new file mode 100644 index 0000000000000000000000000000000000000000..13ec5a967beafcfe590fcb295671706eba9bb4b3 --- /dev/null +++ b/Source/External/ExCSS/Model/Rules/IRuleContainer.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; + +// ReSharper disable once CheckNamespace +namespace ExCSS +{ + public interface IRuleContainer + { + List Declarations { get; } + } +} \ No newline at end of file diff --git a/Source/External/ExCSS/Model/Rules/ImportRule.cs b/Source/External/ExCSS/Model/Rules/ImportRule.cs new file mode 100644 index 0000000000000000000000000000000000000000..8ef67b26bb078605b2a030e81d0a945bf5efb87e --- /dev/null +++ b/Source/External/ExCSS/Model/Rules/ImportRule.cs @@ -0,0 +1,41 @@ +using ExCSS.Model; +using ExCSS.Model.Extensions; + +// ReSharper disable once CheckNamespace +namespace ExCSS +{ + public class ImportRule : RuleSet, ISupportsMedia + { + private string _href; + private readonly MediaTypeList _media; + + public ImportRule() + { + _media = new MediaTypeList(); + RuleType = RuleType.Import; + } + + public string Href + { + get { return _href; } + set { _href = value; } + } + + public MediaTypeList Media + { + get { return _media; } + } + + public override string ToString() + { + return ToString(false); + } + + public override string ToString(bool friendlyFormat, int indentation = 0) + { + return _media.Count > 0 + ? string.Format("@import url({0}) {1};", _href, _media).NewLineIndent(friendlyFormat, indentation) + : string.Format("@import url({0});", _href).NewLineIndent(friendlyFormat, indentation); + } + } +} diff --git a/Source/External/ExCSS/Model/Rules/KeyframeRule.cs b/Source/External/ExCSS/Model/Rules/KeyframeRule.cs new file mode 100644 index 0000000000000000000000000000000000000000..159314dbcd845e81cc77ffed2124e1a62a0a2f0b --- /dev/null +++ b/Source/External/ExCSS/Model/Rules/KeyframeRule.cs @@ -0,0 +1,39 @@ +using ExCSS.Model; +using ExCSS.Model.Extensions; + +// ReSharper disable once CheckNamespace +namespace ExCSS +{ + public class KeyframeRule : RuleSet, ISupportsDeclarations + { + private string _value; + + public KeyframeRule() + { + Declarations = new StyleDeclaration(); + RuleType = RuleType.Keyframe; + } + + public string Value + { + get { return _value; } + set { _value = value; } + } + + public StyleDeclaration Declarations { get; private set; } + + public override string ToString() + { + return ToString(false); + } + + public override string ToString(bool friendlyFormat, int indentation = 0) + { + return string.Empty.Indent(friendlyFormat, indentation) + + _value + + "{" + + Declarations.ToString(friendlyFormat, indentation) + + "}".NewLineIndent(friendlyFormat, indentation); + } + } +} diff --git a/Source/External/ExCSS/Model/Rules/KeyframesRule.cs b/Source/External/ExCSS/Model/Rules/KeyframesRule.cs new file mode 100644 index 0000000000000000000000000000000000000000..d4e4e0687c78fd699befba216a4ef8458edf0e5d --- /dev/null +++ b/Source/External/ExCSS/Model/Rules/KeyframesRule.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using ExCSS.Model.Extensions; + +// ReSharper disable once CheckNamespace +namespace ExCSS +{ + public class KeyframesRule : RuleSet, IRuleContainer + { + private readonly List _ruleSets; + private string _identifier; + + public KeyframesRule() + { + _ruleSets = new List(); + RuleType = RuleType.Keyframes; + } + + public string Identifier + { + get { return _identifier; } + set { _identifier = value; } + } + + //TODO change to "keyframes" + public List Declarations + { + get { return _ruleSets; } + } + + public override string ToString() + { + return ToString(false); + } + + public override string ToString(bool friendlyFormat, int indentation = 0) + { + var join = friendlyFormat ? "".NewLineIndent(true, indentation) : ""; + + var declarationList = _ruleSets.Select(d => d.ToString(friendlyFormat, indentation + 1)); + var declarations = string.Join(join, declarationList.ToArray()); + + return ("@keyframes " + _identifier + "{").NewLineIndent(friendlyFormat, indentation) + + declarations.NewLineIndent(friendlyFormat, indentation) + + "}".NewLineIndent(friendlyFormat, indentation); + } + } +} diff --git a/Source/External/ExCSS/Model/Rules/MediaRule.cs b/Source/External/ExCSS/Model/Rules/MediaRule.cs new file mode 100644 index 0000000000000000000000000000000000000000..89727debe322be99bac8229c6ca58d5e9f80953e --- /dev/null +++ b/Source/External/ExCSS/Model/Rules/MediaRule.cs @@ -0,0 +1,47 @@ +using System; +using System.Linq; +using ExCSS.Model; +using ExCSS.Model.Extensions; + +// ReSharper disable once CheckNamespace +namespace ExCSS +{ + public class MediaRule : ConditionalRule, ISupportsMedia + { + private readonly MediaTypeList _media; + + public MediaRule() + { + _media = new MediaTypeList(); + RuleType = RuleType.Media; + } + + public override string Condition + { + get { return _media.MediaType; } + set { _media.MediaType = value; } + } + + public MediaTypeList Media + { + get { return _media; } + } + + public override string ToString() + { + return ToString(false); + } + + public override string ToString(bool friendlyFormat, int indentation = 0) + { + var join = friendlyFormat ? "".NewLineIndent(true, indentation + 1) : ""; + + var declarationList = RuleSets.Select(d => d.ToString(friendlyFormat, indentation + 1).TrimFirstLine()); + var declarations = string.Join(join, declarationList.ToArray()); + + return ("@media " + _media.MediaType + "{").NewLineIndent(friendlyFormat, indentation) + + declarations.TrimFirstLine().NewLineIndent(friendlyFormat, indentation + 1) + + "}".NewLineIndent(friendlyFormat, indentation); + } + } +} diff --git a/Source/External/ExCSS/Model/Rules/NamespaceRule.cs b/Source/External/ExCSS/Model/Rules/NamespaceRule.cs new file mode 100644 index 0000000000000000000000000000000000000000..0981f4688d00a378eb36f03aea4d744457c39f96 --- /dev/null +++ b/Source/External/ExCSS/Model/Rules/NamespaceRule.cs @@ -0,0 +1,30 @@ +using ExCSS.Model.Extensions; +// ReSharper disable once CheckNamespace + + +namespace ExCSS +{ + public class NamespaceRule : RuleSet + { + public NamespaceRule() + { + RuleType = RuleType.Namespace; + } + + public string Uri { get; set; } + + public string Prefix { get; set; } + + public override string ToString() + { + return ToString(false); + } + + public override string ToString(bool friendlyFormat, int indentation = 0) + { + return string.IsNullOrEmpty(Prefix) + ? string.Format("@namespace '{0}';", Uri).NewLineIndent(friendlyFormat, indentation) + : string.Format("@namespace {0} '{1}';", Prefix, Uri).NewLineIndent(friendlyFormat, indentation); + } + } +} diff --git a/Source/External/ExCSS/Model/Rules/PageRule.cs b/Source/External/ExCSS/Model/Rules/PageRule.cs new file mode 100644 index 0000000000000000000000000000000000000000..43bb0d3db2e62fb68ae12d060c0cf9470b3a6039 --- /dev/null +++ b/Source/External/ExCSS/Model/Rules/PageRule.cs @@ -0,0 +1,58 @@ +using ExCSS.Model; +using ExCSS.Model.Extensions; + +// ReSharper disable once CheckNamespace +namespace ExCSS +{ + public class PageRule : RuleSet, ISupportsSelector, ISupportsDeclarations + { + private readonly StyleDeclaration _declarations; + private BaseSelector _selector; + private string _selectorText; + + public PageRule() + { + _declarations = new StyleDeclaration(); + RuleType = RuleType.Page; + } + + internal PageRule AppendRule(Property rule) + { + _declarations.Properties.Add(rule); + return this; + } + + public BaseSelector Selector + { + get { return _selector; } + set + { + _selector = value; + _selectorText = value.ToString(); + } + } + + public StyleDeclaration Declarations + { + get { return _declarations; } + } + + public override string ToString() + { + return ToString(false); + } + + public override string ToString(bool friendlyFormat, int indentation = 0) + { + var pseudo = string.IsNullOrEmpty(_selectorText) + ? "" + : ":" + _selectorText; + + var declarations = _declarations.ToString(friendlyFormat, indentation);//.TrimFirstLine(); + + return ("@page " + pseudo + "{").NewLineIndent(friendlyFormat, indentation) + + declarations + + "}".NewLineIndent(friendlyFormat, indentation); + } + } +} diff --git a/Source/External/ExCSS/Model/Rules/RuleSet.cs b/Source/External/ExCSS/Model/Rules/RuleSet.cs new file mode 100644 index 0000000000000000000000000000000000000000..ec811e0b957e7ae2e0672c64d14ad6b37e6fec12 --- /dev/null +++ b/Source/External/ExCSS/Model/Rules/RuleSet.cs @@ -0,0 +1,16 @@ + +// ReSharper disable once CheckNamespace +namespace ExCSS +{ + public abstract class RuleSet + { + internal RuleSet() + { + RuleType = RuleType.Unknown; + } + + public RuleType RuleType { get; set; } + + public abstract string ToString(bool friendlyFormat, int indentation = 0); + } +} diff --git a/Source/External/ExCSS/Model/Rules/StyleDeclaration.cs b/Source/External/ExCSS/Model/Rules/StyleDeclaration.cs new file mode 100644 index 0000000000000000000000000000000000000000..2d66277f3dfc4239c168c40a1f70b61539ec4979 --- /dev/null +++ b/Source/External/ExCSS/Model/Rules/StyleDeclaration.cs @@ -0,0 +1,184 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; + +// ReSharper disable once CheckNamespace +namespace ExCSS +{ + public class StyleDeclaration : IList + { + private readonly List _properties; + private readonly Func _getter; + private readonly Action _setter; + private bool _blocking; + + public StyleDeclaration() + { + var text = string.Empty; + _getter = () => text; + _setter = value => text = value; + _properties = new List(); + } + + public string Value + { + get { return _getter(); } + set + { + Update(value); + _setter(value); + } + } + + public RuleSet ParentRule { get; set; } + + public void Add(Property item) + { + _properties.Add(item); + } + + public void Clear() + { + _properties.Clear(); + } + + public bool Contains(Property item) + { + return _properties.Contains(item); + } + + public void CopyTo(Property[] array, int arrayIndex) + { + _properties.CopyTo(array, arrayIndex); + } + + public bool Remove(Property item) + { + return _properties.Remove(item); + } + + public int IndexOf(Property item) + { + return _properties.IndexOf(item); + } + + public void Insert(int index, Property item) + { + _properties.Insert(index, item); + } + + public void RemoveAt(int index) + { + _properties.RemoveAt(index); + } + + public override string ToString() + { + return ToString(false); + } + + public string ToString(bool friendlyFormat, int indentation = 0) + { + var builder = new StringBuilder(); + + foreach (var property in _properties) + { + if (friendlyFormat) + { + builder.Append(Environment.NewLine); + } + + builder.Append(property.ToString(friendlyFormat, indentation+1)).Append(';'); + } + + return builder.ToString(); + } + + internal string RemoveProperty(string propertyName) + { + for (var i = 0; i < _properties.Count; i++) + { + if (!_properties[i].Name.Equals(propertyName)) + { + continue; + } + + var value = _properties[i].Term; + + _properties.RemoveAt(i); + Propagate(); + + return value.ToString(); + } + + return null; + } + + internal string GetPropertyValue(string propertyName) + { + for (var i = 0; i < _properties.Count; i++) + { + if (_properties[i].Name.Equals(propertyName)) + { + return _properties[i].Term.ToString(); + } + } + + return null; + } + + public IEnumerator GetEnumerator() + { + return _properties.GetEnumerator(); + } + + public Property this[int index] + { + get { return _properties[index]; } + set { _properties[index] = value; } + } + + public List Properties + { + get { return _properties; } + } + + public int Count { get { return _properties.Count; } } + + public bool IsReadOnly { get { return false; } } + + internal StyleDeclaration SetProperty(string propertyName, string propertyValue) + { + //_properties.Add(Parser.ParseDeclaration(propertyName + ":" + propertyValue)); + //TODO + Propagate(); + return this; + } + + internal void Update(string value) + { + if (_blocking) + { + return; + } + + var rules = Parser.ParseDeclarations(value ?? string.Empty).Properties; + + _properties.Clear(); + _properties.AddRange(rules); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable)_properties).GetEnumerator(); + } + + private void Propagate() + { + _blocking = true; + _setter(ToString()); + _blocking = false; + } + } +} \ No newline at end of file diff --git a/Source/External/ExCSS/Model/Rules/StyleRule.cs b/Source/External/ExCSS/Model/Rules/StyleRule.cs new file mode 100644 index 0000000000000000000000000000000000000000..1b6780de1a3bedd2a06c37a873084efabc7fd785 --- /dev/null +++ b/Source/External/ExCSS/Model/Rules/StyleRule.cs @@ -0,0 +1,61 @@ +using System; +using ExCSS.Model; +using ExCSS.Model.Extensions; + +// ReSharper disable once CheckNamespace +namespace ExCSS +{ + public class StyleRule : RuleSet, ISupportsSelector, ISupportsDeclarations + { + private string _value; + private BaseSelector _selector; + private readonly StyleDeclaration _declarations; + + public StyleRule() : this( new StyleDeclaration()) + {} + + public StyleRule(StyleDeclaration declarations) + { + RuleType = RuleType.Style; + _declarations = declarations; + } + + public BaseSelector Selector + { + get { return _selector; } + set + { + _selector = value; + _value = value.ToString(); + } + } + + public string Value + { + get { return _value; } + set + { + _selector = Parser.ParseSelector(value); + _value = value; + } + } + + public StyleDeclaration Declarations + { + get { return _declarations; } + } + + public override string ToString() + { + return ToString(false); + } + + public override string ToString(bool friendlyFormat, int indentation = 0) + { + return _value.NewLineIndent(friendlyFormat, indentation) + + "{" + + _declarations.ToString(friendlyFormat, indentation) + + "}".NewLineIndent(friendlyFormat, indentation); + } + } +} diff --git a/Source/External/ExCSS/Model/Rules/SupportsRule.cs b/Source/External/ExCSS/Model/Rules/SupportsRule.cs new file mode 100644 index 0000000000000000000000000000000000000000..b4349c3c0b796f6ecfb5734dcdd638d4e084c3b4 --- /dev/null +++ b/Source/External/ExCSS/Model/Rules/SupportsRule.cs @@ -0,0 +1,42 @@ +using System.Linq; +using ExCSS.Model.Extensions; + +// ReSharper disable once CheckNamespace +namespace ExCSS +{ + public class SupportsRule : ConditionalRule + { + private string _condition; + + public SupportsRule() + { + RuleType = RuleType.Supports; + _condition = string.Empty; + } + + public override string Condition + { + get { return _condition; } + set { _condition = value; } + } + + public bool IsSupported{ get; set; } + + public override string ToString() + { + return ToString(false); + } + + public override string ToString(bool friendlyFormat, int indentation = 0) + { + var join = friendlyFormat ? "".NewLineIndent(true, indentation + 1) : ""; + + var declarationList = RuleSets.Select(d => d.ToString(friendlyFormat, indentation + 1).TrimFirstLine()); + var declarations = string.Join(join, declarationList.ToArray()); + + return ("@supports" + _condition + "{").NewLineIndent(friendlyFormat, indentation) + + declarations.TrimFirstLine().NewLineIndent(friendlyFormat, indentation + 1) + + "}".NewLineIndent(friendlyFormat, indentation); + } + } +} diff --git a/Source/External/ExCSS/Model/Selector/AggregateSelectorList.cs b/Source/External/ExCSS/Model/Selector/AggregateSelectorList.cs new file mode 100644 index 0000000000000000000000000000000000000000..f93de033db66b9ba338081e0388335315223da82 --- /dev/null +++ b/Source/External/ExCSS/Model/Selector/AggregateSelectorList.cs @@ -0,0 +1,44 @@ +using System; +using System.Text; + +// ReSharper disable once CheckNamespace +namespace ExCSS +{ + public class AggregateSelectorList : SelectorList + { + public readonly string Delimiter; + + public AggregateSelectorList(string delimiter) + { + if (delimiter.Length > 1) + { + throw new ArgumentException("Expected single character delimiter or empty string", "delimiter"); + } + + Delimiter = delimiter; + } + + public override string ToString(bool friendlyFormat, int indentation = 0) + { + var builder = new StringBuilder(); + + foreach (var selector in Selectors) + { + builder.Append(selector.ToString(friendlyFormat, indentation + 1)); + builder.Append(Delimiter); + } + + if (Delimiter.Length <= 0) + { + return builder.ToString(); + } + + if (builder.Length > 0) + { + builder.Remove(builder.Length - 1, 1); + } + + return builder.ToString(); + } + } +} diff --git a/Source/External/ExCSS/Model/Selector/BaseSelector.cs b/Source/External/ExCSS/Model/Selector/BaseSelector.cs new file mode 100644 index 0000000000000000000000000000000000000000..c718b5686fb527763575e1c7b0f22d434aa51f1e --- /dev/null +++ b/Source/External/ExCSS/Model/Selector/BaseSelector.cs @@ -0,0 +1,15 @@ + +// ReSharper disable once CheckNamespace +namespace ExCSS +{ + public abstract class BaseSelector + { + public sealed override string ToString() + { + return ToString(false); + } + + public abstract string ToString(bool friendlyFormat, int indentation = 0); + } +} + diff --git a/Source/External/ExCSS/Model/Selector/CombinatorSelector.cs b/Source/External/ExCSS/Model/Selector/CombinatorSelector.cs new file mode 100644 index 0000000000000000000000000000000000000000..f8be92c6e25811d06dd38d65d45e8f1adc1b63cc --- /dev/null +++ b/Source/External/ExCSS/Model/Selector/CombinatorSelector.cs @@ -0,0 +1,45 @@ +using System; +using ExCSS.Model; + +// ReSharper disable once CheckNamespace +namespace ExCSS +{ + public struct CombinatorSelector + { + public BaseSelector Selector; + public Combinator Delimiter; + + public CombinatorSelector(BaseSelector selector, Combinator delimiter) + { + Selector = selector; + Delimiter = delimiter; + } + + public char Character + { + get{ + switch (Delimiter) + { + case Combinator.Child: + return Specification.GreaterThan; + + case Combinator.AdjacentSibling: + return Specification.PlusSign; + + case Combinator.Descendent: + return Specification.Space; + + case Combinator.Sibling: + return Specification.Tilde; + + case Combinator.Namespace: + return Specification.Pipe; + + default: + throw new NotImplementedException("Unknown combinator: " + Delimiter); + } + } + } + } +} + diff --git a/Source/External/ExCSS/Model/Selector/ComplexSelector.cs b/Source/External/ExCSS/Model/Selector/ComplexSelector.cs new file mode 100644 index 0000000000000000000000000000000000000000..e39969875faf92fa2b00894e53beaffe66e158f8 --- /dev/null +++ b/Source/External/ExCSS/Model/Selector/ComplexSelector.cs @@ -0,0 +1,66 @@ +using System; +using System.Text; +using System.Collections.Generic; +using System.Collections; + +// ReSharper disable once CheckNamespace +namespace ExCSS +{ + public class ComplexSelector : BaseSelector, IEnumerable + { + private readonly List _selectors; + + public ComplexSelector() + { + _selectors = new List(); + } + + public ComplexSelector AppendSelector(BaseSelector selector, Combinator combinator) + { + _selectors.Add(new CombinatorSelector(selector, combinator)); + return this; + } + + public IEnumerator GetEnumerator() + { + return _selectors.GetEnumerator(); + } + + internal void ConcludeSelector(BaseSelector selector) + { + _selectors.Add(new CombinatorSelector { Selector = selector }); + } + + public int Length + { + get { return _selectors.Count; } + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable)_selectors).GetEnumerator(); + } + + public override string ToString(bool friendlyFormat, int indentation = 0) + { + var builder = new StringBuilder(); + + if (_selectors.Count <= 0) + { + return builder.ToString(); + } + + var n = _selectors.Count - 1; + + for (var i = 0; i < n; i++) + { + builder.Append(_selectors[i].Selector); + builder.Append(_selectors[i].Character); + } + + builder.Append(_selectors[n].Selector); + + return builder.ToString(); + } + } +} diff --git a/Source/External/ExCSS/Model/Selector/FirstChildSelector.cs b/Source/External/ExCSS/Model/Selector/FirstChildSelector.cs new file mode 100644 index 0000000000000000000000000000000000000000..569bbac788af20f1038281476be9650a96cb6813 --- /dev/null +++ b/Source/External/ExCSS/Model/Selector/FirstChildSelector.cs @@ -0,0 +1,21 @@ +// ReSharper disable once CheckNamespace +namespace ExCSS +{ + internal sealed class FirstChildSelector : BaseSelector, IToString + { + FirstChildSelector() + { } + + static FirstChildSelector _instance; + + public static FirstChildSelector Instance + { + get { return _instance ?? (_instance = new FirstChildSelector()); } + } + + public override string ToString(bool friendlyFormat, int indentation = 0) + { + return ":" + PseudoSelectorPrefix.PseudoFirstchild; + } + } +} \ No newline at end of file diff --git a/Source/External/ExCSS/Model/Selector/LastChildSelector.cs b/Source/External/ExCSS/Model/Selector/LastChildSelector.cs new file mode 100644 index 0000000000000000000000000000000000000000..f0d1bfbdc4c180ceff34d8f06745740db2a058f0 --- /dev/null +++ b/Source/External/ExCSS/Model/Selector/LastChildSelector.cs @@ -0,0 +1,21 @@ +// ReSharper disable once CheckNamespace +namespace ExCSS +{ + internal sealed class LastChildSelector : BaseSelector, IToString + { + LastChildSelector() + { } + + static LastChildSelector _instance; + + public static LastChildSelector Instance + { + get { return _instance ?? (_instance = new LastChildSelector()); } + } + + public override string ToString(bool friendlyFormat, int indentation = 0) + { + return ":" + PseudoSelectorPrefix.PseudoLastchild; + } + } +} \ No newline at end of file diff --git a/Source/External/ExCSS/Model/Selector/MultipleSelectorList.cs b/Source/External/ExCSS/Model/Selector/MultipleSelectorList.cs new file mode 100644 index 0000000000000000000000000000000000000000..57e1e70ca7284a02c871d5577aab61419980ee48 --- /dev/null +++ b/Source/External/ExCSS/Model/Selector/MultipleSelectorList.cs @@ -0,0 +1,41 @@ +using System.Text; + +// ReSharper disable once CheckNamespace +namespace ExCSS +{ + public class MultipleSelectorList : SelectorList, IToString + { + internal static MultipleSelectorList Create(params SimpleSelector[] selectors) + { + var multiple = new MultipleSelectorList(); + + foreach (var selector in selectors) + { + multiple.Selectors.Add(selector); + } + + return multiple; + } + + internal bool IsInvalid { get; set; } + + public override string ToString(bool friendlyFormat, int indentation = 0) + { + var builder = new StringBuilder(); + + if (Selectors.Count <= 0) + { + return builder.ToString(); + } + + builder.Append(Selectors[0]); + + for (var i = 1; i < Selectors.Count; i++) + { + builder.Append(',').Append(Selectors[i]); + } + + return builder.ToString(); + } + } +} diff --git a/Source/External/ExCSS/Model/Selector/NthChildSelector.cs b/Source/External/ExCSS/Model/Selector/NthChildSelector.cs new file mode 100644 index 0000000000000000000000000000000000000000..77fc7425e2cbbefb634200ac3aa881315a3e21fe --- /dev/null +++ b/Source/External/ExCSS/Model/Selector/NthChildSelector.cs @@ -0,0 +1,24 @@ + +// ReSharper disable once CheckNamespace +namespace ExCSS +{ + internal abstract class NthChildSelector : BaseSelector, IToString + { + public int Step; + public int Offset; + internal string FunctionText { get; set; } + + internal string FormatSelector(string functionName) + { + var format = Offset < 0 + ? ":{0}({1}n{2})" + : ":{0}({1}n+{2})"; + + return string.IsNullOrEmpty(FunctionText) + ? string.Format(format, functionName, Step, Offset) + : string.Format(":{0}({1})", functionName, FunctionText); + } + + public abstract override string ToString(bool friendlyFormat, int indentation = 0); + } +} \ No newline at end of file diff --git a/Source/External/ExCSS/Model/Selector/NthFirstChildSelector.cs b/Source/External/ExCSS/Model/Selector/NthFirstChildSelector.cs new file mode 100644 index 0000000000000000000000000000000000000000..154f66292c46f8c1c5f3cd636630e2d159c291c1 --- /dev/null +++ b/Source/External/ExCSS/Model/Selector/NthFirstChildSelector.cs @@ -0,0 +1,12 @@ + +// ReSharper disable once CheckNamespace +namespace ExCSS +{ + internal sealed class NthFirstChildSelector : NthChildSelector, IToString + { + public override string ToString(bool friendlyFormat, int indentation = 0) + { + return FormatSelector(PseudoSelectorPrefix.PseudoFunctionNthchild); + } + } +} \ No newline at end of file diff --git a/Source/External/ExCSS/Model/Selector/NthLastChildSelector.cs b/Source/External/ExCSS/Model/Selector/NthLastChildSelector.cs new file mode 100644 index 0000000000000000000000000000000000000000..797b627578aed515eba0980143d2638c818e8666 --- /dev/null +++ b/Source/External/ExCSS/Model/Selector/NthLastChildSelector.cs @@ -0,0 +1,13 @@ +using System; + +// ReSharper disable once CheckNamespace +namespace ExCSS +{ + internal sealed class NthLastChildSelector : NthChildSelector, IToString + { + public override string ToString(bool friendlyFormat, int indentation = 0) + { + return FormatSelector(PseudoSelectorPrefix.PseudoFunctionNthlastchild); + } + } +} \ No newline at end of file diff --git a/Source/External/ExCSS/Model/Selector/NthLastOfTypeSelector.cs b/Source/External/ExCSS/Model/Selector/NthLastOfTypeSelector.cs new file mode 100644 index 0000000000000000000000000000000000000000..b1bbf9182672c3ffc5987ae67a60dbd29d02009c --- /dev/null +++ b/Source/External/ExCSS/Model/Selector/NthLastOfTypeSelector.cs @@ -0,0 +1,12 @@ + +// ReSharper disable once CheckNamespace +namespace ExCSS +{ + internal sealed class NthLastOfTypeSelector : NthChildSelector, IToString + { + public override string ToString(bool friendlyFormat, int indentation = 0) + { + return FormatSelector(PseudoSelectorPrefix.PseudoFunctionNthLastOfType); + } + } +} \ No newline at end of file diff --git a/Source/External/ExCSS/Model/Selector/NthOfTypeSelector.cs b/Source/External/ExCSS/Model/Selector/NthOfTypeSelector.cs new file mode 100644 index 0000000000000000000000000000000000000000..66a704cbb8f78f465948f8fb2b5d8f9386a9f839 --- /dev/null +++ b/Source/External/ExCSS/Model/Selector/NthOfTypeSelector.cs @@ -0,0 +1,12 @@ + +// ReSharper disable once CheckNamespace +namespace ExCSS +{ + internal sealed class NthOfTypeSelector : NthChildSelector, IToString + { + public override string ToString(bool friendlyFormat, int indentation = 0) + { + return FormatSelector(PseudoSelectorPrefix.PseudoFunctionNthOfType); + } + } +} \ No newline at end of file diff --git a/Source/External/ExCSS/Model/Selector/SelectorFactory.cs b/Source/External/ExCSS/Model/Selector/SelectorFactory.cs new file mode 100644 index 0000000000000000000000000000000000000000..127b2ab1969980de4fd3cae20b8b17bb5161ef21 --- /dev/null +++ b/Source/External/ExCSS/Model/Selector/SelectorFactory.cs @@ -0,0 +1,802 @@ +using System; +using System.Globalization; +using ExCSS.Model; +using ExCSS.Model.TextBlocks; + +// ReSharper disable once CheckNamespace +namespace ExCSS +{ + internal sealed class SelectorFactory + { + private SelectorOperation _selectorOperation; + private BaseSelector _currentSelector; + private AggregateSelectorList _aggregateSelectorList; + private ComplexSelector _complexSelector; + private bool _hasCombinator; + private Combinator _combinator; + private SelectorFactory _nestedSelectorFactory; + private string _attributeName; + private string _attributeValue; + private string _attributeOperator; + + internal SelectorFactory() + { + ResetFactory(); + } + + internal BaseSelector GetSelector() + { + if (_complexSelector != null) + { + _complexSelector.ConcludeSelector(_currentSelector); + _currentSelector = _complexSelector; + } + + if (_aggregateSelectorList == null || _aggregateSelectorList.Length == 0) + { + return _currentSelector ?? SimpleSelector.All; + } + + if (_currentSelector == null && _aggregateSelectorList.Length == 1) + { + return _aggregateSelectorList[0]; + } + + if (_currentSelector == null) + { + return _aggregateSelectorList; + } + + _aggregateSelectorList.AppendSelector(_currentSelector); + _currentSelector = null; + + return _aggregateSelectorList; + } + + internal void Apply(Block token) + { + switch (_selectorOperation) + { + case SelectorOperation.Data: + ParseSymbol(token); + break; + + case SelectorOperation.Class: + PraseClass(token); + break; + + case SelectorOperation.Attribute: + ParseAttribute(token); + break; + + case SelectorOperation.AttributeOperator: + ParseAttributeOperator(token); + break; + + case SelectorOperation.AttributeValue: + ParseAttributeValue(token); + break; + + case SelectorOperation.AttributeEnd: + ParseAttributeEnd(token); + break; + + case SelectorOperation.PseudoClass: + ParsePseudoClass(token); + break; + + case SelectorOperation.PseudoClassFunction: + ParsePseudoClassFunction(token); + break; + + case SelectorOperation.PseudoClassFunctionEnd: + PrasePseudoClassFunctionEnd(token); + break; + + case SelectorOperation.PseudoElement: + ParsePseudoElement(token); + break; + } + } + + internal SelectorFactory ResetFactory() + { + _attributeName = null; + _attributeValue = null; + _attributeOperator = string.Empty; + _selectorOperation = SelectorOperation.Data; + _combinator = Combinator.Descendent; + _hasCombinator = false; + _currentSelector = null; + _aggregateSelectorList = null; + _complexSelector = null; + + return this; + } + + private void ParseSymbol(Block token) + { + switch (token.GrammarSegment) + { + // Attribute [A] + case GrammarSegment.SquareBraceOpen: + _attributeName = null; + _attributeValue = null; + _attributeOperator = string.Empty; + _selectorOperation = SelectorOperation.Attribute; + return; + + // Pseudo :P + case GrammarSegment.Colon: + _selectorOperation = SelectorOperation.PseudoClass; + return; + + // ID #I + case GrammarSegment.Hash: + Insert(SimpleSelector.Id(((SymbolBlock)token).Value)); + return; + + // Type E + case GrammarSegment.Ident: + Insert(SimpleSelector.Type(((SymbolBlock)token).Value)); + return; + + // Whitespace + case GrammarSegment.Whitespace: + Insert(Combinator.Descendent); + return; + + case GrammarSegment.Delimiter: + ParseDelimiter(token); + return; + + case GrammarSegment.Comma: + InsertCommaDelimited(); + return; + } + } + + private void ParseAttribute(Block token) + { + if (token.GrammarSegment == GrammarSegment.Whitespace) + { + return; + } + + _selectorOperation = SelectorOperation.AttributeOperator; + + switch (token.GrammarSegment) + { + case GrammarSegment.Ident: + _attributeName = ((SymbolBlock)token).Value; + break; + + case GrammarSegment.String: + _attributeName = ((StringBlock)token).Value; + break; + + default: + _selectorOperation = SelectorOperation.Data; + break; + } + } + + private void ParseAttributeOperator(Block token) + { + if (token.GrammarSegment == GrammarSegment.Whitespace) + { + return; + } + + _selectorOperation = SelectorOperation.AttributeValue; + + if (token.GrammarSegment == GrammarSegment.SquareBracketClose) + { + ParseAttributeEnd(token); + } + else if (token is MatchBlock || token.GrammarSegment == GrammarSegment.Delimiter) + { + _attributeOperator = token.ToString(); + } + else + { + _selectorOperation = SelectorOperation.AttributeEnd; + } + } + + private void ParseAttributeValue(Block token) + { + if (token.GrammarSegment == GrammarSegment.Whitespace) + { + return; + } + + _selectorOperation = SelectorOperation.AttributeEnd; + + switch (token.GrammarSegment) + { + case GrammarSegment.Ident: + _attributeValue = ((SymbolBlock)token).Value; + break; + + case GrammarSegment.String: + _attributeValue = ((StringBlock)token).Value; + break; + + case GrammarSegment.Number: + _attributeValue = ((NumericBlock)token).Value.ToString(CultureInfo.InvariantCulture); + break; + + default: + _selectorOperation = SelectorOperation.Data; + break; + } + } + + private void ParseAttributeEnd(Block token) + { + if (token.GrammarSegment == GrammarSegment.Whitespace) + { + return; + } + + _selectorOperation = SelectorOperation.Data; + + if (token.GrammarSegment != GrammarSegment.SquareBracketClose) + { + return; + } + + switch (_attributeOperator) + { + case "=": + Insert(SimpleSelector.AttributeMatch(_attributeName, _attributeValue)); + break; + + case "~=": + Insert(SimpleSelector.AttributeSpaceSeparated(_attributeName, _attributeValue)); + break; + + case "|=": + Insert(SimpleSelector.AttributeDashSeparated(_attributeName, _attributeValue)); + break; + + case "^=": + Insert(SimpleSelector.AttributeStartsWith(_attributeName, _attributeValue)); + break; + + case "$=": + Insert(SimpleSelector.AttributeEndsWith(_attributeName, _attributeValue)); + break; + + case "*=": + Insert(SimpleSelector.AttributeContains(_attributeName, _attributeValue)); + break; + + case "!=": + Insert(SimpleSelector.AttributeNegatedMatch(_attributeName, _attributeValue)); + break; + + default: + Insert(SimpleSelector.AttributeUnmatched(_attributeName)); + break; + } + } + + private void ParsePseudoClass(Block token) + { + _selectorOperation = SelectorOperation.Data; + + switch (token.GrammarSegment) + { + case GrammarSegment.Colon: + _selectorOperation = SelectorOperation.PseudoElement; + break; + + case GrammarSegment.Function: + _attributeName = ((SymbolBlock)token).Value; + _attributeValue = string.Empty; + _selectorOperation = SelectorOperation.PseudoClassFunction; + + if (_nestedSelectorFactory != null) + { + _nestedSelectorFactory.ResetFactory(); + } + + break; + + case GrammarSegment.Ident: + var pseudoSelector = GetPseudoSelector(token); + + if (pseudoSelector != null) + { + Insert(pseudoSelector); + } + break; + } + } + + private void ParsePseudoElement(Block token) + { + if (token.GrammarSegment != GrammarSegment.Ident) + { + return; + } + var data = ((SymbolBlock)token).Value; + + switch (data) + { + case PseudoSelectorPrefix.PseudoElementBefore: + Insert(SimpleSelector.PseudoElement(PseudoSelectorPrefix.PseudoElementBefore)); + break; + + case PseudoSelectorPrefix.PseudoElementAfter: + Insert(SimpleSelector.PseudoElement(PseudoSelectorPrefix.PseudoElementAfter)); + break; + + case PseudoSelectorPrefix.PseudoElementSelection: + Insert(SimpleSelector.PseudoElement(PseudoSelectorPrefix.PseudoElementSelection)); + break; + + case PseudoSelectorPrefix.PseudoElementFirstline: + Insert(SimpleSelector.PseudoElement(PseudoSelectorPrefix.PseudoElementFirstline)); + break; + + case PseudoSelectorPrefix.PseudoElementFirstletter: + Insert(SimpleSelector.PseudoElement(PseudoSelectorPrefix.PseudoElementFirstletter)); + break; + + default: + Insert(SimpleSelector.PseudoElement(data)); + break; + } + } + + private void PraseClass(Block token) + { + _selectorOperation = SelectorOperation.Data; + + if (token.GrammarSegment == GrammarSegment.Ident) + { + Insert(SimpleSelector.Class(((SymbolBlock)token).Value)); + } + } + + private void ParsePseudoClassFunction(Block token) + { + if (token.GrammarSegment == GrammarSegment.Whitespace) + { + return; + } + + switch (_attributeName) + { + case PseudoSelectorPrefix.PseudoFunctionNthchild: + case PseudoSelectorPrefix.PseudoFunctionNthlastchild: + case PseudoSelectorPrefix.PseudoFunctionNthOfType: + case PseudoSelectorPrefix.PseudoFunctionNthLastOfType: + { + switch (token.GrammarSegment) + { + case GrammarSegment.Ident: + case GrammarSegment.Number: + case GrammarSegment.Dimension: + _attributeValue += token.ToString(); + return; + + case GrammarSegment.Delimiter: + var chr = ((DelimiterBlock)token).Value; + + if (chr == Specification.PlusSign || chr == Specification.MinusSign) + { + _attributeValue += chr; + return; + } + + break; + } + + break; + } + case PseudoSelectorPrefix.PseudoFunctionNot: + { + if (_nestedSelectorFactory == null) + { + _nestedSelectorFactory = new SelectorFactory(); + } + + if (token.GrammarSegment != GrammarSegment.ParenClose || _nestedSelectorFactory._selectorOperation != SelectorOperation.Data) + { + _nestedSelectorFactory.Apply(token); + return; + } + + break; + } + case PseudoSelectorPrefix.PseudoFunctionDir: + { + if (token.GrammarSegment == GrammarSegment.Ident) + { + _attributeValue = ((SymbolBlock)token).Value; + } + + _selectorOperation = SelectorOperation.PseudoClassFunctionEnd; + return; + } + case PseudoSelectorPrefix.PseudoFunctionLang: + { + if (token.GrammarSegment == GrammarSegment.Ident) + { + _attributeValue = ((SymbolBlock)token).Value; + } + + _selectorOperation = SelectorOperation.PseudoClassFunctionEnd; + return; + } + case PseudoSelectorPrefix.PseudoFunctionContains: + { + switch (token.GrammarSegment) + { + case GrammarSegment.String: + _attributeValue = ((StringBlock)token).Value; + break; + + case GrammarSegment.Ident: + _attributeValue = ((SymbolBlock)token).Value; + break; + } + + _selectorOperation = SelectorOperation.PseudoClassFunctionEnd; + return; + } + } + + PrasePseudoClassFunctionEnd(token); + } + + private void PrasePseudoClassFunctionEnd(Block token) + { + _selectorOperation = SelectorOperation.Data; + + if (token.GrammarSegment != GrammarSegment.ParenClose) + { + return; + } + + switch (_attributeName) + { + case PseudoSelectorPrefix.PseudoFunctionNthchild: + Insert(GetChildSelector()); + break; + + case PseudoSelectorPrefix.PseudoFunctionNthlastchild: + Insert(GetChildSelector()); + break; + + case PseudoSelectorPrefix.PseudoFunctionNthOfType: + Insert(GetChildSelector()); + break; + + case PseudoSelectorPrefix.PseudoFunctionNthLastOfType: + Insert(GetChildSelector()); + break; + + case PseudoSelectorPrefix.PseudoFunctionNot: + { + var selector = _nestedSelectorFactory.GetSelector(); + var code = string.Format("{0}({1})", PseudoSelectorPrefix.PseudoFunctionNot, selector); + Insert(SimpleSelector.PseudoClass(code)); + break; + } + case PseudoSelectorPrefix.PseudoFunctionDir: + { + var code = string.Format("{0}({1})", PseudoSelectorPrefix.PseudoFunctionDir, _attributeValue); + Insert(SimpleSelector.PseudoClass(code)); + break; + } + case PseudoSelectorPrefix.PseudoFunctionLang: + { + var code = string.Format("{0}({1})", PseudoSelectorPrefix.PseudoFunctionLang, _attributeValue); + Insert(SimpleSelector.PseudoClass(code)); + break; + } + case PseudoSelectorPrefix.PseudoFunctionContains: + { + var code = string.Format("{0}({1})", PseudoSelectorPrefix.PseudoFunctionContains, _attributeValue); + Insert(SimpleSelector.PseudoClass(code)); + break; + } + } + } + + private void InsertCommaDelimited() + { + if (_currentSelector == null) + { + return; + } + + if (_aggregateSelectorList == null) + { + _aggregateSelectorList = new AggregateSelectorList(","); + } + + if (_complexSelector != null) + { + _complexSelector.ConcludeSelector(_currentSelector); + _aggregateSelectorList.AppendSelector(_complexSelector); + _complexSelector = null; + } + else + { + _aggregateSelectorList.AppendSelector(_currentSelector); + } + + _currentSelector = null; + } + + private void Insert(BaseSelector selector) + { + if (_currentSelector != null) + { + if (!_hasCombinator) + { + var compound = _currentSelector as AggregateSelectorList; + + if (compound == null) + { + compound = new AggregateSelectorList(""); + compound.AppendSelector(_currentSelector); + } + + compound.AppendSelector(selector); + _currentSelector = compound; + } + else + { + if (_complexSelector == null) + { + _complexSelector = new ComplexSelector(); + } + + _complexSelector.AppendSelector(_currentSelector, _combinator); + _combinator = Combinator.Descendent; + _hasCombinator = false; + _currentSelector = selector; + } + } + else + { + if (_currentSelector == null && _complexSelector == null && _combinator == Combinator.Namespace) + { + _complexSelector = new ComplexSelector(); + _complexSelector.AppendSelector(SimpleSelector.Type(""), _combinator); + _currentSelector = selector; + } + else + { + _combinator = Combinator.Descendent; + _hasCombinator = false; + _currentSelector = selector; + } + } + } + + private void Insert(Combinator combinator) + { + _hasCombinator = true; + + if (combinator != Combinator.Descendent) + { + _combinator = combinator; + } + } + + private void ParseDelimiter(Block token) + { + switch (((DelimiterBlock)token).Value) + { + case Specification.Comma: + InsertCommaDelimited(); + return; + + case Specification.GreaterThan: + Insert(Combinator.Child); + return; + + case Specification.PlusSign: + Insert(Combinator.AdjacentSibling); + return; + + case Specification.Tilde: + Insert(Combinator.Sibling); + return; + + case Specification.Asterisk: + Insert(SimpleSelector.All); + return; + + case Specification.Period: + _selectorOperation = SelectorOperation.Class; + return; + + case Specification.Pipe: + Insert(Combinator.Namespace); + return; + } + } + + private BaseSelector GetChildSelector() where T : NthChildSelector, new() + { + var selector = new T(); + + if (_attributeValue.Equals(PseudoSelectorPrefix.NthChildOdd, StringComparison.OrdinalIgnoreCase)) + { + selector.Step = 2; + selector.Offset = 1; + selector.FunctionText = PseudoSelectorPrefix.NthChildOdd; + } + else if (_attributeValue.Equals(PseudoSelectorPrefix.NthChildEven, StringComparison.OrdinalIgnoreCase)) + { + selector.Step = 2; + selector.Offset = 0; + selector.FunctionText = PseudoSelectorPrefix.NthChildEven; + } + else if (!int.TryParse(_attributeValue, out selector.Offset)) + { + var index = _attributeValue.IndexOf(PseudoSelectorPrefix.NthChildN, StringComparison.OrdinalIgnoreCase); + + if (_attributeValue.Length <= 0 || index == -1) + { + return selector; + } + + var first = _attributeValue.Substring(0, index).Replace(" ", ""); + + var second = ""; + + if (_attributeValue.Length > index + 1) + { + second = _attributeValue.Substring(index + 1).Replace(" ", ""); + } + + if (first == string.Empty || (first.Length == 1 && first[0] == Specification.PlusSign)) + { + selector.Step = 1; + } + else if (first.Length == 1 && first[0] == Specification.MinusSign) + { + selector.Step = -1; + } + else + { + int step; + if (int.TryParse(first, out step)) + { + selector.Step = step; + } + } + + if (second == string.Empty) + { + selector.Offset = 0; + } + else + { + int offset; + if (int.TryParse(second, out offset)) + { + selector.Offset = offset; + } + } + } + + return selector; + } + + private static BaseSelector GetPseudoSelector(Block token) + { + switch (((SymbolBlock)token).Value) + { + case PseudoSelectorPrefix.PseudoRoot: + return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoRoot); + + case PseudoSelectorPrefix.PseudoFirstOfType: + return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoFirstOfType); + + case PseudoSelectorPrefix.PseudoLastoftype: + return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoLastoftype); + + case PseudoSelectorPrefix.PseudoOnlychild: + return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoOnlychild); + + case PseudoSelectorPrefix.PseudoOnlyOfType: + return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoOnlyOfType); + + case PseudoSelectorPrefix.PseudoFirstchild: + return FirstChildSelector.Instance; + + case PseudoSelectorPrefix.PseudoLastchild: + return LastChildSelector.Instance; + + case PseudoSelectorPrefix.PseudoEmpty: + return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoEmpty); + + case PseudoSelectorPrefix.PseudoLink: + return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoLink); + + case PseudoSelectorPrefix.PseudoVisited: + return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoVisited); + + case PseudoSelectorPrefix.PseudoActive: + return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoActive); + + case PseudoSelectorPrefix.PseudoHover: + return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoHover); + + case PseudoSelectorPrefix.PseudoFocus: + return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoFocus); + + case PseudoSelectorPrefix.PseudoTarget: + return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoTarget); + + case PseudoSelectorPrefix.PseudoEnabled: + return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoEnabled); + + case PseudoSelectorPrefix.PseudoDisabled: + return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoDisabled); + + case PseudoSelectorPrefix.PseudoDefault: + return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoDefault); + + case PseudoSelectorPrefix.PseudoChecked: + return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoChecked); + + case PseudoSelectorPrefix.PseudoIndeterminate: + return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoIndeterminate); + + case PseudoSelectorPrefix.PseudoUnchecked: + return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoUnchecked); + + case PseudoSelectorPrefix.PseudoValid: + return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoValid); + + case PseudoSelectorPrefix.PseudoInvalid: + return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoInvalid); + + case PseudoSelectorPrefix.PseudoRequired: + return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoRequired); + + case PseudoSelectorPrefix.PseudoReadonly: + return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoReadonly); + + case PseudoSelectorPrefix.PseudoReadwrite: + return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoReadwrite); + + case PseudoSelectorPrefix.PseudoInrange: + return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoInrange); + + case PseudoSelectorPrefix.PseudoOutofrange: + return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoOutofrange); + + case PseudoSelectorPrefix.PseudoOptional: + return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoOptional); + + case PseudoSelectorPrefix.PseudoElementBefore: + return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoElementBefore); + + case PseudoSelectorPrefix.PseudoElementAfter: + return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoElementAfter); + + case PseudoSelectorPrefix.PseudoElementFirstline: + return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoElementFirstline); + + case PseudoSelectorPrefix.PseudoElementFirstletter: + return SimpleSelector.PseudoClass(PseudoSelectorPrefix.PseudoElementFirstletter); + + default: + return SimpleSelector.PseudoClass(token.ToString()); + } + } + } +} diff --git a/Source/External/ExCSS/Model/Selector/SelectorList.cs b/Source/External/ExCSS/Model/Selector/SelectorList.cs new file mode 100644 index 0000000000000000000000000000000000000000..dc9b7f204ba8d06a495f3d556357d95745ca8ce0 --- /dev/null +++ b/Source/External/ExCSS/Model/Selector/SelectorList.cs @@ -0,0 +1,57 @@ +using System.Collections; +using System.Collections.Generic; + +// ReSharper disable once CheckNamespace +namespace ExCSS +{ + public abstract class SelectorList : BaseSelector, IEnumerable + { + protected List Selectors; + + protected SelectorList() + { + Selectors = new List(); + } + + public int Length + { + get { return Selectors.Count; } + } + + public BaseSelector this[int index] + { + get { return Selectors[index]; } + set { Selectors[index] = value; } + } + + public SelectorList AppendSelector(BaseSelector selector) + { + Selectors.Add(selector); + return this; + } + + public SelectorList RemoveSelector(SimpleSelector selector) + { + Selectors.Remove(selector); + return this; + } + + public SelectorList ClearSelectors() + { + Selectors.Clear(); + return this; + } + + public IEnumerator GetEnumerator() + { + return Selectors.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable)Selectors).GetEnumerator(); + } + + public override abstract string ToString(bool friendlyFormat, int indentation = 0); + } +} diff --git a/Source/External/ExCSS/Model/Selector/SimpleSelector.cs b/Source/External/ExCSS/Model/Selector/SimpleSelector.cs new file mode 100644 index 0000000000000000000000000000000000000000..0fc2f29d3c27a5079189b516956ff290cdc7767f --- /dev/null +++ b/Source/External/ExCSS/Model/Selector/SimpleSelector.cs @@ -0,0 +1,126 @@ +using System; +using ExCSS.Model; +// ReSharper disable once CheckNamespace + +namespace ExCSS +{ + public sealed class SimpleSelector : BaseSelector + { + private readonly string _code; + internal static readonly SimpleSelector All = new SimpleSelector("*"); + + public SimpleSelector(string selectorText) + { + _code = selectorText; + } + + internal static SimpleSelector PseudoElement(string pseudoElement) + { + return new SimpleSelector("::" + pseudoElement); + } + + internal static SimpleSelector PseudoClass(string pseudoClass) + { + return new SimpleSelector(":" + pseudoClass); + } + + internal static SimpleSelector Class(string match) + { + return new SimpleSelector("." + match); + } + + internal static SimpleSelector Id(string match) + { + return new SimpleSelector("#" + match); + } + + internal static SimpleSelector AttributeUnmatched(string match) + { + return new SimpleSelector("[" + match + "]"); + } + + internal static SimpleSelector AttributeMatch(string match, string value) + { + var code = string.Format("[{0}=\"{1}\"]", match, GetValueAsString(value)); + return new SimpleSelector(code); + } + + internal static SimpleSelector AttributeNegatedMatch(string match, string value) + { + var code = string.Format("[{0}!=\"{1}\"]", match, GetValueAsString(value)); + return new SimpleSelector(code); + } + + internal static SimpleSelector AttributeSpaceSeparated(string match, string value) + { + var code = string.Format("[{0}~=\"{1}\"]", match, GetValueAsString(value)); + + return new SimpleSelector(code); + } + + internal static SimpleSelector AttributeStartsWith(string match, string value) + { + var code = string.Format("[{0}^=\"{1}\"]", match, GetValueAsString(value)); + + return new SimpleSelector(code); + } + + internal static SimpleSelector AttributeEndsWith(string match, string value) + { + var code = string.Format("[{0}$=\"{1}\"]", match, GetValueAsString(value)); + + return new SimpleSelector(code); + } + + internal static SimpleSelector AttributeContains(string match, string value) + { + var code = string.Format("[{0}*=\"{1}\"]", match, GetValueAsString(value)); + + return new SimpleSelector(code); + } + + internal static SimpleSelector AttributeDashSeparated(string match, string value) + { + var code = string.Format("[{0}|=\"{1}\"]", match, GetValueAsString(value)); + + return new SimpleSelector(code); + } + + internal static SimpleSelector Type(string match) + { + return new SimpleSelector(match); + } + + private static string GetValueAsString(string value) + { + var containsSpace = false; + + for (var i = 0; i < value.Length; i++) + { + if (!value[i].IsSpaceCharacter()) + { + continue; + } + containsSpace = true; + break; + } + + if (!containsSpace) + { + return value; + } + + if (value.IndexOf(Specification.SingleQuote) != -1) + { + return '"' + value + '"'; + } + + return "'" + value + "'"; + } + + public override string ToString(bool friendlyFormat, int indentation = 0) + { + return _code; + } + } +} diff --git a/Source/External/ExCSS/Model/Specification.cs b/Source/External/ExCSS/Model/Specification.cs new file mode 100644 index 0000000000000000000000000000000000000000..2da18d370ddaa2c3b2fbc6cf5027357dd9acaffb --- /dev/null +++ b/Source/External/ExCSS/Model/Specification.cs @@ -0,0 +1,98 @@ +namespace ExCSS.Model +{ + internal static class Specification + { + internal const char EndOfFile = (char)0x1a; + internal const char Tilde = (char)0x7e; + internal const char Pipe = (char)0x7c; + internal const char Null = (char)0x0; + internal const char Ampersand = (char)0x26; + internal const char Hash = (char)0x23; + internal const char DollarSign = (char)0x24; + internal const char Simicolon = (char)0x3b; + internal const char Asterisk = (char)0x2a; + internal const char EqualSign = (char)0x3d; + internal const char PlusSign = (char)0x2b; + internal const char Comma = (char)0x2c; + internal const char Period = (char)0x2e; + internal const char Accent = (char)0x5e; + internal const char At = (char)0x40; + internal const char LessThan = (char)0x3c; + internal const char GreaterThan = (char)0x3e; + internal const char SingleQuote = (char)0x27; + internal const char DoubleQuote = (char)0x22; + internal const char QuestionMark = (char)0x3f; + internal const char Tab = (char)0x09; + internal const char LineFeed = (char)0x0a; + internal const char CarriageReturn = (char)0x0d; + internal const char FormFeed = (char)0x0c; + internal const char Space = (char)0x20; + internal const char Solidus = (char)0x2f; + internal const char ReverseSolidus = (char)0x5c; + internal const char Colon = (char)0x3a; + internal const char Em = (char)0x21; + internal const char MinusSign = (char)0x2d; + internal const char Replacement = (char)0xfffd; + internal const char Underscore = (char)0x5f; + internal const char ParenOpen = (char)0x28; + internal const char ParenClose = (char)0x29; + internal const char Percent = (char)0x25; + internal const char SquareBracketOpen =(char)0x5b; + internal const char SquareBracketClose = (char)0x5d; + internal const char CurlyBraceOpen = (char)0x7b; + internal const char CurlyBraceClose = (char)0x7d; + internal const int MaxPoint = 0x10FFFF;/// The maximum allowed codepoint (defined in Unicode). + + internal static bool IsNonPrintable(this char c) + { + return (c >= 0x0 && c <= 0x8) || (c >= 0xe && c <= 0x1f) || (c >= 0x7f && c <= 0x9f); + } + + internal static bool IsLetter(this char c) + { + return IsUppercaseAscii(c) || IsLowercaseAscii(c); + } + + internal static bool IsName(this char c) + { + return c >= 0x80 || c.IsLetter() || c == Underscore || c == MinusSign || IsDigit(c); + } + + internal static bool IsNameStart(this char c) + { + return c >= 0x80 || IsUppercaseAscii(c) || IsLowercaseAscii(c) || c == Underscore; + } + + internal static bool IsLineBreak(this char c) + { + //line feed, carriage return + return c == LineFeed || c == CarriageReturn; + } + + internal static bool IsSpaceCharacter(this char c) + { + //white space, tab, line feed, form feed, carriage return + return c == Space || c == Tab || c == LineFeed || c == FormFeed || c == CarriageReturn; + } + + internal static bool IsDigit(this char c) + { + return c >= 0x30 && c <= 0x39; + } + + internal static bool IsUppercaseAscii(this char c) + { + return c >= 0x41 && c <= 0x5a; + } + + internal static bool IsLowercaseAscii(this char c) + { + return c >= 0x61 && c <= 0x7a; + } + + internal static bool IsHex(this char c) + { + return IsDigit(c) || (c >= 0x41 && c <= 0x46) || (c >= 0x61 && c <= 0x66); + } + } +} \ No newline at end of file diff --git a/Source/External/ExCSS/Model/TextBlocks/Block.cs b/Source/External/ExCSS/Model/TextBlocks/Block.cs new file mode 100644 index 0000000000000000000000000000000000000000..16f02dc80eb98ec759b3f1c70203c022366b4581 --- /dev/null +++ b/Source/External/ExCSS/Model/TextBlocks/Block.cs @@ -0,0 +1,28 @@ + +namespace ExCSS.Model.TextBlocks +{ + internal abstract class Block + { + internal GrammarSegment GrammarSegment { get;set; } + + internal static PipeBlock Column + { + get { return PipeBlock.Token; } + } + + internal static DelimiterBlock Delim(char value) + { + return new DelimiterBlock(value); + } + + internal static NumericBlock Number(string value) + { + return new NumericBlock(value); + } + + internal static RangeBlock Range(string start, string end) + { + return new RangeBlock().SetRange(start, end); + } + } +} diff --git a/Source/External/ExCSS/Model/TextBlocks/BracketBlock.cs b/Source/External/ExCSS/Model/TextBlocks/BracketBlock.cs new file mode 100644 index 0000000000000000000000000000000000000000..5de795bd3fdada2390fee7511f0879b6973ff5a3 --- /dev/null +++ b/Source/External/ExCSS/Model/TextBlocks/BracketBlock.cs @@ -0,0 +1,123 @@ + +namespace ExCSS.Model.TextBlocks +{ + internal class BracketBlock : Block + { + private readonly static BracketBlock RoundOpen= new BracketBlock { GrammarSegment = GrammarSegment.ParenOpen, _mirror = GrammarSegment.ParenClose }; + private readonly static BracketBlock RoundClose = new BracketBlock { GrammarSegment = GrammarSegment.ParenClose, _mirror = GrammarSegment.ParenOpen }; + private readonly static BracketBlock CurlyOpen = new BracketBlock { GrammarSegment = GrammarSegment.CurlyBraceOpen, _mirror = GrammarSegment.CurlyBracketClose }; + private readonly static BracketBlock CurlyClose = new BracketBlock { GrammarSegment = GrammarSegment.CurlyBracketClose, _mirror = GrammarSegment.CurlyBraceOpen }; + private readonly static BracketBlock SquareOpen = new BracketBlock { GrammarSegment = GrammarSegment.SquareBraceOpen, _mirror = GrammarSegment.SquareBracketClose }; + private readonly static BracketBlock SquareClose = new BracketBlock { GrammarSegment = GrammarSegment.SquareBracketClose, _mirror = GrammarSegment.SquareBraceOpen }; + + private GrammarSegment _mirror; + + BracketBlock() + { + } + + internal char Open + { + get + { + switch (GrammarSegment) + { + case GrammarSegment.ParenOpen: + return '('; + + case GrammarSegment.SquareBraceOpen: + return '['; + + default: + return '{'; + + } + } + } + + internal char Close + { + get + { + switch (GrammarSegment) + { + case GrammarSegment.ParenOpen: + return ')'; + + case GrammarSegment.SquareBraceOpen: + return ']'; + + default: + return '}'; + + } + } + } + + internal GrammarSegment Mirror + { + get { return _mirror; } + } + + internal static BracketBlock OpenRound + { + get { return RoundOpen; } + } + + internal static BracketBlock CloseRound + { + get { return RoundClose; } + } + + internal static BracketBlock OpenCurly + { + get { return CurlyOpen; } + } + + internal static BracketBlock CloseCurly + { + get { return CurlyClose; } + } + + internal static BracketBlock OpenSquare + { + get { return SquareOpen; } + } + + internal static BracketBlock CloseSquare + { + get { return SquareClose; } + } + + public override string ToString() + { + return ToString(false); + } + + public string ToString(bool friendlyFormat, int indentation = 0) + { + switch (GrammarSegment) + { + case GrammarSegment.CurlyBraceOpen: + return "{"; + + case GrammarSegment.CurlyBracketClose: + return "}"; + + case GrammarSegment.ParenClose: + return ")"; + + case GrammarSegment.ParenOpen: + return "("; + + case GrammarSegment.SquareBracketClose: + return "]"; + + case GrammarSegment.SquareBraceOpen: + return "["; + } + + return string.Empty; + } + } +} diff --git a/Source/External/ExCSS/Model/TextBlocks/CharacterBlock.cs b/Source/External/ExCSS/Model/TextBlocks/CharacterBlock.cs new file mode 100644 index 0000000000000000000000000000000000000000..f5c44731402053688a41771144b036f32484d814 --- /dev/null +++ b/Source/External/ExCSS/Model/TextBlocks/CharacterBlock.cs @@ -0,0 +1,23 @@ + +namespace ExCSS.Model.TextBlocks +{ + internal abstract class CharacterBlock : Block + { + private readonly char _value; + + protected CharacterBlock() + { + _value = Specification.Null; + } + + protected CharacterBlock(char value) + { + _value = value; + } + + internal char Value + { + get { return _value; } + } + } +} diff --git a/Source/External/ExCSS/Model/TextBlocks/CommentBlock.cs b/Source/External/ExCSS/Model/TextBlocks/CommentBlock.cs new file mode 100644 index 0000000000000000000000000000000000000000..a9fe661622bb65940d7218d5c81bcbdff94a0fc0 --- /dev/null +++ b/Source/External/ExCSS/Model/TextBlocks/CommentBlock.cs @@ -0,0 +1,35 @@ + +namespace ExCSS.Model.TextBlocks +{ + internal class CommentBlock : Block + { + private readonly static CommentBlock OpenBlock; + private readonly static CommentBlock CloseBlock; + + static CommentBlock() + { + OpenBlock = new CommentBlock { GrammarSegment = GrammarSegment.CommentOpen }; + CloseBlock = new CommentBlock { GrammarSegment = GrammarSegment.CommentClose }; + } + + CommentBlock() + { + } + + + internal static CommentBlock Open + { + get { return OpenBlock; } + } + + internal static CommentBlock Close + { + get { return CloseBlock; } + } + + public override string ToString() + { + return GrammarSegment == GrammarSegment.CommentOpen ? ""; + } + } +} diff --git a/Source/External/ExCSS/Model/TextBlocks/DelimiterBlock.cs b/Source/External/ExCSS/Model/TextBlocks/DelimiterBlock.cs new file mode 100644 index 0000000000000000000000000000000000000000..6e14f444ee2a42349ba8c8ad6c0829d12ad4d5a1 --- /dev/null +++ b/Source/External/ExCSS/Model/TextBlocks/DelimiterBlock.cs @@ -0,0 +1,23 @@ + +using System.Globalization; + +namespace ExCSS.Model.TextBlocks +{ + internal class DelimiterBlock : CharacterBlock + { + internal DelimiterBlock() + { + GrammarSegment = GrammarSegment.Delimiter; + } + + internal DelimiterBlock(char value) : base(value) + { + GrammarSegment = GrammarSegment.Delimiter; + } + + public override string ToString() + { + return Value.ToString(CultureInfo.InvariantCulture); + } + } +} diff --git a/Source/External/ExCSS/Model/TextBlocks/MatchBlock.cs b/Source/External/ExCSS/Model/TextBlocks/MatchBlock.cs new file mode 100644 index 0000000000000000000000000000000000000000..eb334c067a31fe01f28bcf9d40affd63d5a44599 --- /dev/null +++ b/Source/External/ExCSS/Model/TextBlocks/MatchBlock.cs @@ -0,0 +1,39 @@ + +namespace ExCSS.Model.TextBlocks +{ + internal class MatchBlock : Block + { + internal readonly static MatchBlock Include = new MatchBlock { GrammarSegment = GrammarSegment.IncludeMatch }; + internal readonly static MatchBlock Dash = new MatchBlock { GrammarSegment = GrammarSegment.DashMatch }; + internal readonly static Block Prefix = new MatchBlock { GrammarSegment = GrammarSegment.PrefixMatch }; + internal readonly static Block Substring = new MatchBlock { GrammarSegment = GrammarSegment.SubstringMatch }; + internal readonly static Block Suffix = new MatchBlock { GrammarSegment = GrammarSegment.SuffixMatch }; + internal readonly static Block Not = new MatchBlock { GrammarSegment = GrammarSegment.NegationMatch }; + + public override string ToString() + { + switch (GrammarSegment) + { + case GrammarSegment.SubstringMatch: + return "*="; + + case GrammarSegment.SuffixMatch: + return "$="; + + case GrammarSegment.PrefixMatch: + return "^="; + + case GrammarSegment.IncludeMatch: + return "~="; + + case GrammarSegment.DashMatch: + return "|="; + + case GrammarSegment.NegationMatch: + return "!="; + } + + return string.Empty; + } + } +} diff --git a/Source/External/ExCSS/Model/TextBlocks/NumericBlock.cs b/Source/External/ExCSS/Model/TextBlocks/NumericBlock.cs new file mode 100644 index 0000000000000000000000000000000000000000..facab18ea5e2c17aaa203085b37aa891a6509981 --- /dev/null +++ b/Source/External/ExCSS/Model/TextBlocks/NumericBlock.cs @@ -0,0 +1,26 @@ +using System; +using System.Globalization; + +namespace ExCSS.Model.TextBlocks +{ + internal class NumericBlock : Block + { + private readonly string _data; + + internal NumericBlock(string number) + { + _data = number; + GrammarSegment = GrammarSegment.Number; + } + + public Single Value + { + get { return Single.Parse(_data, CultureInfo.InvariantCulture); } + } + + public override string ToString() + { + return _data; + } + } +} diff --git a/Source/External/ExCSS/Model/TextBlocks/PipeBlock.cs b/Source/External/ExCSS/Model/TextBlocks/PipeBlock.cs new file mode 100644 index 0000000000000000000000000000000000000000..8beefed39e73a190eb6829e39817e783598e1ffc --- /dev/null +++ b/Source/External/ExCSS/Model/TextBlocks/PipeBlock.cs @@ -0,0 +1,28 @@ + +namespace ExCSS.Model.TextBlocks +{ + internal class PipeBlock : Block + { + private readonly static PipeBlock TokenBlock; + + static PipeBlock() + { + TokenBlock = new PipeBlock(); + } + + PipeBlock() + { + GrammarSegment = GrammarSegment.Column; + } + + internal static PipeBlock Token + { + get { return TokenBlock; } + } + + public override string ToString() + { + return "||"; + } + } +} diff --git a/Source/External/ExCSS/Model/TextBlocks/RangeBlock.cs b/Source/External/ExCSS/Model/TextBlocks/RangeBlock.cs new file mode 100644 index 0000000000000000000000000000000000000000..56471cb18f6f58ccfe9d5bb47b728224348b8efb --- /dev/null +++ b/Source/External/ExCSS/Model/TextBlocks/RangeBlock.cs @@ -0,0 +1,69 @@ +using System.Collections.Generic; + +namespace ExCSS.Model.TextBlocks +{ + internal class RangeBlock : Block + { + public RangeBlock() + { + GrammarSegment = GrammarSegment.Range; + } + + internal bool IsEmpty + { + get { return SelectedRange == null || SelectedRange.Length == 0; } + } + + internal string[] SelectedRange { get; private set; } + + internal RangeBlock SetRange(string start, string end) + { + var startValue = int.Parse(start, System.Globalization.NumberStyles.HexNumber); + + if (startValue > Specification.MaxPoint) + { + return this; + } + + if (end == null) + { + SelectedRange = new [] { char.ConvertFromUtf32(startValue) }; + } + else + { + var list = new List(); + var endValue = int.Parse(end, System.Globalization.NumberStyles.HexNumber); + + if (endValue > Specification.MaxPoint) + { + endValue = Specification.MaxPoint; + } + + for (; startValue <= endValue; startValue++) + { + list.Add(char.ConvertFromUtf32(startValue)); + } + + SelectedRange = list.ToArray(); + } + + return this; + } + + public override string ToString() + { + if (IsEmpty) + { + return string.Empty; + } + + if (SelectedRange.Length == 1) + { + return "#" + char.ConvertToUtf32(SelectedRange[0], 0).ToString("x"); + } + + return "#" + char.ConvertToUtf32(SelectedRange[0], 0).ToString("x") + "-#" + + char.ConvertToUtf32(SelectedRange[SelectedRange.Length - 1], 0).ToString("x"); + } + } +} diff --git a/Source/External/ExCSS/Model/TextBlocks/SpecialCharacter.cs b/Source/External/ExCSS/Model/TextBlocks/SpecialCharacter.cs new file mode 100644 index 0000000000000000000000000000000000000000..48fd9a2edeabb463a2614c37a39f4978336bba00 --- /dev/null +++ b/Source/External/ExCSS/Model/TextBlocks/SpecialCharacter.cs @@ -0,0 +1,21 @@ + +namespace ExCSS.Model.TextBlocks +{ + internal class SpecialCharacter : CharacterBlock + { + internal static readonly SpecialCharacter Colon = new SpecialCharacter(Specification.Colon, GrammarSegment.Colon); + internal static readonly SpecialCharacter Comma = new SpecialCharacter(Specification.Comma, GrammarSegment.Comma); + internal static readonly SpecialCharacter Semicolon = new SpecialCharacter(Specification.Simicolon, GrammarSegment.Semicolon); + internal static readonly SpecialCharacter Whitespace = new SpecialCharacter(Specification.Space, GrammarSegment.Whitespace); + + SpecialCharacter(char specialCharacter, GrammarSegment type) : base(specialCharacter) + { + GrammarSegment = type; + } + + public override string ToString() + { + return Value.ToString(); + } + } +} diff --git a/Source/External/ExCSS/Model/TextBlocks/StringBlock.cs b/Source/External/ExCSS/Model/TextBlocks/StringBlock.cs new file mode 100644 index 0000000000000000000000000000000000000000..cce8390b64d345431ac7c38d2401f41d227c8362 --- /dev/null +++ b/Source/External/ExCSS/Model/TextBlocks/StringBlock.cs @@ -0,0 +1,35 @@ + +namespace ExCSS.Model.TextBlocks +{ + internal class StringBlock : Block + { + StringBlock(GrammarSegment type) + { + GrammarSegment = type; + } + + internal static StringBlock Plain(string data, bool bad = false) + { + return new StringBlock(GrammarSegment.String) { Value = data, IsBad = bad }; + } + + internal static StringBlock Url(string data, bool bad = false) + { + return new StringBlock(GrammarSegment.Url) { Value = data, IsBad = bad }; + } + + internal string Value { get; private set; } + + internal bool IsBad { get; private set; } + + public override string ToString() + { + if (GrammarSegment == GrammarSegment.Url) + { + return "url(" + Value + ")"; + } + + return "'" + Value + "'"; + } + } +} diff --git a/Source/External/ExCSS/Model/TextBlocks/SymbolBlock.cs b/Source/External/ExCSS/Model/TextBlocks/SymbolBlock.cs new file mode 100644 index 0000000000000000000000000000000000000000..f2c9024756adcffa2aaf12321d21440d18d1e28f --- /dev/null +++ b/Source/External/ExCSS/Model/TextBlocks/SymbolBlock.cs @@ -0,0 +1,47 @@ + +namespace ExCSS.Model.TextBlocks +{ + internal class SymbolBlock : Block + { + SymbolBlock(GrammarSegment type) + { + GrammarSegment = type; + } + + internal static SymbolBlock Function(string name) + { + return new SymbolBlock(GrammarSegment.Function) { Value = name }; + } + + internal static SymbolBlock Ident(string identifier) + { + return new SymbolBlock(GrammarSegment.Ident) { Value = identifier }; + } + + internal static SymbolBlock At(string name) + { + return new SymbolBlock(GrammarSegment.AtRule) { Value = name }; + } + + internal static SymbolBlock Hash(string characters) + { + return new SymbolBlock(GrammarSegment.Hash) { Value = characters }; + } + + internal string Value { get; private set; } + + public override string ToString() + { + switch (GrammarSegment) + { + case GrammarSegment.Hash: + return "#" + Value; + + case GrammarSegment.AtRule: + return "@" + Value; + } + + return Value; + } + } +} diff --git a/Source/External/ExCSS/Model/TextBlocks/UnitBlock.cs b/Source/External/ExCSS/Model/TextBlocks/UnitBlock.cs new file mode 100644 index 0000000000000000000000000000000000000000..2a21858c4edf1680a1df22190bee8b285fbd53b9 --- /dev/null +++ b/Source/External/ExCSS/Model/TextBlocks/UnitBlock.cs @@ -0,0 +1,37 @@ +using System; +using System.Globalization; + +namespace ExCSS.Model.TextBlocks +{ + internal class UnitBlock : Block + { + private string _value; + + UnitBlock(GrammarSegment type) + { + GrammarSegment = type; + } + + internal Single Value + { + get { return Single.Parse(_value, CultureInfo.InvariantCulture); } + } + + internal string Unit { get; private set; } + + internal static UnitBlock Percentage(string value) + { + return new UnitBlock(GrammarSegment.Percentage) { _value = value, Unit = "%" }; + } + + internal static UnitBlock Dimension(string value, string dimension) + { + return new UnitBlock(GrammarSegment.Dimension) { _value = value, Unit = dimension }; + } + + public override string ToString() + { + return _value + Unit; + } + } +} diff --git a/Source/External/ExCSS/Model/Values/GenericFunction.cs b/Source/External/ExCSS/Model/Values/GenericFunction.cs new file mode 100644 index 0000000000000000000000000000000000000000..6f5ce1a4c46c3e8469161c1b4943f05f6a2d53d5 --- /dev/null +++ b/Source/External/ExCSS/Model/Values/GenericFunction.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using System.Text; +using ExCSS.Model; + +// ReSharper disable once CheckNamespace +namespace ExCSS +{ + public class GenericFunction : Term + { + public string Name { get; set; } + public TermList Arguments { get; set; } + + public GenericFunction(string name, List arguments) + { + this.Name = name; + + var list = new TermList(); + for (int n = 0; n < arguments.Count; n++) + { + list.AddTerm(arguments[n]); + if (n == arguments.Count - 1) + break; + list.AddSeparator(GrammarSegment.Comma); + } + this.Arguments = list; + } + + public override string ToString() + { + return Name + "(" + Arguments + ")"; + } + } +} \ No newline at end of file diff --git a/Source/External/ExCSS/Model/Values/HtmlColor.cs b/Source/External/ExCSS/Model/Values/HtmlColor.cs new file mode 100644 index 0000000000000000000000000000000000000000..32d50df1e7426bde0e1bb5d93ce3d7298e8d3049 --- /dev/null +++ b/Source/External/ExCSS/Model/Values/HtmlColor.cs @@ -0,0 +1,252 @@ +using System; +using System.Runtime.InteropServices; +using ExCSS.Model; +using ExCSS.Model.Extensions; + +// ReSharper disable once CheckNamespace +namespace ExCSS +{ + public class HtmlColor : Term, IEquatable + { + public byte A; + public byte R; + public byte G; + public byte B; + + public HtmlColor(byte r, byte g, byte b) + { + A = 255; + R = r; + B = b; + G = g; + } + + public HtmlColor(byte a, byte r, byte g, byte b) + { + A = a; + R = r; + B = b; + G = g; + } + + public HtmlColor(Double a, byte r, byte g, byte b) + { + A = (byte)Math.Max(Math.Min(Math.Ceiling(255 * a), 255), 0); + R = r; + B = b; + G = g; + } + + public static HtmlColor FromRgba(byte r, byte g, byte b, Single a) + { + return new HtmlColor(a, r, g, b); + } + + public static HtmlColor FromRgba(byte r, byte g, byte b, Double a) + { + return new HtmlColor(a, r, g, b); + } + + public static HtmlColor FromRgb(byte r, byte g, byte b) + { + return new HtmlColor(r, g, b); + } + + public static HtmlColor FromHsl(Single h, Single s, Single l) + { + const Single third = 1f / 3f; + + var m2 = l <= 0.5f ? (l * (s + 1f)) : (l + s - l * s); + var m1 = 2f * l - m2; + var r = (Byte)Math.Round(255 * HueToRgb(m1, m2, h + third)); + var g = (Byte)Math.Round(255 * HueToRgb(m1, m2, h)); + var b = (Byte)Math.Round(255 * HueToRgb(m1, m2, h - third)); + return new HtmlColor(r, g, b); + } + + public static HtmlColor FromHex(string color) + { + if (color.Length == 3) + { + var r = color[0].FromHex(); + r += r * 16; + + var g = color[1].FromHex(); + g += g * 16; + + var b = color[2].FromHex(); + b += b * 16; + + return new HtmlColor((byte)r, (byte)g, (byte)b); + } + + if (color.Length == 6) + { + var r = 16 * color[0].FromHex(); + var g = 16 * color[2].FromHex(); + var b = 16 * color[4].FromHex(); + + r += color[1].FromHex(); + g += color[3].FromHex(); + b += color[5].FromHex(); + + return new HtmlColor((byte)r, (byte)g, (byte)b); + } + + throw new ArgumentException("Invalid color code length: " + color, "color"); + } + + public static bool TryFromHex(string color, out HtmlColor htmlColor) + { + htmlColor = new HtmlColor(255, 0, 0, 0); + + if (color.Length == 3) + { + if (!color[0].IsHex() || !color[1].IsHex() || !color[2].IsHex()) + { + return false; + } + + var r = color[0].FromHex(); + r += r * 16; + + var g = color[1].FromHex(); + g += g * 16; + + var b = color[2].FromHex(); + b += b * 16; + + htmlColor.R = (byte)r; + htmlColor.G = (byte)g; + htmlColor.B = (byte)b; + + return true; + } + + if (color.Length == 6) + { + if (!color[0].IsHex() || !color[1].IsHex() || !color[2].IsHex() || + !color[3].IsHex() || !color[4].IsHex() || !color[5].IsHex()) + { + return false; + } + + var r = 16 * color[0].FromHex(); + var g = 16 * color[2].FromHex(); + var b = 16 * color[4].FromHex(); + + r += color[1].FromHex(); + g += color[3].FromHex(); + b += color[5].FromHex(); + + htmlColor.R = (byte)r; + htmlColor.G = (byte)g; + htmlColor.B = (byte)b; + + return true; + } + + return false; + } + + public double Alpha + { + get { return A / 255.0; } + } + + public static bool operator ==(HtmlColor a, HtmlColor b) + { + return a.GetHashCode() == b.GetHashCode(); + } + + public static bool operator !=(HtmlColor a, HtmlColor b) + { + return a.GetHashCode() != b.GetHashCode(); + } + + public override bool Equals(Object obj) + { + if (obj is HtmlColor) + { + return Equals((HtmlColor)obj); + } + + return false; + } + + public override int GetHashCode() + { + return unchecked(A + (R << 8) + (G << 16) + (B << 24)); + } + + public override string ToString() + { + return ToString(false); + } + + public string ToString(bool friendlyFormat, int indentation = 0) + { + return ToCss().Indent(friendlyFormat, indentation); + } + + public string ToString(bool forceLong, bool friendlyFormat, int indentation = 0) + { + return ToCss(forceLong).Indent(friendlyFormat, indentation); + } + + /// + /// Return the shortest form possible + /// + string ToCss(bool forceLong = false) + { + if (A == 255 && !forceLong && ((R >> 4) == (R & 0x0F)) && ((G >> 4) == (G & 0x0F)) && ((B >> 4) == (B & 0x0F))) + return "#" + R.ToHexChar() + G.ToHexChar() + B.ToHexChar(); + + if (A == 255) + { + return "#" + R.ToHex() + G.ToHex() + B.ToHex(); + //return "rgb(" + R + ", " + G + ", " + B + ")"; + } + + return "rgba(" + R + ", " + G + ", " + B + ", " + Alpha.ToString("0.##") + ")"; + } + + public bool Equals(HtmlColor other) + { + HtmlColor o = other as HtmlColor; + if (o == null) + return false; + return GetHashCode() == other.GetHashCode(); + } + + private static Single HueToRgb(Single m1, Single m2, Single h) + { + const Single sixth = 1f / 6f; + const Single third2 = 2f / 3f; + + if (h < 0f) + { + h += 1f; + } + else if (h > 1f) + { + h -= 1f; + } + + if (h < sixth) + { + return m1 + (m2 - m1) * h * 6f; + } + if (h < 0.5) + { + return m2; + } + if (h < third2) + { + return m1 + (m2 - m1) * (third2 - h) * 6f; + } + + return m1; + } + } +} \ No newline at end of file diff --git a/Source/External/ExCSS/Model/Values/InheritTerm.cs b/Source/External/ExCSS/Model/Values/InheritTerm.cs new file mode 100644 index 0000000000000000000000000000000000000000..c39c02334d47c0c33c35c206256560d413250f99 --- /dev/null +++ b/Source/External/ExCSS/Model/Values/InheritTerm.cs @@ -0,0 +1,17 @@ +using System; + +namespace ExCSS +{ + public class InheritTerm : Term + { + internal InheritTerm() + { + } + + public override string ToString() + { + return "inherit"; + } + } +} + diff --git a/Source/External/ExCSS/Model/Values/PrimitiveTerm.cs b/Source/External/ExCSS/Model/Values/PrimitiveTerm.cs new file mode 100644 index 0000000000000000000000000000000000000000..332e57b8ddc0a2af49aef9d46ad69471c22810d6 --- /dev/null +++ b/Source/External/ExCSS/Model/Values/PrimitiveTerm.cs @@ -0,0 +1,169 @@ +using System; +using System.Globalization; + +// ReSharper disable once CheckNamespace +namespace ExCSS +{ + public class PrimitiveTerm : Term + { + public object Value { get; set; } + public UnitType PrimitiveType { get; set; } + + public PrimitiveTerm(UnitType unitType, string value) + { + PrimitiveType = unitType; + Value = value; + } + + public PrimitiveTerm(UnitType unitType, Single value) + { + PrimitiveType = unitType; + Value = value; + } + + public PrimitiveTerm(string unit, Single value) + { + PrimitiveType = ConvertStringToUnitType(unit);; + Value = value; + } + + public Single? GetFloatValue(UnitType unit) + { + if (!(Value is Single)) + { + return null; + } + + var quantity = (Single)Value; + + switch (unit) + { + case UnitType.Percentage: + quantity = quantity / 100f; + break; + } + + return quantity; + } + + public override string ToString() + { + switch (PrimitiveType) + { + case UnitType.String: + return "'" + Value + "'"; + + case UnitType.Uri: + return "url(" + Value + ")"; + + default: + if (Value is Single) + return ((Single)Value).ToString(CultureInfo.InvariantCulture) + ConvertUnitTypeToString(PrimitiveType); + + return Value.ToString(); + } + } + + internal static UnitType ConvertStringToUnitType(string unit) + { + switch (unit) + { + case "%": + return UnitType.Percentage; + case "em": + return UnitType.Ems; + case "cm": + return UnitType.Centimeter; + case "deg": + return UnitType.Degree; + case "grad": + return UnitType.Grad; + case "rad": + return UnitType.Radian; + case "turn": + return UnitType.Turn; + case "ex": + return UnitType.Exs; + case "hz": + return UnitType.Hertz; + case "in": + return UnitType.Inch; + case "khz": + return UnitType.KiloHertz; + case "mm": + return UnitType.Millimeter; + case "ms": + return UnitType.Millisecond; + case "s": + return UnitType.Second; + case "pc": + return UnitType.Percent; + case "pt": + return UnitType.Point; + case "px": + return UnitType.Pixel; + case "vw": + return UnitType.ViewportWidth; + case "vh": + return UnitType.ViewportHeight; + case "vmin": + return UnitType.ViewportMin; + case "vmax": + return UnitType.ViewportMax; + } + + return UnitType.Unknown; + } + + internal static string ConvertUnitTypeToString(UnitType unit) + { + switch (unit) + { + case UnitType.Percentage: + return "%"; + case UnitType.Ems: + return "em"; + case UnitType.Centimeter: + return "cm"; + case UnitType.Degree: + return "deg"; + case UnitType.Grad: + return "grad"; + case UnitType.Radian: + return "rad"; + case UnitType.Turn: + return "turn"; + case UnitType.Exs: + return "ex"; + case UnitType.Hertz: + return "hz"; + case UnitType.Inch: + return "in"; + case UnitType.KiloHertz: + return "khz"; + case UnitType.Millimeter: + return "mm"; + case UnitType.Millisecond: + return "ms"; + case UnitType.Second: + return "s"; + case UnitType.Percent: + return "pc"; + case UnitType.Point: + return "pt"; + case UnitType.Pixel: + return "px"; + case UnitType.ViewportWidth: + return "vw"; + case UnitType.ViewportHeight: + return "vh"; + case UnitType.ViewportMin: + return "vmin"; + case UnitType.ViewportMax: + return "vmax"; + } + + return string.Empty; + } + } +} diff --git a/Source/External/ExCSS/Model/Values/Property.cs b/Source/External/ExCSS/Model/Values/Property.cs new file mode 100644 index 0000000000000000000000000000000000000000..ebc7a0893ef25cfb1575696e3147c949262b469c --- /dev/null +++ b/Source/External/ExCSS/Model/Values/Property.cs @@ -0,0 +1,47 @@ +using ExCSS.Model.Extensions; + +// ReSharper disable once CheckNamespace +namespace ExCSS +{ + public class Property + { + private Term _term; + private bool _important; + + public Property(string name) + { + Name = name; + } + + public string Name { get; private set; } + + public Term Term + { + get { return _term; } + set { _term = value; } + } + + public bool Important + { + get { return _important; } + set { _important = value; } + } + + public override string ToString() + { + return ToString(false); + } + + public string ToString(bool friendlyFormat, int indentation = 0) + { + var value = Name + ":" + _term; + + if (_important) + { + value += " !important"; + } + + return value.Indent(friendlyFormat, indentation); + } + } +} diff --git a/Source/External/ExCSS/Model/Values/Term.cs b/Source/External/ExCSS/Model/Values/Term.cs new file mode 100644 index 0000000000000000000000000000000000000000..25f695e48592bd199059746200c62f83db2fa339 --- /dev/null +++ b/Source/External/ExCSS/Model/Values/Term.cs @@ -0,0 +1,9 @@ + +// ReSharper disable once CheckNamespace +namespace ExCSS +{ + public abstract class Term + { + public static readonly InheritTerm Inherit = new InheritTerm(); + } +} diff --git a/Source/External/ExCSS/Model/Values/TermList.cs b/Source/External/ExCSS/Model/Values/TermList.cs new file mode 100644 index 0000000000000000000000000000000000000000..51bb3c2fa9c0eab9fc566720fa5c218e6ee5e0ca --- /dev/null +++ b/Source/External/ExCSS/Model/Values/TermList.cs @@ -0,0 +1,123 @@ +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Text; + +// ReSharper disable once CheckNamespace +namespace ExCSS +{ + public class TermList : Term + { + private readonly List _separator = new List(); + private readonly List _items = new List(); + private const GrammarSegment DefaultSeparator = GrammarSegment.Comma; + + public TermList() + { + } + + public TermList(params Term[] terms) + { + for(var i = 0; i < terms.Length; ++i) + { + AddTerm(terms[i]); + if(i != terms.Length-1) + { + AddSeparator(DefaultSeparator); + } + } + } + + public void AddTerm(Term term) + { + if (_items.Count != _separator.Count) + { + throw new NotSupportedException("Must call AddTerm AddSeparator in that order"); + } + + _items.Add(term); + } + + public void AddSeparator(TermSeparator termSeparator) + { + switch(termSeparator) + { + case(TermSeparator.Comma): + { + AddSeparator(GrammarSegment.Comma); + break; + } + case(TermSeparator.Space): + { + AddSeparator(GrammarSegment.Whitespace); + break; + } + } + } + + internal void AddSeparator(GrammarSegment termSepertor) + { + if (_items.Count != _separator.Count + 1) + { + throw new NotSupportedException("Must call AddTerm AddSeparator in that order"); + } + + _separator.Add(termSepertor); + } + + public int Length + { + get { return _items.Count; } + } + + [IndexerName("ListItems")] + public Term this [int index] + { + //return index >= 0 && index < _items.Count ? _items[index] : null; + get { return _items[index]; } + } + + public Term Item(int index) + { + return this[index]; + } + + public override string ToString() + { + var builder = new StringBuilder(); + + for (var i = 0; i < _items.Count; i++) + { + builder.Append(_items[i]); + + if (i == _separator.Count) + break; + + switch (_separator[i]) + { + case GrammarSegment.Whitespace: + builder.Append(" "); + break; + + case GrammarSegment.Comma: + builder.Append(","); + break; + + default: + throw new NotImplementedException(); + } + } + + return builder.ToString(); + } + + /// + /// exposed enumeration for the adding of separators into term lists + /// + public enum TermSeparator + { + Comma, + Space + } + } +} diff --git a/Source/External/ExCSS/Parser.Blocks.cs b/Source/External/ExCSS/Parser.Blocks.cs new file mode 100644 index 0000000000000000000000000000000000000000..9406aecec20db4adbdbf0f2a3edc3ef59e206044 --- /dev/null +++ b/Source/External/ExCSS/Parser.Blocks.cs @@ -0,0 +1,853 @@ +using System; +using System.Text; +using System.Collections.Generic; +using ExCSS.Model; +using ExCSS.Model.TextBlocks; + +namespace ExCSS +{ + public partial class Parser + { + private bool ParseTokenBlock(Block token) + { + switch (_parsingContext) + { + case ParsingContext.DataBlock: + return ParseSymbol(token); + + case ParsingContext.InSelector: + return ParseSelector(token); + + case ParsingContext.InDeclaration: + return ParseDeclaration(token); + + case ParsingContext.AfterProperty: + return ParsePostProperty(token); + + case ParsingContext.BeforeValue: + return ParseValue(token); + + case ParsingContext.InValuePool: + return ParseValuePool(token); + + case ParsingContext.InValueList: + return ParseValueList(token); + + case ParsingContext.InSingleValue: + return ParseSingleValue(token); + + case ParsingContext.ValueImportant: + return ParseImportant(token); + + case ParsingContext.AfterValue: + return ParsePostValue(token); + + case ParsingContext.InMediaList: + return ParseMediaList(token); + + case ParsingContext.InMediaValue: + return ParseMediaValue(token); + + case ParsingContext.BeforeImport: + return ParseImport(token); + + case ParsingContext.AfterInstruction: + return ParsePostInstruction(token); + + case ParsingContext.BeforeCharset: + return ParseCharacterSet(token); + + case ParsingContext.BeforeNamespacePrefix: + return ParseLeadingPrefix(token); + + case ParsingContext.AfterNamespacePrefix: + return ParseNamespace(token); + + case ParsingContext.InCondition: + return ParseCondition(token); + + case ParsingContext.InUnknown: + return ParseUnknown(token); + + case ParsingContext.InKeyframeText: + return ParseKeyframeText(token); + + case ParsingContext.BeforePageSelector: + return ParsePageSelector(token); + + case ParsingContext.BeforeDocumentFunction: + return ParsePreDocumentFunction(token); + + case ParsingContext.InDocumentFunction: + return ParseDocumentFunction(token); + + case ParsingContext.AfterDocumentFunction: + return ParsePostDocumentFunction(token); + + case ParsingContext.BetweenDocumentFunctions: + return ParseDocumentFunctions(token); + + case ParsingContext.BeforeKeyframesName: + return ParseKeyframesName(token); + + case ParsingContext.BeforeKeyframesData: + return ParsePreKeyframesData(token); + + case ParsingContext.KeyframesData: + return ParseKeyframesData(token); + + case ParsingContext.BeforeFontFace: + return ParseFontface(token); + + case ParsingContext.InHexValue: + return ParseHexValue(token); + + case ParsingContext.InFunction: + + return ParseValueFunction(token); + default: + return false; + } + } + + private bool ParseSymbol(Block token) + { + if (token.GrammarSegment == GrammarSegment.AtRule) + { + switch (((SymbolBlock)token).Value) + { + case RuleTypes.Media: + { + AddRuleSet(new MediaRule()); + SetParsingContext(ParsingContext.InMediaList); + break; + } + case RuleTypes.Page: + { + AddRuleSet(new PageRule()); + //SetParsingContext(ParsingContext.InSelector); + SetParsingContext(ParsingContext.BeforePageSelector); + break; + } + case RuleTypes.Import: + { + AddRuleSet(new ImportRule()); + SetParsingContext(ParsingContext.BeforeImport); + break; + } + case RuleTypes.FontFace: + { + AddRuleSet(new FontFaceRule()); + //SetParsingContext(ParsingContext.InDeclaration); + SetParsingContext(ParsingContext.BeforeFontFace); + break; + } + case RuleTypes.CharacterSet: + { + AddRuleSet(new CharacterSetRule()); + SetParsingContext(ParsingContext.BeforeCharset); + break; + } + case RuleTypes.Namespace: + { + AddRuleSet(new NamespaceRule()); + SetParsingContext(ParsingContext.BeforeNamespacePrefix); + break; + } + case RuleTypes.Supports: + { + _buffer = new StringBuilder(); + AddRuleSet(new SupportsRule()); + SetParsingContext(ParsingContext.InCondition); + break; + } + case RuleTypes.Keyframes: + { + AddRuleSet(new KeyframesRule()); + SetParsingContext(ParsingContext.BeforeKeyframesName); + break; + } + case RuleTypes.Document: + { + AddRuleSet(new DocumentRule()); + SetParsingContext(ParsingContext.BeforeDocumentFunction); + break; + } + default: + { + _buffer = new StringBuilder(); + AddRuleSet(new GenericRule()); + SetParsingContext(ParsingContext.InUnknown); + ParseUnknown(token); + break; + } + } + + return true; + } + + if (token.GrammarSegment == GrammarSegment.CurlyBracketClose) + { + return FinalizeRule(); + } + + AddRuleSet(new StyleRule()); + SetParsingContext(ParsingContext.InSelector); + ParseSelector(token); + return true; + + } + + private bool ParseUnknown(Block token) + { + switch (token.GrammarSegment) + { + case GrammarSegment.Semicolon: + CastRuleSet().SetInstruction(_buffer.ToString()); + SetParsingContext(ParsingContext.DataBlock); + + return FinalizeRule(); + + case GrammarSegment.CurlyBraceOpen: + CastRuleSet().SetCondition(_buffer.ToString()); + SetParsingContext(ParsingContext.DataBlock); + break; + + default: + _buffer.Append(token); + break; + } + + return true; + } + + private bool ParseSelector(Block token) + { + switch (token.GrammarSegment) + { + case GrammarSegment.CurlyBraceOpen: + { + var rule = CurrentRule as ISupportsSelector; + + if (rule != null) + { + rule.Selector = _selectorFactory.GetSelector(); + } + + SetParsingContext(CurrentRule is StyleRule + ? ParsingContext.InDeclaration + : ParsingContext.DataBlock); + } + break; + + case GrammarSegment.CurlyBracketClose: + return false; + + default: + _selectorFactory.Apply(token); + break; + } + + return true; + } + + private bool ParseDeclaration(Block token) + { + if (token.GrammarSegment == GrammarSegment.CurlyBracketClose) + { + FinalizeProperty(); + SetParsingContext(CurrentRule is KeyframeRule ? ParsingContext.KeyframesData : ParsingContext.DataBlock); + return FinalizeRule(); + } + + if (token.GrammarSegment != GrammarSegment.Ident) + { + return false; + } + + AddProperty(new Property(((SymbolBlock)token).Value)); + SetParsingContext(ParsingContext.AfterProperty); + return true; + } + + private bool ParsePostInstruction(Block token) + { + if (token.GrammarSegment != GrammarSegment.Semicolon) + { + return false; + } + + SetParsingContext(ParsingContext.DataBlock); + + return FinalizeRule(); + } + + private bool ParseCondition(Block token) + { + switch (token.GrammarSegment) + { + case GrammarSegment.CurlyBraceOpen: + CastRuleSet().Condition = _buffer.ToString(); + SetParsingContext(ParsingContext.DataBlock); + break; + + default: + _buffer.Append(token); + break; + } + + return true; + } + + private bool ParseLeadingPrefix(Block token) + { + if (token.GrammarSegment == GrammarSegment.Ident) + { + CastRuleSet().Prefix = ((SymbolBlock)token).Value; + SetParsingContext(ParsingContext.AfterNamespacePrefix); + + return true; + } + + if (token.GrammarSegment == GrammarSegment.String || token.GrammarSegment == GrammarSegment.Url) + { + CastRuleSet().Uri = ((StringBlock)token).Value; + return true; + } + + SetParsingContext(ParsingContext.AfterInstruction); + + return ParsePostInstruction(token); + } + + private bool ParsePostProperty(Block token) + { + if (token.GrammarSegment == GrammarSegment.Colon) + { + _isFraction = false; + SetParsingContext(ParsingContext.BeforeValue); + return true; + } + + if (token.GrammarSegment == GrammarSegment.Semicolon || token.GrammarSegment == GrammarSegment.CurlyBracketClose) + { + ParsePostValue(token); + } + + return false; + } + + private bool ParseValue(Block token) + { + switch (token.GrammarSegment) + { + case GrammarSegment.Semicolon: + SetParsingContext(ParsingContext.InDeclaration); + break; + + case GrammarSegment.CurlyBracketClose: + ParseDeclaration(token); + break; + + default: + SetParsingContext(ParsingContext.InSingleValue); + return ParseSingleValue(token); + } + + return false; + } + + private bool ParseSingleValue(Block token) + { + switch (token.GrammarSegment) + { + case GrammarSegment.Dimension: // "3px" + return AddTerm(new PrimitiveTerm(((UnitBlock)token).Unit, ((UnitBlock)token).Value)); + + case GrammarSegment.Hash:// "#ffffff" + return ParseSingleValueHexColor(((SymbolBlock)token).Value); + + case GrammarSegment.Delimiter: // "#" + return ParseValueDelimiter((DelimiterBlock)token); + + case GrammarSegment.Ident: // "auto" + return ParseSingleValueIdent((SymbolBlock)token); + + case GrammarSegment.String:// "'some value'" + return AddTerm(new PrimitiveTerm(UnitType.String, ((StringBlock)token).Value)); + + case GrammarSegment.Url:// "url('http://....')" + return AddTerm(new PrimitiveTerm(UnitType.Uri, ((StringBlock)token).Value)); + + case GrammarSegment.Percentage: // "10%" + return AddTerm(new PrimitiveTerm(UnitType.Percentage, ((UnitBlock)token).Value)); + + case GrammarSegment.Number: // "123" + return AddTerm(new PrimitiveTerm(UnitType.Number, ((NumericBlock)token).Value)); + + case GrammarSegment.Whitespace: // " " + _terms.AddSeparator(GrammarSegment.Whitespace); + SetParsingContext(ParsingContext.InValueList); + return true; + + case GrammarSegment.Function: // rgba(...) + _functionBuffers.Push(new FunctionBuffer(((SymbolBlock)token).Value)); + SetParsingContext(ParsingContext.InFunction); + return true; + + case GrammarSegment.Comma: // "," + _terms.AddSeparator(GrammarSegment.Comma); + SetParsingContext(ParsingContext.InValuePool); + return true; + + case GrammarSegment.Semicolon: // ";" + case GrammarSegment.CurlyBracketClose: // "}" + return ParsePostValue(token); + + default: + return false; + } + } + + private bool ParseValueFunction(Block token) + { + switch (token.GrammarSegment) + { + case GrammarSegment.ParenClose: + SetParsingContext(ParsingContext.InSingleValue); + return AddTerm(_functionBuffers.Pop().Done()); + + case GrammarSegment.Comma: + _functionBuffers.Peek().Include(); + return true; + + default: + return ParseSingleValue(token); + } + } + + private bool ParseValueList(Block token) + { + switch (token.GrammarSegment) + { + case GrammarSegment.CurlyBracketClose: + case GrammarSegment.Semicolon: + ParsePostValue(token); + break; + + case GrammarSegment.Comma: + SetParsingContext(ParsingContext.InValuePool); + break; + + default: + SetParsingContext(ParsingContext.InSingleValue); + return ParseSingleValue(token); + } + + return true; + } + + private bool ParseValuePool(Block token) + { + if (token.GrammarSegment == GrammarSegment.Semicolon || token.GrammarSegment == GrammarSegment.CurlyBracketClose) + { + ParsePostValue(token); + } + else + { + SetParsingContext(ParsingContext.InSingleValue); + return ParseSingleValue(token); + } + + return false; + } + + private bool ParseHexValue(Block token) + { + switch (token.GrammarSegment) + { + case GrammarSegment.Number: + case GrammarSegment.Dimension: + case GrammarSegment.Ident: + var rest = token.ToString(); + + if (_buffer.Length + rest.Length <= 6) + { + _buffer.Append(rest); + return true; + } + + break; + } + + ParseSingleValueHexColor(_buffer.ToString()); + SetParsingContext(ParsingContext.InSingleValue); + return ParseSingleValue(token); + } + + private bool ParsePostValue(Block token) + { + if (token.GrammarSegment == GrammarSegment.Semicolon) + { + FinalizeProperty(); + SetParsingContext(ParsingContext.InDeclaration); + return true; + } + + if (token.GrammarSegment == GrammarSegment.CurlyBracketClose) + { + return ParseDeclaration(token); + } + + return false; + } + + private bool ParseImportant(Block token) + { + if (token.GrammarSegment != GrammarSegment.Ident || ((SymbolBlock)token).Value != "important") + { + return ParsePostValue(token); + } + + SetParsingContext(ParsingContext.AfterValue); + _property.Important = true; + + return true; + } + + private bool ParseValueDelimiter(DelimiterBlock token) + { + switch (token.Value) + { + case Specification.Em: + SetParsingContext(ParsingContext.ValueImportant); + return true; + + case Specification.Hash: + _buffer = new StringBuilder(); + SetParsingContext(ParsingContext.InHexValue); + return true; + + case Specification.Solidus: + _isFraction = true; + return true; + + default: + return false; + } + } + + private bool ParseSingleValueIdent(SymbolBlock token) + { + if (token.Value != "inherit") + { + return AddTerm(new PrimitiveTerm(UnitType.Ident, token.Value)); + } + _terms.AddTerm(Term.Inherit); + SetParsingContext(ParsingContext.AfterValue); + return true; + } + + private bool ParseSingleValueHexColor(string color) + { + HtmlColor htmlColor; + + if(HtmlColor.TryFromHex(color, out htmlColor)) + return AddTerm(htmlColor); + return false; + } + + #region Namespace + private bool ParseNamespace(Block token) + { + SetParsingContext(ParsingContext.AfterInstruction); + + if (token.GrammarSegment != GrammarSegment.String) + { + return ParsePostInstruction(token); + } + + CastRuleSet().Uri = ((StringBlock)token).Value; + + return true; + } + #endregion + + #region Charset + private bool ParseCharacterSet(Block token) + { + SetParsingContext(ParsingContext.AfterInstruction); + + if (token.GrammarSegment != GrammarSegment.String) + { + return ParsePostInstruction(token); + } + + CastRuleSet().Encoding = ((StringBlock)token).Value; + + return true; + } + #endregion + + #region Import + private bool ParseImport(Block token) + { + if (token.GrammarSegment == GrammarSegment.String || token.GrammarSegment == GrammarSegment.Url) + { + CastRuleSet().Href = ((StringBlock)token).Value; + SetParsingContext(ParsingContext.InMediaList); + return true; + } + + SetParsingContext(ParsingContext.AfterInstruction); + + return false; + } + #endregion + + #region Font Face + + private bool ParseFontface(Block token) + { + if (token.GrammarSegment == GrammarSegment.CurlyBraceOpen) + { + SetParsingContext(ParsingContext.InDeclaration); + return true; + } + + return false; + } + #endregion + + #region Keyframes + private bool ParseKeyframesName(Block token) + { + //SetParsingContext(ParsingContext.BeforeKeyframesData); + + if (token.GrammarSegment == GrammarSegment.Ident) + { + CastRuleSet().Identifier = ((SymbolBlock)token).Value; + return true; + } + + if (token.GrammarSegment == GrammarSegment.CurlyBraceOpen) + { + SetParsingContext(ParsingContext.KeyframesData); + return true; + } + + return false; + } + + private bool ParsePreKeyframesData(Block token) + { + if (token.GrammarSegment != GrammarSegment.CurlyBraceOpen) + { + return false; + } + + SetParsingContext(ParsingContext.BeforeKeyframesData); + return true; + } + + private bool ParseKeyframesData(Block token) + { + if (token.GrammarSegment == GrammarSegment.CurlyBracketClose) + { + SetParsingContext(ParsingContext.DataBlock); + return FinalizeRule(); + } + + _buffer = new StringBuilder(); + + return ParseKeyframeText(token); + } + + private bool ParseKeyframeText(Block token) + { + if (token.GrammarSegment == GrammarSegment.CurlyBraceOpen) + { + SetParsingContext(ParsingContext.InDeclaration); + return true; + } + + if (token.GrammarSegment == GrammarSegment.CurlyBracketClose) + { + ParseKeyframesData(token); + + return false; + } + + var frame = new KeyframeRule + { + Value = token.ToString() + }; + + + CastRuleSet().Declarations.Add(frame); + _activeRuleSets.Push(frame); + + return true; + } + #endregion + + #region Page + + private bool ParsePageSelector(Block token) + { + if (token.GrammarSegment == GrammarSegment.Colon || token.GrammarSegment == GrammarSegment.Whitespace) + { + return true; + } + + if (token.GrammarSegment == GrammarSegment.Ident) + { + CastRuleSet().Selector = new SimpleSelector(token.ToString()); + return true; + } + + if (token.GrammarSegment == GrammarSegment.CurlyBraceOpen) + { + SetParsingContext(ParsingContext.InDeclaration); + return true; + } + + return false; + } + + #endregion + + #region Document + private bool ParsePreDocumentFunction(Block token) + { + switch (token.GrammarSegment) + { + case GrammarSegment.Url: + CastRuleSet().Conditions.Add(new KeyValuePair(DocumentFunction.Url, ((StringBlock)token).Value)); + break; + + case GrammarSegment.UrlPrefix: + CastRuleSet().Conditions.Add(new KeyValuePair(DocumentFunction.UrlPrefix, ((StringBlock)token).Value)); + break; + + case GrammarSegment.Domain: + CastRuleSet().Conditions.Add(new KeyValuePair(DocumentFunction.Domain, ((StringBlock)token).Value)); + break; + + case GrammarSegment.Function: + if (string.Compare(((SymbolBlock)token).Value, "regexp", StringComparison.OrdinalIgnoreCase) == 0) + { + SetParsingContext(ParsingContext.InDocumentFunction); + return true; + } + SetParsingContext(ParsingContext.AfterDocumentFunction); + return false; + + default: + SetParsingContext(ParsingContext.DataBlock); + return false; + } + + SetParsingContext(ParsingContext.BetweenDocumentFunctions); + return true; + } + + private bool ParseDocumentFunction(Block token) + { + SetParsingContext(ParsingContext.AfterDocumentFunction); + + if (token.GrammarSegment != GrammarSegment.String) return false; + CastRuleSet().Conditions.Add(new KeyValuePair(DocumentFunction.RegExp, ((StringBlock)token).Value)); + return true; + } + + private bool ParsePostDocumentFunction(Block token) + { + SetParsingContext(ParsingContext.BetweenDocumentFunctions); + return token.GrammarSegment == GrammarSegment.ParenClose; + } + + private bool ParseDocumentFunctions(Block token) + { + if (token.GrammarSegment == GrammarSegment.Comma) + { + SetParsingContext(ParsingContext.BeforeDocumentFunction); + return true; + } + + if (token.GrammarSegment == GrammarSegment.CurlyBraceOpen) + { + SetParsingContext(ParsingContext.DataBlock); + return true; + } + + SetParsingContext(ParsingContext.DataBlock); + return false; + } + #endregion + + #region Media + private bool ParseMediaList(Block token) + { + if (token.GrammarSegment == GrammarSegment.Semicolon) + { + FinalizeRule(); + SetParsingContext(ParsingContext.DataBlock); + return true; + } + + _buffer = new StringBuilder(); + SetParsingContext(ParsingContext.InMediaValue); + return ParseMediaValue(token); + } + + private bool ParseMediaValue(Block token) + { + switch (token.GrammarSegment) + { + case GrammarSegment.CurlyBraceOpen: + case GrammarSegment.Semicolon: + { + var container = CurrentRule as ISupportsMedia; + var medium = _buffer.ToString(); + + if (container != null) + { + container.Media.AppendMedium(medium); + } + + if (CurrentRule is ImportRule) + { + return ParsePostInstruction(token); + } + + SetParsingContext(ParsingContext.DataBlock); + return token.GrammarSegment == GrammarSegment.CurlyBraceOpen; + } + case GrammarSegment.Comma: + { + var container = CurrentRule as ISupportsMedia; + + if (container != null) + { + container.Media.AppendMedium(_buffer.ToString()); + } + + _buffer.Length = 0; + return true; + } + case GrammarSegment.Whitespace: + { + _buffer.Append(' '); + return true; + } + default: + { + _buffer.Append(token); + return true; + } + } + } + #endregion + } +} diff --git a/Source/External/ExCSS/Parser.cs b/Source/External/ExCSS/Parser.cs new file mode 100644 index 0000000000000000000000000000000000000000..b44db37cfb249ff5a992016d8a76d1406b811804 --- /dev/null +++ b/Source/External/ExCSS/Parser.cs @@ -0,0 +1,252 @@ +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ExCSS.Model; +using ExCSS.Model.TextBlocks; + +// ReSharper disable once CheckNamespace +using System; + + +namespace ExCSS +{ + internal delegate void ParseErrorEventHandler(StylesheetParseError e); + + public sealed partial class Parser + { + private SelectorFactory _selectorFactory; + private Stack _functionBuffers; + private Lexer _lexer; + private bool _isFraction; + private Property _property; + private TermList _terms = new TermList(); + private StyleSheet _styleSheet; + private Stack _activeRuleSets; + private StringBuilder _buffer; + private ParsingContext _parsingContext; + + public StyleSheet Parse(string css) + { + _selectorFactory = new SelectorFactory(); + _functionBuffers = new Stack(); + _styleSheet = new StyleSheet(); + _activeRuleSets = new Stack(); + _lexer = new Lexer(new StylesheetReader(css)) { ErrorHandler = HandleLexerError }; + + SetParsingContext(ParsingContext.DataBlock); + + var tokens = _lexer.Tokens; + + foreach (var token in tokens) + { + if (ParseTokenBlock(token)) + { + continue; + } + + HandleLexerError(ParserError.UnexpectedLineBreak, ErrorMessages.Default); + } + + if (_property != null) + { + ParseTokenBlock(SpecialCharacter.Semicolon); + } + + return _styleSheet; + } + + internal static BaseSelector ParseSelector(string selector) + { + var tokenizer = new Lexer(new StylesheetReader(selector)); + var tokens = tokenizer.Tokens; + var selctor = new SelectorFactory(); + + foreach (var token in tokens) + { + selctor.Apply(token); + } + + var result = selctor.GetSelector(); + + return result; + } + + internal static RuleSet ParseRule(string css) + { + var parser = new Parser(); + + + var styleSheet = parser.Parse(css); + + return styleSheet.Rules.Count > 0 + ? styleSheet.Rules[0] + : null; + } + + internal static StyleDeclaration ParseDeclarations(string declarations, bool quirksMode = false) + { + var decl = new StyleDeclaration(); + AppendDeclarations(decl, declarations, quirksMode); + + return decl; + } + + internal static void AppendDeclarations(StyleDeclaration list, string css, bool quirksMode = false) + { + var parser = new Parser();//(new StyleSheet(), new StylesheetReader(declarations)) + + + parser.AddRuleSet(list.ParentRule ?? new StyleRule(list)); + + parser._parsingContext = ParsingContext.InDeclaration; + parser.Parse(css); + } + + internal void HandleLexerError(ParserError error, string message) + { + _styleSheet.Errors.Add(new StylesheetParseError(error, message, _lexer.Stream.Line, _lexer.Stream.Column)); + } + + private bool AddTerm(Term value) + { + if (_isFraction) + { + if (_terms.Length > 0) + { + value = new PrimitiveTerm(UnitType.Unknown, _terms[0] + "/" + value); + _terms = new TermList(); + } + + _isFraction = false; + } + + if (_functionBuffers.Count > 0) + { + _functionBuffers.Peek().TermList.Add(value); + } + else if (_terms.Length == 0) + { + _terms.AddTerm(value); + } + else if (_parsingContext == ParsingContext.InSingleValue) + { + _terms.AddTerm(value); + } + else + { + return false; + } + + return true; + } + + private void FinalizeProperty() + { + if (_property != null) + { + if (_terms.Length > 1) + { + _property.Term = _terms; + } + else + { + _property.Term = _terms[0]; + } + } + + _terms = new TermList(); + _property = null; + } + + private bool FinalizeRule() + { + if (_activeRuleSets.Count <= 0) + { + return false; + } + + _activeRuleSets.Pop(); + return true; + } + + private void AddRuleSet(RuleSet rule) + { + //rule.ParentStyleSheet = _styleSheet; + + if (_activeRuleSets.Count > 0) + { + var container = _activeRuleSets.Peek() as ISupportsRuleSets; + + if (container != null) + { + container.RuleSets.Add(rule); + } + } + else + { + _styleSheet.Rules.Add(rule); + } + + _activeRuleSets.Push(rule); + } + + private void AddProperty(Property property) + { + _property = property; + var rule = CurrentRule as ISupportsDeclarations; + + if (rule != null) + { + rule.Declarations.Add(property); + } + } + + private T CastRuleSet() where T : RuleSet + { + if (_activeRuleSets.Count > 0) + { + return _activeRuleSets.Peek() as T; + } + + return default(T); + } + + private void SetParsingContext(ParsingContext newState) + { + switch (newState) + { + case ParsingContext.InSelector: + _lexer.IgnoreComments = true; + _lexer.IgnoreWhitespace = false; + _selectorFactory.ResetFactory(); + break; + + case ParsingContext.InHexValue: + case ParsingContext.InUnknown: + case ParsingContext.InCondition: + case ParsingContext.InSingleValue: + case ParsingContext.InMediaValue: + _lexer.IgnoreComments = true; + _lexer.IgnoreWhitespace = false; + break; + + default: + _lexer.IgnoreComments = true; + _lexer.IgnoreWhitespace = true; + break; + } + + _parsingContext = newState; + } + + internal RuleSet CurrentRule + { + get + { + return _activeRuleSets.Count > 0 + ? _activeRuleSets.Peek() + : null; + } + } + } +} diff --git a/Source/External/ExCSS/Parser.generated.cs b/Source/External/ExCSS/Parser.generated.cs new file mode 100644 index 0000000000000000000000000000000000000000..df0667b241e458e59eac77c7dfdcd136cd96a7a5 --- /dev/null +++ b/Source/External/ExCSS/Parser.generated.cs @@ -0,0 +1,2791 @@ + +/* #line 1 "Parser.rl" */ +using System; +using ExCSS.Model; + +namespace ExCSS +{ + public class Parser + { + private string _css; + private int _currentPosition; + private int p = 0; + private StylesheetContext _context; + + +/* #line 17 "Parser.rl" */ + + + private string GetCssFragment() { + return _css.Substring(_currentPosition, p - _currentPosition); + } + + private void BeginToken(TokenType tokenType){ + _currentPosition = p; + _context.BeginToken(tokenType); + } + + private void EndToken(TokenType tokenType){ + _context.EndToken(tokenType, GetCssFragment()); + } + + #region Generated Scanner + Parser + public void Parse(string value, StylesheetContext context) + { + _css = value; + _context = context; + + char[] data = value.ToCharArray(); + int cs; + int eof = data.Length; + + int pe = eof; + + +/* #line 2 "../ExCSS/Parser.generated.cs" */ + { + cs = selector_start; + } + +/* #line 45 "Parser.rl" */ + +/* #line 5 "../ExCSS/Parser.generated.cs" */ + { + sbyte _klen; + short _trans; + short _keys; + + if ( p == pe ) + goto _test_eof; + if ( cs == 0 ) + goto _out; +_resume: + _keys = _selector_key_offsets[cs]; + _trans = (short)_selector_index_offsets[cs]; + + _klen = _selector_single_lengths[cs]; + if ( _klen > 0 ) { + short _lower = _keys; + short _mid; + short _upper = (short) (_keys + _klen - 1); + while (true) { + if ( _upper < _lower ) + break; + + _mid = (short) (_lower + ((_upper-_lower) >> 1)); + if ( data[p] < _selector_trans_keys[_mid] ) + _upper = (short) (_mid - 1); + else if ( data[p] > _selector_trans_keys[_mid] ) + _lower = (short) (_mid + 1); + else { + _trans += (short) (_mid - _keys); + goto _match; + } + } + _keys += (short) _klen; + _trans += (short) _klen; + } + + _klen = _selector_range_lengths[cs]; + if ( _klen > 0 ) { + short _lower = _keys; + short _mid; + short _upper = (short) (_keys + (_klen<<1) - 2); + while (true) { + if ( _upper < _lower ) + break; + + _mid = (short) (_lower + (((_upper-_lower) >> 1) & ~1)); + if ( data[p] < _selector_trans_keys[_mid] ) + _upper = (short) (_mid - 2); + else if ( data[p] > _selector_trans_keys[_mid+1] ) + _lower = (short) (_mid + 2); + else { + _trans += (short)((_mid - _keys)>>1); + goto _match; + } + } + _trans += (short) _klen; + } + +_match: + cs = _selector_trans_targs[_trans]; + + if ( cs == 0 ) + goto _out; + if ( ++p != pe ) + goto _resume; + _test_eof: {} + _out: {} + } + +/* #line 46 "Parser.rl" */ + } + + +/* #line 73 "../ExCSS/Parser.generated.cs" */ +static readonly short[] _selector_key_offsets = new short [] { + 0, 0, 12, 16, 27, 31, 49, 50, + 72, 74, 76, 78, 80, 82, 84, 86, + 88, 90, 95, 96, 97, 98, 99, 100, + 101, 103, 127, 135, 156, 160, 180, 195, + 215, 237, 240, 243, 246, 249, 252, 255, + 258, 261, 264, 270, 283, 288, 300, 305, + 323, 325, 347, 350, 353, 356, 359, 362, + 365, 368, 371, 374, 380, 393, 398, 410, + 415, 433, 436, 460, 469, 490, 495, 515, + 529, 549, 571, 575, 579, 583, 587, 591, + 595, 599, 603, 607, 614, 628, 634, 647, + 653, 671, 675, 699, 709, 730, 736, 740, + 763, 776, 797, 820, 841, 862, 882, 894, + 906, 924, 937, 950, 963, 976, 989, 1001, + 1004, 1007, 1010, 1017, 1020, 1023, 1045, 1047, + 1069, 1070, 1073, 1076, 1079, 1082, 1085, 1088, + 1091, 1094, 1097, 1103, 1116, 1121, 1133, 1138, + 1156, 1161, 1164, 1188, 1197, 1218, 1223, 1243, + 1258, 1279, 1302, 1305, 1329, 1338, 1359, 1362, + 1385, 1399, 1421, 1442, 1463, 1483, 1495, 1507, + 1525, 1538, 1551, 1564, 1577, 1590, 1602, 1604, + 1606, 1608, 1614, 1616, 1618, 1620, 1642, 1643, + 1646, 1649, 1652, 1655, 1658, 1661, 1664, 1667, + 1670, 1676, 1689, 1694, 1706, 1711, 1729, 1732, + 1756, 1765, 1786, 1791, 1811, 1826, 1846, 1868, + 1872, 1876, 1880, 1884, 1888, 1892, 1896, 1900, + 1904, 1911, 1925, 1931, 1944, 1950, 1968, 1972, + 1996, 2006, 2027, 2033, 2037, 2060, 2074, 2095, + 2118, 2139, 2160, 2180, 2192, 2204, 2222, 2235, + 2248, 2261, 2274, 2287, 2299, 2302, 2305, 2308, + 2315, 2318, 2321, 2343, 2345, 2349, 2353, 2357, + 2361, 2365, 2369, 2373, 2377, 2381, 2388, 2402, + 2408, 2421, 2427, 2445, 2451, 2455, 2479, 2489, + 2510, 2516, 2536, 2551, 2572, 2595, 2599, 2603, + 2607, 2611, 2615, 2619, 2623, 2627, 2631, 2638, + 2652, 2658, 2671, 2677, 2695, 2699, 2723, 2733, + 2754, 2774, 2788, 2810, 2814, 2837, 2858, 2879, + 2899, 2911, 2923, 2941, 2954, 2967, 2980, 2993, + 3006, 3018, 3021, 3024, 3027, 3034, 3037, 3040, + 3051, 3054, 3057, 3060, 3063, 3066, 3086, 3091, + 3111, 3132, 3153, 3174, 3193, 3214, 3221, 3228, + 3235, 3242, 3245, 3248, 3269, 3287, 3303, 3327, + 3340, 3353, 3359, 3377, 3392, 3416, 3419, 3442, + 3463, 3484, 3504, 3516, 3528, 3546, 3559, 3572, + 3585, 3598, 3611, 3623, 3625, 3627, 3629, 3635, + 3637, 3639, 3649, 3651, 3653, 3655, 3657, 3659, + 3679, 3683, 3703, 3724, 3736, 3758, 3772, 3796, + 3798, 3821, 3842, 3863, 3883, 3895, 3907, 3925, + 3938, 3951, 3964, 3977, 3990, 4002, 4003, 4004, + 4005, 4010, 4011, 4012, 4021, 4041, 4044, 4064, + 4085, 4098, 4111, 4124, 4126, 4128, 4130, 4132, + 4134, 4136, 4142, 4144, 4146, 4168, 4183, 4207, + 4210, 4233, 4254, 4275, 4295, 4307, 4319, 4337, + 4350, 4363, 4376, 4389, 4402, 4414, 4416, 4418, + 4420, 4426, 4428, 4430, 4440, 4442, 4444, 4446, + 4448, 4450, 4470, 4474, 4494, 4515, 4529, 4543, + 4557, 4560, 4563, 4566, 4569, 4572, 4575, 4582, + 4585, 4588, 4603, 4618, 4630, 4644, 4658, 4679, + 4702, 4723, 4744, 4764, 4776, 4788, 4806, 4819, + 4832, 4845, 4858, 4871, 4883, 4886, 4889, 4892, + 4899, 4902, 4905, 4916, 4919, 4922, 4925, 4928, + 4931, 4951, 4956, 4976, 4997, 5019, 5023, 5046, + 5067, 5088, 5107, 5128, 5135, 5142, 5149, 5156, + 5159, 5162, 5183, 5201, 5217, 5241, 5254, 5267, + 5273, 5291, 5306, 5330, 5333, 5356, 5377, 5398, + 5418, 5430, 5442, 5460, 5473, 5486, 5499, 5512, + 5525, 5537, 5539, 5541, 5543, 5549, 5551, 5553, + 5563, 5565, 5567, 5569, 5571, 5573, 5593, 5597, + 5617, 5638, 5650, 5662, 5667, 5685, 5696, 5708, + 5720, 5732, 5733, 5734, 5735, 5736, 5737, 5738, + 5743, 5744, 5745, 5758, 5771, 5784, 5786, 5788, + 5790, 5792, 5794, 5796, 5802, 5804, 5806, 5819, + 5825, 5843, 5855, 5868, 5881, 5894, 5896, 5898, + 5900, 5902, 5904, 5906, 5912, 5914, 5916, 5930, + 5944, 5958, 5961, 5964, 5967, 5970, 5973, 5976, + 5983, 5986, 5989, 6004, 6019, 6031, 6045, 6059, + 6070, 6073, 6076, 6079, 6082, 6085, 6105, 6110, + 6130, 6151, 6173, 6194, 6215, 6234, 6255, 6262, + 6269, 6276, 6283, 6286, 6289, 6310, 6328, 6344, + 6368, 6381, 6403, 6416, 6422, 6440, 6455, 6479, + 6489, 6491, 6493, 6495, 6497, 6499, 6519, 6523, + 6543, 6564, 6576, 6589, 6602, 6615, 6617, 6619, + 6621, 6623, 6625, 6627, 6633, 6635, 6637, 6651, + 6665, 6679, 6682, 6685, 6688, 6691, 6694, 6697, + 6704, 6707, 6710, 6725, 6740, 6752, 6766, 6780, + 6801, 6824, 6845, 6868, 6890, 6911, 6932, 6951, + 6972, 6978, 6984, 6990, 6996, 6998, 7000, 7021, + 7035, 7049, 7060, 7073, 7086, 7107, 7128, 7147, + 7168, 7174, 7180, 7186, 7192, 7194, 7196, 7217, + 7238, 7261, 7283, 7304, 7325, 7344, 7365, 7371, + 7377, 7383, 7389, 7391, 7393, 7414, 7428, 7442, + 7453, 7466, 7479, 7490, 7493, 7496, 7499, 7502, + 7505, 7525, 7530, 7550, 7571, 7593, 7614, 7635, + 7654, 7675, 7682, 7689, 7696, 7703, 7706, 7709, + 7730, 7748, 7764, 7788, 7801, 7823, 7845, 7859, + 7873, 7887, 7890, 7893, 7896, 7899, 7902, 7905, + 7912, 7915, 7918, 7933, 7948, 7960, 7974, 7988, + 8010, 8031, 8052, 8071, 8092, 8098, 8104, 8110, + 8116, 8118, 8120, 8141, 8155, 8169, 8180, 8193, + 8206, 8220, 8234, 8245, 8258, 8271, 8292, 8315, + 8337, 8358, 8379, 8398, 8419, 8424, 8429, 8434, + 8439, 8440, 8441, 8462, 8475, 8488, 8498, 8510, + 8522, 8523, 8529, 8550, 8573, 8581, 8602, 8623, + 8646, 8653, 8674, 8697, 8718, 8741, 8748, 8762, + 8771, 8792, 8815, 8823, 8844, 8865, 8888, 8895, + 8909, 8918, 8939, 8962, 8970, 8991, 9012, 9035, + 9042, 9056, 9065, 9086, 9099, 9107, 9128, 9149, + 9162, 9170, 9191, 9214, 9222, 9243, 9257, 9266, + 9287, 9300, 9308, 9321, 9329, 9350, 9362 +}; + +static readonly char[] _selector_trans_keys = new char [] { + '\u0020', '\u002d', '\u0037', '\u003b', '\u005c', '\u007d', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u0031', '\u0037', '\u005c', '\u0000', '\u0031', + '\u0020', '\u003a', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002c', '\u002e', '\u002f', '\u0020', '\u003a', '\u0009', '\u000d', '\u0020', + '\u0022', '\u0027', '\u002b', '\u002d', '\u0037', '\u005c', '\u0075', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002f', '\u0030', '\u0031', '\u0032', + '\u0039', '\u0022', '\u0020', '\u0021', '\u0022', '\u0027', '\u002b', '\u002c', + '\u002d', '\u002f', '\u0037', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002e', '\u0030', '\u0031', '\u0032', '\u0039', + '\u0049', '\u0069', '\u004d', '\u006d', '\u0050', '\u0070', '\u004f', '\u006f', + '\u0052', '\u0072', '\u0054', '\u0074', '\u0041', '\u0061', '\u004e', '\u006e', + '\u0054', '\u0074', '\u0020', '\u003b', '\u007d', '\u0009', '\u000d', '\u002d', + '\u003e', '\u0021', '\u002d', '\u002d', '\u0027', '\u0030', '\u0039', '\u0020', + '\u0021', '\u0022', '\u0025', '\u0027', '\u002b', '\u002d', '\u002e', '\u0037', + '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002a', '\u002c', '\u002f', '\u0030', '\u0031', '\u0032', '\u0039', '\u0037', + '\u005c', '\u0000', '\u002f', '\u0030', '\u0031', '\u0032', '\u0039', '\u0020', + '\u0021', '\u0022', '\u0025', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', + '\u002f', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', '\u0029', '\u0009', '\u000d', + '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', + '\u002f', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u002a', '\u0030', '\u0039', '\u000a', '\u0022', '\u0027', '\u0028', + '\u005c', '\u0075', '\u007d', '\u000c', '\u000d', '\u0030', '\u0039', '\u0041', + '\u0046', '\u0061', '\u0066', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', + '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', '\u0075', '\u007d', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', + '\u0021', '\u0022', '\u0027', '\u002b', '\u002c', '\u002d', '\u002f', '\u0037', + '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002e', '\u0030', '\u0031', '\u0032', '\u0039', '\u0022', '\u0049', '\u0069', + '\u0022', '\u004d', '\u006d', '\u0022', '\u0050', '\u0070', '\u0022', '\u004f', + '\u006f', '\u0022', '\u0052', '\u0072', '\u0022', '\u0054', '\u0074', '\u0022', + '\u0041', '\u0061', '\u0022', '\u004e', '\u006e', '\u0022', '\u0054', '\u0074', + '\u0020', '\u0022', '\u003b', '\u007d', '\u0009', '\u000d', '\u0020', '\u0022', + '\u002d', '\u0037', '\u003b', '\u005c', '\u007d', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u0031', '\u0022', '\u0037', '\u005c', '\u0000', '\u0031', + '\u0020', '\u0022', '\u003a', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u002c', '\u002e', '\u002f', '\u0020', '\u0022', '\u003a', '\u0009', + '\u000d', '\u0020', '\u0022', '\u0027', '\u002b', '\u002d', '\u0037', '\u005c', + '\u0075', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002f', '\u0030', + '\u0031', '\u0032', '\u0039', '\u0022', '\u0027', '\u0020', '\u0021', '\u0022', + '\u0027', '\u002b', '\u002c', '\u002d', '\u002f', '\u0037', '\u005c', '\u0075', + '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002e', '\u0030', + '\u0031', '\u0032', '\u0039', '\u0027', '\u0049', '\u0069', '\u0027', '\u004d', + '\u006d', '\u0027', '\u0050', '\u0070', '\u0027', '\u004f', '\u006f', '\u0027', + '\u0052', '\u0072', '\u0027', '\u0054', '\u0074', '\u0027', '\u0041', '\u0061', + '\u0027', '\u004e', '\u006e', '\u0027', '\u0054', '\u0074', '\u0020', '\u0027', + '\u003b', '\u007d', '\u0009', '\u000d', '\u0020', '\u0027', '\u002d', '\u0037', + '\u003b', '\u005c', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u0031', '\u0027', '\u0037', '\u005c', '\u0000', '\u0031', '\u0020', '\u0027', + '\u003a', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002c', + '\u002e', '\u002f', '\u0020', '\u0027', '\u003a', '\u0009', '\u000d', '\u0020', + '\u0022', '\u0027', '\u002b', '\u002d', '\u0037', '\u005c', '\u0075', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002f', '\u0030', '\u0031', '\u0032', + '\u0039', '\u0027', '\u0030', '\u0039', '\u0020', '\u0021', '\u0022', '\u0025', + '\u0027', '\u002b', '\u002d', '\u002e', '\u0037', '\u005c', '\u0075', '\u007d', + '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u002c', '\u002f', + '\u0030', '\u0031', '\u0032', '\u0039', '\u0027', '\u0037', '\u005c', '\u0000', + '\u002f', '\u0030', '\u0031', '\u0032', '\u0039', '\u0020', '\u0021', '\u0022', + '\u0025', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', + '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', + '\u0030', '\u0039', '\u0020', '\u0027', '\u0029', '\u0009', '\u000d', '\u0020', + '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', + '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002a', '\u0030', '\u0039', '\u000a', '\u0022', '\u0028', '\u005c', '\u0075', + '\u007d', '\u000c', '\u000d', '\u0030', '\u0039', '\u0041', '\u0046', '\u0061', + '\u0066', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', + '\u002e', '\u002f', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', '\u0021', '\u0022', + '\u0027', '\u002b', '\u002c', '\u002d', '\u002f', '\u0037', '\u005c', '\u0075', + '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002e', '\u0030', + '\u0031', '\u0032', '\u0039', '\u0022', '\u0027', '\u0049', '\u0069', '\u0022', + '\u0027', '\u004d', '\u006d', '\u0022', '\u0027', '\u0050', '\u0070', '\u0022', + '\u0027', '\u004f', '\u006f', '\u0022', '\u0027', '\u0052', '\u0072', '\u0022', + '\u0027', '\u0054', '\u0074', '\u0022', '\u0027', '\u0041', '\u0061', '\u0022', + '\u0027', '\u004e', '\u006e', '\u0022', '\u0027', '\u0054', '\u0074', '\u0020', + '\u0022', '\u0027', '\u003b', '\u007d', '\u0009', '\u000d', '\u0020', '\u0022', + '\u0027', '\u002d', '\u0037', '\u003b', '\u005c', '\u007d', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u0031', '\u0022', '\u0027', '\u0037', '\u005c', + '\u0000', '\u0031', '\u0020', '\u0022', '\u0027', '\u003a', '\u005c', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002c', '\u002e', '\u002f', '\u0020', + '\u0022', '\u0027', '\u003a', '\u0009', '\u000d', '\u0020', '\u0022', '\u0027', + '\u002b', '\u002d', '\u0037', '\u005c', '\u0075', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u002f', '\u0030', '\u0031', '\u0032', '\u0039', '\u0022', + '\u0027', '\u0030', '\u0039', '\u0020', '\u0021', '\u0022', '\u0025', '\u0027', + '\u002b', '\u002d', '\u002e', '\u0037', '\u005c', '\u0075', '\u007d', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u002c', '\u002f', '\u0030', + '\u0031', '\u0032', '\u0039', '\u0022', '\u0027', '\u0037', '\u005c', '\u0000', + '\u002f', '\u0030', '\u0031', '\u0032', '\u0039', '\u0020', '\u0021', '\u0022', + '\u0025', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', + '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', + '\u0030', '\u0039', '\u0020', '\u0022', '\u0027', '\u0029', '\u0009', '\u000d', + '\u0022', '\u0027', '\u0030', '\u0039', '\u0020', '\u0021', '\u0022', '\u0025', + '\u0027', '\u002b', '\u002c', '\u002d', '\u002f', '\u0037', '\u005c', '\u0075', + '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002e', '\u0030', + '\u0031', '\u0032', '\u0039', '\u000a', '\u0028', '\u005c', '\u0075', '\u007d', + '\u000c', '\u000d', '\u0030', '\u0039', '\u0041', '\u0046', '\u0061', '\u0066', + '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u0029', '\u002b', '\u002c', + '\u002e', '\u002f', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', '\u0021', '\u0022', + '\u0027', '\u0029', '\u002b', '\u002c', '\u002d', '\u002f', '\u0037', '\u005c', + '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002e', + '\u0030', '\u0031', '\u0032', '\u0039', '\u0020', '\u0021', '\u0022', '\u0027', + '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', '\u0072', '\u0075', + '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', + '\u0039', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', + '\u002e', '\u002f', '\u005c', '\u006c', '\u0075', '\u007d', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', '\u0021', + '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', + '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', + '\u0030', '\u0039', '\u0020', '\u0022', '\u0027', '\u0028', '\u0029', '\u005c', + '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u001f', '\u0020', '\u0022', + '\u0027', '\u0028', '\u0029', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u001f', '\u0020', '\u0022', '\u0027', '\u0028', '\u0029', '\u005c', + '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u001f', '\u0030', '\u0039', + '\u0041', '\u0046', '\u0061', '\u0066', '\u0020', '\u0022', '\u0027', '\u0028', + '\u0029', '\u005c', '\u007b', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u001f', '\u0020', '\u0022', '\u0027', '\u0028', '\u0029', '\u0031', '\u005c', + '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u001f', '\u0020', '\u0022', + '\u0027', '\u0028', '\u0029', '\u002c', '\u005c', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u001f', '\u0020', '\u0022', '\u0027', '\u0028', '\u0029', + '\u0036', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u001f', + '\u0020', '\u0022', '\u0027', '\u0028', '\u0029', '\u005c', '\u007d', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u001f', '\u0020', '\u0022', '\u0027', + '\u0028', '\u0029', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u001f', '\u000d', '\u0022', '\u0027', '\u000a', '\u0022', '\u0027', '\u0022', + '\u0027', '\u007c', '\u0020', '\u0022', '\u0027', '\u0009', '\u000a', '\u000c', + '\u000d', '\u0022', '\u0027', '\u0029', '\u0022', '\u0027', '\u003f', '\u0020', + '\u0021', '\u0022', '\u0027', '\u002b', '\u002c', '\u002d', '\u002f', '\u0037', + '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002e', '\u0030', '\u0031', '\u0032', '\u0039', '\u0022', '\u0027', '\u0020', + '\u0021', '\u0022', '\u0027', '\u002b', '\u002c', '\u002d', '\u002f', '\u0037', + '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002e', '\u0030', '\u0031', '\u0032', '\u0039', '\u0022', '\u0022', '\u0049', + '\u0069', '\u0022', '\u004d', '\u006d', '\u0022', '\u0050', '\u0070', '\u0022', + '\u004f', '\u006f', '\u0022', '\u0052', '\u0072', '\u0022', '\u0054', '\u0074', + '\u0022', '\u0041', '\u0061', '\u0022', '\u004e', '\u006e', '\u0022', '\u0054', + '\u0074', '\u0020', '\u0022', '\u003b', '\u007d', '\u0009', '\u000d', '\u0020', + '\u0022', '\u002d', '\u0037', '\u003b', '\u005c', '\u007d', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u0031', '\u0022', '\u0037', '\u005c', '\u0000', + '\u0031', '\u0020', '\u0022', '\u003a', '\u005c', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u002c', '\u002e', '\u002f', '\u0020', '\u0022', '\u003a', + '\u0009', '\u000d', '\u0020', '\u0022', '\u0027', '\u002b', '\u002d', '\u0037', + '\u005c', '\u0075', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002f', + '\u0030', '\u0031', '\u0032', '\u0039', '\u0020', '\u0022', '\u0029', '\u0009', + '\u000d', '\u0022', '\u0030', '\u0039', '\u0020', '\u0021', '\u0022', '\u0025', + '\u0027', '\u002b', '\u002d', '\u002e', '\u0037', '\u005c', '\u0075', '\u007d', + '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u002c', '\u002f', + '\u0030', '\u0031', '\u0032', '\u0039', '\u0022', '\u0037', '\u005c', '\u0000', + '\u002f', '\u0030', '\u0031', '\u0032', '\u0039', '\u0020', '\u0021', '\u0022', + '\u0025', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', + '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', + '\u0030', '\u0039', '\u0020', '\u0022', '\u0029', '\u0009', '\u000d', '\u0020', + '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', + '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002a', '\u0030', '\u0039', '\u000a', '\u0022', '\u0027', '\u0028', '\u005c', + '\u0075', '\u007d', '\u000c', '\u000d', '\u0030', '\u0039', '\u0041', '\u0046', + '\u0061', '\u0066', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u0029', + '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', '\u0075', '\u007d', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', + '\u0021', '\u0022', '\u0027', '\u0029', '\u002b', '\u002c', '\u002d', '\u002f', + '\u0037', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u002e', '\u0030', '\u0031', '\u0032', '\u0039', '\u0022', '\u0030', + '\u0039', '\u0020', '\u0021', '\u0022', '\u0025', '\u0027', '\u002b', '\u002d', + '\u002e', '\u0037', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u002a', '\u002c', '\u002f', '\u0030', '\u0031', '\u0032', + '\u0039', '\u0022', '\u0037', '\u005c', '\u0000', '\u002f', '\u0030', '\u0031', + '\u0032', '\u0039', '\u0020', '\u0021', '\u0022', '\u0025', '\u0027', '\u0028', + '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', '\u0075', '\u007d', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0022', + '\u0030', '\u0039', '\u0020', '\u0021', '\u0022', '\u0025', '\u0027', '\u002b', + '\u002c', '\u002d', '\u002f', '\u0037', '\u005c', '\u0075', '\u007d', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002e', '\u0030', '\u0031', '\u0032', + '\u0039', '\u000a', '\u0027', '\u0028', '\u005c', '\u0075', '\u007d', '\u000c', + '\u000d', '\u0030', '\u0039', '\u0041', '\u0046', '\u0061', '\u0066', '\u0020', + '\u0021', '\u0022', '\u0025', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', + '\u002f', '\u005c', '\u0075', '\u007b', '\u007d', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', '\u0021', '\u0022', + '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', '\u0072', + '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', + '\u0030', '\u0039', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', + '\u002c', '\u002e', '\u002f', '\u005c', '\u006c', '\u0075', '\u007d', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', + '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', + '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002a', '\u0030', '\u0039', '\u0020', '\u0022', '\u0027', '\u0028', '\u0029', + '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u001f', '\u0020', + '\u0022', '\u0029', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u001f', '\u0027', '\u0028', '\u0020', '\u0022', '\u0029', '\u005c', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u001f', '\u0027', '\u0028', '\u0030', + '\u0039', '\u0041', '\u0046', '\u0061', '\u0066', '\u0020', '\u0022', '\u0029', + '\u005c', '\u007b', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u001f', + '\u0027', '\u0028', '\u0020', '\u0022', '\u0029', '\u0031', '\u005c', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u001f', '\u0027', '\u0028', '\u0020', + '\u0022', '\u0029', '\u002c', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u001f', '\u0027', '\u0028', '\u0020', '\u0022', '\u0029', '\u0036', + '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u001f', '\u0027', + '\u0028', '\u0020', '\u0022', '\u0029', '\u005c', '\u007d', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u001f', '\u0027', '\u0028', '\u0020', '\u0022', + '\u0027', '\u0028', '\u0029', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u001f', '\u000d', '\u0022', '\u000a', '\u0022', '\u0022', '\u007c', + '\u0020', '\u0022', '\u0009', '\u000a', '\u000c', '\u000d', '\u0022', '\u0029', + '\u0022', '\u003f', '\u0022', '\u0027', '\u0020', '\u0021', '\u0022', '\u0027', + '\u002b', '\u002c', '\u002d', '\u002f', '\u0037', '\u005c', '\u0075', '\u007d', + '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002e', '\u0030', '\u0031', + '\u0032', '\u0039', '\u0027', '\u0027', '\u0049', '\u0069', '\u0027', '\u004d', + '\u006d', '\u0027', '\u0050', '\u0070', '\u0027', '\u004f', '\u006f', '\u0027', + '\u0052', '\u0072', '\u0027', '\u0054', '\u0074', '\u0027', '\u0041', '\u0061', + '\u0027', '\u004e', '\u006e', '\u0027', '\u0054', '\u0074', '\u0020', '\u0027', + '\u003b', '\u007d', '\u0009', '\u000d', '\u0020', '\u0027', '\u002d', '\u0037', + '\u003b', '\u005c', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u0031', '\u0027', '\u0037', '\u005c', '\u0000', '\u0031', '\u0020', '\u0027', + '\u003a', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002c', + '\u002e', '\u002f', '\u0020', '\u0027', '\u003a', '\u0009', '\u000d', '\u0020', + '\u0022', '\u0027', '\u002b', '\u002d', '\u0037', '\u005c', '\u0075', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002f', '\u0030', '\u0031', '\u0032', + '\u0039', '\u0027', '\u0030', '\u0039', '\u0020', '\u0021', '\u0022', '\u0025', + '\u0027', '\u002b', '\u002d', '\u002e', '\u0037', '\u005c', '\u0075', '\u007d', + '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u002c', '\u002f', + '\u0030', '\u0031', '\u0032', '\u0039', '\u0027', '\u0037', '\u005c', '\u0000', + '\u002f', '\u0030', '\u0031', '\u0032', '\u0039', '\u0020', '\u0021', '\u0022', + '\u0025', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', + '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', + '\u0030', '\u0039', '\u0020', '\u0027', '\u0029', '\u0009', '\u000d', '\u0020', + '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', + '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002a', '\u0030', '\u0039', '\u000a', '\u0022', '\u0027', '\u0028', '\u005c', + '\u0075', '\u007d', '\u000c', '\u000d', '\u0030', '\u0039', '\u0041', '\u0046', + '\u0061', '\u0066', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', + '\u002c', '\u002e', '\u002f', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', '\u0021', + '\u0022', '\u0027', '\u002b', '\u002c', '\u002d', '\u002f', '\u0037', '\u005c', + '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002e', + '\u0030', '\u0031', '\u0032', '\u0039', '\u0022', '\u0027', '\u0049', '\u0069', + '\u0022', '\u0027', '\u004d', '\u006d', '\u0022', '\u0027', '\u0050', '\u0070', + '\u0022', '\u0027', '\u004f', '\u006f', '\u0022', '\u0027', '\u0052', '\u0072', + '\u0022', '\u0027', '\u0054', '\u0074', '\u0022', '\u0027', '\u0041', '\u0061', + '\u0022', '\u0027', '\u004e', '\u006e', '\u0022', '\u0027', '\u0054', '\u0074', + '\u0020', '\u0022', '\u0027', '\u003b', '\u007d', '\u0009', '\u000d', '\u0020', + '\u0022', '\u0027', '\u002d', '\u0037', '\u003b', '\u005c', '\u007d', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u0031', '\u0022', '\u0027', '\u0037', + '\u005c', '\u0000', '\u0031', '\u0020', '\u0022', '\u0027', '\u003a', '\u005c', + '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002c', '\u002e', '\u002f', + '\u0020', '\u0022', '\u0027', '\u003a', '\u0009', '\u000d', '\u0020', '\u0022', + '\u0027', '\u002b', '\u002d', '\u0037', '\u005c', '\u0075', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002f', '\u0030', '\u0031', '\u0032', '\u0039', + '\u0022', '\u0027', '\u0030', '\u0039', '\u0020', '\u0021', '\u0022', '\u0025', + '\u0027', '\u002b', '\u002d', '\u002e', '\u0037', '\u005c', '\u0075', '\u007d', + '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u002c', '\u002f', + '\u0030', '\u0031', '\u0032', '\u0039', '\u0022', '\u0027', '\u0037', '\u005c', + '\u0000', '\u002f', '\u0030', '\u0031', '\u0032', '\u0039', '\u0020', '\u0021', + '\u0022', '\u0025', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', + '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002a', '\u0030', '\u0039', '\u0020', '\u0022', '\u0027', '\u0029', '\u0009', + '\u000d', '\u0022', '\u0027', '\u0030', '\u0039', '\u0020', '\u0021', '\u0022', + '\u0025', '\u0027', '\u002b', '\u002c', '\u002d', '\u002f', '\u0037', '\u005c', + '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002e', + '\u0030', '\u0031', '\u0032', '\u0039', '\u000a', '\u0027', '\u0028', '\u005c', + '\u0075', '\u007d', '\u000c', '\u000d', '\u0030', '\u0039', '\u0041', '\u0046', + '\u0061', '\u0066', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u0029', + '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', '\u0075', '\u007d', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', + '\u0021', '\u0022', '\u0027', '\u0029', '\u002b', '\u002c', '\u002d', '\u002f', + '\u0037', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u002e', '\u0030', '\u0031', '\u0032', '\u0039', '\u0020', '\u0021', + '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', + '\u0072', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002a', '\u0030', '\u0039', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', + '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', '\u006c', '\u0075', '\u007d', + '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', + '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', + '\u002f', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', '\u0022', '\u0027', '\u0028', + '\u0029', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u001f', + '\u0020', '\u0022', '\u0027', '\u0028', '\u0029', '\u005c', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u001f', '\u0020', '\u0022', '\u0027', '\u0028', + '\u0029', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u001f', + '\u0030', '\u0039', '\u0041', '\u0046', '\u0061', '\u0066', '\u0020', '\u0022', + '\u0027', '\u0028', '\u0029', '\u005c', '\u007b', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u001f', '\u0020', '\u0022', '\u0027', '\u0028', '\u0029', + '\u0031', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u001f', + '\u0020', '\u0022', '\u0027', '\u0028', '\u0029', '\u002c', '\u005c', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u001f', '\u0020', '\u0022', '\u0027', + '\u0028', '\u0029', '\u0036', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u001f', '\u0020', '\u0022', '\u0027', '\u0028', '\u0029', '\u005c', + '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u001f', '\u0020', + '\u0022', '\u0027', '\u0028', '\u0029', '\u005c', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u001f', '\u000d', '\u0022', '\u0027', '\u000a', '\u0022', + '\u0027', '\u0022', '\u0027', '\u007c', '\u0020', '\u0022', '\u0027', '\u0009', + '\u000a', '\u000c', '\u000d', '\u0022', '\u0027', '\u0029', '\u0022', '\u0027', + '\u003f', '\u0020', '\u0021', '\u0022', '\u0027', '\u002b', '\u002c', '\u002d', + '\u002f', '\u0037', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u002e', '\u0030', '\u0031', '\u0032', '\u0039', '\u0022', + '\u0027', '\u0022', '\u0027', '\u0049', '\u0069', '\u0022', '\u0027', '\u004d', + '\u006d', '\u0022', '\u0027', '\u0050', '\u0070', '\u0022', '\u0027', '\u004f', + '\u006f', '\u0022', '\u0027', '\u0052', '\u0072', '\u0022', '\u0027', '\u0054', + '\u0074', '\u0022', '\u0027', '\u0041', '\u0061', '\u0022', '\u0027', '\u004e', + '\u006e', '\u0022', '\u0027', '\u0054', '\u0074', '\u0020', '\u0022', '\u0027', + '\u003b', '\u007d', '\u0009', '\u000d', '\u0020', '\u0022', '\u0027', '\u002d', + '\u0037', '\u003b', '\u005c', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u0031', '\u0022', '\u0027', '\u0037', '\u005c', '\u0000', '\u0031', + '\u0020', '\u0022', '\u0027', '\u003a', '\u005c', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u002c', '\u002e', '\u002f', '\u0020', '\u0022', '\u0027', + '\u003a', '\u0009', '\u000d', '\u0020', '\u0022', '\u0027', '\u002b', '\u002d', + '\u0037', '\u005c', '\u0075', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002f', '\u0030', '\u0031', '\u0032', '\u0039', '\u0020', '\u0022', '\u0027', + '\u0029', '\u0009', '\u000d', '\u0022', '\u0027', '\u0030', '\u0039', '\u0020', + '\u0021', '\u0022', '\u0025', '\u0027', '\u002b', '\u002d', '\u002e', '\u0037', + '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002a', '\u002c', '\u002f', '\u0030', '\u0031', '\u0032', '\u0039', '\u0022', + '\u0027', '\u0037', '\u005c', '\u0000', '\u002f', '\u0030', '\u0031', '\u0032', + '\u0039', '\u0020', '\u0021', '\u0022', '\u0025', '\u0027', '\u0028', '\u002b', + '\u002c', '\u002e', '\u002f', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', '\u0022', + '\u0027', '\u0029', '\u0009', '\u000d', '\u0020', '\u0021', '\u0022', '\u0027', + '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', '\u0075', '\u007d', + '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', + '\u000a', '\u0022', '\u0027', '\u0028', '\u005c', '\u0075', '\u007d', '\u000c', + '\u000d', '\u0030', '\u0039', '\u0041', '\u0046', '\u0061', '\u0066', '\u0020', + '\u0021', '\u0022', '\u0027', '\u0028', '\u0029', '\u002b', '\u002c', '\u002e', + '\u002f', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', '\u0021', '\u0022', '\u0027', + '\u0029', '\u002b', '\u002c', '\u002d', '\u002f', '\u0037', '\u005c', '\u0075', + '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002e', '\u0030', + '\u0031', '\u0032', '\u0039', '\u0022', '\u0027', '\u0049', '\u0069', '\u0022', + '\u0027', '\u004d', '\u006d', '\u0022', '\u0027', '\u0050', '\u0070', '\u0022', + '\u0027', '\u004f', '\u006f', '\u0022', '\u0027', '\u0052', '\u0072', '\u0022', + '\u0027', '\u0054', '\u0074', '\u0022', '\u0027', '\u0041', '\u0061', '\u0022', + '\u0027', '\u004e', '\u006e', '\u0022', '\u0027', '\u0054', '\u0074', '\u0020', + '\u0022', '\u0027', '\u003b', '\u007d', '\u0009', '\u000d', '\u0020', '\u0022', + '\u0027', '\u002d', '\u0037', '\u003b', '\u005c', '\u007d', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u0031', '\u0022', '\u0027', '\u0037', '\u005c', + '\u0000', '\u0031', '\u0020', '\u0022', '\u0027', '\u003a', '\u005c', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002c', '\u002e', '\u002f', '\u0020', + '\u0022', '\u0027', '\u003a', '\u0009', '\u000d', '\u0020', '\u0022', '\u0027', + '\u002b', '\u002d', '\u0037', '\u005c', '\u0075', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u002f', '\u0030', '\u0031', '\u0032', '\u0039', '\u0022', + '\u0027', '\u0030', '\u0039', '\u0020', '\u0021', '\u0022', '\u0025', '\u0027', + '\u002b', '\u002d', '\u002e', '\u0037', '\u005c', '\u0075', '\u007d', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u002c', '\u002f', '\u0030', + '\u0031', '\u0032', '\u0039', '\u0022', '\u0027', '\u0037', '\u005c', '\u0000', + '\u002f', '\u0030', '\u0031', '\u0032', '\u0039', '\u0020', '\u0021', '\u0022', + '\u0025', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', + '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', + '\u0030', '\u0039', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', + '\u002c', '\u002e', '\u002f', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u000a', '\u0022', + '\u0028', '\u005c', '\u0075', '\u007d', '\u000c', '\u000d', '\u0030', '\u0039', + '\u0041', '\u0046', '\u0061', '\u0066', '\u0020', '\u0021', '\u0022', '\u0025', + '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', '\u0075', + '\u007b', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', + '\u0030', '\u0039', '\u0022', '\u0027', '\u0030', '\u0039', '\u0020', '\u0021', + '\u0022', '\u0025', '\u0027', '\u002b', '\u002c', '\u002d', '\u002f', '\u0037', + '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002e', '\u0030', '\u0031', '\u0032', '\u0039', '\u0020', '\u0021', '\u0022', + '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', '\u0072', + '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', + '\u0030', '\u0039', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', + '\u002c', '\u002e', '\u002f', '\u005c', '\u006c', '\u0075', '\u007d', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', + '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', + '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002a', '\u0030', '\u0039', '\u0020', '\u0022', '\u0027', '\u0028', '\u0029', + '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u001f', '\u0020', + '\u0022', '\u0027', '\u0028', '\u0029', '\u005c', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u001f', '\u0020', '\u0022', '\u0027', '\u0028', '\u0029', + '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u001f', '\u0030', + '\u0039', '\u0041', '\u0046', '\u0061', '\u0066', '\u0020', '\u0022', '\u0027', + '\u0028', '\u0029', '\u005c', '\u007b', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u001f', '\u0020', '\u0022', '\u0027', '\u0028', '\u0029', '\u0031', + '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u001f', '\u0020', + '\u0022', '\u0027', '\u0028', '\u0029', '\u002c', '\u005c', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u001f', '\u0020', '\u0022', '\u0027', '\u0028', + '\u0029', '\u0036', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u001f', '\u0020', '\u0022', '\u0027', '\u0028', '\u0029', '\u005c', '\u007d', + '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u001f', '\u0020', '\u0022', + '\u0027', '\u0028', '\u0029', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u001f', '\u000d', '\u0022', '\u0027', '\u000a', '\u0022', '\u0027', + '\u0022', '\u0027', '\u007c', '\u0020', '\u0022', '\u0027', '\u0009', '\u000a', + '\u000c', '\u000d', '\u0022', '\u0027', '\u0029', '\u0022', '\u0027', '\u003f', + '\u0022', '\u0027', '\u002d', '\u0037', '\u005c', '\u0000', '\u002f', '\u0030', + '\u0031', '\u0032', '\u0039', '\u0022', '\u0027', '\u003e', '\u0022', '\u0027', + '\u002d', '\u0021', '\u0022', '\u0027', '\u0022', '\u0027', '\u002d', '\u0022', + '\u0027', '\u002d', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', + '\u002c', '\u002e', '\u002f', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0022', '\u0027', + '\u002d', '\u0049', '\u0069', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', + '\u002b', '\u002c', '\u002d', '\u002f', '\u005c', '\u0075', '\u007d', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002e', '\u0030', '\u0039', '\u0020', + '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', + '\u003e', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', '\u0021', '\u0022', '\u0027', + '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', '\u0031', '\u005c', '\u0075', + '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', + '\u0039', '\u0020', '\u0021', '\u0022', '\u0025', '\u0027', '\u0028', '\u002b', + '\u002c', '\u002e', '\u002f', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', '\u0022', + '\u0027', '\u002b', '\u002d', '\u0036', '\u0037', '\u005c', '\u0075', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002f', '\u0030', '\u0031', '\u0032', + '\u0039', '\u0020', '\u0021', '\u0022', '\u0025', '\u0027', '\u0028', '\u002b', + '\u002c', '\u002e', '\u002f', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u000d', '\u0020', + '\u0022', '\u0027', '\u0029', '\u0009', '\u000c', '\u000a', '\u0020', '\u0022', + '\u0027', '\u0029', '\u0009', '\u000d', '\u0020', '\u0022', '\u0027', '\u0029', + '\u007c', '\u0009', '\u000d', '\u0020', '\u0022', '\u0027', '\u0009', '\u000a', + '\u000c', '\u000d', '\u0022', '\u0027', '\u0029', '\u0022', '\u0027', '\u003f', + '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', + '\u002f', '\u005c', '\u0075', '\u007b', '\u007d', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', '\u0022', '\u0027', + '\u002b', '\u002d', '\u0037', '\u005c', '\u0075', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u002f', '\u0030', '\u0031', '\u0032', '\u0039', '\u0020', + '\u0022', '\u0027', '\u002d', '\u0037', '\u005c', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u002f', '\u0030', '\u0031', '\u0032', '\u0039', '\u0020', + '\u0021', '\u0022', '\u0025', '\u0027', '\u002b', '\u002d', '\u002e', '\u0037', + '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002a', '\u002c', '\u002f', '\u0030', '\u0031', '\u0032', '\u0039', '\u000a', + '\u0022', '\u0027', '\u003a', '\u005c', '\u000c', '\u000d', '\u0030', '\u0039', + '\u0041', '\u0046', '\u0061', '\u0066', '\u0020', '\u0027', '\u0029', '\u003a', + '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002c', '\u002e', + '\u002f', '\u0020', '\u0027', '\u0029', '\u003a', '\u0009', '\u000d', '\u0020', + '\u0022', '\u0027', '\u002b', '\u002d', '\u0037', '\u005c', '\u0075', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002f', '\u0030', '\u0031', '\u0032', + '\u0039', '\u0020', '\u0027', '\u002d', '\u0037', '\u005c', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002f', '\u0030', '\u0031', '\u0032', '\u0039', + '\u0020', '\u0021', '\u0022', '\u0025', '\u0027', '\u002b', '\u002d', '\u002e', + '\u0037', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u002a', '\u002c', '\u002f', '\u0030', '\u0031', '\u0032', '\u0039', + '\u0027', '\u0030', '\u0039', '\u0020', '\u0021', '\u0022', '\u0025', '\u0027', + '\u002b', '\u002c', '\u002d', '\u002f', '\u0037', '\u005c', '\u0075', '\u007d', + '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002e', '\u0030', '\u0031', + '\u0032', '\u0039', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', + '\u002c', '\u002e', '\u002f', '\u005c', '\u0072', '\u0075', '\u007d', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', + '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', + '\u005c', '\u006c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', '\u0021', '\u0022', '\u0027', + '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', '\u0075', '\u007d', + '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', + '\u0020', '\u0022', '\u0027', '\u0028', '\u0029', '\u005c', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u001f', '\u0020', '\u0022', '\u0027', '\u0028', + '\u0029', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u001f', + '\u0020', '\u0022', '\u0027', '\u0028', '\u0029', '\u005c', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u001f', '\u0030', '\u0039', '\u0041', '\u0046', + '\u0061', '\u0066', '\u0020', '\u0022', '\u0027', '\u0028', '\u0029', '\u005c', + '\u007b', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u001f', '\u0020', + '\u0022', '\u0027', '\u0028', '\u0029', '\u0031', '\u005c', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u001f', '\u0020', '\u0022', '\u0027', '\u0028', + '\u0029', '\u002c', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u001f', '\u0020', '\u0022', '\u0027', '\u0028', '\u0029', '\u0036', '\u005c', + '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u001f', '\u0020', '\u0022', + '\u0027', '\u0028', '\u0029', '\u005c', '\u007d', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u001f', '\u0020', '\u0022', '\u0027', '\u0028', '\u0029', + '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u001f', '\u000d', + '\u0027', '\u000a', '\u0027', '\u0027', '\u007c', '\u0020', '\u0027', '\u0009', + '\u000a', '\u000c', '\u000d', '\u0027', '\u0029', '\u0027', '\u003f', '\u0027', + '\u002d', '\u0037', '\u005c', '\u0000', '\u002f', '\u0030', '\u0031', '\u0032', + '\u0039', '\u0027', '\u003e', '\u0027', '\u002d', '\u0021', '\u0027', '\u0027', + '\u002d', '\u0027', '\u002d', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', + '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', '\u0075', '\u007d', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0027', + '\u002d', '\u0049', '\u0069', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', + '\u002b', '\u002c', '\u002d', '\u002f', '\u005c', '\u0075', '\u007d', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002e', '\u0030', '\u0039', '\u0020', + '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', + '\u003e', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u002a', '\u0030', '\u0039', '\u000a', '\u0027', '\u003a', '\u005c', + '\u000c', '\u000d', '\u0030', '\u0039', '\u0041', '\u0046', '\u0061', '\u0066', + '\u0020', '\u0021', '\u0022', '\u0027', '\u002b', '\u002c', '\u002d', '\u002f', + '\u0037', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u002e', '\u0030', '\u0031', '\u0032', '\u0039', '\u0020', '\u002d', + '\u0037', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002f', + '\u0030', '\u0031', '\u0032', '\u0039', '\u0020', '\u0021', '\u0022', '\u0025', + '\u0027', '\u002b', '\u002d', '\u002e', '\u0037', '\u005c', '\u0075', '\u007d', + '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u002c', '\u002f', + '\u0030', '\u0031', '\u0032', '\u0039', '\u0030', '\u0039', '\u0020', '\u0021', + '\u0022', '\u0025', '\u0027', '\u002b', '\u002c', '\u002d', '\u002f', '\u0037', + '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002e', '\u0030', '\u0031', '\u0032', '\u0039', '\u0020', '\u0021', '\u0022', + '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', '\u0072', + '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', + '\u0030', '\u0039', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', + '\u002c', '\u002e', '\u002f', '\u005c', '\u006c', '\u0075', '\u007d', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', + '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', + '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002a', '\u0030', '\u0039', '\u0020', '\u0022', '\u0027', '\u0028', '\u0029', + '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u001f', '\u0020', + '\u0022', '\u0029', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u001f', '\u0027', '\u0028', '\u0020', '\u0022', '\u0029', '\u005c', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u001f', '\u0027', '\u0028', '\u0030', + '\u0039', '\u0041', '\u0046', '\u0061', '\u0066', '\u0020', '\u0022', '\u0029', + '\u005c', '\u007b', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u001f', + '\u0027', '\u0028', '\u0020', '\u0022', '\u0029', '\u0031', '\u005c', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u001f', '\u0027', '\u0028', '\u0020', + '\u0022', '\u0029', '\u002c', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u001f', '\u0027', '\u0028', '\u0020', '\u0022', '\u0029', '\u0036', + '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u001f', '\u0027', + '\u0028', '\u0020', '\u0022', '\u0029', '\u005c', '\u007d', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u001f', '\u0027', '\u0028', '\u0020', '\u0022', + '\u0027', '\u0028', '\u0029', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u001f', '\u000d', '\u000a', '\u007c', '\u0020', '\u0009', '\u000a', + '\u000c', '\u000d', '\u0029', '\u003f', '\u002d', '\u0037', '\u005c', '\u0000', + '\u002f', '\u0030', '\u0031', '\u0032', '\u0039', '\u0020', '\u0021', '\u0022', + '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', '\u0075', + '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', + '\u0039', '\u002d', '\u0049', '\u0069', '\u0020', '\u0021', '\u0022', '\u0027', + '\u0028', '\u002b', '\u002c', '\u002d', '\u002f', '\u005c', '\u0075', '\u007d', + '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002e', '\u0030', '\u0039', + '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', + '\u002f', '\u003e', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', '\u0027', '\u003a', + '\u005c', '\u007b', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002c', + '\u002e', '\u002f', '\u0020', '\u0027', '\u0031', '\u003a', '\u005c', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002c', '\u002e', '\u002f', '\u0020', + '\u0027', '\u002c', '\u003a', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u002b', '\u002e', '\u002f', '\u0027', '\u0036', '\u0027', '\u007d', + '\u0027', '\u0028', '\u000d', '\u0027', '\u000a', '\u0027', '\u0027', '\u007c', + '\u0020', '\u0027', '\u0009', '\u000a', '\u000c', '\u000d', '\u0027', '\u0029', + '\u0027', '\u003f', '\u0020', '\u0021', '\u0022', '\u0027', '\u002b', '\u002c', + '\u002d', '\u002f', '\u0037', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002e', '\u0030', '\u0031', '\u0032', '\u0039', + '\u0020', '\u0022', '\u002d', '\u0037', '\u005c', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u002f', '\u0030', '\u0031', '\u0032', '\u0039', '\u0020', + '\u0021', '\u0022', '\u0025', '\u0027', '\u002b', '\u002d', '\u002e', '\u0037', + '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002a', '\u002c', '\u002f', '\u0030', '\u0031', '\u0032', '\u0039', '\u0022', + '\u0030', '\u0039', '\u0020', '\u0021', '\u0022', '\u0025', '\u0027', '\u002b', + '\u002c', '\u002d', '\u002f', '\u0037', '\u005c', '\u0075', '\u007d', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002e', '\u0030', '\u0031', '\u0032', + '\u0039', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', + '\u002e', '\u002f', '\u005c', '\u0072', '\u0075', '\u007d', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', '\u0021', + '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', + '\u006c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002a', '\u0030', '\u0039', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', + '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', '\u0075', '\u007d', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', + '\u0022', '\u0027', '\u0028', '\u0029', '\u005c', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u001f', '\u0020', '\u0022', '\u0029', '\u005c', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u001f', '\u0027', '\u0028', '\u0020', + '\u0022', '\u0029', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u001f', '\u0027', '\u0028', '\u0030', '\u0039', '\u0041', '\u0046', '\u0061', + '\u0066', '\u0020', '\u0022', '\u0029', '\u005c', '\u007b', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u001f', '\u0027', '\u0028', '\u0020', '\u0022', + '\u0029', '\u0031', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u001f', '\u0027', '\u0028', '\u0020', '\u0022', '\u0029', '\u002c', '\u005c', + '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u001f', '\u0027', '\u0028', + '\u0020', '\u0022', '\u0029', '\u0036', '\u005c', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u001f', '\u0027', '\u0028', '\u0020', '\u0022', '\u0029', + '\u005c', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u001f', + '\u0027', '\u0028', '\u0020', '\u0022', '\u0027', '\u0028', '\u0029', '\u005c', + '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u001f', '\u000d', '\u0022', + '\u000a', '\u0022', '\u0022', '\u007c', '\u0020', '\u0022', '\u0009', '\u000a', + '\u000c', '\u000d', '\u0022', '\u0029', '\u0022', '\u003f', '\u0022', '\u002d', + '\u0037', '\u005c', '\u0000', '\u002f', '\u0030', '\u0031', '\u0032', '\u0039', + '\u0022', '\u003e', '\u0022', '\u002d', '\u0021', '\u0022', '\u0022', '\u002d', + '\u0022', '\u002d', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', + '\u002c', '\u002e', '\u002f', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0022', '\u002d', + '\u0049', '\u0069', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', + '\u002c', '\u002d', '\u002f', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002e', '\u0030', '\u0039', '\u0020', '\u0021', + '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', '\u003e', + '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002a', '\u0030', '\u0039', '\u0020', '\u0022', '\u0027', '\u003a', '\u005c', + '\u007b', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002c', '\u002e', + '\u002f', '\u0020', '\u0022', '\u0027', '\u0031', '\u003a', '\u005c', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002c', '\u002e', '\u002f', '\u0020', + '\u0022', '\u0027', '\u002c', '\u003a', '\u005c', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u002b', '\u002e', '\u002f', '\u0022', '\u0027', '\u0036', + '\u0022', '\u0027', '\u007d', '\u0022', '\u0027', '\u0028', '\u000d', '\u0022', + '\u0027', '\u000a', '\u0022', '\u0027', '\u0022', '\u0027', '\u007c', '\u0020', + '\u0022', '\u0027', '\u0009', '\u000a', '\u000c', '\u000d', '\u0022', '\u0027', + '\u0029', '\u0022', '\u0027', '\u003f', '\u0020', '\u0022', '\u0027', '\u003a', + '\u003b', '\u005c', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002c', '\u002e', '\u002f', '\u0020', '\u0022', '\u0027', '\u002d', '\u0037', + '\u003a', '\u003b', '\u005c', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u0031', '\u0020', '\u0022', '\u0027', '\u002d', '\u003a', '\u005c', + '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002f', '\u0020', '\u0022', + '\u0027', '\u003a', '\u003e', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u002c', '\u002e', '\u002f', '\u0020', '\u0021', '\u0022', '\u0027', + '\u003a', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002c', + '\u002e', '\u002f', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u0029', + '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', '\u0075', '\u007d', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', + '\u0021', '\u0022', '\u0027', '\u0029', '\u002b', '\u002c', '\u002d', '\u002f', + '\u0037', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u002e', '\u0030', '\u0031', '\u0032', '\u0039', '\u0020', '\u0021', + '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', + '\u0072', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002a', '\u0030', '\u0039', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', + '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', '\u006c', '\u0075', '\u007d', + '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', + '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', + '\u002f', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', '\u0022', '\u0027', '\u0028', + '\u0029', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u001f', + '\u0020', '\u0022', '\u0027', '\u0028', '\u0029', '\u005c', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u001f', '\u0020', '\u0022', '\u0027', '\u0028', + '\u0029', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u001f', + '\u0030', '\u0039', '\u0041', '\u0046', '\u0061', '\u0066', '\u0020', '\u0022', + '\u0027', '\u0028', '\u0029', '\u005c', '\u007b', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u001f', '\u0020', '\u0022', '\u0027', '\u0028', '\u0029', + '\u0031', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u001f', + '\u0020', '\u0022', '\u0027', '\u0028', '\u0029', '\u002c', '\u005c', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u001f', '\u0020', '\u0022', '\u0027', + '\u0028', '\u0029', '\u0036', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u001f', '\u0020', '\u0022', '\u0027', '\u0028', '\u0029', '\u005c', + '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u001f', '\u0020', + '\u0022', '\u0027', '\u0028', '\u0029', '\u005c', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u001f', '\u000d', '\u0022', '\u0027', '\u000a', '\u0022', + '\u0027', '\u0022', '\u0027', '\u007c', '\u0020', '\u0022', '\u0027', '\u0009', + '\u000a', '\u000c', '\u000d', '\u0022', '\u0027', '\u0029', '\u0022', '\u0027', + '\u003f', '\u0022', '\u0027', '\u002d', '\u0037', '\u005c', '\u0000', '\u002f', + '\u0030', '\u0031', '\u0032', '\u0039', '\u0022', '\u0027', '\u003e', '\u0022', + '\u0027', '\u002d', '\u0021', '\u0022', '\u0027', '\u0022', '\u0027', '\u002d', + '\u0022', '\u0027', '\u002d', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', + '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', '\u0075', '\u007d', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0022', + '\u0027', '\u002d', '\u0049', '\u0069', '\u0020', '\u0021', '\u0022', '\u0027', + '\u0028', '\u002b', '\u002c', '\u002d', '\u002f', '\u005c', '\u0075', '\u007d', + '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002e', '\u0030', '\u0039', + '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', + '\u002f', '\u003e', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', '\u0021', '\u0022', + '\u0025', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', + '\u0075', '\u007b', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002a', '\u0030', '\u0039', '\u0022', '\u0027', '\u0030', '\u0039', '\u0020', + '\u0021', '\u0022', '\u0025', '\u0027', '\u002b', '\u002c', '\u002d', '\u002f', + '\u0037', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u002e', '\u0030', '\u0031', '\u0032', '\u0039', '\u0020', '\u0021', + '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', '\u0031', + '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002a', '\u0030', '\u0039', '\u0020', '\u0021', '\u0022', '\u0025', '\u0027', + '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', '\u0075', '\u007d', + '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', + '\u0020', '\u0022', '\u0027', '\u002b', '\u002d', '\u0036', '\u0037', '\u005c', + '\u0075', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002f', '\u0030', + '\u0031', '\u0032', '\u0039', '\u0020', '\u0021', '\u0022', '\u0025', '\u0027', + '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', '\u0075', '\u007d', + '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', + '\u000d', '\u0020', '\u0022', '\u0027', '\u0029', '\u0009', '\u000c', '\u000a', + '\u0020', '\u0022', '\u0027', '\u0029', '\u0009', '\u000d', '\u0020', '\u0022', + '\u0027', '\u0029', '\u007c', '\u0009', '\u000d', '\u0020', '\u0022', '\u0027', + '\u0009', '\u000a', '\u000c', '\u000d', '\u0022', '\u0027', '\u0029', '\u0022', + '\u0027', '\u003f', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', + '\u002c', '\u002e', '\u002f', '\u005c', '\u0075', '\u007b', '\u007d', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', + '\u0022', '\u0027', '\u002b', '\u002d', '\u0037', '\u005c', '\u0075', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002f', '\u0030', '\u0031', '\u0032', + '\u0039', '\u0020', '\u0022', '\u0027', '\u002d', '\u0037', '\u005c', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002f', '\u0030', '\u0031', '\u0032', + '\u0039', '\u0020', '\u0021', '\u0022', '\u0025', '\u0027', '\u002b', '\u002d', + '\u002e', '\u0037', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u002a', '\u002c', '\u002f', '\u0030', '\u0031', '\u0032', + '\u0039', '\u000a', '\u0022', '\u0027', '\u003a', '\u005c', '\u000c', '\u000d', + '\u0030', '\u0039', '\u0041', '\u0046', '\u0061', '\u0066', '\u0020', '\u0027', + '\u0029', '\u003a', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002c', '\u002e', '\u002f', '\u0020', '\u0027', '\u0029', '\u003a', '\u0009', + '\u000d', '\u0020', '\u0022', '\u0027', '\u002b', '\u002d', '\u0037', '\u005c', + '\u0075', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002f', '\u0030', + '\u0031', '\u0032', '\u0039', '\u0020', '\u0027', '\u002d', '\u0037', '\u005c', + '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002f', '\u0030', '\u0031', + '\u0032', '\u0039', '\u0020', '\u0021', '\u0022', '\u0025', '\u0027', '\u002b', + '\u002d', '\u002e', '\u0037', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002a', '\u002c', '\u002f', '\u0030', '\u0031', + '\u0032', '\u0039', '\u0027', '\u0030', '\u0039', '\u0020', '\u0021', '\u0022', + '\u0025', '\u0027', '\u002b', '\u002c', '\u002d', '\u002f', '\u0037', '\u005c', + '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002e', + '\u0030', '\u0031', '\u0032', '\u0039', '\u0020', '\u0021', '\u0022', '\u0027', + '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', '\u0072', '\u0075', + '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', + '\u0039', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', + '\u002e', '\u002f', '\u005c', '\u006c', '\u0075', '\u007d', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', '\u0021', + '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', + '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', + '\u0030', '\u0039', '\u0020', '\u0022', '\u0027', '\u0028', '\u0029', '\u005c', + '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u001f', '\u0020', '\u0022', + '\u0027', '\u0028', '\u0029', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u001f', '\u0020', '\u0022', '\u0027', '\u0028', '\u0029', '\u005c', + '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u001f', '\u0030', '\u0039', + '\u0041', '\u0046', '\u0061', '\u0066', '\u0020', '\u0022', '\u0027', '\u0028', + '\u0029', '\u005c', '\u007b', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u001f', '\u0020', '\u0022', '\u0027', '\u0028', '\u0029', '\u0031', '\u005c', + '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u001f', '\u0020', '\u0022', + '\u0027', '\u0028', '\u0029', '\u002c', '\u005c', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u001f', '\u0020', '\u0022', '\u0027', '\u0028', '\u0029', + '\u0036', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u001f', + '\u0020', '\u0022', '\u0027', '\u0028', '\u0029', '\u005c', '\u007d', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u001f', '\u0020', '\u0022', '\u0027', + '\u0028', '\u0029', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u001f', '\u000d', '\u0027', '\u000a', '\u0027', '\u0027', '\u007c', '\u0020', + '\u0027', '\u0009', '\u000a', '\u000c', '\u000d', '\u0027', '\u0029', '\u0027', + '\u003f', '\u0027', '\u002d', '\u0037', '\u005c', '\u0000', '\u002f', '\u0030', + '\u0031', '\u0032', '\u0039', '\u0027', '\u003e', '\u0027', '\u002d', '\u0021', + '\u0027', '\u0027', '\u002d', '\u0027', '\u002d', '\u0020', '\u0021', '\u0022', + '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', '\u0075', + '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', + '\u0039', '\u0027', '\u002d', '\u0049', '\u0069', '\u0020', '\u0021', '\u0022', + '\u0027', '\u0028', '\u002b', '\u002c', '\u002d', '\u002f', '\u005c', '\u0075', + '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002e', '\u0030', + '\u0039', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', + '\u002e', '\u002f', '\u003e', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u000a', '\u0027', + '\u003a', '\u005c', '\u000c', '\u000d', '\u0030', '\u0039', '\u0041', '\u0046', + '\u0061', '\u0066', '\u0020', '\u0029', '\u003a', '\u005c', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002c', '\u002e', '\u002f', '\u0020', '\u0029', + '\u003a', '\u0009', '\u000d', '\u0020', '\u0022', '\u0027', '\u002b', '\u002d', + '\u0037', '\u005c', '\u0075', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002f', '\u0030', '\u0031', '\u0032', '\u0039', '\u000a', '\u003a', '\u005c', + '\u000c', '\u000d', '\u0030', '\u0039', '\u0041', '\u0046', '\u0061', '\u0066', + '\u0020', '\u003a', '\u005c', '\u007b', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u002c', '\u002e', '\u002f', '\u0020', '\u0031', '\u003a', '\u005c', + '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002c', '\u002e', '\u002f', + '\u0020', '\u002c', '\u003a', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u002b', '\u002e', '\u002f', '\u0036', '\u007d', '\u0028', '\u000d', + '\u000a', '\u007c', '\u0020', '\u0009', '\u000a', '\u000c', '\u000d', '\u0029', + '\u003f', '\u0020', '\u0027', '\u003a', '\u005c', '\u007b', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002c', '\u002e', '\u002f', '\u0020', '\u0027', + '\u0031', '\u003a', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002c', '\u002e', '\u002f', '\u0020', '\u0027', '\u002c', '\u003a', '\u005c', + '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002b', '\u002e', '\u002f', + '\u0027', '\u0036', '\u0027', '\u007d', '\u0027', '\u0028', '\u000d', '\u0027', + '\u000a', '\u0027', '\u0027', '\u007c', '\u0020', '\u0027', '\u0009', '\u000a', + '\u000c', '\u000d', '\u0027', '\u0029', '\u0027', '\u003f', '\u0020', '\u0022', + '\u0029', '\u003a', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002c', '\u002e', '\u002f', '\u0020', '\u0022', '\u0029', '\u003a', '\u0009', + '\u000d', '\u0020', '\u0022', '\u0027', '\u002b', '\u002d', '\u0037', '\u005c', + '\u0075', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002f', '\u0030', + '\u0031', '\u0032', '\u0039', '\u000a', '\u0022', '\u003a', '\u005c', '\u000c', + '\u000d', '\u0030', '\u0039', '\u0041', '\u0046', '\u0061', '\u0066', '\u0020', + '\u0022', '\u003a', '\u005c', '\u007b', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u002c', '\u002e', '\u002f', '\u0020', '\u0022', '\u0031', '\u003a', + '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002c', '\u002e', + '\u002f', '\u0020', '\u0022', '\u002c', '\u003a', '\u005c', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002b', '\u002e', '\u002f', '\u0022', '\u0036', + '\u0022', '\u007d', '\u0022', '\u0028', '\u000d', '\u0022', '\u000a', '\u0022', + '\u0022', '\u007c', '\u0020', '\u0022', '\u0009', '\u000a', '\u000c', '\u000d', + '\u0022', '\u0029', '\u0022', '\u003f', '\u0020', '\u0022', '\u0027', '\u003a', + '\u005c', '\u007b', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002c', + '\u002e', '\u002f', '\u0020', '\u0022', '\u0027', '\u0031', '\u003a', '\u005c', + '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002c', '\u002e', '\u002f', + '\u0020', '\u0022', '\u0027', '\u002c', '\u003a', '\u005c', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002b', '\u002e', '\u002f', '\u0022', '\u0027', + '\u0036', '\u0022', '\u0027', '\u007d', '\u0022', '\u0027', '\u0028', '\u000d', + '\u0022', '\u0027', '\u000a', '\u0022', '\u0027', '\u0022', '\u0027', '\u007c', + '\u0020', '\u0022', '\u0027', '\u0009', '\u000a', '\u000c', '\u000d', '\u0022', + '\u0027', '\u0029', '\u0022', '\u0027', '\u003f', '\u0020', '\u0022', '\u0027', + '\u003a', '\u003b', '\u005c', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u002c', '\u002e', '\u002f', '\u0020', '\u0022', '\u0027', '\u002d', + '\u0037', '\u003a', '\u003b', '\u005c', '\u007d', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u0031', '\u0020', '\u0022', '\u0027', '\u002d', '\u003a', + '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002f', '\u0020', + '\u0022', '\u0027', '\u003a', '\u003e', '\u005c', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u002c', '\u002e', '\u002f', '\u0020', '\u0021', '\u0022', + '\u0027', '\u003a', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002c', '\u002e', '\u002f', '\u0022', '\u0027', '\u002d', '\u0037', '\u005c', + '\u0000', '\u002f', '\u0030', '\u0031', '\u0032', '\u0039', '\u0022', '\u0027', + '\u003e', '\u0022', '\u0027', '\u002d', '\u0021', '\u0022', '\u0027', '\u0022', + '\u0027', '\u002d', '\u0022', '\u0027', '\u002d', '\u0020', '\u0021', '\u0022', + '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', '\u0075', + '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', + '\u0039', '\u0022', '\u0027', '\u002d', '\u0049', '\u0069', '\u0020', '\u0021', + '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', '\u002d', '\u002f', '\u005c', + '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002e', + '\u0030', '\u0039', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', + '\u002c', '\u002e', '\u002f', '\u003e', '\u005c', '\u0075', '\u007d', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', + '\u0021', '\u0022', '\u0025', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', + '\u002f', '\u005c', '\u0075', '\u007b', '\u007d', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', '\u0021', '\u0022', + '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', '\u0031', '\u005c', + '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', + '\u0030', '\u0039', '\u0020', '\u0021', '\u0022', '\u0025', '\u0027', '\u0028', + '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', '\u0075', '\u007d', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', + '\u0022', '\u0027', '\u002b', '\u002d', '\u0036', '\u0037', '\u005c', '\u0075', + '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002f', '\u0030', '\u0031', + '\u0032', '\u0039', '\u0020', '\u0021', '\u0022', '\u0025', '\u0027', '\u0028', + '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', '\u0075', '\u007d', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u000d', + '\u0020', '\u0022', '\u0027', '\u0029', '\u0009', '\u000c', '\u000a', '\u0020', + '\u0022', '\u0027', '\u0029', '\u0009', '\u000d', '\u0020', '\u0022', '\u0027', + '\u0029', '\u007c', '\u0009', '\u000d', '\u0020', '\u0022', '\u0027', '\u0009', + '\u000a', '\u000c', '\u000d', '\u0022', '\u0027', '\u0029', '\u0022', '\u0027', + '\u003f', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', + '\u002e', '\u002f', '\u005c', '\u0075', '\u007b', '\u007d', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', '\u0022', + '\u0027', '\u002b', '\u002d', '\u0037', '\u005c', '\u0075', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002f', '\u0030', '\u0031', '\u0032', '\u0039', + '\u0020', '\u0022', '\u0027', '\u002d', '\u0037', '\u005c', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002f', '\u0030', '\u0031', '\u0032', '\u0039', + '\u0020', '\u0021', '\u0022', '\u0025', '\u0027', '\u002b', '\u002d', '\u002e', + '\u0037', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u002a', '\u002c', '\u002f', '\u0030', '\u0031', '\u0032', '\u0039', + '\u000a', '\u0022', '\u0027', '\u003a', '\u005c', '\u000c', '\u000d', '\u0030', + '\u0039', '\u0041', '\u0046', '\u0061', '\u0066', '\u0020', '\u0021', '\u0022', + '\u0027', '\u002b', '\u002c', '\u002d', '\u002f', '\u0037', '\u005c', '\u0075', + '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002e', '\u0030', + '\u0031', '\u0032', '\u0039', '\u0020', '\u0022', '\u0029', '\u003a', '\u005c', + '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002c', '\u002e', '\u002f', + '\u0020', '\u0022', '\u0029', '\u003a', '\u0009', '\u000d', '\u0020', '\u0022', + '\u0027', '\u002b', '\u002d', '\u0037', '\u005c', '\u0075', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002f', '\u0030', '\u0031', '\u0032', '\u0039', + '\u0020', '\u0022', '\u002d', '\u0037', '\u005c', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u002f', '\u0030', '\u0031', '\u0032', '\u0039', '\u0020', + '\u0021', '\u0022', '\u0025', '\u0027', '\u002b', '\u002d', '\u002e', '\u0037', + '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002a', '\u002c', '\u002f', '\u0030', '\u0031', '\u0032', '\u0039', '\u0022', + '\u002d', '\u0037', '\u005c', '\u0000', '\u002f', '\u0030', '\u0031', '\u0032', + '\u0039', '\u0022', '\u003e', '\u0022', '\u002d', '\u0021', '\u0022', '\u0022', + '\u002d', '\u0022', '\u002d', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', + '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', '\u0075', '\u007d', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0022', + '\u002d', '\u0049', '\u0069', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', + '\u002b', '\u002c', '\u002d', '\u002f', '\u005c', '\u0075', '\u007d', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002e', '\u0030', '\u0039', '\u0020', + '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', + '\u003e', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u002a', '\u0030', '\u0039', '\u000a', '\u0022', '\u003a', '\u005c', + '\u000c', '\u000d', '\u0030', '\u0039', '\u0041', '\u0046', '\u0061', '\u0066', + '\u0020', '\u0022', '\u003a', '\u005c', '\u007b', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u002c', '\u002e', '\u002f', '\u0020', '\u0022', '\u0031', + '\u003a', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002c', + '\u002e', '\u002f', '\u0020', '\u0022', '\u002c', '\u003a', '\u005c', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002b', '\u002e', '\u002f', '\u0022', + '\u0036', '\u0022', '\u007d', '\u0022', '\u0028', '\u000d', '\u0022', '\u000a', + '\u0022', '\u0022', '\u007c', '\u0020', '\u0022', '\u0009', '\u000a', '\u000c', + '\u000d', '\u0022', '\u0029', '\u0022', '\u003f', '\u0020', '\u0022', '\u0027', + '\u003a', '\u005c', '\u007b', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002c', '\u002e', '\u002f', '\u0020', '\u0022', '\u0027', '\u0031', '\u003a', + '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002c', '\u002e', + '\u002f', '\u0020', '\u0022', '\u0027', '\u002c', '\u003a', '\u005c', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002b', '\u002e', '\u002f', '\u0022', + '\u0027', '\u0036', '\u0022', '\u0027', '\u007d', '\u0022', '\u0027', '\u0028', + '\u000d', '\u0022', '\u0027', '\u000a', '\u0022', '\u0027', '\u0022', '\u0027', + '\u007c', '\u0020', '\u0022', '\u0027', '\u0009', '\u000a', '\u000c', '\u000d', + '\u0022', '\u0027', '\u0029', '\u0022', '\u0027', '\u003f', '\u0020', '\u0022', + '\u0027', '\u003a', '\u003b', '\u005c', '\u007d', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u002c', '\u002e', '\u002f', '\u0020', '\u0022', '\u0027', + '\u002d', '\u0037', '\u003a', '\u003b', '\u005c', '\u007d', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u0031', '\u0020', '\u0022', '\u0027', '\u002d', + '\u003a', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002f', + '\u0020', '\u0022', '\u0027', '\u003a', '\u003e', '\u005c', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002c', '\u002e', '\u002f', '\u0020', '\u0021', + '\u0022', '\u0027', '\u003a', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u002c', '\u002e', '\u002f', '\u0020', '\u0021', '\u0022', '\u0027', + '\u0028', '\u0029', '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', '\u0075', + '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', + '\u0039', '\u0020', '\u0021', '\u0022', '\u0027', '\u0029', '\u002b', '\u002c', + '\u002d', '\u002f', '\u0037', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002e', '\u0030', '\u0031', '\u0032', '\u0039', + '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u0029', '\u002b', '\u002c', + '\u002e', '\u002f', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', '\u0021', '\u0022', + '\u0027', '\u0029', '\u002b', '\u002c', '\u002d', '\u002f', '\u0037', '\u005c', + '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002e', + '\u0030', '\u0031', '\u0032', '\u0039', '\u0020', '\u0021', '\u0022', '\u0025', + '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', '\u0075', + '\u007b', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', + '\u0030', '\u0039', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', + '\u002c', '\u002e', '\u002f', '\u0031', '\u005c', '\u0075', '\u007d', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', + '\u0021', '\u0022', '\u0025', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', + '\u002f', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', '\u0022', '\u0027', '\u002b', + '\u002d', '\u0036', '\u0037', '\u005c', '\u0075', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u002f', '\u0030', '\u0031', '\u0032', '\u0039', '\u0020', + '\u0021', '\u0022', '\u0025', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', + '\u002f', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u002a', '\u0030', '\u0039', '\u000d', '\u0020', '\u0027', '\u0029', + '\u0009', '\u000c', '\u000a', '\u0020', '\u0027', '\u0029', '\u0009', '\u000d', + '\u0020', '\u0027', '\u0029', '\u007c', '\u0009', '\u000d', '\u0020', '\u0027', + '\u0009', '\u000a', '\u000c', '\u000d', '\u0027', '\u0029', '\u0027', '\u003f', + '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', + '\u002f', '\u005c', '\u0075', '\u007b', '\u007d', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', '\u0027', '\u003a', + '\u003b', '\u005c', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002c', '\u002e', '\u002f', '\u0020', '\u0027', '\u002d', '\u0037', '\u003a', + '\u003b', '\u005c', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u0031', '\u0020', '\u0027', '\u002d', '\u003a', '\u005c', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002f', '\u0020', '\u0027', '\u003a', '\u003e', + '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002c', '\u002e', + '\u002f', '\u0020', '\u0021', '\u0027', '\u003a', '\u005c', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002c', '\u002e', '\u002f', '\u0020', '\u0021', + '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', '\u0031', + '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002a', '\u0030', '\u0039', '\u0020', '\u0021', '\u0022', '\u0025', '\u0027', + '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', '\u0075', '\u007d', + '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', + '\u0020', '\u0022', '\u0027', '\u002b', '\u002d', '\u0036', '\u0037', '\u005c', + '\u0075', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002f', '\u0030', + '\u0031', '\u0032', '\u0039', '\u0020', '\u0021', '\u0022', '\u0025', '\u0027', + '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', '\u0075', '\u007d', + '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', + '\u000d', '\u0020', '\u0022', '\u0029', '\u0009', '\u000c', '\u000a', '\u0020', + '\u0022', '\u0029', '\u0009', '\u000d', '\u0020', '\u0022', '\u0029', '\u007c', + '\u0009', '\u000d', '\u0020', '\u0022', '\u0009', '\u000a', '\u000c', '\u000d', + '\u0022', '\u0029', '\u0022', '\u003f', '\u0020', '\u0021', '\u0022', '\u0027', + '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', '\u0075', '\u007b', + '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', + '\u0039', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u0029', '\u002b', + '\u002c', '\u002e', '\u002f', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', '\u0021', + '\u0022', '\u0027', '\u0029', '\u002b', '\u002c', '\u002d', '\u002f', '\u0037', + '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002e', '\u0030', '\u0031', '\u0032', '\u0039', '\u0020', '\u0021', '\u0022', + '\u0025', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', + '\u0075', '\u007b', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002a', '\u0030', '\u0039', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', + '\u002b', '\u002c', '\u002e', '\u002f', '\u0031', '\u005c', '\u0075', '\u007d', + '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', + '\u0020', '\u0021', '\u0022', '\u0025', '\u0027', '\u0028', '\u002b', '\u002c', + '\u002e', '\u002f', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', '\u0022', '\u0027', + '\u002b', '\u002d', '\u0036', '\u0037', '\u005c', '\u0075', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002f', '\u0030', '\u0031', '\u0032', '\u0039', + '\u0020', '\u0021', '\u0022', '\u0025', '\u0027', '\u0028', '\u002b', '\u002c', + '\u002e', '\u002f', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u000d', '\u0020', '\u0022', + '\u0029', '\u0009', '\u000c', '\u000a', '\u0020', '\u0022', '\u0029', '\u0009', + '\u000d', '\u0020', '\u0022', '\u0029', '\u007c', '\u0009', '\u000d', '\u0020', + '\u0022', '\u0009', '\u000a', '\u000c', '\u000d', '\u0022', '\u0029', '\u0022', + '\u003f', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', + '\u002e', '\u002f', '\u005c', '\u0075', '\u007b', '\u007d', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', '\u0022', + '\u003a', '\u003b', '\u005c', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u002c', '\u002e', '\u002f', '\u0020', '\u0022', '\u002d', '\u0037', + '\u003a', '\u003b', '\u005c', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u0031', '\u0020', '\u0022', '\u002d', '\u003a', '\u005c', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002f', '\u0020', '\u0022', '\u003a', + '\u003e', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002c', + '\u002e', '\u002f', '\u0020', '\u0021', '\u0022', '\u003a', '\u005c', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002c', '\u002e', '\u002f', '\u0022', + '\u0027', '\u002d', '\u0037', '\u005c', '\u0000', '\u002f', '\u0030', '\u0031', + '\u0032', '\u0039', '\u0022', '\u0027', '\u003e', '\u0022', '\u0027', '\u002d', + '\u0021', '\u0022', '\u0027', '\u0022', '\u0027', '\u002d', '\u0022', '\u0027', + '\u002d', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', + '\u002e', '\u002f', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0022', '\u0027', '\u002d', + '\u0049', '\u0069', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', + '\u002c', '\u002d', '\u002f', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002e', '\u0030', '\u0039', '\u0020', '\u0021', + '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', '\u003e', + '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002a', '\u0030', '\u0039', '\u0020', '\u0021', '\u0022', '\u0025', '\u0027', + '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', '\u0075', '\u007b', + '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', + '\u0039', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', + '\u002e', '\u002f', '\u0031', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', '\u0021', + '\u0022', '\u0025', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', + '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002a', '\u0030', '\u0039', '\u0020', '\u0022', '\u0027', '\u002b', '\u002d', + '\u0036', '\u0037', '\u005c', '\u0075', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u002f', '\u0030', '\u0031', '\u0032', '\u0039', '\u0020', '\u0021', + '\u0022', '\u0025', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', + '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002a', '\u0030', '\u0039', '\u000d', '\u0020', '\u0022', '\u0027', '\u0029', + '\u0009', '\u000c', '\u000a', '\u0020', '\u0022', '\u0027', '\u0029', '\u0009', + '\u000d', '\u0020', '\u0022', '\u0027', '\u0029', '\u007c', '\u0009', '\u000d', + '\u0020', '\u0022', '\u0027', '\u0009', '\u000a', '\u000c', '\u000d', '\u0022', + '\u0027', '\u0029', '\u0022', '\u0027', '\u003f', '\u0020', '\u0021', '\u0022', + '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', '\u0075', + '\u007b', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', + '\u0030', '\u0039', '\u0020', '\u0022', '\u0027', '\u002b', '\u002d', '\u0037', + '\u005c', '\u0075', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002f', + '\u0030', '\u0031', '\u0032', '\u0039', '\u0020', '\u0022', '\u0027', '\u002d', + '\u0037', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002f', + '\u0030', '\u0031', '\u0032', '\u0039', '\u0020', '\u0021', '\u0022', '\u0025', + '\u0027', '\u002b', '\u002d', '\u002e', '\u0037', '\u005c', '\u0075', '\u007d', + '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u002c', '\u002f', + '\u0030', '\u0031', '\u0032', '\u0039', '\u000a', '\u0022', '\u0027', '\u003a', + '\u005c', '\u000c', '\u000d', '\u0030', '\u0039', '\u0041', '\u0046', '\u0061', + '\u0066', '\u0020', '\u0021', '\u0022', '\u0027', '\u002b', '\u002c', '\u002d', + '\u002f', '\u0037', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u002e', '\u0030', '\u0031', '\u0032', '\u0039', '\u0020', + '\u0021', '\u0022', '\u0027', '\u002b', '\u002c', '\u002d', '\u002f', '\u0037', + '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002e', '\u0030', '\u0031', '\u0032', '\u0039', '\u0020', '\u0022', '\u0027', + '\u003a', '\u005c', '\u007b', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002c', '\u002e', '\u002f', '\u0020', '\u0022', '\u0027', '\u0031', '\u003a', + '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002c', '\u002e', + '\u002f', '\u0020', '\u0022', '\u0027', '\u002c', '\u003a', '\u005c', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002b', '\u002e', '\u002f', '\u0022', + '\u0027', '\u0036', '\u0022', '\u0027', '\u007d', '\u0022', '\u0027', '\u0028', + '\u000d', '\u0022', '\u0027', '\u000a', '\u0022', '\u0027', '\u0022', '\u0027', + '\u007c', '\u0020', '\u0022', '\u0027', '\u0009', '\u000a', '\u000c', '\u000d', + '\u0022', '\u0027', '\u0029', '\u0022', '\u0027', '\u003f', '\u0020', '\u0022', + '\u0027', '\u003a', '\u003b', '\u005c', '\u007d', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u002c', '\u002e', '\u002f', '\u0020', '\u0022', '\u0027', + '\u002d', '\u0037', '\u003a', '\u003b', '\u005c', '\u007d', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u0031', '\u0020', '\u0022', '\u0027', '\u002d', + '\u003a', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002f', + '\u0020', '\u0022', '\u0027', '\u003a', '\u003e', '\u005c', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002c', '\u002e', '\u002f', '\u0020', '\u0021', + '\u0022', '\u0027', '\u003a', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u002c', '\u002e', '\u002f', '\u0020', '\u0021', '\u0022', '\u0025', + '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', '\u0075', + '\u007b', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', + '\u0030', '\u0039', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', + '\u002c', '\u002e', '\u002f', '\u0031', '\u005c', '\u0075', '\u007d', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', + '\u0021', '\u0022', '\u0025', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', + '\u002f', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', '\u0022', '\u0027', '\u002b', + '\u002d', '\u0036', '\u0037', '\u005c', '\u0075', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u002f', '\u0030', '\u0031', '\u0032', '\u0039', '\u0020', + '\u0021', '\u0022', '\u0025', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', + '\u002f', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u002a', '\u0030', '\u0039', '\u000d', '\u0020', '\u0027', '\u0029', + '\u0009', '\u000c', '\u000a', '\u0020', '\u0027', '\u0029', '\u0009', '\u000d', + '\u0020', '\u0027', '\u0029', '\u007c', '\u0009', '\u000d', '\u0020', '\u0027', + '\u0009', '\u000a', '\u000c', '\u000d', '\u0027', '\u0029', '\u0027', '\u003f', + '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', + '\u002f', '\u005c', '\u0075', '\u007b', '\u007d', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', '\u0027', '\u003a', + '\u003b', '\u005c', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002c', '\u002e', '\u002f', '\u0020', '\u0027', '\u002d', '\u0037', '\u003a', + '\u003b', '\u005c', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u0031', '\u0020', '\u0027', '\u002d', '\u003a', '\u005c', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002f', '\u0020', '\u0027', '\u003a', '\u003e', + '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002c', '\u002e', + '\u002f', '\u0020', '\u0021', '\u0027', '\u003a', '\u005c', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002c', '\u002e', '\u002f', '\u0020', '\u0022', + '\u003a', '\u003b', '\u005c', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u002c', '\u002e', '\u002f', '\u0020', '\u0022', '\u002d', '\u0037', + '\u003a', '\u003b', '\u005c', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u0031', '\u0020', '\u0022', '\u002d', '\u003a', '\u005c', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002f', '\u0020', '\u0022', '\u003a', + '\u003e', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002c', + '\u002e', '\u002f', '\u0020', '\u0021', '\u0022', '\u003a', '\u005c', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002c', '\u002e', '\u002f', '\u0020', + '\u0021', '\u0022', '\u0027', '\u0028', '\u0029', '\u002b', '\u002c', '\u002e', + '\u002f', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', '\u0021', '\u0022', '\u0027', + '\u0029', '\u002b', '\u002c', '\u002d', '\u002f', '\u0037', '\u005c', '\u0075', + '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002e', '\u0030', + '\u0031', '\u0032', '\u0039', '\u0020', '\u0021', '\u0022', '\u0025', '\u0027', + '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', '\u005c', '\u0075', '\u007b', + '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', + '\u0039', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', + '\u002e', '\u002f', '\u0031', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', '\u0021', + '\u0022', '\u0025', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', + '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002a', '\u0030', '\u0039', '\u0020', '\u0022', '\u0027', '\u002b', '\u002d', + '\u0036', '\u0037', '\u005c', '\u0075', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u002f', '\u0030', '\u0031', '\u0032', '\u0039', '\u0020', '\u0021', + '\u0022', '\u0025', '\u0027', '\u0028', '\u002b', '\u002c', '\u002e', '\u002f', + '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002a', '\u0030', '\u0039', '\u000d', '\u0020', '\u0029', '\u0009', '\u000c', + '\u000a', '\u0020', '\u0029', '\u0009', '\u000d', '\u0020', '\u0029', '\u007c', + '\u0009', '\u000d', '\u0020', '\u0009', '\u000a', '\u000c', '\u000d', '\u0029', + '\u003f', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', + '\u002e', '\u002f', '\u005c', '\u0075', '\u007b', '\u007d', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002a', '\u0030', '\u0039', '\u0020', '\u003a', + '\u003b', '\u005c', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002c', '\u002e', '\u002f', '\u0020', '\u002d', '\u0037', '\u003a', '\u003b', + '\u005c', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u0031', + '\u0020', '\u002d', '\u003a', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u002f', '\u0020', '\u003a', '\u003e', '\u005c', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002c', '\u002e', '\u002f', '\u0020', '\u0021', + '\u003a', '\u005c', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002c', + '\u002e', '\u002f', '\u007b', '\u0020', '\u002d', '\u003c', '\u007b', '\u0009', + '\u000d', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', + '\u002d', '\u002f', '\u003c', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002e', '\u0030', '\u0039', '\u0020', '\u0021', + '\u0022', '\u0027', '\u002b', '\u002c', '\u002d', '\u002f', '\u0037', '\u003c', + '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002e', '\u0030', '\u0031', '\u0032', '\u0039', '\u0020', '\u0022', '\u0027', + '\u002d', '\u003c', '\u007b', '\u0009', '\u000d', '\u0020', '\u0021', '\u0022', + '\u0027', '\u0028', '\u002b', '\u002c', '\u002d', '\u002f', '\u003c', '\u005c', + '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002e', + '\u0030', '\u0039', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', + '\u002c', '\u002d', '\u002f', '\u003c', '\u005c', '\u0075', '\u007d', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002e', '\u0030', '\u0039', '\u0020', + '\u0021', '\u0022', '\u0027', '\u002b', '\u002c', '\u002d', '\u002f', '\u0037', + '\u003c', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u002e', '\u0030', '\u0031', '\u0032', '\u0039', '\u0020', '\u0027', + '\u002d', '\u003c', '\u007b', '\u0009', '\u000d', '\u0020', '\u0021', '\u0022', + '\u0027', '\u0028', '\u002b', '\u002c', '\u002d', '\u002f', '\u003c', '\u005c', + '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002e', + '\u0030', '\u0039', '\u0020', '\u0021', '\u0022', '\u0027', '\u002b', '\u002c', + '\u002d', '\u002f', '\u0037', '\u003c', '\u005c', '\u0075', '\u007d', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002e', '\u0030', '\u0031', '\u0032', + '\u0039', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', + '\u002d', '\u002f', '\u003c', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002e', '\u0030', '\u0039', '\u0020', '\u0021', + '\u0022', '\u0027', '\u002b', '\u002c', '\u002d', '\u002f', '\u0037', '\u003c', + '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002e', '\u0030', '\u0031', '\u0032', '\u0039', '\u0020', '\u0022', '\u002d', + '\u003c', '\u007b', '\u0009', '\u000d', '\u0020', '\u0022', '\u0027', '\u002d', + '\u003a', '\u003c', '\u005c', '\u007b', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u002f', '\u0020', '\u0022', '\u0027', '\u002d', '\u003a', '\u003c', + '\u007b', '\u0009', '\u000d', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', + '\u002b', '\u002c', '\u002d', '\u002f', '\u003c', '\u005c', '\u0075', '\u007d', + '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002e', '\u0030', '\u0039', + '\u0020', '\u0021', '\u0022', '\u0027', '\u002b', '\u002c', '\u002d', '\u002f', + '\u0037', '\u003c', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u002e', '\u0030', '\u0031', '\u0032', '\u0039', '\u0020', + '\u0022', '\u0027', '\u002d', '\u003c', '\u007b', '\u0009', '\u000d', '\u0020', + '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', '\u002d', '\u002f', + '\u003c', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u002e', '\u0030', '\u0039', '\u0020', '\u0021', '\u0022', '\u0027', + '\u0028', '\u002b', '\u002c', '\u002d', '\u002f', '\u003c', '\u005c', '\u0075', + '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002e', '\u0030', + '\u0039', '\u0020', '\u0021', '\u0022', '\u0027', '\u002b', '\u002c', '\u002d', + '\u002f', '\u0037', '\u003c', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002e', '\u0030', '\u0031', '\u0032', '\u0039', + '\u0020', '\u0027', '\u002d', '\u003c', '\u007b', '\u0009', '\u000d', '\u0020', + '\u0022', '\u0027', '\u002d', '\u003a', '\u003c', '\u005c', '\u007b', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002f', '\u0020', '\u0022', '\u0027', + '\u002d', '\u003a', '\u003c', '\u007b', '\u0009', '\u000d', '\u0020', '\u0021', + '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', '\u002d', '\u002f', '\u003c', + '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002e', '\u0030', '\u0039', '\u0020', '\u0021', '\u0022', '\u0027', '\u002b', + '\u002c', '\u002d', '\u002f', '\u0037', '\u003c', '\u005c', '\u0075', '\u007d', + '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002e', '\u0030', '\u0031', + '\u0032', '\u0039', '\u0020', '\u0022', '\u0027', '\u002d', '\u003c', '\u007b', + '\u0009', '\u000d', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', + '\u002c', '\u002d', '\u002f', '\u003c', '\u005c', '\u0075', '\u007d', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002e', '\u0030', '\u0039', '\u0020', + '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', '\u002d', '\u002f', + '\u003c', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u002e', '\u0030', '\u0039', '\u0020', '\u0021', '\u0022', '\u0027', + '\u002b', '\u002c', '\u002d', '\u002f', '\u0037', '\u003c', '\u005c', '\u0075', + '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002e', '\u0030', + '\u0031', '\u0032', '\u0039', '\u0020', '\u0022', '\u002d', '\u003c', '\u007b', + '\u0009', '\u000d', '\u0020', '\u0022', '\u0027', '\u002d', '\u003a', '\u003c', + '\u005c', '\u007b', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002f', + '\u0020', '\u0022', '\u0027', '\u002d', '\u003a', '\u003c', '\u007b', '\u0009', + '\u000d', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', + '\u002d', '\u002f', '\u003c', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002e', '\u0030', '\u0039', '\u0020', '\u0027', + '\u002d', '\u003a', '\u003c', '\u005c', '\u007b', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u002f', '\u0020', '\u0027', '\u002d', '\u003a', '\u003c', + '\u007b', '\u0009', '\u000d', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', + '\u002b', '\u002c', '\u002d', '\u002f', '\u003c', '\u005c', '\u0075', '\u007d', + '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', '\u002e', '\u0030', '\u0039', + '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', '\u002d', + '\u002f', '\u003c', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', + '\u000d', '\u000e', '\u002e', '\u0030', '\u0039', '\u0020', '\u0022', '\u002d', + '\u003a', '\u003c', '\u005c', '\u007b', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u002f', '\u0020', '\u0022', '\u002d', '\u003a', '\u003c', '\u007b', + '\u0009', '\u000d', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', + '\u002c', '\u002d', '\u002f', '\u003c', '\u005c', '\u0075', '\u007d', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002e', '\u0030', '\u0039', '\u0020', + '\u0021', '\u0022', '\u0027', '\u002b', '\u002c', '\u002d', '\u002f', '\u0037', + '\u003c', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u002e', '\u0030', '\u0031', '\u0032', '\u0039', '\u0020', '\u0022', + '\u0027', '\u002d', '\u003c', '\u007b', '\u0009', '\u000d', '\u0020', '\u0021', + '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', '\u002d', '\u002f', '\u003c', + '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002e', '\u0030', '\u0039', '\u0020', '\u0022', '\u0027', '\u002d', '\u003a', + '\u003c', '\u005c', '\u007b', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002f', '\u0020', '\u0022', '\u0027', '\u002d', '\u003a', '\u003c', '\u007b', + '\u0009', '\u000d', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', + '\u002c', '\u002d', '\u002f', '\u003c', '\u005c', '\u0075', '\u007d', '\u0000', + '\u0008', '\u0009', '\u000d', '\u000e', '\u002e', '\u0030', '\u0039', '\u0020', + '\u0027', '\u002d', '\u003a', '\u003c', '\u005c', '\u007b', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002f', '\u0020', '\u0027', '\u002d', '\u003a', + '\u003c', '\u007b', '\u0009', '\u000d', '\u0020', '\u0022', '\u002d', '\u003a', + '\u003c', '\u005c', '\u007b', '\u0000', '\u0008', '\u0009', '\u000d', '\u000e', + '\u002f', '\u0020', '\u0022', '\u002d', '\u003a', '\u003c', '\u007b', '\u0009', + '\u000d', '\u0020', '\u0021', '\u0022', '\u0027', '\u0028', '\u002b', '\u002c', + '\u002d', '\u002f', '\u003c', '\u005c', '\u0075', '\u007d', '\u0000', '\u0008', + '\u0009', '\u000d', '\u000e', '\u002e', '\u0030', '\u0039', '\u0020', '\u002d', + '\u003a', '\u003c', '\u005c', '\u007b', '\u0000', '\u0008', '\u0009', '\u000d', + '\u000e', '\u002f', '\u0020', '\u002d', '\u003a', '\u003c', '\u007b', '\u0009', + '\u000d', (char) 0 +}; + +static readonly sbyte[] _selector_single_lengths = new sbyte [] { + 0, 6, 2, 3, 2, 8, 1, 12, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 3, 1, 1, 1, 1, 1, 1, + 0, 12, 2, 13, 2, 12, 7, 12, + 12, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 4, 7, 3, 4, 3, 8, + 2, 12, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 4, 7, 3, 4, 3, + 8, 1, 12, 3, 13, 3, 12, 6, + 12, 12, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 5, 8, 4, 5, 4, + 8, 2, 12, 4, 13, 4, 2, 13, + 5, 13, 13, 13, 13, 12, 6, 6, + 6, 7, 7, 7, 7, 7, 6, 3, + 3, 3, 3, 3, 3, 12, 2, 12, + 1, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 4, 7, 3, 4, 3, 8, + 3, 1, 12, 3, 13, 3, 12, 7, + 13, 13, 1, 12, 3, 13, 1, 13, + 6, 14, 13, 13, 12, 6, 4, 4, + 5, 5, 5, 5, 5, 6, 2, 2, + 2, 2, 2, 2, 2, 12, 1, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 4, 7, 3, 4, 3, 8, 1, 12, + 3, 13, 3, 12, 7, 12, 12, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 5, 8, 4, 5, 4, 8, 2, 12, + 4, 13, 4, 2, 13, 6, 13, 13, + 13, 13, 12, 6, 6, 6, 7, 7, + 7, 7, 7, 6, 3, 3, 3, 3, + 3, 3, 12, 2, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 5, 8, 4, + 5, 4, 8, 4, 2, 12, 4, 13, + 4, 12, 7, 13, 13, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 5, 8, + 4, 5, 4, 8, 2, 12, 4, 13, + 12, 6, 14, 2, 13, 13, 13, 12, + 6, 6, 6, 7, 7, 7, 7, 7, + 6, 3, 3, 3, 3, 3, 3, 5, + 3, 3, 3, 3, 3, 12, 5, 12, + 13, 13, 13, 9, 13, 5, 5, 5, + 3, 3, 3, 13, 8, 6, 12, 5, + 5, 4, 8, 5, 12, 1, 13, 13, + 13, 12, 6, 6, 6, 7, 7, 7, + 7, 7, 6, 2, 2, 2, 2, 2, + 2, 4, 2, 2, 2, 2, 2, 12, + 4, 12, 13, 4, 12, 4, 12, 0, + 13, 13, 13, 12, 6, 4, 4, 5, + 5, 5, 5, 5, 6, 1, 1, 1, + 1, 1, 1, 3, 12, 3, 12, 13, + 5, 5, 5, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 12, 5, 12, 1, + 13, 13, 13, 12, 6, 4, 4, 5, + 5, 5, 5, 5, 6, 2, 2, 2, + 2, 2, 2, 4, 2, 2, 2, 2, + 2, 12, 4, 12, 13, 6, 6, 6, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 7, 9, 6, 6, 6, 13, 13, + 13, 13, 12, 6, 6, 6, 7, 7, + 7, 7, 7, 6, 3, 3, 3, 3, + 3, 3, 5, 3, 3, 3, 3, 3, + 12, 5, 12, 13, 14, 2, 13, 13, + 13, 9, 13, 5, 5, 5, 3, 3, + 3, 13, 8, 6, 12, 5, 5, 4, + 8, 5, 12, 1, 13, 13, 13, 12, + 6, 6, 6, 7, 7, 7, 7, 7, + 6, 2, 2, 2, 2, 2, 2, 4, + 2, 2, 2, 2, 2, 12, 4, 12, + 13, 4, 4, 3, 8, 3, 4, 4, + 4, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 5, 5, 5, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 5, 4, + 8, 4, 5, 5, 5, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 6, 6, + 6, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 7, 9, 6, 6, 6, 5, + 3, 3, 3, 3, 3, 12, 5, 12, + 13, 14, 13, 13, 9, 13, 5, 5, + 5, 3, 3, 3, 13, 8, 6, 12, + 5, 12, 5, 4, 8, 5, 12, 4, + 2, 2, 2, 2, 2, 12, 4, 12, + 13, 4, 5, 5, 5, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 6, 6, + 6, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 7, 9, 6, 6, 6, 13, + 13, 13, 13, 14, 13, 13, 9, 13, + 4, 4, 4, 2, 2, 2, 13, 6, + 8, 5, 5, 5, 13, 13, 9, 13, + 4, 4, 4, 2, 2, 2, 13, 13, + 13, 14, 13, 13, 9, 13, 4, 4, + 4, 2, 2, 2, 13, 6, 8, 5, + 5, 5, 5, 3, 3, 3, 3, 3, + 12, 5, 12, 13, 14, 13, 13, 9, + 13, 5, 5, 5, 3, 3, 3, 13, + 8, 6, 12, 5, 12, 12, 6, 6, + 6, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 7, 9, 6, 6, 6, 14, + 13, 13, 9, 13, 4, 4, 4, 2, + 2, 2, 13, 6, 8, 5, 5, 5, + 6, 8, 5, 5, 5, 13, 13, 14, + 13, 13, 9, 13, 3, 3, 3, 1, + 1, 1, 13, 5, 7, 4, 4, 4, + 1, 4, 13, 13, 6, 13, 13, 13, + 5, 13, 13, 13, 13, 5, 8, 7, + 13, 13, 6, 13, 13, 13, 5, 8, + 7, 13, 13, 6, 13, 13, 13, 5, + 8, 7, 13, 7, 6, 13, 13, 7, + 6, 13, 13, 6, 13, 8, 7, 13, + 7, 6, 7, 6, 13, 6, 5 +}; + +static readonly sbyte[] _selector_range_lengths = new sbyte [] { + 0, 3, 1, 4, 1, 5, 0, 5, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, 0, 0, + 1, 6, 3, 4, 1, 4, 4, 4, + 5, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 3, 1, 4, 1, 5, + 0, 5, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 3, 1, 4, 1, + 5, 1, 6, 3, 4, 1, 4, 4, + 4, 5, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 3, 1, 4, 1, + 5, 1, 6, 3, 4, 1, 1, 5, + 4, 4, 5, 4, 4, 4, 3, 3, + 6, 3, 3, 3, 3, 3, 3, 0, + 0, 0, 2, 0, 0, 5, 0, 5, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 3, 1, 4, 1, 5, + 1, 1, 6, 3, 4, 1, 4, 4, + 4, 5, 1, 6, 3, 4, 1, 5, + 4, 4, 4, 4, 4, 3, 4, 7, + 4, 4, 4, 4, 4, 3, 0, 0, + 0, 2, 0, 0, 0, 5, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 3, 1, 4, 1, 5, 1, 6, + 3, 4, 1, 4, 4, 4, 5, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 3, 1, 4, 1, 5, 1, 6, + 3, 4, 1, 1, 5, 4, 4, 5, + 4, 4, 4, 3, 3, 6, 3, 3, + 3, 3, 3, 3, 0, 0, 0, 2, + 0, 0, 5, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 3, 1, + 4, 1, 5, 1, 1, 6, 3, 4, + 1, 4, 4, 4, 5, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 3, + 1, 4, 1, 5, 1, 6, 3, 4, + 4, 4, 4, 1, 5, 4, 4, 4, + 3, 3, 6, 3, 3, 3, 3, 3, + 3, 0, 0, 0, 2, 0, 0, 3, + 0, 0, 0, 0, 0, 4, 0, 4, + 4, 4, 4, 5, 4, 1, 1, 1, + 2, 0, 0, 4, 5, 5, 6, 4, + 4, 1, 5, 5, 6, 1, 5, 4, + 4, 4, 3, 3, 6, 3, 3, 3, + 3, 3, 3, 0, 0, 0, 2, 0, + 0, 3, 0, 0, 0, 0, 0, 4, + 0, 4, 4, 4, 5, 5, 6, 1, + 5, 4, 4, 4, 3, 4, 7, 4, + 4, 4, 4, 4, 3, 0, 0, 0, + 2, 0, 0, 3, 4, 0, 4, 4, + 4, 4, 4, 0, 0, 0, 0, 0, + 0, 2, 0, 0, 5, 5, 6, 1, + 5, 4, 4, 4, 3, 4, 7, 4, + 4, 4, 4, 4, 3, 0, 0, 0, + 2, 0, 0, 3, 0, 0, 0, 0, + 0, 4, 0, 4, 4, 4, 4, 4, + 0, 0, 0, 0, 0, 0, 2, 0, + 0, 4, 3, 3, 4, 4, 4, 5, + 4, 4, 4, 3, 3, 6, 3, 3, + 3, 3, 3, 3, 0, 0, 0, 2, + 0, 0, 3, 0, 0, 0, 0, 0, + 4, 0, 4, 4, 4, 1, 5, 4, + 4, 5, 4, 1, 1, 1, 2, 0, + 0, 4, 5, 5, 6, 4, 4, 1, + 5, 5, 6, 1, 5, 4, 4, 4, + 3, 3, 6, 3, 3, 3, 3, 3, + 3, 0, 0, 0, 2, 0, 0, 3, + 0, 0, 0, 0, 0, 4, 0, 4, + 4, 4, 4, 1, 5, 4, 4, 4, + 4, 0, 0, 0, 0, 0, 0, 2, + 0, 0, 4, 4, 4, 0, 0, 0, + 0, 0, 0, 2, 0, 0, 4, 1, + 5, 4, 4, 4, 4, 0, 0, 0, + 0, 0, 0, 2, 0, 0, 4, 4, + 4, 0, 0, 0, 0, 0, 0, 2, + 0, 0, 4, 3, 3, 4, 4, 3, + 0, 0, 0, 0, 0, 4, 0, 4, + 4, 4, 4, 4, 5, 4, 1, 1, + 1, 2, 0, 0, 4, 5, 5, 6, + 4, 5, 4, 1, 5, 5, 6, 3, + 0, 0, 0, 0, 0, 4, 0, 4, + 4, 4, 4, 4, 4, 0, 0, 0, + 0, 0, 0, 2, 0, 0, 4, 4, + 4, 0, 0, 0, 0, 0, 0, 2, + 0, 0, 4, 3, 3, 4, 4, 4, + 5, 4, 5, 4, 4, 4, 5, 4, + 1, 1, 1, 2, 0, 0, 4, 4, + 3, 3, 4, 4, 4, 4, 5, 4, + 1, 1, 1, 2, 0, 0, 4, 4, + 5, 4, 4, 4, 5, 4, 1, 1, + 1, 2, 0, 0, 4, 4, 3, 3, + 4, 4, 3, 0, 0, 0, 0, 0, + 4, 0, 4, 4, 4, 4, 4, 5, + 4, 1, 1, 1, 2, 0, 0, 4, + 5, 5, 6, 4, 5, 5, 4, 4, + 4, 0, 0, 0, 0, 0, 0, 2, + 0, 0, 4, 3, 3, 4, 4, 4, + 4, 4, 5, 4, 1, 1, 1, 2, + 0, 0, 4, 4, 3, 3, 4, 4, + 4, 3, 3, 4, 4, 4, 5, 4, + 4, 4, 5, 4, 1, 1, 1, 2, + 0, 0, 4, 4, 3, 3, 4, 4, + 0, 1, 4, 5, 1, 4, 4, 5, + 1, 4, 5, 4, 5, 1, 3, 1, + 4, 5, 1, 4, 4, 5, 1, 3, + 1, 4, 5, 1, 4, 4, 5, 1, + 3, 1, 4, 3, 1, 4, 4, 3, + 1, 4, 5, 1, 4, 3, 1, 4, + 3, 1, 3, 1, 4, 3, 1 +}; + +static readonly short[] _selector_index_offsets = new short [] { + 0, 0, 10, 14, 22, 26, 40, 42, + 60, 63, 66, 69, 72, 75, 78, 81, + 84, 87, 92, 94, 96, 98, 100, 102, + 104, 106, 125, 131, 149, 153, 170, 182, + 199, 217, 221, 225, 229, 233, 237, 241, + 245, 249, 253, 259, 270, 275, 284, 289, + 303, 306, 324, 328, 332, 336, 340, 344, + 348, 352, 356, 360, 366, 377, 382, 391, + 396, 410, 413, 432, 439, 457, 462, 479, + 490, 507, 525, 530, 535, 540, 545, 550, + 555, 560, 565, 570, 577, 589, 595, 605, + 611, 625, 629, 648, 656, 674, 680, 684, + 703, 713, 731, 750, 768, 786, 803, 813, + 823, 836, 847, 858, 869, 880, 891, 901, + 905, 909, 913, 919, 923, 927, 945, 948, + 966, 968, 972, 976, 980, 984, 988, 992, + 996, 1000, 1004, 1010, 1021, 1026, 1035, 1040, + 1054, 1059, 1062, 1081, 1088, 1106, 1111, 1128, + 1140, 1158, 1177, 1180, 1199, 1206, 1224, 1227, + 1246, 1257, 1276, 1294, 1312, 1329, 1339, 1348, + 1360, 1370, 1380, 1390, 1400, 1410, 1420, 1423, + 1426, 1429, 1434, 1437, 1440, 1443, 1461, 1463, + 1467, 1471, 1475, 1479, 1483, 1487, 1491, 1495, + 1499, 1505, 1516, 1521, 1530, 1535, 1549, 1552, + 1571, 1578, 1596, 1601, 1618, 1630, 1647, 1665, + 1670, 1675, 1680, 1685, 1690, 1695, 1700, 1705, + 1710, 1717, 1729, 1735, 1745, 1751, 1765, 1769, + 1788, 1796, 1814, 1820, 1824, 1843, 1854, 1872, + 1891, 1909, 1927, 1944, 1954, 1964, 1977, 1988, + 1999, 2010, 2021, 2032, 2042, 2046, 2050, 2054, + 2060, 2064, 2068, 2086, 2089, 2094, 2099, 2104, + 2109, 2114, 2119, 2124, 2129, 2134, 2141, 2153, + 2159, 2169, 2175, 2189, 2195, 2199, 2218, 2226, + 2244, 2250, 2267, 2279, 2297, 2316, 2321, 2326, + 2331, 2336, 2341, 2346, 2351, 2356, 2361, 2368, + 2380, 2386, 2396, 2402, 2416, 2420, 2439, 2447, + 2465, 2482, 2493, 2512, 2516, 2535, 2553, 2571, + 2588, 2598, 2608, 2621, 2632, 2643, 2654, 2665, + 2676, 2686, 2690, 2694, 2698, 2704, 2708, 2712, + 2721, 2725, 2729, 2733, 2737, 2741, 2758, 2764, + 2781, 2799, 2817, 2835, 2850, 2868, 2875, 2882, + 2889, 2895, 2899, 2903, 2921, 2935, 2947, 2966, + 2976, 2986, 2992, 3006, 3017, 3036, 3039, 3058, + 3076, 3094, 3111, 3121, 3131, 3144, 3155, 3166, + 3177, 3188, 3199, 3209, 3212, 3215, 3218, 3223, + 3226, 3229, 3237, 3240, 3243, 3246, 3249, 3252, + 3269, 3274, 3291, 3309, 3318, 3336, 3346, 3365, + 3367, 3386, 3404, 3422, 3439, 3449, 3458, 3470, + 3480, 3490, 3500, 3510, 3520, 3530, 3532, 3534, + 3536, 3540, 3542, 3544, 3551, 3568, 3572, 3589, + 3607, 3617, 3627, 3637, 3640, 3643, 3646, 3649, + 3652, 3655, 3660, 3663, 3666, 3684, 3695, 3714, + 3717, 3736, 3754, 3772, 3789, 3799, 3808, 3820, + 3830, 3840, 3850, 3860, 3870, 3880, 3883, 3886, + 3889, 3894, 3897, 3900, 3908, 3911, 3914, 3917, + 3920, 3923, 3940, 3945, 3962, 3980, 3991, 4002, + 4013, 4017, 4021, 4025, 4029, 4033, 4037, 4043, + 4047, 4051, 4063, 4076, 4086, 4097, 4108, 4126, + 4145, 4163, 4181, 4198, 4208, 4218, 4231, 4242, + 4253, 4264, 4275, 4286, 4296, 4300, 4304, 4308, + 4314, 4318, 4322, 4331, 4335, 4339, 4343, 4347, + 4351, 4368, 4374, 4391, 4409, 4428, 4432, 4451, + 4469, 4487, 4502, 4520, 4527, 4534, 4541, 4547, + 4551, 4555, 4573, 4587, 4599, 4618, 4628, 4638, + 4644, 4658, 4669, 4688, 4691, 4710, 4728, 4746, + 4763, 4773, 4783, 4796, 4807, 4818, 4829, 4840, + 4851, 4861, 4864, 4867, 4870, 4875, 4878, 4881, + 4889, 4892, 4895, 4898, 4901, 4904, 4921, 4926, + 4943, 4961, 4970, 4979, 4984, 4998, 5006, 5015, + 5024, 5033, 5035, 5037, 5039, 5041, 5043, 5045, + 5049, 5051, 5053, 5063, 5073, 5083, 5086, 5089, + 5092, 5095, 5098, 5101, 5106, 5109, 5112, 5122, + 5128, 5142, 5151, 5161, 5171, 5181, 5184, 5187, + 5190, 5193, 5196, 5199, 5204, 5207, 5210, 5221, + 5232, 5243, 5247, 5251, 5255, 5259, 5263, 5267, + 5273, 5277, 5281, 5293, 5306, 5316, 5327, 5338, + 5347, 5351, 5355, 5359, 5363, 5367, 5384, 5390, + 5407, 5425, 5444, 5462, 5480, 5495, 5513, 5520, + 5527, 5534, 5540, 5544, 5548, 5566, 5580, 5592, + 5611, 5621, 5639, 5649, 5655, 5669, 5680, 5699, + 5707, 5710, 5713, 5716, 5719, 5722, 5739, 5744, + 5761, 5779, 5788, 5798, 5808, 5818, 5821, 5824, + 5827, 5830, 5833, 5836, 5841, 5844, 5847, 5858, + 5869, 5880, 5884, 5888, 5892, 5896, 5900, 5904, + 5910, 5914, 5918, 5930, 5943, 5953, 5964, 5975, + 5993, 6012, 6030, 6049, 6068, 6086, 6104, 6119, + 6137, 6143, 6149, 6155, 6160, 6163, 6166, 6184, + 6195, 6207, 6216, 6226, 6236, 6254, 6272, 6287, + 6305, 6311, 6317, 6323, 6328, 6331, 6334, 6352, + 6370, 6389, 6408, 6426, 6444, 6459, 6477, 6483, + 6489, 6495, 6500, 6503, 6506, 6524, 6535, 6547, + 6556, 6566, 6576, 6585, 6589, 6593, 6597, 6601, + 6605, 6622, 6628, 6645, 6663, 6682, 6700, 6718, + 6733, 6751, 6758, 6765, 6772, 6778, 6782, 6786, + 6804, 6818, 6830, 6849, 6859, 6877, 6895, 6906, + 6917, 6928, 6932, 6936, 6940, 6944, 6948, 6952, + 6958, 6962, 6966, 6978, 6991, 7001, 7012, 7023, + 7042, 7060, 7078, 7093, 7111, 7117, 7123, 7129, + 7134, 7137, 7140, 7158, 7169, 7181, 7190, 7200, + 7210, 7221, 7233, 7242, 7252, 7262, 7280, 7299, + 7318, 7336, 7354, 7369, 7387, 7392, 7397, 7402, + 7406, 7408, 7410, 7428, 7438, 7449, 7457, 7466, + 7475, 7477, 7483, 7501, 7520, 7528, 7546, 7564, + 7583, 7590, 7608, 7627, 7645, 7664, 7671, 7683, + 7692, 7710, 7729, 7737, 7755, 7773, 7792, 7799, + 7811, 7820, 7838, 7857, 7865, 7883, 7901, 7920, + 7927, 7939, 7948, 7966, 7977, 7985, 8003, 8021, + 8032, 8040, 8058, 8077, 8085, 8103, 8115, 8124, + 8142, 8153, 8161, 8172, 8180, 8198, 8208 +}; + +static readonly short[] _selector_trans_targs = new short [] { + 1, 2, 0, 811, 549, 869, 0, 1, + 0, 3, 0, 549, 0, 3, 4, 548, + 549, 0, 4, 0, 0, 3, 4, 5, + 4, 0, 5, 6, 23, 24, 26, 25, + 30, 377, 0, 5, 0, 25, 27, 29, + 7, 6, 7, 8, 6, 23, 24, 5, + 26, 5, 25, 30, 377, 825, 0, 7, + 0, 25, 27, 29, 9, 9, 0, 10, + 10, 0, 11, 11, 0, 12, 12, 0, + 13, 13, 0, 14, 14, 0, 15, 15, + 0, 16, 16, 0, 17, 17, 0, 17, + 1, 817, 17, 0, 19, 0, 817, 0, + 21, 0, 22, 0, 817, 0, 7, 23, + 25, 0, 7, 8, 6, 7, 23, 24, + 26, 375, 25, 30, 377, 825, 0, 7, + 0, 5, 25, 27, 29, 25, 30, 0, + 25, 27, 29, 7, 8, 6, 7, 23, + 28, 24, 5, 375, 5, 30, 377, 825, + 0, 7, 0, 27, 29, 28, 7, 28, + 0, 7, 8, 6, 23, 28, 24, 5, + 0, 5, 30, 377, 825, 0, 7, 0, + 27, 29, 7, 31, 70, 797, 30, 377, + 825, 7, 799, 810, 810, 29, 32, 33, + 32, 48, 136, 146, 47, 6, 47, 152, + 154, 845, 6, 32, 6, 149, 31, 32, + 33, 32, 48, 146, 47, 148, 47, 147, + 152, 154, 845, 6, 32, 6, 147, 149, + 31, 7, 34, 34, 6, 7, 35, 35, + 6, 7, 36, 36, 6, 7, 37, 37, + 6, 7, 38, 38, 6, 7, 39, 39, + 6, 7, 40, 40, 6, 7, 41, 41, + 6, 7, 42, 42, 6, 42, 7, 43, + 847, 42, 6, 43, 7, 44, 6, 792, + 649, 866, 6, 43, 6, 45, 7, 6, + 649, 6, 45, 46, 7, 636, 649, 6, + 46, 6, 6, 45, 46, 7, 47, 46, + 6, 47, 32, 48, 146, 148, 147, 152, + 154, 6, 47, 6, 147, 149, 31, 49, + 32, 48, 49, 50, 48, 49, 65, 64, + 67, 64, 66, 71, 343, 822, 23, 49, + 23, 66, 68, 70, 7, 51, 51, 23, + 7, 52, 52, 23, 7, 53, 53, 23, + 7, 54, 54, 23, 7, 55, 55, 23, + 7, 56, 56, 23, 7, 57, 57, 23, + 7, 58, 58, 23, 7, 59, 59, 23, + 59, 7, 60, 824, 59, 23, 60, 7, + 61, 23, 787, 371, 864, 23, 60, 23, + 62, 7, 23, 371, 23, 62, 63, 7, + 338, 371, 23, 63, 23, 23, 62, 63, + 7, 64, 63, 23, 64, 48, 49, 65, + 67, 66, 71, 343, 23, 64, 23, 66, + 68, 70, 7, 66, 23, 49, 50, 48, + 49, 49, 65, 67, 341, 66, 71, 343, + 822, 23, 49, 23, 64, 66, 68, 70, + 7, 66, 71, 23, 66, 68, 70, 49, + 50, 48, 49, 49, 69, 65, 64, 341, + 64, 71, 343, 822, 23, 49, 23, 68, + 70, 69, 7, 49, 69, 23, 49, 50, + 48, 49, 69, 65, 64, 23, 64, 71, + 343, 822, 23, 49, 23, 68, 70, 49, + 72, 679, 71, 343, 822, 49, 775, 786, + 786, 70, 73, 74, 73, 73, 93, 89, + 88, 48, 88, 96, 99, 857, 48, 73, + 48, 92, 72, 73, 74, 73, 73, 89, + 88, 91, 88, 90, 96, 99, 857, 48, + 73, 48, 90, 92, 72, 49, 32, 75, + 75, 48, 49, 32, 76, 76, 48, 49, + 32, 77, 77, 48, 49, 32, 78, 78, + 48, 49, 32, 79, 79, 48, 49, 32, + 80, 80, 48, 49, 32, 81, 81, 48, + 49, 32, 82, 82, 48, 49, 32, 83, + 83, 48, 83, 49, 32, 84, 859, 83, + 48, 84, 49, 32, 85, 48, 770, 755, + 861, 48, 84, 48, 86, 49, 32, 48, + 755, 48, 86, 87, 49, 32, 752, 755, + 48, 87, 48, 48, 86, 87, 49, 32, + 88, 87, 48, 88, 73, 73, 89, 91, + 90, 96, 99, 48, 88, 48, 90, 92, + 72, 49, 32, 90, 48, 73, 74, 73, + 73, 73, 89, 91, 94, 90, 96, 99, + 857, 48, 73, 48, 88, 90, 92, 72, + 49, 32, 90, 96, 48, 90, 92, 72, + 73, 74, 73, 73, 73, 93, 89, 88, + 94, 88, 96, 99, 857, 48, 73, 48, + 92, 72, 93, 49, 32, 73, 93, 48, + 49, 32, 95, 48, 73, 74, 73, 73, + 73, 89, 88, 91, 88, 90, 96, 99, + 857, 48, 73, 48, 90, 92, 72, 73, + 97, 96, 99, 857, 73, 740, 751, 751, + 72, 98, 74, 73, 73, 93, 73, 89, + 88, 48, 88, 96, 99, 857, 48, 98, + 48, 92, 72, 98, 74, 73, 73, 73, + 89, 88, 91, 88, 90, 96, 99, 857, + 48, 98, 48, 90, 92, 72, 73, 74, + 73, 73, 93, 89, 88, 48, 88, 96, + 100, 99, 857, 48, 73, 48, 92, 72, + 73, 74, 73, 73, 93, 89, 88, 48, + 88, 96, 101, 99, 857, 48, 73, 48, + 92, 72, 73, 74, 73, 73, 102, 89, + 88, 48, 88, 96, 99, 857, 48, 73, + 48, 92, 72, 102, 117, 198, 48, 73, + 104, 48, 102, 48, 103, 93, 49, 32, + 48, 73, 104, 48, 93, 48, 103, 93, + 49, 32, 48, 73, 104, 48, 93, 48, + 105, 105, 105, 103, 93, 49, 32, 48, + 73, 104, 106, 48, 93, 48, 103, 93, + 49, 32, 48, 73, 107, 104, 48, 93, + 48, 103, 93, 49, 32, 48, 73, 108, + 104, 48, 93, 48, 103, 93, 49, 32, + 48, 73, 109, 104, 48, 93, 48, 103, + 93, 49, 32, 48, 73, 104, 110, 48, + 93, 48, 103, 93, 49, 32, 111, 73, + 104, 48, 93, 48, 103, 112, 49, 32, + 48, 113, 49, 32, 48, 49, 32, 114, + 48, 115, 49, 32, 115, 115, 48, 49, + 32, 116, 48, 49, 32, 103, 48, 117, + 269, 93, 117, 284, 283, 286, 283, 285, + 289, 293, 818, 118, 117, 118, 285, 287, + 288, 69, 119, 118, 119, 121, 136, 118, + 137, 135, 139, 135, 138, 143, 417, 827, + 120, 119, 120, 138, 140, 142, 28, 120, + 28, 122, 122, 120, 28, 123, 123, 120, + 28, 124, 124, 120, 28, 125, 125, 120, + 28, 126, 126, 120, 28, 127, 127, 120, + 28, 128, 128, 120, 28, 129, 129, 120, + 28, 130, 130, 120, 130, 28, 131, 829, + 130, 120, 131, 28, 132, 120, 725, 577, + 855, 120, 131, 120, 133, 28, 120, 577, + 120, 133, 134, 28, 576, 577, 120, 134, + 120, 120, 133, 134, 28, 135, 134, 120, + 135, 136, 118, 137, 139, 138, 143, 417, + 120, 135, 120, 138, 140, 142, 136, 7, + 32, 136, 6, 28, 138, 120, 119, 121, + 136, 119, 118, 137, 139, 415, 138, 143, + 417, 827, 120, 119, 120, 135, 138, 140, + 142, 28, 138, 143, 120, 138, 140, 142, + 119, 121, 136, 119, 118, 141, 137, 135, + 415, 135, 143, 417, 827, 120, 119, 120, + 140, 142, 141, 28, 119, 141, 120, 119, + 121, 136, 118, 141, 137, 135, 120, 135, + 143, 417, 827, 120, 119, 120, 140, 142, + 119, 144, 288, 711, 143, 417, 827, 119, + 713, 724, 724, 142, 145, 33, 32, 48, + 136, 32, 146, 47, 6, 47, 152, 154, + 845, 6, 145, 6, 149, 31, 145, 33, + 32, 48, 32, 146, 47, 148, 47, 147, + 152, 154, 845, 6, 145, 6, 147, 149, + 31, 7, 147, 6, 32, 33, 32, 32, + 48, 146, 148, 150, 147, 152, 154, 845, + 6, 32, 6, 47, 147, 149, 31, 7, + 147, 152, 6, 147, 149, 31, 32, 33, + 32, 32, 48, 136, 146, 47, 150, 47, + 152, 154, 845, 6, 32, 6, 149, 31, + 7, 151, 6, 32, 33, 32, 32, 48, + 146, 47, 148, 47, 147, 152, 154, 845, + 6, 32, 6, 147, 149, 31, 32, 72, + 144, 152, 154, 845, 32, 153, 710, 710, + 31, 32, 33, 32, 32, 48, 136, 146, + 47, 150, 47, 152, 154, 700, 845, 6, + 32, 6, 149, 31, 32, 33, 32, 48, + 136, 146, 47, 6, 47, 152, 155, 154, + 845, 6, 32, 6, 149, 31, 32, 33, + 32, 48, 136, 146, 47, 6, 47, 152, + 156, 154, 845, 6, 32, 6, 149, 31, + 32, 33, 32, 48, 157, 146, 47, 6, + 47, 152, 154, 845, 6, 32, 6, 149, + 31, 157, 119, 172, 6, 32, 159, 6, + 157, 6, 158, 136, 7, 32, 159, 6, + 136, 6, 6, 158, 136, 7, 32, 159, + 6, 136, 6, 6, 160, 160, 160, 158, + 136, 7, 32, 159, 161, 6, 136, 6, + 6, 158, 136, 7, 32, 162, 159, 6, + 136, 6, 6, 158, 136, 7, 32, 163, + 159, 6, 136, 6, 6, 158, 136, 7, + 32, 164, 159, 6, 136, 6, 6, 158, + 136, 7, 32, 159, 165, 6, 136, 6, + 6, 158, 136, 7, 6, 166, 32, 159, + 6, 136, 6, 158, 167, 7, 6, 168, + 7, 6, 7, 169, 6, 170, 7, 170, + 170, 6, 7, 171, 6, 7, 158, 6, + 173, 136, 172, 173, 175, 172, 69, 190, + 189, 192, 189, 191, 196, 517, 836, 174, + 173, 174, 191, 193, 195, 28, 174, 28, + 176, 176, 174, 28, 177, 177, 174, 28, + 178, 178, 174, 28, 179, 179, 174, 28, + 180, 180, 174, 28, 181, 181, 174, 28, + 182, 182, 174, 28, 183, 183, 174, 28, + 184, 184, 174, 184, 28, 185, 838, 184, + 174, 185, 28, 186, 174, 695, 545, 851, + 174, 185, 174, 187, 28, 174, 545, 174, + 187, 188, 28, 512, 545, 174, 188, 174, + 174, 187, 188, 28, 189, 188, 174, 189, + 172, 69, 190, 192, 191, 196, 517, 174, + 189, 174, 191, 193, 195, 28, 191, 174, + 173, 175, 172, 173, 69, 190, 192, 515, + 191, 196, 517, 836, 174, 173, 174, 189, + 191, 193, 195, 28, 191, 196, 174, 191, + 193, 195, 173, 175, 172, 173, 69, 194, + 190, 189, 515, 189, 196, 517, 836, 174, + 173, 174, 193, 195, 194, 28, 173, 194, + 174, 173, 175, 172, 69, 194, 190, 189, + 174, 189, 196, 517, 836, 174, 173, 174, + 193, 195, 173, 197, 679, 681, 196, 517, + 836, 173, 683, 694, 694, 195, 198, 199, + 198, 93, 218, 214, 213, 172, 213, 221, + 224, 841, 172, 198, 172, 217, 197, 198, + 199, 198, 93, 214, 213, 216, 213, 215, + 221, 224, 841, 172, 198, 172, 215, 217, + 197, 173, 136, 200, 200, 172, 173, 136, + 201, 201, 172, 173, 136, 202, 202, 172, + 173, 136, 203, 203, 172, 173, 136, 204, + 204, 172, 173, 136, 205, 205, 172, 173, + 136, 206, 206, 172, 173, 136, 207, 207, + 172, 173, 136, 208, 208, 172, 208, 173, + 136, 209, 843, 208, 172, 209, 173, 136, + 210, 172, 674, 632, 848, 172, 209, 172, + 211, 173, 136, 172, 632, 172, 211, 212, + 173, 136, 629, 632, 172, 212, 172, 172, + 211, 212, 173, 136, 213, 212, 172, 213, + 198, 93, 214, 216, 215, 221, 224, 172, + 213, 172, 215, 217, 197, 173, 136, 215, + 172, 198, 199, 198, 198, 93, 214, 216, + 219, 215, 221, 224, 841, 172, 198, 172, + 213, 215, 217, 197, 173, 136, 215, 221, + 172, 215, 217, 197, 198, 199, 198, 198, + 93, 218, 214, 213, 219, 213, 221, 224, + 841, 172, 198, 172, 217, 197, 218, 173, + 136, 198, 218, 172, 173, 136, 220, 172, + 198, 199, 198, 198, 93, 214, 213, 216, + 213, 215, 221, 224, 841, 172, 198, 172, + 215, 217, 197, 198, 97, 222, 221, 224, + 841, 198, 617, 628, 628, 197, 223, 199, + 198, 93, 218, 198, 214, 213, 172, 213, + 221, 224, 841, 172, 223, 172, 217, 197, + 223, 199, 198, 93, 198, 214, 213, 216, + 213, 215, 221, 224, 841, 172, 223, 172, + 215, 217, 197, 198, 199, 198, 93, 218, + 214, 213, 172, 213, 221, 225, 224, 841, + 172, 198, 172, 217, 197, 198, 199, 198, + 93, 218, 214, 213, 172, 213, 221, 226, + 224, 841, 172, 198, 172, 217, 197, 198, + 199, 198, 93, 227, 214, 213, 172, 213, + 221, 224, 841, 172, 198, 172, 217, 197, + 227, 242, 218, 172, 198, 229, 172, 227, + 172, 228, 218, 173, 136, 172, 198, 229, + 172, 218, 172, 228, 218, 173, 136, 172, + 198, 229, 172, 218, 172, 230, 230, 230, + 228, 218, 173, 136, 172, 198, 229, 231, + 172, 218, 172, 228, 218, 173, 136, 172, + 198, 232, 229, 172, 218, 172, 228, 218, + 173, 136, 172, 198, 233, 229, 172, 218, + 172, 228, 218, 173, 136, 172, 198, 234, + 229, 172, 218, 172, 228, 218, 173, 136, + 172, 198, 229, 235, 172, 218, 172, 228, + 218, 173, 136, 236, 198, 229, 172, 218, + 172, 228, 237, 173, 136, 172, 238, 173, + 136, 172, 173, 136, 239, 172, 240, 173, + 136, 240, 240, 172, 173, 136, 241, 172, + 173, 136, 228, 172, 242, 244, 218, 259, + 260, 258, 262, 258, 261, 266, 464, 832, + 243, 242, 243, 261, 263, 265, 194, 141, + 243, 194, 141, 245, 245, 243, 194, 141, + 246, 246, 243, 194, 141, 247, 247, 243, + 194, 141, 248, 248, 243, 194, 141, 249, + 249, 243, 194, 141, 250, 250, 243, 194, + 141, 251, 251, 243, 194, 141, 252, 252, + 243, 194, 141, 253, 253, 243, 253, 194, + 141, 254, 834, 253, 243, 254, 194, 141, + 255, 243, 602, 509, 839, 243, 254, 243, + 256, 194, 141, 243, 509, 243, 256, 257, + 194, 141, 506, 509, 243, 257, 243, 243, + 256, 257, 194, 141, 258, 257, 243, 258, + 218, 259, 260, 262, 261, 266, 464, 243, + 258, 243, 261, 263, 265, 259, 69, 119, + 117, 259, 118, 194, 141, 261, 243, 242, + 244, 218, 242, 259, 260, 262, 493, 261, + 266, 464, 832, 243, 242, 243, 258, 261, + 263, 265, 194, 141, 261, 266, 243, 261, + 263, 265, 242, 244, 218, 242, 259, 264, + 260, 258, 493, 258, 266, 464, 832, 243, + 242, 243, 263, 265, 264, 194, 141, 242, + 264, 243, 242, 244, 218, 259, 264, 260, + 258, 243, 258, 266, 464, 832, 243, 242, + 243, 263, 265, 242, 222, 267, 462, 266, + 464, 832, 242, 492, 505, 505, 265, 268, + 269, 93, 117, 259, 117, 284, 283, 118, + 283, 289, 293, 818, 118, 268, 118, 287, + 288, 268, 269, 93, 117, 117, 284, 283, + 286, 283, 285, 289, 293, 818, 118, 268, + 118, 285, 287, 288, 69, 119, 270, 270, + 118, 69, 119, 271, 271, 118, 69, 119, + 272, 272, 118, 69, 119, 273, 273, 118, + 69, 119, 274, 274, 118, 69, 119, 275, + 275, 118, 69, 119, 276, 276, 118, 69, + 119, 277, 277, 118, 69, 119, 278, 278, + 118, 278, 69, 119, 279, 820, 278, 118, + 279, 69, 119, 280, 118, 457, 335, 830, + 118, 279, 118, 281, 69, 119, 118, 335, + 118, 281, 282, 69, 119, 332, 335, 118, + 282, 118, 118, 281, 282, 69, 119, 283, + 282, 118, 283, 93, 117, 284, 286, 285, + 289, 293, 118, 283, 118, 285, 287, 288, + 69, 119, 285, 118, 117, 269, 93, 117, + 117, 284, 286, 291, 285, 289, 293, 818, + 118, 117, 118, 283, 285, 287, 288, 69, + 119, 285, 289, 118, 285, 287, 288, 117, + 269, 93, 117, 117, 259, 284, 283, 291, + 283, 289, 293, 818, 118, 117, 118, 287, + 288, 117, 269, 93, 117, 259, 284, 283, + 118, 283, 289, 293, 818, 118, 117, 118, + 287, 288, 117, 97, 267, 289, 293, 818, + 117, 290, 331, 331, 288, 117, 269, 93, + 117, 117, 259, 284, 283, 291, 283, 289, + 293, 321, 818, 118, 117, 118, 287, 288, + 69, 119, 292, 118, 117, 269, 93, 117, + 117, 284, 283, 286, 283, 285, 289, 293, + 818, 118, 117, 118, 285, 287, 288, 117, + 269, 93, 117, 259, 284, 283, 118, 283, + 289, 294, 293, 818, 118, 117, 118, 287, + 288, 117, 269, 93, 117, 259, 284, 283, + 118, 283, 289, 295, 293, 818, 118, 117, + 118, 287, 288, 117, 269, 93, 117, 296, + 284, 283, 118, 283, 289, 293, 818, 118, + 117, 118, 287, 288, 296, 259, 242, 118, + 117, 298, 118, 296, 118, 297, 259, 69, + 119, 118, 117, 298, 118, 259, 118, 297, + 259, 69, 119, 118, 117, 298, 118, 259, + 118, 299, 299, 299, 297, 259, 69, 119, + 118, 117, 298, 300, 118, 259, 118, 297, + 259, 69, 119, 118, 117, 301, 298, 118, + 259, 118, 297, 259, 69, 119, 118, 117, + 302, 298, 118, 259, 118, 297, 259, 69, + 119, 118, 117, 303, 298, 118, 259, 118, + 297, 259, 69, 119, 118, 117, 298, 304, + 118, 259, 118, 297, 259, 69, 119, 305, + 117, 298, 118, 259, 118, 297, 306, 69, + 119, 118, 307, 69, 119, 118, 69, 119, + 308, 118, 309, 69, 119, 309, 309, 118, + 69, 119, 310, 118, 69, 119, 297, 118, + 69, 119, 312, 285, 289, 118, 285, 287, + 288, 69, 119, 820, 118, 69, 119, 312, + 118, 315, 69, 119, 118, 69, 119, 316, + 118, 69, 119, 820, 118, 117, 318, 93, + 117, 259, 284, 283, 118, 283, 289, 293, + 818, 118, 117, 118, 287, 288, 69, 119, + 316, 270, 270, 118, 117, 269, 93, 117, + 259, 284, 283, 320, 283, 289, 293, 818, + 118, 117, 118, 287, 288, 117, 269, 93, + 117, 259, 284, 283, 118, 283, 818, 289, + 293, 818, 118, 117, 118, 287, 288, 117, + 269, 93, 117, 259, 284, 283, 118, 283, + 322, 289, 293, 818, 118, 117, 118, 287, + 288, 117, 269, 93, 117, 117, 259, 284, + 323, 291, 283, 289, 293, 818, 118, 117, + 118, 287, 288, 283, 93, 117, 284, 286, + 324, 285, 289, 293, 118, 283, 118, 285, + 287, 288, 117, 269, 93, 117, 117, 259, + 284, 283, 291, 283, 289, 293, 821, 118, + 117, 118, 287, 288, 326, 259, 69, 119, + 117, 259, 118, 327, 259, 69, 119, 117, + 259, 118, 259, 69, 119, 117, 328, 259, + 118, 329, 69, 119, 329, 329, 118, 69, + 119, 330, 118, 69, 119, 288, 118, 117, + 269, 93, 117, 259, 284, 283, 118, 283, + 289, 293, 321, 818, 118, 117, 118, 287, + 288, 283, 93, 117, 284, 333, 334, 289, + 293, 118, 283, 118, 334, 287, 288, 282, + 69, 119, 281, 334, 289, 118, 282, 118, + 334, 287, 288, 117, 269, 93, 117, 117, + 284, 333, 291, 334, 289, 293, 818, 118, + 117, 118, 283, 334, 287, 288, 282, 336, + 412, 332, 335, 282, 445, 445, 445, 281, + 337, 7, 49, 338, 371, 23, 337, 23, + 23, 62, 337, 7, 49, 64, 337, 23, + 64, 48, 49, 65, 339, 340, 71, 343, + 23, 64, 23, 340, 68, 70, 63, 7, + 62, 340, 71, 23, 63, 23, 340, 68, + 70, 49, 50, 48, 49, 49, 65, 339, + 341, 340, 71, 343, 822, 23, 49, 23, + 64, 340, 68, 70, 7, 342, 23, 49, + 50, 48, 49, 49, 65, 64, 67, 64, + 66, 71, 343, 822, 23, 49, 23, 66, + 68, 70, 49, 50, 48, 49, 69, 65, + 64, 23, 64, 71, 344, 343, 822, 23, + 49, 23, 68, 70, 49, 50, 48, 49, + 69, 65, 64, 23, 64, 71, 345, 343, + 822, 23, 49, 23, 68, 70, 49, 50, + 48, 49, 346, 65, 64, 23, 64, 71, + 343, 822, 23, 49, 23, 68, 70, 346, + 118, 173, 23, 49, 348, 23, 346, 23, + 347, 69, 23, 7, 23, 49, 348, 23, + 69, 23, 347, 69, 23, 7, 23, 49, + 348, 23, 69, 23, 349, 349, 349, 347, + 69, 23, 7, 23, 49, 348, 350, 23, + 69, 23, 347, 69, 23, 7, 23, 49, + 351, 348, 23, 69, 23, 347, 69, 23, + 7, 23, 49, 352, 348, 23, 69, 23, + 347, 69, 23, 7, 23, 49, 353, 348, + 23, 69, 23, 347, 69, 23, 7, 23, + 49, 348, 354, 23, 69, 23, 347, 69, + 23, 7, 355, 49, 348, 23, 69, 23, + 347, 356, 7, 23, 357, 7, 23, 7, + 358, 23, 359, 7, 359, 359, 23, 7, + 360, 23, 7, 347, 23, 7, 362, 66, + 71, 23, 66, 68, 70, 7, 824, 23, + 7, 362, 23, 365, 7, 23, 7, 366, + 23, 7, 824, 23, 49, 368, 48, 49, + 69, 65, 64, 23, 64, 71, 343, 822, + 23, 49, 23, 68, 70, 7, 366, 51, + 51, 23, 49, 50, 48, 49, 69, 65, + 64, 370, 64, 71, 343, 822, 23, 49, + 23, 68, 70, 49, 50, 48, 49, 69, + 65, 64, 23, 64, 822, 71, 343, 822, + 23, 49, 23, 68, 70, 63, 372, 338, + 371, 63, 400, 400, 400, 62, 7, 8, + 6, 23, 24, 5, 373, 5, 374, 30, + 377, 825, 0, 7, 0, 374, 27, 29, + 4, 3, 374, 30, 0, 4, 0, 374, + 27, 29, 7, 8, 6, 7, 23, 24, + 373, 375, 374, 30, 377, 825, 0, 7, + 0, 5, 374, 27, 29, 376, 0, 7, + 8, 6, 7, 23, 24, 5, 26, 5, + 25, 30, 377, 825, 0, 7, 0, 25, + 27, 29, 7, 8, 6, 23, 28, 24, + 5, 0, 5, 30, 378, 377, 825, 0, + 7, 0, 27, 29, 7, 8, 6, 23, + 28, 24, 5, 0, 5, 30, 379, 377, + 825, 0, 7, 0, 27, 29, 7, 8, + 6, 23, 380, 24, 5, 0, 5, 30, + 377, 825, 0, 7, 0, 27, 29, 380, + 120, 174, 0, 7, 382, 0, 380, 0, + 381, 28, 0, 7, 382, 0, 28, 0, + 0, 381, 28, 0, 7, 382, 0, 28, + 0, 0, 383, 383, 383, 381, 28, 0, + 7, 382, 384, 0, 28, 0, 0, 381, + 28, 0, 7, 385, 382, 0, 28, 0, + 0, 381, 28, 0, 7, 386, 382, 0, + 28, 0, 0, 381, 28, 0, 7, 387, + 382, 0, 28, 0, 0, 381, 28, 0, + 7, 382, 388, 0, 28, 0, 0, 381, + 28, 0, 0, 389, 7, 382, 0, 28, + 0, 381, 390, 0, 391, 0, 392, 0, + 393, 393, 393, 0, 394, 0, 381, 0, + 19, 25, 30, 0, 25, 27, 29, 7, + 397, 6, 23, 28, 24, 5, 0, 5, + 30, 377, 825, 0, 7, 0, 27, 29, + 22, 9, 9, 0, 7, 8, 6, 23, + 28, 24, 5, 399, 5, 30, 377, 825, + 0, 7, 0, 27, 29, 7, 8, 6, + 23, 28, 24, 5, 0, 5, 825, 30, + 377, 825, 0, 7, 0, 27, 29, 63, + 7, 338, 371, 401, 23, 63, 23, 23, + 62, 63, 7, 402, 338, 371, 23, 63, + 23, 23, 62, 63, 7, 403, 338, 371, + 23, 63, 23, 23, 62, 7, 404, 23, + 7, 405, 23, 7, 406, 23, 407, 7, + 23, 408, 7, 23, 7, 409, 23, 410, + 7, 410, 410, 23, 7, 411, 23, 7, + 62, 23, 119, 121, 136, 118, 137, 135, + 413, 135, 414, 143, 417, 827, 120, 119, + 120, 414, 140, 142, 134, 28, 133, 414, + 143, 120, 134, 120, 414, 140, 142, 119, + 121, 136, 119, 118, 137, 413, 415, 414, + 143, 417, 827, 120, 119, 120, 135, 414, + 140, 142, 28, 416, 120, 119, 121, 136, + 119, 118, 137, 135, 139, 135, 138, 143, + 417, 827, 120, 119, 120, 138, 140, 142, + 119, 121, 136, 118, 141, 137, 135, 120, + 135, 143, 418, 417, 827, 120, 119, 120, + 140, 142, 119, 121, 136, 118, 141, 137, + 135, 120, 135, 143, 419, 417, 827, 120, + 119, 120, 140, 142, 119, 121, 136, 118, + 420, 137, 135, 120, 135, 143, 417, 827, + 120, 119, 120, 140, 142, 420, 141, 243, + 120, 119, 422, 120, 420, 120, 421, 141, + 28, 119, 422, 120, 141, 120, 120, 421, + 141, 28, 119, 422, 120, 141, 120, 120, + 423, 423, 423, 421, 141, 28, 119, 422, + 424, 120, 141, 120, 120, 421, 141, 28, + 119, 425, 422, 120, 141, 120, 120, 421, + 141, 28, 119, 426, 422, 120, 141, 120, + 120, 421, 141, 28, 119, 427, 422, 120, + 141, 120, 120, 421, 141, 28, 119, 422, + 428, 120, 141, 120, 120, 421, 141, 28, + 120, 429, 119, 422, 120, 141, 120, 421, + 430, 28, 120, 431, 28, 120, 28, 432, + 120, 433, 28, 433, 433, 120, 28, 434, + 120, 28, 421, 120, 28, 436, 138, 143, + 120, 138, 140, 142, 28, 829, 120, 28, + 436, 120, 439, 28, 120, 28, 440, 120, + 28, 829, 120, 119, 442, 136, 118, 141, + 137, 135, 120, 135, 143, 417, 827, 120, + 119, 120, 140, 142, 28, 440, 122, 122, + 120, 119, 121, 136, 118, 141, 137, 135, + 444, 135, 143, 417, 827, 120, 119, 120, + 140, 142, 119, 121, 136, 118, 141, 137, + 135, 120, 135, 827, 143, 417, 827, 120, + 119, 120, 140, 142, 282, 69, 119, 332, + 335, 446, 118, 282, 118, 118, 281, 282, + 69, 119, 447, 332, 335, 118, 282, 118, + 118, 281, 282, 69, 119, 448, 332, 335, + 118, 282, 118, 118, 281, 69, 119, 449, + 118, 69, 119, 450, 118, 69, 119, 451, + 118, 452, 69, 119, 118, 453, 69, 119, + 118, 69, 119, 454, 118, 455, 69, 119, + 455, 455, 118, 69, 119, 456, 118, 69, + 119, 281, 118, 458, 69, 119, 332, 457, + 335, 830, 118, 458, 118, 118, 281, 458, + 69, 119, 280, 118, 332, 457, 335, 830, + 118, 458, 118, 281, 282, 69, 119, 460, + 332, 335, 118, 282, 118, 281, 282, 69, + 119, 332, 830, 335, 118, 282, 118, 118, + 281, 282, 315, 69, 119, 332, 335, 118, + 282, 118, 118, 281, 463, 244, 218, 259, + 264, 242, 260, 258, 243, 258, 266, 464, + 832, 243, 463, 243, 263, 265, 463, 244, + 218, 259, 242, 260, 258, 262, 258, 261, + 266, 464, 832, 243, 463, 243, 261, 263, + 265, 242, 244, 218, 259, 264, 260, 258, + 243, 258, 266, 465, 464, 832, 243, 242, + 243, 263, 265, 242, 244, 218, 259, 264, + 260, 258, 243, 258, 266, 466, 464, 832, + 243, 242, 243, 263, 265, 242, 244, 218, + 259, 467, 260, 258, 243, 258, 266, 464, + 832, 243, 242, 243, 263, 265, 467, 264, + 264, 243, 242, 469, 243, 467, 243, 468, + 264, 194, 141, 243, 242, 469, 243, 264, + 243, 468, 264, 194, 141, 243, 242, 469, + 243, 264, 243, 470, 470, 470, 468, 264, + 194, 141, 243, 242, 469, 471, 243, 264, + 243, 468, 264, 194, 141, 243, 242, 472, + 469, 243, 264, 243, 468, 264, 194, 141, + 243, 242, 473, 469, 243, 264, 243, 468, + 264, 194, 141, 243, 242, 474, 469, 243, + 264, 243, 468, 264, 194, 141, 243, 242, + 469, 475, 243, 264, 243, 468, 264, 194, + 141, 476, 242, 469, 243, 264, 243, 468, + 477, 194, 141, 243, 478, 194, 141, 243, + 194, 141, 479, 243, 480, 194, 141, 480, + 480, 243, 194, 141, 481, 243, 194, 141, + 468, 243, 194, 141, 483, 261, 266, 243, + 261, 263, 265, 194, 141, 834, 243, 194, + 141, 483, 243, 486, 194, 141, 243, 194, + 141, 487, 243, 194, 141, 834, 243, 242, + 489, 218, 259, 264, 260, 258, 243, 258, + 266, 464, 832, 243, 242, 243, 263, 265, + 194, 141, 487, 245, 245, 243, 242, 244, + 218, 259, 264, 260, 258, 491, 258, 266, + 464, 832, 243, 242, 243, 263, 265, 242, + 244, 218, 259, 264, 260, 258, 243, 258, + 832, 266, 464, 832, 243, 242, 243, 263, + 265, 242, 244, 218, 242, 259, 264, 260, + 258, 493, 258, 266, 464, 495, 832, 243, + 242, 243, 263, 265, 194, 141, 494, 243, + 242, 244, 218, 242, 259, 260, 258, 262, + 258, 261, 266, 464, 832, 243, 242, 243, + 261, 263, 265, 242, 244, 218, 259, 264, + 260, 258, 243, 258, 496, 266, 464, 832, + 243, 242, 243, 263, 265, 242, 244, 218, + 242, 259, 264, 260, 497, 493, 258, 266, + 464, 832, 243, 242, 243, 263, 265, 258, + 218, 259, 260, 262, 498, 261, 266, 464, + 243, 258, 243, 261, 263, 265, 242, 244, + 218, 242, 259, 264, 260, 258, 493, 258, + 266, 464, 835, 243, 242, 243, 263, 265, + 500, 264, 194, 141, 242, 264, 243, 501, + 264, 194, 141, 242, 264, 243, 264, 194, + 141, 242, 502, 264, 243, 503, 194, 141, + 503, 503, 243, 194, 141, 504, 243, 194, + 141, 265, 243, 242, 244, 218, 259, 264, + 260, 258, 243, 258, 266, 464, 495, 832, + 243, 242, 243, 263, 265, 258, 218, 259, + 260, 507, 508, 266, 464, 243, 258, 243, + 508, 263, 265, 257, 194, 141, 256, 508, + 266, 243, 257, 243, 508, 263, 265, 242, + 244, 218, 242, 259, 260, 507, 493, 508, + 266, 464, 832, 243, 242, 243, 258, 508, + 263, 265, 257, 510, 574, 506, 509, 257, + 590, 590, 590, 256, 511, 28, 173, 512, + 545, 174, 511, 174, 174, 187, 511, 28, + 173, 189, 511, 174, 189, 172, 69, 190, + 513, 514, 196, 517, 174, 189, 174, 514, + 193, 195, 188, 28, 187, 514, 196, 174, + 188, 174, 514, 193, 195, 173, 175, 172, + 173, 69, 190, 513, 515, 514, 196, 517, + 836, 174, 173, 174, 189, 514, 193, 195, + 28, 516, 174, 173, 175, 172, 173, 69, + 190, 189, 192, 189, 191, 196, 517, 836, + 174, 173, 174, 191, 193, 195, 173, 175, + 172, 69, 194, 190, 189, 174, 189, 196, + 518, 517, 836, 174, 173, 174, 193, 195, + 173, 175, 172, 69, 194, 190, 189, 174, + 189, 196, 519, 517, 836, 174, 173, 174, + 193, 195, 173, 175, 172, 69, 520, 190, + 189, 174, 189, 196, 517, 836, 174, 173, + 174, 193, 195, 520, 243, 194, 174, 173, + 522, 174, 520, 174, 521, 194, 174, 28, + 174, 173, 522, 174, 194, 174, 521, 194, + 174, 28, 174, 173, 522, 174, 194, 174, + 523, 523, 523, 521, 194, 174, 28, 174, + 173, 522, 524, 174, 194, 174, 521, 194, + 174, 28, 174, 173, 525, 522, 174, 194, + 174, 521, 194, 174, 28, 174, 173, 526, + 522, 174, 194, 174, 521, 194, 174, 28, + 174, 173, 527, 522, 174, 194, 174, 521, + 194, 174, 28, 174, 173, 522, 528, 174, + 194, 174, 521, 194, 174, 28, 529, 173, + 522, 174, 194, 174, 521, 530, 28, 174, + 531, 28, 174, 28, 532, 174, 533, 28, + 533, 533, 174, 28, 534, 174, 28, 521, + 174, 28, 536, 191, 196, 174, 191, 193, + 195, 28, 838, 174, 28, 536, 174, 539, + 28, 174, 28, 540, 174, 28, 838, 174, + 173, 542, 172, 69, 194, 190, 189, 174, + 189, 196, 517, 836, 174, 173, 174, 193, + 195, 28, 540, 176, 176, 174, 173, 175, + 172, 69, 194, 190, 189, 544, 189, 196, + 517, 836, 174, 173, 174, 193, 195, 173, + 175, 172, 69, 194, 190, 189, 174, 189, + 836, 196, 517, 836, 174, 173, 174, 193, + 195, 188, 546, 512, 545, 188, 562, 562, + 562, 187, 547, 7, 548, 549, 0, 547, + 0, 0, 3, 547, 7, 5, 547, 0, + 5, 6, 23, 24, 373, 374, 30, 377, + 0, 5, 0, 374, 27, 29, 4, 548, + 549, 4, 550, 550, 550, 3, 4, 548, + 549, 551, 0, 4, 0, 0, 3, 4, + 552, 548, 549, 0, 4, 0, 0, 3, + 4, 553, 548, 549, 0, 4, 0, 0, + 3, 554, 0, 555, 0, 556, 0, 557, + 0, 558, 0, 559, 0, 560, 560, 560, + 0, 561, 0, 3, 0, 188, 28, 512, + 545, 563, 174, 188, 174, 174, 187, 188, + 28, 564, 512, 545, 174, 188, 174, 174, + 187, 188, 28, 565, 512, 545, 174, 188, + 174, 174, 187, 28, 566, 174, 28, 567, + 174, 28, 568, 174, 569, 28, 174, 570, + 28, 174, 28, 571, 174, 572, 28, 572, + 572, 174, 28, 573, 174, 28, 187, 174, + 575, 28, 119, 576, 577, 120, 575, 120, + 120, 133, 575, 28, 119, 135, 575, 120, + 135, 136, 118, 137, 413, 414, 143, 417, + 120, 135, 120, 414, 140, 142, 134, 546, + 576, 577, 134, 578, 578, 578, 133, 134, + 28, 576, 577, 579, 120, 134, 120, 120, + 133, 134, 28, 580, 576, 577, 120, 134, + 120, 120, 133, 134, 28, 581, 576, 577, + 120, 134, 120, 120, 133, 28, 582, 120, + 28, 583, 120, 28, 584, 120, 585, 28, + 120, 586, 28, 120, 28, 587, 120, 588, + 28, 588, 588, 120, 28, 589, 120, 28, + 133, 120, 257, 194, 141, 506, 509, 591, + 243, 257, 243, 243, 256, 257, 194, 141, + 592, 506, 509, 243, 257, 243, 243, 256, + 257, 194, 141, 593, 506, 509, 243, 257, + 243, 243, 256, 194, 141, 594, 243, 194, + 141, 595, 243, 194, 141, 596, 243, 597, + 194, 141, 243, 598, 194, 141, 243, 194, + 141, 599, 243, 600, 194, 141, 600, 600, + 243, 194, 141, 601, 243, 194, 141, 256, + 243, 603, 194, 141, 506, 602, 509, 839, + 243, 603, 243, 243, 256, 603, 194, 141, + 255, 243, 506, 602, 509, 839, 243, 603, + 243, 256, 257, 194, 141, 605, 506, 509, + 243, 257, 243, 256, 257, 194, 141, 506, + 839, 509, 243, 257, 243, 243, 256, 257, + 486, 194, 141, 506, 509, 243, 257, 243, + 243, 256, 173, 136, 608, 215, 221, 172, + 215, 217, 197, 173, 136, 843, 172, 173, + 136, 608, 172, 611, 173, 136, 172, 173, + 136, 612, 172, 173, 136, 843, 172, 198, + 614, 198, 93, 218, 214, 213, 172, 213, + 221, 224, 841, 172, 198, 172, 217, 197, + 173, 136, 612, 200, 200, 172, 198, 199, + 198, 93, 218, 214, 213, 616, 213, 221, + 224, 841, 172, 198, 172, 217, 197, 198, + 199, 198, 93, 218, 214, 213, 172, 213, + 841, 221, 224, 841, 172, 198, 172, 217, + 197, 198, 199, 198, 198, 93, 218, 214, + 213, 219, 213, 221, 224, 618, 841, 172, + 198, 172, 217, 197, 198, 199, 198, 93, + 218, 214, 213, 172, 213, 619, 221, 224, + 841, 172, 198, 172, 217, 197, 198, 199, + 198, 198, 93, 218, 214, 620, 219, 213, + 221, 224, 841, 172, 198, 172, 217, 197, + 213, 198, 93, 214, 216, 621, 215, 221, + 224, 172, 213, 172, 215, 217, 197, 198, + 199, 198, 198, 93, 218, 214, 213, 219, + 213, 221, 224, 844, 172, 198, 172, 217, + 197, 623, 218, 173, 136, 198, 218, 172, + 624, 218, 173, 136, 198, 218, 172, 218, + 173, 136, 198, 625, 218, 172, 626, 173, + 136, 626, 626, 172, 173, 136, 627, 172, + 173, 136, 197, 172, 198, 199, 198, 93, + 218, 214, 213, 172, 213, 221, 224, 618, + 841, 172, 198, 172, 217, 197, 213, 198, + 93, 214, 630, 631, 221, 224, 172, 213, + 172, 631, 217, 197, 212, 173, 136, 211, + 631, 221, 172, 212, 172, 631, 217, 197, + 198, 199, 198, 198, 93, 214, 630, 219, + 631, 221, 224, 841, 172, 198, 172, 213, + 631, 217, 197, 212, 633, 634, 629, 632, + 212, 662, 662, 662, 211, 173, 175, 172, + 69, 190, 189, 513, 189, 514, 196, 517, + 836, 174, 173, 174, 514, 193, 195, 635, + 7, 32, 636, 649, 6, 635, 6, 6, + 45, 635, 7, 32, 47, 635, 6, 47, + 32, 48, 146, 637, 638, 152, 154, 6, + 47, 6, 638, 149, 31, 46, 7, 45, + 638, 152, 6, 46, 6, 638, 149, 31, + 32, 33, 32, 32, 48, 146, 637, 150, + 638, 152, 154, 845, 6, 32, 6, 47, + 638, 149, 31, 7, 640, 147, 152, 6, + 147, 149, 31, 7, 847, 6, 7, 640, + 6, 643, 7, 6, 7, 644, 6, 7, + 847, 6, 32, 646, 32, 48, 136, 146, + 47, 6, 47, 152, 154, 845, 6, 32, + 6, 149, 31, 7, 644, 34, 34, 6, + 32, 33, 32, 48, 136, 146, 47, 648, + 47, 152, 154, 845, 6, 32, 6, 149, + 31, 32, 33, 32, 48, 136, 146, 47, + 6, 47, 845, 152, 154, 845, 6, 32, + 6, 149, 31, 46, 372, 636, 649, 46, + 650, 650, 650, 45, 46, 7, 636, 649, + 651, 6, 46, 6, 6, 45, 46, 7, + 652, 636, 649, 6, 46, 6, 6, 45, + 46, 7, 653, 636, 649, 6, 46, 6, + 6, 45, 7, 654, 6, 7, 655, 6, + 7, 656, 6, 657, 7, 6, 658, 7, + 6, 7, 659, 6, 660, 7, 660, 660, + 6, 7, 661, 6, 7, 45, 6, 212, + 173, 136, 629, 632, 663, 172, 212, 172, + 172, 211, 212, 173, 136, 664, 629, 632, + 172, 212, 172, 172, 211, 212, 173, 136, + 665, 629, 632, 172, 212, 172, 172, 211, + 173, 136, 666, 172, 173, 136, 667, 172, + 173, 136, 668, 172, 669, 173, 136, 172, + 670, 173, 136, 172, 173, 136, 671, 172, + 672, 173, 136, 672, 672, 172, 173, 136, + 673, 172, 173, 136, 211, 172, 675, 173, + 136, 629, 674, 632, 848, 172, 675, 172, + 172, 211, 675, 173, 136, 210, 172, 629, + 674, 632, 848, 172, 675, 172, 211, 212, + 173, 136, 677, 629, 632, 172, 212, 172, + 211, 212, 173, 136, 629, 848, 632, 172, + 212, 172, 172, 211, 212, 611, 173, 136, + 629, 632, 172, 212, 172, 172, 211, 680, + 50, 48, 49, 69, 49, 65, 64, 23, + 64, 71, 343, 822, 23, 680, 23, 68, + 70, 680, 50, 48, 49, 49, 65, 64, + 67, 64, 66, 71, 343, 822, 23, 680, + 23, 66, 68, 70, 682, 175, 172, 69, + 194, 173, 190, 189, 174, 189, 196, 517, + 836, 174, 682, 174, 193, 195, 682, 175, + 172, 69, 173, 190, 189, 192, 189, 191, + 196, 517, 836, 174, 682, 174, 191, 193, + 195, 173, 175, 172, 173, 69, 194, 190, + 189, 515, 189, 196, 517, 684, 836, 174, + 173, 174, 193, 195, 173, 175, 172, 69, + 194, 190, 189, 174, 189, 685, 196, 517, + 836, 174, 173, 174, 193, 195, 173, 175, + 172, 173, 69, 194, 190, 686, 515, 189, + 196, 517, 836, 174, 173, 174, 193, 195, + 189, 172, 69, 190, 192, 687, 191, 196, + 517, 174, 189, 174, 191, 193, 195, 173, + 175, 172, 173, 69, 194, 190, 189, 515, + 189, 196, 517, 850, 174, 173, 174, 193, + 195, 689, 194, 28, 173, 194, 174, 690, + 194, 28, 173, 194, 174, 194, 28, 173, + 691, 194, 174, 692, 28, 692, 692, 174, + 28, 693, 174, 28, 195, 174, 173, 175, + 172, 69, 194, 190, 189, 174, 189, 196, + 517, 684, 836, 174, 173, 174, 193, 195, + 696, 28, 512, 695, 545, 851, 174, 696, + 174, 174, 187, 696, 28, 186, 174, 512, + 695, 545, 851, 174, 696, 174, 187, 188, + 28, 698, 512, 545, 174, 188, 174, 187, + 188, 28, 512, 851, 545, 174, 188, 174, + 174, 187, 188, 539, 28, 512, 545, 174, + 188, 174, 174, 187, 32, 33, 32, 48, + 136, 146, 47, 6, 47, 701, 152, 154, + 845, 6, 32, 6, 149, 31, 32, 33, + 32, 32, 48, 136, 146, 702, 150, 47, + 152, 154, 845, 6, 32, 6, 149, 31, + 47, 32, 48, 146, 148, 703, 147, 152, + 154, 6, 47, 6, 147, 149, 31, 32, + 33, 32, 32, 48, 136, 146, 47, 150, + 47, 152, 154, 853, 6, 32, 6, 149, + 31, 705, 136, 7, 32, 136, 6, 706, + 136, 7, 32, 136, 6, 136, 7, 32, + 707, 136, 6, 708, 7, 708, 708, 6, + 7, 709, 6, 7, 31, 6, 32, 33, + 32, 48, 136, 146, 47, 6, 47, 152, + 154, 700, 845, 6, 32, 6, 149, 31, + 712, 121, 136, 118, 141, 119, 137, 135, + 120, 135, 143, 417, 827, 120, 712, 120, + 140, 142, 712, 121, 136, 118, 119, 137, + 135, 139, 135, 138, 143, 417, 827, 120, + 712, 120, 138, 140, 142, 119, 121, 136, + 119, 118, 141, 137, 135, 415, 135, 143, + 417, 714, 827, 120, 119, 120, 140, 142, + 119, 121, 136, 118, 141, 137, 135, 120, + 135, 715, 143, 417, 827, 120, 119, 120, + 140, 142, 119, 121, 136, 119, 118, 141, + 137, 716, 415, 135, 143, 417, 827, 120, + 119, 120, 140, 142, 135, 136, 118, 137, + 139, 717, 138, 143, 417, 120, 135, 120, + 138, 140, 142, 119, 121, 136, 119, 118, + 141, 137, 135, 415, 135, 143, 417, 854, + 120, 119, 120, 140, 142, 719, 141, 28, + 119, 141, 120, 720, 141, 28, 119, 141, + 120, 141, 28, 119, 721, 141, 120, 722, + 28, 722, 722, 120, 28, 723, 120, 28, + 142, 120, 119, 121, 136, 118, 141, 137, + 135, 120, 135, 143, 417, 714, 827, 120, + 119, 120, 140, 142, 726, 28, 576, 725, + 577, 855, 120, 726, 120, 120, 133, 726, + 28, 132, 120, 576, 725, 577, 855, 120, + 726, 120, 133, 134, 28, 728, 576, 577, + 120, 134, 120, 133, 134, 28, 576, 855, + 577, 120, 134, 120, 120, 133, 134, 439, + 28, 576, 577, 120, 134, 120, 120, 133, + 49, 32, 731, 90, 96, 48, 90, 92, + 72, 49, 32, 859, 48, 49, 32, 731, + 48, 734, 49, 32, 48, 49, 32, 735, + 48, 49, 32, 859, 48, 73, 737, 73, + 73, 93, 89, 88, 48, 88, 96, 99, + 857, 48, 73, 48, 92, 72, 49, 32, + 735, 75, 75, 48, 73, 74, 73, 73, + 93, 89, 88, 739, 88, 96, 99, 857, + 48, 73, 48, 92, 72, 73, 74, 73, + 73, 93, 89, 88, 48, 88, 857, 96, + 99, 857, 48, 73, 48, 92, 72, 73, + 74, 73, 73, 73, 93, 89, 88, 94, + 88, 96, 99, 741, 857, 48, 73, 48, + 92, 72, 73, 74, 73, 73, 93, 89, + 88, 48, 88, 742, 96, 99, 857, 48, + 73, 48, 92, 72, 73, 74, 73, 73, + 73, 93, 89, 743, 94, 88, 96, 99, + 857, 48, 73, 48, 92, 72, 88, 73, + 73, 89, 91, 744, 90, 96, 99, 48, + 88, 48, 90, 92, 72, 73, 74, 73, + 73, 73, 93, 89, 88, 94, 88, 96, + 99, 860, 48, 73, 48, 92, 72, 746, + 93, 49, 32, 73, 93, 48, 747, 93, + 49, 32, 73, 93, 48, 93, 49, 32, + 73, 748, 93, 48, 749, 49, 32, 749, + 749, 48, 49, 32, 750, 48, 49, 32, + 72, 48, 73, 74, 73, 73, 93, 89, + 88, 48, 88, 96, 99, 741, 857, 48, + 73, 48, 92, 72, 88, 73, 73, 89, + 753, 754, 96, 99, 48, 88, 48, 754, + 92, 72, 87, 49, 32, 86, 754, 96, + 48, 87, 48, 754, 92, 72, 73, 74, + 73, 73, 73, 89, 753, 94, 754, 96, + 99, 857, 48, 73, 48, 88, 754, 92, + 72, 87, 756, 757, 752, 755, 87, 758, + 758, 758, 86, 49, 50, 48, 49, 65, + 64, 339, 64, 340, 71, 343, 822, 23, + 49, 23, 340, 68, 70, 32, 33, 32, + 48, 146, 47, 637, 47, 638, 152, 154, + 845, 6, 32, 6, 638, 149, 31, 87, + 49, 32, 752, 755, 759, 48, 87, 48, + 48, 86, 87, 49, 32, 760, 752, 755, + 48, 87, 48, 48, 86, 87, 49, 32, + 761, 752, 755, 48, 87, 48, 48, 86, + 49, 32, 762, 48, 49, 32, 763, 48, + 49, 32, 764, 48, 765, 49, 32, 48, + 766, 49, 32, 48, 49, 32, 767, 48, + 768, 49, 32, 768, 768, 48, 49, 32, + 769, 48, 49, 32, 86, 48, 771, 49, + 32, 752, 770, 755, 861, 48, 771, 48, + 48, 86, 771, 49, 32, 85, 48, 752, + 770, 755, 861, 48, 771, 48, 86, 87, + 49, 32, 773, 752, 755, 48, 87, 48, + 86, 87, 49, 32, 752, 861, 755, 48, + 87, 48, 48, 86, 87, 734, 49, 32, + 752, 755, 48, 87, 48, 48, 86, 49, + 50, 48, 49, 49, 69, 65, 64, 341, + 64, 71, 343, 776, 822, 23, 49, 23, + 68, 70, 49, 50, 48, 49, 69, 65, + 64, 23, 64, 777, 71, 343, 822, 23, + 49, 23, 68, 70, 49, 50, 48, 49, + 49, 69, 65, 778, 341, 64, 71, 343, + 822, 23, 49, 23, 68, 70, 64, 48, + 49, 65, 67, 779, 66, 71, 343, 23, + 64, 23, 66, 68, 70, 49, 50, 48, + 49, 49, 69, 65, 64, 341, 64, 71, + 343, 863, 23, 49, 23, 68, 70, 781, + 69, 7, 49, 69, 23, 782, 69, 7, + 49, 69, 23, 69, 7, 49, 783, 69, + 23, 784, 7, 784, 784, 23, 7, 785, + 23, 7, 70, 23, 49, 50, 48, 49, + 69, 65, 64, 23, 64, 71, 343, 776, + 822, 23, 49, 23, 68, 70, 788, 7, + 338, 787, 371, 864, 23, 788, 23, 23, + 62, 788, 7, 61, 23, 338, 787, 371, + 864, 23, 788, 23, 62, 63, 7, 790, + 338, 371, 23, 63, 23, 62, 63, 7, + 338, 864, 371, 23, 63, 23, 23, 62, + 63, 365, 7, 338, 371, 23, 63, 23, + 23, 62, 793, 7, 636, 792, 649, 866, + 6, 793, 6, 6, 45, 793, 7, 44, + 6, 636, 792, 649, 866, 6, 793, 6, + 45, 46, 7, 795, 636, 649, 6, 46, + 6, 45, 46, 7, 636, 866, 649, 6, + 46, 6, 6, 45, 46, 643, 7, 636, + 649, 6, 46, 6, 6, 45, 798, 8, + 6, 23, 28, 7, 24, 5, 0, 5, + 30, 377, 825, 0, 798, 0, 27, 29, + 798, 8, 6, 23, 7, 24, 5, 26, + 5, 25, 30, 377, 825, 0, 798, 0, + 25, 27, 29, 7, 8, 6, 7, 23, + 28, 24, 5, 375, 5, 30, 377, 800, + 825, 0, 7, 0, 27, 29, 7, 8, + 6, 23, 28, 24, 5, 0, 5, 801, + 30, 377, 825, 0, 7, 0, 27, 29, + 7, 8, 6, 7, 23, 28, 24, 802, + 375, 5, 30, 377, 825, 0, 7, 0, + 27, 29, 5, 6, 23, 24, 26, 803, + 25, 30, 377, 0, 5, 0, 25, 27, + 29, 7, 8, 6, 7, 23, 28, 24, + 5, 375, 5, 30, 377, 868, 0, 7, + 0, 27, 29, 805, 28, 7, 28, 0, + 806, 28, 7, 28, 0, 28, 7, 807, + 28, 0, 808, 808, 808, 0, 809, 0, + 29, 0, 7, 8, 6, 23, 28, 24, + 5, 0, 5, 30, 377, 800, 825, 0, + 7, 0, 27, 29, 812, 548, 811, 549, + 869, 0, 812, 0, 0, 3, 812, 2, + 0, 548, 811, 549, 869, 0, 812, 0, + 3, 4, 814, 548, 549, 0, 4, 0, + 3, 4, 548, 869, 549, 0, 4, 0, + 0, 3, 4, 21, 548, 549, 0, 4, + 0, 0, 3, 1, 0, 817, 18, 20, + 1, 817, 0, 819, 269, 93, 117, 259, + 284, 283, 319, 283, 317, 289, 293, 818, + 118, 819, 118, 287, 288, 819, 269, 93, + 117, 284, 283, 311, 283, 285, 317, 289, + 293, 818, 118, 819, 118, 285, 287, 288, + 820, 69, 119, 313, 314, 279, 820, 118, + 819, 269, 93, 117, 325, 284, 283, 319, + 283, 317, 289, 293, 818, 118, 819, 118, + 287, 288, 823, 50, 48, 49, 69, 65, + 64, 369, 64, 367, 71, 343, 822, 23, + 823, 23, 68, 70, 823, 50, 48, 49, + 65, 64, 361, 64, 66, 367, 71, 343, + 822, 23, 823, 23, 66, 68, 70, 824, + 7, 363, 364, 60, 824, 23, 826, 8, + 6, 23, 28, 24, 5, 398, 5, 396, + 30, 377, 825, 0, 826, 0, 27, 29, + 826, 8, 6, 23, 24, 5, 395, 5, + 25, 396, 30, 377, 825, 0, 826, 0, + 25, 27, 29, 828, 121, 136, 118, 141, + 137, 135, 443, 135, 441, 143, 417, 827, + 120, 828, 120, 140, 142, 828, 121, 136, + 118, 137, 135, 435, 135, 138, 441, 143, + 417, 827, 120, 828, 120, 138, 140, 142, + 829, 28, 437, 438, 131, 829, 120, 831, + 69, 119, 459, 332, 461, 335, 457, 118, + 831, 118, 281, 831, 69, 119, 313, 283, + 314, 279, 831, 118, 833, 244, 218, 259, + 264, 260, 258, 490, 258, 488, 266, 464, + 832, 243, 833, 243, 263, 265, 833, 244, + 218, 259, 260, 258, 482, 258, 261, 488, + 266, 464, 832, 243, 833, 243, 261, 263, + 265, 834, 194, 141, 484, 485, 254, 834, + 243, 833, 244, 218, 259, 499, 260, 258, + 490, 258, 488, 266, 464, 832, 243, 833, + 243, 263, 265, 837, 175, 172, 69, 194, + 190, 189, 543, 189, 541, 196, 517, 836, + 174, 837, 174, 193, 195, 837, 175, 172, + 69, 190, 189, 535, 189, 191, 541, 196, + 517, 836, 174, 837, 174, 191, 193, 195, + 838, 28, 537, 538, 185, 838, 174, 840, + 194, 141, 604, 506, 606, 509, 602, 243, + 840, 243, 256, 840, 194, 141, 484, 258, + 485, 254, 840, 243, 842, 199, 198, 93, + 218, 214, 213, 615, 213, 613, 221, 224, + 841, 172, 842, 172, 217, 197, 842, 199, + 198, 93, 214, 213, 607, 213, 215, 613, + 221, 224, 841, 172, 842, 172, 215, 217, + 197, 843, 173, 136, 609, 610, 209, 843, + 172, 842, 199, 198, 93, 622, 214, 213, + 615, 213, 613, 221, 224, 841, 172, 842, + 172, 217, 197, 846, 33, 32, 48, 136, + 146, 47, 647, 47, 645, 152, 154, 845, + 6, 846, 6, 149, 31, 846, 33, 32, + 48, 146, 47, 639, 47, 147, 645, 152, + 154, 845, 6, 846, 6, 147, 149, 31, + 847, 7, 641, 642, 43, 847, 6, 849, + 173, 136, 676, 629, 678, 632, 674, 172, + 849, 172, 211, 849, 173, 136, 609, 213, + 610, 209, 849, 172, 837, 175, 172, 69, + 688, 190, 189, 543, 189, 541, 196, 517, + 836, 174, 837, 174, 193, 195, 852, 28, + 697, 512, 699, 545, 695, 174, 852, 174, + 187, 852, 28, 537, 189, 538, 185, 852, + 174, 846, 33, 32, 48, 704, 146, 47, + 647, 47, 645, 152, 154, 845, 6, 846, + 6, 149, 31, 828, 121, 136, 118, 718, + 137, 135, 443, 135, 441, 143, 417, 827, + 120, 828, 120, 140, 142, 856, 28, 727, + 576, 729, 577, 725, 120, 856, 120, 133, + 856, 28, 437, 135, 438, 131, 856, 120, + 858, 74, 73, 73, 93, 89, 88, 738, + 88, 736, 96, 99, 857, 48, 858, 48, + 92, 72, 858, 74, 73, 73, 89, 88, + 730, 88, 90, 736, 96, 99, 857, 48, + 858, 48, 90, 92, 72, 859, 49, 32, + 732, 733, 84, 859, 48, 858, 74, 73, + 73, 745, 89, 88, 738, 88, 736, 96, + 99, 857, 48, 858, 48, 92, 72, 862, + 49, 32, 772, 752, 774, 755, 770, 48, + 862, 48, 86, 862, 49, 32, 732, 88, + 733, 84, 862, 48, 823, 50, 48, 49, + 780, 65, 64, 369, 64, 367, 71, 343, + 822, 23, 823, 23, 68, 70, 865, 7, + 789, 338, 791, 371, 787, 23, 865, 23, + 62, 865, 7, 363, 64, 364, 60, 865, + 23, 867, 7, 794, 636, 796, 649, 792, + 6, 867, 6, 45, 867, 7, 641, 47, + 642, 43, 867, 6, 826, 8, 6, 23, + 804, 24, 5, 398, 5, 396, 30, 377, + 825, 0, 826, 0, 27, 29, 870, 813, + 548, 815, 549, 811, 0, 870, 0, 3, + 870, 18, 5, 20, 1, 870, 0, 0 +}; + +const int selector_start = 816; +const int selector_first_final = 816; +const int selector_error = 0; + +const int selector_en_main = 816; + + +/* #line 58 "Parser.rl" */ + + #endregion + } +} diff --git a/Source/External/ExCSS/ParserX.cs b/Source/External/ExCSS/ParserX.cs new file mode 100644 index 0000000000000000000000000000000000000000..91f57f0341c62648ee8d530d126c20f74e38ba4b --- /dev/null +++ b/Source/External/ExCSS/ParserX.cs @@ -0,0 +1,1425 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Threading.Tasks; + +namespace ExCSS +{ + public sealed class CssParser + { + CssSelectorConstructor selector; + Stack function; + Boolean skipExceptions; + Lexer tokenizer; + Boolean fraction; + CSSProperty property; + CSSValue value; + List mvalues; + CSSValueList cvalues; + Boolean started; + Boolean quirks; + CSSStyleSheet sheet; + Stack open; + StringBuilder buffer; + CssState state; + Object sync; + Task task; + + #region ctor + + + /// + /// Creates a new CSS parser instance parser with the specified stylesheet + /// based on the given source manager. + /// + /// The stylesheet to be constructed. + /// The source to use. + internal CssParser(StylesheetReader reader) + { + selector = Pool.NewSelectorConstructor(); + sync = new Object(); + skipExceptions = true; + tokenizer = new Lexer(reader); + + started = false; + function = new Stack(); + sheet = stylesheet; + open = new Stack(); + SwitchTo(CssState.Data); + } + + #endregion + + #region Properties + + /// + /// Gets if the parser has been started asynchronously. + /// + public Boolean IsAsync + { + get { return task != null; } + } + + /// + /// Gets or sets if the quirks-mode is activated. + /// + public Boolean IsQuirksMode + { + get { return quirks; } + set { quirks = value; } + } + + /// + /// Gets the current rule if any. + /// + internal CSSRule CurrentRule + { + get { return open.Count > 0 ? open.Peek() : null; } + } + + #endregion + + #region Methods + + /// + /// Parses the given source asynchronously and creates the stylesheet. + /// + /// The task which could be awaited or continued differently. + public Task ParseAsync() + { + lock (sync) + { + if (!started) + { + started = true; + task = Task.Run(() => Kernel()); + } + else if (task == null) + throw new InvalidOperationException("The parser has already run synchronously."); + + return task; + } + } + + /// + /// Parses the given source code. + /// + public void Parse() + { + var run = false; + + lock (sync) + { + if (!started) + { + started = true; + run = true; + } + } + + if (run) + { + Kernel(); + } + } + + #endregion + + #region States + + /// + /// The general state. + /// + /// The current token. + /// The status. + Boolean Data(CssToken token) + { + if (token.Type == CssTokenType.AtKeyword) + { + switch (((CssKeywordToken)token).Data) + { + case RuleNames.MEDIA: + { + AddRule(new CSSMediaRule()); + SwitchTo(CssState.InMediaList); + break; + } + case RuleNames.PAGE: + { + AddRule(new CSSPageRule()); + SwitchTo(CssState.InSelector); + break; + } + case RuleNames.IMPORT: + { + AddRule(new CSSImportRule()); + SwitchTo(CssState.BeforeImport); + break; + } + case RuleNames.FONT_FACE: + { + AddRule(new CSSFontFaceRule()); + SwitchTo(CssState.InDeclaration); + break; + } + case RuleNames.CHARSET: + { + AddRule(new CSSCharsetRule()); + SwitchTo(CssState.BeforeCharset); + break; + } + case RuleNames.NAMESPACE: + { + AddRule(new CSSNamespaceRule()); + SwitchTo(CssState.BeforeNamespacePrefix); + break; + } + case RuleNames.SUPPORTS: + { + buffer = Pool.NewStringBuilder(); + AddRule(new CSSSupportsRule()); + SwitchTo(CssState.InCondition); + break; + } + case RuleNames.KEYFRAMES: + { + AddRule(new CSSKeyframesRule()); + SwitchTo(CssState.BeforeKeyframesName); + break; + } + case RuleNames.DOCUMENT: + { + AddRule(new CSSDocumentRule()); + SwitchTo(CssState.BeforeDocumentFunction); + break; + } + default: + { + buffer = Pool.NewStringBuilder(); + AddRule(new CSSUnknownRule()); + SwitchTo(CssState.InUnknown); + InUnknown(token); + break; + } + } + + return true; + } + else if (token.Type == CssTokenType.CurlyBracketClose) + { + return CloseRule(); + } + else + { + AddRule(new CSSStyleRule()); + SwitchTo(CssState.InSelector); + InSelector(token); + return true; + } + } + + /// + /// State that is called once in the head of an unknown @ rule. + /// + /// The current token. + /// The status. + Boolean InUnknown(CssToken token) + { + switch (token.Type) + { + case CssTokenType.Semicolon: + CurrentRuleAs().SetInstruction(buffer.ToPool()); + SwitchTo(CssState.Data); + return CloseRule(); + case CssTokenType.CurlyBracketOpen: + CurrentRuleAs().SetCondition(buffer.ToPool()); + SwitchTo(CssState.Data); + break; + default: + buffer.Append(token.ToValue()); + break; + } + + return true; + } + + /// + /// State that is called once we are in a CSS selector. + /// + /// The current token. + /// The status. + Boolean InSelector(CssToken token) + { + if (token.Type == CssTokenType.CurlyBracketOpen) + { + var rule = CurrentRule as ICssSelector; + + if (rule != null) + rule.Selector = selector.Result; + + SwitchTo(CurrentRule is CSSStyleRule ? CssState.InDeclaration : CssState.Data); + } + else if (token.Type == CssTokenType.CurlyBracketClose) + return false; + else + selector.Apply(token); + + return true; + } + + /// + /// Called before the property name has been detected. + /// + /// The current token. + /// The status. + Boolean InDeclaration(CssToken token) + { + if (token.Type == CssTokenType.CurlyBracketClose) + { + CloseProperty(); + SwitchTo(CurrentRule is CSSKeyframeRule ? CssState.KeyframesData : CssState.Data); + return CloseRule(); + } + else if (token.Type == CssTokenType.Ident) + { + AddDeclaration(CSSProperty.Create(((CssKeywordToken)token).Data)); + SwitchTo(CssState.AfterProperty); + return true; + } + + return false; + } + + /// + /// After instruction rules a semicolon is required. + /// + /// The current token. + /// The status. + Boolean AfterInstruction(CssToken token) + { + if (token.Type == CssTokenType.Semicolon) + { + SwitchTo(CssState.Data); + return CloseRule(); + } + + return false; + } + + /// + /// In the condition text of a supports rule. + /// + /// The current token. + /// The status. + Boolean InCondition(CssToken token) + { + switch (token.Type) + { + case CssTokenType.CurlyBracketOpen: + CurrentRuleAs().ConditionText = buffer.ToPool(); + SwitchTo(CssState.Data); + break; + default: + buffer.Append(token.ToValue()); + break; + } + + return true; + } + + /// + /// Called before a prefix has been found for the namespace rule. + /// + /// The current token. + /// The status. + Boolean BeforePrefix(CssToken token) + { + if (token.Type == CssTokenType.Ident) + { + CurrentRuleAs().Prefix = ((CssKeywordToken)token).Data; + SwitchTo(CssState.AfterNamespacePrefix); + return true; + } + + SwitchTo(CssState.AfterInstruction); + return AfterInstruction(token); + } + + /// + /// Called before a namespace has been found for the namespace rule. + /// + /// The current token. + /// The status. + Boolean BeforeNamespace(CssToken token) + { + SwitchTo(CssState.AfterInstruction); + + if (token.Type == CssTokenType.String) + { + CurrentRuleAs().NamespaceURI = ((CssStringToken)token).Data; + return true; + } + + return AfterInstruction(token); + } + + /// + /// Before a charset string has been found. + /// + /// The current token. + /// The status. + Boolean BeforeCharset(CssToken token) + { + SwitchTo(CssState.AfterInstruction); + + if (token.Type == CssTokenType.String) + { + CurrentRuleAs().Encoding = ((CssStringToken)token).Data; + return true; + } + + return AfterInstruction(token); + } + + /// + /// Before an URL has been found for the import rule. + /// + /// The current token. + /// The status. + Boolean BeforeImport(CssToken token) + { + if (token.Type == CssTokenType.String || token.Type == CssTokenType.Url) + { + CurrentRuleAs().Href = ((CssStringToken)token).Data; + SwitchTo(CssState.InMediaList); + return true; + } + + SwitchTo(CssState.AfterInstruction); + return false; + } + + /// + /// Called before the property separating colon has been seen. + /// + /// The current token. + /// The status. + Boolean AfterProperty(CssToken token) + { + if (token.Type == CssTokenType.Colon) + { + fraction = false; + SwitchTo(CssState.BeforeValue); + return true; + } + else if (token.Type == CssTokenType.Semicolon || token.Type == CssTokenType.CurlyBracketClose) + AfterValue(token); + + return false; + } + + /// + /// Called before any token in the value regime had been seen. + /// + /// The current token. + /// The status. + Boolean BeforeValue(CssToken token) + { + if (token.Type == CssTokenType.Semicolon) + SwitchTo(CssState.InDeclaration); + else if (token.Type == CssTokenType.CurlyBracketClose) + InDeclaration(token); + else + { + SwitchTo(CssState.InSingleValue); + return InSingleValue(token); + } + + return false; + } + + /// + /// Called when a value has to be computed. + /// + /// The current token. + /// The status. + Boolean InSingleValue(CssToken token) + { + switch (token.Type) + { + case CssTokenType.Dimension: // e.g. "3px" + return AddValue(new CSSPrimitiveValue(((CssUnitToken)token).Unit, ((CssUnitToken)token).Data)); + case CssTokenType.Hash:// e.g. "#ABCDEF" + return InSingleValueHexColor(((CssKeywordToken)token).Data); + case CssTokenType.Delim:// e.g. "#" + return InSingleValueDelim((CssDelimToken)token); + case CssTokenType.Ident: // e.g. "auto" + return InSingleValueIdent((CssKeywordToken)token); + case CssTokenType.String:// e.g. "'i am a string'" + return AddValue(new CSSPrimitiveValue(CssUnit.String, ((CssStringToken)token).Data)); + case CssTokenType.Url:// e.g. "url('this is a valid URL')" + return AddValue(new CSSPrimitiveValue(CssUnit.Uri, ((CssStringToken)token).Data)); + case CssTokenType.Percentage: // e.g. "5%" + return AddValue(new CSSPrimitiveValue(CssUnit.Percentage, ((CssUnitToken)token).Data)); + case CssTokenType.Number: // e.g. "173" + return AddValue(new CSSPrimitiveValue(CssUnit.Number, ((CssNumberToken)token).Data)); + case CssTokenType.Whitespace: // e.g. " " + SwitchTo(CssState.InValueList); + return true; + case CssTokenType.Function: //e.g. rgba(...) + function.Push(new FunctionBuffer(((CssKeywordToken)token).Data)); + SwitchTo(CssState.InFunction); + return true; + case CssTokenType.Comma: // e.g. "," + SwitchTo(CssState.InValuePool); + return true; + case CssTokenType.Semicolon: // e.g. ";" + case CssTokenType.CurlyBracketClose: // e.g. "}" + return AfterValue(token); + default: + return false; + } + } + + /// + /// Gathers a value inside a function. + /// + /// The current token. + /// The status. + Boolean InValueFunction(CssToken token) + { + switch (token.Type) + { + case CssTokenType.RoundBracketClose: + SwitchTo(CssState.InSingleValue); + return AddValue(function.Pop().Done()); + case CssTokenType.Comma: + function.Peek().Include(); + return true; + default: + return InSingleValue(token); + } + } + + /// + /// Called when a new value is seen from the zero-POV (whitespace seen previously). + /// + /// The current token. + /// The status. + Boolean InValueList(CssToken token) + { + if (token.Type == CssTokenType.Semicolon || token.Type == CssTokenType.CurlyBracketClose) + AfterValue(token); + else if (token.Type == CssTokenType.Comma) + SwitchTo(CssState.InValuePool); + else + { + //TDO + SwitchTo(CssState.InSingleValue); + return InSingleValue(token); + } + + return true; + } + + /// + /// Called when a new value is seen from the zero-POV (comma seen previously). + /// + /// The current token. + /// The status. + Boolean InValuePool(CssToken token) + { + if (token.Type == CssTokenType.Semicolon || token.Type == CssTokenType.CurlyBracketClose) + AfterValue(token); + else + { + //TODO + SwitchTo(CssState.InSingleValue); + return InSingleValue(token); + } + + return false; + } + + /// + /// Called if a # sign has been found. + /// + /// The current token. + /// The status. + Boolean InHexValue(CssToken token) + { + switch (token.Type) + { + case CssTokenType.Number: + case CssTokenType.Dimension: + case CssTokenType.Ident: + var rest = token.ToValue(); + + if (buffer.Length + rest.Length <= 6) + { + buffer.Append(rest); + return true; + } + + break; + } + + var s = buffer.ToPool(); + InSingleValueHexColor(buffer.ToString()); + SwitchTo(CssState.InSingleValue); + return InSingleValue(token); + } + + /// + /// Called after the value is known to be over. + /// + /// The current token. + /// The status. + Boolean AfterValue(CssToken token) + { + if (token.Type == CssTokenType.Semicolon) + { + CloseProperty(); + SwitchTo(CssState.InDeclaration); + return true; + } + else if (token.Type == CssTokenType.CurlyBracketClose) + return InDeclaration(token); + + return false; + } + + /// + /// Called once an important instruction is expected. + /// + /// The current token. + /// The status. + Boolean ValueImportant(CssToken token) + { + if (token.Type == CssTokenType.Ident && ((CssKeywordToken)token).Data == "important") + { + SwitchTo(CssState.AfterValue); + property.Important = true; + return true; + } + + return AfterValue(token); + } + + /// + /// Before the name of an @keyframes rule has been detected. + /// + /// The current token. + /// The status. + Boolean BeforeKeyframesName(CssToken token) + { + SwitchTo(CssState.BeforeKeyframesData); + + if (token.Type == CssTokenType.Ident) + { + CurrentRuleAs().Name = ((CssKeywordToken)token).Data; + return true; + } + else if (token.Type == CssTokenType.CurlyBracketOpen) + { + SwitchTo(CssState.KeyframesData); + } + + return false; + } + + /// + /// Before the curly bracket of an @keyframes rule has been seen. + /// + /// The current token. + /// The status. + Boolean BeforeKeyframesData(CssToken token) + { + if (token.Type == CssTokenType.CurlyBracketOpen) + { + SwitchTo(CssState.BeforeKeyframesData); + return true; + } + + return false; + } + + /// + /// Called in the @keyframes rule. + /// + /// The current token. + /// The status. + Boolean KeyframesData(CssToken token) + { + if (token.Type == CssTokenType.CurlyBracketClose) + { + SwitchTo(CssState.Data); + return CloseRule(); + } + else + { + buffer = Pool.NewStringBuilder(); + return InKeyframeText(token); + } + } + + /// + /// Called in the text for a frame in the @keyframes rule. + /// + /// The current token. + /// The status. + Boolean InKeyframeText(CssToken token) + { + if (token.Type == CssTokenType.CurlyBracketOpen) + { + var frame = new CSSKeyframeRule(); + frame.KeyText = buffer.ToPool(); + AddRule(frame); + SwitchTo(CssState.InDeclaration); + return true; + } + else if (token.Type == CssTokenType.CurlyBracketClose) + { + buffer.ToPool(); + KeyframesData(token); + return false; + } + + buffer.Append(token.ToValue()); + return true; + } + + /// + /// Called before a document function has been found. + /// + /// The current token. + /// The status. + Boolean BeforeDocumentFunction(CssToken token) + { + switch (token.Type) + { + case CssTokenType.Url: + CurrentRuleAs().Conditions.Add(Tuple.Create(CSSDocumentRule.DocumentFunction.Url, ((CssStringToken)token).Data)); + break; + case CssTokenType.UrlPrefix: + CurrentRuleAs().Conditions.Add(Tuple.Create(CSSDocumentRule.DocumentFunction.UrlPrefix, ((CssStringToken)token).Data)); + break; + case CssTokenType.Domain: + CurrentRuleAs().Conditions.Add(Tuple.Create(CSSDocumentRule.DocumentFunction.Domain, ((CssStringToken)token).Data)); + break; + case CssTokenType.Function: + if (String.Compare(((CssKeywordToken)token).Data, "regexp", StringComparison.OrdinalIgnoreCase) == 0) + { + SwitchTo(CssState.InDocumentFunction); + return true; + } + SwitchTo(CssState.AfterDocumentFunction); + return false; + default: + SwitchTo(CssState.Data); + return false; + } + + SwitchTo(CssState.BetweenDocumentFunctions); + return true; + } + + /// + /// Called before the argument of a document function has been found. + /// + /// The current token. + /// The status. + Boolean InDocumentFunction(CssToken token) + { + SwitchTo(CssState.AfterDocumentFunction); + + if (token.Type == CssTokenType.String) + { + CurrentRuleAs().Conditions.Add(Tuple.Create(CSSDocumentRule.DocumentFunction.RegExp, ((CssStringToken)token).Data)); + return true; + } + + return false; + } + + /// + /// Called after the arguments of a document function has been found. + /// + /// The current token. + /// The status. + Boolean AfterDocumentFunction(CssToken token) + { + SwitchTo(CssState.BetweenDocumentFunctions); + return token.Type == CssTokenType.RoundBracketClose; + } + + /// + /// Called after a function has been completed. + /// + /// The current token. + /// The status. + Boolean BetweenDocumentFunctions(CssToken token) + { + if (token.Type == CssTokenType.Comma) + { + SwitchTo(CssState.BeforeDocumentFunction); + return true; + } + else if (token.Type == CssTokenType.CurlyBracketOpen) + { + SwitchTo(CssState.Data); + return true; + } + + SwitchTo(CssState.Data); + return false; + } + + /// + /// Before any medium has been found for the @media or @import rule. + /// + /// The current token. + /// The status. + Boolean InMediaList(CssToken token) + { + if (token.Type == CssTokenType.Semicolon) + { + CloseRule(); + SwitchTo(CssState.Data); + return true; + } + + buffer = Pool.NewStringBuilder(); + SwitchTo(CssState.InMediaValue); + return InMediaValue(token); + } + + /// + /// Scans the current medium for the @media or @import rule. + /// + /// The current token. + /// The status. + Boolean InMediaValue(CssToken token) + { + switch (token.Type) + { + case CssTokenType.CurlyBracketOpen: + case CssTokenType.Semicolon: + { + var container = CurrentRule as ICssMedia; + var s = buffer.ToPool(); + + if (container != null) + container.Media.AppendMedium(s); + + if (CurrentRule is CSSImportRule) + return AfterInstruction(token); + + SwitchTo(CssState.Data); + return token.Type == CssTokenType.CurlyBracketClose; + } + case CssTokenType.Comma: + { + var container = CurrentRule as ICssMedia; + + if (container != null) + container.Media.AppendMedium(buffer.ToString()); + + buffer.Clear(); + return true; + } + case CssTokenType.Whitespace: + { + buffer.Append(' '); + return true; + } + default: + { + buffer.Append(token.ToValue()); + return true; + } + } + } + + #endregion + + #region Substates + + /// + /// Called in a value - a delimiter has been found. + /// + /// The current delim token. + /// The status. + Boolean InSingleValueDelim(CssDelimToken token) + { + switch (token.Data) + { + case Specification.EM: + SwitchTo(CssState.ValueImportant); + return true; + case Specification.NUM: + buffer = Pool.NewStringBuilder(); + SwitchTo(CssState.InHexValue); + return true; + case Specification.SOLIDUS: + fraction = true; + return true; + default: + return false; + } + } + + /// + /// Called in a value - an identifier has been found. + /// + /// The current keyword token. + /// The status. + Boolean InSingleValueIdent(CssKeywordToken token) + { + if (token.Data == "inherit") + { + property.Value = CSSValue.Inherit; + SwitchTo(CssState.AfterValue); + return true; + } + + return AddValue(new CSSPrimitiveValue(CssUnit.Ident, token.Data)); + } + + /// + /// Called in a value - a hash (probably hex) value has been found. + /// + /// The value of the token. + /// The status. + Boolean InSingleValueHexColor(String color) + { + CSSColor value; + + if (CSSColor.TryFromHex(color, out value)) + return AddValue(new CSSPrimitiveValue(value)); + + return false; + } + + #endregion + + #region Rule management + + /// + /// Adds the new value to the current value (or replaces it). + /// + /// The value to add. + /// The status. + Boolean AddValue(CSSValue value) + { + if (fraction) + { + if (this.value != null) + { + value = new CSSPrimitiveValue(CssUnit.Unknown, this.value.ToCss() + "/" + value.ToCss()); + this.value = null; + } + + fraction = false; + } + + if (function.Count > 0) + function.Peek().Arguments.Add(value); + else if (this.value == null) + this.value = value; + else + return false; + + return true; + } + + /// + /// Closes a property. + /// + void CloseProperty() + { + if (property != null) + property.Value = value; + + value = null; + property = null; + } + + /// + /// Closes the current rule (if any). + /// + /// The status. + Boolean CloseRule() + { + if (open.Count > 0) + { + open.Pop(); + return true; + } + + return false; + } + + /// + /// Adds a new rule. + /// + /// The new rule. + void AddRule(CSSRule rule) + { + rule.ParentStyleSheet = sheet; + + if (open.Count > 0) + { + var container = open.Peek() as ICssRules; + + if (container != null) + { + container.CssRules.List.Add(rule); + rule.ParentRule = open.Peek(); + } + } + else + sheet.CssRules.List.Add(rule); + + open.Push(rule); + } + + /// + /// Adds a declaration. + /// + /// The new property. + void AddDeclaration(CSSProperty property) + { + this.property = property; + var rule = CurrentRule as IStyleDeclaration; + + if (rule != null) + rule.Style.List.Add(property); + } + + #endregion + + #region Helpers + + /// + /// Gets the current rule casted to the given type. + /// + T CurrentRuleAs() + where T : CSSRule + { + if (open.Count > 0) + return open.Peek() as T; + + return default(T); + } + + /// + /// Switches the current state to the given one. + /// + /// The state to switch to. + void SwitchTo(CssState newState) + { + switch (newState) + { + case CssState.InSelector: + tokenizer.IgnoreComments = true; + tokenizer.IgnoreWhitespace = false; + selector.Reset(); + selector.IgnoreErrors = skipExceptions; + break; + + case CssState.InHexValue: + case CssState.InUnknown: + case CssState.InCondition: + case CssState.InSingleValue: + case CssState.InMediaValue: + tokenizer.IgnoreComments = true; + tokenizer.IgnoreWhitespace = false; + break; + + default: + tokenizer.IgnoreComments = true; + tokenizer.IgnoreWhitespace = true; + break; + } + + state = newState; + } + + /// + /// The kernel that is pulling the tokens into the parser. + /// + void Kernel() + { + var tokens = tokenizer.Tokens; + + foreach (var token in tokens) + { + if (General(token) == false) + RaiseErrorOccurred(ErrorCode.InputUnexpected); + } + + if (property != null) + General(CssSpecialCharacter.Semicolon); + + selector.ToPool(); + } + + /// + /// Examines the token by using the current state. + /// + /// The current token. + /// The status. + Boolean General(CssToken token) + { + switch (state) + { + case CssState.Data: + return Data(token); + case CssState.InSelector: + return InSelector(token); + case CssState.InDeclaration: + return InDeclaration(token); + case CssState.AfterProperty: + return AfterProperty(token); + case CssState.BeforeValue: + return BeforeValue(token); + case CssState.InValuePool: + return InValuePool(token); + case CssState.InValueList: + return InValueList(token); + case CssState.InSingleValue: + return InSingleValue(token); + case CssState.ValueImportant: + return ValueImportant(token); + case CssState.AfterValue: + return AfterValue(token); + case CssState.InMediaList: + return InMediaList(token); + case CssState.InMediaValue: + return InMediaValue(token); + case CssState.BeforeImport: + return BeforeImport(token); + case CssState.AfterInstruction: + return AfterInstruction(token); + case CssState.BeforeCharset: + return BeforeCharset(token); + case CssState.BeforeNamespacePrefix: + return BeforePrefix(token); + case CssState.AfterNamespacePrefix: + return BeforeNamespace(token); + case CssState.InCondition: + return InCondition(token); + case CssState.InUnknown: + return InUnknown(token); + case CssState.InKeyframeText: + return InKeyframeText(token); + case CssState.BeforeDocumentFunction: + return BeforeDocumentFunction(token); + case CssState.InDocumentFunction: + return InDocumentFunction(token); + case CssState.AfterDocumentFunction: + return AfterDocumentFunction(token); + case CssState.BetweenDocumentFunctions: + return BetweenDocumentFunctions(token); + case CssState.BeforeKeyframesName: + return BeforeKeyframesName(token); + case CssState.BeforeKeyframesData: + return BeforeKeyframesData(token); + case CssState.KeyframesData: + return KeyframesData(token); + case CssState.InHexValue: + return InHexValue(token); + case CssState.InFunction: + return InValueFunction(token); + default: + return false; + } + } + + #endregion + + #region Public static methods + + /// + /// Takes a string and transforms it into a selector object. + /// + /// The string to parse. + /// The Selector object. + public static Selector ParseSelector(String selector) + { + var tokenizer = new CssTokenizer(new SourceManager(selector)); + var tokens = tokenizer.Tokens; + var selctor = Pool.NewSelectorConstructor(); + + foreach (var token in tokens) + selctor.Apply(token); + + var result = selctor.Result; + selctor.ToPool(); + return result; + } + + /// + /// Takes a string and transforms it into a CSS stylesheet. + /// + /// The string to parse. + /// Optional: The status of the quirks mode flag (usually not set). + /// The CSSStyleSheet object. + public static CSSStyleSheet ParseStyleSheet(String stylesheet, Boolean quirksMode = false) + { + var parser = new CssParser(stylesheet); + parser.IsQuirksMode = quirksMode; + return parser.Result; + } + + /// + /// Takes a string and transforms it into a CSS rule. + /// + /// The string to parse. + /// Optional: The status of the quirks mode flag (usually not set). + /// The CSSRule object. + public static CSSRule ParseRule(String rule, Boolean quirksMode = false) + { + var parser = new CssParser(rule); + parser.skipExceptions = false; + parser.IsQuirksMode = quirksMode; + parser.Parse(); + + if (parser.sheet.CssRules.Length > 0) + return parser.sheet.CssRules[0]; + + return null; + } + + /// + /// Takes a string and transforms it into CSS declarations. + /// + /// The string to parse. + /// Optional: The status of the quirks mode flag (usually not set). + /// The CSSStyleDeclaration object. + public static CSSStyleDeclaration ParseDeclarations(String declarations, Boolean quirksMode = false) + { + var decl = new CSSStyleDeclaration(); + AppendDeclarations(decl, declarations, quirksMode); + return decl; + } + + /// + /// Takes a string and transforms it into a CSS declaration (CSS property). + /// + /// The string to parse. + /// Optional: The status of the quirks mode flag (usually not set). + /// The CSSProperty object. + public static CSSProperty ParseDeclaration(String declarations, Boolean quirksMode = false) + { + var parser = new CssParser(declarations); + parser.state = CssState.InDeclaration; + parser.IsQuirksMode = quirksMode; + parser.skipExceptions = false; + parser.Parse(); + return parser.property; + } + + /// + /// Takes a string and transforms it into a CSS value. + /// + /// The string to parse. + /// Optional: The status of the quirks mode flag (usually not set). + /// The CSSValue object. + public static CSSValue ParseValue(String source, Boolean quirksMode = false) + { + var parser = new CssParser(source); + var property = new CSSProperty(String.Empty); + parser.property = property; + parser.IsQuirksMode = quirksMode; + parser.skipExceptions = false; + parser.state = CssState.BeforeValue; + parser.Parse(); + return property.Value; + } + + #endregion + + #region Internal static methods + + /// + /// Takes a string and transforms it into a list of CSS values. + /// + /// The string to parse. + /// Optional: The status of the quirks mode flag (usually not set). + /// The CSSValueList object. + internal static CSSValueList ParseValueList(String source, Boolean quirksMode = false) + { + var parser = new CssParser(source); + var list = new CSSValueList(); + var property = new CSSProperty(String.Empty); + property.Value = list; + parser.property = property; + parser.IsQuirksMode = quirksMode; + parser.skipExceptions = false; + parser.state = CssState.InValueList; + parser.Parse(); + return list; + } + + /// + /// Takes a comma separated string and transforms it into a list of CSS values. + /// + /// The string to parse. + /// Optional: The status of the quirks mode flag (usually not set). + /// The CSSValueList object. + internal static CSSValuePool ParseMultipleValues(String source, Boolean quirksMode = false) + { + var parser = new CssParser(source); + var pool = new CSSValuePool(); + var property = new CSSProperty(String.Empty); + property.Value = pool; + parser.property = property; + parser.IsQuirksMode = quirksMode; + parser.skipExceptions = false; + parser.state = CssState.InValuePool; + parser.Parse(); + return pool; + } + + /// + /// Takes a string and transforms it into a CSS keyframe rule. + /// + /// The string to parse. + /// Optional: The status of the quirks mode flag (usually not set). + /// The CSSKeyframeRule object. + internal static CSSKeyframeRule ParseKeyframeRule(String rule, Boolean quirksMode = false) + { + var parser = new CssParser(rule); + var keyframe = new CSSKeyframeRule(); + parser.AddRule(keyframe); + parser.IsQuirksMode = quirksMode; + parser.skipExceptions = false; + parser.state = CssState.InKeyframeText; + parser.Parse(); + return keyframe; + } + + /// + /// Takes a string and appends all rules to the given list of properties. + /// + /// The list of css properties to append to. + /// The string to parse. + /// Optional: The status of the quirks mode flag (usually not set). + internal static void AppendDeclarations(CSSStyleDeclaration list, String declarations, Boolean quirksMode = false) + { + var parser = new CssParser(declarations); + parser.IsQuirksMode = quirksMode; + parser.skipExceptions = false; + + if (list.ParentRule != null) + parser.AddRule(list.ParentRule); + else + parser.AddRule(new CSSStyleRule(list)); + + parser.state = CssState.InDeclaration; + parser.Parse(); + } + + #endregion + + #region State Enumeration + + /// + /// The enumeration with possible state values. + /// + enum CssState + { + Data, + InSelector, + InDeclaration, + AfterProperty, + BeforeValue, + InValuePool, + InValueList, + InSingleValue, + InMediaList, + InMediaValue, + BeforeImport, + BeforeCharset, + BeforeNamespacePrefix, + AfterNamespacePrefix, + AfterInstruction, + InCondition, + BeforeKeyframesName, + BeforeKeyframesData, + KeyframesData, + InKeyframeText, + BeforeDocumentFunction, + InDocumentFunction, + AfterDocumentFunction, + BetweenDocumentFunctions, + InUnknown, + ValueImportant, + AfterValue, + InHexValue, + InFunction + } + + /// + /// A buffer for functions. + /// + class FunctionBuffer + { + #region Members + + String name; + List arguments; + CSSValue value; + + #endregion + + #region ctor + + internal FunctionBuffer(String name) + { + this.arguments = new List(); + this.name = name; + } + + #endregion + + #region Properties + + public List Arguments + { + get { return arguments; } + } + + public CSSValue Value + { + get { return value; } + set { this.value = value; } + } + + #endregion + + #region Methods + + public void Include() + { + if (value != null) + arguments.Add(value); + + value = null; + } + + public CSSValue Done() + { + Include(); + return CSSFunction.Create(name, arguments); + } + + #endregion + } + + #endregion + } +} diff --git a/Source/External/ExCSS/StyleSheet.cs b/Source/External/ExCSS/StyleSheet.cs new file mode 100644 index 0000000000000000000000000000000000000000..6be25e459d6ec7034524e0d5ba2fe437b3a276ca --- /dev/null +++ b/Source/External/ExCSS/StyleSheet.cs @@ -0,0 +1,146 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ExCSS.Model.Extensions; + +// ReSharper disable once CheckNamespace +namespace ExCSS +{ + public sealed class StyleSheet + { + private readonly List _rules; + + public StyleSheet() + { + _rules = new List(); + Errors = new List(); + } + + public List Rules + { + get { return _rules; } + } + + public StyleSheet RemoveRule(int index) + { + if (index >= 0 && index < _rules.Count) + { + _rules.RemoveAt(index); + } + + return this; + } + + public StyleSheet InsertRule(string rule, int index) + { + if (index < 0 || index > _rules.Count) + { + return this; + } + + var value = Parser.ParseRule(rule); + _rules.Insert(index, value); + + return this; + } + + public IList StyleRules + { + get + { + return Rules.Where(r => r is StyleRule).Cast().ToList(); + } + } + + public IList CharsetDirectives + { + get + { + return GetDirectives(RuleType.Charset); + } + } + + public IList ImportDirectives + { + get + { + return GetDirectives(RuleType.Import); + } + } + + public IList FontFaceDirectives + { + get + { + return GetDirectives(RuleType.FontFace); + } + } + + public IList KeyframeDirectives + { + get + { + return GetDirectives(RuleType.Keyframes); + } + } + + public IList MediaDirectives + { + get + { + return GetDirectives(RuleType.Media); + + } + } + + public IList PageDirectives + { + get + { + return GetDirectives(RuleType.Page); + + } + } + + public IList SupportsDirectives + { + get + { + return GetDirectives(RuleType.Supports); + } + } + + public IList NamespaceDirectives + { + get + { + return GetDirectives(RuleType.Namespace); + } + } + + private IList GetDirectives(RuleType ruleType) + { + return Rules.Where(r => r.RuleType == ruleType).Cast().ToList(); + } + + public List Errors { get; private set; } + + public override string ToString() + { + return ToString(false); + } + + public string ToString(bool friendlyFormat, int indentation = 0) + { + var builder = new StringBuilder(); + + foreach (var rule in _rules) + { + builder.Append(rule.ToString(friendlyFormat, indentation).TrimStart() + (friendlyFormat ? Environment.NewLine : "")); + } + + return builder.TrimFirstLine().TrimLastLine().ToString(); + } + } +} diff --git a/Source/External/ExCSS/StylesheetParseError.cs b/Source/External/ExCSS/StylesheetParseError.cs new file mode 100644 index 0000000000000000000000000000000000000000..090629c5fda57c46545dad0943cfa5fec54dd90c --- /dev/null +++ b/Source/External/ExCSS/StylesheetParseError.cs @@ -0,0 +1,27 @@ + +namespace ExCSS +{ + public sealed class StylesheetParseError + { + public StylesheetParseError(ParserError error, string errorMessage, int line, int column) + { + ParserError = error; + Message = errorMessage; + Line = line; + Column = column; + } + + public ParserError ParserError { get; set; } + + public int Line{get;set;} + + public int Column{get;set;} + + public string Message{get;private set;} + + public override string ToString() + { + return string.Format("Line {0}, Column {1}: {2}.", Line, Column, Message); + } + } +} \ No newline at end of file diff --git a/Source/External/ExCSS/StylesheetReader.cs b/Source/External/ExCSS/StylesheetReader.cs new file mode 100644 index 0000000000000000000000000000000000000000..0446822b718849f66e883018711aa09198d95c35 --- /dev/null +++ b/Source/External/ExCSS/StylesheetReader.cs @@ -0,0 +1,186 @@ +using System.Collections.Generic; +using System.IO; +using System.Text; +using ExCSS.Model; + +namespace ExCSS +{ + internal class StylesheetReader + { + private int _insertion; + private readonly Stack _collengths; + private TextReader _reader; + private readonly StringBuilder _buffer; + private bool _lineWithReturn; + + StylesheetReader() + { + _buffer = new StringBuilder(); + _collengths = new Stack(); + Column = 1; + Line = 1; + } + + internal StylesheetReader(string styleText) : this() + { + _reader = new StringReader(styleText); + ReadCurrent(); + } + + internal StylesheetReader(Stream styleStream) : this() + { + _reader = new StreamReader(styleStream, true); + ReadCurrent(); + } + + internal bool IsBeginning + { + get { return _insertion < 2; } + } + + internal int Line { get; private set; } + + internal int Column { get; private set; } + + internal bool IsEnded { get; private set; } + + internal bool IsEnding + { + get { return Current == Specification.EndOfFile; } + } + + internal char Current { get; private set; } + + internal char Next + { + get + { + Advance(); + + return Current; + } + } + + internal char Previous + { + get + { + Back(); + + return Current; + } + } + + internal void Advance() + { + if (!IsEnding) + { + AdvanceUnsafe(); + } + else if (!IsEnded) + { + IsEnded = true; + } + } + + internal void Advance(int positions) + { + while (positions-- > 0 && !IsEnding) + { + AdvanceUnsafe(); + } + } + + internal void Back() + { + IsEnded = false; + + if (!IsBeginning) + { + BackUnsafe(); + } + } + + internal void Back(int positions) + { + IsEnded = false; + + while (positions-- > 0 && !IsBeginning) + { + BackUnsafe(); + } + } + + private void ReadCurrent() + { + if (_insertion < _buffer.Length) + { + Current = _buffer[_insertion]; + _insertion++; + return; + } + + var nextPosition = _reader.Read(); + Current = nextPosition == -1 ? Specification.EndOfFile : (char)nextPosition; + + if (Current == Specification.CarriageReturn) + { + Current = Specification.LineFeed; + _lineWithReturn = true; + } + else if (_lineWithReturn) + { + _lineWithReturn = false; + + if (Current == Specification.LineFeed) + { + ReadCurrent(); + return; + } + } + + _buffer.Append(Current); + _insertion++; + } + + private void AdvanceUnsafe() + { + if (Current.IsLineBreak()) + { + _collengths.Push(Column); + Column = 1; + Line++; + } + else + { + Column++; + } + + ReadCurrent(); + } + + private void BackUnsafe() + { + _insertion--; + + if (_insertion == 0) + { + Column = 0; + Current = Specification.Null; + return; + } + + Current = _buffer[_insertion - 1]; + + if (Current.IsLineBreak()) + { + Column = _collengths.Count != 0 ? _collengths.Pop() : 1; + Line--; + } + else + { + Column--; + } + } + } +} \ No newline at end of file diff --git a/Source/External/Fizzler/Either.cs b/Source/External/Fizzler/Either.cs new file mode 100644 index 0000000000000000000000000000000000000000..23725636ad3d48343690aab706d1892187c80df7 --- /dev/null +++ b/Source/External/Fizzler/Either.cs @@ -0,0 +1,136 @@ +// +// Copyright (c) 2008 Novell, Inc. (http://www.novell.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace Fizzler +{ + #region Imports + + using System; + using System.Collections.Generic; + + #endregion + + // Adapted from Mono Rocks + + internal abstract class Either + : IEquatable> + { + private Either() {} + + public static Either A(TA value) + { + if (value == null) throw new ArgumentNullException("value"); + return new AImpl(value); + } + + public static Either B(TB value) + { + if (value == null) throw new ArgumentNullException("value"); + return new BImpl(value); + } + + public override abstract bool Equals(object obj); + public abstract bool Equals(Either obj); + public override abstract int GetHashCode(); + public override abstract string ToString(); + public abstract TResult Fold(Func a, Func b); + + private sealed class AImpl : Either + { + private readonly TA _value; + + public AImpl(TA value) + { + _value = value; + } + + public override int GetHashCode() + { + return _value.GetHashCode(); + } + + public override bool Equals(object obj) + { + return Equals(obj as AImpl); + } + + public override bool Equals(Either obj) + { + var a = obj as AImpl; + return a != null + && EqualityComparer.Default.Equals(_value, a._value); + } + + public override TResult Fold(Func a, Func b) + { + if (a == null) throw new ArgumentNullException("a"); + if (b == null) throw new ArgumentNullException("b"); + return a(_value); + } + + public override string ToString() + { + return _value.ToString(); + } + } + + private sealed class BImpl : Either + { + private readonly TB _value; + + public BImpl(TB value) + { + _value = value; + } + + public override int GetHashCode() + { + return _value.GetHashCode(); + } + + public override bool Equals(object obj) + { + return Equals(obj as BImpl); + } + + public override bool Equals(Either obj) + { + var b = obj as BImpl; + return b != null + && EqualityComparer.Default.Equals(_value, b._value); + } + + public override TResult Fold(Func a, Func b) + { + if (a == null) throw new ArgumentNullException("a"); + if (b == null) throw new ArgumentNullException("b"); + return b(_value); + } + + public override string ToString() + { + return _value.ToString(); + } + } + } +} \ No newline at end of file diff --git a/Source/External/Fizzler/HumanReadableSelectorGenerator.cs b/Source/External/Fizzler/HumanReadableSelectorGenerator.cs new file mode 100644 index 0000000000000000000000000000000000000000..8070c0f79bf34a1dc2c3b7af51a5219f61e24cfc --- /dev/null +++ b/Source/External/Fizzler/HumanReadableSelectorGenerator.cs @@ -0,0 +1,256 @@ +#region Copyright and License +// +// Fizzler - CSS Selector Engine for Microsoft .NET Framework +// Copyright (c) 2009 Atif Aziz, Colin Ramsay. All rights reserved. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3 of the License, or (at your option) +// any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#endregion + +namespace Fizzler +{ + using System; + + /// + /// An implementation that generates + /// human-readable description of the selector. + /// + public class HumanReadableSelectorGenerator : ISelectorGenerator + { + private int _chainCount; + + /// + /// Initializes the text. + /// + public virtual void OnInit() + { + Text = null; + } + + /// + /// Gets the generated human-readable description text. + /// + public string Text { get; private set; } + + /// + /// Generates human-readable for a selector in a group. + /// + public virtual void OnSelector() + { + if (string.IsNullOrEmpty(Text)) + Text = "Take all"; + else + Text += " and select them. Combined with previous, take all"; + } + + /// + /// Concludes the text. + /// + public virtual void OnClose() + { + Text = Text.Trim(); + Text += " and select them."; + } + + /// + /// Adds to the generated human-readable text. + /// + protected void Add(string selector) + { + if (selector == null) throw new ArgumentNullException("selector"); + Text += selector; + } + + /// + /// Generates human-readable text of this type selector. + /// + public void Type(NamespacePrefix prefix, string type) + { + Add(string.Format(" <{0}> elements", type)); + } + + /// + /// Generates human-readable text of this universal selector. + /// + public void Universal(NamespacePrefix prefix) + { + Add(" elements"); + } + + /// + /// Generates human-readable text of this ID selector. + /// + public void Id(string id) + { + Add(string.Format(" with an ID of '{0}'", id)); + } + + /// + /// Generates human-readable text of this class selector. + /// + void ISelectorGenerator.Class(string clazz) + { + Add(string.Format(" with a class of '{0}'", clazz)); + } + + /// + /// Generates human-readable text of this attribute selector. + /// + public void AttributeExists(NamespacePrefix prefix, string name) + { + Add(string.Format(" which have attribute {0} defined", name)); + } + + /// + /// Generates human-readable text of this attribute selector. + /// + public void AttributeExact(NamespacePrefix prefix, string name, string value) + { + Add(string.Format(" which have attribute {0} with a value of '{1}'", name, value)); + } + + /// + /// Generates human-readable text of this attribute selector. + /// + public void AttributeIncludes(NamespacePrefix prefix, string name, string value) + { + Add(string.Format(" which have attribute {0} that includes the word '{1}'", name, value)); + } + + /// + /// Generates human-readable text of this attribute selector. + /// + public void AttributeDashMatch(NamespacePrefix prefix, string name, string value) + { + Add(string.Format(" which have attribute {0} with a hyphen separated value matching '{1}'", name, value)); + } + + /// + /// Generates human-readable text of this attribute selector. + /// + public void AttributePrefixMatch(NamespacePrefix prefix, string name, string value) + { + Add(string.Format(" which have attribute {0} whose value begins with '{1}'", name, value)); + } + + /// + /// Generates human-readable text of this attribute selector. + /// + public void AttributeSuffixMatch(NamespacePrefix prefix, string name, string value) + { + Add(string.Format(" which have attribute {0} whose value ends with '{1}'", name, value)); + } + + /// + /// Generates human-readable text of this attribute selector. + /// + public void AttributeSubstring(NamespacePrefix prefix, string name, string value) + { + Add(string.Format(" which have attribute {0} whose value contains '{1}'", name, value)); + } + + /// + /// Generates human-readable text of this pseudo-class selector. + /// + public void FirstChild() + { + Add(" which are the first child of their parent"); + } + + /// + /// Generates human-readable text of this pseudo-class selector. + /// + public void LastChild() + { + Add(" which are the last child of their parent"); + } + + /// + /// Generates human-readable text of this pseudo-class selector. + /// + public void NthChild(int a, int b) + { + Add(string.Format(" where the element has {0}n+{1}-1 sibling before it", a, b)); + } + + /// + /// Generates human-readable text of this pseudo-class selector. + /// + public void OnlyChild() + { + Add(" where the element is the only child"); + } + + /// + /// Generates human-readable text of this pseudo-class selector. + /// + public void Empty() + { + Add(" where the element is empty"); + } + + /// + /// Generates human-readable text of this combinator. + /// + public void Child() + { + Add(", then take their immediate children which are"); + } + + /// + /// Generates human-readable text of this combinator. + /// + public void Descendant() + { + if (_chainCount > 0) + { + Add(". With those, take only their descendants which are"); + } + else + { + Add(", then take their descendants which are"); + _chainCount++; + } + } + + /// + /// Generates human-readable text of this combinator. + /// + public void Adjacent() + { + Add(", then take their immediate siblings which are"); + } + + /// + /// Generates a combinator, + /// which separates two sequences of simple selectors. The elements represented + /// by the two sequences share the same parent in the document tree and the + /// element represented by the first sequence precedes (not necessarily + /// immediately) the element represented by the second one. + /// + public void GeneralSibling() + { + Add(", then take their siblings which are"); + } + + /// + /// Generates human-readable text of this combinator. + /// + public void NthLastChild(int a, int b) + { + Add(string.Format(" where the element has {0}n+{1}-1 sibling after it", a, b)); + } + } +} \ No newline at end of file diff --git a/Source/External/Fizzler/IElementOps.cs b/Source/External/Fizzler/IElementOps.cs new file mode 100644 index 0000000000000000000000000000000000000000..e33fb48242cf376b6cf50f2698eefbebb968e64b --- /dev/null +++ b/Source/External/Fizzler/IElementOps.cs @@ -0,0 +1,190 @@ +#region Copyright and License +// +// Fizzler - CSS Selector Engine for Microsoft .NET Framework +// Copyright (c) 2009 Atif Aziz, Colin Ramsay. All rights reserved. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3 of the License, or (at your option) +// any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#endregion + +namespace Fizzler +{ + /// + /// Represents a selectors implementation for an arbitrary document/node system. + /// + public interface IElementOps + { + // + // Selectors + // + + /// + /// Generates a type selector, + /// which represents an instance of the element type in the document tree. + /// + Selector Type(NamespacePrefix prefix, string name); + + /// + /// Generates a universal selector, + /// any single element in the document tree in any namespace + /// (including those without a namespace) if no default namespace + /// has been specified for selectors. + /// + Selector Universal(NamespacePrefix prefix); + + /// + /// Generates a ID selector, + /// which represents an element instance that has an identifier that + /// matches the identifier in the ID selector. + /// + Selector Id(string id); + + /// + /// Generates a class selector, + /// which is an alternative when + /// representing the class attribute. + /// + Selector Class(string clazz); + + // + // Attribute selectors + // + + /// + /// Generates an attribute selector + /// that represents an element with the given attribute + /// whatever the values of the attribute. + /// + Selector AttributeExists(NamespacePrefix prefix, string name); + + /// + /// Generates an attribute selector + /// that represents an element with the given attribute + /// and whose value is exactly . + /// + Selector AttributeExact(NamespacePrefix prefix, string name, string value); + + /// + /// Generates an attribute selector + /// that represents an element with the given attribute + /// and whose value is a whitespace-separated list of words, one of + /// which is exactly . + /// + Selector AttributeIncludes(NamespacePrefix prefix, string name, string value); + + /// + /// Generates an attribute selector + /// that represents an element with the given attribute , + /// its value either being exactly or beginning + /// with immediately followed by "-" (U+002D). + /// + Selector AttributeDashMatch(NamespacePrefix prefix, string name, string value); + + /// + /// Generates an attribute selector + /// that represents an element with the attribute + /// whose value begins with the prefix . + /// + Selector AttributePrefixMatch(NamespacePrefix prefix, string name, string value); + + /// + /// Generates an attribute selector + /// that represents an element with the attribute + /// whose value ends with the suffix . + /// + Selector AttributeSuffixMatch(NamespacePrefix prefix, string name, string value); + + /// + /// Generates an attribute selector + /// that represents an element with the attribute + /// whose value contains at least one instance of the substring . + /// + Selector AttributeSubstring(NamespacePrefix prefix, string name, string value); + + // + // Pseudo-class selectors + // + + /// + /// Generates a pseudo-class selector, + /// which represents an element that is the first child of some other element. + /// + Selector FirstChild(); + + /// + /// Generates a pseudo-class selector, + /// which represents an element that is the last child of some other element. + /// + Selector LastChild(); + + /// + /// Generates a pseudo-class selector, + /// which represents an element that is the N-th child of some other element. + /// + Selector NthChild(int a, int b); + + /// + /// Generates a pseudo-class selector, + /// which represents an element that has a parent element and whose parent + /// element has no other element children. + /// + Selector OnlyChild(); + + /// + /// Generates a pseudo-class selector, + /// which represents an element that has no children at all. + /// + Selector Empty(); + + // + // Combinators + // + + /// + /// Generates a combinator, + /// which represents a childhood relationship between two elements. + /// + Selector Child(); + + /// + /// Generates a combinator, + /// which represents a relationship between two elements where one element is an + /// arbitrary descendant of some ancestor element. + /// + Selector Descendant(); + + /// + /// Generates a combinator, + /// which represents elements that share the same parent in the document tree and + /// where the first element immediately precedes the second element. + /// + Selector Adjacent(); + + /// + /// Generates a combinator, + /// which separates two sequences of simple selectors. The elements represented + /// by the two sequences share the same parent in the document tree and the + /// element represented by the first sequence precedes (not necessarily + /// immediately) the element represented by the second one. + /// + Selector GeneralSibling(); + + /// + /// Generates a pseudo-class selector, + /// which represents an element that is the N-th child from bottom up of some other element. + /// + Selector NthLastChild(int a, int b); + } +} \ No newline at end of file diff --git a/Source/External/Fizzler/ISelectorGenerator.cs b/Source/External/Fizzler/ISelectorGenerator.cs new file mode 100644 index 0000000000000000000000000000000000000000..6d1b18354bee24b8c84043e81ac65c8c7a93a9b7 --- /dev/null +++ b/Source/External/Fizzler/ISelectorGenerator.cs @@ -0,0 +1,206 @@ +#region Copyright and License +// +// Fizzler - CSS Selector Engine for Microsoft .NET Framework +// Copyright (c) 2009 Atif Aziz, Colin Ramsay. All rights reserved. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3 of the License, or (at your option) +// any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#endregion + +namespace Fizzler +{ + /// + /// Represent an implementation that is responsible for generating + /// an implementation for a selector. + /// + public interface ISelectorGenerator + { + /// + /// Delimits the initialization of a generation. + /// + void OnInit(); + + /// + /// Delimits the closing/conclusion of a generation. + /// + void OnClose(); + + /// + /// Delimits a selector generation in a group of selectors. + /// + void OnSelector(); + + // + // Selectors + // + + /// + /// Generates a type selector, + /// which represents an instance of the element type in the document tree. + /// + void Type(NamespacePrefix prefix, string name); + + /// + /// Generates a universal selector, + /// any single element in the document tree in any namespace + /// (including those without a namespace) if no default namespace + /// has been specified for selectors. + /// + void Universal(NamespacePrefix prefix); + + /// + /// Generates a ID selector, + /// which represents an element instance that has an identifier that + /// matches the identifier in the ID selector. + /// + void Id(string id); + + /// + /// Generates a class selector, + /// which is an alternative when + /// representing the class attribute. + /// + void Class(string clazz); + + // + // Attribute selectors + // + + /// + /// Generates an attribute selector + /// that represents an element with the given attribute + /// whatever the values of the attribute. + /// + void AttributeExists(NamespacePrefix prefix, string name); + + /// + /// Generates an attribute selector + /// that represents an element with the given attribute + /// and whose value is exactly . + /// + void AttributeExact(NamespacePrefix prefix, string name, string value); + + /// + /// Generates an attribute selector + /// that represents an element with the given attribute + /// and whose value is a whitespace-separated list of words, one of + /// which is exactly . + /// + void AttributeIncludes(NamespacePrefix prefix, string name, string value); + + /// + /// Generates an attribute selector + /// that represents an element with the given attribute , + /// its value either being exactly or beginning + /// with immediately followed by "-" (U+002D). + /// + void AttributeDashMatch(NamespacePrefix prefix, string name, string value); + + /// + /// Generates an attribute selector + /// that represents an element with the attribute + /// whose value begins with the prefix . + /// + void AttributePrefixMatch(NamespacePrefix prefix, string name, string value); + + /// + /// Generates an attribute selector + /// that represents an element with the attribute + /// whose value ends with the suffix . + /// + void AttributeSuffixMatch(NamespacePrefix prefix, string name, string value); + + /// + /// Generates an attribute selector + /// that represents an element with the attribute + /// whose value contains at least one instance of the substring . + /// + void AttributeSubstring(NamespacePrefix prefix, string name, string value); + + // + // Pseudo-class selectors + // + + /// + /// Generates a pseudo-class selector, + /// which represents an element that is the first child of some other element. + /// + void FirstChild(); + + /// + /// Generates a pseudo-class selector, + /// which represents an element that is the last child of some other element. + /// + void LastChild(); + + /// + /// Generates a pseudo-class selector, + /// which represents an element that is the N-th child of some other element. + /// + void NthChild(int a, int b); + + /// + /// Generates a pseudo-class selector, + /// which represents an element that has a parent element and whose parent + /// element has no other element children. + /// + void OnlyChild(); + + /// + /// Generates a pseudo-class selector, + /// which represents an element that has no children at all. + /// + void Empty(); + + // + // Combinators + // + + /// + /// Generates a combinator, + /// which represents a childhood relationship between two elements. + /// + void Child(); + + /// + /// Generates a combinator, + /// which represents a relationship between two elements where one element is an + /// arbitrary descendant of some ancestor element. + /// + void Descendant(); + + /// + /// Generates a combinator, + /// which represents elements that share the same parent in the document tree and + /// where the first element immediately precedes the second element. + /// + void Adjacent(); + + /// + /// Generates a combinator, + /// which separates two sequences of simple selectors. The elements represented + /// by the two sequences share the same parent in the document tree and the + /// element represented by the first sequence precedes (not necessarily + /// immediately) the element represented by the second one. + /// + void GeneralSibling(); + + /// + /// Generates a pseudo-class selector, + /// which represents an element that is the N-th child from bottom up of some other element. + /// + void NthLastChild(int a, int b); + } +} \ No newline at end of file diff --git a/Source/External/Fizzler/NamespacePrefix.cs b/Source/External/Fizzler/NamespacePrefix.cs new file mode 100644 index 0000000000000000000000000000000000000000..7843d3076c0a04de9a96eba2a0aa33d85d139436 --- /dev/null +++ b/Source/External/Fizzler/NamespacePrefix.cs @@ -0,0 +1,135 @@ +#region Copyright and License +// +// Fizzler - CSS Selector Engine for Microsoft .NET Framework +// Copyright (c) 2009 Atif Aziz, Colin Ramsay. All rights reserved. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3 of the License, or (at your option) +// any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#endregion + +namespace Fizzler +{ + using System; + + /// + /// Represent a type or attribute name. + /// + [Serializable] + public struct NamespacePrefix + { + /// + /// Represents a name from either the default or any namespace + /// in a target document, depending on whether a default namespace is + /// in effect or not. + /// + public static readonly NamespacePrefix None = new NamespacePrefix(null); + + /// + /// Represents an empty namespace. + /// + public static readonly NamespacePrefix Empty = new NamespacePrefix(string.Empty); + + /// + /// Represents any namespace. + /// + public static readonly NamespacePrefix Any = new NamespacePrefix("*"); + + /// + /// Initializes an instance with a namespace prefix specification. + /// + public NamespacePrefix(string text) : this() + { + Text = text; + } + + /// + /// Gets the raw text value of this instance. + /// + public string Text { get; private set; } + + /// + /// Indicates whether this instance represents a name + /// from either the default or any namespace in a target + /// document, depending on whether a default namespace is + /// in effect or not. + /// + public bool IsNone { get { return Text == null; } } + + /// + /// Indicates whether this instance represents a name + /// from any namespace (including one without one) + /// in a target document. + /// + public bool IsAny + { + get { return !IsNone && Text.Length == 1 && Text[0] == '*'; } + } + + /// + /// Indicates whether this instance represents a name + /// without a namespace in a target document. + /// + public bool IsEmpty { get { return !IsNone && Text.Length == 0; } } + + /// + /// Indicates whether this instance represents a name from a + /// specific namespace or not. + /// + public bool IsSpecific { get {return !IsNone && !IsAny; } } + + /// + /// Indicates whether this instance and a specified object are equal. + /// + public override bool Equals(object obj) + { + return obj is NamespacePrefix && Equals((NamespacePrefix) obj); + } + + /// + /// Indicates whether this instance and another are equal. + /// + public bool Equals(NamespacePrefix other) + { + return Text == other.Text; + } + + /// + /// Returns the hash code for this instance. + /// + public override int GetHashCode() + { + return IsNone ? 0 : Text.GetHashCode(); + } + + /// + /// Returns a string representation of this instance. + /// + public override string ToString() + { + return IsNone ? "(none)" : Text; + } + + /// + /// Formats this namespace together with a name. + /// + public string Format(string name) + { + if (name == null) throw new ArgumentNullException("name"); + if (name.Length == 0) throw new ArgumentException(null, "name"); + + return Text + (IsNone ? null : "|") + name; + } + } +} diff --git a/Source/External/Fizzler/Parser.cs b/Source/External/Fizzler/Parser.cs new file mode 100644 index 0000000000000000000000000000000000000000..3af3ed55612d547dc5dbbd22184a21a3e8fe8fe7 --- /dev/null +++ b/Source/External/Fizzler/Parser.cs @@ -0,0 +1,483 @@ +#region Copyright and License +// +// Fizzler - CSS Selector Engine for Microsoft .NET Framework +// Copyright (c) 2009 Atif Aziz, Colin Ramsay. All rights reserved. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3 of the License, or (at your option) +// any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#endregion + +namespace Fizzler +{ + #region Imports + + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.Globalization; + using System.Linq; + + using TokenSpec = Either; + + #endregion + + /// + /// Semantic parser for CSS selector grammar. + /// + public sealed class Parser + { + private readonly Reader _reader; + private readonly ISelectorGenerator _generator; + + private Parser(Reader reader, ISelectorGenerator generator) + { + Debug.Assert(reader != null); + Debug.Assert(generator != null); + _reader = reader; + _generator = generator; + } + + /// + /// Parses a CSS selector group and generates its implementation. + /// + public static TGenerator Parse(string selectors, TGenerator generator) + where TGenerator : ISelectorGenerator + { + return Parse(selectors, generator, g => g); + } + + /// + /// Parses a CSS selector group and generates its implementation. + /// + public static T Parse(string selectors, TGenerator generator, Func resultor) + where TGenerator : ISelectorGenerator + { + if (selectors == null) throw new ArgumentNullException("selectors"); + if (selectors.Length == 0) throw new ArgumentException(null, "selectors"); + + return Parse(Tokener.Tokenize(selectors), generator, resultor); + } + + /// + /// Parses a tokenized stream representing a CSS selector group and + /// generates its implementation. + /// + public static TGenerator Parse(IEnumerable tokens, TGenerator generator) + where TGenerator : ISelectorGenerator + { + return Parse(tokens, generator, g => g); + } + + /// + /// Parses a tokenized stream representing a CSS selector group and + /// generates its implementation. + /// + public static T Parse(IEnumerable tokens, TGenerator generator, Func resultor) + where TGenerator : ISelectorGenerator + { + if (tokens == null) throw new ArgumentNullException("tokens"); + if (resultor == null) throw new ArgumentNullException("resultor"); + + new Parser(new Reader(tokens.GetEnumerator()), generator).Parse(); + return resultor(generator); + } + + private void Parse() + { + _generator.OnInit(); + SelectorGroup(); + _generator.OnClose(); + } + + private void SelectorGroup() + { + //selectors_group + // : selector [ COMMA S* selector ]* + // ; + + Selector(); + while (TryRead(ToTokenSpec(Token.Comma())) != null) + { + TryRead(ToTokenSpec(TokenKind.WhiteSpace)); + Selector(); + } + + Read(ToTokenSpec(TokenKind.Eoi)); + } + + private void Selector() + { + _generator.OnSelector(); + + //selector + // : simple_selector_sequence [ combinator simple_selector_sequence ]* + // ; + + SimpleSelectorSequence(); + while (TryCombinator()) + SimpleSelectorSequence(); + } + + private bool TryCombinator() + { + //combinator + // /* combinators can be surrounded by whitespace */ + // : PLUS S* | GREATER S* | TILDE S* | S+ + // ; + + var token = TryRead(ToTokenSpec(TokenKind.Plus), ToTokenSpec(TokenKind.Greater), ToTokenSpec(TokenKind.Tilde), ToTokenSpec(TokenKind.WhiteSpace)); + + if (token == null) + return false; + + if (token.Value.Kind == TokenKind.WhiteSpace) + { + _generator.Descendant(); + } + else + { + switch (token.Value.Kind) + { + case TokenKind.Tilde: _generator.GeneralSibling(); break; + case TokenKind.Greater: _generator.Child(); break; + case TokenKind.Plus: _generator.Adjacent(); break; + } + + TryRead(ToTokenSpec(TokenKind.WhiteSpace)); + } + + return true; + } + + private void SimpleSelectorSequence() + { + //simple_selector_sequence + // : [ type_selector | universal ] + // [ HASH | class | attrib | pseudo | negation ]* + // | [ HASH | class | attrib | pseudo | negation ]+ + // ; + + var named = false; + for (var modifiers = 0; ; modifiers++) + { + var token = TryRead(ToTokenSpec(TokenKind.Hash), ToTokenSpec(Token.Dot()), ToTokenSpec(Token.LeftBracket()), ToTokenSpec(Token.Colon())); + + if (token == null) + { + if (named || modifiers > 0) + break; + TypeSelectorOrUniversal(); + named = true; + } + else + { + if (modifiers == 0 && !named) + _generator.Universal(NamespacePrefix.None); // implied + + if (token.Value.Kind == TokenKind.Hash) + { + _generator.Id(token.Value.Text); + } + else + { + Unread(token.Value); + switch (token.Value.Text[0]) + { + case '.': Class(); break; + case '[': Attrib(); break; + case ':': Pseudo(); break; + default: throw new Exception("Internal error."); + } + } + } + } + } + + private void Pseudo() + { + //pseudo + // /* '::' starts a pseudo-element, ':' a pseudo-class */ + // /* Exceptions: :first-line, :first-letter, :before and :after. */ + // /* Note that pseudo-elements are restricted to one per selector and */ + // /* occur only in the last simple_selector_sequence. */ + // : ':' ':'? [ IDENT | functional_pseudo ] + // ; + + PseudoClass(); // We do pseudo-class only for now + } + + private void PseudoClass() + { + //pseudo + // : ':' [ IDENT | functional_pseudo ] + // ; + + Read(ToTokenSpec(Token.Colon())); + if (!TryFunctionalPseudo()) + { + var clazz = Read(ToTokenSpec(TokenKind.Ident)).Text; + switch (clazz) + { + case "first-child": _generator.FirstChild(); break; + case "last-child": _generator.LastChild(); break; + case "only-child": _generator.OnlyChild(); break; + case "empty": _generator.Empty(); break; + default: + { + throw new FormatException(string.Format( + "Unknown pseudo-class '{0}'. Use either first-child, last-child, only-child or empty.", clazz)); + } + } + } + } + + private bool TryFunctionalPseudo() + { + //functional_pseudo + // : FUNCTION S* expression ')' + // ; + + var token = TryRead(ToTokenSpec(TokenKind.Function)); + if (token == null) + return false; + + TryRead(ToTokenSpec(TokenKind.WhiteSpace)); + + var func = token.Value.Text; + switch (func) + { + case "nth-child": Nth(); break; + case "nth-last-child": NthLast(); break; + default: + { + throw new FormatException(string.Format( + "Unknown functional pseudo '{0}'. Only nth-child and nth-last-child are supported.", func)); + } + } + + Read(ToTokenSpec(Token.RightParenthesis())); + return true; + } + + private void Nth() + { + //nth + // : S* [ ['-'|'+']? INTEGER? {N} [ S* ['-'|'+'] S* INTEGER ]? | + // ['-'|'+']? INTEGER | {O}{D}{D} | {E}{V}{E}{N} ] S* + // ; + + // TODO Add support for the full syntax + // At present, only INTEGER is allowed + + _generator.NthChild(1, NthB()); + } + + private void NthLast() + { + //nth + // : S* [ ['-'|'+']? INTEGER? {N} [ S* ['-'|'+'] S* INTEGER ]? | + // ['-'|'+']? INTEGER | {O}{D}{D} | {E}{V}{E}{N} ] S* + // ; + + // TODO Add support for the full syntax + // At present, only INTEGER is allowed + + _generator.NthLastChild(1, NthB()); + } + + private int NthB() + { + return int.Parse(Read(ToTokenSpec(TokenKind.Integer)).Text, CultureInfo.InvariantCulture); + } + + private void Attrib() + { + //attrib + // : '[' S* [ namespace_prefix ]? IDENT S* + // [ [ PREFIXMATCH | + // SUFFIXMATCH | + // SUBSTRINGMATCH | + // '=' | + // INCLUDES | + // DASHMATCH ] S* [ IDENT | STRING ] S* + // ]? ']' + // ; + + Read(ToTokenSpec(Token.LeftBracket())); + var prefix = TryNamespacePrefix() ?? NamespacePrefix.None; + var name = Read(ToTokenSpec(TokenKind.Ident)).Text; + + var hasValue = false; + while (true) + { + var op = TryRead( + ToTokenSpec(Token.Equals()), + ToTokenSpec(TokenKind.Includes), + ToTokenSpec(TokenKind.DashMatch), + ToTokenSpec(TokenKind.PrefixMatch), + ToTokenSpec(TokenKind.SuffixMatch), + ToTokenSpec(TokenKind.SubstringMatch)); + + if (op == null) + break; + + hasValue = true; + var value = Read(ToTokenSpec(TokenKind.String), ToTokenSpec(TokenKind.Ident)).Text; + + if (op.Value == Token.Equals()) + { + _generator.AttributeExact(prefix, name, value); + } + else + { + switch (op.Value.Kind) + { + case TokenKind.Includes: _generator.AttributeIncludes(prefix, name, value); break; + case TokenKind.DashMatch: _generator.AttributeDashMatch(prefix, name, value); break; + case TokenKind.PrefixMatch: _generator.AttributePrefixMatch(prefix, name, value); break; + case TokenKind.SuffixMatch: _generator.AttributeSuffixMatch(prefix, name, value); break; + case TokenKind.SubstringMatch: _generator.AttributeSubstring(prefix, name, value); break; + } + } + } + + if (!hasValue) + _generator.AttributeExists(prefix, name); + + Read(ToTokenSpec(Token.RightBracket())); + } + + private void Class() + { + //class + // : '.' IDENT + // ; + + Read(ToTokenSpec(Token.Dot())); + _generator.Class(Read(ToTokenSpec(TokenKind.Ident)).Text); + } + + private NamespacePrefix? TryNamespacePrefix() + { + //namespace_prefix + // : [ IDENT | '*' ]? '|' + // ; + + var pipe = Token.Pipe(); + var token = TryRead(ToTokenSpec(TokenKind.Ident), ToTokenSpec(Token.Star()), ToTokenSpec(pipe)); + + if (token == null) + return null; + + if (token.Value == pipe) + return NamespacePrefix.Empty; + + var prefix = token.Value; + if (TryRead(ToTokenSpec(pipe)) == null) + { + Unread(prefix); + return null; + } + + return prefix.Kind == TokenKind.Ident + ? new NamespacePrefix(prefix.Text) + : NamespacePrefix.Any; + } + + private void TypeSelectorOrUniversal() + { + //type_selector + // : [ namespace_prefix ]? element_name + // ; + //element_name + // : IDENT + // ; + //universal + // : [ namespace_prefix ]? '*' + // ; + + var prefix = TryNamespacePrefix() ?? NamespacePrefix.None; + var token = Read(ToTokenSpec(TokenKind.Ident), ToTokenSpec(Token.Star())); + if (token.Kind == TokenKind.Ident) + _generator.Type(prefix, token.Text); + else + _generator.Universal(prefix); + } + + private Token Peek() + { + return _reader.Peek(); + } + + private Token Read(TokenSpec spec) + { + var token = TryRead(spec); + if (token == null) + { + throw new FormatException( + string.Format(@"Unexpected token {{{0}}} where {{{1}}} was expected.", + Peek().Kind, spec)); + } + return token.Value; + } + + private Token Read(params TokenSpec[] specs) + { + var token = TryRead(specs); + if (token == null) + { + throw new FormatException(string.Format( + @"Unexpected token {{{0}}} where one of [{1}] was expected.", + Peek().Kind, string.Join(", ", specs.Select(k => k.ToString()).ToArray()))); + } + return token.Value; + } + + private Token? TryRead(params TokenSpec[] specs) + { + foreach (var kind in specs) + { + var token = TryRead(kind); + if (token != null) + return token; + } + return null; + } + + private Token? TryRead(TokenSpec spec) + { + var token = Peek(); + if (!spec.Fold(a => a == token.Kind, b => b == token)) + return null; + _reader.Read(); + return token; + } + + private void Unread(Token token) + { + _reader.Unread(token); + } + + private static TokenSpec ToTokenSpec(TokenKind kind) + { + return TokenSpec.A(kind); + } + + private static TokenSpec ToTokenSpec(Token token) + { + return TokenSpec.B(token); + } + } +} diff --git a/Source/External/Fizzler/Reader.cs b/Source/External/Fizzler/Reader.cs new file mode 100644 index 0000000000000000000000000000000000000000..ace8b6ce0252b65701be6fcaf39e7187b26d12af --- /dev/null +++ b/Source/External/Fizzler/Reader.cs @@ -0,0 +1,175 @@ +#region Copyright and License +// +// Fizzler - CSS Selector Engine for Microsoft .NET Framework +// Copyright (c) 2009 Atif Aziz, Colin Ramsay. All rights reserved. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3 of the License, or (at your option) +// any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#endregion + +namespace Fizzler +{ + #region Imports + + using System; + using System.Collections; + using System.Collections.Generic; + + #endregion + + /// + /// Adds reading semantics to a base with the + /// option to un-read and insert new elements while consuming the source. + /// + public sealed class Reader : IDisposable, IEnumerable + { + private IEnumerator _enumerator; + private Stack _buffer; + + /// + /// Initialize a new with a base + /// object. + /// + public Reader(IEnumerable e) : + this(CheckNonNull(e).GetEnumerator()) { } + + private static IEnumerable CheckNonNull(IEnumerable e) + { + if (e == null) throw new ArgumentNullException("e"); + return e; + } + + /// + /// Initialize a new with a base + /// object. + /// + public Reader(IEnumerator e) + { + if(e == null) throw new ArgumentNullException("e"); + _enumerator = e; + _buffer = new Stack(); + RealRead(); + } + + /// + /// Indicates whether there is, at least, one value waiting to be read or not. + /// + public bool HasMore + { + get + { + EnsureAlive(); + return _buffer.Count > 0; + } + } + + /// + /// Pushes back a new value that will be returned on the next read. + /// + public void Unread(T value) + { + EnsureAlive(); + _buffer.Push(value); + } + + /// + /// Reads and returns the next value. + /// + public T Read() + { + if (!HasMore) + throw new InvalidOperationException(); + + var value = _buffer.Pop(); + + if (_buffer.Count == 0) + RealRead(); + + return value; + } + + /// + /// Peeks the next value waiting to be read. + /// + /// + /// Thrown if there is no value waiting to be read. + /// + public T Peek() + { + if (!HasMore) + throw new InvalidOperationException(); + + return _buffer.Peek(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + /// + /// Returns an enumerator that iterates through the remaining + /// values to be read. + /// + public IEnumerator GetEnumerator() + { + EnsureAlive(); + return GetEnumeratorImpl(); + } + + private IEnumerator GetEnumeratorImpl() + { + while (HasMore) + yield return Read(); + } + + private void RealRead() + { + EnsureAlive(); + + if (_enumerator.MoveNext()) + Unread(_enumerator.Current); + } + + /// + /// Disposes the enumerator used to initialize this object + /// if that enumerator supports . + /// + public void Close() + { + Dispose(); + } + + void IDisposable.Dispose() + { + Dispose(); + } + + void Dispose() + { + if(_enumerator == null) + return; + _enumerator.Dispose(); + _enumerator = null; + _buffer = null; + } + + private void EnsureAlive() + { + if (_enumerator == null) + throw new ObjectDisposedException(GetType().Name); + } + } +} \ No newline at end of file diff --git a/Source/External/Fizzler/Selector.cs b/Source/External/Fizzler/Selector.cs new file mode 100644 index 0000000000000000000000000000000000000000..ac7d85ccac690764efb06a50f5bf4f31350f58b0 --- /dev/null +++ b/Source/External/Fizzler/Selector.cs @@ -0,0 +1,30 @@ +#region Copyright and License +// +// Fizzler - CSS Selector Engine for Microsoft .NET Framework +// Copyright (c) 2009 Atif Aziz, Colin Ramsay. All rights reserved. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3 of the License, or (at your option) +// any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#endregion + +namespace Fizzler +{ + using System.Collections.Generic; + + /// + /// Represents a selector implementation over an arbitrary type of elements. + /// + public delegate IEnumerable Selector(IEnumerable elements); +} \ No newline at end of file diff --git a/Source/External/Fizzler/SelectorGenerator.cs b/Source/External/Fizzler/SelectorGenerator.cs new file mode 100644 index 0000000000000000000000000000000000000000..1f3d1773d556c4970e4c7681bb6987028a63496a --- /dev/null +++ b/Source/External/Fizzler/SelectorGenerator.cs @@ -0,0 +1,341 @@ +#region Copyright and License +// +// Fizzler - CSS Selector Engine for Microsoft .NET Framework +// Copyright (c) 2009 Atif Aziz, Colin Ramsay. All rights reserved. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3 of the License, or (at your option) +// any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#endregion + +namespace Fizzler +{ + #region Imports + + using System; + using System.Collections.Generic; + using System.Linq; + + #endregion + + /// + /// A selector generator implementation for an arbitrary document/element system. + /// + public class SelectorGenerator : ISelectorGenerator + { + private readonly IEqualityComparer _equalityComparer; + private readonly Stack> _selectors; + + /// + /// Initializes a new instance of this object with an instance + /// of and the default equality + /// comparer that is used for determining if two elements are equal. + /// + public SelectorGenerator(IElementOps ops) : this(ops, null) {} + + /// + /// Initializes a new instance of this object with an instance + /// of and an equality comparer + /// used for determining if two elements are equal. + /// + public SelectorGenerator(IElementOps ops, IEqualityComparer equalityComparer) + { + if(ops == null) throw new ArgumentNullException("ops"); + Ops = ops; + _equalityComparer = equalityComparer ?? EqualityComparer.Default; + _selectors = new Stack>(); + } + + /// + /// Gets the selector implementation. + /// + /// + /// If the generation is not complete, this property returns the + /// last generated selector. + /// + public Selector Selector { get; private set; } + + /// + /// Gets the instance that this object + /// was initialized with. + /// + public IElementOps Ops { get; private set; } + + /// + /// Returns the collection of selector implementations representing + /// a group. + /// + /// + /// If the generation is not complete, this method return the + /// selectors generated so far in a group. + /// + public IEnumerable> GetSelectors() + { + var selectors = _selectors; + var top = Selector; + return top == null + ? selectors.Select(s => s) + : selectors.Concat(Enumerable.Repeat(top, 1)); + } + + /// + /// Adds a generated selector. + /// + protected void Add(Selector selector) + { + if(selector == null) throw new ArgumentNullException("selector"); + + var top = Selector; + Selector = top == null ? selector : (elements => selector(top(elements))); + } + + /// + /// Delimits the initialization of a generation. + /// + public virtual void OnInit() + { + _selectors.Clear(); + Selector = null; + } + + /// + /// Delimits a selector generation in a group of selectors. + /// + public virtual void OnSelector() + { + if (Selector != null) + _selectors.Push(Selector); + Selector = null; + } + + /// + /// Delimits the closing/conclusion of a generation. + /// + public virtual void OnClose() + { + var sum = GetSelectors().Aggregate((a, b) => (elements => a(elements).Concat(b(elements)))); + var normalize = Ops.Descendant(); + Selector = elements => sum(normalize(elements)).Distinct(_equalityComparer); + _selectors.Clear(); + } + + /// + /// Generates a ID selector, + /// which represents an element instance that has an identifier that + /// matches the identifier in the ID selector. + /// + public virtual void Id(string id) + { + Add(Ops.Id(id)); + } + + /// + /// Generates a class selector, + /// which is an alternative when + /// representing the class attribute. + /// + public virtual void Class(string clazz) + { + Add(Ops.Class(clazz)); + } + + /// + /// Generates a type selector, + /// which represents an instance of the element type in the document tree. + /// + public virtual void Type(NamespacePrefix prefix, string type) + { + Add(Ops.Type(prefix, type)); + } + + /// + /// Generates a universal selector, + /// any single element in the document tree in any namespace + /// (including those without a namespace) if no default namespace + /// has been specified for selectors. + /// + public virtual void Universal(NamespacePrefix prefix) + { + Add(Ops.Universal(prefix)); + } + + /// + /// Generates an attribute selector + /// that represents an element with the given attribute + /// whatever the values of the attribute. + /// + public virtual void AttributeExists(NamespacePrefix prefix, string name) + { + Add(Ops.AttributeExists(prefix, name)); + } + + /// + /// Generates an attribute selector + /// that represents an element with the given attribute + /// and whose value is exactly . + /// + public virtual void AttributeExact(NamespacePrefix prefix, string name, string value) + { + Add(Ops.AttributeExact(prefix, name, value)); + } + + /// + /// Generates an attribute selector + /// that represents an element with the given attribute + /// and whose value is a whitespace-separated list of words, one of + /// which is exactly . + /// + public virtual void AttributeIncludes(NamespacePrefix prefix, string name, string value) + { + Add(Ops.AttributeIncludes(prefix, name, value)); + } + + /// + /// Generates an attribute selector + /// that represents an element with the given attribute , + /// its value either being exactly or beginning + /// with immediately followed by "-" (U+002D). + /// + public virtual void AttributeDashMatch(NamespacePrefix prefix, string name, string value) + { + Add(Ops.AttributeDashMatch(prefix, name, value)); + } + + /// + /// Generates an attribute selector + /// that represents an element with the attribute + /// whose value begins with the prefix . + /// + public void AttributePrefixMatch(NamespacePrefix prefix, string name, string value) + { + Add(Ops.AttributePrefixMatch(prefix, name, value)); + } + + /// + /// Generates an attribute selector + /// that represents an element with the attribute + /// whose value ends with the suffix . + /// + public void AttributeSuffixMatch(NamespacePrefix prefix, string name, string value) + { + Add(Ops.AttributeSuffixMatch(prefix, name, value)); + } + + /// + /// Generates an attribute selector + /// that represents an element with the attribute + /// whose value contains at least one instance of the substring . + /// + public void AttributeSubstring(NamespacePrefix prefix, string name, string value) + { + Add(Ops.AttributeSubstring(prefix, name, value)); + } + + /// + /// Generates a pseudo-class selector, + /// which represents an element that is the first child of some other element. + /// + public virtual void FirstChild() + { + Add(Ops.FirstChild()); + } + + /// + /// Generates a pseudo-class selector, + /// which represents an element that is the last child of some other element. + /// + public virtual void LastChild() + { + Add(Ops.LastChild()); + } + + /// + /// Generates a pseudo-class selector, + /// which represents an element that is the N-th child of some other element. + /// + public virtual void NthChild(int a, int b) + { + Add(Ops.NthChild(a, b)); + } + + /// + /// Generates a pseudo-class selector, + /// which represents an element that has a parent element and whose parent + /// element has no other element children. + /// + public virtual void OnlyChild() + { + Add(Ops.OnlyChild()); + } + + /// + /// Generates a pseudo-class selector, + /// which represents an element that has no children at all. + /// + public virtual void Empty() + { + Add(Ops.Empty()); + } + + /// + /// Generates a combinator, + /// which represents a childhood relationship between two elements. + /// + public virtual void Child() + { + Add(Ops.Child()); + } + + /// + /// Generates a combinator, + /// which represents a relationship between two elements where one element is an + /// arbitrary descendant of some ancestor element. + /// + public virtual void Descendant() + { + Add(Ops.Descendant()); + } + + /// + /// Generates a combinator, + /// which represents elements that share the same parent in the document tree and + /// where the first element immediately precedes the second element. + /// + public virtual void Adjacent() + { + Add(Ops.Adjacent()); + } + + /// + /// Generates a combinator, + /// which separates two sequences of simple selectors. The elements represented + /// by the two sequences share the same parent in the document tree and the + /// element represented by the first sequence precedes (not necessarily + /// immediately) the element represented by the second one. + /// + public virtual void GeneralSibling() + { + Add(Ops.GeneralSibling()); + } + + /// + /// Generates a pseudo-class selector, + /// which represents an element that is the N-th child from bottom up of some other element. + /// + public void NthLastChild(int a, int b) + { + Add(Ops.NthLastChild(a, b)); + } + } +} \ No newline at end of file diff --git a/Source/External/Fizzler/SelectorGeneratorTee.cs b/Source/External/Fizzler/SelectorGeneratorTee.cs new file mode 100644 index 0000000000000000000000000000000000000000..c1485e7f7fc4f27b91f4313a15736d4e4142ade5 --- /dev/null +++ b/Source/External/Fizzler/SelectorGeneratorTee.cs @@ -0,0 +1,273 @@ +#region Copyright and License +// +// Fizzler - CSS Selector Engine for Microsoft .NET Framework +// Copyright (c) 2009 Atif Aziz, Colin Ramsay. All rights reserved. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3 of the License, or (at your option) +// any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#endregion + +namespace Fizzler +{ + using System; + + /// + /// An implementation that delegates + /// to two other objects, which + /// can be useful for doing work in a single pass. + /// + public sealed class SelectorGeneratorTee : ISelectorGenerator + { + /// + /// Gets the first generator used to initialize this generator. + /// + public ISelectorGenerator Primary { get; private set; } + + /// + /// Gets the second generator used to initialize this generator. + /// + public ISelectorGenerator Secondary { get; private set; } + + /// + /// Initializes a new instance of + /// with the two other objects + /// it delegates to. + /// + public SelectorGeneratorTee(ISelectorGenerator primary, ISelectorGenerator secondary) + { + if (primary == null) throw new ArgumentNullException("primary"); + if (secondary == null) throw new ArgumentNullException("secondary"); + + Primary = primary; + Secondary = secondary; + } + + /// + /// Delegates to then generator. + /// + public void OnInit() + { + Primary.OnInit(); + Secondary.OnInit(); + } + + /// + /// Delegates to then generator. + /// + public void OnClose() + { + Primary.OnClose(); + Secondary.OnClose(); + } + + /// + /// Delegates to then generator. + /// + public void OnSelector() + { + Primary.OnSelector(); + Secondary.OnSelector(); + } + + /// + /// Delegates to then generator. + /// + public void Type(NamespacePrefix prefix, string type) + { + Primary.Type(prefix, type); + Secondary.Type(prefix, type); + } + + /// + /// Delegates to then generator. + /// + public void Universal(NamespacePrefix prefix) + { + Primary.Universal(prefix); + Secondary.Universal(prefix); + } + + /// + /// Delegates to then generator. + /// + public void Id(string id) + { + Primary.Id(id); + Secondary.Id(id); + } + + /// + /// Delegates to then generator. + /// + public void Class(string clazz) + { + Primary.Class(clazz); + Secondary.Class(clazz); + } + + /// + /// Delegates to then generator. + /// + public void AttributeExists(NamespacePrefix prefix, string name) + { + Primary.AttributeExists(prefix, name); + Secondary.AttributeExists(prefix, name); + } + + /// + /// Delegates to then generator. + /// + public void AttributeExact(NamespacePrefix prefix, string name, string value) + { + Primary.AttributeExact(prefix, name, value); + Secondary.AttributeExact(prefix, name, value); + } + + /// + /// Delegates to then generator. + /// + public void AttributeIncludes(NamespacePrefix prefix, string name, string value) + { + Primary.AttributeIncludes(prefix, name, value); + Secondary.AttributeIncludes(prefix, name, value); + } + + /// + /// Delegates to then generator. + /// + public void AttributeDashMatch(NamespacePrefix prefix, string name, string value) + { + Primary.AttributeDashMatch(prefix, name, value); + Secondary.AttributeDashMatch(prefix, name, value); + } + + /// + /// Delegates to then generator. + /// + public void AttributePrefixMatch(NamespacePrefix prefix, string name, string value) + { + Primary.AttributePrefixMatch(prefix, name, value); + Secondary.AttributePrefixMatch(prefix, name, value); + } + + /// + /// Delegates to then generator. + /// + public void AttributeSuffixMatch(NamespacePrefix prefix, string name, string value) + { + Primary.AttributeSuffixMatch(prefix, name, value); + Secondary.AttributeSuffixMatch(prefix, name, value); + } + + /// + /// Delegates to then generator. + /// + public void AttributeSubstring(NamespacePrefix prefix, string name, string value) + { + Primary.AttributeSubstring(prefix, name, value); + Secondary.AttributeSubstring(prefix, name, value); + } + + /// + /// Delegates to then generator. + /// + public void FirstChild() + { + Primary.FirstChild(); + Secondary.FirstChild(); + } + + /// + /// Delegates to then generator. + /// + public void LastChild() + { + Primary.LastChild(); + Secondary.LastChild(); + } + + /// + /// Delegates to then generator. + /// + public void NthChild(int a, int b) + { + Primary.NthChild(a, b); + Secondary.NthChild(a, b); + } + + /// + /// Delegates to then generator. + /// + public void OnlyChild() + { + Primary.OnlyChild(); + Secondary.OnlyChild(); + } + + /// + /// Delegates to then generator. + /// + public void Empty() + { + Primary.Empty(); + Secondary.Empty(); + } + + /// + /// Delegates to then generator. + /// + public void Child() + { + Primary.Child(); + Secondary.Child(); + } + + /// + /// Delegates to then generator. + /// + public void Descendant() + { + Primary.Descendant(); + Secondary.Descendant(); + } + + /// + /// Delegates to then generator. + /// + public void Adjacent() + { + Primary.Adjacent(); + Secondary.Adjacent(); + } + + /// + /// Delegates to then generator. + /// + public void GeneralSibling() + { + Primary.GeneralSibling(); + Secondary.GeneralSibling(); + } + + /// + /// Delegates to then generator. + /// + public void NthLastChild(int a, int b) + { + Primary.NthLastChild(a, b); + Secondary.NthLastChild(a, b); + } + } +} diff --git a/Source/External/Fizzler/SelectorsCachingCompiler.cs b/Source/External/Fizzler/SelectorsCachingCompiler.cs new file mode 100644 index 0000000000000000000000000000000000000000..f910dac8f448b11d391ab31b54d26be9717b523b --- /dev/null +++ b/Source/External/Fizzler/SelectorsCachingCompiler.cs @@ -0,0 +1,78 @@ +#region Copyright and License +// +// Fizzler - CSS Selector Engine for Microsoft .NET Framework +// Copyright (c) 2009 Atif Aziz, Colin Ramsay. All rights reserved. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3 of the License, or (at your option) +// any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#endregion + +namespace Fizzler +{ + #region Imports + + using System; + using System.Collections.Generic; + using System.Diagnostics; + + #endregion + + /// + /// Implementation for a selectors compiler that supports caching. + /// + /// + /// This class is primarily targeted for developers of selection + /// over an arbitrary document model. + /// + public static class SelectorsCachingCompiler + { + /// + /// Creates a caching selectors compiler on top on an existing compiler. + /// + public static Func Create(Func compiler) + { + return Create(compiler, null); + } + + /// + /// Creates a caching selectors compiler on top on an existing compiler. + /// An addition parameter specified a dictionary to use as the cache. + /// + /// + /// If is null then this method uses a + /// the implementation with an + /// ordinally case-insensitive selectors text comparer. + /// + public static Func Create(Func compiler, IDictionary cache) + { + if(compiler == null) throw new ArgumentNullException("compiler"); + return CreateImpl(compiler, cache ?? new Dictionary(StringComparer.OrdinalIgnoreCase)); + } + + private static Func CreateImpl(Func compiler, IDictionary cache) + { + Debug.Assert(compiler != null); + Debug.Assert(cache != null); + + return selector => + { + T compiled; + return cache.TryGetValue(selector, out compiled) + ? compiled + : cache[selector] = compiler(selector); + }; + } + } +} \ No newline at end of file diff --git a/Source/External/Fizzler/Token.cs b/Source/External/Fizzler/Token.cs new file mode 100644 index 0000000000000000000000000000000000000000..cc92dbc958a5456646f04377a62524aa6e848588 --- /dev/null +++ b/Source/External/Fizzler/Token.cs @@ -0,0 +1,319 @@ +#region Copyright and License +// +// Fizzler - CSS Selector Engine for Microsoft .NET Framework +// Copyright (c) 2009 Atif Aziz, Colin Ramsay. All rights reserved. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3 of the License, or (at your option) +// any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#endregion + +namespace Fizzler +{ + using System; + + /// + /// Represent a token and optionally any text associated with it. + /// + public struct Token : IEquatable + { + /// + /// Gets the kind/type/class of the token. + /// + public TokenKind Kind { get; private set; } + + /// + /// Gets text, if any, associated with the token. + /// + public string Text { get; private set; } + + private Token(TokenKind kind) : this(kind, null) {} + + private Token(TokenKind kind, string text) : this() + { + Kind = kind; + Text = text; + } + + /// + /// Creates an end-of-input token. + /// + public static Token Eoi() + { + return new Token(TokenKind.Eoi); + } + + private static readonly Token _star = Char('*'); + private static readonly Token _dot = Char('.'); + private static readonly Token _colon = Char(':'); + private static readonly Token _comma = Char(','); + private static readonly Token _rightParenthesis = Char(')'); + private static readonly Token _equals = Char('='); + private static readonly Token _pipe = Char('|'); + private static readonly Token _leftBracket = Char('['); + private static readonly Token _rightBracket = Char(']'); + + /// + /// Creates a star token. + /// + public static Token Star() + { + return _star; + } + + /// + /// Creates a dot token. + /// + public static Token Dot() + { + return _dot; + } + + /// + /// Creates a colon token. + /// + public static Token Colon() + { + return _colon; + } + + /// + /// Creates a comma token. + /// + public static Token Comma() + { + return _comma; + } + + /// + /// Creates a right parenthesis token. + /// + public static Token RightParenthesis() + { + return _rightParenthesis; + } + + /// + /// Creates an equals token. + /// + public static Token Equals() + { + return _equals; + } + + /// + /// Creates a left bracket token. + /// + public static Token LeftBracket() + { + return _leftBracket; + } + + /// + /// Creates a right bracket token. + /// + public static Token RightBracket() + { + return _rightBracket; + } + + /// + /// Creates a pipe (vertical line) token. + /// + public static Token Pipe() + { + return _pipe; + } + + /// + /// Creates a plus token. + /// + public static Token Plus() + { + return new Token(TokenKind.Plus); + } + + /// + /// Creates a greater token. + /// + public static Token Greater() + { + return new Token(TokenKind.Greater); + } + + /// + /// Creates an includes token. + /// + public static Token Includes() + { + return new Token(TokenKind.Includes); + } + + /// + /// Creates a dash-match token. + /// + public static Token DashMatch() + { + return new Token(TokenKind.DashMatch); + } + + /// + /// Creates a prefix-match token. + /// + public static Token PrefixMatch() + { + return new Token(TokenKind.PrefixMatch); + } + + /// + /// Creates a suffix-match token. + /// + public static Token SuffixMatch() + { + return new Token(TokenKind.SuffixMatch); + } + + /// + /// Creates a substring-match token. + /// + public static Token SubstringMatch() + { + return new Token(TokenKind.SubstringMatch); + } + + /// + /// Creates a general sibling token. + /// + public static Token Tilde() + { + return new Token(TokenKind.Tilde); + } + + /// + /// Creates an identifier token. + /// + public static Token Ident(string text) + { + ValidateTextArgument(text); + return new Token(TokenKind.Ident, text); + } + + /// + /// Creates an integer token. + /// + public static Token Integer(string text) + { + ValidateTextArgument(text); + return new Token(TokenKind.Integer, text); + } + + /// + /// Creates a hash-name token. + /// + public static Token Hash(string text) + { + ValidateTextArgument(text); + return new Token(TokenKind.Hash, text); + } + + /// + /// Creates a white-space token. + /// + public static Token WhiteSpace(string space) + { + ValidateTextArgument(space); + return new Token(TokenKind.WhiteSpace, space); + } + + /// + /// Creates a string token. + /// + public static Token String(string text) + { + return new Token(TokenKind.String, text ?? string.Empty); + } + + /// + /// Creates a function token. + /// + public static Token Function(string text) + { + ValidateTextArgument(text); + return new Token(TokenKind.Function, text); + } + + /// + /// Creates an arbitrary character token. + /// + public static Token Char(char ch) + { + return new Token(TokenKind.Char, ch.ToString()); + } + + /// + /// Indicates whether this instance and a specified object are equal. + /// + public override bool Equals(object obj) + { + return obj != null && obj is Token && Equals((Token) obj); + } + + /// + /// Returns the hash code for this instance. + /// + public override int GetHashCode() + { + return Text == null ? Kind.GetHashCode() : Kind.GetHashCode() ^ Text.GetHashCode(); + } + + /// + /// Indicates whether the current object is equal to another object of the same type. + /// + public bool Equals(Token other) + { + return Kind == other.Kind && Text == other.Text; + } + + /// + /// Gets a string representation of the token. + /// + public override string ToString() + { + return Text == null ? Kind.ToString() : Kind + ": " + Text; + } + /// + /// Performs a logical comparison of the two tokens to determine + /// whether they are equal. + /// + public static bool operator==(Token a, Token b) + { + return a.Equals(b); + } + + /// + /// Performs a logical comparison of the two tokens to determine + /// whether they are inequal. + /// + public static bool operator !=(Token a, Token b) + { + return !a.Equals(b); + } + + private static void ValidateTextArgument(string text) + { + if (text == null) throw new ArgumentNullException("text"); + if (text.Length == 0) throw new ArgumentException(null, "text"); + } + } +} \ No newline at end of file diff --git a/Source/External/Fizzler/TokenKind.cs b/Source/External/Fizzler/TokenKind.cs new file mode 100644 index 0000000000000000000000000000000000000000..ef0d8b99d938f357111cec0a9b1e6e14c2236300 --- /dev/null +++ b/Source/External/Fizzler/TokenKind.cs @@ -0,0 +1,109 @@ +#region Copyright and License +// +// Fizzler - CSS Selector Engine for Microsoft .NET Framework +// Copyright (c) 2009 Atif Aziz, Colin Ramsay. All rights reserved. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3 of the License, or (at your option) +// any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#endregion + +namespace Fizzler +{ + /// + /// Represents the classification of a token. + /// + public enum TokenKind + { + /// + /// Represents end of input/file/stream + /// + Eoi, + + /// + /// Represents {ident} + /// + Ident, + + /// + /// Represents "#" {name} + /// + Hash, + + /// + /// Represents "~=" + /// + Includes, + + /// + /// Represents "|=" + /// + DashMatch, + + /// + /// Represents "^=" + /// + PrefixMatch, + + /// + /// Represents "$=" + /// + SuffixMatch, + + /// + /// Represents "*=" + /// + SubstringMatch, + + /// + /// Represents {string} + /// + String, + + /// + /// Represents S* "+" + /// + Plus, + + /// + /// Represents S* ">" + /// + Greater, + + /// + /// Represents [ \t\r\n\f]+ + /// + WhiteSpace, + + /// + /// Represents {ident} ")" + /// + Function, + + /// + /// Represents [0-9]+ + /// + Integer, + + /// + /// Represents S* "~" + /// + Tilde, + + /// + /// Represents an arbitrary character + /// + Char, + } +} \ No newline at end of file diff --git a/Source/External/Fizzler/Tokener.cs b/Source/External/Fizzler/Tokener.cs new file mode 100644 index 0000000000000000000000000000000000000000..c2edc0085cac64f658d1d9962505cab94d810ba0 --- /dev/null +++ b/Source/External/Fizzler/Tokener.cs @@ -0,0 +1,325 @@ +#region Copyright and License +// +// Fizzler - CSS Selector Engine for Microsoft .NET Framework +// Copyright (c) 2009 Atif Aziz, Colin Ramsay. All rights reserved. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3 of the License, or (at your option) +// any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#endregion + +namespace Fizzler +{ + #region Imports + + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.IO; + using System.Text; + + #endregion + + /// + /// Lexer for tokens in CSS selector grammar. + /// + public static class Tokener + { + /// + /// Parses tokens from a given text source. + /// + public static IEnumerable Tokenize(TextReader reader) + { + if (reader == null) throw new ArgumentNullException("reader"); + return Tokenize(reader.ReadToEnd()); + } + + /// + /// Parses tokens from a given string. + /// + public static IEnumerable Tokenize(string input) + { + var reader = new Reader(input ?? string.Empty); + + while (reader.Read() != null) + { + var ch = reader.Value; + + // + // Identifier or function + // + if (ch == '-' || IsNmStart(ch)) + { + reader.Mark(); + if (reader.Value == '-') + { + if (!IsNmStart(reader.Read())) + throw new FormatException(string.Format("Invalid identifier at position {0}.", reader.Position)); + } + while (IsNmChar(reader.Read())) { /* NOP */ } + if (reader.Value == '(') + yield return Token.Function(reader.Marked()); + else + yield return Token.Ident(reader.MarkedWithUnread()); + } + // + // Integer + // + else if (IsDigit(ch)) + { + reader.Mark(); + do { /* NOP */ } while (IsDigit(reader.Read())); + yield return Token.Integer(reader.MarkedWithUnread()); + } + // + // Whitespace, including that which is coupled with some punctuation + // + else if (IsS(ch)) + { + var space = ParseWhiteSpace(reader); + ch = reader.Read(); + switch (ch) + { + case ',': yield return Token.Comma(); break; + case '+': yield return Token.Plus(); break; + case '>': yield return Token.Greater(); break; + case '~': yield return Token.Tilde(); break; + + default: + reader.Unread(); + yield return Token.WhiteSpace(space); + break; + } + } + else switch(ch) + { + case '*': // * or *= + case '~': // ~ or ~= + case '|': // | or |= + { + if (reader.Read() == '=') + { + yield return ch == '*' + ? Token.SubstringMatch() + : ch == '|' ? Token.DashMatch() + : Token.Includes(); + } + else + { + reader.Unread(); + yield return ch == '*' || ch == '|' + ? Token.Char(ch.Value) + : Token.Tilde(); + } + break; + } + case '^': // ^= + case '$': // $= + { + if (reader.Read() != '=') + throw new FormatException(string.Format("Invalid character at position {0}.", reader.Position)); + + switch (ch) + { + case '^': yield return Token.PrefixMatch(); break; + case '$': yield return Token.SuffixMatch(); break; + } + break; + } + // + // Single-character punctuation + // + case '.': yield return Token.Dot(); break; + case ':': yield return Token.Colon(); break; + case ',': yield return Token.Comma(); break; + case '=': yield return Token.Equals(); break; + case '[': yield return Token.LeftBracket(); break; + case ']': yield return Token.RightBracket(); break; + case ')': yield return Token.RightParenthesis(); break; + case '+': yield return Token.Plus(); break; + case '>': yield return Token.Greater(); break; + case '#': yield return Token.Hash(ParseHash(reader)); break; + // + // Single- or double-quoted strings + // + case '\"': + case '\'': yield return ParseString(reader, /* quote */ ch.Value); break; + + default: + throw new FormatException(string.Format("Invalid character at position {0}.", reader.Position)); + } + } + yield return Token.Eoi(); + } + + private static string ParseWhiteSpace(Reader reader) + { + Debug.Assert(reader != null); + + reader.Mark(); + while (IsS(reader.Read())) { /* NOP */ } + return reader.MarkedWithUnread(); + } + + private static string ParseHash(Reader reader) + { + Debug.Assert(reader != null); + + reader.MarkFromNext(); // skipping # + while (IsNmChar(reader.Read())) { /* NOP */ } + var text = reader.MarkedWithUnread(); + if (text.Length == 0) + throw new FormatException(string.Format("Invalid hash at position {0}.", reader.Position)); + return text; + } + + private static Token ParseString(Reader reader, char quote) + { + Debug.Assert(reader != null); + + // + // TODO Support full string syntax! + // + // string {string1}|{string2} + // string1 \"([^\n\r\f\\"]|\\{nl}|{nonascii}|{escape})*\" + // string2 \'([^\n\r\f\\']|\\{nl}|{nonascii}|{escape})*\' + // nonascii [^\0-\177] + // escape {unicode}|\\[^\n\r\f0-9a-f] + // unicode \\[0-9a-f]{1,6}(\r\n|[ \n\r\t\f])? + // + + var strpos = reader.Position; + reader.MarkFromNext(); // skipping quote + + char? ch; + StringBuilder sb = null; + + while ((ch = reader.Read()) != quote) + { + if (ch == null) + throw new FormatException(string.Format("Unterminated string at position {0}.", strpos)); + + if (ch == '\\') + { + ch = reader.Read(); + + // + // NOTE: Only escaping of quote and backslash supported! + // + + if (ch != quote && ch != '\\') + throw new FormatException(string.Format("Invalid escape sequence at position {0} in a string at position {1}.", reader.Position, strpos)); + + if (sb == null) + sb = new StringBuilder(); + + sb.Append(reader.MarkedExceptLast()); + reader.Mark(); + } + } + + var text = reader.Marked(); + + if (sb != null) + text = sb.Append(text).ToString(); + + return Token.String(text); + } + + private static bool IsDigit(char? ch) // [0-9] + { + return ch >= '0' && ch <= '9'; + } + + private static bool IsS(char? ch) // [ \t\r\n\f] + { + return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == '\f'; + } + + private static bool IsNmStart(char? ch) // [_a-z]|{nonascii}|{escape} + { + return ch == '_' + || (ch >= 'a' && ch <= 'z') + || (ch >= 'A' && ch <= 'Z'); + } + + private static bool IsNmChar(char? ch) // [_a-z0-9-]|{nonascii}|{escape} + { + return IsNmStart(ch) || ch == '-' || (ch >= '0' && ch <= '9'); + } + + private sealed class Reader + { + private readonly string _input; + private int _index = -1; + private int _start = -1; + + public Reader(string input) + { + _input = input; + } + + private bool Ready { get { return _index >= 0 && _index < _input.Length; } } + public char? Value { get { return Ready ? _input[_index] : (char?)null; } } + public int Position { get { return _index + 1; } } + + public void Mark() + { + _start = _index; + } + + public void MarkFromNext() + { + _start = _index + 1; + } + + public string Marked() + { + return Marked(0); + } + + public string MarkedExceptLast() + { + return Marked(-1); + } + + private string Marked(int trim) + { + var start = _start; + var count = Math.Min(_input.Length, _index + trim) - start; + return count > 0 + ? _input.Substring(start, count) + : string.Empty; + } + + public char? Read() + { + _index = Position >= _input.Length ? _input.Length : _index + 1; + return Value; + } + + public void Unread() + { + _index = Math.Max(-1, _index - 1); + } + + public string MarkedWithUnread() + { + var text = Marked(); + Unread(); + return text; + } + } + } +} diff --git a/Source/Painting/EnumConverters.cs b/Source/Painting/EnumConverters.cs index 553e39a8a5b62ffe649b9f173bf31c1446450f97..75fe2573660a5b978d21103266f0abd6e460b0cb 100644 --- a/Source/Painting/EnumConverters.cs +++ b/Source/Painting/EnumConverters.cs @@ -124,7 +124,7 @@ namespace Svg { public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { - if (value == "small-caps") return SvgFontVariant.smallcaps; + if (value.ToString() == "small-caps") return SvgFontVariant.smallcaps; return base.ConvertFrom(context, culture, value); } public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) diff --git a/Source/Paths/SvgPathBuilder.cs b/Source/Paths/SvgPathBuilder.cs index 7595c91dc2c09cab382da5cbcb1ed07c4b1f60f6..740e4f5abf1b61c3ae90faaabe89c815916883e7 100644 --- a/Source/Paths/SvgPathBuilder.cs +++ b/Source/Paths/SvgPathBuilder.cs @@ -223,8 +223,7 @@ namespace Svg var lastSegment = segments.Last; // if the last element is a SvgClosePathSegment the position of the previous element should be used because the position of SvgClosePathSegment is 0,0 - if (lastSegment is SvgClosePathSegment) - lastSegment = segments[segments.Count - 2]; + if (lastSegment is SvgClosePathSegment) lastSegment = segments.Reverse().OfType().First(); if (isRelativeX) { diff --git a/Source/Svg.csproj b/Source/Svg.csproj index 50f91ad6f4b34433512c430947df47abf6c6a9b6..1b00cbb5ce1e55b14525c509e6a3400035079b1e 100644 --- a/Source/Svg.csproj +++ b/Source/Svg.csproj @@ -60,7 +60,7 @@ true - true + false PdbOnly @@ -76,7 +76,7 @@ bin\Release\Svg.XML - True + false svgkey.snk @@ -99,6 +99,8 @@ + + @@ -117,8 +119,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Source/SvgDocument.cs b/Source/SvgDocument.cs index 025db5303b71dced7e3af0a91f08a28f5bcd177d..fca66984e98e2cccbc005edf883d0c14e022b5b1 100644 --- a/Source/SvgDocument.cs +++ b/Source/SvgDocument.cs @@ -9,6 +9,8 @@ using System.IO; using System.Text; using System.Xml; using System.Linq; +using ExCSS; +using Svg.Css; namespace Svg { @@ -43,7 +45,7 @@ namespace Svg return _idManager; } } - + /// /// Overwrites the current IdManager with a custom implementation. /// Be careful with this: If elements have been inserted into the document before, @@ -113,8 +115,8 @@ namespace Svg { return (this.GetElementById(id) as TSvgElement); } - - /// + + /// /// Opens the document at the specified path and loads the SVG contents. /// /// A containing the path of the file to open. @@ -167,6 +169,27 @@ namespace Svg return Open(stream, null); } + + /// + /// Attempts to create an SVG document from the specified string data. + /// + /// The SVG data. + public static T FromSvg(string svg) where T : SvgDocument, new() + { + if (string.IsNullOrEmpty(svg)) + { + throw new ArgumentNullException("svg"); + } + + using (var strReader = new System.IO.StringReader(svg)) + { + var reader = new SvgTextReader(strReader, null); + reader.XmlResolver = new SvgDtdResolver(); + reader.WhitespaceHandling = WhitespaceHandling.None; + return Open(reader); + } + } + /// /// Opens an SVG document from the specified and adds the specified entities. /// @@ -180,94 +203,133 @@ namespace Svg throw new ArgumentNullException("stream"); } - //Trace.TraceInformation("Begin Read"); + // Don't close the stream via a dispose: that is the client's job. + var reader = new SvgTextReader(stream, entities); + reader.XmlResolver = new SvgDtdResolver(); + reader.WhitespaceHandling = WhitespaceHandling.None; + return Open(reader); + } - using (var reader = new SvgTextReader(stream, entities)) + private static T Open(XmlReader reader) where T : SvgDocument, new() + { + var elementStack = new Stack(); + bool elementEmpty; + SvgElement element = null; + SvgElement parent; + T svgDocument = null; + + var styles = new List(); + + while (reader.Read()) { - var elementStack = new Stack(); - bool elementEmpty; - SvgElement element = null; - SvgElement parent; - T svgDocument = null; - reader.XmlResolver = new SvgDtdResolver(); - reader.WhitespaceHandling = WhitespaceHandling.None; - - while (reader.Read()) + try { - try + switch (reader.NodeType) { - switch (reader.NodeType) - { - case XmlNodeType.Element: - // Does this element have a value or children - // (Must do this check here before we progress to another node) - elementEmpty = reader.IsEmptyElement; - // Create element - if (elementStack.Count > 0) - { - element = SvgElementFactory.CreateElement(reader, svgDocument); - } - else - { - svgDocument = SvgElementFactory.CreateDocument(reader); - element = svgDocument; - } - - // Add to the parents children - if (elementStack.Count > 0) + case XmlNodeType.Element: + // Does this element have a value or children + // (Must do this check here before we progress to another node) + elementEmpty = reader.IsEmptyElement; + // Create element + if (elementStack.Count > 0) + { + element = SvgElementFactory.CreateElement(reader, svgDocument); + } + else + { + svgDocument = SvgElementFactory.CreateDocument(reader); + element = svgDocument; + } + + // Add to the parents children + if (elementStack.Count > 0) + { + parent = elementStack.Peek(); + if (parent != null && element != null) { - parent = elementStack.Peek(); - if (parent != null && element != null) - { - parent.Children.Add(element); - parent.Nodes.Add(element); - } + parent.Children.Add(element); + parent.Nodes.Add(element); } + } + + // Push element into stack + elementStack.Push(element); + + // Need to process if the element is empty + if (elementEmpty) + { + goto case XmlNodeType.EndElement; + } + + break; + case XmlNodeType.EndElement: + + // Pop the element out of the stack + element = elementStack.Pop(); + + if (element.Nodes.OfType().Any()) + { + element.Content = (from e in element.Nodes select e.Content).Aggregate((p, c) => p + c); + } + else + { + element.Nodes.Clear(); // No sense wasting the space where it isn't needed + } + + var unknown = element as SvgUnknownElement; + if (unknown != null && unknown.ElementName == "style") + { + styles.Add(unknown); + } + break; + case XmlNodeType.CDATA: + case XmlNodeType.Text: + element = elementStack.Peek(); + element.Nodes.Add(new SvgContentNode() { Content = reader.Value }); + break; + case XmlNodeType.EntityReference: + reader.ResolveEntity(); + element = elementStack.Peek(); + element.Nodes.Add(new SvgContentNode() { Content = reader.Value }); + break; + } + } + catch (Exception exc) + { + Trace.TraceError(exc.Message); + } + } - // Push element into stack - elementStack.Push(element); - - // Need to process if the element is empty - if (elementEmpty) - { - goto case XmlNodeType.EndElement; - } - - break; - case XmlNodeType.EndElement: - - // Pop the element out of the stack - element = elementStack.Pop(); + if (styles.Any()) + { + var cssTotal = styles.Select((s) => s.Content).Aggregate((p, c) => p + Environment.NewLine + c); + var cssParser = new Parser(); + var sheet = cssParser.Parse(cssTotal); + IEnumerable elemsToStyle; - if (element.Nodes.OfType().Any()) - { - element.Content = (from e in element.Nodes select e.Content).Aggregate((p, c) => p + c); - } - else - { - element.Nodes.Clear(); // No sense wasting the space where it isn't needed - } - break; - case XmlNodeType.CDATA: - case XmlNodeType.Text: - element = elementStack.Peek(); - element.Nodes.Add(new SvgContentNode() { Content = reader.Value }); - break; - case XmlNodeType.EntityReference: - reader.ResolveEntity(); - element = elementStack.Peek(); - element.Nodes.Add(new SvgContentNode() { Content = reader.Value }); - break; - } - } - catch (Exception exc) + foreach (var rule in sheet.StyleRules) + { + elemsToStyle = svgDocument.QuerySelectorAll(rule.Selector.ToString()); + foreach (var elem in elemsToStyle) { - Trace.TraceError(exc.Message); + foreach (var decl in rule.Declarations) + { + elem.AddStyle(decl.Name, decl.Term.ToString(), rule.Selector.GetSpecificity()); + } } } + } + + FlushStyles(svgDocument); + return svgDocument; + } - //Trace.TraceInformation("End Read"); - return svgDocument; + private static void FlushStyles(SvgElement elem) + { + elem.FlushStyles(); + foreach (var child in elem.Children) + { + FlushStyles(child); } } @@ -339,7 +401,7 @@ namespace Svg var size = GetDimensions(); var bitmap = new Bitmap((int)Math.Ceiling(size.Width), (int)Math.Ceiling(size.Height)); - // bitmap.SetResolution(300, 300); + // bitmap.SetResolution(300, 300); try { Draw(bitmap); @@ -395,7 +457,7 @@ namespace Svg public void Write(string path) { - using(var fs = new FileStream(path, FileMode.Create, FileAccess.Write)) + using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write)) { this.Write(fs); } diff --git a/Source/SvgElement.cs b/Source/SvgElement.cs index f56cf6507ae4b38a9b22ffca3863c683b2858bee..594559b3ba3f96ab53913edae33b685712dfc4a8 100644 --- a/Source/SvgElement.cs +++ b/Source/SvgElement.cs @@ -44,6 +44,29 @@ namespace Svg private SvgCustomAttributeCollection _customAttributes; private List _nodes = new List(); + + private Dictionary> _styles = new Dictionary>(); + + public void AddStyle(string name, string value, int specificity) + { + SortedDictionary rules; + if (!_styles.TryGetValue(name, out rules)) + { + rules = new SortedDictionary(); + _styles[name] = rules; + } + while (rules.ContainsKey(specificity)) specificity++; + rules[specificity] = value; + } + public void FlushStyles() + { + foreach (var s in _styles) + { + SvgElementFactory.SetPropertyValue(this, s.Key, s.Value.Last().Value, this.OwnerDocument); + } + _styles = null; + } + /// /// Gets the name of the element. /// diff --git a/Source/SvgElementFactory.cs b/Source/SvgElementFactory.cs index cd4d55de70b16a42496ad9cc3bcea95d06d80406..22fe86267b8234cd60b5b85adc834b3e4e2700cd 100644 --- a/Source/SvgElementFactory.cs +++ b/Source/SvgElementFactory.cs @@ -5,6 +5,7 @@ using System.Xml; using System.ComponentModel; using System.Diagnostics; using System.Linq; +using ExCSS; namespace Svg { @@ -15,11 +16,12 @@ namespace Svg { private static List availableElements; private const string svgNS = "http://www.w3.org/2000/svg"; + private static Parser cssParser = new Parser(); /// /// Gets a list of available types that can be used when creating an . /// - private static List AvailableElements + public static List AvailableElements { get { @@ -43,7 +45,7 @@ namespace Svg /// The containing the node to parse into an . /// The parameter cannot be null. /// The CreateDocument method can only be used to parse root <svg> elements. - public static T CreateDocument(XmlTextReader reader) where T : SvgDocument, new() + public static T CreateDocument(XmlReader reader) where T : SvgDocument, new() { if (reader == null) { @@ -64,7 +66,7 @@ namespace Svg /// The containing the node to parse into a subclass of . /// The that the created element belongs to. /// The and parameters cannot be null. - public static SvgElement CreateElement(XmlTextReader reader, SvgDocument document) + public static SvgElement CreateElement(XmlReader reader, SvgDocument document) { if (reader == null) { @@ -74,7 +76,7 @@ namespace Svg return CreateElement(reader, false, document); } - private static SvgElement CreateElement(XmlTextReader reader, bool fragmentIsDocument, SvgDocument document) where T : SvgDocument, new() + private static SvgElement CreateElement(XmlReader reader, bool fragmentIsDocument, SvgDocument document) where T : SvgDocument, new() { SvgElement createdElement = null; string elementName = reader.LocalName; @@ -118,49 +120,65 @@ namespace Svg return createdElement; } - private static void SetAttributes(SvgElement element, XmlTextReader reader, SvgDocument document) + private static void SetAttributes(SvgElement element, XmlReader reader, SvgDocument document) { //Trace.TraceInformation("Begin SetAttributes"); - string[] styles = null; - string[] style = null; - int i = 0; + //string[] styles = null; + //string[] style = null; + //int i = 0; while (reader.MoveToNextAttribute()) { - // Special treatment for "style" - if (reader.LocalName.Equals("style") && !(element is NonSvgElement)) - { - styles = reader.Value.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); + //// Special treatment for "style" + //if (reader.LocalName.Equals("style") && !(element is NonSvgElement)) + //{ + // styles = reader.Value.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); + + // for (i = 0; i < styles.Length; i++) + // { + // if (!styles[i].Contains(":")) + // { + // continue; + // } + + // style = styles[i].Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries); + // SetPropertyValue(element, style[0].Trim(), style[1].Trim(), document); + // } + + // //defaults for text can come from the document + // if (element.ElementName == "text") + // { + // if (!styles.Contains("font-size") && document.CustomAttributes.ContainsKey("font-size") && document.CustomAttributes["font-size"] != null) + // { + // SetPropertyValue(element, "font-size", document.CustomAttributes["font-size"], document); + // } + // if (!styles.Contains("font-family") && document.CustomAttributes.ContainsKey("font-family") && document.CustomAttributes["font-family"] != null) + // { + // SetPropertyValue(element, "font-family", document.CustomAttributes["font-family"], document); + // } + + // } + // continue; + //} + + //SetPropertyValue(element, reader.LocalName, reader.Value, document); - for (i = 0; i < styles.Length; i++) + if (reader.LocalName.Equals("style") && !(element is NonSvgElement)) + { + var inlineSheet = cssParser.Parse("#a{" + reader.Value + "}"); + foreach (var rule in inlineSheet.StyleRules) { - if (!styles[i].Contains(":")) + foreach (var decl in rule.Declarations) { - continue; + element.AddStyle(decl.Name, decl.Term.ToString(), 1 << 16); } - - style = styles[i].Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries); - SetPropertyValue(element, style[0].Trim(), style[1].Trim(), document); } - - //defaults for text can come from the document - if (element.ElementName == "text") - { - if (!styles.Contains("font-size") && document.CustomAttributes.ContainsKey("font-size") && document.CustomAttributes["font-size"] != null) - { - SetPropertyValue(element, "font-size", document.CustomAttributes["font-size"], document); - } - if (!styles.Contains("font-family") && document.CustomAttributes.ContainsKey("font-family") && document.CustomAttributes["font-family"] != null) - { - SetPropertyValue(element, "font-family", document.CustomAttributes["font-family"], document); - } - - } - continue; } - - SetPropertyValue(element, reader.LocalName, reader.Value, document); + else + { + element.AddStyle(reader.LocalName, reader.Value, 2 << 16); + } } //Trace.TraceInformation("End SetAttributes"); @@ -169,7 +187,7 @@ namespace Svg private static Dictionary> _propertyDescriptors = new Dictionary>(); private static object syncLock = new object(); - private static void SetPropertyValue(SvgElement element, string attributeName, string attributeValue, SvgDocument document) + internal static void SetPropertyValue(SvgElement element, string attributeName, string attributeValue, SvgDocument document) { var elementType = element.GetType(); diff --git a/Source/SvgTextReader.cs b/Source/SvgTextReader.cs index 114cfd45fafe26f5ca9c673ba5f29fcc95a944b2..41ce58feb7495ee898174bdf22edf9b9e069b2da 100644 --- a/Source/SvgTextReader.cs +++ b/Source/SvgTextReader.cs @@ -22,6 +22,13 @@ namespace Svg this._entities = entities; } + public SvgTextReader(TextReader reader, Dictionary entities) + : base(reader) + { + this.EntityHandling = EntityHandling.ExpandCharEntities; + this._entities = entities; + } + /// /// Gets the text value of the current node. ///