From Code to Charts- Use the DataWrapper API to create graphics in R

Adam Marton · February 17, 2025


Reference

DataWrapper API documentation: https://developer.datawrapper.de/docs/getting-started

DatawRappr package documentation: https://munichrocker.github.io/DatawRappr/index.html


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: API screen.

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)

Call in data and display head

We are working with Minneapolis crime data from 2019 through early 2025.

The data can be downloaded here: https://raw.githubusercontent.com/amarton/nicar-2025/refs/heads/main/datawrapper-r/mn-crime-data.csv

If you are on a training computer at NICAR, it should already be available in the course folder.


crime_data <- read.csv("mn-crime-data.csv")
head(crime_data)

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: Our line chart.

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: Our bar chart.

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: Our bar chart.

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: Precinct Chart.

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: Precinct Chart.

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: Our map


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:

  1. Map all of the assaults that occurred in November 2024
  2. Map all of the crimes that occurred in the Powderhorn Park neighborhood in the summer of 2024
  3. Map all of the carjackings in Ward 8 in 2024

Next steps

There is a lot more you can do with the DataWrapper API. A few examples:

  1. Web scraping: If you need to grab live or updating data from a remote source, you could add scraping into this workflow. Use the rvest package (https://rvest.tidyverse.org/) to easily scrape data in R then follow the steps we outlined above

  2. Integrations - a more complex use of the API is integrations: using the API in existing application workflows. See the documentation here: https://developer.datawrapper.de/docs/getting-started-with-integrations.

  3. Urban Institute has a great blog post about how they used the API in Svelte to create a customized map, here: https://medium.com/urban-institute/using-datawrapper-to-make-custom-data-visualization-more-efficient-4aced93873a6

LS0tCnRpdGxlOiAnRnJvbSBDb2RlIHRvIENoYXJ0czogQ3JlYXRlIERhdGFXcmFwcGVyIEdyYXBoaWNzIFN0cmFpZ2h0IGZyb20gUicKYXV0aG9yOiAiQWRhbSBNYXJ0b24iCnN1YnRpdGxlOiBOSUNBUiAyMDI1Cm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCioqKioqKgoKIyMjIFJlZmVyZW5jZQoKRGF0YVdyYXBwZXIgQVBJIGRvY3VtZW50YXRpb246Cmh0dHBzOi8vZGV2ZWxvcGVyLmRhdGF3cmFwcGVyLmRlL2RvY3MvZ2V0dGluZy1zdGFydGVkIAoKRGF0YXdSYXBwciBwYWNrYWdlIGRvY3VtZW50YXRpb246Cmh0dHBzOi8vbXVuaWNocm9ja2VyLmdpdGh1Yi5pby9EYXRhd1JhcHByL2luZGV4Lmh0bWwKCgoqKioqKioKCiMjIyBBc3N1bXB0aW9ucwoKVGhpcyB0dXRvcmlhbCBhc3N1bWVzIHlvdSBoYXZlIHNvbWUgcHJldmlvdXMgZXhwZXJpZW5jZSB3aXRoIGJvdGggUiBhbmQgRGF0YVdyYXBwZXIKCioqKioqKgoKCiMjIyBTZXQgdXAKCkluc3RhbGwgdGhlIG5lZWRlZCBwYWNrYWdlcwoKKiBJZiB5b3UgYXJlIGRvaW5nIHRoaXMgYXQgaG9tZSwgdW5jb21tZW50IHRoZSB0d28gbGluZXMgYmVsb3cKKiBUaGVzZSBzaG91bGQgYWxyZWFkeSBiZSBpbnN0YWxsZWQgb24gdGhlIE5JQ0FSIGNvbXB1dGVycwoKCmBgYHtyfQojIGluc3RhbGwucGFja2FnZXMoImRldnRvb2xzIikgIyBpZiBub3QgYWxyZWFkeSBpbnN0YWxsZWQgb24geW91ciBzeXN0ZW0KIyBkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoIm11bmljaHJvY2tlci9EYXRhd1JhcHByIikKYGBgCgoKIyMjIyMgQ3JlYXRlIGFuIEFQSSBrZXkKCllvdSB3aWxsIG5lZWQgdG8gY3JlYXRlIGEgRGF0YVdyYXBwZXIgQVBJIHRva2VuLgoKKiBPcGVuIHlvdXIgRGF0YVdyYXBwZXIgYWNjb3VudAoqIEdvIHRvIFNldHRpbmdzIC0+IEFQSS1Ub2tlbnMKKiBDcmVhdGUgYSBuZXcgdG9rZW4KKiBDaGVjayBhbGwgb2YgdGhlIGJveGVzCiogU2F2ZSB5b3VyIEFQSSBrZXkgc29tZXdoZXJlICh5b3Ugd29uJ3QgYmUgYWJsZSB0byBzZWUgaXQgYWdhaW4pCgpUaGUgc2NyZWVuIHdpbGwgbG9vayBsaWtlIHRoaXM6CiFbQVBJIHNjcmVlbi5dKGltYWdlcy9hcGkucG5nKQoKCiMjIyMjIENhbGwgbmVlZGVkIGxpYnJhcmllcwpCZSBzdXJlIHRvIGluc2VydCB5b3UgQVBJIHRva2VuIGluIHRoZSBwcm9wZXIgcGxhY2UgYmVsb3cuCgpgYGB7cn0KbGlicmFyeShEYXRhd1JhcHByKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKZGF0YXdyYXBwZXJfYXV0aChhcGlfa2V5ID0gICJJTlNFUlQgWU9VUiBBUEkgS0VZIEhFUkUiLCBvdmVyd3JpdGU9VFJVRSkKCmBgYAoKCiMjIyMgQ2FsbCBpbiBkYXRhIGFuZCBkaXNwbGF5IGhlYWQKV2UgYXJlIHdvcmtpbmcgd2l0aCBNaW5uZWFwb2xpcyBjcmltZSBkYXRhIGZyb20gMjAxOSB0aHJvdWdoIGVhcmx5IDIwMjUuCgpUaGUgZGF0YSBjYW4gYmUgZG93bmxvYWRlZCBoZXJlOgpodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vYW1hcnRvbi9uaWNhci0yMDI1L3JlZnMvaGVhZHMvbWFpbi9kYXRhd3JhcHBlci1yL21uLWNyaW1lLWRhdGEuY3N2P3Rva2VuPUdIU0FUMEFBQUFBQUM1TUtWSFU2SUlHWUpQSEo1UldOVUJBWjRJSURUUQoKSWYgeW91IGFyZSBvbiBhIHRyYWluaW5nIGNvbXB1dGVyIGF0IE5JQ0FSLCBpdCBzaG91bGQgYWxyZWFkeSBiZSBhdmFpbGFibGUgaW4gdGhlIGNvdXJzZSBmb2xkZXIuCgpgYGB7cn0KCmNyaW1lX2RhdGEgPC0gcmVhZC5jc3YoIm1uLWNyaW1lLWRhdGEuY3N2IikKaGVhZChjcmltZV9kYXRhKQoKYGBgCgoKKioqKioqCiMjIyBXb3JrIHRoZSBkYXRhCgpVc2UgTHVicmlkYXRlIHRvIGV4dHJhY3QgdGhlIHllYXIgZnJvbSB0aGUgUmVwb3J0ZWRfRGF0ZSBjb2x1bW4gYW5kIHB1dCBpdCBpbiBhIG5ldyBjb2x1bW4gY2FsbGVkICJ5ZWFyIgpgYGB7cn0KY3JpbWVfZGF0YSRZZWFyIDwtIHllYXIoY3JpbWVfZGF0YSRSZXBvcnRlZF9EYXRlKQoKYGBgCgoKRmlsdGVyIG91dCAyMDI1IGRhdGEgc2luY2UgaXQgaXMgaW5jb21wbGV0ZQpgYGB7cn0KY3JpbWVfZGF0YSA8LSBjcmltZV9kYXRhICU+JSAKICBmaWx0ZXIoWWVhciA8IDIwMjUpCmBgYAoKCkNvdW50IG51bWJlciBvZiBjcmltZXMgcGVyIHllYXIgdXNpbmcgZHlwbHIgLS0gdGhpcyBpcyB0aGUgZGF0YSBmb3Igb3VyIGNoYXJ0CmBgYHtyfQpjcmltZV9zdW1tYXJ5IDwtIGNyaW1lX2RhdGEgJT4lCiAgY291bnQoWWVhcikKCmBgYAoKQ0hFQ0s6IENvdW50IHRoZSBudW1iZXIgb2Ygcm93cyBpbiB0aGUgY3JpbWVfZGF0YSBhbmQgc3VtIHRoZSBuIGNvbCBpbiBjcmltZV9zdW1tYXJ5IGFzIGEgZG91YmxlIGNoZWNrIChzaG91bGQgbWF0Y2gpCgpgYGB7cn0KI25yb3coY3JpbWVfZGF0YSkKI3N1bShjcmltZV9zdW1tYXJ5JG4pCmBgYAoKClJlbmFtZSB0aGUgbiBjb2x1bW4gdG8gIlJlcG9ydGVkIENyaW1lcyIgKHRoaXMgd2lsbCBiZSBoZWxwZnVsIGZvciBvdXIgcG9wdXBzIGluIHRoZSBEYXRhV3JhcHBlcikKYGBge3J9CmNyaW1lX3N1bW1hcnkgPC0gY3JpbWVfc3VtbWFyeSAlPiUKICByZW5hbWUoIlJlcG9ydGVkIGNyaW1lcyIgPSAibiIpCmBgYAoKCioqKioqKgoKIyMjIENyZWF0ZSBvdXIgZmlyc3QgY2hhcnQgCgpXZSB3aWxsIG1ha2UgYSBsaW5lIGNoYXJ0IHNob3dpbmcgcmVwb3J0ZWQgY3JpbWVzIHBlciB5ZWFyCgpDcmVhdGUgYSBuZXcgY2hhcnQgYW5kIGFzc2lnbiBpdCB0byB0aGUgdmFyaWFibGUgIm15X2NoYXJ0IiAodGhpcyB3YXksIHlvdSBkb24ndCBuZWVkIHRvIHdvcnJ5IGFib3V0IHRoZSBJRCkKYGBge3J9Cm15X2NoYXJ0IDwtIGR3X2NyZWF0ZV9jaGFydCgpCmBgYAoKCkFkZCBvdXIgZGF0YSB0byBjaGFydApgYGB7cn0KZHdfZGF0YV90b19jaGFydChjcmltZV9zdW1tYXJ5LCBteV9jaGFydCkKYGBgCgpZb3UgY291bGQgc3RvcCBoZXJlLiBUaGlzIGlzIGFjdHVhbGx5IHByZXR0eSB1c2VmdWwuIFdlIGhhdmUgc2VudCBvdXIgZGF0YSBmcm9tIFIgdG8gRGF0YVdyYXBwZXIgd2l0aG91dCB0aGUgbmVlZCB0byBleHBvcnQgLyBpbXBvcnQuIAoKQnV0IHdlIGNhbiB0YWtlIHRoaXMgYSBsb3QgZnVydGhlci4gTGV0J3MgdXBkYXRlIGFuZCBtYWtlIGNoYW5nZXMgdG8gb3VyIGNoYXJ0IHJpZ2h0IGZyb20gUi4KCgpVcGRhdGUgdGhlIGNoYXJ0LS0gSGVyZSB3ZSBhZGQgYSBoZWFkbGluZSBhbmQgY2hhdHRlcgpgYGB7cn0KZHdfZWRpdF9jaGFydChteV9jaGFydCwgdGl0bGUgPSAiQ3JpbWUgaW4gTWlubmVhcG9saXMgaGl0IGEgdGhyZWUteWVhciBsb3cgaW4gMjAyNCIsIAppbnRybyA9ICJSZXBvcnRlZCBjcmltZXMgaW4gdGhlIGNpdHkgYmV0d2VlbiAyMDE5IGFuZCAyMDI0IGhpdCBhIGhpZ2ggbWFyayBpbiAyMDIyIGJ1dCBoYXZlIGJlZW4gb24gdGhlIGRlY2xpbmUgc2luY2UuIiwgc291cmNlX25hbWUgPSAiT3BlbiBEYXRhIE1pbm5lYXBvbGlzIikKYGBgCgoKTmV4dCwgd2UgY2FuIHB1Ymxpc2ggb3VyIGdyYXBoaWMKYGBge3J9CmR3X3B1Ymxpc2hfY2hhcnQobXlfY2hhcnQpCmBgYAoKT3IgZXhwb3J0IGFzIGFuIGltYWdlCmBgYHtyfQpwbmdfY2hhcnQgPC0gZHdfZXhwb3J0X2NoYXJ0KG15X2NoYXJ0LCB0eXBlID0gInBuZyIpCgptYWdpY2s6OmltYWdlX3dyaXRlKHBuZ19jaGFydCwgImxpbmUtY2hhcnQucG5nIikKYGBgCgoKSXQgc2hvdWxkIGxvb2sgbGlrZSB0aGlzOgohW091ciBsaW5lIGNoYXJ0Ll0oaW1hZ2VzL2xpbmUtY2hhcnQucG5nKQoKVGhlcmUgYXJlIGEgZmV3IHRoaW5ncyBJIHdvdWxkIGNoYW5nZSBoZXJlOgoKKiBJbmNyZWFzZSB0aGUgc2NhbGUgb2YgdGhlIHktYXhpcy0gdGhlIGN1cnJlbnQgc2NhbGUgbWFrZXMgdGhlIGNoYW5nZSBiZXR3ZWVuIHllYXJzIGxvb2sgYmlnZ2VyIHRoYW4gaXQgYWN0dWFsbHkgaXMuCiogRm9ybWF0IGRhdGVzIGluIHRoZSBwb3B1cHMtIGluc3RlYWQgb2YgIjIwMTkgSmFuIDEiIGl0IHNob3VsZCBqdXN0IHNheSAiMjAxOS4iCgpXZSBjb3VsZCBtYWtlIHRoZXNlIGNoYW5nZXMgcHJldHR5IGVhc2lseSBpbiBEYXRhV3JhcHBlciwgd2hpY2ggaXMgYSBmaW5lIHdheSB0byBkbyBpdC4gT3Igd2UgY291bGQgZnVydGhlciBtb2RpZnkgb3VyIGdyYXBoaWMgZGlyZWN0bHkgZnJvbSBSLiBMZXQncyBtb3ZlIG9uIGFuZCBzZWUgaG93IHRoYXQgaXMgZG9uZS4KCgoKIyMjIENyZWF0ZSBhIGJhciBjaGFydAoKRm9yIG91ciBzZWNvbmQgY2hhcnQsIGxldCdzIHVzZSB0aGUgc2FtZSBkYXRhIHRvIG1ha2UgYSBiYXIgY2hhcnQgb2YgcmVwb3J0ZWQgY3JpbWVzIHBlciB5ZWFyIGFuZCBtYWtlIHNvbWUgZGVzaWduIG1vZGlmaWNhdGlvbnMuCgoKQ3JlYXRlIGEgY2hhcnQsIGNob29zZSB0aGUgY2hhcnQgdHlwZSBhbmQgYWRkIGEgdGl0bGUgCgoqIFdlIHdpbGwgbWFrZSBhIGJhciBjaGFydCB0aGlzIHRpbWUgdXNpbmcgdGhlIHR5cGUgImQzLWJhcnMiCiogRm9yIHZpc3VhbGl6YXRpb24gdHlwZXMsIHNlZTogaHR0cHM6Ly9kZXZlbG9wZXIuZGF0YXdyYXBwZXIuZGUvZG9jcy9jaGFydC10eXBlcwoKYGBge3J9CmJhcl9jaGFydCA8LSBkd19jcmVhdGVfY2hhcnQoCiAgdHlwZT0iZDMtYmFycyIsCiAgdGl0bGU9Ik1pbm5lYXBvbGlzIHJlcG9ydGVkIGNyaW1lLCAyMDE5LTIwMjQiCikKYGBgCgpBZGQgb3VyIGRhdGEKYGBge3J9CmR3X2RhdGFfdG9fY2hhcnQoY3JpbWVfc3VtbWFyeSwgYmFyX2NoYXJ0KQpgYGAKCgpVcGRhdGUgd2l0aCBhIG5ldyBoZWFkbGluZSwgY2hhdHRlciBhbmQgc291cmNlCmBgYHtyfQpkd19lZGl0X2NoYXJ0KGJhcl9jaGFydCwgdGl0bGUgPSAiQ3JpbWUgaW4gTWlubmVhcG9saXMgaGl0IGEgdGhyZWUteWVhciBsb3cgaW4gMjAyNCIsIAppbnRybyA9ICJSZXBvcnRlZCBjcmltZXMgaW4gdGhlIGNpdHkgYmV0d2VlbiAyMDE5IGFuZCAyMDI0IGhpdCBhIGhpZ2ggbWFyayBpbiAyMDIyIGJ1dCBoYXZlIGJlZW4gb24gdGhlIGRlY2xpbmUgc2luY2UuIiwgc291cmNlX25hbWUgPSAiT3BlbiBEYXRhIE1pbm5lYXBvbGlzIikKYGBgCgoKTm93LCBsZXQncyB0YWtlIGEgbG9vayBhdCBvdXIgY2hhcnQncyBtZXRhZGF0YS0tIHRoaXMgaXMgZ29vZCBrZXkgdG8gd2hhdCBjYW4gYmUgY2hhbmdlZC4KCmBgYHtyfQpkd19yZXRyaWV2ZV9jaGFydF9tZXRhZGF0YShiYXJfY2hhcnQpCmBgYAoKSXQgY2FuIHRha2UgYSBsaXR0bGUgd29yayB0byBmaWd1cmUgb3V0IHdoYXQgbWV0YWRhdGEgdmFsdWVzIHRvIGNoYW5nZS4gU29tZXRpbWVzIHRoZSBkb2N1bWVudGF0aW9uIHdpbGwgaGVscC4gCgpNb2RpZnkgc29tZSBvZiB0aGUgYXR0cmlidXRlcyBvZiB0aGUgZ3JhcGhpYzoKCiogQWRkIGEgYnlsaW5lCiogQ2hhbmdlIHRoZSBiYXIgY29sb3IKKiBNYWtlIHRoZSBiYXJzIHRoaWNrCiogQWxpZ24gdGhlIGxhYmVscyB0byB0aGUgcmlnaHQKCmBgYHtyfQpkd19lZGl0X2NoYXJ0KGJhcl9jaGFydCwgCiAgICAgICAgICAgICAgYnlsaW5lID0gIkFkYW0gTWFydG9uIiwKICAgICAgICAgICAgICB2aXN1YWxpemUgPSBsaXN0KAogICAgICAgICAgICAgICAgImJhc2UtY29sb3IiID0gIiNhNDc3NjQiLAogICAgICAgICAgICAgICAgInRoaWNrIiA9ICJ0cnVlIiwKICAgICAgICAgICAgICAgICJ2YWx1ZS1sYWJlbC1hbGlnbm1lbnQiID0gInJpZ2h0IgogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICkKYGBgCgoKUHVibGlzaCBvdXIgbmV3IGdyYXBoaWMKYGBge3J9CmR3X3B1Ymxpc2hfY2hhcnQoYmFyX2NoYXJ0KQpgYGAKCkl0IHNob3VsZCBsb29rIGxpa2UgdGhpczoKIVtPdXIgYmFyIGNoYXJ0Ll0oaW1hZ2VzL2Jhci1jaGFydC5wbmcpCgoKCiMjIyBUZW1wbGF0aW5nCgpMZXQncyBkdXBsaWNhdGUgdGhhdCBjaGFydCBhZGQgbmV3IGRhdGEuIFlvdSBjYW4gdXNlIHRoaXMgbWV0aG9kIHRvIGNyZWF0ZSB5b3VyIG93biB0ZW1wbGF0ZXMuICAKCkZvciBvdXIgbmV4dCBncmFwaGljLCBsZXQncyBsb29rIGF0IHRoZSBPZmZlbnNlIENhdGVnb3J5IGNvbHVtbi4gV2Ugd2lsbCB2aXN1YWxpemUgd2hhdCB0aGUgdG9wIDEwIGNhdGVnb3JpZXMgd2VyZSBpbiAyMDI0LgoKKioqKgoKIyMjIyBGaXJzdCwgc29tZSBxdWljayBkYXRhIHdvcmsKCkxldHMgbWFrZSBhIG5ldyBkYXRhZnJhbWUgY2FsbGVkICJjcmltZXNfMjAyNCIgYW5kIGZpbHRlciB0aGUgY3JpbWUgZGF0YSBmb3IganVzdCAyMDI0CmBgYHtyfQpjcmltZXNfMjAyNCA8LSBjcmltZV9kYXRhICU+JSAKICBmaWx0ZXIoWWVhciA9PSAyMDI0KQpgYGAKCgpOZXh0LCB3ZSBjb3VudCB0aGUgbnVtYmVyIG9mIGNyaW1lcyBpbiBlYWNoICJvZmZlbnNlIGNhdGVnb3J5IiBpbiAyMDI0IHVzaW5nIGR5cGxyCmBgYHtyfQpjcmltZV9vZmZlbnNlX3N1bW1hcnkgPC0gY3JpbWVzXzIwMjQgJT4lCiAgY291bnQoT2ZmZW5zZV9DYXRlZ29yeSkKYGBgCgoKVGhlbiB3ZSBzb3J0IHRoZSBjb2x1bW4gbnVtYmVyIChuKSBjb2x1bW4gYnkgZGVzY2VuZGluZyBhbmQgcmVkdWNlIHRvIGp1c3QgdGhlIHRvcCAxMCB1c2luZyBzbGljZQpgYGB7cn0KY3JpbWVfb2ZmZW5zZV9zdW1tYXJ5IDwtIGNyaW1lX29mZmVuc2Vfc3VtbWFyeSAlPiUKICAgIGFycmFuZ2UoZGVzYyhuKSkgJT4lCiAgICBzbGljZSgxOjEwKSAKYGBgCgpUaGlzIHRoZSBkYXRhIHdlIHdpbGwgdXNlIGZvciBvdXIgbmV3IChkdXBsaWNhdGUpIGNoYXJ0CgoqKioqCgojIyMjIER1cGxpY2F0ZSB0aGUgYmFyIGNoYXJ0IHdlIG1hZGUgYWJvdmUgYW5kIGFkZCBpbiBvdXIgbmV3IGRhdGEKCgpEdXBsaWNhdGUgdGhlIGJhciBjaGFydAoKKipXZSBuZWVkIHRoZSBjaGFydCBpZCBmb3IgdGhpcy4gV2UgY2FuIGdldCBpdCBhYm92ZSBmcm9tIHdoZW4gd2UgZmlyc3QgbWFkZSB0aGUgYmFyIGNoYXJ0IG9yIGZyb20gdGhlIGNoYXJ0IFVSTApgYGB7cn0Kb2ZmZW5zZV9jaGFydCA8LSBkd19jb3B5X2NoYXJ0KGNvcHlfZnJvbSA9ICJJTlNFUlQgQ0hBUlQgSUQgRlJPTSBCQVIgQ0hBUlQgQUJPVkUiKQpgYGAKClVwZGF0ZSB0aGUgZHVwbGljYXRlZCBjaGFydCB3aXRoIHRoZSBuZXcgZGF0YQpgYGB7cn0KZHdfZGF0YV90b19jaGFydChjcmltZV9vZmZlbnNlX3N1bW1hcnksIG9mZmVuc2VfY2hhcnQpCgpgYGAKClVwZGF0ZSB0ZXh0CmBgYHtyfQpkd19lZGl0X2NoYXJ0KG9mZmVuc2VfY2hhcnQsIHRpdGxlID0gIlRvcCAxMCBoaWdoZXN0IGNhdGVnb3JpZXMgb2YgY3JpbWUgb2ZmZW5zZXMgaW4gTWlubmVhcG9saXMgaW4gMjAyNCIsIAppbnRybyA9ICJBbG1vc3QgMTMsMDAwIGxhcmNlbnkgYW5kIHRoZWZ0IG9mZmVuc2VzIGFuZCBvdmVyIDgsMDAwIGFzc2F1bHQgb2ZmZW5zZXMgd2VyZSByZXBvcnRlZC4iLCBzb3VyY2VfbmFtZSA9ICJPcGVuIERhdGEgTWlubmVhcG9saXMiKQpgYGAKCgpMZXQncyB0YWtlIGEgbG9vayBhdCB0aGUgY2hhcnQgbm93IGFuZCBkZWNpZGUgd2hhdCB3ZSBuZWVkIHRvIGNoYW5nZS4gWW91IGNhbiBvcGVuIGl0IGluIERhdGFXcmFwcGVyIG9yIHB1Ymxpc2ggYW5kIGxvb2sgaW4gdGhlIGJyb3dzZXIuCgpQdWJsaXNoCmBgYHtyfQpkd19wdWJsaXNoX2NoYXJ0KG9mZmVuc2VfY2hhcnQpCmBgYAoKTmV4dCwgbG9vayBhdCB0aGUgbWV0YWRhdGEKYGBge3J9CmR3X3JldHJpZXZlX2NoYXJ0X21ldGFkYXRhKG9mZmVuc2VfY2hhcnQpCgpgYGAKCk1vZGlmeSBzb21lIG9mIHRoZSBhdHRyaWJ1dGVzIG9mIHRoZSBncmFwaGljOgoKKiBjaGFuZ2UgdGhlIGJhciBjb2xvcgoqIHNvcnQgdGhlIGJhcnMgYnkgdmFsdWUKKiBBZGQgbGluZXMgYmV0d2VlbiB0aGUgYmFycwoqIEFkZCBhIGJhY2tncm91bmQgYmVoaW5kIHRoZSBiYXJzCiogUHV0IHRoZSBsYWJlbHMgYW5kIGJhcnMgb2Ygc2VwYXJhdGUgbGluZXMgKCJibG9jayBsYWJlbHMiPykKKiBhbGlnbiB0aGUgbGFiZWxzIHRvIHRoZSByaWdodAoKYGBge3J9CmR3X2VkaXRfY2hhcnQob2ZmZW5zZV9jaGFydCwgCiAgICAgICAgICAgICAgdmlzdWFsaXplID0gbGlzdCgKICAgICAgICAgICAgICAgICJiYXNlLWNvbG9yIiA9ICIjOEFDRTAwIiwKICAgICAgICAgICAgICAgICJzb3J0LWJhcnMiID0gInRydWUiLAogICAgICAgICAgICAgICAgInJ1bGVzIiA9ICJ0cnVlIiwKICAgICAgICAgICAgICAgICJiYWNrZ3JvdW5kIiA9ICJ0cnVlIiwKICAgICAgICAgICAgICAgICJibG9jay1sYWJlbHMiID0gInRydWUiLAogICAgICAgICAgICAgICAgInZhbHVlLWxhYmVsLWFsaWdubWVudCIgPSAicmlnaHQiCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgKQpgYGAKClJlcHVibGlzaApgYGB7cn0KZHdfcHVibGlzaF9jaGFydChvZmZlbnNlX2NoYXJ0KQpgYGAKCgpJdCBzaG91bGQgbG9vayBzb21ldGhpbmcgbGlrZSB0aGlzOgohW091ciBiYXIgY2hhcnQuXShpbWFnZXMvb2ZmZW5zZV9jaGFydC5wbmcpCgpIb3cgbWlnaHQgc29tZXRoaW5nIGxpa2UgdGhpcyBiZSB1c2VmdWw/CkhvdyBjb3VsZCB5b3UgdXNlIGl0IHRvIHNhdmUgdGltZSBkdXJpbmcgcHJvZHVjdGlvbiB0YXNrcz8KCgoqKioKCiMjIyBPbiB5b3VyIG93bjogRXhlcmNpc2UgMQpUYWtlIHdoYXQgd2UgbGVhcm5lZCBhYm92ZSBhbmQgY3JlYXRlIGEgY2hhcnQgdGhhdCBzaG93cyB0aGUgbmVpZ2hib3Job29kcyB3aXRoIHRoZSBoaWdoZXN0IHJlcG9ydGVkIGNyaW1lcyBpbiAyMDI0LiBVc2Ugd2hhdGV2ZXIgY2hhcnQgdHlwZSB5b3UgbGlrZS4gU3R5bGUgaXQgaG93ZXZlciB5b3UgbGlrZS4gWW91IGNhbiBkdXBsaWNhdGUgb25lIG9mIG91ciBwcmV2aW91cyBjaGFydHMgb3IgbWFrZSB5b3VyIG93bi4gQmUgc3VyZSB0byBpbmNsdWRlIGEgaGVhZGxpbmUsIGNoYXR0ZXIgYW5kIHNvdXJjZS4gCgpJJ3ZlIGRvbmUgdGhlIGRhdGEgd29yayBmb3IgeW91IGJlbG93OgoKQ291bnQgdGhlIG51bWJlciBvZiBjcmltZXMgaW4gZWFjaCAibmVpZ2hib3Job29kIiBpbiAyMDI0IHVzaW5nIGR5cGxyCmBgYHtyfQpjcmltZV9uZWlnaGJvcmhvb2Rfc3VtbWFyeSA8LSBjcmltZXNfMjAyNCAlPiUKICBjb3VudChOZWlnaGJvcmhvb2QpCmBgYAoKClRoZW4gd2Ugc29ydCB0aGUgY29sdW1uIG51bWJlciAobikgY29sdW1uIGJ5IGRlc2NlbmRpbmcgYW5kIHJlZHVjZSB0byBqdXN0IHRoZSB0b3AgMTAgdXNpbmcgc2xpY2UKYGBge3J9CmNyaW1lX25laWdoYm9yaG9vZF9zdW1tYXJ5IDwtIGNyaW1lX25laWdoYm9yaG9vZF9zdW1tYXJ5ICU+JQogICAgYXJyYW5nZShkZXNjKG4pKSAlPiUKICAgIHNsaWNlKDE6MTApIApgYGAKCk5vdyB5b3UgaGF2ZSBhIGRhdGFmcmFtZSBjYWxsZWQgImNyaW1lX25laWdoYm9yaG9vZF9zdW1tYXJ5IiB3aXRoIHRoZSB0b3AgdGVuIG5laWdoYm9yaG9vZHMgd2hlcmUgY3JpbWVzIHdlcmUgcmVwb3J0ZWQgaW4gMjAyNC4gVXNlIHRoYXQgdG8gbWFrZSB5b3VyIGNoYXJ0LgoKCgoKCgoKKioqCgoKIyMjIEZ1bmN0aW9ucwoKTGV0J3MgbWFrZSBhIGZ1bmN0aW9uIHRoYXQgd2lsbCBhdXRvbWF0aWNhbGx5IGdlbmVyYXRlIGEgY2hhcnQuCgpIZXJlIGlzIGEgc2ltcGxlIGZ1bmN0aW9uIHRoYXQgY3JlYXRlcyBhIGNoYXJ0IGxvb2tpbmcgYXQgcmVwb3J0ZWQgY3JpbWVzIGJ5IHllYXIgaW4gcHJlY2luY3QgMS4gUmVhZCB0aHJvdWdoIHRoZSBjb21tZW50cyBpbiB0aGUgZnVuY3Rpb24gdG8gc2VlIGhvdyBpdCB3b3Jrcy4KYGBge3J9CgoKbXlfZnVuY3Rpb24gPC0gZnVuY3Rpb24oKSB7CiAgCiAgI21ha2UgYSBuZXcgZGF0YSBmcmFtZSB0aGF0IGhvbGRzIGRhdGEganVzdCBmb3IgcHJlY2luY3QgMQogIHByZWNpbmN0X2RhdGEgPC0gY3JpbWVfZGF0YSAlPiUgZmlsdGVyKFByZWNpbmN0PT0gMSkKCiAgI2NvdW50IG51bWJlciBvZiBhcnJlc3RzIHBlciB5ZWFyIGluIHRoYXQgcHJlY2luY3QKICBwcmVjaW5jdF9zdW1tYXJ5IDwtIHByZWNpbmN0X2RhdGEgJT4lY291bnQoWWVhcikKICAKICAjY3JlYXRlIG5ldyBjaGFydAogIG15X2NoYXJ0IDwtIGR3X2NyZWF0ZV9jaGFydCgKICB0eXBlPSJkMy1iYXJzIiwKICApCgogICNhZGQgZGF0YQogIGR3X2RhdGFfdG9fY2hhcnQocHJlY2luY3Rfc3VtbWFyeSwgbXlfY2hhcnQpCgogICNlZGl0IGNoYXJ0CiAgZHdfZWRpdF9jaGFydChteV9jaGFydCwgdGl0bGUgPSBwYXN0ZSgiUmVwb3J0ZWQgY3JpbWVzIGJ5IHllYXIgaW4gTWlubmVhcG9saXMgUHJlY2luY3QgMSIpLCBzb3VyY2VfbmFtZSA9ICJPcGVuIERhdGEgTWlubmVhcG9saXMiKQogIAogICNwdWJsaXNoCiAgZHdfcHVibGlzaF9jaGFydChteV9jaGFydCkKfQoKI0NhbGwgdGhlIGZ1bmN0aW9uIHRvIHJ1biBpdApteV9mdW5jdGlvbigpCgpgYGAKClRoZSBvdXRwdXR0ZWQgZ3JhcGhpYyBzaG91bGQgbG9vayBzb21ldGhpbmcgbGlrZSB0aGlzOgohW1ByZWNpbmN0IENoYXJ0Ll0oaW1hZ2VzL3ByZWNpbmN0LTEucG5nKQoKV2UgY2FuIG1ha2UgdGhpcyBtdWNoIG1vcmUgdXNlZnVsIHdpdGggb25lIGNoYW5nZSAtLSBtYWtpbmcgdGhlIHNwZWNpZmljIHByZWNpbmN0IGEgcGFyYW1ldGVyIGluIHRoZSBmdW5jdGlvbi4KQ2hhbmdlcyBhcmUgaW5kaWN0ZWQgaW4gdGhlIGNvbW1lbnRzIGJlbG93CgpgYGB7cn0KCiNhZGQgYSBwYXJhbWV0ZXIgY2FsbGVkIHByZWNpbmN0Cm15X2Z1bmN0aW9uIDwtIGZ1bmN0aW9uKHByZWNpbmN0KSB7CiAgCiAgI2luc3RlYWQgb2YgbmFtaW5nIHRoZSBwcmVjaW5jdCBoZXJlLCB1c2UgdGhlIHBhcmFtZXRlcgogIHByZWNpbmN0X2RhdGEgPC0gY3JpbWVfZGF0YSAlPiUgZmlsdGVyKFByZWNpbmN0ID09IHByZWNpbmN0KQoKICBwcmVjaW5jdF9zdW1tYXJ5IDwtIHByZWNpbmN0X2RhdGEgJT4lY291bnQoWWVhcikKICAKICBteV9jaGFydCA8LSBkd19jcmVhdGVfY2hhcnQoCiAgdHlwZT0iZDMtYmFycyIsCiAgKQoKICBkd19kYXRhX3RvX2NoYXJ0KHByZWNpbmN0X3N1bW1hcnksIG15X2NoYXJ0KQoKICAjQWdhaW4sIHVzZSB0aGUgcGFyYW1ldGVyIGluc3RlYWQgb2YgbmFtaW5nIHRoZSBzcGVjaWZpYyBwcmVjaW5jdCBpbiB0aGUgaGVhZGxpbmUKICBkd19lZGl0X2NoYXJ0KG15X2NoYXJ0LCB0aXRsZSA9IHBhc3RlKCJSZXBvcnRlZCBjcmltZXMgYnkgeWVhciBpbiBNaW5uZWFwb2xpcyBQcmVjaW5jdCIsIHByZWNpbmN0KSwgc291cmNlX25hbWUgPSAiT3BlbiBEYXRhIE1pbm5lYXBvbGlzIikKICAKICBkd19wdWJsaXNoX2NoYXJ0KG15X2NoYXJ0KQp9CgojQ2FsbCB0aGUgZnVuY3Rpb24gYW5kIHBhc3MgYW4gYXJndW1lbnQgLS0gIjIiLS0gdG8gdGhlIHBhcmFtZXRlcgojVGhpcyBwYXNzZXMgdGhlIDIgZXZlcnl3aGVyZSB3ZSBoYXZlIHRoZSBwYXJhbWV0ZXIgaW4gdGhlIGZ1bmN0aW9uLCBzbyBvdXIgZ3JhcGhpYyB3aWxsIGRpc3BsYXkgY3JpbWVzIGluIHByZWNpbmN0IDIKbXlfZnVuY3Rpb24oIjIiKQpgYGAKCk5vdyB3ZSBjYW4gdXNlIHRoaXMgZnVuY3Rpb24gdG8gY3JlYXRlIGEgZ3JhcGhpYyBmb3IgYW55IHByZWNpbmN0IGp1c3QgYnkgY2hhbmdpbmcgdGhlIGFyZ3VtZW50IHRvIGEgZGlmZmVyZW50IHByZWNpbmN0IG51bWJlciB3aGVuIHdlIGNhbGwgdGhlIGZ1bmN0aW9uLgoKKioqKgoKIyMjIyBBZGQgYSBsb29wCgpXZSBjYW4gd3JhcCBvdXIgZnVuY3Rpb24gaW4gYSBsb29wIC0tIGFsc28gY2FsbGVkIGEgImZvciBzdGF0ZW1lbnQiIC0tIHRvIHF1aWNrbHkgY3JlYXRlIGEgZ3JhcGhpYyBmb3IgYWxsIHByZWNpbmN0cyEKCmBgYHtyfQpmb3IocHJlY2luY3QgaW4gdW5pcXVlKGNyaW1lX2RhdGEkUHJlY2luY3QpKSB7CiAgbXlfZnVuY3Rpb24ocHJlY2luY3QpCn0KCmBgYApUaGlzIHNheXM6IGZvciBlYWNoIHVuaXF1ZSB2YWx1ZSBpbiB0aGUgUHJlY2luY3QgY29sdW1uIG9mIG91ciBkYXRhLCBleGVjdXRlIG15X2Z1bmN0aW9uIGFuZCBwdXQgdGhlIHVuaXF1ZSBwcmVjaW5jdCBuYW1lIGFzIHRoZSBmdW5jdGlvbidzIGFyZ3VtZW50LgoKClRoaXMgc2hvdWxkIG91dHB1dCA1IGdyYXBoaWNzLCBvbmUgZm9yIGVhY2ggUHJlY2luY3QuIEVhY2ggb2YgdGhlIGdyYXBoaWNzIHNob3VsZCBsb29rIHNvbWV0aGluZyBsaWtlIHRoaXM6CiFbUHJlY2luY3QgQ2hhcnQuXShpbWFnZXMvcHJlY2luY3QtMS5wbmcpCgpXZSBjb3VsZCB1c2UgdGhpcyB0byBjcmVhdGUgZG96ZW5zIG9yIGV2ZW4gaHVuZHJlZHMgb2YgY2hhcnRzIGF0IGF0IHRpbWUuCgoKCioqKioKCiMjIyBNYWtlIGEgc3ltYm9sIG1hcAoKCiMjIyMgT3VyIERhdGEKCkluIHRoaXMgZXhhbXBsZSwgd2Ugd2lsbCBwdWxsIGNyaW1lcyBmcm9tIHRoZSBsYXN0IHNldmVuIGRheXMuCgpXZSB3aWxsIG5lZWQgdG8gZmFrZSBpdCBhIGxpdHRsZSBiaXQgc2luY2Ugd2Ugb25seSBoYXZlIGRhdGEgdGhyb3VnaCB0aGUgZW5kIG9mIDIwMjQuIEZvbGxvdyB0aGUgY29tbWVudHMgYmVsb3cgdG8gc2VlIGhvdyB0aGlzIHdvcmtzLgoKYGBge3J9CiNGaXJzdCB3ZSBzZXQgdG9kYXkncyBkYXRlCiAgIyBsZXQncyBmYWtlIHRoZSBjdXJyZW50IGRhdGUgdG8gbWFrZSB0aGlzIGV4YW1wbGUgaW1tb3J0YWw6Cm5vdyA9IGFzLkRhdGUoIjEyLzMxLzIwMjQiLCBmb3JtYXQgPSAiJW0vJWQvJVkiKQogICMgaG93ZXZlciwgaW4gInJlYWwgbGlmZSIgeW91IHNob3VsZCByZXBsYWNlIGl0IHdpdGggdGhpcyBmb3IgdGhlIGN1cnJlbnQgZGF0ZToKICAjIG5vdyA9IFN5cy5EYXRlKCkKCiNOZXh0LCBsZXQncyBtYWtlIGEgbmV3IGRhdGFmcmFtZSB0aGF0IG9ubHkgc2hvd3MgY3JpbWVzIHNldmVuIGRheXMgYmVmb3JlICJub3ciCmNyaW1lc19sYXN0XzcgPC0gc3Vic2V0KGNyaW1lc18yMDI0LCBjcmltZXNfMjAyNCRSZXBvcnRlZF9EYXRlID4gbm93LTcpCgpgYGAKCiMjIyMgTWFrZSB0aGUgbWFwCgpDcmVhdGUgYSBuZXcgc3ltYm9sIG1hcC4KYGBge3J9Cm5ld19zeW1ib2xfY2hhcnQgPC0gZHdfY3JlYXRlX2NoYXJ0KAogIHRpdGxlID0gIkNyaW1lcyBpbiBNaW5uZWFwb2xpcyBpbiB0aGUgbGFzdCBzZXZlbiBkYXlzIiwgCiAgdHlwZSA9ICJkMy1tYXBzLXN5bWJvbHMiCiAgKQoKYGBgCgpXZSBuZWVkIHRvIGRlY2lkZSB3aGljaCBiYXNlIG1hcCB0byB1c2UuIEl0IGlzIGlkZW50aWZpZWQgYnkgdGhlIGlkLWNvbHVtbi4KCllvdSBjYW4gdXNlIGRwbHly4oCZcyBWaWV3KCkgdG8gZ2V0IGFuIGludGVyYWN0aXZlIHRhYmxlIG9mIGF2YWlsYWJsZSBtYXBzIGFuZCBzZWFyY2ggZm9yIHdoYXQgeW91IGFyZSBsb29raW5nIGZvci4gCmBgYHtyfQp2aWV3KGR3X2Jhc2VtYXBzKQpgYGAKV2Ugd2lsbCB1c2UgYSBiYXNlbWFwIG9mIE1pbm5lYXBvbGlzIG5laWdoYm9yaG9vZHMsIHdoaWNoIGhhcyB0aGUgaWQgIm1pbm5lYXBvbGlzLW5laWdoYm9yaG9vZHMiCgoKQ29ubmVjdCBvdXIgZGF0YSB0byB0aGUgY2hhcnQKYGBge3J9CmR3X2RhdGFfdG9fY2hhcnQoY3JpbWVzX2xhc3RfNywgY2hhcnRfaWQgPSBuZXdfc3ltYm9sX2NoYXJ0KQpgYGAKCkVkaXQgdGhlIGNoYXJ0LiAKCiogV2UgbmVlZCB0byBpbmNsdWRlIHRoZSBsYXRpdHVkZSBhbmQgbG9uZ2l0dWRlICh3aGljaCwgbHVja2lseSwgd2UgaGF2ZSBpbiBvdXIgZGF0YSBhbHJlYWR5IHNvIHRoZXJlIGlzIG5vIGdlb2NvZGluZyBuZWVkZWQpCiogV2UgYWxzbyBpbmNsdWRlICJ2YWx1ZXMiIHdoaWNoIHdpbGwgY29sb3Igb3VyIHN5bWJvbHMgYmFzZWQgb24gYSBjb2x1bW4KKiBGaW5hbGx5LCB3ZSBpZGVudGlmeSB0aGUgYmFzZW1hcC4KYGBge3J9CmR3X2VkaXRfY2hhcnQobmV3X3N5bWJvbF9jaGFydCwgCiAgICAgICAgICAgICAgYXhlcyA9IGxpc3QoCiAgICAgICAgICAgICAgICBsYXQgPSAiTGF0aXR1ZGUiLCAKICAgICAgICAgICAgICAgIGxvbiA9ICJMb25naXR1ZGUiLAogICAgICAgICAgICAgICAgdmFsdWVzID0gIk9mZmVuc2VfQ2F0ZWdvcnkiCiAgICAgICAgICAgICAgICApLCAKICAgICAgICAgICAgICB2aXN1YWxpemUgPSBsaXN0KAogICAgICAgICAgICAgICAgYmFzZW1hcCA9ICJtaW5uZWFwb2xpcy1uZWlnaGJvcmhvb2RzIgogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICkKYGBgCgoKQWRkIC8gRWRpdCB0b29sdGlwcwoKKiBUaXRsZSBzaG93cyBhYm92ZSB0aGUgdG9vbHRpcCBhbmQgYm9keSBpcyB0aGUgbWFpbiB0ZXh0CiogUmVmZXIgdG8geW91ciBkYXRhIGNvbHVtbnMgaW4gZG91YmxlIGJyYWNrZXRzIHt7IH19CiogWW91IGhhdmUgdG8gZGVmaW5lIHlvdXIgdmFyaWFibGVzIGluIHRoZSBmaWVsZHMgbGlzdC4gSXQgaXMgYmVzdCBqdXN0IHRvIG5hbWUgdGhlIHZhcmlhYmxlcyBhZnRlciB0aGUgY29sdW1ucy4KCmBgYHtyfQpkd19lZGl0X2NoYXJ0KG5ld19zeW1ib2xfY2hhcnQsIHZpc3VhbGl6ZSA9IGxpc3QoCiAgdG9vbHRpcCA9IGxpc3QoCiAgICBib2R5ID0gIlJlcG9ydGVkIERhdGU6IHt7IHJlcG9ydGVkX2RhdGUgfX08YnI+IEFkZHJlc3M6IHt7IGFkZHJlc3MgfX0iLAogICAgdGl0bGUgPSAie3sgb2ZmZW5zZSB9fSIsCiAgICBmaWVsZHMgPSBsaXN0KAogICAgICAicmVwb3J0ZWRfZGF0ZSIgPSAicmVwb3J0ZWRfZGF0ZSIsCiAgICAgICJvZmZlbnNlIiA9ICJvZmZlbnNlIiwKICAgICAgImFkZHJlc3MiID0gImFkZHJlc3MiCiAgICApLAogICAgZW5hYmxlZCA9ICJUUlVFIgogICAgKSkpCmBgYApJdCBpcyBlYXNpZXN0IHRvIG9wZW4gdXAgZGF0YXdyYXBwZXIgYXQgdGhpcyBwb2ludCB0byBlZGl0IC8gdHdlYWsgdGhlIGxlZ2VuZC4gWW91IGNvdWxkIGFsc28gZG8gaXQgdmlhIHRoZSBtZXRhZGF0YSBpZiB5b3UgbGlrZS4KClB1Ymxpc2gKYGBge3J9CmR3X3B1Ymxpc2hfY2hhcnQobmV3X3N5bWJvbF9jaGFydCkKYGBgCgpUaGUgcHVibGlzaGVkIG1hcCBzaG91bGQgbG9vayBzb21ldGhpbmcgbGlrZSB0aGlzOgohW091ciBtYXBdKGltYWdlcy9tYXAucG5nKQoKCioqKioKCiMjIyBPbiB5b3VyIG93bgpDcmVhdGUgeW91ciBvd24gbWFwLiBMb29rIGF0IHRoZSBkYXRhIGFuZCB0aGluayBhYm91dCB3aGF0IG1pZ2h0IGJlIGludGVyZXN0aW5nIHRvIHZpc3VhbGl6ZSBvbiBhIG1hcC4gUHJlcGFyZSB5b3VyIGRhdGEgYW5kIHRoZW4gZm9sbG93IHRoZSB3b3JrZmxvdyBhYm92ZSB0byBjcmVhdGUgeW91ciBvd24gc3ltYm9sIC8gZG90IG1hcC4gUmVmZXIgdG8gdGhlIGRvY3VtZW50YXRpb24gYXMgbmVlZGVkIChzZWUgdGhlIHRvcCBvZiB0aGlzIGRvYyBmb3IgbGlua3MpLiBIZXJlIGFyZSBhIGZldyBpZGVhczoKCjEuIE1hcCBhbGwgb2YgdGhlIGFzc2F1bHRzIHRoYXQgb2NjdXJyZWQgaW4gTm92ZW1iZXIgMjAyNAoyLiBNYXAgYWxsIG9mIHRoZSBjcmltZXMgdGhhdCBvY2N1cnJlZCBpbiB0aGUgUG93ZGVyaG9ybiBQYXJrIG5laWdoYm9yaG9vZCBpbiB0aGUgc3VtbWVyIG9mIDIwMjQKMy4gTWFwIGFsbCBvZiB0aGUgY2FyamFja2luZ3MgaW4gV2FyZCA4IGluIDIwMjQKCgoqKioqCgojIyMgTmV4dCBzdGVwcwoKVGhlcmUgaXMgYSBsb3QgbW9yZSB5b3UgY2FuIGRvIHdpdGggdGhlIERhdGFXcmFwcGVyIEFQSS4gQSBmZXcgZXhhbXBsZXM6CgoxLiBXZWIgc2NyYXBpbmc6IElmIHlvdSBuZWVkIHRvIGdyYWIgbGl2ZSBvciB1cGRhdGluZyBkYXRhIGZyb20gYSByZW1vdGUgc291cmNlLCB5b3UgY291bGQgYWRkIHNjcmFwaW5nIGludG8gdGhpcyB3b3JrZmxvdy4gVXNlIHRoZSBydmVzdCBwYWNrYWdlIChodHRwczovL3J2ZXN0LnRpZHl2ZXJzZS5vcmcvKSB0byBlYXNpbHkgc2NyYXBlIGRhdGEgaW4gUiB0aGVuIGZvbGxvdyB0aGUgc3RlcHMgd2Ugb3V0bGluZWQgYWJvdmUKCjIuIEludGVncmF0aW9ucyAtIGEgbW9yZSBjb21wbGV4IHVzZSBvZiB0aGUgQVBJIGlzIGludGVncmF0aW9uczogdXNpbmcgdGhlIEFQSSBpbiBleGlzdGluZyBhcHBsaWNhdGlvbiB3b3JrZmxvd3MuIFNlZSB0aGUgZG9jdW1lbnRhdGlvbiBoZXJlOiBodHRwczovL2RldmVsb3Blci5kYXRhd3JhcHBlci5kZS9kb2NzL2dldHRpbmctc3RhcnRlZC13aXRoLWludGVncmF0aW9ucy4gCgozLiBVcmJhbiBJbnN0aXR1dGUgaGFzIGEgZ3JlYXQgYmxvZyBwb3N0IGFib3V0IGhvdyB0aGV5IHVzZWQgdGhlIEFQSSBpbiBTdmVsdGUgdG8gY3JlYXRlIGEgY3VzdG9taXplZCBtYXAsIGhlcmU6IGh0dHBzOi8vbWVkaXVtLmNvbS91cmJhbi1pbnN0aXR1dGUvdXNpbmctZGF0YXdyYXBwZXItdG8tbWFrZS1jdXN0b20tZGF0YS12aXN1YWxpemF0aW9uLW1vcmUtZWZmaWNpZW50LTRhY2VkOTM4NzNhNiAKCgo=

Twitter, Facebook