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.
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
Packages
We will work with Diagrammer
first and then with
nomnoml
.
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.
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
}
")
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]
Some definitions on
the “grammar of shapes” in nomnoml
Association Types: Connectors between blocks(
i.e. Classifiers)
Classifier Types: Kinds of blocks.
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
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 ]
Directives
Directives change the nature of the diagram rendered, by affective
parameters like colour, direction and margins.
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]
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
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]
LS0tDQp0aXRsZTogIlRoZSBHcmFtbWFyIG9mIERpYWdyYW1zIg0Kc3VidGl0bGU6ICIgQ29udmVydGluZyBUZXh0IHRvIERpYWdyYW1zIGluIFIiDQphdXRob3I6IEFydmluZCBWZW5rYXRhZHJpDQphZmZpbGlhdGlvbjogU3Jpc2h0aSBNYW5pcGFsIEluc3RpdHV0ZSBvZiBBcnQsIERlc2lnbiwgYW5kIFRlY2hub2xvZ3ksIEJhbmdhbG9yZQ0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIHRoZW1lOiBmbGF0bHkNCiAgICB0b2M6IFRSVUUNCiAgICB0b2NfZmxvYXQ6IFRSVUUNCiAgICB0b2NfZGVwdGg6IDINCiAgICBudW1iZXJfc2VjdGlvbnM6IFRSVUUNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBjb2RlX2Rvd25sb2FkOiBUUlVFDQphYnN0cmFjdDogUGFydCBvZiB0aGUgYFIgZm9yIEFydGlzdHMgYW5kIERlc2lnbmVyc2Agd29ya3Nob3AgY291cnNlIGF0IHRoZSBTY2hvb2wgb2YgRm91bmRhdGlvbiBTdHVkaWVzLCBTcmlzaHRpIE1hbmlwYWwgSW5zdGl0dXRlIG9mIEFydCwgRGVzaWduLCBhbmQgVGVjaG5vbG9neSwgQmFuZ2Fsb3JlLg0KLS0tDQoNCiMgSW50cm9kdWN0aW9uDQoNClRoZXJlIGFyZSBtYW55IHByZXNlbnRhdGlvbiBhbmQgZHJhd2luZyB0b29scyBvdXQgdGhlcmUuIEFuZCB0aGVzZSBhbGxvdyB0aGUgdXNlciBmdWxsIGNvbnRyb2wgb3ZlciB0aGUgZGlhZ3JhbSBzbyBnZW5lcmFsbHkgcmVzdWx0IGluIHByZXR0aWVyIGRpYWdyYW1zIHRoYXQgY2FuIGNvbnZleSBtb3JlIGluZm9ybWF0aW9uIHRvIHRoZSBhdWRpZW5jZSBhdCB0aGF0IHBvaW50IGluIHRpbWUuDQoNCkJ1dCB0aGF0IHBvaW50IGluIHRpbWUgcGFzc2VzLCBhbmQgKipwcmV0dHkgcGljdHVyZXMgY2FuIHF1aWNrbHkgYmVjb21lIG91dC1vZi1kYXRlKiogYW5kLCBpcm9uaWNhbGx5LCBtaXNpbmZvcm1pbmcgaWYgdGhleSBkb24ndCBtYXRjaCB0aGUgcmVhbGl0eSBvZiB0aGUgc3lzdGVtIHRoZXkgYXJlIGRlc2NyaWJpbmcuIFRoaXMgaXMgZXNwZWNpYWxseSBzbyBpZiBvbmUgdGVhbSBpcyBkcmF3aW5nIHRoZSBwcmV0dHkgcGljdHVyZXMsIGFuZCBhbm90aGVyIHRlYW0gaXMgd3JpdGluZyB0aGUgc29mdHdhcmUvaW1wbGVtZW50aW5nIHRoZSBzeXN0ZW0uDQoNCkhhdmluZyAqKmRpYWdyYW1zIGFzIGNvZGUgdGhhdCBjYW4gbGl2ZSBiZXNpZGUgdGhlIHN5c3RlbSBkZXNpZ24vY29kZSoqLCB0aGF0IHRoZSBzdGFrZWhvbGRlcnMgYXJlIGVxdWFsbHkgY29tZm9ydGFibGUgZWRpdGluZyBhbmQgdmlld2luZyxyZWR1Y2VzIHRoZSBnYXAgaS5lLiAiV2hlcmUgc3lzdGVtIGRpYWdyYW1zIG1lZXQgc3lzdGVtIHJlYWxpdHkiLg0KDQpXZSB3aWxsICJleHBsb3JlIiB0d28gcGFja2FnZXMgdG8gZG8gdGhpczogYERpYWdyYW1tZVJgDQphbmQgYG5vbW5vbWxgLiBFYWNoIG9mIHRoZXNlIGZvbGxvd3MgYSBzcGVjaWZpYyBncmFtbWFyIHNvIHRoYXQgc2V0cyBvZiAic2VudGVuY2VzIiB3aWxsIG1vcnBoIGludG8gdmVyeSBkaWZmZXJlbnQga2luZHMgb2YgZGlhZ3JhbXMuDQoNCg0KIyBHb2Fscw0KDQpBdCB0aGUgZW5kIG9mIHRoaXMgTGFiIHNlc3Npb24sIHdlIHdpbGwgYmUgYWJsZSB0bzoNCg0KLSBNYWtlIGNvbmNlcHR1YWwgQmxvY2sgRGlhZ3JhbXMgb2YgZGlmZmVyZW50IHR5cGVzLCB1c2luZyBgdGV4dGANCi0gQmUgYWJsZSB0byBjcmVhdGUgRmxvdyBDaGFydHMsIFNlcXVlbmNlIERpYWdyYW1zLCBHYW50dCBDaGFydHMgZXRjLiB0byByZXByZXNlbnQgZGl2ZXJzZSByZWFsaXRpZXMgaW4gZGlhZ3JhbSBmb3JtDQotIEJlIGFibGUgdG8gdXNlIGBtZXJtYWlkYCBhbmQgYG5vbW9tbGAgc3ludGF4IGluIFINCg0KIyBQYWNrYWdlcw0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgbWVzc2FnZSA9IEZBTFNFKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KERpYWdyYW1tZVIpDQpsaWJyYXJ5KG5vbW5vbWwpDQpgYGANCg0KV2Ugd2lsbCB3b3JrIHdpdGggYERpYWdyYW1tZXJgIGZpcnN0IGFuZCB0aGVuIHdpdGggYG5vbW5vbWxgLiANCg0KDQojIFVzaW5nIERpYWdyYW1tZVINCg0KYERpYWdyYW1tZVJgIGlzIGEgdW5pcXVlIHBhY2thZ2Ugc2luY2UgaXQgYWxsb3dzIHlvdSBjcmVhdGUgRGlhZ3JhbXMgKiphbmQqKiB0aGUgTmV0d29yayBEaWFncmFtcyB0aGF0IHlvdSBoYXZlIGNyZWF0ZWQgdXNpbmcgYHRpZHlncmFwaGAgYW5kIGBnZ3JhcGhgLiBBbmQgaXQgdXNlcyB0aGUgdGlkeXZlcnNlIHBpcGUgYCU+JWAgc3ludGF4IHRvbyEgU28gaXQgaXMgd29ydGggZXhwbG9yaW5nIGluIGl0cyBlbnRpcmV0eS4gQnV0IHRoYXQgaXMgZm9yIGFub3RoZXIgdGltZSwgb3IgcGVyaGFwcyB5b3UgY2FuIGV4cGxvcmUgdGhpcyB5b3Vyc2VsZiEhDQoNCg0KKipNZXJtYWlkKiogbGFuZ3VhZ2UgKCoqV2hhdCAhISBBbm90aGVyIGxhbmd1YWdlPyEhISoqKSBpcyBhbiBhcHByb2FjaCB0byBjcmVhdGluZyBkaWFncmFtcyB1c2luZyB0ZXh0LiAgSXQgaXMgYW4gaW50ZWdyYWwgcGFydCBvZiB0aGUgYERpYWdyYW1tZVJgIFIgcGFja2FnZS4gQW5kIGhlbmNlIHRoZSBjb2RlIHlvdSB3cml0ZSBpcyBhY3R1YWxseSBSIGNvZGUsIHRvIGNyZWF0ZSBEaWFncmFtcy4NCg0KIyMgU2VxdWVuY2UgRGlhZ3JhbQ0KDQpMb29rIGF0IHRoZSBjb2RlIGJlbG93OiBXaGF0IGRvIHlvdSB0aGluayBpdCByZXByZXNlbnRzPw0KDQpgYGB7ciBTZXF1ZW5jZV8xfQ0KRGlhZ3JhbW1lUigiDQpzZXF1ZW5jZURpYWdyYW0NCkFydmluZCAtPj4gQW5hbWlrYTogV2h5IGFyZSB5b3UgbGF0ZSB0b2RheT8NCkFuYW1pa2EgLT4+IEFuYW1pa2E6IFVscC4uLg0KQW5hbWlrYSAtPj4gQXJ2aW5kOiBJIGFtIHNvcnJ5Li4uIDxicj4gbWF5IEkgY29tZSBpbiBwbGVhc2U/DQoNCkFydmluZCAtPj4gS29tYWw6IEFuZCB5b3U/IFdoYXQga2VwdCB5b3U/DQpLb21hbCAtPj4gQW5hbWlrYTogKFF1aWV0bHkpIEhlJ3MgaGF2aW5nIGEgYmFkIGRheSwgZHVkZS4uLg0KQW5hbWlrYSAtPj4gS29tYWw6IChXaGlzcGVyKSBCb29tZXIuLi4NCiIpDQoNCmBgYA0KVGhpcyBpcyBhIHNpbXBsZSBTZXF1ZW5jZSBEaWFncmFtISBTaG93cyBhICoqc3RyaWN0bHkqKiBpbWFnaW5hcnkgZXhjaGFuZ2UgYmV0d2VlbiBhIHBhaXIgb2Ygc3R1ZGVudHMgYW5kIGFuIHVua25vd24gRmFjdWx0eSBNZW1iZXIuDQoNCkxldCB1cyBub3cgc2VlIGhvdyB3ZSBjYW4gZW1iZWxsaXNoIHRoaXMga2luZCBvZiBkaWFncmFtLiBDYW4gd2UgaGF2ZSBhIEdhcmRlbiBvZiBGb3JraW5nIFBhdGhzPw0KDQpgYGB7cn0NCkRpYWdyYW1tZVIoIg0KICAgIG1lcm1haWQuc2VxdWVuY2VDb25maWcgPSB7DQogICAgZGlhZ3JhbU1hcmdpblg6IDUwLA0KICAgIGRpYWdyYW1NYXJnaW5ZOiAxMCwNCiAgICBib3hUZXh0TWFyZ2luOiA1LA0KICAgIG5vdGVNYXJnaW46IDEwLA0KICAgIG1lc3NhZ2VNYXJnaW46IDM1LA0KICAgIG1pcnJvckFjdG9yczogdHJ1ZQ0KfTsNCiIpDQpgYGANCg0KDQpgYGB7ciBTZXF1ZW5jZV8yfQ0KDQpEaWFncmFtbWVSKCINCiAgICAgICAgc2VxdWVuY2VEaWFncmFtDQogICAgICAgIA0KICAgICAgICBhbHQgQW5hbWlrYSBpcyBhbHdheXMgcHVuY3R1YWwNCiAgICAgICAgQXJ2aW5kIC0+PiBBbmFtaWthOiBXaHkgaGF2ZW4ndCB5b3UgcHV0IHVwIHlvdXIgRGFpbHkgUmVmbGVjdGlvbj8NCiAgICAgICAgQW5hbWlrYSAtPj4gQW5hbWlrYTogVWxwLi4uDQogICAgICAgIE5vdGUgcmlnaHQgb2YgQW5hbWlrYSA6IEkgaGF2ZSBoYWQgaXQgdG9kYXkuLg0KICAgICAgICBBbmFtaWthIC0+PiBBcnZpbmQ6IEkgYW0gc29ycnkuLi4gDQogICAgICAgIEFydmluZCAtPj4gQW5hbWlrYTogT2sgd3JpdGUgaXQgdG9kYXkNCiAgICAgICAgDQogICAgICAgIGVsc2UgQW5hbWlrYSBpcyB1c3VhbGx5IHRhcmR5DQogICAgICAgIEFydmluZCAtPj4gQW5hbWlrYTogV2h5IGhhdmVuJ3QgeW91IHB1dCB1cCB5b3VyIERhaWx5IFJlZmxlY3Rpb24/DQogICAgICAgIEFuYW1pa2EgLT4+IEFuYW1pa2E6IFVscC4uLg0KICAgICAgICBBbmFtaWthIC0+PiBBcnZpbmQ6IEkgYW0gc29ycnkuLi4gDQogICAgICAgIEFydmluZCAtPj4gQW5hbWlrYTogVGhpcyBpcyBub3QgYWNjZXB0YWJsZSBhbmQgd2lsbCByZWZsZWN0IGluIHlvdXIgZ3JhZGUNCiAgICAgICAgZW5kDQogICAgICAgIA0KICAgICAgICBBcnZpbmQgLT4+IEtvbWFsOiBBbmQgeW91PyBXaGF0IGtlcHQgeW91Pw0KICAgICAgICBLb21hbCAtPj4gQW5hbWlrYTogKFF1aWV0bHkpIEhlJ3MgaGF2aW5nIGEgYmFkIGRheSwgZHVkZS4uLg0KICAgICAgICBBbmFtaWthIC0+PiBLb21hbDogKFdoaXNwZXIpIEJvb21lci4uLg0KICAgICAgICBOb3RlIG92ZXIgQW5hbWlrYSxLb21hbDogR2lnZ2xlLi4uDQoiKQ0KDQpgYGANCg0KRnJvbSBoZXJlOiA8aHR0cHM6Ly9jeWJlcmhlbHAuc2VzeW5jLm9yZy9ibG9nL3Zpc3VhbGl6YXRpb24td2l0aC1kaWFncmFtbWVSLmh0bWw+DQoNCg0KYGBge3J9DQpnclZpeigiZGlncmFwaHsNCg0KICAgICAgZ3JhcGhbcmFua2RpciA9IExSXQ0KICANCiAgICAgIG5vZGVbc2hhcGUgPSByZWN0YW5nbGUsIHN0eWxlID0gZmlsbGVkXQ0KICANCiAgICAgIG5vZGVbZmlsbGNvbG9yID0gQ29yYWwsIG1hcmdpbiA9IDAuMl0NCiAgICAgIEFbbGFiZWwgPSAnRmlndXJlIDE6IE1hcCddDQogICAgICBCW2xhYmVsID0gJ0ZpZ3VyZSAyOiBNZXRyaWNzJ10NCiAgDQogICAgICBub2RlW2ZpbGxjb2xvciA9IEN5YW4sIG1hcmdpbiA9IDAuMl0NCiAgICAgIENbbGFiZWwgPSAnRmlndXJlcy5SbWQnXQ0KICANCiAgICAgIG5vZGVbZmlsbGNvbG9yID0gVmlvbGV0LCBtYXJnaW4gPSAwLjJdDQogICAgICBEW2xhYmVsID0gJ0FuYWx5c2lzXzEuUiddDQogICAgICBFW2xhYmVsID0gJ0FuYWx5c2lzXzIuUiddDQogIA0KICAgICAgc3ViZ3JhcGggY2x1c3Rlcl8wIHsNCiAgICAgICAgZ3JhcGhbc2hhcGUgPSByZWN0YW5nbGVdDQogICAgICAgIHN0eWxlID0gcm91bmRlZA0KICAgICAgICBiZ2NvbG9yID0gR29sZA0KICAgIA0KICAgICAgICBsYWJlbCA9ICdEYXRhIFNvdXJjZSAxJw0KICAgICAgICBub2RlW3NoYXBlID0gcmVjdGFuZ2xlLCBmaWxsY29sb3IgPSBMZW1vbkNoaWZmb24sIG1hcmdpbiA9IDAuMjVdDQogICAgICAgIEZbbGFiZWwgPSAnbXlfZGF0YWZyYW1lXzEuY3N2J10NCiAgICAgICAgR1tsYWJlbCA9ICdteV9kYXRhZnJhbWVfMi5jc3YnXQ0KICAgICAgfQ0KICANCiAgICAgIHN1YmdyYXBoIGNsdXN0ZXJfMSB7DQogICAgICAgICBncmFwaFtzaGFwZSA9IHJlY3RhbmdsZV0NCiAgICAgICAgIHN0eWxlID0gcm91bmRlZA0KICAgICAgICAgYmdjb2xvciA9IEdvbGQNCiAgICANCiAgICAgICAgIGxhYmVsID0gJ0RhdGEgU291cmNlIDInDQogICAgICAgICBub2RlW3NoYXBlID0gcmVjdGFuZ2xlLCBmaWxsY29sb3IgPSBMZW1vbkNoaWZmb24sIG1hcmdpbiA9IDAuMjVdDQogICAgICAgICBIW2xhYmVsID0gJ215X2RhdGFmcmFtZV8zLmNzdiddDQogICAgICAgICBJW2xhYmVsID0gJ215X2RhdGFmcmFtZV80LmNzdiddDQogICAgICB9DQogIA0KICAgICAgZWRnZVtjb2xvciA9IGJsYWNrLCBhcnJvd2hlYWQgPSB2ZWUsIGFycm93c2l6ZSA9IDEuMjVdDQogICAgICBDIC0+IHtBIEJ9DQogICAgICBEIC0+IEMNCiAgICAgIEUgLT4gQw0KICAgICAgRiAtPiBEDQogICAgICBHIC0+IEQNCiAgICAgIEggLT4gRQ0KICAgICAgSSAtPiBFDQogICAgICANCiAgICAgIH0iKQ0KDQpgYGANCg0KDQpgYGB7cn0NCm1lcm1haWQoIg0KICAgICAgICBncmFwaCBCVA0KICAgICAgICBBKChTYWxpbml0eSkpDQogICAgICAgIEEtLT5CKEJhcm5hY2xlcykNCiAgICAgICAgQi0uLT58LTAuMTB8QjF7TXVzc2Vsc30NCiAgICAgICAgQS0tIDAuMzAgLS0+QjENCg0KICAgICAgICBDW0FpciBUZW1wXQ0KICAgICAgICBDLS0+Qg0KICAgICAgICBDLS4tPkUoTWFjcm9hbGdhZSkNCiAgICAgICAgRS0tPkIxDQogICAgICAgIEM9PSAwLjg5ID09PkIxDQoNCiAgICAgICAgc3R5bGUgQSBmaWxsOiNGRkYsIHN0cm9rZTojMzMzLCBzdHJva2Utd2lkdGg6NHB4DQogICAgICAgIHN0eWxlIEIgZmlsbDojOUFBLCBzdHJva2U6IzlBQSwgc3Ryb2tlLXdpZHRoOjJweA0KICAgICAgICBzdHlsZSBCMSBmaWxsOiM4NzksIHN0cm9rZTojMzMzLCBzdHJva2Utd2lkdGg6MXB4DQogICAgICAgIHN0eWxlIEMgZmlsbDojQURGLCBzdHJva2U6IzMzMywgc3Ryb2tlLXdpZHRoOjJweA0KICAgICAgICBzdHlsZSBFIGZpbGw6IzlDMiwgc3Ryb2tlOiM5QzIsIHN0cm9rZS13aWR0aDoycHgNCg0KICAgICAgICAiKQ0KYGBgDQoNCmBgYHtyfQ0KRGlhZ3JhbW1lUigiDQpzZXF1ZW5jZURpYWdyYW0NCiAgQXJ2aW5kIC0+PnRpY2tldCBzZWxsZXI6IGFzayB0aWNrZXQNCiAgdGlja2V0IHNlbGxlci0+PmRhdGFiYXNlOiBzZWF0cw0KICBhbHQgdGlja2V0cyBhdmFpbGFibGUNCiAgICBkYXRhYmFzZS0+PnRpY2tldCBzZWxsZXI6IG9rDQogICAgdGlja2V0IHNlbGxlci0+PmN1c3RvbWVyOiBjb25maXJtDQogICAgQXJ2aW5kIC0+PnRpY2tldCBzZWxsZXI6IG9rDQogICAgdGlja2V0IHNlbGxlci0+PmRhdGFiYXNlOiBib29rIGEgc2VhdA0KICAgIHRpY2tldCBzZWxsZXItPj5wcmludGVyOiBwcmludCB0aWNrZXQNCiAgZWxzZSBzb2xkIG91dA0KICAgIGRhdGFiYXNlLT4+dGlja2V0IHNlbGxlcjogbm9uZSBsZWZ0DQogICAgdGlja2V0IHNlbGxlci0+PmN1c3RvbWVyOiBzb3JyeQ0KICBlbmQNCiIpDQpgYGANCmBgYHtyfQ0KRGlhZ3JhbW1lUigiDQogIGdyYXBoIExSDQogICAgQS0tPkINCiAgICBBLS0+Qw0KICAgIEMtLT5FDQogICAgQi0tPkQNCiAgICBDLS0+RA0KICAgIEQtLT5GDQogICAgRS0tPkYNCiIpDQoNCmBgYA0KDQpgYGB7ciB9DQpEaWFncmFtbWVSKA0KImdyYXBoIFRCOw0KQShSb3VuZGVkKS0tPkJbU3F1YXJlZF07DQpCLS0+Q3tBIERlY2lzaW9ufTsNCkMtLT5EW1NxdWFyZSBPbmVdOw0KQy0tPkVbU3F1YXJlIFR3b107DQoNCiUlIE5vdyBzdHlsaW5nIHRoZXNlIGJsb2Nrcw0Kc3R5bGUgQSBmaWxsOiNFNUUyNUY7ICANCnN0eWxlIEIgZmlsbDojODdBQjUxOyANCnN0eWxlIEMgZmlsbDojM0M4OTM3Ow0Kc3R5bGUgRCBmaWxsOiMyMzc3MkM7ICANCnN0eWxlIEUgZmlsbDojQjZFNkU2Ow0KIg0KKQ0KYGBgDQoNCg0KYGBge3IgRGlhZ3JhbW1lUiwgZmlnLndpZHRoPTcsIGZpZy5oZWlnaHQ9IDgsIGZpZy5hbGlnbj0nY2VudGVyJ30NCg0KICBnclZpeigiDQpkaWdyYXBoIGJveGVzX2FuZF9jaXJjbGVzIHsNCg0KICAjIGEgJ2dyYXBoJyBzdGF0ZW1lbnQNCiAgZ3JhcGggW292ZXJsYXAgPSB0cnVlLCBmb250c2l6ZSA9IDEwLGZvcmNlbGFiZWxzID0gdHJ1ZV0NCg0KICAjIHNldmVyYWwgJ25vZGUnIHN0YXRlbWVudHMNCiAgbm9kZSBbc2hhcGUgPSBib3gsZm9udG5hbWUgPSBIZWx2ZXRpY2EsIGNvbG9yID0gcmVkLCBzdHlsZSA9IGZpbGxlZF0NCiAgQVtsYWJlbCA9ICdUaGlzIGlzIFxcbiBhbiBpbnRlcm5hbCBcXG4gbGFiZWwnLCB4bGFiZWwgPSAnVGhpcyBpcyBcXG5hbiBleHRlcm5hbCBcXG5sYWJlbCddOyBCOyBDOyBEOyBFOyBGDQoNCiAgbm9kZSBbc2hhcGUgPSBjaXJjbGUsIGZpeGVkc2l6ZSA9IHRydWUsIGNvbG9yID0gcGFsZWdyZWVuLCB3aWR0aCA9IDAuOV0gLy8gc2V0cyBhcyBjaXJjbGVzDQogIDE7IDI7IDM7IDQ7IDU7IDY7IDc7IDgNCg0KICAjIHNldmVyYWwgJ2VkZ2UnIHN0YXRlbWVudHMNCiAgQS0+ezEsMiwzLDR9IEItPjIgQi0+MyBCLT40IEMtPkENCiAgMS0+RCBFLT5BIDItPjQgMS0+NSAxLT5GDQogIEUtPjYgNC0+NiA1LT43IDYtPjcgMy0+OCAzLT4xDQp9DQoiKQ0KDQpgYGANCg0KDQoNCg0KIyMgU2VxdWVuY2UgRGlhZ3JhbS0yDQoNCiMjIFNlcXVlbmNlIERpYWdyYW0gMw0KDQojIyBNaW5kbWFwDQoNCg0KDQojIyBHYW50dCBDaGFydA0KDQoNCg0KIyMgRmxvdyBjaGFydA0KDQoNCg0KDQoNCg0KIyBVc2luZyBgbm9tbm9tbGANCg0KYG5vbW5vbWxgIGlzIHRvdXRlZCBhcyBhICJzYXNzeSIgVU1MIGRpYWdyYW0gY3JlYXRvciwgaW4gUi4gSXQgYWxsb3dzIHVzDQp0byByYXBpZGx5IGNyZWF0ZSBtYW55IG9mIGRpYWdyYW1zIHRoYXQgd2UgY2FuIHVzZSBpbiBTeXN0ZW0gRGVzY3JpcHRpb25zLg0KDQpUaGUgc3ludGF4IG9wdGlvbnMgZm9yIG5vbW5vbWwgYW5kIHdoYXQgY2FuIGJlIGNyZWF0ZWQgaXMgZGVzY3JpYmVkIGhlcmUNCjxodHRwczovL25vbW5vbWwuY29tLz4NCg0KVGhlIFIgcGRmIE1hbnVhbCBmb3Igbm9tbm9tbCBhdA0KW0NSQU5dKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9ub21ub21sL25vbW5vbWwucGRmKSAoDQpyZWFkIGp1c3QgdGhlIGZpcnN0IGhhbGYtcGFnZSBhbmQgeW91IGFyZSByZWFkeSEhKQ0KDQpTbyB3aGF0IGNhbiBpdCBkbz8NCg0KYGBge25vbW5vbWx9DQojaW1wb3J0OiBmaWxlbmFtZQ0KI2Fycm93U2l6ZTogMQ0KI2JlbmRTaXplOiAwLjMNCiNkaXJlY3Rpb246IGRvd24gfCByaWdodA0KI2d1dHRlcjogNQ0KI2VkZ2VNYXJnaW46IDANCiNncmF2aXR5OiAxDQojZWRnZXM6IGhhcmQgfCByb3VuZGVkDQojYmFja2dyb3VuZDogbGlnaHRncmV5DQoNCi8vbmVzdGVkIGxpc3Qgb2YgY29sb3Vycw0KLy8jZmlsbDogI2ZjZmNmYzsgI2VlZThkNTsgI2ZkZjZlMw0KI2ZpbGw6IGxpZ2h0Z3JlZW47IHBpbms7DQojZmlsbEFycm93czogZmFsc2UNCiNmb250OiBDYWxpYnJpDQojZm9udFNpemU6IDEyDQojbGVhZGluZzogMS4yNQ0KI2xpbmVXaWR0aDogMw0KI3BhZGRpbmc6IDgNCiNzcGFjaW5nOiA0MA0KI3N0cm9rZTogIzMzMzIyRQ0KI3RpdGxlOiBmaWxlbmFtZQ0KI3pvb206IDENCiNhY3ljbGljZXI6IGdyZWVkeQ0KI3JhbmtlcjogbmV0d29yay1zaW1wbGV4IHwgdGlnaHQtdHJlZSB8IGxvbmdlc3QtcGF0aA0KDQpbUGlyYXRlfGV5ZUNvdW50OiBJbnR8cmFpZCgpfHBpbGxhZ2UoKXwNCiAgW2JlYXJkXS0tW3BhcnJvdF0NCiAgW2JlYXJkXS06Pltmb3VsIG1vdXRoXQ0KICBdDQoNCls8dGFibGU+bWlzY2hpZWYgfCBiYXdsIHwgc2luZyB8fCB5ZWxsIHwgZHJpbmtdDQoNCls8YWJzdHJhY3Q+TWFyYXVkZXJdPDotLVtQaXJhdGVdDQpbUGlyYXRlXS0gMC4uN1ttaXNjaGllZl0NCltqb2xseW5lc3NdXz5bUGlyYXRlXQ0KW2pvbGx5bmVzc10tPltydW1dDQpbam9sbHluZXNzXS0+W3NpbmdpbmddDQpbUGlyYXRlXS0+ICpbcnVtfHRhc3RpbmVzczogSW50fHN3aWcoKV0NCltQaXJhdGVdLT5bc2luZ2luZ10NCltzaW5naW5nXTwtPltydW1dDQoNCls8c3RhcnQ+c3RdLT5bPHN0YXRlPnBsdW5kZXJdDQpbcGx1bmRlcl0tPls8Y2hvaWNlPm1vcmUgbG9vdF0NClttb3JlIGxvb3RdLT5bc3RdDQpbbW9yZSBsb290XSBubyAtPls8ZW5kPmVdDQoNCls8YWN0b3I+U2FpbG9yXSAtIFs8dXNlY2FzZT5zaGl2ZXIgbWU7dGltYmVyc10NCmBgYA0KDQojIyBTb21lIGRlZmluaXRpb25zIG9uIHRoZSAiZ3JhbW1hciBvZiBzaGFwZXMiIGluIGBub21ub21sYA0KDQoxLiAgQXNzb2NpYXRpb24gVHlwZXM6IENvbm5lY3RvcnMgYmV0d2VlbiBibG9ja3MoIGkuZS4gQ2xhc3NpZmllcnMpDQoNCjIuICBDbGFzc2lmaWVyIFR5cGVzOiBLaW5kcyBvZiAqKmJsb2NrcyoqLg0KDQozLiAgRGlyZWN0aXZlIFR5cGVzOiBEaXJlY3RpdmVzIGNoYW5nZSB0aGUgbmF0dXJlIG9mIHRoZSBkaWFncmFtDQogICAgcmVuZGVyZWQsIGJ5IGFmZmVjdGl2ZSBwYXJhbWV0ZXJzIGxpa2UgY29sb3VyLCBkaXJlY3Rpb24gYW5kDQogICAgbWFyZ2lucy4gKCBIYSEgVkMgcGVvcGxlISEpDQoNCkNTUyBjb2xvdXJzIDxodHRwczovL3d3dy53M3NjaG9vbHMuY29tL2Nzc3JlZi9jc3NfY29sb3JzLmFzcD4gT25seSB0aGVzZQ0KY29sb3VycyBhcmUgcGVybWl0dGVkLCBzbyB1c2UgZWl0aGVyIHRoZSBuYW1lcyBvciB0aGVzZSBzcGVjaWZpYyBjb2xvdXINCmhhc2ggY29kZXMuIEFueSBnZW5lcmFsIGhhc2ggY29kZSB3aWxsICpub3QqIHJlbmRlci4NCg0KYGBge25vbW5vbWwgYXNzb2NpYXRpb24tMX0NCi8vYXNzb2NpYXRpb24tMQ0KW2FdIC0gW2JdIA0KDQovL2Fzc29jaWF0aW9uLTINCltiXSAtPiBbY10gDQoNCi8vYXNzb2NpYXRpb25fMw0KW2NdIDwtPiBbYV0NCg0KLy9kZXBlbmRlbmN5LTENClthXSA8LS0+W2RdDQoNCi8vZGVwZW5kZW5jeS0yDQojLmVsbDogdmlzdWFsPWVsbGlwc2UgZmlsbD0jZmJmYjA5IGJvbGQNCiMuYXJ2aW5kOiB2aXN1YWw9cmhvbWIgZmlsbD0jZmYyMjM0IGJvbGQNCls8ZWxsPmVdLS0+W2FdDQovL2dlbmVyYWxpemF0aW9uLTENCltjXS06Pls8YXJ2aW5kPmtdDQoNCi8vaW1wbGVtZW50YXRpb24gLS06Pg0KW2tdLS06PltkXQ0KYGBgDQoNCmBgYHtub21ub21sIGFzc29jaWF0aW9uLTIsc3ZnPVRSVUV9DQovL2NvbXBvc2l0aW9uICstDQpbYV0rLVtiXQ0KLy9jb21wb3NpdGlvbiArLT4NCltiXS0rW2NdDQovL2FnZ3JlZ2F0aW9uIG8tDQpbY11vLT5bZF0NCi8vYWdncmVnYXRpb24gby0+DQpbZF1vLT5bYV0NCi8vbm90ZSAtLQ0KW2RdLS1bZXZlcnl0aGluZyBoYXBwZW5zO2hlcmVdDQovL2hpZGRlbiAtLy0NCltkXS0vLVtmXQ0KLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vDQovL3dlaWdodGxlc3MgZWRnZSBfPg0KLy9ba11fPltkXSAvL25vdCB3b3JraW5nDQovL3dlaWdodGxlc3MgZGFzaGVkX18NCi8vW2RdX19bal0gLy9ub3Qgd29ya2luZw0KYGBgDQoNCiMjIyBDbGFzc2lmaWVyIFR5cGVzDQoNClRoZXNlIGFyZSBkaWZmZXJlbnQga2luZHMgb2YgKipibG9ja3MqKi4NCg0KYGBge25vbW5vbWwsIHN2Zz1UUlVFfQ0KW2NsYXNzXS0+WzxhYnN0cmFjdD4gYWJzdHJhY3RdDQpbPGFic3RyYWN0PiBhYnN0cmFjdF0tOj5bPGluc3RhbmNlPiBpbnN0YW5jZV0NCls8aW5zdGFuY2U+IGluc3RhbmNlXS06Pls8bm90ZT4gbm90ZV0NCls8bm90ZT4gbm90ZV0tLT5bPHJlZmVyZW5jZT4gcmVmZXJlbmNlXQ0KYGBgDQoNCmBgYHtub21ub21sfQ0KWzxwYWNrYWdlPiBwYWNrYWdlfGNvbXBvbmVudHNdLS0+WzxmcmFtZT4gZnJhbWV8XQ0KWzxkYXRhYmFzZT4gZGF0YWJhc2VdLS0+WzxzdGFydD4gc3RhcnRdDQpbPGVuZD4gZW5kXS1vPls8c3RhdGU+IHN0YXRlXQ0KYGBgDQoNCmBgYHtub21ub21sfQ0KWzxjaG9pY2U+IGNob2ljZV0tLS0+WzxzeW5jPiBzeW5jXQ0KWzxpbnB1dD4gaW5wdXRdLT5bPHNlbmRlcj4gc2VuZGVyXQ0KWzxyZWNlaXZlcj4gcmVjZWl2ZXJdby1bPHRyYW5zY2VpdmVyPiB0cmFuc2NlaXZlcl0NCmBgYA0KDQpgYGB7bm9tbm9tbCwgc3ZnPVRSVUV9DQojZGlyZWN0aW9uOmRvd24NCiNiYWNrZ3JvdW5kOmxpZ2h0Z3JleQ0KI2ZpbGw6IGZ1Y2hzaWE7IGdyZWVuOyBwdXJwbGUNCiNmaWxsQXJyb3dzOiBmYWxzZQ0KI2ZvbnQ6IENvdXJpZXINCltjbGFzc10tPls8YWJzdHJhY3Q+IGFic3RyYWN0XQ0KWzxhYnN0cmFjdD4gYWJzdHJhY3RdLTo+WzxpbnN0YW5jZT4gaW5zdGFuY2VdDQpbPGluc3RhbmNlPiBpbnN0YW5jZV0tOj5bPG5vdGU+IG5vdGVdDQpbPG5vdGU+IG5vdGVdLS0+WzxyZWZlcmVuY2U+IHJlZmVyZW5jZV0NCmBgYA0KDQpgYGB7bm9tbm9tbH0NCiNmb250OiBDZW50dXJ5U2Nob29sYm9vaw0KI2ZpbGw6IGxpZ2h0eWVsbG93DQojc3Ryb2tlOiBncmVlbg0KDQpbPGFjdG9yPiBhY3Rvcl0tLS1bPHVzZWNhc2U+IHVzZWNhc2VdDQpbPHVzZWNhc2U+IHVzZWNhc2VdPC0tPls8bGFiZWw+IGxhYmVsXQ0KWzx1c2VjYXNlPiB1c2VjYXNlXS0vLVs8aGlkZGVuPiBoaWRkZW5dDQpgYGANCg0KYGBge25vbW5vbWx9DQpbPHRhYmxlPiB0YWJsZXwgYSB8IDUgfHwgYiB8IDddDQpgYGANCg0KYGBge25vbW5vbWx9DQpbPHRhYmxlPiB0YWJsZXwgYyB8IDkgXQ0KYGBgDQoNCiMjIERpcmVjdGl2ZXMNCg0KRGlyZWN0aXZlcyBjaGFuZ2UgdGhlIG5hdHVyZSBvZiB0aGUgZGlhZ3JhbSByZW5kZXJlZCwgYnkgYWZmZWN0aXZlDQpwYXJhbWV0ZXJzIGxpa2UgY29sb3VyLCBkaXJlY3Rpb24gYW5kIG1hcmdpbnMuDQoNCiMjIEN1c3RvbSBjbGFzc2lmaWVyIHN0eWxlcw0KDQpBIGRpcmVjdGl2ZSB0aGF0IHN0YXJ0cyB3aXRoICIuIiBkZWZpbmUgYSAqKmNsYXNzaWZpZXIncyBzdHlsZSoqLiBUaGUNCnN0eWxlIGlzIHdyaXR0ZW4gYXMgYSBzcGFjZSBzZXBhcmF0ZWQgbGlzdCBvZiAqbW9kaWZpZXJzKiBhbmQgKmtleS92YWx1ZQ0KcGFpcnMqLg0KDQpgYGB7bm9tbm9tbH0NCiMuYm94OiBmaWxsPSM4ZjggZGFzaGVkDQojLmJsb2I6IHZpc3VhbD1lbGxpcHNlIHRpdGxlPWJvbGQNCiMuYXJ2aW5kOiB2aXN1YWw9cmhvbWIgdGl0bGU9Ym9sZCBkYXNoZWQgZmlsbD1Db3JuRmxvd2VyQmx1ZQ0KWzxib3g+IEdyZWVuQm94XQ0KWzxibG9iPiBCbG9iYnldDQpbPGFydmluZD4gU29tZW9uZV0NCmBgYA0KDQojIyBgbm9tbm9tbGAgS2V5L3ZhbHVlIHBhaXJzDQoNCi0gICBmaWxsPShhbnkgY3NzIGNvbG9yKQ0KLSAgIHN0cm9rZT0oYW55IGNzcyBjb2xvcikNCi0gICBhbGlnbj1jZW50ZXIgYWxpZ249bGVmdA0KLSAgIGRpcmVjdGlvbj1yaWdodCBkaXJlY3Rpb249ZG93bg0KLSAgIHZpc3VhbD1hY3Rvcg0KLSAgIHZpc3VhbD1jbGFzcw0KLSAgIHZpc3VhbD1kYXRhYmFzZQ0KLSAgIHZpc3VhbD1lbGxpcHNlDQotICAgdmlzdWFsPWVuZA0KLSAgIHZpc3VhbD1mcmFtZQ0KLSAgIHZpc3VhbD1oaWRkZW4NCi0gICB2aXN1YWw9aW5wdXQNCi0gICB2aXN1YWw9bm9uZQ0KLSAgIHZpc3VhbD1ub3RlDQotICAgdmlzdWFsPXBhY2thZ2UNCi0gICB2aXN1YWw9cmVjZWl2ZXINCi0gICB2aXN1YWw9cmhvbWINCi0gICB2aXN1YWw9cm91bmRyZWN0DQotICAgdmlzdWFsPXNlbmRlcg0KLSAgIHZpc3VhbD1zdGFydA0KLSAgIHZpc3VhbD1zeW5jDQotICAgdmlzdWFsPXRhYmxlDQotICAgdmlzdWFsPXRyYW5zY2VpdmVyDQoNCiMjIFRleHQgbW9kaWZpZXJzDQoNCmJvbGQgY2VudGVyIGl0YWxpYyBsZWZ0IHVuZGVybGluZQ0KDQpgYGB7bm9tbm9tbH0NCiMgLmJveDogZmlsbD0jOGY4IGRhc2hlZA0KIyAuYmxvYjogdmlzdWFsPXJob21iIHRpdGxlPWJvbGQgZmlsbD0jOGY4IGRhc2hlZA0KDQpbQV0tW0JdDQpbQl0tLVs8dXNlY2FzZT5DXQ0KW0NdLVs8Ym94PiBEXQ0KW0JdLS1bPGJsb2I+IEphYmJhO1RoZUh1dF0NCmBgYA0KDQpgYGB7bm9tbm9tbH0NClthXSAtPltiXQ0KW2JdIC06PiBbY10NCltjXW8tPltkXQ0KW2RdLS8tW2VdDQpgYGANCg0KYGBge25vbW5vbWx9DQojZmlsbDogbGlnaHRncmVlbjsgbGlnaHRibHVlOyBsaWdodHllbGxvdzsgZ3JleTsgd2hpdGUNCg0KWzx0YWJsZT4gdGFibGUgfCBjIHwgOSBdDQoNCltSIHwgWzx0YWJsZT4gUGFja2FnZXMgfA0KICAgICAgICAgQmFzZSBSIHwNCiAgICAgICAgIFsgPHRhYmxlPiB0aWR5dmVyc2V8IGdncGxvdCB8IHRpZHlyIHwgcmVhZHIgfA0KICAgICAgICAgICAgIFs8dGFibGU+IGRwbHlyfA0KICAgICAgICAgICAgICAgICBtYWdyaXR0ciB8IE90aGVyc11dXV0NCmBgYA0KDQpgYGB7bm9tbm9tbH0NCiNmaWxsOiBsaWdodGdyZWVuOyBsaWdodGJsdWU7IGxpZ2h0eWVsbG93OyBwaW5rOyB3aGl0ZQ0KDQpbUlN0dWRpbyB8IFtSIHwgWzx0YWJsZT4gUGFja2FnZXMgfA0KICAgICAgICAgICAgICAgICAgIEJhc2UgUiB8IFsgdGlkeXZlcnNlIHwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZ3Bsb3QgfCB0aWR5ciB8IHJlYWRyIHwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbZHBseXJdLS1bbWFncml0dHJdDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgW2RwbHlyXS0tW090aGVyc10NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCB0aWJibGUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXQ0KICAgICAgICAgICAgICAgICB8IGx1YnJpZGF0ZSB8IERpYWdyYW1tZVIgfCBMYXR0aWNlXV1dDQpgYGANCg0KYGBge25vbW5vbWwgbWluZG1hcH0NCltMaW51eF0rLVtVYnVudHVdDQpbTGludXhdKy1bTWludF0NCltVYnVudHVdLS1bTWludF0NCltMaW51eF0rLVtSb3NhIExpbnV4XQ0KW0xpbnV4XSstW014IExpbnV4XQ0KW0RlYmlhbl0tK1tMaW51eF0NCg0KDQpbRmVkb3JhXS0rW0xpbnV4XQ0KW1B1cHB5IExpbnV4XS0rW0xpbnV4XQ0KW1BlcnNvbmFsIFB1cHNdLStbUHVwcHkgTGludXhdDQoNCmBgYA0K