1 Introduction

There are many presentation and drawing tools out there. And these allow the user full control over the diagram so generally result in prettier diagrams that can convey more information to the audience at that point in time.

But that point in time passes, and pretty pictures can quickly become out-of-date and, ironically, misinforming if they don’t match the reality of the system they are describing. This is especially so if one team is drawing the pretty pictures, and another team is writing the software/implementing the system.

Having diagrams as code that can live beside the system design/code, that the stakeholders are equally comfortable editing and viewing,reduces the gap i.e. “Where system diagrams meet system reality”.

We will “explore” two packages to do this: DiagrammeR and nomnoml. Each of these follows a specific grammar so that sets of “sentences” will morph into very different kinds of diagrams.

2 Goals

At the end of this Lab session, we will be able to:

  • Make conceptual Block Diagrams of different types, using text
  • Be able to create Flow Charts, Sequence Diagrams, Gantt Charts etc. to represent diverse realities in diagram form
  • Be able to use mermaid and nomoml syntax in R

3 Packages

We will work with Diagrammer first and then with nomnoml.

4 Using DiagrammeR

DiagrammeR is a unique package since it allows you create Diagrams and the Network Diagrams that you have created using tidygraph and ggraph. And it uses the tidyverse pipe %>% syntax too! So it is worth exploring in its entirety. But that is for another time, or perhaps you can explore this yourself!!

Mermaid language (What !! Another language?!!!) is an approach to creating diagrams using text. It is an integral part of the DiagrammeR R package. And hence the code you write is actually R code, to create Diagrams.

4.1 Sequence Diagram

Look at the code below: What do you think it represents?

DiagrammeR("
sequenceDiagram
Arvind ->> Anamika: Why are you late today?
Anamika ->> Anamika: Ulp...
Anamika ->> Arvind: I am sorry... <br> may I come in please?

Arvind ->> Komal: And you? What kept you?
Komal ->> Anamika: (Quietly) He's having a bad day, dude...
Anamika ->> Komal: (Whisper) Boomer...
")

This is a simple Sequence Diagram! Shows a strictly imaginary exchange between a pair of students and an unknown Faculty Member.

Let us now see how we can embellish this kind of diagram. Can we have a Garden of Forking Paths?

DiagrammeR("
    mermaid.sequenceConfig = {
    diagramMarginX: 50,
    diagramMarginY: 10,
    boxTextMargin: 5,
    noteMargin: 10,
    messageMargin: 35,
    mirrorActors: true
};
")
DiagrammeR("
        sequenceDiagram
        
        alt Anamika is always punctual
        Arvind ->> Anamika: Why haven't you put up your Daily Reflection?
        Anamika ->> Anamika: Ulp...
        Note right of Anamika : I have had it today..
        Anamika ->> Arvind: I am sorry... 
        Arvind ->> Anamika: Ok write it today
        
        else Anamika is usually tardy
        Arvind ->> Anamika: Why haven't you put up your Daily Reflection?
        Anamika ->> Anamika: Ulp...
        Anamika ->> Arvind: I am sorry... 
        Arvind ->> Anamika: This is not acceptable and will reflect in your grade
        end
        
        Arvind ->> Komal: And you? What kept you?
        Komal ->> Anamika: (Quietly) He's having a bad day, dude...
        Anamika ->> Komal: (Whisper) Boomer...
        Note over Anamika,Komal: Giggle...
")

From here: https://cyberhelp.sesync.org/blog/visualization-with-diagrammeR.html

grViz("digraph{

      graph[rankdir = LR]
  
      node[shape = rectangle, style = filled]
  
      node[fillcolor = Coral, margin = 0.2]
      A[label = 'Figure 1: Map']
      B[label = 'Figure 2: Metrics']
  
      node[fillcolor = Cyan, margin = 0.2]
      C[label = 'Figures.Rmd']
  
      node[fillcolor = Violet, margin = 0.2]
      D[label = 'Analysis_1.R']
      E[label = 'Analysis_2.R']
  
      subgraph cluster_0 {
        graph[shape = rectangle]
        style = rounded
        bgcolor = Gold
    
        label = 'Data Source 1'
        node[shape = rectangle, fillcolor = LemonChiffon, margin = 0.25]
        F[label = 'my_dataframe_1.csv']
        G[label = 'my_dataframe_2.csv']
      }
  
      subgraph cluster_1 {
         graph[shape = rectangle]
         style = rounded
         bgcolor = Gold
    
         label = 'Data Source 2'
         node[shape = rectangle, fillcolor = LemonChiffon, margin = 0.25]
         H[label = 'my_dataframe_3.csv']
         I[label = 'my_dataframe_4.csv']
      }
  
      edge[color = black, arrowhead = vee, arrowsize = 1.25]
      C -> {A B}
      D -> C
      E -> C
      F -> D
      G -> D
      H -> E
      I -> E
      
      }")
mermaid("
        graph BT
        A((Salinity))
        A-->B(Barnacles)
        B-.->|-0.10|B1{Mussels}
        A-- 0.30 -->B1

        C[Air Temp]
        C-->B
        C-.->E(Macroalgae)
        E-->B1
        C== 0.89 ==>B1

        style A fill:#FFF, stroke:#333, stroke-width:4px
        style B fill:#9AA, stroke:#9AA, stroke-width:2px
        style B1 fill:#879, stroke:#333, stroke-width:1px
        style C fill:#ADF, stroke:#333, stroke-width:2px
        style E fill:#9C2, stroke:#9C2, stroke-width:2px

        ")
DiagrammeR("
sequenceDiagram
  Arvind ->>ticket seller: ask ticket
  ticket seller->>database: seats
  alt tickets available
    database->>ticket seller: ok
    ticket seller->>customer: confirm
    Arvind ->>ticket seller: ok
    ticket seller->>database: book a seat
    ticket seller->>printer: print ticket
  else sold out
    database->>ticket seller: none left
    ticket seller->>customer: sorry
  end
")
DiagrammeR("
  graph LR
    A-->B
    A-->C
    C-->E
    B-->D
    C-->D
    D-->F
    E-->F
")
DiagrammeR(
"graph TB;
A(Rounded)-->B[Squared];
B-->C{A Decision};
C-->D[Square One];
C-->E[Square Two];

%% Now styling these blocks
style A fill:#E5E25F;  
style B fill:#87AB51; 
style C fill:#3C8937;
style D fill:#23772C;  
style E fill:#B6E6E6;
"
)
  grViz("
digraph boxes_and_circles {

  # a 'graph' statement
  graph [overlap = true, fontsize = 10,forcelabels = true]

  # several 'node' statements
  node [shape = box,fontname = Helvetica, color = red, style = filled]
  A[label = 'This is \\n an internal \\n label', xlabel = 'This is \\nan external \\nlabel']; B; C; D; E; F

  node [shape = circle, fixedsize = true, color = palegreen, width = 0.9] // sets as circles
  1; 2; 3; 4; 5; 6; 7; 8

  # several 'edge' statements
  A->{1,2,3,4} B->2 B->3 B->4 C->A
  1->D E->A 2->4 1->5 1->F
  E->6 4->6 5->7 6->7 3->8 3->1
}
")

4.2 Sequence Diagram-2

4.3 Sequence Diagram 3

4.4 Mindmap

4.5 Gantt Chart

4.6 Flow chart

5 Using nomnoml

nomnoml is touted as a “sassy” UML diagram creator, in R. It allows us to rapidly create many of diagrams that we can use in System Descriptions.

The syntax options for nomnoml and what can be created is described here https://nomnoml.com/

The R pdf Manual for nomnoml at CRAN ( read just the first half-page and you are ready!!)

So what can it do?

#import: filename
#arrowSize: 1
#bendSize: 0.3
#direction: down | right
#gutter: 5
#edgeMargin: 0
#gravity: 1
#edges: hard | rounded
#background: lightgrey

//nested list of colours
//#fill: #fcfcfc; #eee8d5; #fdf6e3
#fill: lightgreen; pink;
#fillArrows: false
#font: Calibri
#fontSize: 12
#leading: 1.25
#lineWidth: 3
#padding: 8
#spacing: 40
#stroke: #33322E
#title: filename
#zoom: 1
#acyclicer: greedy
#ranker: network-simplex | tight-tree | longest-path

[Pirate|eyeCount: Int|raid()|pillage()|
  [beard]--[parrot]
  [beard]-:>[foul mouth]
  ]

[<table>mischief | bawl | sing || yell | drink]

[<abstract>Marauder]<:--[Pirate]
[Pirate]- 0..7[mischief]
[jollyness]_>[Pirate]
[jollyness]->[rum]
[jollyness]->[singing]
[Pirate]-> *[rum|tastiness: Int|swig()]
[Pirate]->[singing]
[singing]<->[rum]

[<start>st]->[<state>plunder]
[plunder]->[<choice>more loot]
[more loot]->[st]
[more loot] no ->[<end>e]

[<actor>Sailor] - [<usecase>shiver me;timbers]

5.1 Some definitions on the “grammar of shapes” in nomnoml

  1. Association Types: Connectors between blocks( i.e. Classifiers)

  2. Classifier Types: Kinds of blocks.

  3. Directive Types: Directives change the nature of the diagram rendered, by affective parameters like colour, direction and margins. ( Ha! VC people!!)

CSS colours https://www.w3schools.com/cssref/css_colors.asp Only these colours are permitted, so use either the names or these specific colour hash codes. Any general hash code will not render.

//association-1
[a] - [b] 

//association-2
[b] -> [c] 

//association_3
[c] <-> [a]

//dependency-1
[a] <-->[d]

//dependency-2
#.ell: visual=ellipse fill=#fbfb09 bold
#.arvind: visual=rhomb fill=#ff2234 bold
[<ell>e]-->[a]
//generalization-1
[c]-:>[<arvind>k]

//implementation --:>
[k]--:>[d]
//composition +-
[a]+-[b]
//composition +->
[b]-+[c]
//aggregation o-
[c]o->[d]
//aggregation o->
[d]o->[a]
//note --
[d]--[everything happens;here]
//hidden -/-
[d]-/-[f]
////////////////////////
//weightless edge _>
//[k]_>[d] //not working
//weightless dashed__
//[d]__[j] //not working

5.1.1 Classifier Types

These are different kinds of blocks.

[class]->[<abstract> abstract]
[<abstract> abstract]-:>[<instance> instance]
[<instance> instance]-:>[<note> note]
[<note> note]-->[<reference> reference]
[<package> package|components]-->[<frame> frame|]
[<database> database]-->[<start> start]
[<end> end]-o>[<state> state]
[<choice> choice]--->[<sync> sync]
[<input> input]->[<sender> sender]
[<receiver> receiver]o-[<transceiver> transceiver]
#direction:down
#background:lightgrey
#fill: fuchsia; green; purple
#fillArrows: false
#font: Courier
[class]->[<abstract> abstract]
[<abstract> abstract]-:>[<instance> instance]
[<instance> instance]-:>[<note> note]
[<note> note]-->[<reference> reference]
#font: CenturySchoolbook
#fill: lightyellow
#stroke: green

[<actor> actor]---[<usecase> usecase]
[<usecase> usecase]<-->[<label> label]
[<usecase> usecase]-/-[<hidden> hidden]
[<table> table| a | 5 || b | 7]
[<table> table| c | 9 ]

5.2 Directives

Directives change the nature of the diagram rendered, by affective parameters like colour, direction and margins.

5.3 Custom classifier styles

A directive that starts with “.” define a classifier’s style. The style is written as a space separated list of modifiers and key/value pairs.

#.box: fill=#8f8 dashed
#.blob: visual=ellipse title=bold
#.arvind: visual=rhomb title=bold dashed fill=CornFlowerBlue
[<box> GreenBox]
[<blob> Blobby]
[<arvind> Someone]

5.4 nomnoml Key/value pairs

  • fill=(any css color)
  • stroke=(any css color)
  • align=center align=left
  • direction=right direction=down
  • visual=actor
  • visual=class
  • visual=database
  • visual=ellipse
  • visual=end
  • visual=frame
  • visual=hidden
  • visual=input
  • visual=none
  • visual=note
  • visual=package
  • visual=receiver
  • visual=rhomb
  • visual=roundrect
  • visual=sender
  • visual=start
  • visual=sync
  • visual=table
  • visual=transceiver

5.5 Text modifiers

bold center italic left underline

# .box: fill=#8f8 dashed
# .blob: visual=rhomb title=bold fill=#8f8 dashed

[A]-[B]
[B]--[<usecase>C]
[C]-[<box> D]
[B]--[<blob> Jabba;TheHut]
[a] ->[b]
[b] -:> [c]
[c]o->[d]
[d]-/-[e]
#fill: lightgreen; lightblue; lightyellow; grey; white

[<table> table | c | 9 ]

[R | [<table> Packages |
         Base R |
         [ <table> tidyverse| ggplot | tidyr | readr |
             [<table> dplyr|
                 magrittr | Others]]]]
#fill: lightgreen; lightblue; lightyellow; pink; white

[RStudio | [R | [<table> Packages |
                   Base R | [ tidyverse |
                               ggplot | tidyr | readr |
                               [dplyr]--[magrittr]
                               [dplyr]--[Others]
                             | tibble
                             ]
                 | lubridate | DiagrammeR | Lattice]]]
[Linux]+-[Ubuntu]
[Linux]+-[Mint]
[Ubuntu]--[Mint]
[Linux]+-[Rosa Linux]
[Linux]+-[Mx Linux]
[Debian]-+[Linux]


[Fedora]-+[Linux]
[Puppy Linux]-+[Linux]
[Personal Pups]-+[Puppy Linux]
LS0tCnRpdGxlOiAiVGhlIEdyYW1tYXIgb2YgRGlhZ3JhbXMiCnN1YnRpdGxlOiAiIENvbnZlcnRpbmcgVGV4dCB0byBEaWFncmFtcyBpbiBSIgphdXRob3I6IEFydmluZCBWZW5rYXRhZHJpCmFmZmlsaWF0aW9uOiBTcmlzaHRpIE1hbmlwYWwgSW5zdGl0dXRlIG9mIEFydCwgRGVzaWduLCBhbmQgVGVjaG5vbG9neSwgQmFuZ2Fsb3JlCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdGhlbWU6IGZsYXRseQogICAgdG9jOiBUUlVFCiAgICB0b2NfZmxvYXQ6IFRSVUUKICAgIHRvY19kZXB0aDogMgogICAgbnVtYmVyX3NlY3Rpb25zOiBUUlVFCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIGNvZGVfZG93bmxvYWQ6IFRSVUUKYWJzdHJhY3Q6IFBhcnQgb2YgdGhlIGBSIGZvciBBcnRpc3RzIGFuZCBEZXNpZ25lcnNgIHdvcmtzaG9wIGNvdXJzZSBhdCB0aGUgU2Nob29sIG9mIEZvdW5kYXRpb24gU3R1ZGllcywgU3Jpc2h0aSBNYW5pcGFsIEluc3RpdHV0ZSBvZiBBcnQsIERlc2lnbiwgYW5kIFRlY2hub2xvZ3ksIEJhbmdhbG9yZS4KLS0tCgojIEludHJvZHVjdGlvbgoKVGhlcmUgYXJlIG1hbnkgcHJlc2VudGF0aW9uIGFuZCBkcmF3aW5nIHRvb2xzIG91dCB0aGVyZS4gQW5kIHRoZXNlIGFsbG93IHRoZSB1c2VyIGZ1bGwgY29udHJvbCBvdmVyIHRoZSBkaWFncmFtIHNvIGdlbmVyYWxseSByZXN1bHQgaW4gcHJldHRpZXIgZGlhZ3JhbXMgdGhhdCBjYW4gY29udmV5IG1vcmUgaW5mb3JtYXRpb24gdG8gdGhlIGF1ZGllbmNlIGF0IHRoYXQgcG9pbnQgaW4gdGltZS4KCkJ1dCB0aGF0IHBvaW50IGluIHRpbWUgcGFzc2VzLCBhbmQgKipwcmV0dHkgcGljdHVyZXMgY2FuIHF1aWNrbHkgYmVjb21lIG91dC1vZi1kYXRlKiogYW5kLCBpcm9uaWNhbGx5LCBtaXNpbmZvcm1pbmcgaWYgdGhleSBkb24ndCBtYXRjaCB0aGUgcmVhbGl0eSBvZiB0aGUgc3lzdGVtIHRoZXkgYXJlIGRlc2NyaWJpbmcuIFRoaXMgaXMgZXNwZWNpYWxseSBzbyBpZiBvbmUgdGVhbSBpcyBkcmF3aW5nIHRoZSBwcmV0dHkgcGljdHVyZXMsIGFuZCBhbm90aGVyIHRlYW0gaXMgd3JpdGluZyB0aGUgc29mdHdhcmUvaW1wbGVtZW50aW5nIHRoZSBzeXN0ZW0uCgpIYXZpbmcgKipkaWFncmFtcyBhcyBjb2RlIHRoYXQgY2FuIGxpdmUgYmVzaWRlIHRoZSBzeXN0ZW0gZGVzaWduL2NvZGUqKiwgdGhhdCB0aGUgc3Rha2Vob2xkZXJzIGFyZSBlcXVhbGx5IGNvbWZvcnRhYmxlIGVkaXRpbmcgYW5kIHZpZXdpbmcscmVkdWNlcyB0aGUgZ2FwIGkuZS4gIldoZXJlIHN5c3RlbSBkaWFncmFtcyBtZWV0IHN5c3RlbSByZWFsaXR5Ii4KCldlIHdpbGwgImV4cGxvcmUiIHR3byBwYWNrYWdlcyB0byBkbyB0aGlzOiBgRGlhZ3JhbW1lUmAKYW5kIGBub21ub21sYC4gRWFjaCBvZiB0aGVzZSBmb2xsb3dzIGEgc3BlY2lmaWMgZ3JhbW1hciBzbyB0aGF0IHNldHMgb2YgInNlbnRlbmNlcyIgd2lsbCBtb3JwaCBpbnRvIHZlcnkgZGlmZmVyZW50IGtpbmRzIG9mIGRpYWdyYW1zLgoKCiMgR29hbHMKCkF0IHRoZSBlbmQgb2YgdGhpcyBMYWIgc2Vzc2lvbiwgd2Ugd2lsbCBiZSBhYmxlIHRvOgoKLSBNYWtlIGNvbmNlcHR1YWwgQmxvY2sgRGlhZ3JhbXMgb2YgZGlmZmVyZW50IHR5cGVzLCB1c2luZyBgdGV4dGAKLSBCZSBhYmxlIHRvIGNyZWF0ZSBGbG93IENoYXJ0cywgU2VxdWVuY2UgRGlhZ3JhbXMsIEdhbnR0IENoYXJ0cyBldGMuIHRvIHJlcHJlc2VudCBkaXZlcnNlIHJlYWxpdGllcyBpbiBkaWFncmFtIGZvcm0KLSBCZSBhYmxlIHRvIHVzZSBgbWVybWFpZGAgYW5kIGBub21vbWxgIHN5bnRheCBpbiBSCgojIFBhY2thZ2VzCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCBtZXNzYWdlID0gRkFMU0UpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KERpYWdyYW1tZVIpCmxpYnJhcnkobm9tbm9tbCkKYGBgCgpXZSB3aWxsIHdvcmsgd2l0aCBgRGlhZ3JhbW1lcmAgZmlyc3QgYW5kIHRoZW4gd2l0aCBgbm9tbm9tbGAuIAoKCiMgVXNpbmcgRGlhZ3JhbW1lUgoKYERpYWdyYW1tZVJgIGlzIGEgdW5pcXVlIHBhY2thZ2Ugc2luY2UgaXQgYWxsb3dzIHlvdSBjcmVhdGUgRGlhZ3JhbXMgKiphbmQqKiB0aGUgTmV0d29yayBEaWFncmFtcyB0aGF0IHlvdSBoYXZlIGNyZWF0ZWQgdXNpbmcgYHRpZHlncmFwaGAgYW5kIGBnZ3JhcGhgLiBBbmQgaXQgdXNlcyB0aGUgdGlkeXZlcnNlIHBpcGUgYCU+JWAgc3ludGF4IHRvbyEgU28gaXQgaXMgd29ydGggZXhwbG9yaW5nIGluIGl0cyBlbnRpcmV0eS4gQnV0IHRoYXQgaXMgZm9yIGFub3RoZXIgdGltZSwgb3IgcGVyaGFwcyB5b3UgY2FuIGV4cGxvcmUgdGhpcyB5b3Vyc2VsZiEhCgoKKipNZXJtYWlkKiogbGFuZ3VhZ2UgKCoqV2hhdCAhISBBbm90aGVyIGxhbmd1YWdlPyEhISoqKSBpcyBhbiBhcHByb2FjaCB0byBjcmVhdGluZyBkaWFncmFtcyB1c2luZyB0ZXh0LiAgSXQgaXMgYW4gaW50ZWdyYWwgcGFydCBvZiB0aGUgYERpYWdyYW1tZVJgIFIgcGFja2FnZS4gQW5kIGhlbmNlIHRoZSBjb2RlIHlvdSB3cml0ZSBpcyBhY3R1YWxseSBSIGNvZGUsIHRvIGNyZWF0ZSBEaWFncmFtcy4KCiMjIFNlcXVlbmNlIERpYWdyYW0KCkxvb2sgYXQgdGhlIGNvZGUgYmVsb3c6IFdoYXQgZG8geW91IHRoaW5rIGl0IHJlcHJlc2VudHM/CgpgYGB7ciBTZXF1ZW5jZV8xfQpEaWFncmFtbWVSKCIKc2VxdWVuY2VEaWFncmFtCkFydmluZCAtPj4gQW5hbWlrYTogV2h5IGFyZSB5b3UgbGF0ZSB0b2RheT8KQW5hbWlrYSAtPj4gQW5hbWlrYTogVWxwLi4uCkFuYW1pa2EgLT4+IEFydmluZDogSSBhbSBzb3JyeS4uLiA8YnI+IG1heSBJIGNvbWUgaW4gcGxlYXNlPwoKQXJ2aW5kIC0+PiBLb21hbDogQW5kIHlvdT8gV2hhdCBrZXB0IHlvdT8KS29tYWwgLT4+IEFuYW1pa2E6IChRdWlldGx5KSBIZSdzIGhhdmluZyBhIGJhZCBkYXksIGR1ZGUuLi4KQW5hbWlrYSAtPj4gS29tYWw6IChXaGlzcGVyKSBCb29tZXIuLi4KIikKCmBgYApUaGlzIGlzIGEgc2ltcGxlIFNlcXVlbmNlIERpYWdyYW0hIFNob3dzIGEgKipzdHJpY3RseSoqIGltYWdpbmFyeSBleGNoYW5nZSBiZXR3ZWVuIGEgcGFpciBvZiBzdHVkZW50cyBhbmQgYW4gdW5rbm93biBGYWN1bHR5IE1lbWJlci4KCkxldCB1cyBub3cgc2VlIGhvdyB3ZSBjYW4gZW1iZWxsaXNoIHRoaXMga2luZCBvZiBkaWFncmFtLiBDYW4gd2UgaGF2ZSBhIEdhcmRlbiBvZiBGb3JraW5nIFBhdGhzPwoKYGBge3J9CkRpYWdyYW1tZVIoIgogICAgbWVybWFpZC5zZXF1ZW5jZUNvbmZpZyA9IHsKICAgIGRpYWdyYW1NYXJnaW5YOiA1MCwKICAgIGRpYWdyYW1NYXJnaW5ZOiAxMCwKICAgIGJveFRleHRNYXJnaW46IDUsCiAgICBub3RlTWFyZ2luOiAxMCwKICAgIG1lc3NhZ2VNYXJnaW46IDM1LAogICAgbWlycm9yQWN0b3JzOiB0cnVlCn07CiIpCmBgYAoKCmBgYHtyIFNlcXVlbmNlXzJ9CgpEaWFncmFtbWVSKCIKICAgICAgICBzZXF1ZW5jZURpYWdyYW0KICAgICAgICAKICAgICAgICBhbHQgQW5hbWlrYSBpcyBhbHdheXMgcHVuY3R1YWwKICAgICAgICBBcnZpbmQgLT4+IEFuYW1pa2E6IFdoeSBoYXZlbid0IHlvdSBwdXQgdXAgeW91ciBEYWlseSBSZWZsZWN0aW9uPwogICAgICAgIEFuYW1pa2EgLT4+IEFuYW1pa2E6IFVscC4uLgogICAgICAgIE5vdGUgcmlnaHQgb2YgQW5hbWlrYSA6IEkgaGF2ZSBoYWQgaXQgdG9kYXkuLgogICAgICAgIEFuYW1pa2EgLT4+IEFydmluZDogSSBhbSBzb3JyeS4uLiAKICAgICAgICBBcnZpbmQgLT4+IEFuYW1pa2E6IE9rIHdyaXRlIGl0IHRvZGF5CiAgICAgICAgCiAgICAgICAgZWxzZSBBbmFtaWthIGlzIHVzdWFsbHkgdGFyZHkKICAgICAgICBBcnZpbmQgLT4+IEFuYW1pa2E6IFdoeSBoYXZlbid0IHlvdSBwdXQgdXAgeW91ciBEYWlseSBSZWZsZWN0aW9uPwogICAgICAgIEFuYW1pa2EgLT4+IEFuYW1pa2E6IFVscC4uLgogICAgICAgIEFuYW1pa2EgLT4+IEFydmluZDogSSBhbSBzb3JyeS4uLiAKICAgICAgICBBcnZpbmQgLT4+IEFuYW1pa2E6IFRoaXMgaXMgbm90IGFjY2VwdGFibGUgYW5kIHdpbGwgcmVmbGVjdCBpbiB5b3VyIGdyYWRlCiAgICAgICAgZW5kCiAgICAgICAgCiAgICAgICAgQXJ2aW5kIC0+PiBLb21hbDogQW5kIHlvdT8gV2hhdCBrZXB0IHlvdT8KICAgICAgICBLb21hbCAtPj4gQW5hbWlrYTogKFF1aWV0bHkpIEhlJ3MgaGF2aW5nIGEgYmFkIGRheSwgZHVkZS4uLgogICAgICAgIEFuYW1pa2EgLT4+IEtvbWFsOiAoV2hpc3BlcikgQm9vbWVyLi4uCiAgICAgICAgTm90ZSBvdmVyIEFuYW1pa2EsS29tYWw6IEdpZ2dsZS4uLgoiKQoKYGBgCgpGcm9tIGhlcmU6IDxodHRwczovL2N5YmVyaGVscC5zZXN5bmMub3JnL2Jsb2cvdmlzdWFsaXphdGlvbi13aXRoLWRpYWdyYW1tZVIuaHRtbD4KCgpgYGB7cn0KZ3JWaXooImRpZ3JhcGh7CgogICAgICBncmFwaFtyYW5rZGlyID0gTFJdCiAgCiAgICAgIG5vZGVbc2hhcGUgPSByZWN0YW5nbGUsIHN0eWxlID0gZmlsbGVkXQogIAogICAgICBub2RlW2ZpbGxjb2xvciA9IENvcmFsLCBtYXJnaW4gPSAwLjJdCiAgICAgIEFbbGFiZWwgPSAnRmlndXJlIDE6IE1hcCddCiAgICAgIEJbbGFiZWwgPSAnRmlndXJlIDI6IE1ldHJpY3MnXQogIAogICAgICBub2RlW2ZpbGxjb2xvciA9IEN5YW4sIG1hcmdpbiA9IDAuMl0KICAgICAgQ1tsYWJlbCA9ICdGaWd1cmVzLlJtZCddCiAgCiAgICAgIG5vZGVbZmlsbGNvbG9yID0gVmlvbGV0LCBtYXJnaW4gPSAwLjJdCiAgICAgIERbbGFiZWwgPSAnQW5hbHlzaXNfMS5SJ10KICAgICAgRVtsYWJlbCA9ICdBbmFseXNpc18yLlInXQogIAogICAgICBzdWJncmFwaCBjbHVzdGVyXzAgewogICAgICAgIGdyYXBoW3NoYXBlID0gcmVjdGFuZ2xlXQogICAgICAgIHN0eWxlID0gcm91bmRlZAogICAgICAgIGJnY29sb3IgPSBHb2xkCiAgICAKICAgICAgICBsYWJlbCA9ICdEYXRhIFNvdXJjZSAxJwogICAgICAgIG5vZGVbc2hhcGUgPSByZWN0YW5nbGUsIGZpbGxjb2xvciA9IExlbW9uQ2hpZmZvbiwgbWFyZ2luID0gMC4yNV0KICAgICAgICBGW2xhYmVsID0gJ215X2RhdGFmcmFtZV8xLmNzdiddCiAgICAgICAgR1tsYWJlbCA9ICdteV9kYXRhZnJhbWVfMi5jc3YnXQogICAgICB9CiAgCiAgICAgIHN1YmdyYXBoIGNsdXN0ZXJfMSB7CiAgICAgICAgIGdyYXBoW3NoYXBlID0gcmVjdGFuZ2xlXQogICAgICAgICBzdHlsZSA9IHJvdW5kZWQKICAgICAgICAgYmdjb2xvciA9IEdvbGQKICAgIAogICAgICAgICBsYWJlbCA9ICdEYXRhIFNvdXJjZSAyJwogICAgICAgICBub2RlW3NoYXBlID0gcmVjdGFuZ2xlLCBmaWxsY29sb3IgPSBMZW1vbkNoaWZmb24sIG1hcmdpbiA9IDAuMjVdCiAgICAgICAgIEhbbGFiZWwgPSAnbXlfZGF0YWZyYW1lXzMuY3N2J10KICAgICAgICAgSVtsYWJlbCA9ICdteV9kYXRhZnJhbWVfNC5jc3YnXQogICAgICB9CiAgCiAgICAgIGVkZ2VbY29sb3IgPSBibGFjaywgYXJyb3doZWFkID0gdmVlLCBhcnJvd3NpemUgPSAxLjI1XQogICAgICBDIC0+IHtBIEJ9CiAgICAgIEQgLT4gQwogICAgICBFIC0+IEMKICAgICAgRiAtPiBECiAgICAgIEcgLT4gRAogICAgICBIIC0+IEUKICAgICAgSSAtPiBFCiAgICAgIAogICAgICB9IikKCmBgYAoKCmBgYHtyfQptZXJtYWlkKCIKICAgICAgICBncmFwaCBCVAogICAgICAgIEEoKFNhbGluaXR5KSkKICAgICAgICBBLS0+QihCYXJuYWNsZXMpCiAgICAgICAgQi0uLT58LTAuMTB8QjF7TXVzc2Vsc30KICAgICAgICBBLS0gMC4zMCAtLT5CMQoKICAgICAgICBDW0FpciBUZW1wXQogICAgICAgIEMtLT5CCiAgICAgICAgQy0uLT5FKE1hY3JvYWxnYWUpCiAgICAgICAgRS0tPkIxCiAgICAgICAgQz09IDAuODkgPT0+QjEKCiAgICAgICAgc3R5bGUgQSBmaWxsOiNGRkYsIHN0cm9rZTojMzMzLCBzdHJva2Utd2lkdGg6NHB4CiAgICAgICAgc3R5bGUgQiBmaWxsOiM5QUEsIHN0cm9rZTojOUFBLCBzdHJva2Utd2lkdGg6MnB4CiAgICAgICAgc3R5bGUgQjEgZmlsbDojODc5LCBzdHJva2U6IzMzMywgc3Ryb2tlLXdpZHRoOjFweAogICAgICAgIHN0eWxlIEMgZmlsbDojQURGLCBzdHJva2U6IzMzMywgc3Ryb2tlLXdpZHRoOjJweAogICAgICAgIHN0eWxlIEUgZmlsbDojOUMyLCBzdHJva2U6IzlDMiwgc3Ryb2tlLXdpZHRoOjJweAoKICAgICAgICAiKQpgYGAKCmBgYHtyfQpEaWFncmFtbWVSKCIKc2VxdWVuY2VEaWFncmFtCiAgQXJ2aW5kIC0+PnRpY2tldCBzZWxsZXI6IGFzayB0aWNrZXQKICB0aWNrZXQgc2VsbGVyLT4+ZGF0YWJhc2U6IHNlYXRzCiAgYWx0IHRpY2tldHMgYXZhaWxhYmxlCiAgICBkYXRhYmFzZS0+PnRpY2tldCBzZWxsZXI6IG9rCiAgICB0aWNrZXQgc2VsbGVyLT4+Y3VzdG9tZXI6IGNvbmZpcm0KICAgIEFydmluZCAtPj50aWNrZXQgc2VsbGVyOiBvawogICAgdGlja2V0IHNlbGxlci0+PmRhdGFiYXNlOiBib29rIGEgc2VhdAogICAgdGlja2V0IHNlbGxlci0+PnByaW50ZXI6IHByaW50IHRpY2tldAogIGVsc2Ugc29sZCBvdXQKICAgIGRhdGFiYXNlLT4+dGlja2V0IHNlbGxlcjogbm9uZSBsZWZ0CiAgICB0aWNrZXQgc2VsbGVyLT4+Y3VzdG9tZXI6IHNvcnJ5CiAgZW5kCiIpCmBgYApgYGB7cn0KRGlhZ3JhbW1lUigiCiAgZ3JhcGggTFIKICAgIEEtLT5CCiAgICBBLS0+QwogICAgQy0tPkUKICAgIEItLT5ECiAgICBDLS0+RAogICAgRC0tPkYKICAgIEUtLT5GCiIpCgpgYGAKCmBgYHtyIH0KRGlhZ3JhbW1lUigKImdyYXBoIFRCOwpBKFJvdW5kZWQpLS0+QltTcXVhcmVkXTsKQi0tPkN7QSBEZWNpc2lvbn07CkMtLT5EW1NxdWFyZSBPbmVdOwpDLS0+RVtTcXVhcmUgVHdvXTsKCiUlIE5vdyBzdHlsaW5nIHRoZXNlIGJsb2NrcwpzdHlsZSBBIGZpbGw6I0U1RTI1RjsgIApzdHlsZSBCIGZpbGw6Izg3QUI1MTsgCnN0eWxlIEMgZmlsbDojM0M4OTM3OwpzdHlsZSBEIGZpbGw6IzIzNzcyQzsgIApzdHlsZSBFIGZpbGw6I0I2RTZFNjsKIgopCmBgYAoKCmBgYHtyIERpYWdyYW1tZVIsIGZpZy53aWR0aD03LCBmaWcuaGVpZ2h0PSA4LCBmaWcuYWxpZ249J2NlbnRlcid9CgogIGdyVml6KCIKZGlncmFwaCBib3hlc19hbmRfY2lyY2xlcyB7CgogICMgYSAnZ3JhcGgnIHN0YXRlbWVudAogIGdyYXBoIFtvdmVybGFwID0gdHJ1ZSwgZm9udHNpemUgPSAxMCxmb3JjZWxhYmVscyA9IHRydWVdCgogICMgc2V2ZXJhbCAnbm9kZScgc3RhdGVtZW50cwogIG5vZGUgW3NoYXBlID0gYm94LGZvbnRuYW1lID0gSGVsdmV0aWNhLCBjb2xvciA9IHJlZCwgc3R5bGUgPSBmaWxsZWRdCiAgQVtsYWJlbCA9ICdUaGlzIGlzIFxcbiBhbiBpbnRlcm5hbCBcXG4gbGFiZWwnLCB4bGFiZWwgPSAnVGhpcyBpcyBcXG5hbiBleHRlcm5hbCBcXG5sYWJlbCddOyBCOyBDOyBEOyBFOyBGCgogIG5vZGUgW3NoYXBlID0gY2lyY2xlLCBmaXhlZHNpemUgPSB0cnVlLCBjb2xvciA9IHBhbGVncmVlbiwgd2lkdGggPSAwLjldIC8vIHNldHMgYXMgY2lyY2xlcwogIDE7IDI7IDM7IDQ7IDU7IDY7IDc7IDgKCiAgIyBzZXZlcmFsICdlZGdlJyBzdGF0ZW1lbnRzCiAgQS0+ezEsMiwzLDR9IEItPjIgQi0+MyBCLT40IEMtPkEKICAxLT5EIEUtPkEgMi0+NCAxLT41IDEtPkYKICBFLT42IDQtPjYgNS0+NyA2LT43IDMtPjggMy0+MQp9CiIpCgpgYGAKCgoKCiMjIFNlcXVlbmNlIERpYWdyYW0tMgoKIyMgU2VxdWVuY2UgRGlhZ3JhbSAzCgojIyBNaW5kbWFwCgoKCiMjIEdhbnR0IENoYXJ0CgoKCiMjIEZsb3cgY2hhcnQKCgoKCgoKIyBVc2luZyBgbm9tbm9tbGAKCmBub21ub21sYCBpcyB0b3V0ZWQgYXMgYSAic2Fzc3kiIFVNTCBkaWFncmFtIGNyZWF0b3IsIGluIFIuIEl0IGFsbG93cyB1cwp0byByYXBpZGx5IGNyZWF0ZSBtYW55IG9mIGRpYWdyYW1zIHRoYXQgd2UgY2FuIHVzZSBpbiBTeXN0ZW0gRGVzY3JpcHRpb25zLgoKVGhlIHN5bnRheCBvcHRpb25zIGZvciBub21ub21sIGFuZCB3aGF0IGNhbiBiZSBjcmVhdGVkIGlzIGRlc2NyaWJlZCBoZXJlCjxodHRwczovL25vbW5vbWwuY29tLz4KClRoZSBSIHBkZiBNYW51YWwgZm9yIG5vbW5vbWwgYXQKW0NSQU5dKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9ub21ub21sL25vbW5vbWwucGRmKSAoCnJlYWQganVzdCB0aGUgZmlyc3QgaGFsZi1wYWdlIGFuZCB5b3UgYXJlIHJlYWR5ISEpCgpTbyB3aGF0IGNhbiBpdCBkbz8KCmBgYHtub21ub21sfQojaW1wb3J0OiBmaWxlbmFtZQojYXJyb3dTaXplOiAxCiNiZW5kU2l6ZTogMC4zCiNkaXJlY3Rpb246IGRvd24gfCByaWdodAojZ3V0dGVyOiA1CiNlZGdlTWFyZ2luOiAwCiNncmF2aXR5OiAxCiNlZGdlczogaGFyZCB8IHJvdW5kZWQKI2JhY2tncm91bmQ6IGxpZ2h0Z3JleQoKLy9uZXN0ZWQgbGlzdCBvZiBjb2xvdXJzCi8vI2ZpbGw6ICNmY2ZjZmM7ICNlZWU4ZDU7ICNmZGY2ZTMKI2ZpbGw6IGxpZ2h0Z3JlZW47IHBpbms7CiNmaWxsQXJyb3dzOiBmYWxzZQojZm9udDogQ2FsaWJyaQojZm9udFNpemU6IDEyCiNsZWFkaW5nOiAxLjI1CiNsaW5lV2lkdGg6IDMKI3BhZGRpbmc6IDgKI3NwYWNpbmc6IDQwCiNzdHJva2U6ICMzMzMyMkUKI3RpdGxlOiBmaWxlbmFtZQojem9vbTogMQojYWN5Y2xpY2VyOiBncmVlZHkKI3JhbmtlcjogbmV0d29yay1zaW1wbGV4IHwgdGlnaHQtdHJlZSB8IGxvbmdlc3QtcGF0aAoKW1BpcmF0ZXxleWVDb3VudDogSW50fHJhaWQoKXxwaWxsYWdlKCl8CiAgW2JlYXJkXS0tW3BhcnJvdF0KICBbYmVhcmRdLTo+W2ZvdWwgbW91dGhdCiAgXQoKWzx0YWJsZT5taXNjaGllZiB8IGJhd2wgfCBzaW5nIHx8IHllbGwgfCBkcmlua10KCls8YWJzdHJhY3Q+TWFyYXVkZXJdPDotLVtQaXJhdGVdCltQaXJhdGVdLSAwLi43W21pc2NoaWVmXQpbam9sbHluZXNzXV8+W1BpcmF0ZV0KW2pvbGx5bmVzc10tPltydW1dCltqb2xseW5lc3NdLT5bc2luZ2luZ10KW1BpcmF0ZV0tPiAqW3J1bXx0YXN0aW5lc3M6IEludHxzd2lnKCldCltQaXJhdGVdLT5bc2luZ2luZ10KW3NpbmdpbmddPC0+W3J1bV0KCls8c3RhcnQ+c3RdLT5bPHN0YXRlPnBsdW5kZXJdCltwbHVuZGVyXS0+WzxjaG9pY2U+bW9yZSBsb290XQpbbW9yZSBsb290XS0+W3N0XQpbbW9yZSBsb290XSBubyAtPls8ZW5kPmVdCgpbPGFjdG9yPlNhaWxvcl0gLSBbPHVzZWNhc2U+c2hpdmVyIG1lO3RpbWJlcnNdCmBgYAoKIyMgU29tZSBkZWZpbml0aW9ucyBvbiB0aGUgImdyYW1tYXIgb2Ygc2hhcGVzIiBpbiBgbm9tbm9tbGAKCjEuICBBc3NvY2lhdGlvbiBUeXBlczogQ29ubmVjdG9ycyBiZXR3ZWVuIGJsb2NrcyggaS5lLiBDbGFzc2lmaWVycykKCjIuICBDbGFzc2lmaWVyIFR5cGVzOiBLaW5kcyBvZiAqKmJsb2NrcyoqLgoKMy4gIERpcmVjdGl2ZSBUeXBlczogRGlyZWN0aXZlcyBjaGFuZ2UgdGhlIG5hdHVyZSBvZiB0aGUgZGlhZ3JhbQogICAgcmVuZGVyZWQsIGJ5IGFmZmVjdGl2ZSBwYXJhbWV0ZXJzIGxpa2UgY29sb3VyLCBkaXJlY3Rpb24gYW5kCiAgICBtYXJnaW5zLiAoIEhhISBWQyBwZW9wbGUhISkKCkNTUyBjb2xvdXJzIDxodHRwczovL3d3dy53M3NjaG9vbHMuY29tL2Nzc3JlZi9jc3NfY29sb3JzLmFzcD4gT25seSB0aGVzZQpjb2xvdXJzIGFyZSBwZXJtaXR0ZWQsIHNvIHVzZSBlaXRoZXIgdGhlIG5hbWVzIG9yIHRoZXNlIHNwZWNpZmljIGNvbG91cgpoYXNoIGNvZGVzLiBBbnkgZ2VuZXJhbCBoYXNoIGNvZGUgd2lsbCAqbm90KiByZW5kZXIuCgpgYGB7bm9tbm9tbCBhc3NvY2lhdGlvbi0xfQovL2Fzc29jaWF0aW9uLTEKW2FdIC0gW2JdIAoKLy9hc3NvY2lhdGlvbi0yCltiXSAtPiBbY10gCgovL2Fzc29jaWF0aW9uXzMKW2NdIDwtPiBbYV0KCi8vZGVwZW5kZW5jeS0xClthXSA8LS0+W2RdCgovL2RlcGVuZGVuY3ktMgojLmVsbDogdmlzdWFsPWVsbGlwc2UgZmlsbD0jZmJmYjA5IGJvbGQKIy5hcnZpbmQ6IHZpc3VhbD1yaG9tYiBmaWxsPSNmZjIyMzQgYm9sZApbPGVsbD5lXS0tPlthXQovL2dlbmVyYWxpemF0aW9uLTEKW2NdLTo+WzxhcnZpbmQ+a10KCi8vaW1wbGVtZW50YXRpb24gLS06Pgpba10tLTo+W2RdCmBgYAoKYGBge25vbW5vbWwgYXNzb2NpYXRpb24tMixzdmc9VFJVRX0KLy9jb21wb3NpdGlvbiArLQpbYV0rLVtiXQovL2NvbXBvc2l0aW9uICstPgpbYl0tK1tjXQovL2FnZ3JlZ2F0aW9uIG8tCltjXW8tPltkXQovL2FnZ3JlZ2F0aW9uIG8tPgpbZF1vLT5bYV0KLy9ub3RlIC0tCltkXS0tW2V2ZXJ5dGhpbmcgaGFwcGVucztoZXJlXQovL2hpZGRlbiAtLy0KW2RdLS8tW2ZdCi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwovL3dlaWdodGxlc3MgZWRnZSBfPgovL1trXV8+W2RdIC8vbm90IHdvcmtpbmcKLy93ZWlnaHRsZXNzIGRhc2hlZF9fCi8vW2RdX19bal0gLy9ub3Qgd29ya2luZwpgYGAKCiMjIyBDbGFzc2lmaWVyIFR5cGVzCgpUaGVzZSBhcmUgZGlmZmVyZW50IGtpbmRzIG9mICoqYmxvY2tzKiouCgpgYGB7bm9tbm9tbCwgc3ZnPVRSVUV9CltjbGFzc10tPls8YWJzdHJhY3Q+IGFic3RyYWN0XQpbPGFic3RyYWN0PiBhYnN0cmFjdF0tOj5bPGluc3RhbmNlPiBpbnN0YW5jZV0KWzxpbnN0YW5jZT4gaW5zdGFuY2VdLTo+Wzxub3RlPiBub3RlXQpbPG5vdGU+IG5vdGVdLS0+WzxyZWZlcmVuY2U+IHJlZmVyZW5jZV0KYGBgCgpgYGB7bm9tbm9tbH0KWzxwYWNrYWdlPiBwYWNrYWdlfGNvbXBvbmVudHNdLS0+WzxmcmFtZT4gZnJhbWV8XQpbPGRhdGFiYXNlPiBkYXRhYmFzZV0tLT5bPHN0YXJ0PiBzdGFydF0KWzxlbmQ+IGVuZF0tbz5bPHN0YXRlPiBzdGF0ZV0KYGBgCgpgYGB7bm9tbm9tbH0KWzxjaG9pY2U+IGNob2ljZV0tLS0+WzxzeW5jPiBzeW5jXQpbPGlucHV0PiBpbnB1dF0tPls8c2VuZGVyPiBzZW5kZXJdCls8cmVjZWl2ZXI+IHJlY2VpdmVyXW8tWzx0cmFuc2NlaXZlcj4gdHJhbnNjZWl2ZXJdCmBgYAoKYGBge25vbW5vbWwsIHN2Zz1UUlVFfQojZGlyZWN0aW9uOmRvd24KI2JhY2tncm91bmQ6bGlnaHRncmV5CiNmaWxsOiBmdWNoc2lhOyBncmVlbjsgcHVycGxlCiNmaWxsQXJyb3dzOiBmYWxzZQojZm9udDogQ291cmllcgpbY2xhc3NdLT5bPGFic3RyYWN0PiBhYnN0cmFjdF0KWzxhYnN0cmFjdD4gYWJzdHJhY3RdLTo+WzxpbnN0YW5jZT4gaW5zdGFuY2VdCls8aW5zdGFuY2U+IGluc3RhbmNlXS06Pls8bm90ZT4gbm90ZV0KWzxub3RlPiBub3RlXS0tPls8cmVmZXJlbmNlPiByZWZlcmVuY2VdCmBgYAoKYGBge25vbW5vbWx9CiNmb250OiBDZW50dXJ5U2Nob29sYm9vawojZmlsbDogbGlnaHR5ZWxsb3cKI3N0cm9rZTogZ3JlZW4KCls8YWN0b3I+IGFjdG9yXS0tLVs8dXNlY2FzZT4gdXNlY2FzZV0KWzx1c2VjYXNlPiB1c2VjYXNlXTwtLT5bPGxhYmVsPiBsYWJlbF0KWzx1c2VjYXNlPiB1c2VjYXNlXS0vLVs8aGlkZGVuPiBoaWRkZW5dCmBgYAoKYGBge25vbW5vbWx9Cls8dGFibGU+IHRhYmxlfCBhIHwgNSB8fCBiIHwgN10KYGBgCgpgYGB7bm9tbm9tbH0KWzx0YWJsZT4gdGFibGV8IGMgfCA5IF0KYGBgCgojIyBEaXJlY3RpdmVzCgpEaXJlY3RpdmVzIGNoYW5nZSB0aGUgbmF0dXJlIG9mIHRoZSBkaWFncmFtIHJlbmRlcmVkLCBieSBhZmZlY3RpdmUKcGFyYW1ldGVycyBsaWtlIGNvbG91ciwgZGlyZWN0aW9uIGFuZCBtYXJnaW5zLgoKIyMgQ3VzdG9tIGNsYXNzaWZpZXIgc3R5bGVzCgpBIGRpcmVjdGl2ZSB0aGF0IHN0YXJ0cyB3aXRoICIuIiBkZWZpbmUgYSAqKmNsYXNzaWZpZXIncyBzdHlsZSoqLiBUaGUKc3R5bGUgaXMgd3JpdHRlbiBhcyBhIHNwYWNlIHNlcGFyYXRlZCBsaXN0IG9mICptb2RpZmllcnMqIGFuZCAqa2V5L3ZhbHVlCnBhaXJzKi4KCmBgYHtub21ub21sfQojLmJveDogZmlsbD0jOGY4IGRhc2hlZAojLmJsb2I6IHZpc3VhbD1lbGxpcHNlIHRpdGxlPWJvbGQKIy5hcnZpbmQ6IHZpc3VhbD1yaG9tYiB0aXRsZT1ib2xkIGRhc2hlZCBmaWxsPUNvcm5GbG93ZXJCbHVlCls8Ym94PiBHcmVlbkJveF0KWzxibG9iPiBCbG9iYnldCls8YXJ2aW5kPiBTb21lb25lXQpgYGAKCiMjIGBub21ub21sYCBLZXkvdmFsdWUgcGFpcnMKCi0gICBmaWxsPShhbnkgY3NzIGNvbG9yKQotICAgc3Ryb2tlPShhbnkgY3NzIGNvbG9yKQotICAgYWxpZ249Y2VudGVyIGFsaWduPWxlZnQKLSAgIGRpcmVjdGlvbj1yaWdodCBkaXJlY3Rpb249ZG93bgotICAgdmlzdWFsPWFjdG9yCi0gICB2aXN1YWw9Y2xhc3MKLSAgIHZpc3VhbD1kYXRhYmFzZQotICAgdmlzdWFsPWVsbGlwc2UKLSAgIHZpc3VhbD1lbmQKLSAgIHZpc3VhbD1mcmFtZQotICAgdmlzdWFsPWhpZGRlbgotICAgdmlzdWFsPWlucHV0Ci0gICB2aXN1YWw9bm9uZQotICAgdmlzdWFsPW5vdGUKLSAgIHZpc3VhbD1wYWNrYWdlCi0gICB2aXN1YWw9cmVjZWl2ZXIKLSAgIHZpc3VhbD1yaG9tYgotICAgdmlzdWFsPXJvdW5kcmVjdAotICAgdmlzdWFsPXNlbmRlcgotICAgdmlzdWFsPXN0YXJ0Ci0gICB2aXN1YWw9c3luYwotICAgdmlzdWFsPXRhYmxlCi0gICB2aXN1YWw9dHJhbnNjZWl2ZXIKCiMjIFRleHQgbW9kaWZpZXJzCgpib2xkIGNlbnRlciBpdGFsaWMgbGVmdCB1bmRlcmxpbmUKCmBgYHtub21ub21sfQojIC5ib3g6IGZpbGw9IzhmOCBkYXNoZWQKIyAuYmxvYjogdmlzdWFsPXJob21iIHRpdGxlPWJvbGQgZmlsbD0jOGY4IGRhc2hlZAoKW0FdLVtCXQpbQl0tLVs8dXNlY2FzZT5DXQpbQ10tWzxib3g+IERdCltCXS0tWzxibG9iPiBKYWJiYTtUaGVIdXRdCmBgYAoKYGBge25vbW5vbWx9ClthXSAtPltiXQpbYl0gLTo+IFtjXQpbY11vLT5bZF0KW2RdLS8tW2VdCmBgYAoKYGBge25vbW5vbWx9CiNmaWxsOiBsaWdodGdyZWVuOyBsaWdodGJsdWU7IGxpZ2h0eWVsbG93OyBncmV5OyB3aGl0ZQoKWzx0YWJsZT4gdGFibGUgfCBjIHwgOSBdCgpbUiB8IFs8dGFibGU+IFBhY2thZ2VzIHwKICAgICAgICAgQmFzZSBSIHwKICAgICAgICAgWyA8dGFibGU+IHRpZHl2ZXJzZXwgZ2dwbG90IHwgdGlkeXIgfCByZWFkciB8CiAgICAgICAgICAgICBbPHRhYmxlPiBkcGx5cnwKICAgICAgICAgICAgICAgICBtYWdyaXR0ciB8IE90aGVyc11dXV0KYGBgCgpgYGB7bm9tbm9tbH0KI2ZpbGw6IGxpZ2h0Z3JlZW47IGxpZ2h0Ymx1ZTsgbGlnaHR5ZWxsb3c7IHBpbms7IHdoaXRlCgpbUlN0dWRpbyB8IFtSIHwgWzx0YWJsZT4gUGFja2FnZXMgfAogICAgICAgICAgICAgICAgICAgQmFzZSBSIHwgWyB0aWR5dmVyc2UgfAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2dwbG90IHwgdGlkeXIgfCByZWFkciB8CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbZHBseXJdLS1bbWFncml0dHJdCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbZHBseXJdLS1bT3RoZXJzXQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgdGliYmxlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXQogICAgICAgICAgICAgICAgIHwgbHVicmlkYXRlIHwgRGlhZ3JhbW1lUiB8IExhdHRpY2VdXV0KYGBgCgpgYGB7bm9tbm9tbCBtaW5kbWFwfQpbTGludXhdKy1bVWJ1bnR1XQpbTGludXhdKy1bTWludF0KW1VidW50dV0tLVtNaW50XQpbTGludXhdKy1bUm9zYSBMaW51eF0KW0xpbnV4XSstW014IExpbnV4XQpbRGViaWFuXS0rW0xpbnV4XQoKCltGZWRvcmFdLStbTGludXhdCltQdXBweSBMaW51eF0tK1tMaW51eF0KW1BlcnNvbmFsIFB1cHNdLStbUHVwcHkgTGludXhdCgpgYGAK