COIN-OR::LEMON - Graph Library

source: lemon/lemon/concepts/graph.h @ 606:c5fd2d996909

Last change on this file since 606:c5fd2d996909 was 606:c5fd2d996909, checked in by Peter Kovacs <kpeter@…>, 10 years ago

Various doc improvements (#248)

  • Rename all the ugly template parameters (too long and/or starting with an underscore).
  • Rename function parameters starting with an underscore.
  • Extend the doc for many classes.
  • Use LaTeX-style O(...) expressions only for the complicated ones.
  • A lot of small unification changes.
  • Small fixes.
  • Some other improvements.
File size: 24.4 KB
Line 
1/* -*- mode: C++; indent-tabs-mode: nil; -*-
2 *
3 * This file is a part of LEMON, a generic C++ optimization library.
4 *
5 * Copyright (C) 2003-2009
6 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7 * (Egervary Research Group on Combinatorial Optimization, EGRES).
8 *
9 * Permission to use, modify and distribute this software is granted
10 * provided that this copyright notice appears in all copies. For
11 * precise terms see the accompanying LICENSE file.
12 *
13 * This software is provided "AS IS" with no warranty of any kind,
14 * express or implied, and with no claim as to its suitability for any
15 * purpose.
16 *
17 */
18
19///\ingroup graph_concepts
20///\file
21///\brief The concept of Undirected Graphs.
22
23#ifndef LEMON_CONCEPTS_GRAPH_H
24#define LEMON_CONCEPTS_GRAPH_H
25
26#include <lemon/concepts/graph_components.h>
27#include <lemon/core.h>
28
29namespace lemon {
30  namespace concepts {
31
32    /// \ingroup graph_concepts
33    ///
34    /// \brief Class describing the concept of Undirected Graphs.
35    ///
36    /// This class describes the common interface of all Undirected
37    /// Graphs.
38    ///
39    /// As all concept describing classes it provides only interface
40    /// without any sensible implementation. So any algorithm for
41    /// undirected graph should compile with this class, but it will not
42    /// run properly, of course.
43    ///
44    /// The LEMON undirected graphs also fulfill the concept of
45    /// directed graphs (\ref lemon::concepts::Digraph "Digraph
46    /// Concept"). Each edges can be seen as two opposite
47    /// directed arc and consequently the undirected graph can be
48    /// seen as the direceted graph of these directed arcs. The
49    /// Graph has the Edge inner class for the edges and
50    /// the Arc type for the directed arcs. The Arc type is
51    /// convertible to Edge or inherited from it so from a directed
52    /// arc we can get the represented edge.
53    ///
54    /// In the sense of the LEMON each edge has a default
55    /// direction (it should be in every computer implementation,
56    /// because the order of edge's nodes defines an
57    /// orientation). With the default orientation we can define that
58    /// the directed arc is forward or backward directed. With the \c
59    /// direction() and \c direct() function we can get the direction
60    /// of the directed arc and we can direct an edge.
61    ///
62    /// The EdgeIt is an iterator for the edges. We can use
63    /// the EdgeMap to map values for the edges. The InArcIt and
64    /// OutArcIt iterates on the same edges but with opposite
65    /// direction. The IncEdgeIt iterates also on the same edges
66    /// as the OutArcIt and InArcIt but it is not convertible to Arc just
67    /// to Edge.
68    class Graph {
69    public:
70      /// \brief The undirected graph should be tagged by the
71      /// UndirectedTag.
72      ///
73      /// The undirected graph should be tagged by the UndirectedTag. This
74      /// tag helps the enable_if technics to make compile time
75      /// specializations for undirected graphs.
76      typedef True UndirectedTag;
77
78      /// \brief The base type of node iterators,
79      /// or in other words, the trivial node iterator.
80      ///
81      /// This is the base type of each node iterator,
82      /// thus each kind of node iterator converts to this.
83      /// More precisely each kind of node iterator should be inherited
84      /// from the trivial node iterator.
85      class Node {
86      public:
87        /// Default constructor
88
89        /// @warning The default constructor sets the iterator
90        /// to an undefined value.
91        Node() { }
92        /// Copy constructor.
93
94        /// Copy constructor.
95        ///
96        Node(const Node&) { }
97
98        /// Invalid constructor \& conversion.
99
100        /// This constructor initializes the iterator to be invalid.
101        /// \sa Invalid for more details.
102        Node(Invalid) { }
103        /// Equality operator
104
105        /// Two iterators are equal if and only if they point to the
106        /// same object or both are invalid.
107        bool operator==(Node) const { return true; }
108
109        /// Inequality operator
110
111        /// \sa operator==(Node n)
112        ///
113        bool operator!=(Node) const { return true; }
114
115        /// Artificial ordering operator.
116
117        /// To allow the use of graph descriptors as key type in std::map or
118        /// similar associative container we require this.
119        ///
120        /// \note This operator only have to define some strict ordering of
121        /// the items; this order has nothing to do with the iteration
122        /// ordering of the items.
123        bool operator<(Node) const { return false; }
124
125      };
126
127      /// This iterator goes through each node.
128
129      /// This iterator goes through each node.
130      /// Its usage is quite simple, for example you can count the number
131      /// of nodes in graph \c g of type \c Graph like this:
132      ///\code
133      /// int count=0;
134      /// for (Graph::NodeIt n(g); n!=INVALID; ++n) ++count;
135      ///\endcode
136      class NodeIt : public Node {
137      public:
138        /// Default constructor
139
140        /// @warning The default constructor sets the iterator
141        /// to an undefined value.
142        NodeIt() { }
143        /// Copy constructor.
144
145        /// Copy constructor.
146        ///
147        NodeIt(const NodeIt& n) : Node(n) { }
148        /// Invalid constructor \& conversion.
149
150        /// Initialize the iterator to be invalid.
151        /// \sa Invalid for more details.
152        NodeIt(Invalid) { }
153        /// Sets the iterator to the first node.
154
155        /// Sets the iterator to the first node of \c g.
156        ///
157        NodeIt(const Graph&) { }
158        /// Node -> NodeIt conversion.
159
160        /// Sets the iterator to the node of \c the graph pointed by
161        /// the trivial iterator.
162        /// This feature necessitates that each time we
163        /// iterate the arc-set, the iteration order is the same.
164        NodeIt(const Graph&, const Node&) { }
165        /// Next node.
166
167        /// Assign the iterator to the next node.
168        ///
169        NodeIt& operator++() { return *this; }
170      };
171
172
173      /// The base type of the edge iterators.
174
175      /// The base type of the edge iterators.
176      ///
177      class Edge {
178      public:
179        /// Default constructor
180
181        /// @warning The default constructor sets the iterator
182        /// to an undefined value.
183        Edge() { }
184        /// Copy constructor.
185
186        /// Copy constructor.
187        ///
188        Edge(const Edge&) { }
189        /// Initialize the iterator to be invalid.
190
191        /// Initialize the iterator to be invalid.
192        ///
193        Edge(Invalid) { }
194        /// Equality operator
195
196        /// Two iterators are equal if and only if they point to the
197        /// same object or both are invalid.
198        bool operator==(Edge) const { return true; }
199        /// Inequality operator
200
201        /// \sa operator==(Edge n)
202        ///
203        bool operator!=(Edge) const { return true; }
204
205        /// Artificial ordering operator.
206
207        /// To allow the use of graph descriptors as key type in std::map or
208        /// similar associative container we require this.
209        ///
210        /// \note This operator only have to define some strict ordering of
211        /// the items; this order has nothing to do with the iteration
212        /// ordering of the items.
213        bool operator<(Edge) const { return false; }
214      };
215
216      /// This iterator goes through each edge.
217
218      /// This iterator goes through each edge of a graph.
219      /// Its usage is quite simple, for example you can count the number
220      /// of edges in a graph \c g of type \c Graph as follows:
221      ///\code
222      /// int count=0;
223      /// for(Graph::EdgeIt e(g); e!=INVALID; ++e) ++count;
224      ///\endcode
225      class EdgeIt : public Edge {
226      public:
227        /// Default constructor
228
229        /// @warning The default constructor sets the iterator
230        /// to an undefined value.
231        EdgeIt() { }
232        /// Copy constructor.
233
234        /// Copy constructor.
235        ///
236        EdgeIt(const EdgeIt& e) : Edge(e) { }
237        /// Initialize the iterator to be invalid.
238
239        /// Initialize the iterator to be invalid.
240        ///
241        EdgeIt(Invalid) { }
242        /// This constructor sets the iterator to the first edge.
243
244        /// This constructor sets the iterator to the first edge.
245        EdgeIt(const Graph&) { }
246        /// Edge -> EdgeIt conversion
247
248        /// Sets the iterator to the value of the trivial iterator.
249        /// This feature necessitates that each time we
250        /// iterate the edge-set, the iteration order is the
251        /// same.
252        EdgeIt(const Graph&, const Edge&) { }
253        /// Next edge
254
255        /// Assign the iterator to the next edge.
256        EdgeIt& operator++() { return *this; }
257      };
258
259      /// \brief This iterator goes trough the incident undirected
260      /// arcs of a node.
261      ///
262      /// This iterator goes trough the incident edges
263      /// of a certain node of a graph. You should assume that the
264      /// loop arcs will be iterated twice.
265      ///
266      /// Its usage is quite simple, for example you can compute the
267      /// degree (i.e. count the number of incident arcs of a node \c n
268      /// in graph \c g of type \c Graph as follows.
269      ///
270      ///\code
271      /// int count=0;
272      /// for(Graph::IncEdgeIt e(g, n); e!=INVALID; ++e) ++count;
273      ///\endcode
274      class IncEdgeIt : public Edge {
275      public:
276        /// Default constructor
277
278        /// @warning The default constructor sets the iterator
279        /// to an undefined value.
280        IncEdgeIt() { }
281        /// Copy constructor.
282
283        /// Copy constructor.
284        ///
285        IncEdgeIt(const IncEdgeIt& e) : Edge(e) { }
286        /// Initialize the iterator to be invalid.
287
288        /// Initialize the iterator to be invalid.
289        ///
290        IncEdgeIt(Invalid) { }
291        /// This constructor sets the iterator to first incident arc.
292
293        /// This constructor set the iterator to the first incident arc of
294        /// the node.
295        IncEdgeIt(const Graph&, const Node&) { }
296        /// Edge -> IncEdgeIt conversion
297
298        /// Sets the iterator to the value of the trivial iterator \c e.
299        /// This feature necessitates that each time we
300        /// iterate the arc-set, the iteration order is the same.
301        IncEdgeIt(const Graph&, const Edge&) { }
302        /// Next incident arc
303
304        /// Assign the iterator to the next incident arc
305        /// of the corresponding node.
306        IncEdgeIt& operator++() { return *this; }
307      };
308
309      /// The directed arc type.
310
311      /// The directed arc type. It can be converted to the
312      /// edge or it should be inherited from the undirected
313      /// arc.
314      class Arc : public Edge {
315      public:
316        /// Default constructor
317
318        /// @warning The default constructor sets the iterator
319        /// to an undefined value.
320        Arc() { }
321        /// Copy constructor.
322
323        /// Copy constructor.
324        ///
325        Arc(const Arc& e) : Edge(e) { }
326        /// Initialize the iterator to be invalid.
327
328        /// Initialize the iterator to be invalid.
329        ///
330        Arc(Invalid) { }
331        /// Equality operator
332
333        /// Two iterators are equal if and only if they point to the
334        /// same object or both are invalid.
335        bool operator==(Arc) const { return true; }
336        /// Inequality operator
337
338        /// \sa operator==(Arc n)
339        ///
340        bool operator!=(Arc) const { return true; }
341
342        /// Artificial ordering operator.
343
344        /// To allow the use of graph descriptors as key type in std::map or
345        /// similar associative container we require this.
346        ///
347        /// \note This operator only have to define some strict ordering of
348        /// the items; this order has nothing to do with the iteration
349        /// ordering of the items.
350        bool operator<(Arc) const { return false; }
351
352      };
353      /// This iterator goes through each directed arc.
354
355      /// This iterator goes through each arc of a graph.
356      /// Its usage is quite simple, for example you can count the number
357      /// of arcs in a graph \c g of type \c Graph as follows:
358      ///\code
359      /// int count=0;
360      /// for(Graph::ArcIt e(g); e!=INVALID; ++e) ++count;
361      ///\endcode
362      class ArcIt : public Arc {
363      public:
364        /// Default constructor
365
366        /// @warning The default constructor sets the iterator
367        /// to an undefined value.
368        ArcIt() { }
369        /// Copy constructor.
370
371        /// Copy constructor.
372        ///
373        ArcIt(const ArcIt& e) : Arc(e) { }
374        /// Initialize the iterator to be invalid.
375
376        /// Initialize the iterator to be invalid.
377        ///
378        ArcIt(Invalid) { }
379        /// This constructor sets the iterator to the first arc.
380
381        /// This constructor sets the iterator to the first arc of \c g.
382        ///@param g the graph
383        ArcIt(const Graph &g) { ignore_unused_variable_warning(g); }
384        /// Arc -> ArcIt conversion
385
386        /// Sets the iterator to the value of the trivial iterator \c e.
387        /// This feature necessitates that each time we
388        /// iterate the arc-set, the iteration order is the same.
389        ArcIt(const Graph&, const Arc&) { }
390        ///Next arc
391
392        /// Assign the iterator to the next arc.
393        ArcIt& operator++() { return *this; }
394      };
395
396      /// This iterator goes trough the outgoing directed arcs of a node.
397
398      /// This iterator goes trough the \e outgoing arcs of a certain node
399      /// of a graph.
400      /// Its usage is quite simple, for example you can count the number
401      /// of outgoing arcs of a node \c n
402      /// in graph \c g of type \c Graph as follows.
403      ///\code
404      /// int count=0;
405      /// for (Graph::OutArcIt e(g, n); e!=INVALID; ++e) ++count;
406      ///\endcode
407
408      class OutArcIt : public Arc {
409      public:
410        /// Default constructor
411
412        /// @warning The default constructor sets the iterator
413        /// to an undefined value.
414        OutArcIt() { }
415        /// Copy constructor.
416
417        /// Copy constructor.
418        ///
419        OutArcIt(const OutArcIt& e) : Arc(e) { }
420        /// Initialize the iterator to be invalid.
421
422        /// Initialize the iterator to be invalid.
423        ///
424        OutArcIt(Invalid) { }
425        /// This constructor sets the iterator to the first outgoing arc.
426
427        /// This constructor sets the iterator to the first outgoing arc of
428        /// the node.
429        ///@param n the node
430        ///@param g the graph
431        OutArcIt(const Graph& n, const Node& g) {
432          ignore_unused_variable_warning(n);
433          ignore_unused_variable_warning(g);
434        }
435        /// Arc -> OutArcIt conversion
436
437        /// Sets the iterator to the value of the trivial iterator.
438        /// This feature necessitates that each time we
439        /// iterate the arc-set, the iteration order is the same.
440        OutArcIt(const Graph&, const Arc&) { }
441        ///Next outgoing arc
442
443        /// Assign the iterator to the next
444        /// outgoing arc of the corresponding node.
445        OutArcIt& operator++() { return *this; }
446      };
447
448      /// This iterator goes trough the incoming directed arcs of a node.
449
450      /// This iterator goes trough the \e incoming arcs of a certain node
451      /// of a graph.
452      /// Its usage is quite simple, for example you can count the number
453      /// of outgoing arcs of a node \c n
454      /// in graph \c g of type \c Graph as follows.
455      ///\code
456      /// int count=0;
457      /// for(Graph::InArcIt e(g, n); e!=INVALID; ++e) ++count;
458      ///\endcode
459
460      class InArcIt : public Arc {
461      public:
462        /// Default constructor
463
464        /// @warning The default constructor sets the iterator
465        /// to an undefined value.
466        InArcIt() { }
467        /// Copy constructor.
468
469        /// Copy constructor.
470        ///
471        InArcIt(const InArcIt& e) : Arc(e) { }
472        /// Initialize the iterator to be invalid.
473
474        /// Initialize the iterator to be invalid.
475        ///
476        InArcIt(Invalid) { }
477        /// This constructor sets the iterator to first incoming arc.
478
479        /// This constructor set the iterator to the first incoming arc of
480        /// the node.
481        ///@param n the node
482        ///@param g the graph
483        InArcIt(const Graph& g, const Node& n) {
484          ignore_unused_variable_warning(n);
485          ignore_unused_variable_warning(g);
486        }
487        /// Arc -> InArcIt conversion
488
489        /// Sets the iterator to the value of the trivial iterator \c e.
490        /// This feature necessitates that each time we
491        /// iterate the arc-set, the iteration order is the same.
492        InArcIt(const Graph&, const Arc&) { }
493        /// Next incoming arc
494
495        /// Assign the iterator to the next inarc of the corresponding node.
496        ///
497        InArcIt& operator++() { return *this; }
498      };
499
500      /// \brief Read write map of the nodes to type \c T.
501      ///
502      /// ReadWrite map of the nodes to type \c T.
503      /// \sa Reference
504      template<class T>
505      class NodeMap : public ReadWriteMap< Node, T >
506      {
507      public:
508
509        ///\e
510        NodeMap(const Graph&) { }
511        ///\e
512        NodeMap(const Graph&, T) { }
513
514      private:
515        ///Copy constructor
516        NodeMap(const NodeMap& nm) : ReadWriteMap< Node, T >(nm) { }
517        ///Assignment operator
518        template <typename CMap>
519        NodeMap& operator=(const CMap&) {
520          checkConcept<ReadMap<Node, T>, CMap>();
521          return *this;
522        }
523      };
524
525      /// \brief Read write map of the directed arcs to type \c T.
526      ///
527      /// Reference map of the directed arcs to type \c T.
528      /// \sa Reference
529      template<class T>
530      class ArcMap : public ReadWriteMap<Arc,T>
531      {
532      public:
533
534        ///\e
535        ArcMap(const Graph&) { }
536        ///\e
537        ArcMap(const Graph&, T) { }
538      private:
539        ///Copy constructor
540        ArcMap(const ArcMap& em) : ReadWriteMap<Arc,T>(em) { }
541        ///Assignment operator
542        template <typename CMap>
543        ArcMap& operator=(const CMap&) {
544          checkConcept<ReadMap<Arc, T>, CMap>();
545          return *this;
546        }
547      };
548
549      /// Read write map of the edges to type \c T.
550
551      /// Reference map of the arcs to type \c T.
552      /// \sa Reference
553      template<class T>
554      class EdgeMap : public ReadWriteMap<Edge,T>
555      {
556      public:
557
558        ///\e
559        EdgeMap(const Graph&) { }
560        ///\e
561        EdgeMap(const Graph&, T) { }
562      private:
563        ///Copy constructor
564        EdgeMap(const EdgeMap& em) : ReadWriteMap<Edge,T>(em) {}
565        ///Assignment operator
566        template <typename CMap>
567        EdgeMap& operator=(const CMap&) {
568          checkConcept<ReadMap<Edge, T>, CMap>();
569          return *this;
570        }
571      };
572
573      /// \brief Direct the given edge.
574      ///
575      /// Direct the given edge. The returned arc source
576      /// will be the given node.
577      Arc direct(const Edge&, const Node&) const {
578        return INVALID;
579      }
580
581      /// \brief Direct the given edge.
582      ///
583      /// Direct the given edge. The returned arc
584      /// represents the given edge and the direction comes
585      /// from the bool parameter. The source of the edge and
586      /// the directed arc is the same when the given bool is true.
587      Arc direct(const Edge&, bool) const {
588        return INVALID;
589      }
590
591      /// \brief Returns true if the arc has default orientation.
592      ///
593      /// Returns whether the given directed arc is same orientation as
594      /// the corresponding edge's default orientation.
595      bool direction(Arc) const { return true; }
596
597      /// \brief Returns the opposite directed arc.
598      ///
599      /// Returns the opposite directed arc.
600      Arc oppositeArc(Arc) const { return INVALID; }
601
602      /// \brief Opposite node on an arc
603      ///
604      /// \return The opposite of the given node on the given edge.
605      Node oppositeNode(Node, Edge) const { return INVALID; }
606
607      /// \brief First node of the edge.
608      ///
609      /// \return The first node of the given edge.
610      ///
611      /// Naturally edges don't have direction and thus
612      /// don't have source and target node. However we use \c u() and \c v()
613      /// methods to query the two nodes of the arc. The direction of the
614      /// arc which arises this way is called the inherent direction of the
615      /// edge, and is used to define the "default" direction
616      /// of the directed versions of the arcs.
617      /// \sa v()
618      /// \sa direction()
619      Node u(Edge) const { return INVALID; }
620
621      /// \brief Second node of the edge.
622      ///
623      /// \return The second node of the given edge.
624      ///
625      /// Naturally edges don't have direction and thus
626      /// don't have source and target node. However we use \c u() and \c v()
627      /// methods to query the two nodes of the arc. The direction of the
628      /// arc which arises this way is called the inherent direction of the
629      /// edge, and is used to define the "default" direction
630      /// of the directed versions of the arcs.
631      /// \sa u()
632      /// \sa direction()
633      Node v(Edge) const { return INVALID; }
634
635      /// \brief Source node of the directed arc.
636      Node source(Arc) const { return INVALID; }
637
638      /// \brief Target node of the directed arc.
639      Node target(Arc) const { return INVALID; }
640
641      /// \brief Returns the id of the node.
642      int id(Node) const { return -1; }
643
644      /// \brief Returns the id of the edge.
645      int id(Edge) const { return -1; }
646
647      /// \brief Returns the id of the arc.
648      int id(Arc) const { return -1; }
649
650      /// \brief Returns the node with the given id.
651      ///
652      /// \pre The argument should be a valid node id in the graph.
653      Node nodeFromId(int) const { return INVALID; }
654
655      /// \brief Returns the edge with the given id.
656      ///
657      /// \pre The argument should be a valid edge id in the graph.
658      Edge edgeFromId(int) const { return INVALID; }
659
660      /// \brief Returns the arc with the given id.
661      ///
662      /// \pre The argument should be a valid arc id in the graph.
663      Arc arcFromId(int) const { return INVALID; }
664
665      /// \brief Returns an upper bound on the node IDs.
666      int maxNodeId() const { return -1; }
667
668      /// \brief Returns an upper bound on the edge IDs.
669      int maxEdgeId() const { return -1; }
670
671      /// \brief Returns an upper bound on the arc IDs.
672      int maxArcId() const { return -1; }
673
674      void first(Node&) const {}
675      void next(Node&) const {}
676
677      void first(Edge&) const {}
678      void next(Edge&) const {}
679
680      void first(Arc&) const {}
681      void next(Arc&) const {}
682
683      void firstOut(Arc&, Node) const {}
684      void nextOut(Arc&) const {}
685
686      void firstIn(Arc&, Node) const {}
687      void nextIn(Arc&) const {}
688
689      void firstInc(Edge &, bool &, const Node &) const {}
690      void nextInc(Edge &, bool &) const {}
691
692      // The second parameter is dummy.
693      Node fromId(int, Node) const { return INVALID; }
694      // The second parameter is dummy.
695      Edge fromId(int, Edge) const { return INVALID; }
696      // The second parameter is dummy.
697      Arc fromId(int, Arc) const { return INVALID; }
698
699      // Dummy parameter.
700      int maxId(Node) const { return -1; }
701      // Dummy parameter.
702      int maxId(Edge) const { return -1; }
703      // Dummy parameter.
704      int maxId(Arc) const { return -1; }
705
706      /// \brief Base node of the iterator
707      ///
708      /// Returns the base node (the source in this case) of the iterator
709      Node baseNode(OutArcIt e) const {
710        return source(e);
711      }
712      /// \brief Running node of the iterator
713      ///
714      /// Returns the running node (the target in this case) of the
715      /// iterator
716      Node runningNode(OutArcIt e) const {
717        return target(e);
718      }
719
720      /// \brief Base node of the iterator
721      ///
722      /// Returns the base node (the target in this case) of the iterator
723      Node baseNode(InArcIt e) const {
724        return target(e);
725      }
726      /// \brief Running node of the iterator
727      ///
728      /// Returns the running node (the source in this case) of the
729      /// iterator
730      Node runningNode(InArcIt e) const {
731        return source(e);
732      }
733
734      /// \brief Base node of the iterator
735      ///
736      /// Returns the base node of the iterator
737      Node baseNode(IncEdgeIt) const {
738        return INVALID;
739      }
740
741      /// \brief Running node of the iterator
742      ///
743      /// Returns the running node of the iterator
744      Node runningNode(IncEdgeIt) const {
745        return INVALID;
746      }
747
748      template <typename _Graph>
749      struct Constraints {
750        void constraints() {
751          checkConcept<IterableGraphComponent<>, _Graph>();
752          checkConcept<IDableGraphComponent<>, _Graph>();
753          checkConcept<MappableGraphComponent<>, _Graph>();
754        }
755      };
756
757    };
758
759  }
760
761}
762
763#endif
Note: See TracBrowser for help on using the repository browser.