private void SetPaintType(bool hasUri, bool hasRgb, bool hasIcc, bool hasNone, bool hasCurrentColor) { if (hasUri) { if (hasRgb) { if (hasIcc) { _paintType = SvgPaintType.UriRgbColorIccColor; } else { _paintType = SvgPaintType.UriRgbColor; } } else if (hasNone) { _paintType = SvgPaintType.UriNone; } else if (hasCurrentColor) { _paintType = SvgPaintType.UriCurrentColor; } else { _paintType = SvgPaintType.Uri; } } else { if (hasRgb) { if (hasIcc) { _paintType = SvgPaintType.RgbColorIccColor; } else { _paintType = SvgPaintType.RgbColor; } } else if (hasNone) { _paintType = SvgPaintType.None; } else if (hasCurrentColor) { _paintType = SvgPaintType.CurrentColor; } else { _paintType = SvgPaintType.Unknown; } } }
private void ParsePaint(string str) { bool hasUri = false; bool hasRgb = false; bool hasIcc = false; bool hasNone = false; bool hasCurrentColor = false; const StringComparison compareType = StringComparison.OrdinalIgnoreCase; str = str.Trim(); if (str.StartsWith("url(", compareType)) { hasUri = true; int endUri = str.IndexOf(")", compareType); _uri = str.Substring(4, endUri - 4); str = str.Substring(endUri + 1).Trim(); } if (str.Equals("currentColor", compareType)) { base.ParseColor(str); hasCurrentColor = true; } else if (str.Equals("context-fill", compareType) || str.Equals("contextFill", compareType)) { _paintType = SvgPaintType.ContextFill; return; } else if (str.Equals("context-stroke", compareType) || str.Equals("contextStroke", compareType)) { _paintType = SvgPaintType.ContextStroke; return; } else if (str.Equals("none", compareType) || str.Equals("transparent", compareType) || str.Equals("null", compareType)) { hasNone = true; } else if (str.Length > 0) { base.ParseColor(str); hasRgb = true; hasIcc = (base.ColorType == SvgColorType.RgbColorIccColor); } SetPaintType(hasUri, hasRgb, hasIcc, hasNone, hasCurrentColor); }
public void SetUri(string uri) { _paintType = SvgPaintType.Uri; _uri = uri; }
public static bool TryGetBrush(SvgStyleableElement element, string property, Rect bounds, Matrix transform, out Brush brush) { SvgPaint paint = new SvgPaint(element.GetComputedStyle(string.Empty).GetPropertyValue(property)); SvgPaint svgBrush; if (paint.PaintType == SvgPaintType.None) { brush = null; return(false); } if (paint.PaintType == SvgPaintType.CurrentColor) { svgBrush = new SvgPaint(element.GetComputedStyle(string.Empty).GetPropertyValue(CssConstants.PropColor)); } else { svgBrush = paint; } SvgPaintType paintType = svgBrush.PaintType; if (paintType == SvgPaintType.Uri || paintType == SvgPaintType.UriCurrentColor || paintType == SvgPaintType.UriNone || paintType == SvgPaintType.UriRgbColor || paintType == SvgPaintType.UriRgbColorIccColor) { SvgStyleableElement fillNode = null; string absoluteUri = element.ResolveUri(svgBrush.Uri); if (element.Imported && element.ImportDocument != null && element.ImportNode != null) { // We need to determine whether the provided URI refers to element in the // original document or in the current document... SvgStyleableElement styleElm = element.ImportNode as SvgStyleableElement; if (styleElm != null) { string propertyValue = styleElm.GetComputedStyle(string.Empty).GetPropertyValue(property); if (!string.IsNullOrWhiteSpace(propertyValue)) { SvgPaint importFill = new SvgPaint(styleElm.GetComputedStyle(string.Empty).GetPropertyValue(property)); if (string.Equals(svgBrush.Uri, importFill.Uri, StringComparison.OrdinalIgnoreCase)) { fillNode = element.ImportDocument.GetNodeByUri(absoluteUri) as SvgStyleableElement; } } } } else { fillNode = element.OwnerDocument.GetNodeByUri(absoluteUri) as SvgStyleableElement; } if (fillNode != null) { SvgLinearGradientElement linearGradient; SvgRadialGradientElement radialGradient; SvgPatternElement pattern; if (TryCast.Cast(fillNode, out linearGradient)) { brush = ConstructBrush(linearGradient, bounds, transform); return(true); } if (TryCast.Cast(fillNode, out radialGradient)) { brush = ConstructBrush(radialGradient, bounds, transform); return(true); } if (TryCast.Cast(fillNode, out pattern)) { brush = ConstructBrush(pattern, bounds, transform); return(true); } } } Color solidColor; if (svgBrush == null || svgBrush.RgbColor == null || !TryConvertColor(svgBrush.RgbColor, out solidColor)) { brush = null; return(false); } brush = new SolidColorBrush(solidColor); brush.Opacity = GetOpacity(element, property); if (brush.CanFreeze) { brush.Freeze(); } return(true); }
public SvgPaint(string iriReference) { PaintType = SvgPaintType.IRIReference; _iriReference = iriReference ?? throw new ArgumentNullException(nameof(iriReference)); }
public SvgPaint(SvgPaintType paintType, SvgColor color) { PaintType = paintType; _color = color; }
private Brush GetBrush(GraphicsPath gp, string propPrefix) { SvgPaint painter; SvgPaintType curPaintType = this.PaintType; if (curPaintType == SvgPaintType.None) { return(null); } else if (curPaintType == SvgPaintType.CurrentColor) { painter = new GdiSvgPaint(_element, "color"); } else { painter = this; } SvgPaintType paintType = painter.PaintType; if (paintType == SvgPaintType.Uri || paintType == SvgPaintType.UriCurrentColor || paintType == SvgPaintType.UriNone || paintType == SvgPaintType.UriRgbColor || paintType == SvgPaintType.UriRgbColorIccColor) { _paintFill = GetPaintFill(painter.Uri); if (_paintFill != null) { Brush br = _paintFill.GetBrush(gp.GetBounds(), this.GetOpacityValue(propPrefix)); if (_paintFill.FillType == GdiFillType.Pattern) { return(br); } if (_paintFill.FillType == GdiFillType.LinearGradient) { LinearGradientBrush lgb = br as LinearGradientBrush; if (lgb != null) { int opacityl = GetOpacity(propPrefix); for (int i = 0; i < lgb.InterpolationColors.Colors.Length; i++) { lgb.InterpolationColors.Colors[i] = Color.FromArgb(opacityl, lgb.InterpolationColors.Colors[i]); } for (int i = 0; i < lgb.LinearColors.Length; i++) { lgb.LinearColors[i] = Color.FromArgb(opacityl, lgb.LinearColors[i]); } return(br); } } if (_paintFill.FillType == GdiFillType.RadialGradient) { PathGradientBrush pgb = br as PathGradientBrush; if (pgb != null) { int opacityl = GetOpacity(propPrefix); for (int i = 0; i < pgb.InterpolationColors.Colors.Length; i++) { pgb.InterpolationColors.Colors[i] = Color.FromArgb(opacityl, pgb.InterpolationColors.Colors[i]); } for (int i = 0; i < pgb.SurroundColors.Length; i++) { pgb.SurroundColors[i] = Color.FromArgb(opacityl, pgb.SurroundColors[i]); } return(br); } } } else { if (curPaintType == SvgPaintType.UriNone || curPaintType == SvgPaintType.Uri) { return(null); } else if (curPaintType == SvgPaintType.UriCurrentColor) { painter = new GdiSvgPaint(_element, "color"); } else { painter = this; } } } if (painter == null || painter.RgbColor == null) { return(null); } SolidBrush brush = new SolidBrush(GdiConverter.ToColor(painter.RgbColor)); int opacity = GetOpacity(propPrefix); brush.Color = Color.FromArgb(opacity, brush.Color); return(brush); }
private Brush GetBrush(Geometry geometry, string propPrefix, bool setOpacity) { SvgPaint fill; if (PaintType == SvgPaintType.None) { return(null); } else if (PaintType == SvgPaintType.CurrentColor) { fill = new WpfSvgPaint(_context, _element, "color"); } else { fill = this; } SvgPaintType paintType = fill.PaintType; if (paintType == SvgPaintType.Uri || paintType == SvgPaintType.UriCurrentColor || paintType == SvgPaintType.UriNone || paintType == SvgPaintType.UriRgbColor || paintType == SvgPaintType.UriRgbColorIccColor) { _paintFill = GetPaintFill(fill.Uri); if (_paintFill != null) { Brush brush = null; if (geometry != null) { brush = _paintFill.GetBrush(geometry.Bounds, _context); } else { brush = _paintFill.GetBrush(Rect.Empty, _context); } if (brush != null) { brush.Opacity = GetOpacity(propPrefix); } return(brush); } else { if (PaintType == SvgPaintType.UriNone || PaintType == SvgPaintType.Uri) { return(null); } else if (PaintType == SvgPaintType.UriCurrentColor) { fill = new WpfSvgPaint(_context, _element, "color"); } else { fill = this; } } } if (fill == null || fill.RgbColor == null) { return(null); } Color?solidColor = WpfConvert.ToColor(fill.RgbColor); if (solidColor == null) { return(null); } SolidColorBrush solidBrush = new SolidColorBrush(solidColor.Value); //int opacity = GetOpacity(propPrefix); //solidBrush.Color = Color.FromArgb(opacity, brush.Color); if (setOpacity) { solidBrush.Opacity = GetOpacity(propPrefix); } return(solidBrush); }
public Pen GetPen(Geometry geometry, bool setOpacity = true) { double strokeWidth = GetStrokeWidth(); if (strokeWidth.Equals(0.0d)) { return(null); } WpfSvgPaintContext paintContext = null; SvgPaintType paintType = this.PaintType; WpfSvgPaint stroke; if (paintType == SvgPaintType.None) { return(null); } if (paintType == SvgPaintType.CurrentColor) { stroke = new WpfSvgPaint(_context, _element, "color"); } else if (paintType == SvgPaintType.ContextFill) { paintContext = GetFillContext(); if (paintContext != null) { stroke = paintContext.Fill; } else { stroke = this; } } else if (paintType == SvgPaintType.ContextStroke) { paintContext = GetStrokeContext(); if (paintContext != null) { stroke = paintContext.Stroke; } else { stroke = this; } } else { stroke = this; } Brush brush = stroke.GetBrush(geometry, "stroke", setOpacity); if (brush == null) { WpfSvgPaint fallbackPaint = stroke.WpfFallback; if (fallbackPaint != null) { brush = fallbackPaint.GetBrush(geometry, "stroke", setOpacity); } } Pen pen = new Pen(brush, strokeWidth); pen.StartLineCap = pen.EndLineCap = GetLineCap(); pen.LineJoin = GetLineJoin(); double miterLimit = GetMiterLimit(strokeWidth); if (miterLimit > 0) { pen.MiterLimit = miterLimit; } //pen.MiterLimit = 1.0f; DoubleCollection dashArray = GetDashArray(strokeWidth); if (dashArray != null && dashArray.Count != 0) { bool isValidDashes = true; //Do not draw if dash array had a zero value in it for (int i = 0; i < dashArray.Count; i++) { if (dashArray[i].Equals(0.0d)) { isValidDashes = false; } } if (isValidDashes) { DashStyle dashStyle = new DashStyle(dashArray, GetDashOffset(strokeWidth)); pen.DashStyle = dashStyle; // This is the one that works well for the XAML, the default is not Flat as // stated in the documentations... pen.DashCap = PenLineCap.Flat; } } return(pen); }
public void SetPaint(SvgPaintType paintType, string uri, string rgbColor, string iccColor) { _paintType = paintType; // check URI switch (_paintType) { case SvgPaintType.Uri: case SvgPaintType.UriCurrentColor: case SvgPaintType.UriNone: case SvgPaintType.UriRgbColor: case SvgPaintType.UriRgbColorIccColor: if (uri == null) { throw new SvgException(SvgExceptionType.SvgInvalidValueErr, "Missing URI"); } else { _uri = uri; } break; default: if (uri != null) { throw new SvgException(SvgExceptionType.SvgInvalidValueErr, "URI must be null"); } break; } // check RGB and ICC color switch (_paintType) { case SvgPaintType.CurrentColor: case SvgPaintType.UriCurrentColor: base.ParseColor("currentColor"); break; case SvgPaintType.RgbColor: case SvgPaintType.UriRgbColor: if (rgbColor != null && rgbColor.Length > 0) { base.SetRgbColor(rgbColor); } else { throw new SvgException(SvgExceptionType.SvgInvalidValueErr, "Missing RGB color"); } break; case SvgPaintType.RgbColorIccColor: case SvgPaintType.UriRgbColorIccColor: if (rgbColor != null && rgbColor.Length > 0 && iccColor != null && iccColor.Length > 0) { base.SetRgbColorIccColor(rgbColor, iccColor); } else { throw new SvgException(SvgExceptionType.SvgInvalidValueErr, "Missing RGB or ICC color"); } break; default: if (rgbColor != null) { throw new SvgException(SvgExceptionType.SvgInvalidValueErr, "rgbColor must be null"); } break; } }
private Brush GetBrush(Geometry geometry, string propPrefix, bool setOpacity) { WpfSvgPaintContext paintContext = null; SvgPaintType paintType = this.PaintType; WpfSvgPaint fill; if (paintType == SvgPaintType.None) { return(null); } if (paintType == SvgPaintType.CurrentColor) { //TODO: Find a better way to support currentColor specified on parent element. var deferredFill = this.GetDeferredFill(); if (deferredFill == null) { fill = new WpfSvgPaint(_context, _element, CssConstants.PropColor); } else { fill = deferredFill; } } else if (paintType == SvgPaintType.ContextFill) { paintContext = GetFillContext(); if (paintContext != null) { fill = paintContext.Fill; } else { fill = this; } } else if (paintType == SvgPaintType.ContextStroke) { paintContext = GetStrokeContext(); if (paintContext != null) { fill = paintContext.Stroke; } else { fill = this; } } else { fill = this; } SvgPaintType fillType = fill.PaintType; if (fillType == SvgPaintType.Uri || fillType == SvgPaintType.UriCurrentColor || fillType == SvgPaintType.UriNone || fillType == SvgPaintType.UriRgbColor || fillType == SvgPaintType.UriRgbColorIccColor) { _paintFill = GetPaintFill(fill.Uri); if (_paintFill != null) { Brush brush = null; if (geometry != null) { brush = _paintFill.GetBrush(geometry.Bounds, _context, geometry.Transform); } else { brush = _paintFill.GetBrush(Rect.Empty, _context, null); } if (brush != null) { brush.Opacity = GetOpacity(propPrefix); } return(brush); } if (paintType == SvgPaintType.UriNone || paintType == SvgPaintType.Uri) { return(null); } if (paintType == SvgPaintType.UriCurrentColor) { fill = new WpfSvgPaint(_context, _element, CssConstants.PropColor); } else { fill = this; } } if (fill == null || fill.RgbColor == null) { return(null); } if (fill.RgbColor.IsVarColor) { var cssVar = this.GetVarsValue(fill); if (cssVar != null) { var cssVariables = _context.Settings.CssVariables; if (cssVariables != null && cssVariables.ContainsKey(cssVar.VarName)) { var cssColor = new CssColor(cssVariables[cssVar.VarName]); Color?varColor = WpfConvert.ToColor(cssColor); if (varColor != null) { var varBrush = new SolidColorBrush(varColor.Value); if (setOpacity) { varBrush.Opacity = GetOpacity(propPrefix); } return(varBrush); } } var cssValue = _element.GetComputedCssValue(cssVar.VarName, string.Empty) as CssAbsPrimitiveValue; if (cssValue != null) { Color?varColor = WpfConvert.ToColor(cssValue.GetRgbColorValue()); if (varColor != null) { var varBrush = new SolidColorBrush(varColor.Value); if (setOpacity) { varBrush.Opacity = GetOpacity(propPrefix); } return(varBrush); } } var fallbackValue = cssVar.VarValue; if (!string.IsNullOrWhiteSpace(fallbackValue)) { var cssColor = new CssColor(fallbackValue); Color?varColor = WpfConvert.ToColor(cssColor); if (varColor != null) { var varBrush = new SolidColorBrush(varColor.Value); if (setOpacity) { varBrush.Opacity = GetOpacity(propPrefix); } return(varBrush); } } } } Color?solidColor = WpfConvert.ToColor(fill.RgbColor); if (solidColor == null) { return(null); } SolidColorBrush solidBrush = new SolidColorBrush(solidColor.Value); if (setOpacity) { solidBrush.Opacity = GetOpacity(propPrefix); } return(solidBrush); }
public Pen GetPen(Geometry geometry, bool setOpacity = true) { double strokeWidth = GetStrokeWidth(); if (strokeWidth.Equals(0.0d)) { return(null); } WpfSvgPaintContext paintContext = null; SvgPaintType paintType = this.PaintType; WpfSvgPaint stroke; if (paintType == SvgPaintType.None) { return(null); } if (paintType == SvgPaintType.CurrentColor) { stroke = new WpfSvgPaint(_context, _element, CssConstants.PropColor); } else if (paintType == SvgPaintType.ContextFill) { paintContext = GetFillContext(); if (paintContext != null) { stroke = paintContext.Fill; } else { stroke = this; } } else if (paintType == SvgPaintType.ContextStroke) { paintContext = GetStrokeContext(); if (paintContext != null) { stroke = paintContext.Stroke; } else { stroke = this; } } else { stroke = this; } Brush brush = stroke.GetBrush(geometry, CssConstants.PropStroke, setOpacity); if (brush == null) { WpfSvgPaint fallbackPaint = stroke.WpfFallback; if (fallbackPaint != null) { brush = fallbackPaint.GetBrush(geometry, CssConstants.PropStroke, setOpacity); } } Pen pen = new Pen(brush, strokeWidth); if (_element.HasAttribute(CssConstants.PropStrokeOpacity)) { double opacityValue = -1; string opacity = _element.GetAttribute(CssConstants.PropStrokeOpacity); if (!string.IsNullOrWhiteSpace(opacity)) { opacityValue = SvgNumber.ParseNumber(opacity); opacityValue = Math.Min(opacityValue, 1); opacityValue = Math.Max(opacityValue, 0); if (opacityValue >= 0 && opacityValue < 1) { brush.Opacity = opacityValue; } } } var lineCap = this.GetLineCap(); pen.StartLineCap = pen.EndLineCap = lineCap; pen.LineJoin = GetLineJoin(); double miterLimit = GetMiterLimit(strokeWidth); if (miterLimit > 0) { pen.MiterLimit = miterLimit; } //pen.MiterLimit = 1.0f; DoubleCollection dashArray = GetDashArray(strokeWidth); if (dashArray != null && dashArray.Count != 0) { bool isValidDashes = true; int nonZeroCount = 0; // Specs: If all of the values in the list are zero, then the stroke is // rendered as a solid line without any dashing. // If any value in the list is negative, the dash-array value is invalid. for (int i = 0; i < dashArray.Count; i++) { if (dashArray[i] < 0.0d) { isValidDashes = false; break; } if (dashArray[i].Equals(0.0d) == false) { nonZeroCount++; } } isValidDashes = isValidDashes && nonZeroCount != 0; if (isValidDashes) { DashStyle dashStyle = new DashStyle(dashArray, GetDashOffset(strokeWidth)); pen.DashStyle = dashStyle; // This is the one that works well for the XAML, the default is not Flat as // stated in the documentations... //pen.DashCap = PenLineCap.Flat; pen.DashCap = lineCap; } } return(pen); }
private void ParsePaint(string str) { bool hasUri = false; bool hasRgb = false; bool hasIcc = false; bool hasNone = false; bool hasCurrentColor = false; var comparer = StringComparison.OrdinalIgnoreCase; str = str.Trim(); if (string.IsNullOrWhiteSpace(str) || str.Equals(CssConstants.ValNone, comparer) || str.Equals("transparent", comparer) || str.Equals("null", comparer)) { hasNone = true; } else if (str.Equals("currentColor", comparer)) { base.ParseColor(str); hasCurrentColor = true; } else if (str.Equals("context-fill", comparer) || str.Equals("contextFill", comparer)) { _paintType = SvgPaintType.ContextFill; return; } else if (str.Equals("context-stroke", comparer) || str.Equals("contextStroke", comparer)) { _paintType = SvgPaintType.ContextStroke; return; } else { List <string> strList = new List <string>(); while (!string.IsNullOrWhiteSpace(str)) { if (str.StartsWith("url(", comparer)) { var endUri = str.IndexOf(')', 4); strList.Add(str.Substring(0, endUri + 1)); str = str.Substring(endUri + 1).Trim(); } else if (str.StartsWith("rgb(", comparer)) { var leftParen = str.IndexOf(')', 4); strList.Add(str.Substring(0, leftParen + 1)); str = str.Substring(leftParen + 1).Trim(); } else if (str.StartsWith("rgba(", comparer)) { var leftParen = str.IndexOf(')', 5); strList.Add(str.Substring(0, leftParen + 1)); str = str.Substring(leftParen + 1).Trim(); } else if (str.StartsWith("hsl(", comparer)) { var leftParen = str.IndexOf(')', 4); strList.Add(str.Substring(0, leftParen + 1)); str = str.Substring(leftParen + 1).Trim(); } else if (str.StartsWith("hsla(", comparer)) { var leftParen = str.IndexOf(')', 5); strList.Add(str.Substring(0, leftParen + 1)); str = str.Substring(leftParen + 1).Trim(); } else if (str.StartsWith("#", comparer)) // Otherwise try and parse as colour { switch (CountHexDigits(str, 1)) { // RGB syntax variations case 3: strList.Add(str.Substring(0, 4)); str = str.Substring(4).Trim(); break; case 6: strList.Add(str.Substring(0, 7)); str = str.Substring(7).Trim(); break; // RGB transparency variations case 4: strList.Add(str.Substring(0, 5)); str = str.Substring(5).Trim(); break; case 8: strList.Add(str.Substring(0, 9)); str = str.Substring(9).Trim(); break; default: strList.Add(str); break; } } else { strList.Add(str.Trim()); break; } } if (strList.Count > 1) { _fallback = new SvgPaint(strList[1]); this.ParsePaint(strList[0]); return; } else { str = strList[0]; if (str.StartsWith("url(", comparer)) { hasUri = true; int endUri = str.IndexOf(")", comparer); _uri = str.Substring(4, endUri - 4); str = str.Substring(endUri + 1).Trim(); } if (str.Length > 0) { base.ParseColor(str); hasRgb = true; hasIcc = (base.ColorType == SvgColorType.RgbColorIccColor); } } } SetPaintType(hasUri, hasRgb, hasIcc, hasNone, hasCurrentColor); }
public void SetPaint(SvgPaintType paintType, JsString uri, JsString rgbColor, JsString iccColor) { }
private Brush GetBrush(Geometry geometry, string propPrefix, bool setOpacity) { WpfSvgPaintContext paintContext = null; SvgPaintType paintType = this.PaintType; WpfSvgPaint fill; if (paintType == SvgPaintType.None) { return(null); } if (paintType == SvgPaintType.CurrentColor) { //TODO: Find a better way to support currentColor specified on parent element. var deferredFill = this.GetDeferredFill(); if (deferredFill == null) { fill = new WpfSvgPaint(_context, _element, "color"); } else { fill = deferredFill; } } else if (paintType == SvgPaintType.ContextFill) { paintContext = GetFillContext(); if (paintContext != null) { fill = paintContext.Fill; } else { fill = this; } } else if (paintType == SvgPaintType.ContextStroke) { paintContext = GetStrokeContext(); if (paintContext != null) { fill = paintContext.Stroke; } else { fill = this; } } else { fill = this; } SvgPaintType fillType = fill.PaintType; if (fillType == SvgPaintType.Uri || fillType == SvgPaintType.UriCurrentColor || fillType == SvgPaintType.UriNone || fillType == SvgPaintType.UriRgbColor || fillType == SvgPaintType.UriRgbColorIccColor) { _paintFill = GetPaintFill(fill.Uri); if (_paintFill != null) { Brush brush = null; if (geometry != null) { brush = _paintFill.GetBrush(geometry.Bounds, _context, geometry.Transform); } else { brush = _paintFill.GetBrush(Rect.Empty, _context, null); } if (brush != null) { brush.Opacity = GetOpacity(propPrefix); } return(brush); } if (paintType == SvgPaintType.UriNone || paintType == SvgPaintType.Uri) { return(null); } if (paintType == SvgPaintType.UriCurrentColor) { fill = new WpfSvgPaint(_context, _element, "color"); } else { fill = this; } } if (fill == null || fill.RgbColor == null) { return(null); } Color?solidColor = WpfConvert.ToColor(fill.RgbColor); if (solidColor == null) { return(null); } SolidColorBrush solidBrush = new SolidColorBrush(solidColor.Value); if (setOpacity) { solidBrush.Opacity = GetOpacity(propPrefix); } return(solidBrush); }