Introduction
This is going to be a bit of a of an attempt to talk you through and
train you at the same time on how to create a markdown report.
You run a markdown by ‘knit’ ing it. There is literally an icon with
a ball of wool with a knitting needle in it. That is the button we need
and it knits together all the markdown stuff and r code into one super
snazzy output.
Will get you to knit the report and see the results and then we will
pick apart the code and see how it is done behind the scenes.
If you have 2 screens try to have the code on one side and the report
on the other and you can look side by side at what is happening.
I will also be presenting and you can look at me to follow as
well.
How many times have you wanted to create a report that has the beauty
and readability of a word document but want to add interactive graphs
and functionality of a excel filtered table or even a pivot table?
If only there was a way you could pull your data, wrangle it and then
finally get it to produce a beautiful report, all in one process.
If only…
If only…
Hang on! Sounds really complicated and difficult and need lots of
tricky code. Have we not been telling you how brilliant R is?
Introducing
You can import images, either from the web or from a local directory
- this one is from the web and it is massive! You can see above you can
also insert animated gifs.
(I fear what I have done to the NHS by releasing that knowledge into the
wild - I take no responsibility for any repercussions of animated nyan
cat reports.)
R Markdown
This is an R Markdown document. Markdown is a simple formatting
syntax for authoring HTML, PDF, and MS Word documents. For more details
on using R Markdown see http://rmarkdown.rstudio.com.
Word and PDF reports are fine and you can do some very pretty but
flat reports in these outputs. Thats fine but the cool kats and kitties
want interactive and flashy.
When you click the Knit button a document will be
generated that includes both content as well as the output of any
embedded R code chunks within the document.
You may notice the nice floating contents page to the left. This is
created in the YAML header at the very start of the document. YAML
stands for YAML Ain’t Markup Language. It sets some global parameters
and can do some cool stuff. You set the headings as per the next section
and the document automatically picks up those with a single ‘#’.
So what can you do?
Markdown formatting
Tabsets
Tabsets are great for creating nice interactive documents and
reducing the length of your document but still cramming in loads of
extra data without your reader realising it.
If you look at the code you can see that you can add a little fade to
give your report a little extra sparkle or you can leave it for extra
zip. I am using a bit of fade sparkle for this example
Results by provider
Provider code RXQ
Blah blah blah super important commentary about the blue line going
up.
Provider code RJ1
Oh my - the red line is going up, no one wants to see a red line
going up. Must remember to RAG rate this later and add a sad smiley
face, pretty sure there will be a lesson on how to do that later.
Provider code RYJ
-insert witty commentary here-
That is the basic text formatting stuff, but we want to do clever
things and incorporate our data
Adding some data
We are going to use the NHR-R sample data set and use the AE
attendances data. This has a date, a organisation code, a type, number
for attendances, admissions and breaches.
You can include data within the markdown specifically within the text
by doing a back tick r and entering a variable or formula (you can also
format it into a nice readable number).
For example the total number of attendances from the data set is
8,295,237
The date of 07 October 2022 is when you pressed the knit button
report.
You can also add ‘code chunks’, these are chunks of code
that sit within your markdown document.
So here is a the base way to include some data you simple do triple
back ticks to tell R studio that now you want to do some R stuff.
This will print the summary of the AE attendnace* data set in a not
very pretty table
* just noticed a typo in ‘attendance’ - R studio does have a spell
check feature - remember to use it as not automatic, no wavy red lines
like word!**
** you also have to do backslash asterisk when you actually want to use
an asterisk
## # A tibble: 9 × 6
## period org_code type attendances breaches admissions
## <date> <fct> <fct> <dbl> <dbl> <dbl>
## 1 2019-03-01 RF4 other 10289 90 0
## 2 2019-02-01 RF4 other 9643 87 0
## 3 2019-01-01 RF4 other 10424 77 0
## 4 2018-12-01 RF4 other 9460 95 0
## 5 2018-11-01 RF4 other 8264 30 0
## 6 2018-10-01 RF4 other 7900 14 0
## 7 2018-09-01 RF4 other 7604 39 0
## 8 2018-08-01 RF4 other 7184 73 0
## 9 2018-07-01 RF4 other 5072 10 0
Library - Kable
Basic but by no means pretty, we can use the kable package to make a
prettier table, in just 2 lines of code you can produce this, which has
better readability and a nice reading hover over.
period
|
org_code
|
type
|
attendances
|
breaches
|
admissions
|
2019-03-01
|
RF4
|
other
|
10289
|
90
|
0
|
2019-02-01
|
RF4
|
other
|
9643
|
87
|
0
|
2019-01-01
|
RF4
|
other
|
10424
|
77
|
0
|
2018-12-01
|
RF4
|
other
|
9460
|
95
|
0
|
2018-11-01
|
RF4
|
other
|
8264
|
30
|
0
|
2018-10-01
|
RF4
|
other
|
7900
|
14
|
0
|
2018-09-01
|
RF4
|
other
|
7604
|
39
|
0
|
2018-08-01
|
RF4
|
other
|
7184
|
73
|
0
|
2018-07-01
|
RF4
|
other
|
5072
|
10
|
0
|
The kable package to make a prettier table, indent rows and colour it
in and change formats, add sub headings and is quite simple to use.
period
|
org_code
|
type
|
attendances
|
breaches
|
admissions
|
sub heading and indent first 3 rows
|
2019-03-01
|
RF4
|
other
|
10289
|
90
|
0
|
2019-02-01
|
RF4
|
other
|
9643
|
87
|
0
|
2019-01-01
|
RF4
|
other
|
10424
|
77
|
0
|
2018-12-01
|
RF4
|
other
|
9460
|
95
|
0
|
2018-11-01
|
RF4
|
other
|
8264
|
30
|
0
|
2018-10-01
|
RF4
|
other
|
7900
|
14
|
0
|
2018-09-01
|
RF4
|
other
|
7604
|
39
|
0
|
2018-08-01
|
RF4
|
other
|
7184
|
73
|
0
|
2018-07-01
|
RF4
|
other
|
5072
|
10
|
0
|
Kable is really good for a static and pretty, but we want
interactive.
Library - DT (short for data table)
This is a DT datatable - has lovely filters on the periods and
different columns. You can re order the data and show as much or as
little as you like. The export buttons export what you have selected.
There is also a search function for the data.
You can mess around with the defaults so that it shows a larger
table.
DT Datatable is pretty good and quick, even the base default comes up
with a pretty good table. It is very nice at presenting a flat table,
but if you want calculations and totals , you have to hard code them
into your table.
That is one format or if you want more summary type reports you can
use reactable.
Library - Reactable
This is reactable, and it works a little more like a filtered and sub
grouped table. It is a bit trickier to use, but seems to be able to all
the stuff of data table and a bit more.
Reactable is really good at creating summaries and drill down
datasets. It creates all the groupings of data itself and so you do not
have to wrangle the data into groups before you make the table. You can
also create high level aggregate functions on a group and have the
ability to drill down to see the underlying data.
Reactable has many more functions than a DT datatable but as I said,
is a little more tricky to use.
You can use it to do funky stuff like this, I see your spark lines
excel and raise you spark box plots! (and conditional formatting)
(Want to be super impressed? Hover over the spark box)
Lets get plotting…
Of course we can add a plot, you can change the size, alignment and
all of that stuff. You can wrap your text around a plot and potentially
have plots side by size.
You need to switch to the code here for a little funky plotting short
cut.
Library - esquisse
So that’s a plot, does what it says on the tin, but what is better
than a static plot?
Interactive plots…
Library - plotly
- You can click on the legend to add or remove line
- You can click and drag an area to zoom in on
- You can hover over line to see data points
- You can export as an image
All is far more customisable within the plotly function, you can have
multiple select-able data sets and all manner of other stuff.
Animated graphs
Pretty cool but lets show off and animate
Obviously pretty pointless in this example, but may be good as a way
to be more visual to get a point across.
If it gets people actually looking at the data and wanting their
little wiggly lines going up that has to be good for patient care.
Library - dygraphs
So how about we take the admissions data for the providers above and
create a nice time series graph. This DY graph is nice for playing with
time series as it allows you to zoom in on certain areas.
There is also a nice little box on the bottom left of the graph. This
allows you to smooth your data with a rolling average on the fly. Really
useful for things such as length of stay or things with lots of
variablity and trying to pull out an overall trend.
Other good functions for visualising data sets.
Library - Treemap
One is treemap, it is like a posh pie chart for looking at
proportions of a variable.
Obviously R can do pie charts, but I whereas I am
willing to show you how add animated gifs into your reports, even I
would not sink that low.
This is a nice overview of a large amount of data, gets a bit messy
when you have a lot of factors
Library - collapsibleTree
Another really cool thing to play with is a dendrogram which you can
make with collapsibleTree.
This is really good at showing flow through pathways and systems. You
can make them horizontal or vertical and play with all manner of bits on
the nodes.
Click on the nodes and you can also zoom in and out and scroll
around.
I also find it really relaxing for some reason.
Library - Leaflet
Leaflet is a great mapping library and works with open street map so
you don’t have to worry about google API tokens and the like. There are
some fantastic things you can do with the google service which allows
you to access travel times and route finding, however for simple mapping
leaflet is great. You can do heatmaps and areas, draw lines across
points and also add layers that you can select on and off.
This example has 3 teams that are set up as layers and youcan turn
each one on and off.
The maps can be scrolled and zoomed, what is nice is the icons remain
to scale.
Library - Wordcloud2
Wordcloud2 is the sequel to wordcloud, much like Evil Dead 2 to the
original, it is a far superior product, it has some really nice easy to
use features and can make all manner of different wordclouds types.
However before you get to a word cloud you need some data which is
basically a list of words and their frequency. You can do this manually
on your fingers or you can get R to do this for you. I definately
recommend the latter.
To get to that you read in some data, strip out all the gubbins such
as punctuation, remove all the ‘stop words’ such as ‘the’ and ‘and’ etc
and then remove white space and there you have a bunch of words fit for
a cloud.
This is an example that pulls the text from a popular childrens novel
and creates a cloud. Hopefully you can guess the book from the
cloud.
You can hover over the words in the cloud and it will tell you the
word and give you the number of the frequency.
Library - Rpivottable
Saving perhaps my favorite until last, is the super awesome
Rpivottable.
This has full click and drag functionality as well the option to set
up defaults in the report and also you can click through, create charts
and heat maps, filter your data, calculate a pivot table with a median
and just do all sorts of magic.
You can click and drag the variables around. You can click on the
arrows to the side of the variables to filter them. You can click on the
count to select a different metric and finally you can click on the
table to change the results to a graph or heatmap or loads of
things.
It doesn’t like super huge data sets if you are running it locally
but if you get clever with shiny, you can do big things.
It also has a habbit of overlapping with stuff below it. I am working
on a HTNL solution to this and I think this is a ‘feature’ that is being
worked on by the developers. I usually just add it at the end of a
report or on a seperate tab to get around this issue.
This whole functionality is done with one line of code. (!!!)
LS0tDQp0aXRsZTogIlIgTWFya2Rvd24gVHJhaW5pbmciDQphdXRob3I6ICJTaW1vbiBXZWxsZXNsZXktTWlsbGVyIg0KZGF0ZTogIjA5LzA3LzIwMjAiDQpvdXRwdXQ6IA0KICBodG1sX2RvY3VtZW50Og0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19mbG9hdDogdHJ1ZQ0KLS0tDQoNCmBgYHtyIHNldHVwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQobWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZWNobyA9IEZBTFNFKQ0KDQojIyBjaGFuZ2UgdGhlIGVjaG8gdG8gVFJVRSB0byBzaG93IHRoZSBSIGNvZGUgaW4gdGhlIGRvY3VtZW50DQojIyBoYXZpbmcgaXQgc2hvd2luZyBpcyByZWFsbHkgdXNlZnVsIHdoZW4gYnVpbGRpbmcgYSByZXBvcnQgYXMgaXQgaGVscHMgd29ya2luZyBvdXQgd2hhdCBiaXQgaXMgZG9pbmcgd2hhdA0KIyMgeW91IGNhbiByZWFsbHkgZ2V0IGluIHRvIGEgcmFiaXQgaG9sZSBvZiB0aGUgUiAgLyBNYXJrZG93biBjb2RlIGxvb2tpbmcgbm90aGluZyBsaWtlIHRoZSBvdXRwdXQNCg0KDQojI3VzdWFsbHkgZ2dvZCBwcmFjdGljZSB0byBsb2FkIGFsbCB5b3VyIGxpYnJhcnlzIGF0IHRoZSBzdGFydA0KDQpsaWJyYXJ5KE5IU1JkYXRhc2V0cykNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShrYWJsZUV4dHJhKQ0KbGlicmFyeShyZWFjdGFibGUpDQpsaWJyYXJ5KGVzcXVpc3NlKQ0KbGlicmFyeShycGl2b3RUYWJsZSkNCmxpYnJhcnkobGVhZmxldCkNCmxpYnJhcnkoRFQpDQpsaWJyYXJ5KHNwYXJrbGluZSkNCmxpYnJhcnkocGxvdGx5KQ0KbGlicmFyeShsdWJyaWRhdGUpDQpsaWJyYXJ5KHRyZWVtYXApDQpsaWJyYXJ5KGNvbGxhcHNpYmxlVHJlZSkNCmxpYnJhcnkodGlkeWdlb2NvZGVyKQ0KbGlicmFyeShsZWFmbGV0KQ0KbGlicmFyeSh3aWRnZXRmcmFtZSkNCmxpYnJhcnkoInRtIikNCmxpYnJhcnkoIlNub3diYWxsQyIpDQpsaWJyYXJ5KCJ3b3JkY2xvdWQyIikNCmxpYnJhcnkoIlJDb2xvckJyZXdlciIpDQpsaWJyYXJ5KGR5Z3JhcGhzKQ0KbGlicmFyeSh4dHMpICAgDQoNCg0KDQoNCiMjIHB1bGwgc29tZSBkYXRhIGZyb20gdGhlIE5IUyBSIGRhdGFzZXQNCmRhdGEgPC0gYWVfYXR0ZW5kYW5jZXMNCg0KZGF0YTQgPC0gZGF0YSAlPiUgZmlsdGVyIChvcmdfY29kZSA9PSJSWFEiKQ0KDQojI0p1c3Qgc2V0dGluZyB1cCBhIGNvdXBsZSBvZiBwbG90cyB0byB1c2UgbGF0ZXIgaW4gdGhlIGV4YW1wbGUNCiMjdGhpcyB3aWxsIGJlIGV4cGxhaW5lZCBhIGxpdHRsZSBsYXRlcg0KIyNzbyBub3RoaW5nIHRvIHNlZSBoZXJlLCBtb3ZlIGFsb25nIA0KDQpwMSA8LWdncGxvdCggZmlsdGVyKGRhdGEsb3JnX2NvZGUgPT0iUlhRIiksIGFlcyh4ID0gcGVyaW9kLCB5ID0gYXR0ZW5kYW5jZXMsIGdyb3VwID0gdHlwZSwgY29sb3VyID0gdHlwZSkpICsNCiBnZW9tX2xpbmUoc2l6ZSA9IDEuMzIpICsNCiBsYWJzKHRpdGxlID0gIlJYUSBOdW1iZXIgb2YgYXR0ZW5kYW5jZXMgYnkgdHlwZSIpICsNCiB0aGVtZV9taW5pbWFsKCkNCnAyIDwtZ2dwbG90KCBmaWx0ZXIoZGF0YSxvcmdfY29kZSA9PSJSSjEiKSwgYWVzKHggPSBwZXJpb2QsIHkgPSBhdHRlbmRhbmNlcywgZ3JvdXAgPSB0eXBlLCBjb2xvdXIgPSB0eXBlKSkgKw0KIGdlb21fbGluZShzaXplID0gMS4zMikgKw0KIGxhYnModGl0bGUgPSAiUkoxIE51bWJlciBvZiBhdHRlbmRhbmNlcyBieSB0eXBlIikgKw0KIHRoZW1lX21pbmltYWwoKQ0KcDMgPC1nZ3Bsb3QoIGZpbHRlcihkYXRhLG9yZ19jb2RlID09IlJZSiIpLCBhZXMoeCA9IHBlcmlvZCwgeSA9IGF0dGVuZGFuY2VzLCBncm91cCA9IHR5cGUsIGNvbG91ciA9IHR5cGUpKSArDQogZ2VvbV9saW5lKHNpemUgPSAxLjMyKSArDQogbGFicyh0aXRsZSA9ICJSSDEgTnVtYmVyIG9mIGF0dGVuZGFuY2VzIGJ5IHR5cGUiKSArDQogdGhlbWVfbWluaW1hbCgpDQoNCiMjIEkgZmluZCBpdCBpcyB1c3VhbGx5IGdvb2QgcHJhY3RpY2UgdG8gd3JpdGUgYWxsIHlvdXIgUiBjb2RlIGF0IHRoZSBzdGFydCBhbmQgY3JlYXRlIGFsbCB5b3VyIGNoYXJ0cyBhbmQgdGFibGVzIGFuZCBzdHVmZiBhdCBzdGFydCBhbmQgbWFrZSB0aGVtIG9iamVjdHMuICBZb3UgY2FuIHRoZW4gaW5zZXJ0IHRoZW0gaW50byB0aGUgbWFya2Rvd24gZG9jdW1lbnQuICANCg0KIyMgVGhpcyBzcGxpdHMgdGhlIHR3byB0aGluZ3MgYW5kIG1ha2VzIGl0IGVhc2llciB0byByZWFkIHRoZSBtYXJrZG93biBhbmQgYWxsIHRoZSBjb2RlIGlzIHRvZ2V0aGVyLg0KDQojIyBIb3dldmVyIGZvciB0aGlzIGV4YW1wbGUgSSBhbSBicmVha2luZyB0aGlzIHJ1bGUgYW5kIHdyaXR0aW5nIG1vc3Qgb2YgdGhlIGNvZGUgYmVmb3JlIGEgY2h1bmsgb2YgbWFya2Rvd24gc28gdGhhdCB5b3UgY2FuIGRpcmVjdGx5IHNlZSB3aGljaCBlYWNoIGJpdCBpcyBkb2luZy4NCg0KIyMgVGhpcyBpcyBxdWl0ZSBhIGNvYmJsZWQgdG9ndGhlciBwaWVjZSBvZiBjb2RlIGZyb20gbWFueSBwcm9qZWN0cywgc28gSSBoYXZlIG5vdCBiZWVuIHZlcnkgY29uc2lzdGVudCB3aXRoIG15IG5hbWluZyBjb252ZW50aW9ucyBhbmQgSSBhbSByZXVzaW5nIGFuZCBkdXBsaWNhdGluZyBhIGZhciBiaXQgb2YgZGF0YSB3aGljaCBpcyBieSBubyBtZWFucyB0aGUgbW9zdCBlZmZpY2llbnQgd2F5IG9mIGRvaW5nIHRoaW5ncyBhbmQgaGFzIG92ZXIgaW5mbGF0ZWQgdGhlIGZpbmFsIGZpbGUgc2l6ZSBvZiB0aGUgb3V0cHV0LiAgT2ggd2VsbC4NCg0KDQoNCmBgYA0KDQojIEludHJvZHVjdGlvbg0KDQpUaGlzIGlzIGdvaW5nIHRvIGJlIGEgYml0IG9mIGEgb2YgYW4gYXR0ZW1wdCB0byB0YWxrIHlvdSB0aHJvdWdoIGFuZCB0cmFpbiB5b3UgYXQgdGhlIHNhbWUgdGltZSBvbiBob3cgdG8gY3JlYXRlIGEgbWFya2Rvd24gcmVwb3J0Lg0KDQpZb3UgcnVuIGEgbWFya2Rvd24gYnkgJ2tuaXQnIGluZyBpdC4gIFRoZXJlIGlzIGxpdGVyYWxseSBhbiBpY29uIHdpdGggYSBiYWxsIG9mIHdvb2wgd2l0aCBhIGtuaXR0aW5nIG5lZWRsZSBpbiBpdC4gIFRoYXQgaXMgdGhlIGJ1dHRvbiB3ZSBuZWVkIGFuZCBpdCBrbml0cyB0b2dldGhlciBhbGwgdGhlIG1hcmtkb3duIHN0dWZmIGFuZCByIGNvZGUgaW50byBvbmUgc3VwZXIgc25henp5IG91dHB1dC4NCg0KV2lsbCBnZXQgeW91IHRvIGtuaXQgdGhlIHJlcG9ydCBhbmQgc2VlIHRoZSByZXN1bHRzIGFuZCB0aGVuIHdlIHdpbGwgcGljayBhcGFydCB0aGUgY29kZSBhbmQgc2VlIGhvdyBpdCBpcyBkb25lIGJlaGluZCB0aGUgc2NlbmVzLg0KDQpJZiB5b3UgaGF2ZSAyIHNjcmVlbnMgdHJ5IHRvIGhhdmUgdGhlIGNvZGUgb24gb25lIHNpZGUgYW5kIHRoZSByZXBvcnQgb24gdGhlIG90aGVyIGFuZCB5b3UgY2FuIGxvb2sgc2lkZSBieSBzaWRlIGF0IHdoYXQgaXMgaGFwcGVuaW5nLg0KDQpJIHdpbGwgYWxzbyBiZSBwcmVzZW50aW5nIGFuZCB5b3UgY2FuIGxvb2sgYXQgbWUgdG8gZm9sbG93IGFzIHdlbGwuDQoNCj4gSG93IG1hbnkgdGltZXMgaGF2ZSB5b3Ugd2FudGVkIHRvIGNyZWF0ZSBhIHJlcG9ydCB0aGF0IGhhcyB0aGUgYmVhdXR5IGFuZCByZWFkYWJpbGl0eSBvZiBhIHdvcmQgZG9jdW1lbnQgYnV0IHdhbnQgdG8gYWRkIGludGVyYWN0aXZlIGdyYXBocyBhbmQgZnVuY3Rpb25hbGl0eSBvZiBhIGV4Y2VsIGZpbHRlcmVkIHRhYmxlIG9yIGV2ZW4gYSBwaXZvdCB0YWJsZT8gIA0KDQpJZiBvbmx5IHRoZXJlIHdhcyBhIHdheSB5b3UgY291bGQgcHVsbCB5b3VyIGRhdGEsIHdyYW5nbGUgaXQgYW5kIHRoZW4gZmluYWxseSBnZXQgaXQgdG8gcHJvZHVjZSBhIGJlYXV0aWZ1bCByZXBvcnQsIGFsbCBpbiBvbmUgcHJvY2Vzcy4NCg0KSWYgb25seS4uLg0KDQpJZiBvbmx5Li4uDQoNCkhhbmcgb24hICBTb3VuZHMgcmVhbGx5IGNvbXBsaWNhdGVkIGFuZCBkaWZmaWN1bHQgYW5kIG5lZWQgbG90cyBvZiB0cmlja3kgY29kZS4gIEhhdmUgd2Ugbm90IGJlZW4gdGVsbGluZyB5b3UgaG93IGJyaWxsaWFudCBSIGlzPyAgDQoNCiFbXShodHRwczovL21lZGlhLmdpcGh5LmNvbS9tZWRpYS9iNHpsSnRyUk0xNXE4L2dpcGh5LmdpZikNCg0KDQoNCkludHJvZHVjaW5nDQoNCg0KIVtNYXJrZG93bkljb25dKGh0dHBzOi8vYm9va2Rvd24ub3JnL3lpaHVpL3JtYXJrZG93bi9pbWFnZXMvaGV4LXJtYXJrZG93bi5wbmcpDQoNCllvdSBjYW4gaW1wb3J0IGltYWdlcywgZWl0aGVyIGZyb20gdGhlIHdlYiBvciBmcm9tIGEgbG9jYWwgZGlyZWN0b3J5IC0gdGhpcyBvbmUgaXMgZnJvbSB0aGUgd2ViIGFuZCBpdCBpcyBtYXNzaXZlISBZb3UgY2FuIHNlZSBhYm92ZSB5b3UgY2FuIGFsc28gaW5zZXJ0IGFuaW1hdGVkIGdpZnMuICANCihJIGZlYXIgd2hhdCBJIGhhdmUgZG9uZSB0byB0aGUgTkhTIGJ5IHJlbGVhc2luZyB0aGF0IGtub3dsZWRnZSBpbnRvIHRoZSB3aWxkIC0gSSB0YWtlIG5vIHJlc3BvbnNpYmlsaXR5IGZvciBhbnkgcmVwZXJjdXNzaW9ucyBvZiBhbmltYXRlZCBueWFuIGNhdCByZXBvcnRzLikNCg0KIyMgUiBNYXJrZG93bg0KDQpUaGlzIGlzIGFuIFIgTWFya2Rvd24gZG9jdW1lbnQuIE1hcmtkb3duIGlzIGEgc2ltcGxlIGZvcm1hdHRpbmcgc3ludGF4IGZvciBhdXRob3JpbmcgSFRNTCwgUERGLCBhbmQgTVMgV29yZCBkb2N1bWVudHMuIEZvciBtb3JlIGRldGFpbHMgb24gdXNpbmcgUiBNYXJrZG93biBzZWUgPGh0dHA6Ly9ybWFya2Rvd24ucnN0dWRpby5jb20+Lg0KDQpXb3JkIGFuZCBQREYgcmVwb3J0cyBhcmUgZmluZSBhbmQgeW91IGNhbiBkbyBzb21lIHZlcnkgcHJldHR5IGJ1dCBmbGF0IHJlcG9ydHMgaW4gdGhlc2Ugb3V0cHV0cy4gIFRoYXRzIGZpbmUgYnV0IHRoZSBjb29sIGthdHMgYW5kIGtpdHRpZXMgd2FudCBpbnRlcmFjdGl2ZSBhbmQgZmxhc2h5LiANCg0KV2hlbiB5b3UgY2xpY2sgdGhlICoqS25pdCoqIGJ1dHRvbiBhIGRvY3VtZW50IHdpbGwgYmUgZ2VuZXJhdGVkIHRoYXQgaW5jbHVkZXMgYm90aCBjb250ZW50IGFzIHdlbGwgYXMgdGhlIG91dHB1dCBvZiBhbnkgZW1iZWRkZWQgUiBjb2RlIGNodW5rcyB3aXRoaW4gdGhlIGRvY3VtZW50LiANCg0KWW91IG1heSBub3RpY2UgdGhlIG5pY2UgZmxvYXRpbmcgY29udGVudHMgcGFnZSB0byB0aGUgbGVmdC4gIFRoaXMgaXMgY3JlYXRlZCBpbiB0aGUgWUFNTCBoZWFkZXIgYXQgdGhlIHZlcnkgc3RhcnQgb2YgdGhlIGRvY3VtZW50LiAgWUFNTCBzdGFuZHMgZm9yIFlBTUwgQWluJ3QgTWFya3VwIExhbmd1YWdlLiAgSXQgc2V0cyBzb21lIGdsb2JhbCBwYXJhbWV0ZXJzIGFuZCBjYW4gZG8gc29tZSBjb29sIHN0dWZmLiAgWW91IHNldCB0aGUgaGVhZGluZ3MgYXMgcGVyIHRoZSBuZXh0IHNlY3Rpb24gYW5kIHRoZSBkb2N1bWVudCBhdXRvbWF0aWNhbGx5IHBpY2tzIHVwIHRob3NlIHdpdGggYSBzaW5nbGUgJyMnLg0KDQoqU28gd2hhdCBjYW4geW91IGRvPyoNCg0KIyBNYXJrZG93biBmb3JtYXR0aW5nDQoNCiMjIFlvdSBjYW4gcGxheSB3aXRoIGhlYWRlcnMgdGhhdCBnZXQgc21hbGxlcg0KDQojIyMgWW91IGNhbiBwbGF5IHdpdGggaGVhZGVycyAtIGFuZCBzbWFsbGVyDQoNCiMjIyMgWW91IGNhbiBwbGF5IHdpdGggaGVhZGVycyAgLSBhbmQgc21hbGxlcg0KDQojIyMjIyBZb3UgY2FuIHBsYXkgd2l0aCBoZWFkZXJzICAtIGFuZCBzbWFsbGVzdA0KDQpZb3UgY2FuIG1ha2UgYSBsaW5lIG1ha2UgYSBsaW5lIGJyZWFrDQoNCioqKg0KDQpZb3UgY2FuIGRvIGFsbCB0aGUgbm9ybWFsICppdGFsaWNzKiBhbmQgKipib2xkKiogYW5kIF5zdXBlcnNjcmlwdF4gYW5kIH5+c3RyaWtlLXRob3VnaH5+DQoNCj4gVGhpbmdzIGxpa2UgYmxvY2sgcXVvdGVzIGxvb2sgZnVua3kgIA0KPiBlc3BlY2lhbGx5IGlmIHlvdSBwdXQgYSBmZXcgdG9nZXRoZXIgIA0KPiBtYWtlIHN1cmUgeW91IGVuZCB5b3VyIHNlbnRlbmNlcyB3aXRoIDIgIA0KPiBzcGFjZXMgdG8gc3RhcnQgYSBuZXcgcGFyYWdyYXBoICANCg0KDQpPdGhlciB0aGluZ3MgdGhhdCBhcmUgZWFzeQ0KDQoqIGxpc3RzDQoqIHB1dHRpbmcgc3R1ZmYgaW4gbGlzdHMNCiAgKyBwdXR0aW5nIHN0dWZmIGluIHN1YiBsaXN0cw0KICArIHN1Y2ggYXMgdGhpcw0KKiBkaWQgSSBzYXkgbGlzdHM/DQoNCllvdSBjYW4gYWxzbyBkbyBudW1iZXJlZCBsaXN0cw0KDQooQCkgTGlrZSB0aGlzDQooQCkgRmluZSBleGFtcGxlIG9mIGEgbGlzdA0KICAgICsgYW5kIGRvIHN1YiBsaXN0cyBpbiBhIG51bWJlcmVkIGxpc3QNCiAgICAgIGkpIGFuZCBkbyBzdWIgc3ViIGxpc3RzICANCiAgICAgICAgQS4gYW5kIHN1YiBzdWIgc3ViIGxpc3QNCg0KV3JpdGUgc29tZSBzdHVmZiBpbiB0aGUgbWlkZGxlIG9mIHlvdXIgbGlzdCAgICAgICAgDQogICAgICAgIA0KKEApIGFuZCB0aGVuIGdvIGJhY2sgdG8gdGhlIGxpc3QNCihAKSBOT1RFOiB0aGUgbnVtYmVycyBpbiB0aGUgbGlzdCBhcmUgbm90IHNwZWNpZmllZCwgdGhleSBhcmUgZHluYW1pYyBhbmQgaWYgeW91IGdvIGFuZCBlZGl0IG9uZSBvdXQgaXQgd2lsbCBhZGp1c3QgdGhlbSBhdXRvbWF0aWNhbGx5DQoNCjxzdHlsZT4NCmRpdi5ibHVlIHsgYmFja2dyb3VuZC1jb2xvcjojZTZmMGZmOyBib3JkZXItcmFkaXVzOiA1cHg7IHBhZGRpbmc6IDIwcHg7fQ0KPC9zdHlsZT4NCjxkaXYgY2xhc3MgPSAiYmx1ZSI+DQoNCllvdSBjYW4gY29sb3VyIGluIGEgYmxvY2sgdG8gYXNzaXN0IHdpdGggaGlnaGxpZ2h0aW5nIGFuIGFyZWEuDQoNCi0gVGhpcyBpcyBteSBmaXJzdCBjb25jbHVzaW9uDQotIFRoaXMgaXMgbXkgc2Vjb25kIGNvbmNsdXNpb24gIA0KDQo8L2Rpdj4NCg0KWW91IGNhbiBhZGQgZm9vdG5vdGVzW14xXQ0KDQpbXjFdOlRoaXMgaXMgdGhlIGZvb3Rub3RlIGZyb20gdGhlIGZvb3Rub3RlIGFkZGVkIHdheSB3YXkgdXAgYWJvdmUNCg0KWW91IGNhbiBhbHNvIGRvIGJhc2ljIGR5bmFtaWMgdGFibGVzIGp1c3QgaW4gbWFya2Rvd24gLSBsb29rcyBtZXNzeSBpbiB0aGUgY29kZSwgcHJldHR5IGluIHRoZSBtYXJrZG93biBhbmQgdGhhbmtzIHRvIHRoZSBwb3dlciBvZiBIVE1MLCB0aGV5IHJlLXNpemUgYWNjb3JkaW5nIHRvIHRoZSBzY3JlZW4sIGFsbCBvZiB0aGVzZSB0YWJsZXMgYW5kIGNoYXJ0cyBhcmUgbW9iaWxlIGZyaWVuZGx5Lg0KDQpDb2x1bW4gaGVhZGluZyBvbmUgfCBTZWNvbmQgY29sdW1uIGhlYWRpbmcNCi0tLXwtLS0NClN0dWZmIHwgQ29sdW1uIDIgc3R1ZmYNCkFub3RoZXIgcm93IG9mIHN0dWZmIHwgTW9yZSBjb2x1bW4gMiBzdHVmZiAgDQoNCllvdSBjYW4gYWxpZ24gdGhlIHN0dWZmIGluIHRoZXNlIHRhYmxlcyBidXQgdGhleSBkb24ndCB3b3JrIHdlbGwgd2l0aCBudW1iZXJzDQoNCnwgUmlnaHQgfCBMZWZ0ICB8IERlZmF1bHQgfCBDZW50cmUgfA0KfC0tLTp8Oi0tLXwtLS0tfDotLS0tOnwNCnwgYmx1cmIgcmlnaHQgYWxpZ25lZCB8IGJsdXJiIGxlZnQgYWxpZ25lZCB8IGJsdXJiIGRlZmF1bHQgfCBibHVyYiBpbiBkYSBjZW50cmUgfA0KfCAxMjM0IHwgNTY3ODggfCA0NTQ1NjQ0IHwgNDM1MzUgfA0KfCAgMzQuMiB8IDM0NDIuMSB8IDM0MjEuMSB8IDQ1MTIuNDUgfA0KDQoNCjxwIHN0eWxlPSJmb250LWZhbWlseTogY29taWMgc2FucyBNUzsgZm9udC1zaXplOjIwcHQiPg0KICAgIFlvdSBjYW4gYWxzbyBwbGF5IHdpdGggSFRNTCB0YWdzIHRvIGNoYW5nZSBmb250IHRvIGNvbWljIHNhbnMNCjwvcD4NCg0KPHAgc3R5bGU9ImZvbnQtZmFtaWx5OiBJbXBhY3QsIENoYXJjb2FsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6MTBwdDsgZm9udC1zdHlsZTppdGFsaWMiPg0KICAgIEp1c3QgYmVjYXVzZSB5b3UgY2FuIGRvZXMgbm90IG1lYW4geW91IHNob3VsZCENCjwvcD4NCg0KDQojIFRhYnNldHMNCg0KVGFic2V0cyBhcmUgZ3JlYXQgZm9yIGNyZWF0aW5nIG5pY2UgaW50ZXJhY3RpdmUgZG9jdW1lbnRzIGFuZCByZWR1Y2luZyB0aGUgbGVuZ3RoIG9mIHlvdXIgZG9jdW1lbnQgYnV0IHN0aWxsIGNyYW1taW5nIGluIGxvYWRzIG9mIGV4dHJhIGRhdGEgd2l0aG91dCB5b3VyIHJlYWRlciByZWFsaXNpbmcgaXQuDQoNCklmIHlvdSBsb29rIGF0IHRoZSBjb2RlIHlvdSBjYW4gc2VlIHRoYXQgeW91IGNhbiBhZGQgYSBsaXR0bGUgZmFkZSB0byBnaXZlIHlvdXIgcmVwb3J0IGEgbGl0dGxlIGV4dHJhIHNwYXJrbGUgb3IgeW91IGNhbiBsZWF2ZSBpdCBmb3IgZXh0cmEgemlwLiBJIGFtIHVzaW5nIGEgYml0IG9mIGZhZGUgc3BhcmtsZSBmb3IgdGhpcyBleGFtcGxlDQoNCiMjIFJlc3VsdHMgYnkgcHJvdmlkZXIgey50YWJzZXQgLnRhYnNldC1mYWRlIC50YWJzZXQtcGlsbHN9DQoNCg0KDQojIyMgUHJvdmlkZXIgY29kZSBSWFENCg0KYGBge3IgcDF9DQpwMQ0KYGBgDQoNCkJsYWggYmxhaCBibGFoIHN1cGVyIGltcG9ydGFudCBjb21tZW50YXJ5IGFib3V0IHRoZSBibHVlIGxpbmUgZ29pbmcgdXAuDQoNCiMjIyBQcm92aWRlciBjb2RlIFJKMQ0KYGBge3IgcDJ9DQpwMg0KYGBgDQoNCk9oIG15IC0gdGhlIHJlZCBsaW5lIGlzIGdvaW5nIHVwLCBubyBvbmUgd2FudHMgdG8gc2VlIGEgcmVkIGxpbmUgZ29pbmcgdXAuICBNdXN0IHJlbWVtYmVyIHRvIFJBRyByYXRlIHRoaXMgbGF0ZXIgYW5kIGFkZCBhIHNhZCBzbWlsZXkgZmFjZSwgcHJldHR5IHN1cmUgdGhlcmUgd2lsbCBiZSBhIGxlc3NvbiBvbiBob3cgdG8gZG8gdGhhdCBsYXRlci4NCg0KIyMjIFByb3ZpZGVyIGNvZGUgUllKDQpgYGB7ciBwM30NCnAzDQpgYGANCg0KLWluc2VydCB3aXR0eSBjb21tZW50YXJ5IGhlcmUtDQoNCiMjIHsudW5saXN0ZWQgLnVubnVtYmVyZWR9DQoNClRoYXQgaXMgdGhlIGJhc2ljIHRleHQgZm9ybWF0dGluZyBzdHVmZiwgYnV0IHdlIHdhbnQgdG8gZG8gY2xldmVyIHRoaW5ncyBhbmQgaW5jb3Jwb3JhdGUgb3VyIGRhdGENCg0KIyBBZGRpbmcgc29tZSBkYXRhDQoNCldlIGFyZSBnb2luZyB0byB1c2UgdGhlIE5IUi1SIHNhbXBsZSBkYXRhIHNldCBhbmQgdXNlIHRoZSBBRSBhdHRlbmRhbmNlcyBkYXRhLiAgVGhpcyBoYXMgYSBkYXRlLCBhIG9yZ2FuaXNhdGlvbiBjb2RlLCBhIHR5cGUsICBudW1iZXIgZm9yIGF0dGVuZGFuY2VzLCBhZG1pc3Npb25zIGFuZCBicmVhY2hlcy4gDQoNCllvdSBjYW4gaW5jbHVkZSBkYXRhIHdpdGhpbiB0aGUgbWFya2Rvd24gc3BlY2lmaWNhbGx5IHdpdGhpbiB0aGUgdGV4dCBieSBkb2luZyBhIGJhY2sgdGljayByIGFuZCBlbnRlcmluZyBhIHZhcmlhYmxlIG9yIGZvcm11bGEgKHlvdSBjYW4gYWxzbyBmb3JtYXQgaXQgaW50byBhIG5pY2UgcmVhZGFibGUgbnVtYmVyKS4NCg0KRm9yIGV4YW1wbGUgdGhlIHRvdGFsIG51bWJlciBvZiBhdHRlbmRhbmNlcyBmcm9tIHRoZSBkYXRhIHNldCBpcyBgciBmb3JtYXQoc3VtKGRhdGEkYnJlYWNoZXMpLGZvcm1hdD0iZiIsIGJpZy5tYXJrPSIsIilgDQoNClRoZSBkYXRlIG9mIGByIGFzLmNoYXJhY3Rlcih0b2RheSgpLGZvcm1hdD0iJWQgJUIgJVkiKWAgaXMgd2hlbiB5b3UgcHJlc3NlZCB0aGUga25pdCBidXR0b24gcmVwb3J0Lg0KDQpZb3UgY2FuIGFsc28gYWRkIConY29kZSBjaHVua3MnKiwgdGhlc2UgYXJlIGNodW5rcyBvZiBjb2RlIHRoYXQgc2l0IHdpdGhpbiB5b3VyIG1hcmtkb3duIGRvY3VtZW50LiANCg0KU28gaGVyZSBpcyBhIHRoZSBiYXNlIHdheSB0byBpbmNsdWRlIHNvbWUgZGF0YSB5b3Ugc2ltcGxlIGRvIHRyaXBsZSBiYWNrIHRpY2tzIHRvIHRlbGwgUiBzdHVkaW8gdGhhdCBub3cgeW91IHdhbnQgdG8gZG8gc29tZSBSIHN0dWZmLg0KDQpUaGlzIHdpbGwgcHJpbnQgdGhlIHN1bW1hcnkgb2YgdGhlIEFFIGF0dGVuZG5hY2UqIGRhdGEgc2V0IGluIGEgbm90IHZlcnkgcHJldHR5IHRhYmxlDQoNCj4gXCoganVzdCBub3RpY2VkIGEgdHlwbyBpbiAnYXR0ZW5kYW5jZScgLSBSIHN0dWRpbyBkb2VzIGhhdmUgYSBzcGVsbCBjaGVjayBmZWF0dXJlIC0gcmVtZW1iZXIgdG8gdXNlIGl0IGFzIG5vdCBhdXRvbWF0aWMsIG5vIHdhdnkgcmVkIGxpbmVzIGxpa2Ugd29yZCFcKiogIA0KPiBcKiogeW91IGFsc28gaGF2ZSB0byBkbyBiYWNrc2xhc2ggYXN0ZXJpc2sgd2hlbiB5b3UgYWN0dWFsbHkgd2FudCB0byB1c2UgYW4gYXN0ZXJpc2sNCg0KYGBge3IgYXR0ZW5kfQ0KIyBUaGUgYml0IHRoZSB0aGUgY3VybHkgYnJhY2tldHMgYWZ0ZXIgdGhlIFIgaXMgc2ltcGx5IHRoZSBuYW1lIG9mIHRoZSBjb2RlIGNodW5rDQojIGhlbHBzIHRvIGZpbmQgeW91ciB3YXkgYXJvdW5kIHdoZW4geW91IGhhdmUgbG90cyBvZiBiaXRzIG9mIGNvZGUNCiMgYXMgeW91IGNhbiBzZWUgJyMncyBoYXZlIGdvbmUgYmFjayB0byBiZWluZyBjb21tZW50cyBpbiB0aGUgUiBjb2RlIGFuZCBub3QgaGVhZGluZ3MNCiMgeW91IGNhbiB1c2UgdGhpcyBjaHVuayBoZWFkZXIgdG8gc2V0IHNldmVyYWwgcGVyYW1ldGVycyBzdWNocyBhcyB3aGV0aGVyIHRvIGRpc3BsYXkgDQojIHRoaXMgY29kZSBhbmQgc2V0IHNpemUgb2YgYW55IGNoYXJ0cyB5b3UgY2FsbCB1cCBhbmQgc3R1ZmYgbGlrZSB0aGF0Lg0KDQoNCiMjIGp1c3QgY3JlYXRlIGEgbGl0dGxlIHN1YnNldCBzbyBpdCB3aWxsIGZpdCBpbiBhIHNpbXBsZSB0YWJsZQ0KZGF0YTIgPC0gZGF0YSAlPiUgZmlsdGVyKG9yZ19jb2RlPT0iUkY0IiwgdHlwZSA9PSAib3RoZXIiLCBhdHRlbmRhbmNlcyA+PSA1MDAwKQ0KDQojIFlvdSBjYW4gcHJpbnQgdGhlIGRhdGEgZnJhbWUgc2ltcGx5IGJ5IHByaW50aW5nIGl0IChwcmludCBjb21tYW5kIG5vdCByZXF1aXJlZCkNCmRhdGEyDQoNCiMgZW5kIHRoZSBSIGNvZGUgY2h1bmsgd2l0aCBhbm90aGVyIDMgYmFja3RpY2tzDQpgYGANCg0KIyBMaWJyYXJ5IC0gS2FibGUNCg0KQmFzaWMgYnV0IGJ5IG5vIG1lYW5zIHByZXR0eSwgd2UgY2FuIHVzZSB0aGUga2FibGUgcGFja2FnZSB0byBtYWtlIGEgcHJldHRpZXIgdGFibGUsIGluIGp1c3QgMiBsaW5lcyBvZiBjb2RlIHlvdSBjYW4gcHJvZHVjZSB0aGlzLCB3aGljaCBoYXMgYmV0dGVyIHJlYWRhYmlsaXR5IGFuZCBhIG5pY2UgcmVhZGluZyBob3ZlciBvdmVyLiANCg0KYGBge3Iga2FibGVhdHRlbmR9DQoNCmthYmxlKGRhdGEyKSAlPiUNCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiLCAiY29uZGVuc2VkIiwgInJlc3BvbnNpdmUiKSkNCg0KYGBgDQoNClRoZSBrYWJsZSBwYWNrYWdlIHRvIG1ha2UgYSBwcmV0dGllciB0YWJsZSwgaW5kZW50IHJvd3MgYW5kIGNvbG91ciBpdCBpbiBhbmQgY2hhbmdlIGZvcm1hdHMsIGFkZCBzdWIgaGVhZGluZ3MgYW5kIGlzIHF1aXRlIHNpbXBsZSB0byB1c2UuDQoNCmBgYHtyIGthYmxlYXR0ZW5kZnVua3l9DQoNCmthYmxlKGRhdGEyKSAlPiUNCiAgIGthYmxlX3N0eWxpbmcoInN0cmlwZWQiKSAlPiUNCiAgcGFja19yb3dzKCJzdWIgaGVhZGluZyBhbmQgaW5kZW50IGZpcnN0IDMgcm93cyIsIDEsIDMpICU+JQ0KICByb3dfc3BlYyg0LCBib2xkID0gVCwgYmFja2dyb3VuZCA9ICJ5ZWxsb3ciKSAlPiUNCiAgcm93X3NwZWMoNywgYm9sZCA9IFQsIGNvbG9yID0gIndoaXRlIiwgYmFja2dyb3VuZCA9ICIjRDcyNjFFIikNCmBgYA0KDQpLYWJsZSBpcyByZWFsbHkgZ29vZCBmb3IgYSBzdGF0aWMgYW5kIHByZXR0eSwgYnV0IHdlIHdhbnQgaW50ZXJhY3RpdmUuDQoNCiMgTGlicmFyeSAtIERUIChzaG9ydCBmb3IgZGF0YSB0YWJsZSkNCg0KVGhpcyBpcyBhIERUIGRhdGF0YWJsZSAtIGhhcyBsb3ZlbHkgZmlsdGVycyBvbiB0aGUgcGVyaW9kcyBhbmQgZGlmZmVyZW50IGNvbHVtbnMuICBZb3UgY2FuIHJlIG9yZGVyIHRoZSBkYXRhIGFuZCBzaG93IGFzIG11Y2ggb3IgYXMgbGl0dGxlIGFzIHlvdSBsaWtlLiAgIFRoZSBleHBvcnQgYnV0dG9ucyBleHBvcnQgd2hhdCB5b3UgaGF2ZSBzZWxlY3RlZC4gIFRoZXJlIGlzIGFsc28gYSBzZWFyY2ggZnVuY3Rpb24gZm9yIHRoZSBkYXRhLg0KDQpZb3UgY2FuIG1lc3MgYXJvdW5kIHdpdGggdGhlIGRlZmF1bHRzIHNvIHRoYXQgaXQgc2hvd3MgYSBsYXJnZXIgdGFibGUuDQoNCg0KYGBge3IgZGF0YXRhYmxlfQ0KDQpkYXRhdGFibGUoZGF0YSwgZmlsdGVyID0gJ3RvcCcsIA0KICAgICAgICAgIGV4dGVuc2lvbnMgPSAnQnV0dG9ucycsDQogICAgICAgICAgb3B0aW9ucyA9IGxpc3QoZG9tID0gJ0JsZnJ0aXAnLA0KICAgICAgICAgIGJ1dHRvbnMgPSBjKCdjb3B5JywgJ2NzdicsICdwZGYnLCAncHJpbnQnKSwNCiAgICAgICAgICBsZW5ndGhNZW51ID0gbGlzdChjKDEwLDI1LDUwLC0xKSwNCiAgICAgICAgICBjKDEwLDI1LDUwLCJBbGwiKSkpKQ0KYGBgDQoNCkRUIERhdGF0YWJsZSBpcyBwcmV0dHkgZ29vZCBhbmQgcXVpY2ssIGV2ZW4gdGhlIGJhc2UgZGVmYXVsdCBjb21lcyB1cCB3aXRoIGEgcHJldHR5IGdvb2QgdGFibGUuICBJdCBpcyB2ZXJ5IG5pY2UgYXQgcHJlc2VudGluZyBhIGZsYXQgdGFibGUsIGJ1dCBpZiB5b3Ugd2FudCBjYWxjdWxhdGlvbnMgYW5kIHRvdGFscyAsIHlvdSBoYXZlIHRvIGhhcmQgY29kZSB0aGVtIGludG8geW91ciB0YWJsZS4NCg0KVGhhdCBpcyBvbmUgZm9ybWF0IG9yIGlmIHlvdSB3YW50IG1vcmUgc3VtbWFyeSB0eXBlIHJlcG9ydHMgeW91IGNhbiB1c2UgcmVhY3RhYmxlLg0KDQojIExpYnJhcnkgLSBSZWFjdGFibGUNCg0KVGhpcyBpcyByZWFjdGFibGUsIGFuZCBpdCB3b3JrcyBhIGxpdHRsZSBtb3JlIGxpa2UgYSBmaWx0ZXJlZCBhbmQgc3ViIGdyb3VwZWQgdGFibGUuICBJdCBpcyBhIGJpdCB0cmlja2llciB0byB1c2UsIGJ1dCBzZWVtcyB0byBiZSBhYmxlIHRvIGFsbCB0aGUgc3R1ZmYgb2YgZGF0YSB0YWJsZSBhbmQgYSBiaXQgbW9yZS4NCg0KYGBge3IgcmVhY3RhYmxlfQ0KDQpyZWFjdGFibGUoZGF0YSwgZ3JvdXBCeSA9ICJvcmdfY29kZSIsICBtaW5Sb3dzID0gMTApDQoNCmBgYA0KDQoNClJlYWN0YWJsZSBpcyByZWFsbHkgZ29vZCBhdCBjcmVhdGluZyBzdW1tYXJpZXMgYW5kIGRyaWxsIGRvd24gZGF0YXNldHMuICBJdCBjcmVhdGVzIGFsbCB0aGUgZ3JvdXBpbmdzIG9mIGRhdGEgaXRzZWxmIGFuZCBzbyB5b3UgZG8gbm90IGhhdmUgdG8gd3JhbmdsZSB0aGUgZGF0YSBpbnRvIGdyb3VwcyBiZWZvcmUgeW91IG1ha2UgdGhlIHRhYmxlLiAgWW91IGNhbiBhbHNvIGNyZWF0ZSBoaWdoIGxldmVsIGFnZ3JlZ2F0ZSBmdW5jdGlvbnMgb24gYSBncm91cCBhbmQgaGF2ZSB0aGUgYWJpbGl0eSB0byBkcmlsbCBkb3duIHRvIHNlZSB0aGUgdW5kZXJseWluZyBkYXRhLg0KDQpgYGB7ciByZWFjdGFibGVzdW1tYXJ5fQ0KDQojI2RhdGEyIDwtIGRhdGEgJT4lIGZpbHRlciAodHlwZSA9PSAyKQ0KDQpyZWFjdGFibGUoZGF0YSwgZ3JvdXBCeSA9IGMoInBlcmlvZCIsICJ0eXBlIiksICANCiAgICAgICAgICBtaW5Sb3dzID0gMTAsDQogICAgICAgICAgY29sdW1ucyA9IGxpc3QgKA0KICAgICAgICAgICAgICAgICAgICAgICAgICBhdHRlbmRhbmNlcyA9Y29sRGVmKGFnZ3JlZ2F0ZSA9ICJtZWRpYW4iLCBuYW1lID0gIk1lZGlhbiBhdHRlbmRhbmNlcyIsIGFsaWduID0gImxlZnQiKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFjaGVzID0gY29sRGVmKGFnZ3JlZ2F0ZSA9ICAibWF4IiwgbmFtZSA9ICJNYXggYnJlYWNoZXMiLCBhbGlnbiA9ICJsZWZ0IikgICwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgYWRtaXNzaW9ucyA9IGNvbERlZihhZ2dyZWdhdGUgPSAibWVhbiIsIGZvcm1hdCA9IGNvbEZvcm1hdChkaWdpdHMgPSAxKSwgbmFtZSA9ICJNZWFuIGFkbWlzc2lvbnMiLCBhbGlnbiA9ICJsZWZ0IikgKSkNCg0KYGBgDQoNClJlYWN0YWJsZSBoYXMgbWFueSBtb3JlIGZ1bmN0aW9ucyB0aGFuIGEgRFQgZGF0YXRhYmxlIGJ1dCBhcyBJIHNhaWQsIGlzIGEgbGl0dGxlIG1vcmUgdHJpY2t5IHRvIHVzZS4gIA0KDQpZb3UgY2FuIHVzZSBpdCB0byBkbyBmdW5reSBzdHVmZiBsaWtlIHRoaXMsIEkgc2VlIHlvdXIgc3BhcmsgbGluZXMgZXhjZWwgYW5kIHJhaXNlIHlvdSBzcGFyayBib3ggcGxvdHMhICAoYW5kIGNvbmRpdGlvbmFsIGZvcm1hdHRpbmcpDQoNCmBgYHtyIHNwYXJreXRhYmxlfQ0KDQpkYXRhMyA8LSBkYXRhICU+JSBmaWx0ZXIgKG9yZ19jb2RlID09ICdSSjInLCB0eXBlID09ICIxIiApDQoNCnJlYWN0YWJsZSAoZGF0YTMsDQogIGRlZmF1bHRQYWdlU2l6ZSA9IDE1LA0KICBib3JkZXJlZCA9IFRSVUUsDQogIGNvbHVtbnMgPSBsaXN0IChicmVhY2hlcyA9IGNvbERlZihzdHlsZSA9IGZ1bmN0aW9uKHZhbHVlKSB7DQogICAgaWYgKHZhbHVlIDwgMzAwMCkge2NvbG9yIDwtICIjMDA4MDAwIg0KICAgIH0gZWxzZSBpZiAodmFsdWUgPiAzMDAxKSB7Y29sb3IgPC0gIiNlMDAwMDAiDQogICAgfSBlbHNlIHtjb2xvciA8LSAiIzc3NyJ9DQogICAgbGlzdChjb2xvciA9IGNvbG9yLCBmb250V2VpZ2h0ID0gImJvbGQiKQ0KICB9KQ0KICApLA0KICBkZWZhdWx0Q29sRGVmID0gY29sRGVmKGZvb3RlciA9IGZ1bmN0aW9uKHZhbHVlcykgew0KICAgIGlmICghaXMubnVtZXJpYyh2YWx1ZXMpKSByZXR1cm4oKQ0KICAgIHNwYXJrbGluZSh2YWx1ZXMsIHR5cGUgPSAiYm94Iiwgd2lkdGggPSAxMDAsIGhlaWdodCA9IDMwKQ0KICB9KQ0KKQ0KYGBgDQoNCihXYW50IHRvIGJlIHN1cGVyIGltcHJlc3NlZD8gIEhvdmVyIG92ZXIgdGhlIHNwYXJrIGJveCkNCg0KKioqDQojIyMgTGV0cyBnZXQgcGxvdHRpbmcuLi4NCioqKg0KDQpPZiBjb3Vyc2Ugd2UgY2FuIGFkZCBhIHBsb3QsIHlvdSBjYW4gY2hhbmdlIHRoZSBzaXplLCBhbGlnbm1lbnQgYW5kIGFsbCBvZiB0aGF0IHN0dWZmLiAgWW91IGNhbiB3cmFwIHlvdXIgdGV4dCBhcm91bmQgYSBwbG90IGFuZCBwb3RlbnRpYWxseSBoYXZlIHBsb3RzIHNpZGUgYnkgc2l6ZS4NCg0KWW91IG5lZWQgdG8gc3dpdGNoIHRvIHRoZSBjb2RlIGhlcmUgZm9yIGEgbGl0dGxlIGZ1bmt5IHBsb3R0aW5nIHNob3J0IGN1dC4NCg0KIyBMaWJyYXJ5IC0gZXNxdWlzc2UNCg0KYGBge3IgcGxvdHR5bWNwbG90ZmFjZX0NCg0KIyMgc28gd2Ugd2FudCB0byBpbmNsdWRlIGEgcGxvdCAtIGJ1dCB3aGF0IHBsb3Qgc2hhbGwgd2UgbWFrZT8NCiMjIGhvcGVmdWxseSB3ZSBoYXZlIGEgYml0IG9mIGtub3dsZWRnZSBvZiBnZ3Bsb3QgYnV0IHNvbWV0aW1lcyBhIGxpdHRsZSB0cmlja3kgdG8gcGxheSB3aXRoIA0KIyNvciB5b3UgbWF5IHdhbnQgdG8gcXVpY2tseSBoYXZlIGEgbG9vayBhdCBhIG51bWJlciBvZiBwbG90cyB0byBzZWUgd2hpY2ggb25lIGlzIGJlc3QgZm9yIHlvdS4NCg0KIyNpbnRyb2R1Y2luZyB0aGUgZXNxdWlzc2UgcGFja2FnZSAoZnJlbmNoIHdvcmQgdGhhdCBtZWFucyAnYSByb3VnaCBvciBwcmVsaW1pbmFyeSBza2V0Y2gnKSANCg0KIyMgbGV0cyBqdXN0IG1ha2UgYSBxdWljayBjdXQgZG93biBkYXRhc2V0DQpkYXRhNCA8LSBkYXRhICU+JSBmaWx0ZXIgKG9yZ19jb2RlID09IlJYUSIpDQoNCg0KDQojIyBjbGljayBpbiB0aGUgY29kZSB3aGVyZSB5b3Ugd291bGQgbGlrZSB0byBhZGQgc29tZSBwbG90IGNvZGUNCg0KIyMgIGVzcXVpc3NlcihkYXRhKSAgICMjcnVuIHRoaXMgaW4gdGhlIGNvbnNvbGUNCg0KIyMgIGRyYWcgcGVyaW9kIHRvIHgNCiMjICBkcmFnIGF0dGVuZGFuY2VzIHRvIHkNCiMjICBkcmFnIHR5cGUgdG8gZ3JvdXANCiMjICBjYW4gYWxzbyBwbGF5ICB3aXRoIGZvcm1hdHMgYW5kIHRoZW1lcyBhbmQgZmlsdGVyIHRoZSBkYXRhIHRvIGEgc21hbGwgYW1vdW50DQojIyAgY2FuIHRoZW4gcGxhY2UgY29kZSBpbnRvIHlvdXIgc2NyaXB0DQoNCiMjIHRhIGRhIQ0KDQpnZ3Bsb3QoZGF0YTQsIGFlcyh4ID0gcGVyaW9kLCB5ID0gYXR0ZW5kYW5jZXMsIGdyb3VwID0gdHlwZSwgY29sb3VyID0gdHlwZSkpICsNCiBnZW9tX2xpbmUoc2l6ZSA9IDEuMzIpICsNCiBsYWJzKHRpdGxlID0gIlJYUSBOdW1iZXIgb2YgYXR0ZW5kYW5jZXMgYnkgdHlwZSIpICsNCiB0aGVtZV9taW5pbWFsKCkNCg0KDQpgYGANCg0KU28gdGhhdCdzIGEgcGxvdCwgZG9lcyB3aGF0IGl0IHNheXMgb24gdGhlIHRpbiwgYnV0IHdoYXQgaXMgYmV0dGVyIHRoYW4gYSBzdGF0aWMgcGxvdD8NCg0KSW50ZXJhY3RpdmUgcGxvdHMuLi4NCg0KDQojIExpYnJhcnkgLSBwbG90bHkNCg0KYGBge3IgaW50ZXJhY3RpdmVwbG90dHltY3Bsb3RmYWNlfQ0KDQojI3Rha2Ugb3VyIG5vcm1hbCBncmFwaCB3ZSBqdXN0IG1hZGUgYW5kIG1ha2UgaXQgYW4gb2JqZWN0DQoNCnAxIDwtIGdncGxvdChkYXRhNCwgYWVzKHggPSBwZXJpb2QsIHkgPSBhdHRlbmRhbmNlcywgZ3JvdXAgPSB0eXBlLCBjb2xvdXIgPSB0eXBlKSkgKw0KIGdlb21fbGluZShzaXplID0gMS4zMikgKw0KIGxhYnModGl0bGUgPSAiUlhRIE51bWJlciBvZiBhdHRlbmRhbmNlcyBieSB0eXBlIikgKw0KIHRoZW1lX21pbmltYWwoKQ0KDQojIyB0aGVuIHNpbXBseSAoZ2cpcGxvdGx5IGl0Li4NCg0KZ2dwbG90bHkocDEpDQoNCmBgYA0KDQoNCiogWW91IGNhbiBjbGljayBvbiB0aGUgbGVnZW5kIHRvIGFkZCBvciByZW1vdmUgbGluZQ0KKiBZb3UgY2FuIGNsaWNrIGFuZCBkcmFnIGFuIGFyZWEgdG8gem9vbSBpbiBvbg0KKiBZb3UgY2FuIGhvdmVyIG92ZXIgbGluZSB0byBzZWUgZGF0YSBwb2ludHMNCiogWW91IGNhbiBleHBvcnQgYXMgYW4gaW1hZ2UNCg0KQWxsIGlzIGZhciBtb3JlIGN1c3RvbWlzYWJsZSB3aXRoaW4gdGhlIHBsb3RseSBmdW5jdGlvbiwgeW91IGNhbiBoYXZlIG11bHRpcGxlIHNlbGVjdC1hYmxlIGRhdGEgc2V0cyBhbmQgYWxsIG1hbm5lciBvZiBvdGhlciBzdHVmZi4NCg0KIyMgQW5pbWF0ZWQgZ3JhcGhzDQoNClByZXR0eSBjb29sIGJ1dCBsZXRzIHNob3cgb2ZmIGFuZCBhbmltYXRlDQoNCg0KYGBge3IgYW5pbWF0ZWRwbG90dHltY3Bsb3RmYWNlfQ0KDQpkYXRhNSA8LSBkYXRhNA0KDQphY2N1bXVsYXRlX2J5IDwtIGZ1bmN0aW9uKGRhdCwgdmFyKSB7DQogIHZhciA8LSBsYXp5ZXZhbDo6Zl9ldmFsKHZhciwgZGF0KQ0KICBsdmxzIDwtIHBsb3RseTo6OmdldExldmVscyh2YXIpDQogIGRhdHMgPC0gbGFwcGx5KHNlcV9hbG9uZyhsdmxzKSwgZnVuY3Rpb24oeCkgew0KICAgIGNiaW5kKGRhdFt2YXIgJWluJSBsdmxzW3NlcSgxLCB4KV0sIF0sIGZyYW1lID0gbHZsc1tbeF1dKQ0KICB9KQ0KICBkcGx5cjo6YmluZF9yb3dzKGRhdHMpDQp9DQoNCmRhdGE1JHllYXIgPC0geWVhcihkYXRhNSRwZXJpb2QpDQpkYXRhNSRkYXRlIDwtIGRlY2ltYWxfZGF0ZShkYXRhNSRwZXJpb2QpDQpmaWcgPC0gZGF0YTUgJT4lIGFjY3VtdWxhdGVfYnkofnBlcmlvZCkNCg0KZmlnIDwtIGZpZyAlPiUNCiAgcGxvdF9seSgNCiAgICB4ID0gfmRhdGUsIA0KICAgIHkgPSB+YXR0ZW5kYW5jZXMsDQogICAgc3BsaXQgPSB+dHlwZSwNCiAgICBmcmFtZSA9IH5mcmFtZSwgDQogICAgI3R5cGUgPSAnc2NhdHRlcicsDQogICAgbW9kZSA9ICdsaW5lcycgDQogICAjIG1vZGUgPSAnbGluZXMrbWFya2VycycsDQogICAjIHR5cGUgPSAnc2NhdHRlcicsIA0KICAjICBtb2RlID0gJ25vbmUnLCANCiAgIyAgZmlsbCA9ICd0b3plcm95JywNCiAgIyAgbGluZSA9IGxpc3Qoc2ltcGx5ZnkgPSBUKQ0KICApDQpmaWcgPC0gZmlnICU+JSBsYXlvdXQoDQogIHhheGlzID0gbGlzdCgNCiAgICB0aXRsZSA9ICJEYXRlIiwNCiAgICB6ZXJvbGluZSA9IEYNCiAgKSwNCiAgeWF4aXMgPSBsaXN0KA0KICAgIHRpdGxlID0gIkFkbWlzc2lvbnMiLA0KICAgIHplcm9saW5lID0gVA0KICApDQopIA0KZmlnIDwtIGZpZyAlPiUgYW5pbWF0aW9uX29wdHMoDQogIGZyYW1lID0gMTAwLCANCiAgdHJhbnNpdGlvbiA9IDAsIA0KICByZWRyYXcgPSBUUlVFDQopDQpmaWcgPC0gZmlnICU+JSBhbmltYXRpb25fc2xpZGVyKA0KICBoaWRlID0gRg0KKQ0KZmlnIDwtIGZpZyAlPiUgYW5pbWF0aW9uX2J1dHRvbigNCiAgeCA9IDEsIHhhbmNob3IgPSAicmlnaHQiLCB5ID0gMCwgeWFuY2hvciA9ICJib3R0b20iDQopDQoNCmZpZw0KDQpgYGANCg0KT2J2aW91c2x5IHByZXR0eSBwb2ludGxlc3MgaW4gdGhpcyBleGFtcGxlLCBidXQgbWF5IGJlIGdvb2QgYXMgYSB3YXkgdG8gYmUgbW9yZSB2aXN1YWwgdG8gZ2V0IGEgcG9pbnQgYWNyb3NzLiAgDQoNCklmIGl0IGdldHMgcGVvcGxlIGFjdHVhbGx5IGxvb2tpbmcgYXQgdGhlIGRhdGEgYW5kIHdhbnRpbmcgdGhlaXIgbGl0dGxlIHdpZ2dseSBsaW5lcyBnb2luZyB1cCB0aGF0IGhhcyB0byBiZSBnb29kIGZvciBwYXRpZW50IGNhcmUuDQoNCiMgTGlicmFyeSAtIGR5Z3JhcGhzDQoNClNvIGhvdyBhYm91dCB3ZSB0YWtlIHRoZSBhZG1pc3Npb25zIGRhdGEgZm9yIHRoZSBwcm92aWRlcnMgYWJvdmUgYW5kIGNyZWF0ZSBhIG5pY2UgdGltZSBzZXJpZXMgZ3JhcGguICBUaGlzIERZIGdyYXBoIGlzIG5pY2UgZm9yIHBsYXlpbmcgd2l0aCB0aW1lIHNlcmllcyBhcyBpdCBhbGxvd3MgeW91IHRvIHpvb20gaW4gb24gY2VydGFpbiBhcmVhcy4NCg0KVGhlcmUgaXMgYWxzbyBhIG5pY2UgbGl0dGxlIGJveCBvbiB0aGUgYm90dG9tIGxlZnQgb2YgdGhlIGdyYXBoLiAgVGhpcyBhbGxvd3MgeW91IHRvIHNtb290aCB5b3VyIGRhdGEgd2l0aCBhIHJvbGxpbmcgYXZlcmFnZSBvbiB0aGUgZmx5LiAgUmVhbGx5IHVzZWZ1bCBmb3IgdGhpbmdzIHN1Y2ggYXMgbGVuZ3RoIG9mIHN0YXkgb3IgdGhpbmdzIHdpdGggbG90cyBvZiB2YXJpYWJsaXR5IGFuZCB0cnlpbmcgdG8gcHVsbCBvdXQgYW4gb3ZlcmFsbCB0cmVuZC4NCg0KDQpgYGB7ciBpbnRlcmFjdGl2ZXRpbWVzZXJpZXNwbG90dHltY3Bsb3RmYWNlfQ0KDQpkYXRhMTQgPC0gZGF0YTQgJT4lIGZpbHRlcih0eXBlPT0nMScpICU+JSBzZWxlY3QoJ3BlcmlvZCcsICdhdHRlbmRhbmNlcycpIA0KDQojIFRoZW4geW91IGNhbiBjcmVhdGUgdGhlIHh0cyBuZWNlc3NhcnkgdG8gdXNlIGR5Z3JhcGgNCmRvbiA8LSB4dHMoeCA9IGRhdGExNCRhdHRlbmRhbmNlcywgb3JkZXIuYnkgPSBkYXRhMTQkcGVyaW9kKQ0KDQoNCg0KIyBGaW5hbGx5IHRoZSBwbG90DQpwIDwtIGR5Z3JhcGgoZG9uLCBtYWluID0gIkFkbWlzc2lvbnMgb3ZlciB0aW1lIikgJT4lDQogIGR5T3B0aW9ucyhsYWJlbHNVVEMgPSBUUlVFLCBmaWxsR3JhcGg9VFJVRSwgZmlsbEFscGhhPTAuMSwgZHJhd0dyaWQgPSBGQUxTRSwgY29sb3JzPSIjRDhBRTVBIiwpICU+JQ0KICBkeVJhbmdlU2VsZWN0b3IoKSAlPiUNCiAgZHlDcm9zc2hhaXIoZGlyZWN0aW9uID0gInZlcnRpY2FsIikgJT4lDQogIGR5SGlnaGxpZ2h0KGhpZ2hsaWdodENpcmNsZVNpemUgPSA1LCBoaWdobGlnaHRTZXJpZXNCYWNrZ3JvdW5kQWxwaGEgPSAwLjIsIGhpZGVPbk1vdXNlT3V0ID0gRkFMU0UpICU+JQ0KICBkeVJvbGxlcihyb2xsUGVyaW9kID0gMCkgJT4lDQogIGR5QXhpcygieSIsIGxhYmVsID0gIk51bWJlciBvZiBhZG1pc3Npb25zIikNCg0KcA0KDQpgYGANCg0KT3RoZXIgZ29vZCBmdW5jdGlvbnMgZm9yIHZpc3VhbGlzaW5nIGRhdGEgc2V0cy4NCg0KIyBMaWJyYXJ5IC0gVHJlZW1hcA0KDQpPbmUgaXMgdHJlZW1hcCwgaXQgaXMgbGlrZSBhIHBvc2ggcGllIGNoYXJ0IGZvciBsb29raW5nIGF0IHByb3BvcnRpb25zIG9mIGEgdmFyaWFibGUuDQoNCk9idmlvdXNseSBSICoqY2FuKiogZG8gcGllIGNoYXJ0cywgYnV0IEkgd2hlcmVhcyBJIGFtIHdpbGxpbmcgdG8gc2hvdyB5b3UgaG93IGFkZCBhbmltYXRlZCBnaWZzIGludG8geW91ciByZXBvcnRzLCBldmVuIEkgd291bGQgbm90IHNpbmsgdGhhdCBsb3cuIA0KDQpgYGB7ciB0cmVlbWFwfQ0KDQpkYXRhOCA8LSBkYXRhICU+JSBmaWx0ZXIgKHR5cGUgPT0gJzInLCBwZXJpb2QgPT0gJzIwMTgtMDQtMDEnKQ0KDQoNCnRyZWVtYXAoZGF0YTgsIGluZGV4PWMoIm9yZ19jb2RlIiwgInR5cGUiKSx2U2l6ZT0iYXR0ZW5kYW5jZXMiKQ0KDQoNCmBgYA0KDQpUaGlzIGlzIGEgbmljZSBvdmVydmlldyBvZiBhIGxhcmdlIGFtb3VudCBvZiBkYXRhLCBnZXRzIGEgYml0IG1lc3N5IHdoZW4geW91IGhhdmUgYSBsb3Qgb2YgZmFjdG9ycw0KDQojIExpYnJhcnkgLSBjb2xsYXBzaWJsZVRyZWUNCg0KQW5vdGhlciByZWFsbHkgY29vbCB0aGluZyB0byBwbGF5IHdpdGggaXMgYSBkZW5kcm9ncmFtIHdoaWNoIHlvdSBjYW4gbWFrZSB3aXRoIGNvbGxhcHNpYmxlVHJlZS4gDQoNClRoaXMgaXMgcmVhbGx5IGdvb2QgYXQgc2hvd2luZyBmbG93IHRocm91Z2ggcGF0aHdheXMgYW5kIHN5c3RlbXMuICBZb3UgY2FuIG1ha2UgdGhlbSBob3Jpem9udGFsIG9yIHZlcnRpY2FsIGFuZCBwbGF5IHdpdGggYWxsIG1hbm5lciBvZiBiaXRzIG9uIHRoZSBub2Rlcy4NCg0KQ2xpY2sgb24gdGhlIG5vZGVzIGFuZCB5b3UgY2FuIGFsc28gem9vbSBpbiBhbmQgb3V0IGFuZCBzY3JvbGwgYXJvdW5kLg0KDQpJIGFsc28gZmluZCBpdCByZWFsbHkgcmVsYXhpbmcgZm9yIHNvbWUgcmVhc29uLg0KDQoNCmBgYHtyIGNvbGxhcHNlYWJsZXRyZWV9DQoNCmRhdGE2IDwtIGRhdGEgJT4lIGZpbHRlciAob3JnX2NvZGUgJWluJSBjKCJSSzkiLCAiUldKIiwgIkFEOTEzIikpDQoNCg0KDQpjb2xsYXBzaWJsZVRyZWUoIGRhdGE2LCBjKCJvcmdfY29kZSIsICJ0eXBlIiwicGVyaW9kIiwgImF0dGVuZGFuY2VzIiksIG5vZGVTaXplID0gJ2xlYWZDb3VudCcsIHJvb3QgPSAnQmFzZSBkYXRhJywgdG9vbHRpcCA9IFRSVUUpDQoNCmBgYA0KDQojIExpYnJhcnkgLSBMZWFmbGV0DQoNCkxlYWZsZXQgaXMgYSBncmVhdCBtYXBwaW5nIGxpYnJhcnkgYW5kIHdvcmtzIHdpdGggb3BlbiBzdHJlZXQgbWFwIHNvIHlvdSBkb24ndCBoYXZlIHRvIHdvcnJ5IGFib3V0IGdvb2dsZSBBUEkgdG9rZW5zIGFuZCB0aGUgbGlrZS4gIFRoZXJlIGFyZSBzb21lIGZhbnRhc3RpYyB0aGluZ3MgeW91IGNhbiBkbyB3aXRoIHRoZSBnb29nbGUgc2VydmljZSB3aGljaCBhbGxvd3MgeW91IHRvIGFjY2VzcyB0cmF2ZWwgdGltZXMgYW5kIHJvdXRlIGZpbmRpbmcsIGhvd2V2ZXIgZm9yIHNpbXBsZSBtYXBwaW5nIGxlYWZsZXQgaXMgZ3JlYXQuICBZb3UgY2FuIGRvIGhlYXRtYXBzIGFuZCBhcmVhcywgZHJhdyBsaW5lcyBhY3Jvc3MgcG9pbnRzIGFuZCBhbHNvIGFkZCBsYXllcnMgdGhhdCB5b3UgY2FuIHNlbGVjdCBvbiBhbmQgb2ZmLiAgDQoNClRoaXMgZXhhbXBsZSBoYXMgMyB0ZWFtcyB0aGF0IGFyZSBzZXQgdXAgYXMgbGF5ZXJzIGFuZCB5b3VjYW4gdHVybiBlYWNoIG9uZSBvbiBhbmQgb2ZmLiAgDQoNClRoZSBtYXBzIGNhbiBiZSBzY3JvbGxlZCBhbmQgem9vbWVkLCB3aGF0IGlzIG5pY2UgaXMgdGhlIGljb25zIHJlbWFpbiB0byBzY2FsZS4NCg0KDQpgYGB7ciBtYXBweW1jbWFwZmFjZX0NCg0KIyMgY3JlYXRlcyBhIGJhc2ljIGRhdGFmcmFtZSB3aXRoIHNvbWUgdGVhbXMgYW5kIHBvc3Rjb2Rlcw0KbGFiZWwgPC0gYygnVGVhbSBBJywgJ1RlYW0gQScsICdUZWFtIEInLCAnVGVhbSBCJywgJ1RlYW0gQycpDQpwb3N0Y29kZSA8LSBjKCdFWDE2IDdGTCcsICdFWDM5IDVFTicsICdQTDEzIDJXUCcsICdQTDE1IDhSWicsICdQTDMwIDRQWCcpDQpkZiA8LSBkYXRhLmZyYW1lKGxhYmVsLHBvc3Rjb2RlKQ0KDQojIyBUaGlzIGlzIHRoZSBtYWdpYyBiaXQgdGhhdCB1c2VzIHRoZSB0aWR5Z2VvY29kZXIgcGFja2FnZSB0byBmaW5kIGxvbmdhdHVkZXMgYW5kIGxhdGl0dWRlcw0KZGYgPC0gZGYgJT4lIG11dGF0ZSggZ2VvKGFkZHJlc3MgPSBkZiRwb3N0Y29kZSwgbWV0aG9kID0gJ29zbScpKQ0KDQojIyBGaWx0ZXJzIGNvaG9ydCBpbnRvIHRocmVlIGxpc3RzLCBvbmUgZm9yIGVhY2ggaWNvbnNldA0KY29ob3J0X2ZpbHRlcjEgPC0gZGYgJT4lDQogIGZpbHRlcihkZiRsYWJlbCA9PSAiVGVhbSBBIikNCmNvaG9ydF9maWx0ZXIyIDwtIGRmICU+JQ0KICBmaWx0ZXIoZGYkbGFiZWwgPT0gIlRlYW0gQiIpDQpjb2hvcnRfZmlsdGVyMyA8LSBkZiAlPiUNCiAgZmlsdGVyKGRmJGxhYmVsID09ICJUZWFtIEMiKQ0KDQojIyAgQ3JlYXRlIGF3ZXNvbWUgaWNvbiBzZXRzIGZvciBjb2xvdXJzDQppY29uU2V0IDwtIGF3ZXNvbWVJY29uTGlzdCgNCiAgIlRlYW0gQSIgID0gbWFrZUF3ZXNvbWVJY29uKCBpY29uID0gJ21hbGUnLCBsaWIgPSAnZmEnLCBpY29uQ29sb3IgPSAiYmxhY2siLCBtYXJrZXJDb2xvciA9ICJyZWQiICAgLCBzcGluID0gRkFMU0UgKSAsDQogICJUZWFtIEIiICAgICAgICAgICAgID0gbWFrZUF3ZXNvbWVJY29uKCBpY29uID0gJ21hbGUnLCBsaWIgPSAnZmEnLCBpY29uQ29sb3IgPSAiYmxhY2siLCBtYXJrZXJDb2xvciA9ICJvcmFuZ2UiLCBzcGluID0gRkFMU0UgKSAsDQogICJUZWFtIEMiICAgICAgID0gbWFrZUF3ZXNvbWVJY29uKCBpY29uID0gJ21hbGUnLCBsaWIgPSAnZmEnLCBpY29uQ29sb3IgPSAiYmxhY2siLCBtYXJrZXJDb2xvciA9ICJiZWlnZSIgLCBzcGluID0gRkFMU0UgKSApDQoNCiMjIENyZWF0ZXMgbGF5b3JzIGZvciBtYXAsIGVhY2ggZm9yIHRoZSB0aHJlZSBpY29uc2V0ICdUZWFtcycNCm1hcCA8LSBsZWFmbGV0KGRmKSAlPiUgIA0KICBhZGRUaWxlcygpICU+JQ0KICBhZGRQcm92aWRlclRpbGVzKHByb3ZpZGVycyRPcGVuU3RyZWV0TWFwKSAlPiUgDQogIGFkZEF3ZXNvbWVNYXJrZXJzKCBsbmcgPSBjb2hvcnRfZmlsdGVyMSRsb25nLA0KICAgICAgICAgICAgICAgICAgICAgbGF0ID0gY29ob3J0X2ZpbHRlcjEkbGF0LA0KICAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSAiVGVhbSBBIiwNCiAgICAgICAgICAgICAgICAgICAgIGljb24gPSBpY29uU2V0W2NvaG9ydF9maWx0ZXIxJGxhYmVsXSwNCiAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gcGFzdGUoc2VwID0gIiAtICIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvaG9ydF9maWx0ZXIxJGxhYmVsICkgKSAlPiUNCiAgYWRkQXdlc29tZU1hcmtlcnMoIGxuZyA9IGNvaG9ydF9maWx0ZXIyJGxvbmcsDQogICAgICAgICAgICAgICAgICAgICBsYXQgPSBjb2hvcnRfZmlsdGVyMiRsYXQsDQogICAgICAgICAgICAgICAgICAgICBncm91cCA9ICJUZWFtIEIiLA0KICAgICAgICAgICAgICAgICAgICAgaWNvbiA9IGljb25TZXRbY29ob3J0X2ZpbHRlcjIkbGFiZWxdLA0KICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSBwYXN0ZShzZXAgPSAiIC0gIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29ob3J0X2ZpbHRlcjIkbGFiZWwgKSApICU+JQ0KICBhZGRBd2Vzb21lTWFya2VycyggbG5nID0gY29ob3J0X2ZpbHRlcjMkbG9uZywNCiAgICAgICAgICAgICAgICAgICAgIGxhdCA9IGNvaG9ydF9maWx0ZXIzJGxhdCwNCiAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gIlRlYW0gQyIsDQogICAgICAgICAgICAgICAgICAgICBpY29uID0gaWNvblNldFtjb2hvcnRfZmlsdGVyMyRsYWJlbF0sDQogICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IHBhc3RlKHNlcCA9ICIgLSAiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2hvcnRfZmlsdGVyMyRsYWJlbCApICkgJT4lIA0KICBhZGRMYXllcnNDb250cm9sKG92ZXJsYXlHcm91cHMgPSBjKCJUZWFtIEEiLCAiVGVhbSBCIiwgIlRlYW0gQyIpLCAgICAjI3RoaXMgYml0IGFkZHMgdGhlIGNvbnRyb2xzDQogICAgb3B0aW9ucyA9IGxheWVyc0NvbnRyb2xPcHRpb25zKGNvbGxhcHNlZCA9IEZBTFNFKSApIA0KDQptYXANCg0KYGBgDQoNCiMgTGlicmFyeSAtIFdvcmRjbG91ZDINCg0KV29yZGNsb3VkMiBpcyB0aGUgc2VxdWVsIHRvIHdvcmRjbG91ZCwgbXVjaCBsaWtlIEV2aWwgRGVhZCAyIHRvIHRoZSBvcmlnaW5hbCwgaXQgaXMgYSBmYXIgc3VwZXJpb3IgcHJvZHVjdCwgaXQgaGFzIHNvbWUgcmVhbGx5IG5pY2UgZWFzeSB0byB1c2UgZmVhdHVyZXMgYW5kIGNhbiBtYWtlIGFsbCBtYW5uZXIgb2YgZGlmZmVyZW50IHdvcmRjbG91ZHMgdHlwZXMuICANCg0KSG93ZXZlciBiZWZvcmUgeW91IGdldCB0byBhIHdvcmQgY2xvdWQgeW91IG5lZWQgc29tZSBkYXRhIHdoaWNoIGlzIGJhc2ljYWxseSBhIGxpc3Qgb2Ygd29yZHMgYW5kIHRoZWlyIGZyZXF1ZW5jeS4gIFlvdSBjYW4gZG8gdGhpcyBtYW51YWxseSBvbiB5b3VyIGZpbmdlcnMgb3IgeW91IGNhbiBnZXQgUiB0byBkbyB0aGlzIGZvciB5b3UuICBJIGRlZmluYXRlbHkgcmVjb21tZW5kIHRoZSBsYXR0ZXIuDQoNClRvIGdldCB0byB0aGF0IHlvdSByZWFkIGluIHNvbWUgZGF0YSwgc3RyaXAgb3V0IGFsbCB0aGUgZ3ViYmlucyBzdWNoIGFzIHB1bmN0dWF0aW9uLCByZW1vdmUgYWxsIHRoZSAnc3RvcCB3b3Jkcycgc3VjaCBhcyAndGhlJyBhbmQgJ2FuZCcgZXRjIGFuZCB0aGVuIHJlbW92ZSB3aGl0ZSBzcGFjZSBhbmQgdGhlcmUgeW91IGhhdmUgYSBidW5jaCBvZiB3b3JkcyBmaXQgZm9yIGEgY2xvdWQuDQoNClRoaXMgaXMgYW4gZXhhbXBsZSB0aGF0IHB1bGxzIHRoZSB0ZXh0IGZyb20gYSBwb3B1bGFyIGNoaWxkcmVucyBub3ZlbCBhbmQgY3JlYXRlcyBhIGNsb3VkLiAgSG9wZWZ1bGx5IHlvdSBjYW4gZ3Vlc3MgdGhlIGJvb2sgZnJvbSB0aGUgY2xvdWQuDQoNCllvdSBjYW4gaG92ZXIgb3ZlciB0aGUgd29yZHMgaW4gdGhlIGNsb3VkIGFuZCBpdCB3aWxsIHRlbGwgeW91IHRoZSB3b3JkIGFuZCBnaXZlIHlvdSB0aGUgbnVtYmVyIG9mIHRoZSBmcmVxdWVuY3kuDQoNCg0KYGBge3IgY2xvdWR5d2l0aGFjaGFuY2VvZndvcmRzfQ0KDQojIyMjIyBOb3RlIHRoYXQgdGhpcyBzZWN0aW9uIG1heSBub3QgcnVuIGlmIHlvdXIgVlBOIGhhcyBoaWdoIHNlY3VyaXR5ICMjIyMjIA0KIyMgcmVhZHMgaW4gdGV4dCBmaWxlIGZyb20gdGhlIGludGVyd2Vieg0KZmlsZVBhdGggPC0gImh0dHBzOi8vd3d3Lmd1dGVuYmVyZy5vcmcvZmlsZXMvMTEvMTEtMC50eHQiDQp0ZXh0IDwtIHJlYWRMaW5lcyhmaWxlUGF0aCkNCg0KIyNjb252ZXJ0cyB0aGUgZmlsZSBpbnRvIGEgY29ycHVzICh2ZWN0b3IgZmlsZSBmb3IgdGV4dCBtaW5pbmcpDQpkb2NzIDwtIENvcnB1cyhWZWN0b3JTb3VyY2UodGV4dCkpDQoNCiMjIHJlbW92ZXMgc3BhY2VzIGFzIGFuZCBvZGQgY2hhcmFjdGVycw0KdG9TcGFjZSA8LSBjb250ZW50X3RyYW5zZm9ybWVyKGZ1bmN0aW9uICh4ICwgcGF0dGVybiApIGdzdWIocGF0dGVybiwgIiAiLCB4KSkNCmRvY3MgPC0gdG1fbWFwKGRvY3MsIHRvU3BhY2UsICIvIikNCmRvY3MgPC0gdG1fbWFwKGRvY3MsIHRvU3BhY2UsICJAIikNCmRvY3MgPC0gdG1fbWFwKGRvY3MsIHRvU3BhY2UsICJcXHwiKQ0KZG9jcyA8LSB0bV9tYXAoZG9jcywgdG9TcGFjZSwgIiciKQ0KZG9jcyA8LSB0bV9tYXAoZG9jcywgdG9TcGFjZSwgImAiKQ0KIyBSZW1vdmUgcHVuY3R1YXRpb25zDQpkb2NzIDwtIHRtX21hcChkb2NzLCByZW1vdmVQdW5jdHVhdGlvbikNCiMgQ29udmVydCB0aGUgdGV4dCB0byBsb3dlciBjYXNlDQpkb2NzIDwtIHRtX21hcChkb2NzLCBjb250ZW50X3RyYW5zZm9ybWVyKHRvbG93ZXIpKQ0KIyBSZW1vdmUgbnVtYmVycw0KZG9jcyA8LSB0bV9tYXAoZG9jcywgcmVtb3ZlTnVtYmVycykNCiMgUmVtb3ZlIGVuZ2xpc2ggY29tbW9uIHN0b3B3b3Jkcw0KZG9jcyA8LSB0bV9tYXAoZG9jcywgcmVtb3ZlV29yZHMsIHN0b3B3b3JkcygiZW5nbGlzaCIpKQ0KIyBzcGVjaWZ5IHlvdXIgc3RvcHdvcmRzIGFzIGEgY2hhcmFjdGVyIHZlY3RvciAtIGluIHRoaXMgaW5zdGFuY2UgaXQgd2FzIHBpY2tpbmcgdXAgc29tZSBvZiB0aGUgY29weXJpZ2h0IG5vdGljZQ0KZG9jcyA8LSB0bV9tYXAoZG9jcywgcmVtb3ZlV29yZHMsIGMoInByb2plY3QiLCAibGljZW5zZSIsICJjb3B5cmlnaHQiLCJndXRlbmJlcmciLCJlbGVjdHJvbmljIiwiYWdyZWVtZW50IiwiZ3V0ZW5iZXJndG0iKSkgDQojIEVsaW1pbmF0ZSBleHRyYSB3aGl0ZSBzcGFjZXMNCmRvY3MgPC0gdG1fbWFwKGRvY3MsIHN0cmlwV2hpdGVzcGFjZSkNCiNpdCB3YXMgc3RpbGwgYnJpbmdpbmcgYmFjayBzb21lIHF1b3RhdGlvbiBtYXJrcyBhbmQgc28gdGhpcyBmaW5hbGx5IHJlbW92ZXMgd2hhdCBpcyBsZWZ0DQpyZW1vdmVTcGVjaWFsQ2hhcnMgPC0gZnVuY3Rpb24oeCkgZ3N1YigiW15hLXpBLVowLTkgXSIsIiIseCkNCmRvY3MgPC0gdG1fbWFwKGRvY3MsIGNvbnRlbnRfdHJhbnNmb3JtZXIocmVtb3ZlU3BlY2lhbENoYXJzKSkNCg0KIyB0aGlzIGJpdCBzb3J0cyBhbmQgcmFua3MgdGhlIHdvcmQgZnJlcXVlbmNpZXMgYW5kIHBsb25rcyBpbnRvIHRoZSBkYXRhZnJhbWUgJ2QnDQpkdG0gPC0gVGVybURvY3VtZW50TWF0cml4KGRvY3MpDQptIDwtIGFzLm1hdHJpeChkdG0pDQp2IDwtIHNvcnQocm93U3VtcyhtKSxkZWNyZWFzaW5nPVRSVUUpDQpkIDwtIGRhdGEuZnJhbWUod29yZCA9IG5hbWVzKHYpLGZyZXE9dikNCg0KIyB0aGlzIGlzIHRoZSBsaW5lIHRoYXQgY3JlYXRlcyB0aGUgd29yZCBjbG91ZA0Kd29yZGNsb3VkMihkLCBjb2xvciA9ICJyYW5kb20tbGlnaHQiLCBiYWNrZ3JvdW5kQ29sb3IgPSAid2hpdGUiKQ0KYGBgDQoNCiMgTGlicmFyeSAtIFJwaXZvdHRhYmxlDQoNClNhdmluZyBwZXJoYXBzIG15IGZhdm9yaXRlIHVudGlsIGxhc3QsIGlzIHRoZSBzdXBlciBhd2Vzb21lIFJwaXZvdHRhYmxlLg0KDQpUaGlzIGhhcyBmdWxsIGNsaWNrIGFuZCBkcmFnIGZ1bmN0aW9uYWxpdHkgYXMgd2VsbCB0aGUgb3B0aW9uIHRvIHNldCB1cCBkZWZhdWx0cyBpbiB0aGUgcmVwb3J0IGFuZCBhbHNvIHlvdSBjYW4gY2xpY2sgdGhyb3VnaCwgY3JlYXRlIGNoYXJ0cyBhbmQgaGVhdCBtYXBzLCBmaWx0ZXIgeW91ciBkYXRhLCBjYWxjdWxhdGUgYSBwaXZvdCB0YWJsZSB3aXRoIGEgbWVkaWFuIGFuZCBqdXN0IGRvIGFsbCBzb3J0cyBvZiBtYWdpYy4NCg0KWW91IGNhbiBjbGljayBhbmQgZHJhZyB0aGUgdmFyaWFibGVzIGFyb3VuZC4gIFlvdSBjYW4gY2xpY2sgb24gdGhlIGFycm93cyB0byB0aGUgc2lkZSBvZiB0aGUgdmFyaWFibGVzIHRvIGZpbHRlciB0aGVtLiAgWW91IGNhbiBjbGljayBvbiB0aGUgY291bnQgdG8gc2VsZWN0IGEgZGlmZmVyZW50IG1ldHJpYyBhbmQgZmluYWxseSB5b3UgY2FuIGNsaWNrIG9uIHRoZSB0YWJsZSB0byBjaGFuZ2UgdGhlIHJlc3VsdHMgdG8gYSBncmFwaCBvciBoZWF0bWFwIG9yIGxvYWRzIG9mIHRoaW5ncy4gDQoNCkl0IGRvZXNuJ3QgbGlrZSBzdXBlciBodWdlIGRhdGEgc2V0cyBpZiB5b3UgYXJlIHJ1bm5pbmcgaXQgbG9jYWxseSBidXQgaWYgeW91IGdldCBjbGV2ZXIgd2l0aCBzaGlueSwgeW91IGNhbiBkbyBiaWcgdGhpbmdzLg0KDQpJdCBhbHNvIGhhcyBhIGhhYmJpdCBvZiBvdmVybGFwcGluZyB3aXRoIHN0dWZmIGJlbG93IGl0LiAgSSBhbSB3b3JraW5nIG9uIGEgSFROTCBzb2x1dGlvbiB0byB0aGlzIGFuZCBJIHRoaW5rIHRoaXMgaXMgYSAnZmVhdHVyZScgdGhhdCBpcyBiZWluZyB3b3JrZWQgb24gYnkgdGhlIGRldmVsb3BlcnMuICBJIHVzdWFsbHkganVzdCBhZGQgaXQgYXQgdGhlIGVuZCBvZiBhIHJlcG9ydCBvciBvbiBhIHNlcGVyYXRlIHRhYiB0byBnZXQgYXJvdW5kIHRoaXMgaXNzdWUuDQoNClRoaXMgd2hvbGUgZnVuY3Rpb25hbGl0eSBpcyBkb25lIHdpdGggb25lIGxpbmUgb2YgY29kZS4gICghISEpDQoNCmBgYHtyIHBpdm90dGFibGV9DQoNCg0KcnBpdm90VGFibGUoZGF0YTYscm93cz1jKCJvcmdfY29kZSIpLCBjb2xzPWMoInR5cGUiKSwgdmFscz1jKCJhZG1pc3Npb25zIiksd2lkdGg9IjEwMCUiLCBoZWlnaHQ9IjEyMDBweCIpDQpgYGANCg0KDQojIFRoYXRzIGFsbCBmb2xrcw0KDQpQbGVhc2UgZmVlbCBmcmVlIHRvIGhhY2sgYW5kIH5+c3RlYWx+fiBzaGFyZSBiZXN0IHByYWN0aWNlIGZyb20gdGhpcyByZXBvcnQuICANCg0KU29tZSByZWFsbHkgbmljZSB2aXN1YWxpc2F0aW9uIHRpcHMgY2FuIGJlIGZvdW5kIGF0DQoNCmh0dHBzOi8vd3d3LmRhdGEtdG8tdml6LmNvbS9jYXZlYXRzLmh0bWwNCg0KYW5kIHNvbWUgbW9yZSBtYXJrZG93biB0aXBzIGF0DQoNCmh0dHBzOi8vaG9sdHp5LmdpdGh1Yi5pby9QaW1wLW15LXJtZC8NCg0KT3RoZXIgdGhhdCBJIHdpc2ggeW91IHdlbGwgb24geW91ciBSIGpvdXJuZXkgYW5kIHBsZWFzZSBkbyBub3QgaGVzaWF0dGUgdG8gY29udGFjdCBtZSBpZiB5b3UgaGF2ZSBmb3VuZCBhbnkgaW50ZXJlc3RpbmcgdGhpbmdzIHRvIHNoYXJlIA0KDQpNZXJyeSBtYXJrZG93bmluZw0KDQo+IENvbnRhY3QNClNpbW9uLldlbGxlc2xleS1NaWxsZXJAbmhzLm5ldCANCg0K