Assumptions
This tutorial assumes you have some previous experience with both R
and DataWrapper
Set up
Install the needed packages
- If you are doing this at home, uncomment the two lines below
- These should already be installed on the NICAR computers
# install.packages("devtools") # if not already installed on your system
# devtools::install_github("munichrocker/DatawRappr")
Create an API key
You will need to create a DataWrapper API token.
- Open your DataWrapper account
- Go to Settings -> API-Tokens
- Create a new token
- Check all of the boxes
- Save your API key somewhere (you won’t be able to see it again)
The screen will look like this: 
Call needed libraries
Be sure to insert you API token in the proper place below.
library(DatawRappr)
library(tidyverse)
datawrapper_auth(api_key = "INSERT YOUR API KEY HERE", overwrite=TRUE)
Work the data
Use Lubridate to extract the year from the Reported_Date column and
put it in a new column called “year”
crime_data$Year <- year(crime_data$Reported_Date)
Filter out 2025 data since it is incomplete
crime_data <- crime_data %>%
filter(Year < 2025)
Count number of crimes per year using dyplr – this is the data for
our chart
crime_summary <- crime_data %>%
count(Year)
CHECK: Count the number of rows in the crime_data and sum the n col
in crime_summary as a double check (should match)
#nrow(crime_data)
#sum(crime_summary$n)
Rename the n column to “Reported Crimes” (this will be helpful for
our popups in the DataWrapper)
crime_summary <- crime_summary %>%
rename("Reported crimes" = "n")
Create our first chart
We will make a line chart showing reported crimes per year
Create a new chart and assign it to the variable “my_chart” (this
way, you don’t need to worry about the ID)
my_chart <- dw_create_chart()
Add our data to chart
dw_data_to_chart(crime_summary, my_chart)
You could stop here. This is actually pretty useful. We have sent our
data from R to DataWrapper without the need to export / import.
But we can take this a lot further. Let’s update and make changes to
our chart right from R.
Update the chart– Here we add a headline and chatter
dw_edit_chart(my_chart, title = "Crime in Minneapolis hit a three-year low in 2024",
intro = "Reported crimes in the city between 2019 and 2024 hit a high mark in 2022 but have been on the decline since.", source_name = "Open Data Minneapolis")
Next, we can publish our graphic
dw_publish_chart(my_chart)
Or export as an image
png_chart <- dw_export_chart(my_chart, type = "png")
magick::image_write(png_chart, "line-chart.png")
It should look like this: 
There are a few things I would change here:
- Increase the scale of the y-axis- the current scale makes the change
between years look bigger than it actually is.
- Format dates in the popups- instead of “2019 Jan 1” it should just
say “2019.”
We could make these changes pretty easily in DataWrapper, which is a
fine way to do it. Or we could further modify our graphic directly from
R. Let’s move on and see how that is done.
Create a bar chart
For our second chart, let’s use the same data to make a bar chart of
reported crimes per year and make some design modifications.
Create a chart, choose the chart type and add a title
bar_chart <- dw_create_chart(
type="d3-bars",
title="Minneapolis reported crime, 2019-2024"
)
Add our data
dw_data_to_chart(crime_summary, bar_chart)
Update with a new headline, chatter and source
dw_edit_chart(bar_chart, title = "Crime in Minneapolis hit a three-year low in 2024",
intro = "Reported crimes in the city between 2019 and 2024 hit a high mark in 2022 but have been on the decline since.", source_name = "Open Data Minneapolis")
Now, let’s take a look at our chart’s metadata– this is good key to
what can be changed.
dw_retrieve_chart_metadata(bar_chart)
It can take a little work to figure out what metadata values to
change. Sometimes the documentation will help.
Modify some of the attributes of the graphic:
- Add a byline
- Change the bar color
- Make the bars thick
- Align the labels to the right
dw_edit_chart(bar_chart,
byline = "Adam Marton",
visualize = list(
"base-color" = "#a47764",
"thick" = "true",
"value-label-alignment" = "right"
)
)
Publish our new graphic
dw_publish_chart(bar_chart)
It should look like this: 
Templating
Let’s duplicate that chart add new data. You can use this method to
create your own templates.
For our next graphic, let’s look at the Offense Category column. We
will visualize what the top 10 categories were in 2024.
First, some quick data work
Lets make a new dataframe called “crimes_2024” and filter the crime
data for just 2024
crimes_2024 <- crime_data %>%
filter(Year == 2024)
Next, we count the number of crimes in each “offense category” in
2024 using dyplr
crime_offense_summary <- crimes_2024 %>%
count(Offense_Category)
Then we sort the column number (n) column by descending and reduce to
just the top 10 using slice
crime_offense_summary <- crime_offense_summary %>%
arrange(desc(n)) %>%
slice(1:10)
This the data we will use for our new (duplicate) chart
Duplicate the bar chart we made above and add in our new data
Duplicate the bar chart
**We need the chart id for this. We can get it above from when we
first made the bar chart or from the chart URL
offense_chart <- dw_copy_chart(copy_from = "INSERT CHART ID FROM BAR CHART ABOVE")
Update the duplicated chart with the new data
dw_data_to_chart(crime_offense_summary, offense_chart)
Update text
dw_edit_chart(offense_chart, title = "Top 10 highest categories of crime offenses in Minneapolis in 2024",
intro = "Almost 13,000 larceny and theft offenses and over 8,000 assault offenses were reported.", source_name = "Open Data Minneapolis")
Let’s take a look at the chart now and decide what we need to change.
You can open it in DataWrapper or publish and look in the browser.
Publish
dw_publish_chart(offense_chart)
Next, look at the metadata
dw_retrieve_chart_metadata(offense_chart)
Modify some of the attributes of the graphic:
- change the bar color
- sort the bars by value
- Add lines between the bars
- Add a background behind the bars
- Put the labels and bars of separate lines (“block labels”?)
- align the labels to the right
dw_edit_chart(offense_chart,
visualize = list(
"base-color" = "#8ACE00",
"sort-bars" = "true",
"rules" = "true",
"background" = "true",
"block-labels" = "true",
"value-label-alignment" = "right"
)
)
Republish
dw_publish_chart(offense_chart)
It should look something like this: 
How might something like this be useful? How could you use it to save
time during production tasks?
On your own: Exercise 1
Take what we learned above and create a chart that shows the
neighborhoods with the highest reported crimes in 2024. Use whatever
chart type you like. Style it however you like. You can duplicate one of
our previous charts or make your own. Be sure to include a headline,
chatter and source.
I’ve done the data work for you below:
Count the number of crimes in each “neighborhood” in 2024 using
dyplr
crime_neighborhood_summary <- crimes_2024 %>%
count(Neighborhood)
Then we sort the column number (n) column by descending and reduce to
just the top 10 using slice
crime_neighborhood_summary <- crime_neighborhood_summary %>%
arrange(desc(n)) %>%
slice(1:10)
Now you have a dataframe called “crime_neighborhood_summary” with the
top ten neighborhoods where crimes were reported in 2024. Use that to
make your chart.
Functions
Let’s make a function that will automatically generate a chart.
Here is a simple function that creates a chart looking at reported
crimes by year in precinct 1. Read through the comments in the function
to see how it works.
my_function <- function() {
#make a new data frame that holds data just for precinct 1
precinct_data <- crime_data %>% filter(Precinct== 1)
#count number of arrests per year in that precinct
precinct_summary <- precinct_data %>%count(Year)
#create new chart
my_chart <- dw_create_chart(
type="d3-bars",
)
#add data
dw_data_to_chart(precinct_summary, my_chart)
#edit chart
dw_edit_chart(my_chart, title = paste("Reported crimes by year in Minneapolis Precinct 1"), source_name = "Open Data Minneapolis")
#publish
dw_publish_chart(my_chart)
}
#Call the function to run it
my_function()
The outputted graphic should look something like this: 
We can make this much more useful with one change – making the
specific precinct a parameter in the function. Changes are indicted in
the comments below
#add a parameter called precinct
my_function <- function(precinct) {
#instead of naming the precinct here, use the parameter
precinct_data <- crime_data %>% filter(Precinct == precinct)
precinct_summary <- precinct_data %>%count(Year)
my_chart <- dw_create_chart(
type="d3-bars",
)
dw_data_to_chart(precinct_summary, my_chart)
#Again, use the parameter instead of naming the specific precinct in the headline
dw_edit_chart(my_chart, title = paste("Reported crimes by year in Minneapolis Precinct", precinct), source_name = "Open Data Minneapolis")
dw_publish_chart(my_chart)
}
#Call the function and pass an argument -- "2"-- to the parameter
#This passes the 2 everywhere we have the parameter in the function, so our graphic will display crimes in precinct 2
my_function("2")
Now we can use this function to create a graphic for any precinct
just by changing the argument to a different precinct number when we
call the function.
Add a loop
We can wrap our function in a loop – also called a “for statement” –
to quickly create a graphic for all precincts!
for(precinct in unique(crime_data$Precinct)) {
my_function(precinct)
}
This says: for each unique value in the Precinct column of our data,
execute my_function and put the unique precinct name as the function’s
argument.
This should output 5 graphics, one for each Precinct. Each of the
graphics should look something like this: 
We could use this to create dozens or even hundreds of charts at at
time.
Make a symbol map
Our Data
In this example, we will pull crimes from the last seven days.
We will need to fake it a little bit since we only have data through
the end of 2024. Follow the comments below to see how this works.
#First we set today's date
# let's fake the current date to make this example immortal:
now = as.Date("12/31/2024", format = "%m/%d/%Y")
# however, in "real life" you should replace it with this for the current date:
# now = Sys.Date()
#Next, let's make a new dataframe that only shows crimes seven days before "now"
crimes_last_7 <- subset(crimes_2024, crimes_2024$Reported_Date > now-7)
Make the map
Create a new symbol map.
new_symbol_chart <- dw_create_chart(
title = "Crimes in Minneapolis in the last seven days",
type = "d3-maps-symbols"
)
We need to decide which base map to use. It is identified by the
id-column.
You can use dplyr’s View() to get an interactive table of available
maps and search for what you are looking for.
view(dw_basemaps)
We will use a basemap of Minneapolis neighborhoods, which has the id
“minneapolis-neighborhoods”
Connect our data to the chart
dw_data_to_chart(crimes_last_7, chart_id = new_symbol_chart)
Edit the chart.
- We need to include the latitude and longitude (which, luckily, we
have in our data already so there is no geocoding needed)
- We also include “values” which will color our symbols based on a
column
- Finally, we identify the basemap.
dw_edit_chart(new_symbol_chart,
axes = list(
lat = "Latitude",
lon = "Longitude",
values = "Offense_Category"
),
visualize = list(
basemap = "minneapolis-neighborhoods"
)
)
Add / Edit tooltips
- Title shows above the tooltip and body is the main text
- Refer to your data columns in double brackets
- You have to define your variables in the fields list. It is best
just to name the variables after the columns.
dw_edit_chart(new_symbol_chart, visualize = list(
tooltip = list(
body = "Reported Date: <br> Address: ",
title = "",
fields = list(
"reported_date" = "reported_date",
"offense" = "offense",
"address" = "address"
),
enabled = "TRUE"
)))
It is easiest to open up datawrapper at this point to edit / tweak
the legend. You could also do it via the metadata if you like.
Publish
dw_publish_chart(new_symbol_chart)
The published map should look something like this: 
On your own
Create your own map. Look at the data and think about what might be
interesting to visualize on a map. Prepare your data and then follow the
workflow above to create your own symbol / dot map. Refer to the
documentation as needed (see the top of this doc for links). Here are a
few ideas:
- Map all of the assaults that occurred in November 2024
- Map all of the crimes that occurred in the Powderhorn Park
neighborhood in the summer of 2024
- Map all of the carjackings in Ward 8 in 2024
LS0tCnRpdGxlOiAnRnJvbSBDb2RlIHRvIENoYXJ0czogQ3JlYXRlIERhdGFXcmFwcGVyIEdyYXBoaWNzIFN0cmFpZ2h0IGZyb20gUicKYXV0aG9yOiAiQWRhbSBNYXJ0b24iCnN1YnRpdGxlOiBOSUNBUiAyMDI1Cm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCioqKioqKgoKIyMjIFJlZmVyZW5jZQoKRGF0YVdyYXBwZXIgQVBJIGRvY3VtZW50YXRpb246Cmh0dHBzOi8vZGV2ZWxvcGVyLmRhdGF3cmFwcGVyLmRlL2RvY3MvZ2V0dGluZy1zdGFydGVkIAoKRGF0YXdSYXBwciBwYWNrYWdlIGRvY3VtZW50YXRpb246Cmh0dHBzOi8vbXVuaWNocm9ja2VyLmdpdGh1Yi5pby9EYXRhd1JhcHByL2luZGV4Lmh0bWwKCgoqKioqKioKCiMjIyBBc3N1bXB0aW9ucwoKVGhpcyB0dXRvcmlhbCBhc3N1bWVzIHlvdSBoYXZlIHNvbWUgcHJldmlvdXMgZXhwZXJpZW5jZSB3aXRoIGJvdGggUiBhbmQgRGF0YVdyYXBwZXIKCioqKioqKgoKCiMjIyBTZXQgdXAKCkluc3RhbGwgdGhlIG5lZWRlZCBwYWNrYWdlcwoKKiBJZiB5b3UgYXJlIGRvaW5nIHRoaXMgYXQgaG9tZSwgdW5jb21tZW50IHRoZSB0d28gbGluZXMgYmVsb3cKKiBUaGVzZSBzaG91bGQgYWxyZWFkeSBiZSBpbnN0YWxsZWQgb24gdGhlIE5JQ0FSIGNvbXB1dGVycwoKCmBgYHtyfQojIGluc3RhbGwucGFja2FnZXMoImRldnRvb2xzIikgIyBpZiBub3QgYWxyZWFkeSBpbnN0YWxsZWQgb24geW91ciBzeXN0ZW0KIyBkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoIm11bmljaHJvY2tlci9EYXRhd1JhcHByIikKYGBgCgoKIyMjIyMgQ3JlYXRlIGFuIEFQSSBrZXkKCllvdSB3aWxsIG5lZWQgdG8gY3JlYXRlIGEgRGF0YVdyYXBwZXIgQVBJIHRva2VuLgoKKiBPcGVuIHlvdXIgRGF0YVdyYXBwZXIgYWNjb3VudAoqIEdvIHRvIFNldHRpbmdzIC0+IEFQSS1Ub2tlbnMKKiBDcmVhdGUgYSBuZXcgdG9rZW4KKiBDaGVjayBhbGwgb2YgdGhlIGJveGVzCiogU2F2ZSB5b3VyIEFQSSBrZXkgc29tZXdoZXJlICh5b3Ugd29uJ3QgYmUgYWJsZSB0byBzZWUgaXQgYWdhaW4pCgpUaGUgc2NyZWVuIHdpbGwgbG9vayBsaWtlIHRoaXM6CiFbQVBJIHNjcmVlbi5dKGltYWdlcy9hcGkucG5nKQoKCiMjIyMjIENhbGwgbmVlZGVkIGxpYnJhcmllcwpCZSBzdXJlIHRvIGluc2VydCB5b3UgQVBJIHRva2VuIGluIHRoZSBwcm9wZXIgcGxhY2UgYmVsb3cuCgpgYGB7cn0KbGlicmFyeShEYXRhd1JhcHByKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKZGF0YXdyYXBwZXJfYXV0aChhcGlfa2V5ID0gICJJTlNFUlQgWU9VUiBBUEkgS0VZIEhFUkUiLCBvdmVyd3JpdGU9VFJVRSkKCmBgYAoKCiMjIyMgQ2FsbCBpbiBkYXRhIGFuZCBkaXNwbGF5IGhlYWQKV2UgYXJlIHdvcmtpbmcgd2l0aCBNaW5uZWFwb2xpcyBjcmltZSBkYXRhIGZyb20gMjAxOSB0aHJvdWdoIGVhcmx5IDIwMjUuCgpUaGUgZGF0YSBjYW4gYmUgZG93bmxvYWRlZCBoZXJlOgpodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vYW1hcnRvbi9uaWNhci0yMDI1L3JlZnMvaGVhZHMvbWFpbi9kYXRhd3JhcHBlci1yL21uLWNyaW1lLWRhdGEuY3N2P3Rva2VuPUdIU0FUMEFBQUFBQUM1TUtWSFU2SUlHWUpQSEo1UldOVUJBWjRJSURUUQoKSWYgeW91IGFyZSBvbiBhIHRyYWluaW5nIGNvbXB1dGVyIGF0IE5JQ0FSLCBpdCBzaG91bGQgYWxyZWFkeSBiZSBhdmFpbGFibGUgaW4gdGhlIGNvdXJzZSBmb2xkZXIuCgpgYGB7cn0KCmNyaW1lX2RhdGEgPC0gcmVhZC5jc3YoIm1uLWNyaW1lLWRhdGEuY3N2IikKaGVhZChjcmltZV9kYXRhKQoKYGBgCgoKKioqKioqCiMjIyBXb3JrIHRoZSBkYXRhCgpVc2UgTHVicmlkYXRlIHRvIGV4dHJhY3QgdGhlIHllYXIgZnJvbSB0aGUgUmVwb3J0ZWRfRGF0ZSBjb2x1bW4gYW5kIHB1dCBpdCBpbiBhIG5ldyBjb2x1bW4gY2FsbGVkICJ5ZWFyIgpgYGB7cn0KY3JpbWVfZGF0YSRZZWFyIDwtIHllYXIoY3JpbWVfZGF0YSRSZXBvcnRlZF9EYXRlKQoKYGBgCgoKRmlsdGVyIG91dCAyMDI1IGRhdGEgc2luY2UgaXQgaXMgaW5jb21wbGV0ZQpgYGB7cn0KY3JpbWVfZGF0YSA8LSBjcmltZV9kYXRhICU+JSAKICBmaWx0ZXIoWWVhciA8IDIwMjUpCmBgYAoKCkNvdW50IG51bWJlciBvZiBjcmltZXMgcGVyIHllYXIgdXNpbmcgZHlwbHIgLS0gdGhpcyBpcyB0aGUgZGF0YSBmb3Igb3VyIGNoYXJ0CmBgYHtyfQpjcmltZV9zdW1tYXJ5IDwtIGNyaW1lX2RhdGEgJT4lCiAgY291bnQoWWVhcikKCmBgYAoKQ0hFQ0s6IENvdW50IHRoZSBudW1iZXIgb2Ygcm93cyBpbiB0aGUgY3JpbWVfZGF0YSBhbmQgc3VtIHRoZSBuIGNvbCBpbiBjcmltZV9zdW1tYXJ5IGFzIGEgZG91YmxlIGNoZWNrIChzaG91bGQgbWF0Y2gpCgpgYGB7cn0KI25yb3coY3JpbWVfZGF0YSkKI3N1bShjcmltZV9zdW1tYXJ5JG4pCmBgYAoKClJlbmFtZSB0aGUgbiBjb2x1bW4gdG8gIlJlcG9ydGVkIENyaW1lcyIgKHRoaXMgd2lsbCBiZSBoZWxwZnVsIGZvciBvdXIgcG9wdXBzIGluIHRoZSBEYXRhV3JhcHBlcikKYGBge3J9CmNyaW1lX3N1bW1hcnkgPC0gY3JpbWVfc3VtbWFyeSAlPiUKICByZW5hbWUoIlJlcG9ydGVkIGNyaW1lcyIgPSAibiIpCmBgYAoKCioqKioqKgoKIyMjIENyZWF0ZSBvdXIgZmlyc3QgY2hhcnQgCgpXZSB3aWxsIG1ha2UgYSBsaW5lIGNoYXJ0IHNob3dpbmcgcmVwb3J0ZWQgY3JpbWVzIHBlciB5ZWFyCgpDcmVhdGUgYSBuZXcgY2hhcnQgYW5kIGFzc2lnbiBpdCB0byB0aGUgdmFyaWFibGUgIm15X2NoYXJ0IiAodGhpcyB3YXksIHlvdSBkb24ndCBuZWVkIHRvIHdvcnJ5IGFib3V0IHRoZSBJRCkKYGBge3J9Cm15X2NoYXJ0IDwtIGR3X2NyZWF0ZV9jaGFydCgpCmBgYAoKCkFkZCBvdXIgZGF0YSB0byBjaGFydApgYGB7cn0KZHdfZGF0YV90b19jaGFydChjcmltZV9zdW1tYXJ5LCBteV9jaGFydCkKYGBgCgpZb3UgY291bGQgc3RvcCBoZXJlLiBUaGlzIGlzIGFjdHVhbGx5IHByZXR0eSB1c2VmdWwuIFdlIGhhdmUgc2VudCBvdXIgZGF0YSBmcm9tIFIgdG8gRGF0YVdyYXBwZXIgd2l0aG91dCB0aGUgbmVlZCB0byBleHBvcnQgLyBpbXBvcnQuIAoKQnV0IHdlIGNhbiB0YWtlIHRoaXMgYSBsb3QgZnVydGhlci4gTGV0J3MgdXBkYXRlIGFuZCBtYWtlIGNoYW5nZXMgdG8gb3VyIGNoYXJ0IHJpZ2h0IGZyb20gUi4KCgpVcGRhdGUgdGhlIGNoYXJ0LS0gSGVyZSB3ZSBhZGQgYSBoZWFkbGluZSBhbmQgY2hhdHRlcgpgYGB7cn0KZHdfZWRpdF9jaGFydChteV9jaGFydCwgdGl0bGUgPSAiQ3JpbWUgaW4gTWlubmVhcG9saXMgaGl0IGEgdGhyZWUteWVhciBsb3cgaW4gMjAyNCIsIAppbnRybyA9ICJSZXBvcnRlZCBjcmltZXMgaW4gdGhlIGNpdHkgYmV0d2VlbiAyMDE5IGFuZCAyMDI0IGhpdCBhIGhpZ2ggbWFyayBpbiAyMDIyIGJ1dCBoYXZlIGJlZW4gb24gdGhlIGRlY2xpbmUgc2luY2UuIiwgc291cmNlX25hbWUgPSAiT3BlbiBEYXRhIE1pbm5lYXBvbGlzIikKYGBgCgoKTmV4dCwgd2UgY2FuIHB1Ymxpc2ggb3VyIGdyYXBoaWMKYGBge3J9CmR3X3B1Ymxpc2hfY2hhcnQobXlfY2hhcnQpCmBgYAoKT3IgZXhwb3J0IGFzIGFuIGltYWdlCmBgYHtyfQpwbmdfY2hhcnQgPC0gZHdfZXhwb3J0X2NoYXJ0KG15X2NoYXJ0LCB0eXBlID0gInBuZyIpCgptYWdpY2s6OmltYWdlX3dyaXRlKHBuZ19jaGFydCwgImxpbmUtY2hhcnQucG5nIikKYGBgCgoKSXQgc2hvdWxkIGxvb2sgbGlrZSB0aGlzOgohW091ciBsaW5lIGNoYXJ0Ll0oaW1hZ2VzL2xpbmUtY2hhcnQucG5nKQoKVGhlcmUgYXJlIGEgZmV3IHRoaW5ncyBJIHdvdWxkIGNoYW5nZSBoZXJlOgoKKiBJbmNyZWFzZSB0aGUgc2NhbGUgb2YgdGhlIHktYXhpcy0gdGhlIGN1cnJlbnQgc2NhbGUgbWFrZXMgdGhlIGNoYW5nZSBiZXR3ZWVuIHllYXJzIGxvb2sgYmlnZ2VyIHRoYW4gaXQgYWN0dWFsbHkgaXMuCiogRm9ybWF0IGRhdGVzIGluIHRoZSBwb3B1cHMtIGluc3RlYWQgb2YgIjIwMTkgSmFuIDEiIGl0IHNob3VsZCBqdXN0IHNheSAiMjAxOS4iCgpXZSBjb3VsZCBtYWtlIHRoZXNlIGNoYW5nZXMgcHJldHR5IGVhc2lseSBpbiBEYXRhV3JhcHBlciwgd2hpY2ggaXMgYSBmaW5lIHdheSB0byBkbyBpdC4gT3Igd2UgY291bGQgZnVydGhlciBtb2RpZnkgb3VyIGdyYXBoaWMgZGlyZWN0bHkgZnJvbSBSLiBMZXQncyBtb3ZlIG9uIGFuZCBzZWUgaG93IHRoYXQgaXMgZG9uZS4KCgoKIyMjIENyZWF0ZSBhIGJhciBjaGFydAoKRm9yIG91ciBzZWNvbmQgY2hhcnQsIGxldCdzIHVzZSB0aGUgc2FtZSBkYXRhIHRvIG1ha2UgYSBiYXIgY2hhcnQgb2YgcmVwb3J0ZWQgY3JpbWVzIHBlciB5ZWFyIGFuZCBtYWtlIHNvbWUgZGVzaWduIG1vZGlmaWNhdGlvbnMuCgoKQ3JlYXRlIGEgY2hhcnQsIGNob29zZSB0aGUgY2hhcnQgdHlwZSBhbmQgYWRkIGEgdGl0bGUgCgoqIFdlIHdpbGwgbWFrZSBhIGJhciBjaGFydCB0aGlzIHRpbWUgdXNpbmcgdGhlIHR5cGUgImQzLWJhcnMiCiogRm9yIHZpc3VhbGl6YXRpb24gdHlwZXMsIHNlZTogaHR0cHM6Ly9kZXZlbG9wZXIuZGF0YXdyYXBwZXIuZGUvZG9jcy9jaGFydC10eXBlcwoKYGBge3J9CmJhcl9jaGFydCA8LSBkd19jcmVhdGVfY2hhcnQoCiAgdHlwZT0iZDMtYmFycyIsCiAgdGl0bGU9Ik1pbm5lYXBvbGlzIHJlcG9ydGVkIGNyaW1lLCAyMDE5LTIwMjQiCikKYGBgCgpBZGQgb3VyIGRhdGEKYGBge3J9CmR3X2RhdGFfdG9fY2hhcnQoY3JpbWVfc3VtbWFyeSwgYmFyX2NoYXJ0KQpgYGAKCgpVcGRhdGUgd2l0aCBhIG5ldyBoZWFkbGluZSwgY2hhdHRlciBhbmQgc291cmNlCmBgYHtyfQpkd19lZGl0X2NoYXJ0KGJhcl9jaGFydCwgdGl0bGUgPSAiQ3JpbWUgaW4gTWlubmVhcG9saXMgaGl0IGEgdGhyZWUteWVhciBsb3cgaW4gMjAyNCIsIAppbnRybyA9ICJSZXBvcnRlZCBjcmltZXMgaW4gdGhlIGNpdHkgYmV0d2VlbiAyMDE5IGFuZCAyMDI0IGhpdCBhIGhpZ2ggbWFyayBpbiAyMDIyIGJ1dCBoYXZlIGJlZW4gb24gdGhlIGRlY2xpbmUgc2luY2UuIiwgc291cmNlX25hbWUgPSAiT3BlbiBEYXRhIE1pbm5lYXBvbGlzIikKYGBgCgoKTm93LCBsZXQncyB0YWtlIGEgbG9vayBhdCBvdXIgY2hhcnQncyBtZXRhZGF0YS0tIHRoaXMgaXMgZ29vZCBrZXkgdG8gd2hhdCBjYW4gYmUgY2hhbmdlZC4KCmBgYHtyfQpkd19yZXRyaWV2ZV9jaGFydF9tZXRhZGF0YShiYXJfY2hhcnQpCmBgYAoKSXQgY2FuIHRha2UgYSBsaXR0bGUgd29yayB0byBmaWd1cmUgb3V0IHdoYXQgbWV0YWRhdGEgdmFsdWVzIHRvIGNoYW5nZS4gU29tZXRpbWVzIHRoZSBkb2N1bWVudGF0aW9uIHdpbGwgaGVscC4gCgpNb2RpZnkgc29tZSBvZiB0aGUgYXR0cmlidXRlcyBvZiB0aGUgZ3JhcGhpYzoKCiogQWRkIGEgYnlsaW5lCiogQ2hhbmdlIHRoZSBiYXIgY29sb3IKKiBNYWtlIHRoZSBiYXJzIHRoaWNrCiogQWxpZ24gdGhlIGxhYmVscyB0byB0aGUgcmlnaHQKCmBgYHtyfQpkd19lZGl0X2NoYXJ0KGJhcl9jaGFydCwgCiAgICAgICAgICAgICAgYnlsaW5lID0gIkFkYW0gTWFydG9uIiwKICAgICAgICAgICAgICB2aXN1YWxpemUgPSBsaXN0KAogICAgICAgICAgICAgICAgImJhc2UtY29sb3IiID0gIiNhNDc3NjQiLAogICAgICAgICAgICAgICAgInRoaWNrIiA9ICJ0cnVlIiwKICAgICAgICAgICAgICAgICJ2YWx1ZS1sYWJlbC1hbGlnbm1lbnQiID0gInJpZ2h0IgogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICkKYGBgCgoKUHVibGlzaCBvdXIgbmV3IGdyYXBoaWMKYGBge3J9CmR3X3B1Ymxpc2hfY2hhcnQoYmFyX2NoYXJ0KQpgYGAKCkl0IHNob3VsZCBsb29rIGxpa2UgdGhpczoKIVtPdXIgYmFyIGNoYXJ0Ll0oaW1hZ2VzL2Jhci1jaGFydC5wbmcpCgoKCiMjIyBUZW1wbGF0aW5nCgpMZXQncyBkdXBsaWNhdGUgdGhhdCBjaGFydCBhZGQgbmV3IGRhdGEuIFlvdSBjYW4gdXNlIHRoaXMgbWV0aG9kIHRvIGNyZWF0ZSB5b3VyIG93biB0ZW1wbGF0ZXMuICAKCkZvciBvdXIgbmV4dCBncmFwaGljLCBsZXQncyBsb29rIGF0IHRoZSBPZmZlbnNlIENhdGVnb3J5IGNvbHVtbi4gV2Ugd2lsbCB2aXN1YWxpemUgd2hhdCB0aGUgdG9wIDEwIGNhdGVnb3JpZXMgd2VyZSBpbiAyMDI0LgoKKioqKgoKIyMjIyBGaXJzdCwgc29tZSBxdWljayBkYXRhIHdvcmsKCkxldHMgbWFrZSBhIG5ldyBkYXRhZnJhbWUgY2FsbGVkICJjcmltZXNfMjAyNCIgYW5kIGZpbHRlciB0aGUgY3JpbWUgZGF0YSBmb3IganVzdCAyMDI0CmBgYHtyfQpjcmltZXNfMjAyNCA8LSBjcmltZV9kYXRhICU+JSAKICBmaWx0ZXIoWWVhciA9PSAyMDI0KQpgYGAKCgpOZXh0LCB3ZSBjb3VudCB0aGUgbnVtYmVyIG9mIGNyaW1lcyBpbiBlYWNoICJvZmZlbnNlIGNhdGVnb3J5IiBpbiAyMDI0IHVzaW5nIGR5cGxyCmBgYHtyfQpjcmltZV9vZmZlbnNlX3N1bW1hcnkgPC0gY3JpbWVzXzIwMjQgJT4lCiAgY291bnQoT2ZmZW5zZV9DYXRlZ29yeSkKYGBgCgoKVGhlbiB3ZSBzb3J0IHRoZSBjb2x1bW4gbnVtYmVyIChuKSBjb2x1bW4gYnkgZGVzY2VuZGluZyBhbmQgcmVkdWNlIHRvIGp1c3QgdGhlIHRvcCAxMCB1c2luZyBzbGljZQpgYGB7cn0KY3JpbWVfb2ZmZW5zZV9zdW1tYXJ5IDwtIGNyaW1lX29mZmVuc2Vfc3VtbWFyeSAlPiUKICAgIGFycmFuZ2UoZGVzYyhuKSkgJT4lCiAgICBzbGljZSgxOjEwKSAKYGBgCgpUaGlzIHRoZSBkYXRhIHdlIHdpbGwgdXNlIGZvciBvdXIgbmV3IChkdXBsaWNhdGUpIGNoYXJ0CgoqKioqCgojIyMjIER1cGxpY2F0ZSB0aGUgYmFyIGNoYXJ0IHdlIG1hZGUgYWJvdmUgYW5kIGFkZCBpbiBvdXIgbmV3IGRhdGEKCgpEdXBsaWNhdGUgdGhlIGJhciBjaGFydAoKKipXZSBuZWVkIHRoZSBjaGFydCBpZCBmb3IgdGhpcy4gV2UgY2FuIGdldCBpdCBhYm92ZSBmcm9tIHdoZW4gd2UgZmlyc3QgbWFkZSB0aGUgYmFyIGNoYXJ0IG9yIGZyb20gdGhlIGNoYXJ0IFVSTApgYGB7cn0Kb2ZmZW5zZV9jaGFydCA8LSBkd19jb3B5X2NoYXJ0KGNvcHlfZnJvbSA9ICJJTlNFUlQgQ0hBUlQgSUQgRlJPTSBCQVIgQ0hBUlQgQUJPVkUiKQpgYGAKClVwZGF0ZSB0aGUgZHVwbGljYXRlZCBjaGFydCB3aXRoIHRoZSBuZXcgZGF0YQpgYGB7cn0KZHdfZGF0YV90b19jaGFydChjcmltZV9vZmZlbnNlX3N1bW1hcnksIG9mZmVuc2VfY2hhcnQpCgpgYGAKClVwZGF0ZSB0ZXh0CmBgYHtyfQpkd19lZGl0X2NoYXJ0KG9mZmVuc2VfY2hhcnQsIHRpdGxlID0gIlRvcCAxMCBoaWdoZXN0IGNhdGVnb3JpZXMgb2YgY3JpbWUgb2ZmZW5zZXMgaW4gTWlubmVhcG9saXMgaW4gMjAyNCIsIAppbnRybyA9ICJBbG1vc3QgMTMsMDAwIGxhcmNlbnkgYW5kIHRoZWZ0IG9mZmVuc2VzIGFuZCBvdmVyIDgsMDAwIGFzc2F1bHQgb2ZmZW5zZXMgd2VyZSByZXBvcnRlZC4iLCBzb3VyY2VfbmFtZSA9ICJPcGVuIERhdGEgTWlubmVhcG9saXMiKQpgYGAKCgpMZXQncyB0YWtlIGEgbG9vayBhdCB0aGUgY2hhcnQgbm93IGFuZCBkZWNpZGUgd2hhdCB3ZSBuZWVkIHRvIGNoYW5nZS4gWW91IGNhbiBvcGVuIGl0IGluIERhdGFXcmFwcGVyIG9yIHB1Ymxpc2ggYW5kIGxvb2sgaW4gdGhlIGJyb3dzZXIuCgpQdWJsaXNoCmBgYHtyfQpkd19wdWJsaXNoX2NoYXJ0KG9mZmVuc2VfY2hhcnQpCmBgYAoKTmV4dCwgbG9vayBhdCB0aGUgbWV0YWRhdGEKYGBge3J9CmR3X3JldHJpZXZlX2NoYXJ0X21ldGFkYXRhKG9mZmVuc2VfY2hhcnQpCgpgYGAKCk1vZGlmeSBzb21lIG9mIHRoZSBhdHRyaWJ1dGVzIG9mIHRoZSBncmFwaGljOgoKKiBjaGFuZ2UgdGhlIGJhciBjb2xvcgoqIHNvcnQgdGhlIGJhcnMgYnkgdmFsdWUKKiBBZGQgbGluZXMgYmV0d2VlbiB0aGUgYmFycwoqIEFkZCBhIGJhY2tncm91bmQgYmVoaW5kIHRoZSBiYXJzCiogUHV0IHRoZSBsYWJlbHMgYW5kIGJhcnMgb2Ygc2VwYXJhdGUgbGluZXMgKCJibG9jayBsYWJlbHMiPykKKiBhbGlnbiB0aGUgbGFiZWxzIHRvIHRoZSByaWdodAoKYGBge3J9CmR3X2VkaXRfY2hhcnQob2ZmZW5zZV9jaGFydCwgCiAgICAgICAgICAgICAgdmlzdWFsaXplID0gbGlzdCgKICAgICAgICAgICAgICAgICJiYXNlLWNvbG9yIiA9ICIjOEFDRTAwIiwKICAgICAgICAgICAgICAgICJzb3J0LWJhcnMiID0gInRydWUiLAogICAgICAgICAgICAgICAgInJ1bGVzIiA9ICJ0cnVlIiwKICAgICAgICAgICAgICAgICJiYWNrZ3JvdW5kIiA9ICJ0cnVlIiwKICAgICAgICAgICAgICAgICJibG9jay1sYWJlbHMiID0gInRydWUiLAogICAgICAgICAgICAgICAgInZhbHVlLWxhYmVsLWFsaWdubWVudCIgPSAicmlnaHQiCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgKQpgYGAKClJlcHVibGlzaApgYGB7cn0KZHdfcHVibGlzaF9jaGFydChvZmZlbnNlX2NoYXJ0KQpgYGAKCgpJdCBzaG91bGQgbG9vayBzb21ldGhpbmcgbGlrZSB0aGlzOgohW091ciBiYXIgY2hhcnQuXShpbWFnZXMvb2ZmZW5zZV9jaGFydC5wbmcpCgpIb3cgbWlnaHQgc29tZXRoaW5nIGxpa2UgdGhpcyBiZSB1c2VmdWw/CkhvdyBjb3VsZCB5b3UgdXNlIGl0IHRvIHNhdmUgdGltZSBkdXJpbmcgcHJvZHVjdGlvbiB0YXNrcz8KCgoqKioKCiMjIyBPbiB5b3VyIG93bjogRXhlcmNpc2UgMQpUYWtlIHdoYXQgd2UgbGVhcm5lZCBhYm92ZSBhbmQgY3JlYXRlIGEgY2hhcnQgdGhhdCBzaG93cyB0aGUgbmVpZ2hib3Job29kcyB3aXRoIHRoZSBoaWdoZXN0IHJlcG9ydGVkIGNyaW1lcyBpbiAyMDI0LiBVc2Ugd2hhdGV2ZXIgY2hhcnQgdHlwZSB5b3UgbGlrZS4gU3R5bGUgaXQgaG93ZXZlciB5b3UgbGlrZS4gWW91IGNhbiBkdXBsaWNhdGUgb25lIG9mIG91ciBwcmV2aW91cyBjaGFydHMgb3IgbWFrZSB5b3VyIG93bi4gQmUgc3VyZSB0byBpbmNsdWRlIGEgaGVhZGxpbmUsIGNoYXR0ZXIgYW5kIHNvdXJjZS4gCgpJJ3ZlIGRvbmUgdGhlIGRhdGEgd29yayBmb3IgeW91IGJlbG93OgoKQ291bnQgdGhlIG51bWJlciBvZiBjcmltZXMgaW4gZWFjaCAibmVpZ2hib3Job29kIiBpbiAyMDI0IHVzaW5nIGR5cGxyCmBgYHtyfQpjcmltZV9uZWlnaGJvcmhvb2Rfc3VtbWFyeSA8LSBjcmltZXNfMjAyNCAlPiUKICBjb3VudChOZWlnaGJvcmhvb2QpCmBgYAoKClRoZW4gd2Ugc29ydCB0aGUgY29sdW1uIG51bWJlciAobikgY29sdW1uIGJ5IGRlc2NlbmRpbmcgYW5kIHJlZHVjZSB0byBqdXN0IHRoZSB0b3AgMTAgdXNpbmcgc2xpY2UKYGBge3J9CmNyaW1lX25laWdoYm9yaG9vZF9zdW1tYXJ5IDwtIGNyaW1lX25laWdoYm9yaG9vZF9zdW1tYXJ5ICU+JQogICAgYXJyYW5nZShkZXNjKG4pKSAlPiUKICAgIHNsaWNlKDE6MTApIApgYGAKCk5vdyB5b3UgaGF2ZSBhIGRhdGFmcmFtZSBjYWxsZWQgImNyaW1lX25laWdoYm9yaG9vZF9zdW1tYXJ5IiB3aXRoIHRoZSB0b3AgdGVuIG5laWdoYm9yaG9vZHMgd2hlcmUgY3JpbWVzIHdlcmUgcmVwb3J0ZWQgaW4gMjAyNC4gVXNlIHRoYXQgdG8gbWFrZSB5b3VyIGNoYXJ0LgoKCgoKCgoKKioqCgoKIyMjIEZ1bmN0aW9ucwoKTGV0J3MgbWFrZSBhIGZ1bmN0aW9uIHRoYXQgd2lsbCBhdXRvbWF0aWNhbGx5IGdlbmVyYXRlIGEgY2hhcnQuCgpIZXJlIGlzIGEgc2ltcGxlIGZ1bmN0aW9uIHRoYXQgY3JlYXRlcyBhIGNoYXJ0IGxvb2tpbmcgYXQgcmVwb3J0ZWQgY3JpbWVzIGJ5IHllYXIgaW4gcHJlY2luY3QgMS4gUmVhZCB0aHJvdWdoIHRoZSBjb21tZW50cyBpbiB0aGUgZnVuY3Rpb24gdG8gc2VlIGhvdyBpdCB3b3Jrcy4KYGBge3J9CgoKbXlfZnVuY3Rpb24gPC0gZnVuY3Rpb24oKSB7CiAgCiAgI21ha2UgYSBuZXcgZGF0YSBmcmFtZSB0aGF0IGhvbGRzIGRhdGEganVzdCBmb3IgcHJlY2luY3QgMQogIHByZWNpbmN0X2RhdGEgPC0gY3JpbWVfZGF0YSAlPiUgZmlsdGVyKFByZWNpbmN0PT0gMSkKCiAgI2NvdW50IG51bWJlciBvZiBhcnJlc3RzIHBlciB5ZWFyIGluIHRoYXQgcHJlY2luY3QKICBwcmVjaW5jdF9zdW1tYXJ5IDwtIHByZWNpbmN0X2RhdGEgJT4lY291bnQoWWVhcikKICAKICAjY3JlYXRlIG5ldyBjaGFydAogIG15X2NoYXJ0IDwtIGR3X2NyZWF0ZV9jaGFydCgKICB0eXBlPSJkMy1iYXJzIiwKICApCgogICNhZGQgZGF0YQogIGR3X2RhdGFfdG9fY2hhcnQocHJlY2luY3Rfc3VtbWFyeSwgbXlfY2hhcnQpCgogICNlZGl0IGNoYXJ0CiAgZHdfZWRpdF9jaGFydChteV9jaGFydCwgdGl0bGUgPSBwYXN0ZSgiUmVwb3J0ZWQgY3JpbWVzIGJ5IHllYXIgaW4gTWlubmVhcG9saXMgUHJlY2luY3QgMSIpLCBzb3VyY2VfbmFtZSA9ICJPcGVuIERhdGEgTWlubmVhcG9saXMiKQogIAogICNwdWJsaXNoCiAgZHdfcHVibGlzaF9jaGFydChteV9jaGFydCkKfQoKI0NhbGwgdGhlIGZ1bmN0aW9uIHRvIHJ1biBpdApteV9mdW5jdGlvbigpCgpgYGAKClRoZSBvdXRwdXR0ZWQgZ3JhcGhpYyBzaG91bGQgbG9vayBzb21ldGhpbmcgbGlrZSB0aGlzOgohW1ByZWNpbmN0IENoYXJ0Ll0oaW1hZ2VzL3ByZWNpbmN0LTEucG5nKQoKV2UgY2FuIG1ha2UgdGhpcyBtdWNoIG1vcmUgdXNlZnVsIHdpdGggb25lIGNoYW5nZSAtLSBtYWtpbmcgdGhlIHNwZWNpZmljIHByZWNpbmN0IGEgcGFyYW1ldGVyIGluIHRoZSBmdW5jdGlvbi4KQ2hhbmdlcyBhcmUgaW5kaWN0ZWQgaW4gdGhlIGNvbW1lbnRzIGJlbG93CgpgYGB7cn0KCiNhZGQgYSBwYXJhbWV0ZXIgY2FsbGVkIHByZWNpbmN0Cm15X2Z1bmN0aW9uIDwtIGZ1bmN0aW9uKHByZWNpbmN0KSB7CiAgCiAgI2luc3RlYWQgb2YgbmFtaW5nIHRoZSBwcmVjaW5jdCBoZXJlLCB1c2UgdGhlIHBhcmFtZXRlcgogIHByZWNpbmN0X2RhdGEgPC0gY3JpbWVfZGF0YSAlPiUgZmlsdGVyKFByZWNpbmN0ID09IHByZWNpbmN0KQoKICBwcmVjaW5jdF9zdW1tYXJ5IDwtIHByZWNpbmN0X2RhdGEgJT4lY291bnQoWWVhcikKICAKICBteV9jaGFydCA8LSBkd19jcmVhdGVfY2hhcnQoCiAgdHlwZT0iZDMtYmFycyIsCiAgKQoKICBkd19kYXRhX3RvX2NoYXJ0KHByZWNpbmN0X3N1bW1hcnksIG15X2NoYXJ0KQoKICAjQWdhaW4sIHVzZSB0aGUgcGFyYW1ldGVyIGluc3RlYWQgb2YgbmFtaW5nIHRoZSBzcGVjaWZpYyBwcmVjaW5jdCBpbiB0aGUgaGVhZGxpbmUKICBkd19lZGl0X2NoYXJ0KG15X2NoYXJ0LCB0aXRsZSA9IHBhc3RlKCJSZXBvcnRlZCBjcmltZXMgYnkgeWVhciBpbiBNaW5uZWFwb2xpcyBQcmVjaW5jdCIsIHByZWNpbmN0KSwgc291cmNlX25hbWUgPSAiT3BlbiBEYXRhIE1pbm5lYXBvbGlzIikKICAKICBkd19wdWJsaXNoX2NoYXJ0KG15X2NoYXJ0KQp9CgojQ2FsbCB0aGUgZnVuY3Rpb24gYW5kIHBhc3MgYW4gYXJndW1lbnQgLS0gIjIiLS0gdG8gdGhlIHBhcmFtZXRlcgojVGhpcyBwYXNzZXMgdGhlIDIgZXZlcnl3aGVyZSB3ZSBoYXZlIHRoZSBwYXJhbWV0ZXIgaW4gdGhlIGZ1bmN0aW9uLCBzbyBvdXIgZ3JhcGhpYyB3aWxsIGRpc3BsYXkgY3JpbWVzIGluIHByZWNpbmN0IDIKbXlfZnVuY3Rpb24oIjIiKQpgYGAKCk5vdyB3ZSBjYW4gdXNlIHRoaXMgZnVuY3Rpb24gdG8gY3JlYXRlIGEgZ3JhcGhpYyBmb3IgYW55IHByZWNpbmN0IGp1c3QgYnkgY2hhbmdpbmcgdGhlIGFyZ3VtZW50IHRvIGEgZGlmZmVyZW50IHByZWNpbmN0IG51bWJlciB3aGVuIHdlIGNhbGwgdGhlIGZ1bmN0aW9uLgoKKioqKgoKIyMjIyBBZGQgYSBsb29wCgpXZSBjYW4gd3JhcCBvdXIgZnVuY3Rpb24gaW4gYSBsb29wIC0tIGFsc28gY2FsbGVkIGEgImZvciBzdGF0ZW1lbnQiIC0tIHRvIHF1aWNrbHkgY3JlYXRlIGEgZ3JhcGhpYyBmb3IgYWxsIHByZWNpbmN0cyEKCmBgYHtyfQpmb3IocHJlY2luY3QgaW4gdW5pcXVlKGNyaW1lX2RhdGEkUHJlY2luY3QpKSB7CiAgbXlfZnVuY3Rpb24ocHJlY2luY3QpCn0KCmBgYApUaGlzIHNheXM6IGZvciBlYWNoIHVuaXF1ZSB2YWx1ZSBpbiB0aGUgUHJlY2luY3QgY29sdW1uIG9mIG91ciBkYXRhLCBleGVjdXRlIG15X2Z1bmN0aW9uIGFuZCBwdXQgdGhlIHVuaXF1ZSBwcmVjaW5jdCBuYW1lIGFzIHRoZSBmdW5jdGlvbidzIGFyZ3VtZW50LgoKClRoaXMgc2hvdWxkIG91dHB1dCA1IGdyYXBoaWNzLCBvbmUgZm9yIGVhY2ggUHJlY2luY3QuIEVhY2ggb2YgdGhlIGdyYXBoaWNzIHNob3VsZCBsb29rIHNvbWV0aGluZyBsaWtlIHRoaXM6CiFbUHJlY2luY3QgQ2hhcnQuXShpbWFnZXMvcHJlY2luY3QtMS5wbmcpCgpXZSBjb3VsZCB1c2UgdGhpcyB0byBjcmVhdGUgZG96ZW5zIG9yIGV2ZW4gaHVuZHJlZHMgb2YgY2hhcnRzIGF0IGF0IHRpbWUuCgoKCioqKioKCiMjIyBNYWtlIGEgc3ltYm9sIG1hcAoKCiMjIyMgT3VyIERhdGEKCkluIHRoaXMgZXhhbXBsZSwgd2Ugd2lsbCBwdWxsIGNyaW1lcyBmcm9tIHRoZSBsYXN0IHNldmVuIGRheXMuCgpXZSB3aWxsIG5lZWQgdG8gZmFrZSBpdCBhIGxpdHRsZSBiaXQgc2luY2Ugd2Ugb25seSBoYXZlIGRhdGEgdGhyb3VnaCB0aGUgZW5kIG9mIDIwMjQuIEZvbGxvdyB0aGUgY29tbWVudHMgYmVsb3cgdG8gc2VlIGhvdyB0aGlzIHdvcmtzLgoKYGBge3J9CiNGaXJzdCB3ZSBzZXQgdG9kYXkncyBkYXRlCiAgIyBsZXQncyBmYWtlIHRoZSBjdXJyZW50IGRhdGUgdG8gbWFrZSB0aGlzIGV4YW1wbGUgaW1tb3J0YWw6Cm5vdyA9IGFzLkRhdGUoIjEyLzMxLzIwMjQiLCBmb3JtYXQgPSAiJW0vJWQvJVkiKQogICMgaG93ZXZlciwgaW4gInJlYWwgbGlmZSIgeW91IHNob3VsZCByZXBsYWNlIGl0IHdpdGggdGhpcyBmb3IgdGhlIGN1cnJlbnQgZGF0ZToKICAjIG5vdyA9IFN5cy5EYXRlKCkKCiNOZXh0LCBsZXQncyBtYWtlIGEgbmV3IGRhdGFmcmFtZSB0aGF0IG9ubHkgc2hvd3MgY3JpbWVzIHNldmVuIGRheXMgYmVmb3JlICJub3ciCmNyaW1lc19sYXN0XzcgPC0gc3Vic2V0KGNyaW1lc18yMDI0LCBjcmltZXNfMjAyNCRSZXBvcnRlZF9EYXRlID4gbm93LTcpCgpgYGAKCiMjIyMgTWFrZSB0aGUgbWFwCgpDcmVhdGUgYSBuZXcgc3ltYm9sIG1hcC4KYGBge3J9Cm5ld19zeW1ib2xfY2hhcnQgPC0gZHdfY3JlYXRlX2NoYXJ0KAogIHRpdGxlID0gIkNyaW1lcyBpbiBNaW5uZWFwb2xpcyBpbiB0aGUgbGFzdCBzZXZlbiBkYXlzIiwgCiAgdHlwZSA9ICJkMy1tYXBzLXN5bWJvbHMiCiAgKQoKYGBgCgpXZSBuZWVkIHRvIGRlY2lkZSB3aGljaCBiYXNlIG1hcCB0byB1c2UuIEl0IGlzIGlkZW50aWZpZWQgYnkgdGhlIGlkLWNvbHVtbi4KCllvdSBjYW4gdXNlIGRwbHly4oCZcyBWaWV3KCkgdG8gZ2V0IGFuIGludGVyYWN0aXZlIHRhYmxlIG9mIGF2YWlsYWJsZSBtYXBzIGFuZCBzZWFyY2ggZm9yIHdoYXQgeW91IGFyZSBsb29raW5nIGZvci4gCmBgYHtyfQp2aWV3KGR3X2Jhc2VtYXBzKQpgYGAKV2Ugd2lsbCB1c2UgYSBiYXNlbWFwIG9mIE1pbm5lYXBvbGlzIG5laWdoYm9yaG9vZHMsIHdoaWNoIGhhcyB0aGUgaWQgIm1pbm5lYXBvbGlzLW5laWdoYm9yaG9vZHMiCgoKQ29ubmVjdCBvdXIgZGF0YSB0byB0aGUgY2hhcnQKYGBge3J9CmR3X2RhdGFfdG9fY2hhcnQoY3JpbWVzX2xhc3RfNywgY2hhcnRfaWQgPSBuZXdfc3ltYm9sX2NoYXJ0KQpgYGAKCkVkaXQgdGhlIGNoYXJ0LiAKCiogV2UgbmVlZCB0byBpbmNsdWRlIHRoZSBsYXRpdHVkZSBhbmQgbG9uZ2l0dWRlICh3aGljaCwgbHVja2lseSwgd2UgaGF2ZSBpbiBvdXIgZGF0YSBhbHJlYWR5IHNvIHRoZXJlIGlzIG5vIGdlb2NvZGluZyBuZWVkZWQpCiogV2UgYWxzbyBpbmNsdWRlICJ2YWx1ZXMiIHdoaWNoIHdpbGwgY29sb3Igb3VyIHN5bWJvbHMgYmFzZWQgb24gYSBjb2x1bW4KKiBGaW5hbGx5LCB3ZSBpZGVudGlmeSB0aGUgYmFzZW1hcC4KYGBge3J9CmR3X2VkaXRfY2hhcnQobmV3X3N5bWJvbF9jaGFydCwgCiAgICAgICAgICAgICAgYXhlcyA9IGxpc3QoCiAgICAgICAgICAgICAgICBsYXQgPSAiTGF0aXR1ZGUiLCAKICAgICAgICAgICAgICAgIGxvbiA9ICJMb25naXR1ZGUiLAogICAgICAgICAgICAgICAgdmFsdWVzID0gIk9mZmVuc2VfQ2F0ZWdvcnkiCiAgICAgICAgICAgICAgICApLCAKICAgICAgICAgICAgICB2aXN1YWxpemUgPSBsaXN0KAogICAgICAgICAgICAgICAgYmFzZW1hcCA9ICJtaW5uZWFwb2xpcy1uZWlnaGJvcmhvb2RzIgogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICkKYGBgCgoKQWRkIC8gRWRpdCB0b29sdGlwcwoKKiBUaXRsZSBzaG93cyBhYm92ZSB0aGUgdG9vbHRpcCBhbmQgYm9keSBpcyB0aGUgbWFpbiB0ZXh0CiogUmVmZXIgdG8geW91ciBkYXRhIGNvbHVtbnMgaW4gZG91YmxlIGJyYWNrZXRzIHt7IH19CiogWW91IGhhdmUgdG8gZGVmaW5lIHlvdXIgdmFyaWFibGVzIGluIHRoZSBmaWVsZHMgbGlzdC4gSXQgaXMgYmVzdCBqdXN0IHRvIG5hbWUgdGhlIHZhcmlhYmxlcyBhZnRlciB0aGUgY29sdW1ucy4KCmBgYHtyfQpkd19lZGl0X2NoYXJ0KG5ld19zeW1ib2xfY2hhcnQsIHZpc3VhbGl6ZSA9IGxpc3QoCiAgdG9vbHRpcCA9IGxpc3QoCiAgICBib2R5ID0gIlJlcG9ydGVkIERhdGU6IHt7IHJlcG9ydGVkX2RhdGUgfX08YnI+IEFkZHJlc3M6IHt7IGFkZHJlc3MgfX0iLAogICAgdGl0bGUgPSAie3sgb2ZmZW5zZSB9fSIsCiAgICBmaWVsZHMgPSBsaXN0KAogICAgICAicmVwb3J0ZWRfZGF0ZSIgPSAicmVwb3J0ZWRfZGF0ZSIsCiAgICAgICJvZmZlbnNlIiA9ICJvZmZlbnNlIiwKICAgICAgImFkZHJlc3MiID0gImFkZHJlc3MiCiAgICApLAogICAgZW5hYmxlZCA9ICJUUlVFIgogICAgKSkpCmBgYApJdCBpcyBlYXNpZXN0IHRvIG9wZW4gdXAgZGF0YXdyYXBwZXIgYXQgdGhpcyBwb2ludCB0byBlZGl0IC8gdHdlYWsgdGhlIGxlZ2VuZC4gWW91IGNvdWxkIGFsc28gZG8gaXQgdmlhIHRoZSBtZXRhZGF0YSBpZiB5b3UgbGlrZS4KClB1Ymxpc2gKYGBge3J9CmR3X3B1Ymxpc2hfY2hhcnQobmV3X3N5bWJvbF9jaGFydCkKYGBgCgpUaGUgcHVibGlzaGVkIG1hcCBzaG91bGQgbG9vayBzb21ldGhpbmcgbGlrZSB0aGlzOgohW091ciBtYXBdKGltYWdlcy9tYXAucG5nKQoKCioqKioKCiMjIyBPbiB5b3VyIG93bgpDcmVhdGUgeW91ciBvd24gbWFwLiBMb29rIGF0IHRoZSBkYXRhIGFuZCB0aGluayBhYm91dCB3aGF0IG1pZ2h0IGJlIGludGVyZXN0aW5nIHRvIHZpc3VhbGl6ZSBvbiBhIG1hcC4gUHJlcGFyZSB5b3VyIGRhdGEgYW5kIHRoZW4gZm9sbG93IHRoZSB3b3JrZmxvdyBhYm92ZSB0byBjcmVhdGUgeW91ciBvd24gc3ltYm9sIC8gZG90IG1hcC4gUmVmZXIgdG8gdGhlIGRvY3VtZW50YXRpb24gYXMgbmVlZGVkIChzZWUgdGhlIHRvcCBvZiB0aGlzIGRvYyBmb3IgbGlua3MpLiBIZXJlIGFyZSBhIGZldyBpZGVhczoKCjEuIE1hcCBhbGwgb2YgdGhlIGFzc2F1bHRzIHRoYXQgb2NjdXJyZWQgaW4gTm92ZW1iZXIgMjAyNAoyLiBNYXAgYWxsIG9mIHRoZSBjcmltZXMgdGhhdCBvY2N1cnJlZCBpbiB0aGUgUG93ZGVyaG9ybiBQYXJrIG5laWdoYm9yaG9vZCBpbiB0aGUgc3VtbWVyIG9mIDIwMjQKMy4gTWFwIGFsbCBvZiB0aGUgY2FyamFja2luZ3MgaW4gV2FyZCA4IGluIDIwMjQKCgoqKioqCgojIyMgTmV4dCBzdGVwcwoKVGhlcmUgaXMgYSBsb3QgbW9yZSB5b3UgY2FuIGRvIHdpdGggdGhlIERhdGFXcmFwcGVyIEFQSS4gQSBmZXcgZXhhbXBsZXM6CgoxLiBXZWIgc2NyYXBpbmc6IElmIHlvdSBuZWVkIHRvIGdyYWIgbGl2ZSBvciB1cGRhdGluZyBkYXRhIGZyb20gYSByZW1vdGUgc291cmNlLCB5b3UgY291bGQgYWRkIHNjcmFwaW5nIGludG8gdGhpcyB3b3JrZmxvdy4gVXNlIHRoZSBydmVzdCBwYWNrYWdlIChodHRwczovL3J2ZXN0LnRpZHl2ZXJzZS5vcmcvKSB0byBlYXNpbHkgc2NyYXBlIGRhdGEgaW4gUiB0aGVuIGZvbGxvdyB0aGUgc3RlcHMgd2Ugb3V0bGluZWQgYWJvdmUKCjIuIEludGVncmF0aW9ucyAtIGEgbW9yZSBjb21wbGV4IHVzZSBvZiB0aGUgQVBJIGlzIGludGVncmF0aW9uczogdXNpbmcgdGhlIEFQSSBpbiBleGlzdGluZyBhcHBsaWNhdGlvbiB3b3JrZmxvd3MuIFNlZSB0aGUgZG9jdW1lbnRhdGlvbiBoZXJlOiBodHRwczovL2RldmVsb3Blci5kYXRhd3JhcHBlci5kZS9kb2NzL2dldHRpbmctc3RhcnRlZC13aXRoLWludGVncmF0aW9ucy4gCgozLiBVcmJhbiBJbnN0aXR1dGUgaGFzIGEgZ3JlYXQgYmxvZyBwb3N0IGFib3V0IGhvdyB0aGV5IHVzZWQgdGhlIEFQSSBpbiBTdmVsdGUgdG8gY3JlYXRlIGEgY3VzdG9taXplZCBtYXAsIGhlcmU6IGh0dHBzOi8vbWVkaXVtLmNvbS91cmJhbi1pbnN0aXR1dGUvdXNpbmctZGF0YXdyYXBwZXItdG8tbWFrZS1jdXN0b20tZGF0YS12aXN1YWxpemF0aW9uLW1vcmUtZWZmaWNpZW50LTRhY2VkOTM4NzNhNiAKCgo=