c      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ Internal functions Ivan.Miljenovic@gmail.com  First character of a non-quoted  must match this. The rest of a non-quoted  must match this. .Determine if this String represents a number. This assumes that  is . 0Determine if this String represents an integer. :Graphviz requires double quotes to be explicitly escaped. +Remove explicit escaping of double quotes. KThe following are Dot keywords and are not valid as labels, etc. unquoted.  Fold over s; first param is for  , second for .  Helper functions for Parsing. Ivan.Miljenovic@gmail.com6A ReadS-like type alias. ?Parse the required value, returning also the rest of the input   that hasn't been parsed. 7Use this when you do not want numbers to be treated as  values. *Used when quotes are explicitly required;  ?Parse a floating point number that actually contains decimals. 6Consume all whitespace and newlines until a line with > non-whitespace is reached. The whitespace on that line is  not consumed. ?Parses and returns all characters up till the end of the line, 1 then skips to the beginning of the next line. !"#$For 6-like data structures where the presence of the field 1 name without a value implies a default value. %&'()*+,9Remove unparseable features of Dot, such as comments and D multi-line strings (which are converted to single-line strings). @Parse out comments and make quoted strings spread over multiple 4 lines only over a single line. Should parse the entire input  . Parse -style comments. Parse * ... *-style comments.  Parse out <newline> from a quoted string. L  !"#$%&'()*+,-   )*+ !"#$%&'(,+  !"#$%&'()*+,/Helper functions for converting to Dot format. Ivan.Miljenovic@gmail.com-DA class used to correctly print parts of the Graphviz Dot language.  Minimal implementation is .. .>The unquoted representation, for use when composing values to $ produce a larger printing value. />The actual quoted representation; this should be quoted if it A contains characters not permitted a plain ID String, a number  or it is not an HTML string.  Defaults to .. 0:The correct way of representing a list of this value when ? printed; not all Dot values require this to be implemented. 1 Defaults to Haskell-like list representation. 1The quoted form of 0; defaults to wrapping & double quotes around the result of 0 (since the ? default implementation has characters that must be quoted). 21A type alias to indicate what is being produced. 3"Correctly render Graphviz output. 4AConvert to DotCode; note that this has no indentation, as we can F only have one of indentation and (possibly) infinite line lengths. Check to see if this  needs to be quoted or not. 5)Escape quotes in Strings that need them. EEscape quotes and quote Strings that need them (including keywords). 6786 -./012345678 23-./0145678 -./01./012345678/Helper functions for converting to Dot format. Ivan.Miljenovic@gmail.com_9AThe X11 colors that Graphviz uses. Note that these are slightly  different from the "normal"% X11 colors used (e.g. the inclusion  of Crimson ). Graphviz'(s list of colors also duplicated almost  all Gray colors with Grey ones; parsing of an ^9  which is specified using "grey" will succeed, even for those  that don'$t have the duplicate spelling (e.g. DarkSlateGray1). :;<=>?@ABCDEFGHIJKLMNOPQREquivalent to setting Style [SItem Invisible []]. STUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\@Defining a color for use with Graphviz. Note that named colors  have been split up into ^9s and those based upon the  Brewer color schemes. ]This value should be between 1  and the level of the i  being used. ^_The `, a and b values must all  be 0 <= x <=1. `abcdefghi+All of these have a minimum level value of 3, with a maximum  of 9 unless otherwise specified. jklmn Maximum of 11. o Maximum of 12. p Maximum of 8. qrs Maximum of 11. t Maximum of 11. uv Maximum of 11$; note that the last two are listed  after the u values in the  documentation. w Maximum of 11$; note that the last two are listed  first. xyz Maximum of 11$; note that the last two are listed  after the y values in the  documentation. {|} Maximum of 11. ~ Maximum of 11.  Maximum of 8.  Maximum of 12.  Maximum of 8.  Maximum of 11.  Maximum of 8. =This represents the color schemes that Graphviz accepts. As  mentioned above, these are not used for actual parsing or  printing. The value of the  scheme number  depends on  the name.   Attempt to convert a \ into a   value with an alpha  channel. The use of   is because ] values 4 cannot be converted without knowing which actual i and % level color scheme is being used.  Convert an ^9 to its equivalent   value. Note  that it uses  because of R ; all other  ^9 values are completely opaque.  Convert a   value to an e \.  Convert an  to an c \. The exception to  this is for any  which has alphaChannel ac == 0;  these are converted to  X11Color R (note that the   instance for such an  is " transparent"). The  of a  value. [9:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~^i~}|{zyxwvutsrqponmlkj\ec_^]fghfghd`ab9[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('&%$#"!      ~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('&%$#"!      ~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:[9"[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('&%$#"!      ~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('&%$#"!      ~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;::;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\ec_^]fghfghd`ab]^_`abcdefghi#~}|{zyxwvutsrqponmlkjjklmnopqrstuvwxyz{|}~'Definition of the Graphviz attributes. Ivan.Miljenovic@gmail.comOnly valid for Nodes. Device Dependent Nodes and Clusters  Nodes only Nodes and Clusters Nodes and Edges Nodes and Edges Nodes and Edges Nodes and Edges Nodes and Edges Has synonym of none. Has synonyms of rect and  rectangle. GSpecify the root node either as a Node attribute or a Graph attribute. For Graphs only For Nodes only For Nodes only     @The number of points in the list must be equivalent to 1 mod 3; " note that this is not checked.  +Upper-case first character is major order; / lower-case second character is minor order. -Controls how (and if) edges are represented.  fdp only  !Sort by cols, sort  by user, number of  rows/cols "#$%&,If non-negative, then packs; otherwise doesn't. '()*+,-?The list represent (Separator, Name). You should not have any # quote characters for any of the s, since there are  parsing problems with them. ./1You should not have any quote characters for the 0 option,  as it won't be parseable. 01234567 Only when mode == J 89:Only when sfdp is available,  is non-negative ;<=>?@ABCDEFGHIJKLMN Either a  or a A?. OPQ Only when mode == J. RSTUVWXYZ[\]^_`abcBRepresents which side (when looking towards the node the arrow is  pointing to) is drawn. defghij"What modifications to apply to an n. klmnopqrstuvwxDot; has a basic grammar of arrow shapes which allows usage of ; up to 1,544,761 different shapes from 9 different basic  n5s. Note that whilst an explicit list is used in the  definition of x), there must be at least one tuple and a C maximum of 4 (since that is what is required by Dot). For more  information, see:  (http://graphviz.org/doc/info/arrows.html >The 19 basic arrows shown on the overall attributes page have : been defined below as a convenience. Parsing of the 5 8 backward-compatible special cases is also supported. yz)No checks are placed on the content of a  z value; however, 2 you should ensure that it does not contain any '>' or '<' C characters; Graphviz might care about escaping other characters B properly, but for the purposes of this library the presence of 7 these characters will make it harder to parse URLs. {|}Some "s (mainly label-like ones) take a  argument : that allows for extra escape codes. This library doesn' t do any E extra checks or special parsing for these escape codes, but usage  of } rather than  indicates that the Graphviz ; tools will recognise these extra escape codes for these  s. 8The extra escape codes include (note that these are all s):  \N- Replace with the name of the node (for Node s). \G. Replace with the name of the graph (for Node s) ? or the name of the graph or cluster, whichever is 5 applicable (for Graph, Cluster and Edge s). \E6 Replace with the name of the edge, formed by the two 9 adjoining nodes and the edge type (for Edge s). \T2 Replace with the name of the tail node (for Edge  s). \H2 Replace with the name of the head node (for Edge  s). \L Replace with the object's label (for all s).  Also, if the  in question is B,  or  , then \n, \l and \r split the label into lines > centered, left-justified and right-justified respectively. ~,These attributes have been implemented in a  permissive manner: C that is, rather than split them up based on which type of value G they are allowed, they have all been included in the one data type, A with functions to determine if they are indeed valid for what  they're being applied to. To interpret the  Valid for listings:  G Valid for Graphs. C Valid for Clusters. S+ Valid for Sub-Graphs (and also Clusters). N Valid for Nodes. E Valid for Edges. The Default7 listings are those that the various Graphviz commands  use if that  isn'$t specified (in cases where this is  none, this is equivalent to a  value; that is, no value  is used). The Parsing Default" listings represent what value is  used (i.e. corresponds to  ) when the  name is  listed on its own in Dot source code.  Valid for: N; Default: 0.0; Minimum:  -MAXFLOAT, -1000  Valid for: N; Default: 0.75; Minimum: 0.01  Valid for: E; Default: 1.0; Minimum: 0 (dot), 1 (neato,fdp,sfdp)  Valid for: G; Default: 0.05; Minimum: 0.0; Notes : not dot  Valid for: G; Default: none  Valid for: N; Notes : write only  Valid for: G; Parsing Default: ; Notes: bitmap output only  Valid for: NEC; Default: ""; Notes: svg, cmap only  Valid for: ENGC; Default: none; Notes: svg, map only  Valid for: E; Default: ""; Notes: svg, cmap only  Valid for: E; Default: none; Notes: svg, map only  Valid for: E; Default : center  Valid for: E; Default: ""  Valid for: E; Default: ; Parsing Default:   Valid for: E; Default: ""; Notes: svg, map only  Valid for: ENC  Valid for: G; Default: ""; Notes : svg only  Valid for: G; Default: ""; Notes: fdp, neato only  Valid for: G; Parsing Default:   Valid for: GCN; Default: 0; Minimum: 0  Valid for: G; Default: ; Notes : sfdp only  Valid for: N; Default: 0.0; Minimum: -100.0  Valid for: G  Valid for: N; Default: 4; Minimum: 0  Valid for: ENG; Default: 0; Minimum: 0; Notes : dot only  Valid for: N; Default:   Valid for: N; Default: ""  Valid for: G; Default: +4; Notes : not dot  Valid for: G; Default: 30; Notes : dot only  Valid for: N; Default: 8 (output), 20 (overlap and image maps)  Valid for: E; Default: ""; Notes : dot only  Valid for: E; Default: ""; Notes : dot only  Valid for: G; Default: 0  Valid for: GN; Default:  "" (graphs),  (nodes); Parsing Default: ; Notes: circo, twopi only  Valid for: G; Default: 1.0; Minimum: 0.0; Notes : sfdp only  Valid for: G; Default: ; Parsing Default: ; Notes : dot only  Valid for: N; Default: ; Parsing Default:   Valid for: N; Notes : write only  Valid for: G  Valid for: S; Notes : dot only  Valid for: G; Default: 0.5 (dot), 1.0 (twopi); Minimum: 0.02; Notes: twopi, dot only  Valid for: G; Default: TB; Notes : dot only  Valid for: G; Default: 0.0; Minimum: 0.0  Valid for: G; Default:  ; Parsing Default:  ; Notes : sfdp only  Valid for: EN  Valid for: N; Default: ; Parsing Default: ; Notes: fdp, neato only  Valid for: NC; Default: shape default (nodes), 1 (clusters); Minimum: 0  Valid for: CNE; Default: 1.0; Minimum: 0.0  Valid for: C; Default:  X11Color E  Valid for: G  Valid for: G; Default: BL  Valid for: G; Default: P 0.0555 (4 points)  Valid for: G; Default: ; Parsing Default: (; Notes : not dot  Valid for: G; Default: $; Notes : not dot  Valid for: G; Default: >; Parsing Default: >; Notes : not dot  Valid for: G; Default: -4; Minimum: -1.0e10; Notes : prism only  Valid for: G; Default: ,  Valid for: N; Default: 0.0; Minimum: 360.0  Valid for: G; Default: ""; Notes : dot only  Valid for: G; Notes : dot only  Valid for: G; Notes : dot only  Valid for: G; Default: ; Parsing Default: ; Notes : not dot  Valid for: GCNE; Default: ; Parsing Default:   Valid for: G; Default: 0.25; Minimum: 0.02; Notes : dot only  Valid for: G; Default: ; Parsing Default: ; Notes*: neato only; requires the Mosek software  Valid for: G; Default: M; Notes : neato only  Valid for: G; Default: H; Notes : neato only  Valid for: E; Default: 1; Minimum: 0; Notes : dot only  Valid for: G; Default: 1.0; Minimum: 0.0; Notes : circo only  Valid for: G; Default: 1.0; Notes : dot only  Valid for: G; Default: 100 * # nodes (mode == L), 200 (mode == M), 600 (fdp); Notes: fdp, neato only  Valid for: NG; Default: device-dependent  Valid for: E; Default: ""; Notes : dot only  Valid for: EGC; Notes : write only  Valid for: E; Default: ""; Notes : dot only  Valid for: G; Default: MAXINT; Minimum: 0; Notes : sfdp only  Valid for: G; Default: 0.0; Notes : neato only  Valid for: E; Default: 1.0 (neato), 0.3 (fdp); Notes: fdp, neato only  Valid for: G; Default: ""  Valid for: EN; Default: ""  Valid for: G; Default: ""  Valid for: G; Default: " :t"  Valid for: G; Default: ; Parsing Default:   Valid for: ENGC; Default: D "N" (nodes), D "" (otherwise)  Valid for: E; Default: ""; Notes: svg, cmap only  Valid for: E; Default: none; Notes: svg, map only  Valid for: GCN; Default:  (clusters),  (root graphs),  (nodes)  Valid for: GC; Default:   Valid for: E; Default: 14.0; Minimum: 1.0  Valid for: E; Default: " Times-Roman"  Valid for: E; Default:  X11Color E  Valid for: E; Default: ; Parsing Default:   Valid for: E; Default: 1.0; Minimum: 0.0  Valid for: E; Default: -25.0; Minimum: -180.0  Valid for: E; Default: ""; Notes: svg, map only  Valid for: N; Default: ; Parsing Default:   Valid for: N; Default: ""  Valid for: GNE; Default: ""; Notes: svg, postscript, map only  Valid for: N; Default: 0.5; Minimum: 0.02  Valid for: E; Default: ""; Notes: svg, cmap only  Valid for: E; Default: none; Notes: svg, map only  Valid for: E; Default:    Valid for: E; Default: ""  Valid for: E; Default: ; Parsing Default:   Valid for: E; Default: ""; Notes: svg, map only  Valid for: N; Default: ""; Notes : dot only  Valid for: ENGC; Default: 14.0; Minimum: 1.0  Valid for: G; Default: system-dependent  Valid for: G; Default: ""; Notes : svg only  Valid for: ENGC; Default: " Times-Roman"  Valid for: ENGC; Default:  X11Color E  Valid for: N; Default: ; Parsing Default:   Valid for: NC; Default:  X11Color ) (nodes),  X11Color E (clusters)  Valid for: G; Default: +3; Notes : not dot  Valid for: G; Default: .0001 * # nodes (mode == L), .0001 (mode == M); Notes : neato only  Valid for: E; Default: ""; Notes: svg, cmap only  Valid for: E; Default: none; Notes: svg, map only  Valid for: E; Default: ""; Notes: svg, map only  Valid for: G; Default: 96.0, 0.0; Notes: svg, bitmap output only; " resolution" is a synonym  Valid for: N; Default: 0.0; Minimum: -100.0  Valid for: G; Default: S; Parsing Default: T; Notes : neato only  Valid for: E; Default: Y (directed), V (undirected)  Valid for: G; Default: 2; Minimum: 2; Notes: sfdp, fdp, neato only  Valid for: G; Default: 2; Minimum: 2; Notes: sfdp, fdp, neato only  Valid for: G; Default: 1+(avg. len)*sqrt(|V|); Minimum: epsilon; Notes : neato only  Valid for: E; Default: ; Parsing Default:   Valid for: E; Default: ; Parsing Default: ; Notes : dot only  Valid for: G; Default: ; Parsing Default:   Valid for: G; Default: ; Parsing Default: ; Notes : dot only  Valid for: ENG; Default: ""  Valid for: ENC; Default:  X11Color E  Valid for: ENCG; Default:   Valid for: G; Default: ]; Notes : dot only  Valid for: G; Default: "UTF-8"  Valid for: G; Default: ; Parsing Default:   Valid for: GC; Default : X11Color R  Valid for: G; Notes : write only   Valid for: G; Notes : dot only   Valid for: E; Default:    Valid for: E; Default: 1.0; Minimum: 0.0   Valid for: E; Default:    Valid for: ENGC; Default: none; Notes: svg, postscript, map only  Valid for: GC; Default: 0.3; Minimum: 0; Notes: sfdp, fdp only  Valid for: G; Default: 0.99; Minimum: 0.0; Notes : neato only :Determine if this Attribute is valid for use with Graphs. <Determine if this Attribute is valid for use with Clusters. =Determine if this Attribute is valid for use with SubGraphs. 9Determine if this Attribute is valid for use with Nodes. 9Determine if this Attribute is valid for use with Edges.  !"#$%&'(Apply no modifications to an n. )i and d *+9:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+     ~}z{|xy`ba^_Z]\[UYXWVQTSRNPOIMLKJEHGFBDC?A@6>=<;:987354/210-.),+*%('& $#"!     nwvutsrqpojklmgihcfed#"'$ !%&()*+            $#"!!"#$%('&&'(),+**+,-../210012354456>=<;:987789:;<=>?A@@ABDCCDEHGFFGHIMLKJJKLMNPOOPQTSRRSTUYXWVVWXYZ]\[[\]^__`baabcfeddefgihhijklmklmn wvutsrqpoopqrstuvwxyyz{|{|}~           !"#$%&'()*+"Definition of the Graphviz types. Ivan.Miljenovic@gmail.coma, An edge in PO. -./012 A node in PO) is either a singular node, or a cluster 2 containing nodes (or more clusters) within it. + At the moment, clusters are not parsed. 3456789:;'Represents a list of top-level list of  s for the  entire graph/sub-graph. Note that > also applies to  6s. Note that Dot allows a single  to be listen on a line; 6 if this is the case then when parsing, the type of  it " is determined and that type of GlobalAttribute is created. <=>?@ABCDEFAA polymorphic type that covers all possible ID values allowed by % Dot syntax. Note that whilst the  and -  instances for ( will properly take care of the special 9 cases for numbers, they are treated differently here. GHIJKUsed to record invalid  usage. A  value denotes # that it was used in an explicit 32 or -, usage;   means that it was used in a ; value. LMNO4The internal representation of a graph in Dot form. PQIf , no multiple edges are drawn. RSTU)A strict graph disallows multiple edges. VSet the ID of the graph. WReturn all the 32s contained within this PO. Note < that it does not yet return all implicitly defined nodes  contained only within -,s. XReturn all the -,s contained within this PO. Y The actual Dot code for a PO. Note that it is expected  that Z . Y ==   (this might not A be true the other way around due to un-parseable components). Z5Parse a limited subset of the Dot language to form a PO # (that is, the caveats listed in Data.GraphViz.Attributes aside, 5 Dot graphs are parsed if they match the layout of PO). 0Also removes any comments, etc. before parsing. [Check if all the s are being used correctly. \ Return detectable errors in the PO. !"#$%&'()*+,-.;The function represents which function to use to check the  > values. /0123456Print the actual ID for a 6. 789:;<=>?@ABCDEFGHIJKLMNOP1,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\3OPQRSTYZVUWXKNML[\FJIHG@ABCDE;>=<???6789:2345,-./011,-./01-./0123453456789:789:;>=<???<=>?@ABCDEABCDEFJIHGGHIJKNMLLMNOPQRSTPQRSTUVWXYZ[\$Functions to run Graphviz commands. Ivan.Miljenovic@gmail.com;],Represents the result of running a command. ^_`Unlike c', these items do not produce an output C file; instead, they directly draw a canvas (i.e. a window) with  the resulting image. abc:The possible Graphviz output formats (that is, those that  actually produce a file). dWireless BitMap format; " monochrome format usually used ! for mobile computing devices. e"Virtual Reality Modeling Language $ format; requires nodes to have a   attribute. fCompressed VML format; i is  usually preferred. gVector Markup Language; j is  usually preferred. hTagged Image File Format. iCompressed SVG format. j!Scalable Vector Graphics format. kPostScript for PDF. l PostScript. m#Portable Network Graphvics format. nAs for o, but provides port % names on head and tail nodes when  applicable. oSimple text format. pPortable Document Format. qThe JPEG image format. rAs for t, except only ! rectangles are used as active  areas. sAs for u, except only ! rectangles are used as active  areas. tClient-side imagemap. uServer-side imagemap. vIcon image file format. wGraphics Interchange Format. xCompressed version of y. yInternal GD library format. zFIG graphics language. {Encapsulated PostScript. |As with }, but provides $ even more information on how the  graph is drawn. } Reproduces the input along with  layout information. ~"Pretty-printed Dot output with no  layout performed. Windows Bitmap Format. QBThis class is for those data types that are valid options for the " Graphviz tools to use with the -T argument. RS?The available Graphviz commands. The following directions are B based upon those in the Graphviz man page (available online at   !http://graphviz.org/pdf/dot.1.pdf, or if installed on your  system  man graphviz)). Note that any command can be used on ( both directed and undirected graphs.  For symmetric layout of graphs. For circular layout of graphs. For radial layout of graphs.  For symmetric layouts of graphs " (ideal for undirected graphs). "For hierachical graphs (ideal for  directed graphs). T)The default command for directed graphs. +The default command for undirected graphs. @The appropriate (default) Graphviz command for the given graph. U"A default file extension for each c. V<Return the error if there is one, otherwise return Success. FRun the recommended Graphviz command on this graph, saving the result 3 to the file provided (note: file extensions are not checked). ARun the chosen Graphviz command on this graph, saving the result 3 to the file provided (note: file extensions are not checked). .Append the default extension for the provided c to  the provided W for the output file. <Run the chosen Graphviz command on this graph, but send the 5 result to the given handle rather than to a file. Note that the X -> Y a function must fully consume  the input from the X;  is an version of  Z that will ensure this happens. &If the command was unsuccessful, then  Left error is returned. Which command to run The PO to use The c type Extract the output The error or the result. [\Store the result of the X consumption into the ]. BRun the chosen Graphviz command on this graph and render it using  the given canvas type. ARun the recommended Graphviz command on this graph and render it  using the given canvas type.  A version of Z& that fully evaluates the contents of  the X' (that is, until EOF is reached). The X is  not closed. 3]^_`abcdefghijklmnopqrstuvwxyz{|}~3c~}|{zyxwvutsrqponmlkjihgfed`ba]_^3]_^^_`baabc~}|{zyxwvutsrqponmlkjihgfeddefghijklmnopqrstuvwxyz{|}~ 1Definition of the clustering types for Graphviz. Ivan.Miljenovic@gmail.com^$A tree representation of a cluster. _`5Define into which cluster a particular node belongs. . Clusters can be nested to arbitrary depth. Indicates that the   is in  the Cluster c. (Indicates the actual Node in the Graph. a Create the Dot% representation for the given graph. b<Convert a single node cluster into its tree representation. cTwo nodes are in the same default" cluster; otherwise check if they  are in the same cluster. dFSingleton nodes come first, and then ordering based upon the cluster. eExtract the sub-trees. fCombine clusters. g5Convert the cluster representation of the trees into 32s  and 6s (with 8 = , and  9 = ). h Convert this ^ into its Dot representation. aaGraphviz bindings for Haskell. Ivan.Miljenovic@gmail.comi,Determine if the given graph is undirected. j*Determine if the given graph is directed. Convert a graph to Graphviz's Dot format. The  value is   for directed graphs,  otherwise. Convert a graph to Graphviz's Dot format with automatic  direction detection. Convert a graph to Dot1 format, using the specified clustering function ! to group nodes into clusters. . Clusters can be nested to arbitrary depth.  The  argument is  for directed graphs,  otherwise. Convert a graph to Dot1 format, using the specified clustering function ! to group nodes into clusters. . Clusters can be nested to arbitrary depth. . Graph direction is automatically inferred. 9Run the appropriate Graphviz command on the graph to get A positional information and then combine that information back C into the original graph. Note that for the edge information to C be parsed properly when using multiple edges, each edge between + two nodes needs to have a unique label. The  argument is  for directed graphs,  2 otherwise. Directed graphs are passed through dot, and  undirected graphs through neato. k9Run the appropriate Graphviz command on the graph to get A positional information and then combine that information back  into the original graph. +Graph direction is automatically inferred. ?Run the appropriate Graphviz command on the clustered graph to E get positional information and then combine that information back C into the original graph. Note that for the edge information to C be parsed properly when using multiple edges, each edge between + two nodes needs to have a unique label. The  argument is  for directed graphs,  2 otherwise. Directed graphs are passed through dot, and  undirected graphs through neato. ?Run the appropriate Graphviz command on the clustered graph to E get positional information and then combine that information back  into the original graph. +Graph direction is automatically inferred. Pass the graph through  with no  s. This  is an Y& action, however since the state doesn' t change it's  safe to use l to convert this to a normal  function. The  argument is  for directed graphs,  2 otherwise. Directed graphs are passed through dot, and  undirected graphs through neato. Pass the graph through  with no  s. This  is an Y& action, however since the state doesn' t change it's  safe to use l to convert this to a normal  function. /The graph direction is automatically inferred. !Pass the clustered graph through  with no  s. This is an Y! action, however since the state  doesn' t change it's safe to use l to convert this  to a normal function. The  argument is  for directed graphs,  2 otherwise. Directed graphs are passed through dot, and  undirected graphs through neato. !Pass the clustered graph through  with no  s. This is an Y! action, however since the state  doesn' t change it's safe to use l to convert this  to a normal function. /The graph direction is automatically inferred. Pretty-print the PO by passing it through the ~  output type (which produces " canonical" output). This is  required because the printIt function in  Data.GraphViz.Types.Printing no longer uses indentation to - ensure the Dot code is printed correctly. The l d version of . Graphviz should D always produce the same pretty-printed output, so this should be  safe. j9:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~m     !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefgChijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHGIJKLMNOPQRSTUVWXYZ[\]^_`abcdeefghijklmnopqrstuvwxyz{|}~ %-(>LIf      !"#$$%&'())*+,-./0123456789:;<=>?@ABCDEEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~   S       ?  ! "#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcd e f g h i j k l m n opqrZstgraphviz-2999.7.0.0Data.GraphViz.Types.ParsingData.GraphViz.Types.PrintingData.GraphViz.Attributes.ColorsData.GraphViz.AttributesData.GraphViz.TypesData.GraphViz.Commands Data.GraphVizData.GraphViz.Types.InternalData.GraphViz.Types.Clustering isNumString isIntStringParseDot parseUnqtparse parseUnqtList parseListParseparseItonlyBool numString stringBlock quotedStringparseStrictFloat parseAndSpacestring stringRep stringRepsstrings hasString characternoneOf whitespace whitespace'optionalQuotedStringoptionalQuoted quotedParseorQuote quoteCharnewlinenewline' skipToNewline parseField parseFieldsparseFieldBoolparseFieldsBool parseFieldDefparseFieldsDefcommaSep commaSepUnqt commaSep' parseComma tryParseList tryParseList' preProcessPrintDotunqtDottoDot unqtListToDot listToDotDotCode renderDotprintIt addQuoteswrapcommaDel printFieldX11Color YellowGreenYellow4Yellow3Yellow2Yellow1Yellow WhiteSmokeWhiteWheat4Wheat3Wheat2Wheat1Wheat VioletRed4 VioletRed3 VioletRed2 VioletRed1 VioletRedViolet Turquoise4 Turquoise3 Turquoise2 Turquoise1 Turquoise TransparentTomato4Tomato3Tomato2Tomato1TomatoThistle4Thistle3Thistle2Thistle1ThistleTan4Tan3Tan2Tan1Tan SteelBlue4 SteelBlue3 SteelBlue2 SteelBlue1 SteelBlue SpringGreen4 SpringGreen3 SpringGreen2 SpringGreen1 SpringGreenSnow4Snow3Snow2Snow1Snow SlateGray4 SlateGray3 SlateGray2 SlateGray1 SlateGray SlateBlue4 SlateBlue3 SlateBlue2 SlateBlue1 SlateBlueSkyBlue4SkyBlue3SkyBlue2SkyBlue1SkyBlueSienna4Sienna3Sienna2Sienna1Sienna SeaShell4 SeaShell3 SeaShell2 SeaShell1SeaShell SeaGreen4 SeaGreen3 SeaGreen2 SeaGreen1SeaGreen SandyBrownSalmon4Salmon3Salmon2Salmon1Salmon SaddleBrown RoyalBlue4 RoyalBlue3 RoyalBlue2 RoyalBlue1 RoyalBlue RosyBrown4 RosyBrown3 RosyBrown2 RosyBrown1 RosyBrownRed4Red3Red2Red1RedPurple4Purple3Purple2Purple1Purple PowderBluePlum4Plum3Plum2Plum1PlumPink4Pink3Pink2Pink1PinkPeru PeachPuff4 PeachPuff3 PeachPuff2 PeachPuff1 PeachPuff PapayaWhipPaleVioletRed4PaleVioletRed3PaleVioletRed2PaleVioletRed1 PaleVioletRedPaleTurquoise4PaleTurquoise3PaleTurquoise2PaleTurquoise1 PaleTurquoise PaleGreen4 PaleGreen3 PaleGreen2 PaleGreen1 PaleGreen PaleGoldenrodOrchid4Orchid3Orchid2Orchid1Orchid OrangeRed4 OrangeRed3 OrangeRed2 OrangeRed1 OrangeRedOrange4Orange3Orange2Orange1Orange OliveDrab4 OliveDrab3 OliveDrab2 OliveDrab1 OliveDrabOldLaceNavyBlueNavy NavajoWhite4 NavajoWhite3 NavajoWhite2 NavajoWhite1 NavajoWhiteMoccasin MistyRose4 MistyRose3 MistyRose2 MistyRose1 MistyRose MintCream MidnightBlueMediumVioletRedMediumTurquoiseMediumSpringGreenMediumSlateBlueMediumSeaGreen MediumPurple4 MediumPurple3 MediumPurple2 MediumPurple1 MediumPurple MediumOrchid4 MediumOrchid3 MediumOrchid2 MediumOrchid1 MediumOrchid MediumBlueMediumAquamarineMaroon4Maroon3Maroon2Maroon1MaroonMagenta4Magenta3Magenta2Magenta1MagentaLinen LimeGreen LightYellow4 LightYellow3 LightYellow2 LightYellow1 LightYellowLightSteelBlue4LightSteelBlue3LightSteelBlue2LightSteelBlue1LightSteelBlueLightSlateGrayLightSlateBlue LightSkyBlue4 LightSkyBlue3 LightSkyBlue2 LightSkyBlue1 LightSkyBlue LightSeaGreen LightSalmon4 LightSalmon3 LightSalmon2 LightSalmon1 LightSalmon LightPink4 LightPink3 LightPink2 LightPink1 LightPink LightGrayLightGoldenrodYellowLightGoldenrod4LightGoldenrod3LightGoldenrod2LightGoldenrod1LightGoldenrod LightCyan4 LightCyan3 LightCyan2 LightCyan1 LightCyan LightCoral LightBlue4 LightBlue3 LightBlue2 LightBlue1 LightBlue LemonChiffon4 LemonChiffon3 LemonChiffon2 LemonChiffon1 LemonChiffon LawnGreenLavenderBlush4LavenderBlush3LavenderBlush2LavenderBlush1 LavenderBlushLavenderKhaki4Khaki3Khaki2Khaki1KhakiIvory4Ivory3Ivory2Ivory1IvoryIndigo IndianRed4 IndianRed3 IndianRed2 IndianRed1 IndianRedHotPink4HotPink3HotPink2HotPink1HotPink HoneyDew4 HoneyDew3 HoneyDew2 HoneyDew1HoneyDew GreenYellowGreen4Green3Green2Green1GreenGray100Gray99Gray98Gray97Gray96Gray95Gray94Gray93Gray92Gray91Gray90Gray89Gray88Gray87Gray86Gray85Gray84Gray83Gray82Gray81Gray80Gray79Gray78Gray77Gray76Gray75Gray74Gray73Gray72Gray71Gray70Gray69Gray68Gray67Gray66Gray65Gray64Gray63Gray62Gray61Gray60Gray59Gray58Gray57Gray56Gray55Gray54Gray53Gray52Gray51Gray50Gray49Gray48Gray47Gray46Gray45Gray44Gray43Gray42Gray41Gray40Gray39Gray38Gray37Gray36Gray35Gray34Gray33Gray32Gray31Gray30Gray29Gray28Gray27Gray26Gray25Gray24Gray23Gray22Gray21Gray20Gray19Gray18Gray17Gray16Gray15Gray14Gray13Gray12Gray11Gray10Gray9Gray8Gray7Gray6Gray5Gray4Gray3Gray2Gray1Gray0Gray Goldenrod4 Goldenrod3 Goldenrod2 Goldenrod1 GoldenrodGold4Gold3Gold2Gold1Gold GhostWhite Gainsboro ForestGreen FloralWhite Firebrick4 Firebrick3 Firebrick2 Firebrick1 Firebrick DodgerBlue4 DodgerBlue3 DodgerBlue2 DodgerBlue1 DodgerBlueDimGray DeepSkyBlue4 DeepSkyBlue3 DeepSkyBlue2 DeepSkyBlue1 DeepSkyBlue DeepPink4 DeepPink3 DeepPink2 DeepPink1DeepPink DarkViolet DarkTurquoiseDarkSlateGray4DarkSlateGray3DarkSlateGray2DarkSlateGray1 DarkSlateGray DarkSlateBlue DarkSeaGreen4 DarkSeaGreen3 DarkSeaGreen2 DarkSeaGreen1 DarkSeaGreen DarkSalmon DarkOrchid4 DarkOrchid3 DarkOrchid2 DarkOrchid1 DarkOrchid DarkOrange4 DarkOrange3 DarkOrange2 DarkOrange1 DarkOrangeDarkOliveGreen4DarkOliveGreen3DarkOliveGreen2DarkOliveGreen1DarkOliveGreen Darkkhaki DarkGreenDarkGoldenrod4DarkGoldenrod3DarkGoldenrod2DarkGoldenrod1 DarkGoldenrodCyan4Cyan3Cyan2Cyan1CyanCrimson CornSilk4 CornSilk3 CornSilk2 CornSilk1CornSilkCornFlowerBlueCoral4Coral3Coral2Coral1Coral Chocolate4 Chocolate3 Chocolate2 Chocolate1 Chocolate Chartreuse4 Chartreuse3 Chartreuse2 Chartreuse1 Chartreuse CadetBlue4 CadetBlue3 CadetBlue2 CadetBlue1 CadetBlue Burlywood4 Burlywood3 Burlywood2 Burlywood1 BurlywoodBrown4Brown3Brown2Brown1Brown BlueVioletBlue4Blue3Blue2Blue1BlueBlanchedAlmondBlackBisque4Bisque3Bisque2Bisque1BisqueBeigeAzure4Azure3Azure2Azure1Azure Aquamarine4 Aquamarine3 Aquamarine2 Aquamarine1 Aquamarine AntiqueWhite4 AntiqueWhite3 AntiqueWhite2 AntiqueWhite1 AntiqueWhite AliceBlueColor BrewerColorHSVhue saturationvalueRGBAalphaRGBredgreenblue BrewerNameYlorrdYlorbrYlgnbuYlgnSpectralSet3Set2Set1RedsRdylgnRdylbuRdpuRdgyRdbuPurplesPurdPuorPubugnPubuPrgnPiygPastel2Pastel1PairedOrrdOrangesGreysGreensGnbuDark2BupuBugnBrbgBluesAccent ColorScheme BrewerSchemeX11toColour x11Colour fromColour fromAColourRatios AutoRatio ExpandRatio CompressRatio FillRatio AspectRatio JustificationJCenterJRightJLeft ScaleTypeFillBoth FillHeight FillWidthNoScale UniformScaleVerticalPlacementVBottomVCenterVTop FocusType NodeFocusXYViewPortVPwValhValzValfocus CompassPointNoCP CenterPoint NorthWestWest SouthWestSouth SouthEastEast NorthEastNorthPortPosPP StyleNameDDRounded DiagonalsFilled InvisibleBoldSolidDottedDashed StyleItemSItemSTStyle RandomStyle SelfStyle RegularStyle StartTypeStartStyleSeed StartSeed StartStyle SmoothTypeTriangleSmoothSpringRNG PowerDist GraphDistAvgDistNoSmoothShape ComponentBox3DFolderTabNoteMCircleMSquareMDiamondInvHouse InvTrapezium InvTriangle TripleOctagon DoubleOctagon DoubleCircleOctagonSeptagonHexagonPentagonHouse Parallelogram Trapezium DiamondShape PlainTextTriangleEgg PointShapeCircleEllipsePolygonBoxShapeRankDir FromRight FromBottomFromLeftFromTopRankTypeSinkRankMaxRank SourceRankMinRankSameRankRootNodeName NotCentral IsCentralQuadTypeNoQTFastQTNormalQTSplinePageDirLtLbRtRbTrTlBrBlEdgeType CompoundEdgePolyLineNoEdges LineEdges SplineEdgesPos SplinePosPointPosPackMode PackArray PackGraph PackClustPackNodePack PackMarginDontPackDoPack OutputMode EdgesFirst NodesFirst BreadthFirst LayerListLLLayerIDLRNameLRInt AllLayers LayerRangeLRSLRIDOverlap IpsepOverlap VpscOverlapCompressOverlap PrismOverlapScaleXYOverlaps ScaleOverlapsRemoveOverlaps KeepOverlapsPointPointDLabelURLLabelStrLabelModelCircuitSubSet ShortPathModeTypeIpSepHierKKMajorDPointPValDVal DEConstraintsHierConstraints NoConstraintsEdgeConstraintsDirTypeNoDirBothBackForward ClusterMode NoClusterGlobalLocalRect AspectTypeRatioPassCount RatioOnly ArrowSide BothSides RightSideLeftSide ArrowFill FilledArrow OpenArrow ArrowModifierArrMod arrowFill arrowSide ArrowShapeVeeTeeNormalNoArrowInvDotArrowDiamondCrowBox ArrowTypeATypeURLUStr urlString EscString Attributes AttributeZWidthWeight VoroMarginVertices TrueColorTooltipTarget TailTooltip TailTargetTailPort TailLabelTailClipTailURLStyle StyleSheetStartSplinesSortV SmoothingSkewSizeSides ShowBoxes ShapeFileSep SearchSize SamplePointsSameTailSameHeadRotateRepulsiveForce ReMinCrossRegularRectsRatioRankRankSepQuantumQuadTreePin PeripheriesPenWidthPenColorPagePadOverlapScaling OutputOrder OrientationOrderingNslimitNslimit1 Normalize NoJustifyNodeSepMosekModeMinLenMinDistMCLimitMaxIterMarginLTailLPosLHeadLevels LevelsGapLenLayoutLayerLayersLayerSep Landscape LabelTooltip LabelTargetLabelLoc LabelJust LabelFontSize LabelFontNameLabelFontColor LabelFloat LabelDistance LabelAngleLabelURL ImageScaleImageIDHeight HeadTooltip HeadTargetHeadPort HeadLabelHeadClipHeadURLGroupFontSizeFontPath FontNamesFontName FontColor FixedSize FillColorESepEpsilon EdgeTooltip EdgeTargetEdgeURLDPI DistortionDirEdgeConstraintsDirDimDimen DefaultDistDecorate Constraint ConcentrateCompoundComment ClusterRankCharsetCenterBgColorBbAspect ArrowTail ArrowSize ArrowHeadKDamping usedByGraphsusedByClustersusedBySubGraphs usedByNodes usedByEdgesnormalinvdotArrowinvDotoDotinvODotnoArrowteeemptyArrinvEmptydiamondoDiamondeDiamondcrowboxoBoxopenArrhalfOpenveenoModsopenMod defLayerSep notLayerSepDotEdgeedgeFromNodeID edgeToNodeID directedEdgeedgeAttributesDotNodenodeIDnodeAttributes DotSubGraphDotSG isCluster subGraphID subGraphStmtsGlobalAttributes EdgeAttrs NodeAttrs GraphAttrsattrs DotStatementsDotStmts attrStmts subGraphs nodeStmts edgeStmtsGraphIDHTMLDblIntStrDotError EdgeError NodeError GraphErrorDotGraph strictGraph directedGraphgraphIDgraphStatements makeStrictsetID graphNodes graphEdges printDotGraph parseDotGraph isValidGraph graphErrors RunResultSuccessErrorGraphvizCanvasXlibGtkGraphvizOutputWBmpVrmlVmlZVmlTiffSvgZSvgPs2PsPngPlainExtPlainPdfJpegCmapxNPImapNPCmapxImapIcoGifGd2GdFigEpsXDot DotOutputCanonBmpGraphvizCommandFdpCircoTwoPiNeatoDot dirCommand undirCommand commandFor runGraphvizrunGraphvizCommand addExtensiongraphvizWithHandlerunGraphvizCanvasrunGraphvizCanvas' hGetContents' NodeClusterCN AttributeEdge AttributeNode graphToDot graphToDot'clusterGraphToDotclusterGraphToDot' graphToGraph graphToGraph'clusterGraphToGraphclusterGraphToGraph' dotizeGraph dotizeGraph'dotizeClusterGraphdotizeClusterGraph' prettyPrint prettyPrint' isIDString frstIDStringbaseGHC.BaseString restIDStringtoDoubleghc-primGHC.BoolTrue stringToInt escapeQuotes descapeQuotes isKeywordkeywordsboolBoolFalsestringInterior parseSignedparseInt parseInt' parseFloat parseFloat' parseQuoteparseOutUnwantedparseLineCommentparseMultiLineCommentparseSplitStrings polyparse-1.4 Text.ParserCombinators.Poly.Lazyreparsesatisfyeofnext runParserPParserFailure CommittedResult Text.ParserCombinators.Poly.Base manyFinallybracket bracketSepsepBy1sepBymany1manyexactlyoptionalindentoneOf adjustErrBaddiscardfailBadapplyoneOf'onFail adjustErrcommit PolyParseqtChar GHC.TypesChar needsQuotes unqtStringqtStringpretty-1.0.1.1Text.PrettyPrint.HughesPJfcatfsepcatsep<+><>$+$$$nest zeroWidthTextptexttextcharisEmptyempty punctuatehangvcathsephcatbracesbracketsparens doubleQuotesquotesrationaldoublefloatintegerintrbracelbracerbracklbrackrparenlparenequalsspacecommacolonsemiDochexColorword8Doc colour-2.3.1Data.Colour.InternalColour Data.MaybeMaybe toOpacity AlphaColourGHC.ShowShowmaxWordGHC.EnummaxBoundGHC.WordWord8DoubleNothingspecialArrowParse parseLayerSepparseLayerNameparseLayerName'checkLayerName parseArgscheckDDparseStyleNameJustid printGraphID parseGraphIDdirGraph dirGraph' undirGraph undirGraph'strGraph strGraph' stringNumprintStmtBasedprintStmtBasedListparseStmtBasedparseStmtBasedList invalidStmtsstatementNodesstatementEdgesprintGlobAttrTypeparseGlobAttrType determineType invalidGlobalprintSubGraphID printSGIDparseSubGraphID parseSGIDsGraphsGraph'clustclust'invalidSubGraph subGraphNodes subGraphEdges printNodeID parseNodeID invalidNode printEdgeID parseEdgeID parseEdgeType parseEdgeLinedirEdgedirEdge' undirEdge undirEdge' invalidEdgeprintAttrBasedprintAttrBasedListparseAttrBasedparseAttrBasedListlineEndGraphvizResult outputCallisBinaryshowCmddefaultExtensionmaybeErrGHC.IOFilePathGHC.IO.Handle.TypesHandleIOGHC.IO.Handle.Text hGetContentsgraphvizWithHandle'signalWhenDoneGHC.MVarMVar ClusterTreeCTNTclustersToNodes clustToTree sameClust clustOrdergetNodescollapseNClusts treesToDot treeToDot isUndirected isDirected dotAttributesunsafePerformIO