protected override AAllShortestPaths <CircleNode, ArrowEdge> Create(
     CircleNodeScene scene)
 {
     return(new BasicAllShortestPaths <CircleNode, ArrowEdge>(
                new DijkstraShortestPath <CircleNode, ArrowEdge>(
                    scene.Graph, this.Directed, this.Reversed)));
 }
Beispiel #2
0
 public SimpleTreeLayoutForCircles(CircleNodeScene scene,
                                   IClusterNode clusterNode)
     : base(scene.Graph, clusterNode)
 {
     this.mScene             = scene;
     this.AdaptToSizeChanges = true;
 }
Beispiel #3
0
 public override void CreateGraph(CircleNodeScene scene,
                                  float rad, float ang)
 {
     this.GenerateWagonWheelGraph(scene, rad, ang, 15,
                                  10f, 50f, false,
                                  false, false, false, false);
 }
Beispiel #4
0
 public SimpleTreeLayoutForCircles(CircleNodeScene scene,
                                   Box2F boundingBox)
     : base(scene.Graph, boundingBox)
 {
     this.mScene             = scene;
     this.AdaptToSizeChanges = true;
 }
 public void RefreshAlgorithm(CircleNodeScene scene)
 {
     if (this.IsDirty)
     {
         this.mAlg = this.Create(scene);
         this.mAlg.Compute();
         this.IsDirty = false;
     }
 }
Beispiel #6
0
 public SCircleLayoutForCircles(CircleNodeScene scene,
                                Box2F boundingBox)
     : base(scene.Graph, boundingBox)
 {
     this.mScene             = scene;
     this.CenterX            = boundingBox.X + boundingBox.W / 2;
     this.CenterY            = boundingBox.Y + boundingBox.H / 2;
     this.AdaptToSizeChanges = true;
 }
Beispiel #7
0
        private void GenerateRandomGraph(CircleNodeScene scene,
                                         float rad, float ang, int minNodes, int maxNodes,
                                         int minEdgesPerNode, int maxEdgeDiff, bool preventSelfLoops)
        {
            Random rnd = new Random(DateTime.Now.Millisecond);
            int    i, count = rnd.Next() % (maxNodes - minNodes) + minNodes;

            CircleNode[] nodes = new CircleNode[count];
            CircleNode   node;

            for (i = 0; i < count; i++)
            {
                node     = new CircleNode(scene, rad, (i + 1).ToString("n00"));
                nodes[i] = node;
            }
            int       j, k, eCount, mod = count - maxEdgeDiff - minEdgesPerNode;
            float     w = 1;
            ArrowEdge edge;

            for (i = 0; i < count; i++)
            {
                node   = nodes[i];
                eCount = rnd.Next() % mod + minEdgesPerNode;
                for (j = 0; j < eCount; j++)
                {
                    k = rnd.Next() % count;
                    while ((preventSelfLoops && k == i) ||
                           scene.Graph.IndexOfEdge(node, nodes[k]) >= 0)
                    {
                        k = rnd.Next() % count;
                    }
                    edge = new ArrowEdge(node, nodes[k], scene, w, ang);
                }
            }

            GraphForms.Box2F bbox = scene.LayoutBBox;
            int cols = (int)Math.Ceiling(Math.Sqrt(nodes.Length * bbox.W / bbox.H));
            int rows = (int)Math.Ceiling(Math.Sqrt(nodes.Length * bbox.H / bbox.W));

            float unit = 50;
            float x, y = this.mCenterY - (unit * (cols - 1) / 2f);

            k = 0;
            for (i = 0; i < rows && k < nodes.Length; i++)
            {
                x = this.mCenterX - (unit * (rows - 1) / 2f);
                for (j = 0; j < cols && k < nodes.Length; j++)
                {
                    nodes[k].SetPosition(x, y);
                    k++;
                    x += unit;
                }
                y += unit;
            }
            scene.UpdateEdges();
        }
Beispiel #8
0
        public SCircleLayoutForCircles(CircleNodeScene scene,
                                       IClusterNode clusterNode)
            : base(scene.Graph, clusterNode)
        {
            this.mScene = scene;
            Box2F bbox = clusterNode.LayoutBBox;

            this.CenterX            = bbox.X + bbox.W / 2;
            this.CenterY            = bbox.Y + bbox.H / 2;
            this.AdaptToSizeChanges = true;
        }
Beispiel #9
0
        public ArrowEdge(CircleNode srcNode, CircleNode dstNode,
                         CircleNodeScene scene, float weight, double angle, string aName)
        {
            this.mSrcNode = srcNode;
            this.mDstNode = dstNode;
            this.mWeight  = weight;
            this.mAngle   = angle * Math.PI / 180.0;
            this.mAName   = aName;

            this.mScene = scene;
            this.mScene.AddItem(this);
            this.mScene.Graph.AddEdge(this, false);
            this.Update();
        }
        public void ColorShortestPath(CircleNodeScene scene)
        {
            int i;

            Digraph <CircleNode, ArrowEdge> .GNode[] nodes
                = scene.Graph.InternalNodes;
            for (i = 0; i < nodes.Length; i++)
            {
                nodes[i].Data.BorderColor = Color.Black;
            }
            int        src = scene.MouseUpHistory[1];
            int        dst = scene.MouseUpHistory[0];
            CircleNode node;

            if (src >= 0 && dst >= 0 && src != dst)
            {
                node             = scene.Graph.NodeAt(src);
                node.BorderColor = sSrcColor;
                node             = scene.Graph.NodeAt(dst);
                node.BorderColor = sDstColor;
                ArrowEdge[] edges = scene.Graph.Edges;
                for (i = 0; i < edges.Length; i++)
                {
                    edges[i].LineColor = Color.Black;
                }
                //string test = this.PrintDistances();
                edges = this.mAlg.TryGetEdgePath(src, dst);
                if (edges != null)
                {
                    for (i = 0; i < edges.Length; i++)
                    {
                        edges[i].LineColor = sPathColor;
                    }
                }
                int[] path = this.mAlg.TryGetNodePath(src, dst);
                if (path != null)
                {
                    for (i = path.Length - 2; i >= 1; i--)
                    {
                        nodes[path[i]].Data.BorderColor = sPathColor;
                    }
                }
            }
            else if (dst >= 0)
            {
                node             = scene.Graph.NodeAt(dst);
                node.BorderColor = sSrcColor;
            }
        }
        public override void Compute(CircleNodeScene scene)
        {
            Digraph <CircleNode, ArrowEdge> .GEdge[] edges
                = scene.Graph.InternalEdges;
            Color color = sLineColors[this.mColor];

            for (int i = 0; i < edges.Length; i++)
            {
                if (edges[i].Data.LineDashStyle == DashStyle.Dash)
                {
                    edges[i].Data.LineColor = color;
                }
            }
            this.mColor = (this.mColor + 1) % sLineColors.Length;
        }
 public override void Compute(CircleNodeScene scene)
 {
     this.mAlg = new DFLongestPath <CircleNode, ArrowEdge>(
         scene.Graph, this.Directed, this.Reversed);
     this.mAlg.Compute();
     Digraph <CircleNode, ArrowEdge> .GEdge[] edges
         = scene.Graph.InternalEdges;
     for (int i = 0; i < edges.Length; i++)
     {
         edges[i].Data.LineColor = Color.Black;
     }
     ArrowEdge[] pEdges = this.mAlg.PathEdges;
     for (int j = 0; j < pEdges.Length; j++)
     {
         pEdges[j].LineColor = Color.Red;
     }
 }
        public override void Compute(CircleNodeScene scene)
        {
            this.mAlg = a(scene);
            this.mAlg.Compute();
            int i;

            Digraph <CircleNode, ArrowEdge> .GEdge[] edges
                = scene.Graph.InternalEdges;
            for (i = 0; i < edges.Length; i++)
            {
                edges[i].Data.LineDashStyle = DashStyle.Solid;
            }
            edges = this.mAlg.SpanningTree.InternalEdges;
            for (i = 0; i < edges.Length; i++)
            {
                edges[i].Data.LineDashStyle = DashStyle.Dash;
            }
        }
Beispiel #14
0
        public override void CreateGraph(CircleNodeScene scene,
                                         float rad, float ang)
        {
            CircleNode n01 = new CircleNode(scene, rad, "n01");
            CircleNode n02 = new CircleNode(scene, rad, "n02");
            CircleNode n03 = new CircleNode(scene, rad, "n03");
            ArrowEdge  e01 = new ArrowEdge(n01, n02, scene, 1, ang);
            ArrowEdge  e02 = new ArrowEdge(n02, n03, scene, 1, ang);
            ArrowEdge  e03 = new ArrowEdge(n03, n01, scene, 1, ang);

            CircleNode n04 = new CircleNode(scene, rad, "n04");
            CircleNode n05 = new CircleNode(scene, rad, "n05");
            ArrowEdge  e04 = new ArrowEdge(n04, n02, scene, 1, ang);
            ArrowEdge  e05 = new ArrowEdge(n04, n03, scene, 1, ang);
            ArrowEdge  e06 = new ArrowEdge(n04, n05, scene, 1, ang);
            ArrowEdge  e07 = new ArrowEdge(n05, n04, scene, 1, ang);

            CircleNode n06 = new CircleNode(scene, rad, "n06");
            CircleNode n07 = new CircleNode(scene, rad, "n07");
            ArrowEdge  e08 = new ArrowEdge(n05, n06, scene, 1, ang);
            ArrowEdge  e09 = new ArrowEdge(n06, n07, scene, 1, ang);
            ArrowEdge  e10 = new ArrowEdge(n07, n06, scene, 1, ang);
            ArrowEdge  e11 = new ArrowEdge(n06, n03, scene, 1, ang);

            CircleNode n08 = new CircleNode(scene, rad, "n08");
            ArrowEdge  e12 = new ArrowEdge(n08, n05, scene, 1, ang);
            ArrowEdge  e13 = new ArrowEdge(n08, n07, scene, 1, ang);
            ArrowEdge  e14 = new ArrowEdge(n08, n08, scene, 1, ang);

            float unit = 50;
            float left = this.mCenterX - 3 * unit;
            float top  = this.mCenterY - unit;

            n01.SetPosition(left + 0 * unit, top + 0 * unit);
            n02.SetPosition(left + 0 * unit, top + 2 * unit);
            n03.SetPosition(left + 2 * unit, top + 0 * unit);
            n04.SetPosition(left + 2 * unit, top + 2 * unit);
            n05.SetPosition(left + 4 * unit, top + 2 * unit);
            n06.SetPosition(left + 4 * unit, top + 0 * unit);
            n07.SetPosition(left + 6 * unit, top + 0 * unit);
            n08.SetPosition(left + 6 * unit, top + 2 * unit);

            scene.UpdateEdges();
        }
 public override void Compute(CircleNodeScene scene)
 {
     scene.ConvexHullColor = Color.Transparent;
     Digraph <CircleNode, ArrowEdge> .GEdge[] edges
         = scene.Graph.InternalEdges;
     for (int i = 0; i < edges.Length; i++)
     {
         edges[i].Data.LineColor     = Color.Black;
         edges[i].Data.LineDashStyle = DashStyle.Solid;
     }
     Digraph <CircleNode, ArrowEdge> .GNode[] nodes
         = scene.Graph.InternalNodes;
     for (int j = 0; j < nodes.Length; j++)
     {
         nodes[j].Data.MarkerColor = Color.Transparent;
         nodes[j].Data.BorderColor = Color.Black;
         nodes[j].Data.TextString  = null;
     }
 }
Beispiel #16
0
        public override void CreateGraph(CircleNodeScene scene,
                                         float rad, float ang)
        {
            CircleNode nA = new CircleNode(scene, rad, "nA");
            CircleNode nB = new CircleNode(scene, rad, "nB");
            CircleNode nC = new CircleNode(scene, rad, "nC");
            CircleNode nD = new CircleNode(scene, rad, "nD");
            CircleNode nE = new CircleNode(scene, rad, "nE");
            CircleNode nF = new CircleNode(scene, rad, "nF");
            CircleNode nG = new CircleNode(scene, rad, "nG");

            ArrowEdge eAB = new ArrowEdge(nA, nB, scene, 7, ang, "eAB");
            ArrowEdge eAD = new ArrowEdge(nA, nD, scene, 4, ang, "eAD");
            ArrowEdge eBC = new ArrowEdge(nB, nC, scene, 11, ang, "eBC");
            ArrowEdge eBD = new ArrowEdge(nB, nD, scene, 9, ang, "eBD");
            ArrowEdge eBE = new ArrowEdge(nB, nE, scene, 10, ang, "eBE");
            ArrowEdge eCE = new ArrowEdge(nC, nE, scene, 5, ang, "eCE");
            ArrowEdge eDE = new ArrowEdge(nD, nE, scene, 15, ang, "eDE");
            ArrowEdge eDF = new ArrowEdge(nD, nF, scene, 6, ang, "eDF");
            ArrowEdge eEF = new ArrowEdge(nE, nF, scene, 12, ang, "eEF");
            ArrowEdge eEG = new ArrowEdge(nE, nG, scene, 8, ang, "eEG");
            ArrowEdge eFG = new ArrowEdge(nF, nG, scene, 13, ang, "eFG");

            //ArrowEdge eDA = new ArrowEdge(nD, nA, scene,  4, ang, "eDA");
            //ArrowEdge eDB = new ArrowEdge(nD, nB, scene,  9, ang, "eDB");

            float unit = 50;
            float left = this.mCenterX - 2 * unit;
            float top  = this.mCenterY - 2 * unit;

            nA.SetPosition(left + 0 * unit, top + 0 * unit);
            nB.SetPosition(left + 2 * unit, top + 1 * unit);
            nC.SetPosition(left + 4 * unit, top + 0 * unit);
            nD.SetPosition(left + 1 * unit, top + 2 * unit);
            nE.SetPosition(left + 3 * unit, top + 2 * unit);
            nF.SetPosition(left + 2 * unit, top + 3 * unit);
            nG.SetPosition(left + 4 * unit, top + 4 * unit);

            scene.UpdateEdges();
        }
        public override void Compute(CircleNodeScene scene)
        {
            this.mAlg = this.Create(scene);
            this.mAlg.Compute();

            /*CircleNode[] comp;
             * CircleNode[][] comps = this.mAlg.Components;
             * int i, j, sC = sLineColors.Length;
             * for (i = 0; i < comps.Length; i++)
             * {
             *  comp = comps[i];
             *  for (j = 0; j < comp.Length; j++)
             *  {
             *      comp[j].BorderColor = sLineColors[i % sC];
             *  }
             * }
             * comp = this.mAlg.Roots;
             * for (i = 0; i < comp.Length; i++)
             * {
             *  comp[i].MarkerColor = sLineColors[i % sC];
             * }/* */
            CircleNode node;
            int        i, sC = sLineColors.Length;
            Digraph <CircleNode, ArrowEdge> graph = scene.Graph;

            int[] compIds = this.mAlg.ComponentIds;
            for (i = 0; i < compIds.Length; i++)
            {
                node             = graph.NodeAt(i);
                node.BorderColor = sLineColors[compIds[i] % sC];
            }
            Digraph <CircleNode, ArrowEdge> .GNode[] roots
                = this.mAlg.ComponentRoots;
            for (i = 0; i < roots.Length; i++)
            {
                roots[i].Data.MarkerColor = sLineColors[i % sC];
            }
        }
Beispiel #18
0
        public CircleNode(CircleNodeScene scene, float radius, string aName)
        {
            this.mScene = scene;

            Digraph <CircleNode, ArrowEdge> graph = scene.Graph;
            int index = graph.IndexOfNode(this);

            if (index < 0)
            {
                graph.AddNode(this);
                index = graph.IndexOfNode(this);
            }
            this.mGraphNode = graph.InternalNodeAt(index);

            this.Radius = radius;
            this.Zvalue = -1;

            this.mScene.AddItem(this);

            this.mAName = aName;

            this.InitializeTextStuff();
        }
        public override void Compute(CircleNodeScene scene)
        {
            this.mAlg = new BCCAlgorithm <CircleNode, ArrowEdge>(
                scene.Graph, this.Reversed);
            this.mAlg.Compute();
            Digraph <CircleNode, ArrowEdge> .GEdge[]   comp;
            Digraph <CircleNode, ArrowEdge> .GEdge[][] comps
                = this.mAlg.Components;
            int i, j, sC = sLineColors.Length;

            for (i = 0; i < comps.Length; i++)
            {
                comp = comps[i];
                for (j = 0; j < comp.Length; j++)
                {
                    comp[j].Data.LineColor = sLineColors[i % sC];
                }
            }
            Digraph <CircleNode, ArrowEdge> .GNode[] nodes
                = this.mAlg.ArticulationNodes;
            for (i = 0; i < nodes.Length; i++)
            {
                nodes[i].Data.MarkerColor = sLineColors[0];
            }
            this.mAlg.ArticulateToLargerCompactGroups();
            Digraph <CircleNode, ArrowEdge> .GNode[][] cGrps
                = this.mAlg.CompactGroups;
            for (i = 0; i < cGrps.Length; i++)
            {
                nodes = cGrps[i];
                for (j = 0; j < nodes.Length; j++)
                {
                    nodes[j].Data.BorderColor = sLineColors[i % sC];
                }
            }
        }
Beispiel #20
0
        public DemoForm()
        {
            InitializeComponent();
            this.mScene             = new CircleNodeScene();
            this.mScene.BoundingBox = new RectangleF(0, 0, 400, 400);
            this.mScene.UpdateBounds();
            this.mScene.AddView(this.graphPanel);

            /*this.mLayouts = new IForceDirectedLayoutAlgorithm[]
             * {
             *  new ElasticLayoutForCircles(this.mScene),
             *  new FRFreeLayoutForCircles(this.mScene),
             *  new FRBoundedLayoutForCircles(this.mScene),
             *  new ISOMLayoutForCircles(this.mScene),
             *  new KKLayoutForCircles(this.mScene),
             *  new LinLogLayoutForCircles(this.mScene),
             *  new FDSCircleLayoutForCircles(this.mScene)
             * };/* */
            this.mLayouts = new LayoutAlgorithm <CircleNode, ArrowEdge>[]
            {
                new ElasticLayoutForCircles(mScene, mScene.LayoutBBox),
                new FRFreeLayoutForCircles(mScene, mScene.LayoutBBox),
                new FRBoundedLayoutForCircles(mScene, mScene.LayoutBBox),
                new ISOMLayoutForCircles(mScene, mScene.LayoutBBox),
                new KKLayoutForCircles(mScene, mScene.LayoutBBox),
                new LinLogLayoutForCircles(mScene, mScene.LayoutBBox),
                new SCircleLayoutForCircles(mScene, mScene.LayoutBBox),
                new BalloonCirclesLayoutForCircles(mScene, mScene.LayoutBBox),
                new BalloonTreeLayoutForCircles(mScene, mScene.LayoutBBox),
                new SimpleTreeLayoutForCircles(mScene, mScene.LayoutBBox)
            };/* */

            /*this.mLayouts = new NewLayoutAlgorithm<CircleNode, ArrowEdge>[]
             * {
             *  new ElasticLayoutForCircles(this.mScene, this.mScene),
             *  new FRFreeLayoutForCircles(this.mScene, this.mScene),
             *  new FRBoundedLayoutForCircles(this.mScene, this.mScene),
             *  new ISOMLayoutForCircles(this.mScene, this.mScene),
             *  new KKLayoutForCircles(this.mScene, this.mScene),
             *  new LinLogLayoutForCircles(this.mScene, this.mScene),
             *  new FDSCircleLayoutForCircles(this.mScene, this.mScene),
             *  new BalloonCirclesLayoutForCircles(this.mScene, this.mScene),
             *  new BalloonTreeLayoutForCircles(this.mScene, this.mScene),
             *  new SimpleTreeLayoutForCircles(this.mScene, this.mScene)
             * };/* */
            this.layoutAlgCMB.Items.AddRange(this.mLayouts);
            this.mPrevLayoutIndex = this.layoutAlgCMB.SelectedIndex;

            this.layoutOnNodeMovedCHK.Checked = this.mScene.LayoutOnNodeMoved;
            this.layoutPausedCHK.Checked      = this.mScene.LayoutPaused;

            this.mStyleAlgs = new StyleAlgorithm[]
            {
                new BCCStyleAlgorithm(),
                new CCStyleAlgorithm(),
                new SCCStyleAlgorithm(),
                new WCCStyleAlgorithm(),
                new BFSpanTreeStyleAlgorithm(),
                new DFSpanTreeStyleAlgorithm(),
                new KruskalSpanTreeStyleAlgorithm(),
                new BoruvkaSpanTreeStyleAlgorithm(),
                new PrimSpanTreeStyleAlgorithm(),
                new DFLongestPathStyleAlgorithm(),
                new AddColorToDashedStyleAlgorithm(),
#if DEBUG
                new DrawConvexHullStyleAlgorithm(),
#endif
                new ClearAllStyleAlgorithm()
            };
            this.styleAlgCMB.Items.AddRange(this.mStyleAlgs);

            this.mGraphCreators = new IGraphCreator[]
            {
                new RandomGraphCreator(),
                new BCCTestGraphCreator(),
                new SCCTestGraphCreator(),
                new MinSpanTreeTestGraphCreator(),
                new SPQRTestGraphCreator(),
                new WagonWheelGraphCreator(),
                new BalloonCirclesTestGraph01(),
                new BalloonCirclesTestGraph02()
            };
            this.graphCreatorCMB.Items.AddRange(this.mGraphCreators);

            this.mShortPathAlgs = new ShortPathColorAlg[]
            {
                new FloydWarshallShortPathColorAlg(),
                new BellManFordShortPathColorAlg(),
                new DijkstraShortPathColorAlg()
            };
            this.shortPathAlgCMB.Items.AddRange(this.mShortPathAlgs);

            this.bShortPathOn           = false;
            this.shortPathOnOffBTN.Text = "On";
            this.bShortPathDirected     = this.shortPathDirectedCHK.Checked;
            this.bShortPathReversed     = this.shortPathReversedCHK.Checked;
            this.mShortPathAlgIndex     = this.shortPathAlgCMB.SelectedIndex;

            IGraphCreator gc = new BCCTestGraphCreator();
            if (this.graphStyleResetOnCreateCHK.Checked)
            {
                this.nodeRadNUM.Value = (decimal)gc.DefaultNodeRad;
                this.edgeAngNUM.Value = (decimal)gc.DefaultEdgeAng;
                gc.CreateGraph(this.mScene,
                               gc.DefaultNodeRad, gc.DefaultEdgeAng);
            }
            else
            {
                gc.CreateGraph(this.mScene,
                               (float)this.nodeRadNUM.Value,
                               (float)this.edgeAngNUM.Value);
            }
            this.RefreshShortPathAlgs();

            this.mScene.NodeMouseUp   += new Action <CircleNode>(sceneNodeMouseUp);
            this.mScene.NodeMoved     += new Action <CircleNode>(sceneNodeMoved);
            this.mScene.LayoutStopped += new EventHandler(sceneLayoutStopped);

            this.bPendingGraphCreation = false;
        }
 public abstract void Compute(CircleNodeScene scene);
 public override void Compute(CircleNodeScene scene)
 {
     scene.ConvexHullColor = sLineColors[this.mColor];
     this.mColor           = (this.mColor + 1) % sLineColors.Length;
 }
Beispiel #23
0
 public ArrowEdge(CircleNode srcNode, CircleNode dstNode,
                  CircleNodeScene scene, float weight)
     : this(srcNode, dstNode, scene, weight, 30, null)
 {
 }
 protected override ISpanningTreeAlgorithm <CircleNode, ArrowEdge> a(
     CircleNodeScene scene)
 {
     return(new PrimMinSpanningTree <CircleNode, ArrowEdge>(
                scene.Graph));
 }
 protected override ISpanningTreeAlgorithm <CircleNode, ArrowEdge> a(
     CircleNodeScene scene)
 {
     return(new DFSpanningTree <CircleNode, ArrowEdge>(
                scene.Graph, this.Directed, this.Reversed));
 }
Beispiel #26
0
 public ArrowEdge(CircleNode srcNode, CircleNode dstNode,
                  CircleNodeScene scene, float weight, string aName)
     : this(srcNode, dstNode, scene, weight, 30, aName)
 {
 }
 protected abstract ISpanningTreeAlgorithm <CircleNode, ArrowEdge> a(
     CircleNodeScene scene);
 protected override ICCAlgorithm <CircleNode, ArrowEdge> Create(
     CircleNodeScene scene)
 {
     return(new WCCAlgorithm <CircleNode, ArrowEdge>(
                scene.Graph, this.Reversed));
 }
 protected abstract ICCAlgorithm <CircleNode, ArrowEdge> Create(
     CircleNodeScene scene);
Beispiel #30
0
 public ArrowEdge(CircleNode srcNode, CircleNode dstNode,
                  CircleNodeScene scene, float weight, double angle)
     : this(srcNode, dstNode, scene, weight, angle, null)
 {
 }