Exemple #1
0
        internal void DrawMarkers(SvgMarkerElement svgMarkerElement, SKPath sKPath)
        {
            var pathTypes  = SkiaUtil.GetPathTypes(sKPath);
            var pathLength = pathTypes.Count;

            if (svgMarkerElement.MarkerStart != null)
            {
                var refPoint1 = pathTypes[0].Point;
                var index     = 1;
                while (index < pathLength && pathTypes[index].Point == refPoint1)
                {
                    ++index;
                }
                var refPoint2 = pathTypes[index].Point;
                var marker    = svgMarkerElement.OwnerDocument.GetElementById <SvgMarker>(svgMarkerElement.MarkerStart.ToString());
                DrawMarker(marker, svgMarkerElement, refPoint1, refPoint1, refPoint2, true);
            }

            if (svgMarkerElement.MarkerMid != null)
            {
                var marker      = svgMarkerElement.OwnerDocument.GetElementById <SvgMarker>(svgMarkerElement.MarkerMid.ToString());
                int bezierIndex = -1;
                for (int i = 1; i <= pathLength - 2; i++)
                {
                    // for Bezier curves, the marker shall only been shown at the last point
                    if ((pathTypes[i].Type & (byte)PathPointType.PathTypeMask) == (byte)PathPointType.Bezier)
                    {
                        bezierIndex = (bezierIndex + 1) % 3;
                    }
                    else
                    {
                        bezierIndex = -1;
                    }

                    if (bezierIndex == -1 || bezierIndex == 2)
                    {
                        DrawMarker(marker, svgMarkerElement, pathTypes[i].Point, pathTypes[i - 1].Point, pathTypes[i].Point, pathTypes[i + 1].Point);
                    }
                }
            }

            if (svgMarkerElement.MarkerEnd != null)
            {
                var marker    = svgMarkerElement.OwnerDocument.GetElementById <SvgMarker>(svgMarkerElement.MarkerEnd.ToString());
                var index     = pathLength - 1;
                var refPoint1 = pathTypes[index].Point;
                --index;
                while (index > 0 && pathTypes[index].Point == refPoint1)
                {
                    --index;
                }
                var refPoint2 = pathTypes[index].Point;
                DrawMarker(marker, svgMarkerElement, refPoint1, refPoint2, pathTypes[pathLength - 1].Point, false);
            }
        }
        protected override void Initialize(SvgElement element)
        {
            base.Initialize(element);

            _matrix      = Matrix.Identity;
            _drawGroup   = null;
            _hostElement = null;
            _pathFigures = null;

            _markerElement = element as SvgMarkerElement;
        }
Exemple #3
0
        public void RenderMarker2(WpfDrawingRenderer renderer, WpfDrawingContext gr,
                                  SvgMarkerPosition markerPos, SvgStyleableElement refElement)
        {
            ISharpMarkerHost markerHostElm = (ISharpMarkerHost)refElement;
            SvgMarkerElement markerElm     = (SvgMarkerElement)_svgElement;

            SvgPointF[] vertexPositions = markerHostElm.MarkerPositions;
            int         start;
            int         len;

            // Choose which part of the position array to use
            switch (markerPos)
            {
            case SvgMarkerPosition.Start:
                start = 0;
                len   = 1;
                break;

            case SvgMarkerPosition.Mid:
                start = 1;
                len   = vertexPositions.Length - 2;
                break;

            default:
                // == MarkerPosition.End
                start = vertexPositions.Length - 1;
                len   = 1;
                break;
            }

            for (int i = start; i < start + len; i++)
            {
                SvgPointF point = vertexPositions[i];

                //GdiGraphicsContainer gc = gr.BeginContainer();

                this.BeforeRender(renderer);

                //Matrix matrix = Matrix.Identity;

                Matrix matrix = GetTransformMatrix(_svgElement);

                if (markerElm.OrientType.AnimVal.Equals((ushort)SvgMarkerOrient.Angle))
                {
                    matrix.Rotate(markerElm.OrientAngle.AnimVal.Value);
                }
                else
                {
                    double angle = 0;

                    switch (markerPos)
                    {
                    case SvgMarkerPosition.Start:
                        angle = markerHostElm.GetStartAngle(i + 1);
                        break;

                    case SvgMarkerPosition.Mid:
                        //angle = (markerHostElm.GetEndAngle(i) + markerHostElm.GetStartAngle(i + 1)) / 2;
                        angle = SvgNumber.CalcAngleBisection(markerHostElm.GetEndAngle(i), markerHostElm.GetStartAngle(i + 1));
                        break;

                    default:
                        angle = markerHostElm.GetEndAngle(i);
                        break;
                    }
                    matrix.Rotate(angle);
                }

                if (markerElm.MarkerUnits.AnimVal.Equals((ushort)SvgMarkerUnit.StrokeWidth))
                {
                    SvgLength strokeWidthLength = new SvgLength(refElement,
                                                                "stroke-width", SvgLengthSource.Css, SvgLengthDirection.Viewport, "1");
                    double strokeWidth = strokeWidthLength.Value;
                    matrix.Scale(strokeWidth, strokeWidth);
                }

                SvgPreserveAspectRatio spar =
                    (SvgPreserveAspectRatio)markerElm.PreserveAspectRatio.AnimVal;
                double[] translateAndScale = spar.FitToViewBox((SvgRect)markerElm.ViewBox.AnimVal,
                                                               new SvgRect(0, 0, markerElm.MarkerWidth.AnimVal.Value,
                                                                           markerElm.MarkerHeight.AnimVal.Value));


                matrix.Translate(-markerElm.RefX.AnimVal.Value * translateAndScale[2],
                                 -markerElm.RefY.AnimVal.Value * translateAndScale[3]);

                matrix.Scale(translateAndScale[2], translateAndScale[3]);

                matrix.Translate(point.X, point.Y);

                _matrix = matrix;
                this.Render(renderer);

                //Clip(gr);

                renderer.RenderChildren(markerElm);

                //gr.EndContainer(gc);

                this.AfterRender(renderer);
            }
        }
Exemple #4
0
        public void RenderMarker0(WpfDrawingRenderer renderer, WpfDrawingContext gr,
                                  SvgMarkerPosition markerPos, SvgStyleableElement refElement)
        {
            //PathGeometry g;
            //g.GetPointAtFractionLength(

            ISharpMarkerHost markerHostElm = (ISharpMarkerHost)refElement;
            SvgMarkerElement markerElm     = (SvgMarkerElement)_svgElement;

            SvgPointF[] vertexPositions = markerHostElm.MarkerPositions;
            int         start;
            int         len;

            // Choose which part of the position array to use
            switch (markerPos)
            {
            case SvgMarkerPosition.Start:
                start = 0;
                len   = 1;
                break;

            case SvgMarkerPosition.Mid:
                start = 1;
                len   = vertexPositions.Length - 2;
                break;

            default:
                // == MarkerPosition.End
                start = vertexPositions.Length - 1;
                len   = 1;
                break;
            }

            for (int i = start; i < start + len; i++)
            {
                SvgPointF point = vertexPositions[i];

                Matrix m = GetTransformMatrix(_svgElement);

                //GraphicsContainer gc = gr.BeginContainer();

                this.BeforeRender(renderer);

                //gr.TranslateTransform(point.X, point.Y);

                //PAUL:
                //m.Translate(point.X, point.Y);

                if (markerElm.OrientType.AnimVal.Equals((ushort)SvgMarkerOrient.Angle))
                {
                    m.Rotate(markerElm.OrientAngle.AnimVal.Value);
                    //gr.RotateTransform((double)markerElm.OrientAngle.AnimVal.Value);
                }
                else
                {
                    double angle;

                    switch (markerPos)
                    {
                    case SvgMarkerPosition.Start:
                        angle = markerHostElm.GetStartAngle(i + 1);
                        break;

                    case SvgMarkerPosition.Mid:
                        //angle = (markerHostElm.GetEndAngle(i) + markerHostElm.GetStartAngle(i + 1)) / 2;
                        angle = SvgNumber.CalcAngleBisection(markerHostElm.GetEndAngle(i), markerHostElm.GetStartAngle(i + 1));
                        break;

                    default:
                        angle = markerHostElm.GetEndAngle(i);
                        break;
                    }
                    //gr.RotateTransform(angle);
                    m.Rotate(angle);
                }

                if (markerElm.MarkerUnits.AnimVal.Equals((ushort)SvgMarkerUnit.StrokeWidth))
                {
                    string propValue = refElement.GetPropertyValue("stroke-width");
                    if (propValue.Length == 0)
                    {
                        propValue = "1";
                    }

                    SvgLength strokeWidthLength = new SvgLength("stroke-width", propValue, refElement, SvgLengthDirection.Viewport);
                    double    strokeWidth       = strokeWidthLength.Value;
                    //gr.ScaleTransform(strokeWidth, strokeWidth);
                    m.Scale(strokeWidth, strokeWidth);
                }

                SvgPreserveAspectRatio spar = (SvgPreserveAspectRatio)markerElm.PreserveAspectRatio.AnimVal;
                double[] translateAndScale  = spar.FitToViewBox(
                    (SvgRect)markerElm.ViewBox.AnimVal, new SvgRect(0, 0,
                                                                    markerElm.MarkerWidth.AnimVal.Value, markerElm.MarkerHeight.AnimVal.Value));


                //PAUL:
                //m.Translate(-(double)markerElm.RefX.AnimVal.Value * translateAndScale[2], -(double)markerElm.RefY.AnimVal.Value * translateAndScale[3]);

                //PAUL:
                m.Scale(translateAndScale[2], translateAndScale[3]);
                m.Translate(point.X, point.Y);

                //Matrix oldTransform = TransformMatrix;
                //TransformMatrix = m;
                //try
                //{
                //newTransform.Append(m);
                //TransformGroup tg = new TransformGroup();

                //renderer.Canvas.re

                //gr.TranslateTransform(
                //    -(double)markerElm.RefX.AnimVal.Value * translateAndScale[2],
                //    -(double)markerElm.RefY.AnimVal.Value * translateAndScale[3]
                //    );

                //gr.ScaleTransform(translateAndScale[2], translateAndScale[3]);

                renderer.RenderChildren(markerElm);
                //                markerElm.RenderChildren(renderer);
                //}
                //finally
                //{
                //    TransformMatrix = oldTransform;
                //}
                //    //gr.EndContainer(gc);

                _matrix = m;
                this.Render(renderer);

                //gr.EndContainer(gc);

                this.AfterRender(renderer);
            }
        }
Exemple #5
0
 public WpfMarkerRendering(SvgElement element)
     : base(element)
 {
     _markerElement = element as SvgMarkerElement;
 }
Exemple #6
0
        public void PaintMarker(GdiGraphicsRenderer renderer, GdiGraphics gr,
                                SvgMarkerPosition markerPos, SvgStyleableElement refElement)
        {
            ISharpMarkerHost markerHostElm = (ISharpMarkerHost)refElement;
            SvgMarkerElement markerElm     = (SvgMarkerElement)_svgElement;

            SvgPointF[] vertexPositions = markerHostElm.MarkerPositions;
            if (vertexPositions == null)
            {
                return;
            }
            var comparer = StringComparison.OrdinalIgnoreCase;

            bool mayHaveCurves = markerHostElm.MayHaveCurves;
            int  start;
            int  len;

            // Choose which part of the position array to use
            switch (markerPos)
            {
            case SvgMarkerPosition.Start:
                start = 0;
                len   = 1;
                break;

            case SvgMarkerPosition.Mid:
                start = 1;
                len   = vertexPositions.Length - 2;
                break;

            default:
                // == MarkerPosition.End
                start = vertexPositions.Length - 1;
                len   = 1;
                break;
            }
            int end = start + len;

            for (int i = start; i < end; i++)
            {
                SvgPointF point = vertexPositions[i];

                GdiGraphicsContainer gc = gr.BeginContainer();

                gr.TranslateTransform(point.X, point.Y);

                if (markerElm.OrientType.AnimVal.Equals((ushort)SvgMarkerOrient.Angle))
                {
                    double scaleValue = markerElm.OrientAngle.AnimVal.Value;
                    if (!scaleValue.Equals(0))
                    {
                        gr.RotateTransform((float)scaleValue);
                    }
                }
                else
                {
                    double angle;

                    switch (markerPos)
                    {
                    case SvgMarkerPosition.Start:
                        angle = markerHostElm.GetStartAngle(i);
                        //angle = markerHostElm.GetStartAngle(i + 1);
                        if (vertexPositions.Length >= 2)
                        {
                            SvgPointF pMarkerPoint1 = vertexPositions[start];
                            SvgPointF pMarkerPoint2 = vertexPositions[end];
                            float     xDiff         = pMarkerPoint2.X - pMarkerPoint1.X;
                            float     yDiff         = pMarkerPoint2.Y - pMarkerPoint1.Y;
                            double    angleMarker   = (float)(Math.Atan2(yDiff, xDiff) * 180.0 / Math.PI);
                            if (!angleMarker.Equals(angle))
                            {
                                angle = angleMarker;
                            }
                        }
                        break;

                    case SvgMarkerPosition.Mid:
                        //angle = (markerHostElm.GetEndAngle(i) + markerHostElm.GetStartAngle(i + 1)) / 2;
                        angle = SvgNumber.CalcAngleBisection(markerHostElm.GetEndAngle(i), markerHostElm.GetStartAngle(i + 1));
                        break;

                    default:
                        angle = markerHostElm.GetEndAngle(i - 1);
                        //double angle2 = markerHostElm.GetEndAngle(i);
                        if (vertexPositions.Length >= 2)
                        {
                            SvgPointF pMarkerPoint1 = vertexPositions[start - 1];
                            SvgPointF pMarkerPoint2 = vertexPositions[start];
                            float     xDiff         = pMarkerPoint2.X - pMarkerPoint1.X;
                            float     yDiff         = pMarkerPoint2.Y - pMarkerPoint1.Y;
                            double    angleMarker   = (float)(Math.Atan2(yDiff, xDiff) * 180.0 / Math.PI);
                            if (!angleMarker.Equals(angle))
                            {
                                angle = angleMarker;
                            }
                        }
                        //if (mayHaveCurves)
                        //{
                        //	angle = this.GetAngleAt(start - 1, angle, markerPos, markerHostElm);
                        //}
                        break;
                    }
                    gr.RotateTransform((float)angle);
                }

                // 'viewBox' and 'preserveAspectRatio' attributes
                // viewBox -> viewport(0, 0, markerWidth, markerHeight)
                var      spar = (SvgPreserveAspectRatio)markerElm.PreserveAspectRatio.AnimVal;
                double[] translateAndScale = spar.FitToViewBox((SvgRect)markerElm.ViewBox.AnimVal,
                                                               new SvgRect(0, 0, markerElm.MarkerWidth.AnimVal.Value, markerElm.MarkerHeight.AnimVal.Value));

                //// Warning at this time, refX and refY are relative to the painted element's coordinate system.
                //// We need to move the reference point to the marker's coordinate system
                //float refX = (float)markerElm.RefX.AnimVal.Value;
                //float refY = (float)markerElm.RefY.AnimVal.Value;

                ////if (!(refX.Equals(0) && refY.Equals(0)))
                ////{
                ////	var points = new PointF[] { new PointF(refX, refY) };
                ////	gr.Transform.TransformPoints(points);

                ////	refX = points[0].X;
                ////	refY = points[0].Y;

                ////	gr.TranslateTransform(-refX, -refY);
                ////}

                //if (markerElm.MarkerUnits.AnimVal.Equals((ushort)SvgMarkerUnit.StrokeWidth))
                //{
                //	SvgLength strokeWidthLength = new SvgLength(refElement,
                //                    "stroke-width", SvgLengthSource.Css, SvgLengthDirection.Viewport, "1");
                //	float strokeWidth = (float)strokeWidthLength.Value;
                //	gr.ScaleTransform(strokeWidth, strokeWidth);
                //}

                //gr.TranslateTransform(-(float)(markerElm.RefX.AnimVal.Value * translateAndScale[2]),
                //	-(float)(markerElm.RefY.AnimVal.Value * translateAndScale[3]));

                //gr.ScaleTransform((float)translateAndScale[2], (float)translateAndScale[3]);

                // compute an additional transform for 'strokeWidth' coordinate system
                ISvgAnimatedEnumeration markerUnits = markerElm.MarkerUnits;
                if (markerUnits.AnimVal.Equals((ushort)SvgMarkerUnit.StrokeWidth))
                {
                    SvgLength strokeWidthLength = new SvgLength(refElement,
                                                                "stroke-width", SvgLengthSource.Css, SvgLengthDirection.Viewport, SvgConstants.ValOne);
                    double strokeWidth = strokeWidthLength.Value;
                    if (!strokeWidth.Equals(1))
                    {
                        gr.ScaleTransform((float)strokeWidth, (float)strokeWidth);
                    }
                }

                gr.TranslateTransform(-(float)(markerElm.RefX.AnimVal.Value * translateAndScale[2]),
                                      -(float)(markerElm.RefY.AnimVal.Value * translateAndScale[3]));

                if (!(translateAndScale[2].Equals(1) && translateAndScale[3].Equals(1)))
                {
                    gr.ScaleTransform((float)translateAndScale[2], (float)translateAndScale[3]);
                }

                //				gr.TranslateTransform(point.X, point.Y);

                RectangleF rectClip = RectangleF.Empty;

                if (markerUnits.AnimVal.Equals((ushort)SvgMarkerUnit.StrokeWidth))
                {
                    string overflowAttr = markerElm.GetAttribute("overflow");
                    if (string.IsNullOrWhiteSpace(overflowAttr) ||
                        overflowAttr.Equals("scroll", comparer) || overflowAttr.Equals(CssConstants.ValHidden, comparer))
                    {
                        var     markerClip = RectangleF.Empty;
                        SvgRect clipRect   = (SvgRect)markerElm.ViewBox.AnimVal;
                        if (clipRect != null && !clipRect.IsEmpty)
                        {
                            rectClip = new RectangleF((float)clipRect.X, (float)clipRect.Y,
                                                      (float)clipRect.Width, (float)clipRect.Height);
                        }
                        else if (markerElm.IsSizeDefined)
                        {
                            rectClip = new RectangleF(0, 0,
                                                      (float)markerElm.MarkerWidth.AnimVal.Value, (float)markerElm.MarkerHeight.AnimVal.Value);
                        }
                    }
                }

                if (rectClip.IsEmpty)
                {
                    SetClip(gr);
                }
                else
                {
                    gr.SetClip(rectClip);
                }

                renderer.RenderChildren(markerElm);

                gr.EndContainer(gc);
            }
        }
Exemple #7
0
        public static void CreateMarkers(this SvgMarkerElement svgMarkerElement, SKPath skPath, SKRect skOwnerBounds, ref List <Drawable>?markerDrawables, CompositeDisposable disposable)
        {
            var pathTypes  = skPath.GetPathTypes();
            var pathLength = pathTypes.Count;

            var markerStart = svgMarkerElement.MarkerStart;

            if (markerStart != null && pathLength > 0 && !SvgExtensions.HasRecursiveReference(svgMarkerElement, (e) => e.MarkerStart, new HashSet <Uri>()))
            {
                var marker = SvgExtensions.GetReference <SvgMarker>(svgMarkerElement, markerStart);
                if (marker != null)
                {
                    var refPoint1 = pathTypes[0].Point;
                    var index     = 1;
                    while (index < pathLength && pathTypes[index].Point == refPoint1)
                    {
                        ++index;
                    }
                    var refPoint2 = pathLength == 1 ? refPoint1 : pathTypes[index].Point;
                    CreateMarker(marker, svgMarkerElement, refPoint1, refPoint1, refPoint2, true, skOwnerBounds, ref markerDrawables, disposable);
                }
            }

            var markerMid = svgMarkerElement.MarkerMid;

            if (markerMid != null && pathLength > 0 && !SvgExtensions.HasRecursiveReference(svgMarkerElement, (e) => e.MarkerMid, new HashSet <Uri>()))
            {
                var marker = SvgExtensions.GetReference <SvgMarker>(svgMarkerElement, markerMid);
                if (marker != null)
                {
                    int bezierIndex = -1;
                    for (int i = 1; i <= pathLength - 2; i++)
                    {
                        // for Bezier curves, the marker shall only been shown at the last point
                        if ((pathTypes[i].Type & (byte)PathPointType.PathTypeMask) == (byte)PathPointType.Bezier)
                        {
                            bezierIndex = (bezierIndex + 1) % 3;
                        }
                        else
                        {
                            bezierIndex = -1;
                        }

                        if (bezierIndex == -1 || bezierIndex == 2)
                        {
                            CreateMarker(marker, svgMarkerElement, pathTypes[i].Point, pathTypes[i - 1].Point, pathTypes[i].Point, pathTypes[i + 1].Point, skOwnerBounds, ref markerDrawables, disposable);
                        }
                    }
                }
            }

            var markerEnd = svgMarkerElement.MarkerEnd;

            if (markerEnd != null && pathLength > 0 && !SvgExtensions.HasRecursiveReference(svgMarkerElement, (e) => e.MarkerEnd, new HashSet <Uri>()))
            {
                var marker = SvgExtensions.GetReference <SvgMarker>(svgMarkerElement, markerEnd);
                if (marker != null)
                {
                    var index     = pathLength - 1;
                    var refPoint1 = pathTypes[index].Point;
                    if (pathLength > 1)
                    {
                        --index;
                        while (index > 0 && pathTypes[index].Point == refPoint1)
                        {
                            --index;
                        }
                    }
                    var refPoint2 = pathLength == 1 ? refPoint1 : pathTypes[index].Point;
                    CreateMarker(marker, svgMarkerElement, refPoint1, refPoint2, pathTypes[pathLength - 1].Point, false, skOwnerBounds, ref markerDrawables, disposable);
                }
            }
        }
Exemple #8
0
        public void PaintMarker(GdiGraphicsRenderer renderer, GdiGraphicsWrapper gr,
                                SvgMarkerPosition markerPos, SvgStyleableElement refElement)
        {
            ISharpMarkerHost markerHostElm = (ISharpMarkerHost)refElement;
            SvgMarkerElement markerElm     = (SvgMarkerElement)element;

            SvgPointF[] vertexPositions = markerHostElm.MarkerPositions;
            int         start;
            int         len;

            // Choose which part of the position array to use
            switch (markerPos)
            {
            case SvgMarkerPosition.Start:
                start = 0;
                len   = 1;
                break;

            case SvgMarkerPosition.Mid:
                start = 1;
                len   = vertexPositions.Length - 2;
                break;

            default:
                // == MarkerPosition.End
                start = vertexPositions.Length - 1;
                len   = 1;
                break;
            }

            for (int i = start; i < start + len; i++)
            {
                SvgPointF point = vertexPositions[i];

                GdiGraphicsContainer gc = gr.BeginContainer();

                gr.TranslateTransform(point.X, point.Y);

                if (markerElm.OrientType.AnimVal.Equals((ushort)SvgMarkerOrient.Angle))
                {
                    gr.RotateTransform((float)markerElm.OrientAngle.AnimVal.Value);
                }
                else
                {
                    double angle;

                    switch (markerPos)
                    {
                    case SvgMarkerPosition.Start:
                        angle = markerHostElm.GetStartAngle(i + 1);
                        break;

                    case SvgMarkerPosition.Mid:
                        //angle = (markerHostElm.GetEndAngle(i) + markerHostElm.GetStartAngle(i + 1)) / 2;
                        angle = SvgNumber.CalcAngleBisection(markerHostElm.GetEndAngle(i), markerHostElm.GetStartAngle(i + 1));
                        break;

                    default:
                        angle = markerHostElm.GetEndAngle(i);
                        break;
                    }
                    gr.RotateTransform((float)angle);
                }

                if (markerElm.MarkerUnits.AnimVal.Equals((ushort)SvgMarkerUnit.StrokeWidth))
                {
                    SvgLength strokeWidthLength = new SvgLength(refElement,
                                                                "stroke-width", SvgLengthSource.Css, SvgLengthDirection.Viewport, "1");
                    float strokeWidth = (float)strokeWidthLength.Value;
                    gr.ScaleTransform(strokeWidth, strokeWidth);
                }

                SvgPreserveAspectRatio spar = (SvgPreserveAspectRatio)markerElm.PreserveAspectRatio.AnimVal;
                double[] translateAndScale  = spar.FitToViewBox((SvgRect)markerElm.ViewBox.AnimVal,
                                                                new SvgRect(0, 0, markerElm.MarkerWidth.AnimVal.Value,
                                                                            markerElm.MarkerHeight.AnimVal.Value));


                gr.TranslateTransform(-(float)(markerElm.RefX.AnimVal.Value * translateAndScale[2]),
                                      -(float)(markerElm.RefY.AnimVal.Value * translateAndScale[3]));

                gr.ScaleTransform((float)translateAndScale[2], (float)translateAndScale[3]);

                Clip(gr);

                renderer.RenderChildren(markerElm);

                gr.EndContainer(gc);
            }
        }