<< Workshop Home

Mapping Shapefiles

# Set Working Directory
setwd("/Users/Carrie/Desktop/Spatial Workshop") #replace with your directory

Loading Packages

If you want to use an installed package, you will need to load the package using the library() function. Each time you close R and then re-open it, you will need to re-load the packages you want to use.

# Load packages for this working session
library(sp)
library(rgdal)

The ? function is useful for looking up documentation on packages or code. The results will display in the Help tab within R Studio. If you do not find what you are looking for, remember that you can find lots of help by searching online.

# What do these packages do?
?sp #provides classes & methods for spatial data
?rgdal #helps to read shapefiles

Importing Shapefiles

There are many different commands to import data in R, depending on the type of data. We downloaded health facilities and provinces as shapfiles, which means they are spatial vector data. Shapefiles are pretty easy to work with. Use the readOGR() function from the rgdal package to import shapefiles (files ending in .shp). R can easily find the file by name because you set your working directory to the location of the file. Assign your shapefile to an object called facilities_shp, using the <- notation.

# Options
options(stringsAsFactors = FALSE) #import text variables as characters

# Import the health facilities shapefile
facilities_shp <- readOGR("zwe_health_facility_mohcw.shp")

Examining Data

It’s always a good idea to examine your data after you import it. In particular, we need to know what class of data we are working with. Different classes of data require different commands.

# Class of data
class(facilities_shp)

We see that facilities_shp is a SpatialPointsDataFrame, which means it contains point vector data which can be readily mapped. Try it out with R’s built-in plot() function!

# Plot as a map
plot(facilities_shp)
# View the dataset
View(facilities_shp) #View opens a new tab showing the data as a spreadsheet
# Look at the first few rows of data in the Console
head(facilities_shp)

It appears that our health facilities shapefile came with lots of data about each facility! There are variables including its name, year built, type of facility, number of doctors, number of nurses, etc! Unfortunately it appears that many of these values are missing, judging by all of those zeros. It looks like the data have not been updated since 1998 for these facilities.

# Look at the last few rows of data
tail(facilities_shp)

At the end of the dataset, the updated year is more recent (2007), and there are some values filled in for doctors, nurses, beds, etc. Exciting! Now let’s take a look at the data for some of these variables.

TIP! If you have ever used Stata, you should note a key difference in R is that you can easily work with numerous datasets at a time. So, when you want to access a variable, you need to tell R which dataset the variable is in. This is done using the $ symbol.

# Year updated
table(facilities_shp$UPDATED)

We see that there are two years for the UPDATED variable: 1998 and 2007. Most of the facilities (1,212 of them) were updated in 1998, while 258 facilities were updated in 2007.

# Number of doctors
table(facilities_shp$NUMOFDOCTO)

We see that most facilities have 0 recorded for the number of doctors. 15 facilities have 1 doctor, 5 facilities have 2 doctors, and 2 facilities have 3 doctors recorded. It’s likely that many of the 0 values should actually be recorded as missing (NA).

# Number of nurses
table(facilities_shp$NUMOFNURSE)

Again, most of the facilities have 0 recorded for the number of nurses. However, there are more facilities with at least 1 nurse, and 1 facility even has 41 nurses recorded.

# Number of beds
summary(facilities_shp$NUMOFBEDS)

Using the summary command, we can see that at least three-quarters of facilities have 0 beds recorded. The maximum number of beds recorded is 150.

# Types of facilities
table(facilities_shp$TYPEOFFACI)

There are so many facility types that it is difficult to tell which are most common. Why are they not sorted by order of frequency like they were for doctors, nurses, and beds?

# Check class of data
class(facilities_shp$TYPEOFFACI)

After checking the class, we see that facility types are “character” data, meaning they are made up of letter or symbols rather than numbers (called “string” in Stata). So when we use the table() function, R sorts by alphabetical letter. This is helpful for spotting some of the data cleaning needs, but we need to give R special instructions if we want to order by frequency.

#Sort in descending order
sort(table(facilities_shp$TYPEOFFACI),decreasing=TRUE)

What is the most common type of facility?

Great! Now we have a feel for our facilities data. But all of those points mapped in a blank space are not very helpful for getting a sense of where the facilities are located.

# Import the provinces shapefile
provinces_shp <- readOGR("zwe_polbnda_adm1_250k_cso.shp")

# Class of data
class(provinces_shp)

Again, we have spatial vector data, but this time the data are polygons. Let’s see what they look like.

# Plot as a map
plot(provinces_shp)

Neat! But where did our facilities go? We need to add them on top of the provinces.

# Plot facilities on top of provinces
plot(provinces_shp)
plot(facilities_shp, add=TRUE) #add=TRUE adds to previous plot

Selecting a Subset of a Shapefile

Now that we have examined our data and determined that much of the data are out of date, moving forward we just want to use the facilities that were updated more recently. Let’s look at what proportion of the total facilities we will be keeping if we do that.

# Examine the data again, this time with a proportion table
prop.table(table(facilities_shp$UPDATED))

With the prop.table() (proportion table) function, we see that 17.55% of facilities that were updated in 2007. Let’s select those facilities using the subset() function:

  • We specify that within the dataset facilities_shp, we want to keep all records where the variable UPDATED is equal to 2007.
  • We assign this subset to a new object called facilities2007_shp.
# Select facilities updated in 2007
facilities2007_shp <- subset(facilities_shp, UPDATED==2007)

Now let’s plot our new shapefile to look at the spatial distribution of facilities with data updated in 2007.

# Plot
plot(provinces_shp)
plot(facilities2007_shp, add=TRUE)

What do you notice? Which provinces did not have any facilities included in the 2007 data update?

Alright, let’s examine the data in our 2007 facilities shapefile. This time we’ll construct a more nicely formatted output with columns for the frequency and proportion of facilities by type. We do this by creating two new objects we’ll call Freq and Pct, and binding them together with the cbind() function. We’ll also use the head() function again, this time specifying that we want to see the first 15 rows.

# Within the recently updated facilities, select the clinics, RHCs, and hospitals.
# Explore the types of facilities
Freq <- sort(table(facilities_shp$TYPEOFFACI), decreasing=TRUE)
Pct <- prop.table(Freq)*100 #multiply by 100 for percentage format
Pct <- round(Pct, 2) # round the Pct values to two decimal points
head(cbind(Freq, Pct),15) #use head( ,15) to just look at first 15 rows of the table

We can see the most of the facilities are some type of clinic, rural health centre, or hospital. Let’s create three new shapefiles, one for each of these facility types. We’ll use the subset() function again. To indicate multiple values to include in a single subset, use the | symbol (meaning “or”). R is case sensitive, so we need to specify that we want both Clinic and clinic values in our new clinics2007_shp object.

# Create a new shapefile with just selected clinics
clinics2007_shp <- subset(facilities2007_shp,
                          TYPEOFFACI=="Clinic" | #this bar signifies "OR"
                          TYPEOFFACI=="clinic")

# Create a new shapefile for RHCs
RHCs2007_shp <- subset(facilities2007_shp,
                       TYPEOFFACI=="Rural Health Centre" |
                       TYPEOFFACI=="Rural Health centre")

# Create a new shapefile for Hospitals
hospitals2007_shp <- subset(facilities2007_shp,
                            TYPEOFFACI=="Hospital" |
                            TYPEOFFACI=="Mission Hospital" |
                            TYPEOFFACI=="Rural Hospital" |
                            TYPEOFFACI=="District Hospital" |
                            TYPEOFFACI=="Provincial Hospital")

Visualizing Qualitative Data

Now let’s map these three new shapefiles using different shapes and colors. Within the plot command, you can specify the following inputs:

  • col: a color
  • pch: a symbol code (1 to 24)
# Plot facilities by type using different shapes and colors
plot(provinces_shp)
plot(clinics2007_shp, add = T, col = "purple", pch = 19) #19=circle symbol
plot(RHCs2007_shp, add = T, col = "blue", pch = 15) #15=square symbol
plot(hospitals2007_shp, add = T, col = "red", pch = 17) #17=triangle symbol
# Tip: view more symbols and colors
?plot #see more plot options, including pch symbol options
colors() #see list of color options

Now add some more plot specifications.

  • Provinces polygons:
    • col: fill color
    • border: border color
    • main: title for the plot
  • Facilities points:
    • pch: this time, specify filled symbols
    • col: outline color
    • bg: fill color
    • alpha: transparency for the fill color
    • cex: font size (1 is default)
# Make it prettier
plot(provinces_shp, col = "grey93", border = "grey",
      main = "Zimbabwe Health Facilities Updated in 2007") #title of plot
plot(clinics2007_shp, add = T,
      pch = 21, #filled circle symbol
      col = "blue4", #outline color
      bg = adjustcolor("blue1", alpha = 0.6), #fill color, alpha=transparency
      cex = 1.5) # increase font size
plot(RHCs2007_shp, add = T,
      pch = 22, #filled square symbol
      col = "purple4",
      bg = adjustcolor("purple1", alpha = 0.7),
      cex = 1.5)
plot(hospitals2007_shp, add = T,
      pch = 24, #filled triangle symbol
      col = "red4",
      bg = adjustcolor("red1", alpha = 0.8),
      cex = 1.5)

# Assign plot to an object for easy modification!
plot_2007 <- recordPlot()

Adding a Legend

Now let’s create a legend. We’ll need a list of the labels we want to give to each symbol.

# Create a vector of labels for the legend
legendLab <- c("Clinic", "Rural Health Centre", "Hospital")
legendLab

# Plot with legend
plot_2007 # Render the saved plot
legend("bottomleft", legend=legendLab) # Add legend

We can see that just providing the labels was not sufficient. We also need to tell the legend() function the symbols and colors to go with each label.

# Create a vector of symbols for the legend
legendSym <- c(19, 15, 17)
# Create a vector of colors for the legend
legendCol <- c("blue", "purple", "red")

# Re-draw the plot and legend
plot_2007
legend("topleft", legend = legendLab,
       pch = legendSym, 
       col = legendCol,
       cex = 1, # font size
       pt.cex = 1.5, # increase the symbol size
       bty = "n") # turn off the legend border

# Save changes to plot
plot_2007 <- recordPlot()

Adding a Scale Bar and North Arrow

Now let’s add some finishing touches. Every finished map should include a scale bar and north arrow as references.

# Load the prettymapr package
library(prettymapr)

# Try adding these
plot_2007
addscalebar()
addnortharrow()

The default settings are not ideal for our map. The scale bar and legend are important, but should not distract from the map. Let’s investigate how we can customize these so they attract less attention.

# Check how to adjust the scale bar and north arrow
?addscalebar
?addnortharrow
# Try again
plot_2007
addscalebar(style = "ticks")
addnortharrow(cols = c("white", "grey50"), scale = 0.4)
# Save changes to plot
plot_2007 <- recordPlot()

<< Workshop Home

LS0tDQp0aXRsZTogIkludHJvZHVjdGlvbiB0byBNYXBwaW5nIFNwYXRpYWwgRGF0YSBpbiBSIg0Kc3VidGl0bGU6ICJQYXJ0IDE6IFNoYXBlZmlsZXMiDQpvdXRwdXQ6IA0KICBodG1sX2RvY3VtZW50Og0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19mbG9hdDogDQogICAgICBjb2xsYXBzZWQ6IGZhbHNlDQogICAgICBzbW9vdGhfc2Nyb2xsOiBmYWxzZQ0KICAgIHRvY19kZXB0aDogMg0KICAgIG51bWJlcl9zZWN0aW9uczogZmFsc2UgDQogICAgdGhlbWU6IGx1bWVuDQogICAgaGlnaGxpZ2h0OiB0ZXh0bWF0ZQ0KICBodG1sX25vdGVib29rOg0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19mbG9hdDogDQogICAgICBjb2xsYXBzZWQ6IGZhbHNlDQogICAgICBzbW9vdGhfc2Nyb2xsOiBmYWxzZQ0KICAgIHRvY19kZXB0aDogMg0KICAgIG51bWJlcl9zZWN0aW9uczogZmFsc2UgDQogICAgdGhlbWU6IGx1bWVuDQogICAgaGlnaGxpZ2h0OiB0ZXh0bWF0ZSAgDQoNCi0tLQ0KDQpgYGB7Y3NzfQ0KY29kZSB7DQogIHdoaXRlLXNwYWNlOiBwcmUgIWltcG9ydGFudDsNCiAgb3ZlcmZsb3cteDogc2Nyb2xsICFpbXBvcnRhbnQ7DQogIHdvcmQtYnJlYWs6IGtlZXAtYWxsICFpbXBvcnRhbnQ7DQogIHdvcmQtd3JhcDogaW5pdGlhbCAhaW1wb3J0YW50Ow0KICANCn0NCmJvZHl7IC8qIE5vcm1hbCAgKi8NCiAgICAgIGZvbnQtc2l6ZTogMTZweDsNCiAgfQ0KDQpgYGANCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UpDQpvcHRpb25zKHdpZHRoPTUwMCkNCmBgYA0KDQpbKio8PCBXb3Jrc2hvcCBIb21lKipdKGh0dHBzOi8vY2FmYWhleS5naXRodWIuaW8vc3BhdGlhbCkNCg0KI01hcHBpbmcgU2hhcGVmaWxlcw0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCiMgU2V0IFdvcmtpbmcgRGlyZWN0b3J5DQpzZXR3ZCgiL1VzZXJzL0NhcnJpZS9EZXNrdG9wL1NwYXRpYWwgV29ya3Nob3AiKSAjcmVwbGFjZSB3aXRoIHlvdXIgZGlyZWN0b3J5DQpgYGANCg0KIyNMb2FkaW5nIFBhY2thZ2VzDQoNCklmIHlvdSB3YW50IHRvIHVzZSBhbiBpbnN0YWxsZWQgcGFja2FnZSwgeW91IHdpbGwgbmVlZCB0byBsb2FkIHRoZSBwYWNrYWdlIHVzaW5nIHRoZSBgbGlicmFyeSgpYCBmdW5jdGlvbi4gRWFjaCB0aW1lIHlvdSBjbG9zZSBSIGFuZCB0aGVuIHJlLW9wZW4gaXQsIHlvdSB3aWxsIG5lZWQgdG8gcmUtbG9hZCB0aGUgcGFja2FnZXMgeW91IHdhbnQgdG8gdXNlLg0KDQpgYGB7cn0NCiMgTG9hZCBwYWNrYWdlcyBmb3IgdGhpcyB3b3JraW5nIHNlc3Npb24NCmxpYnJhcnkoc3ApDQpsaWJyYXJ5KHJnZGFsKQ0KYGBgDQoNClRoZSBgP2AgZnVuY3Rpb24gaXMgdXNlZnVsIGZvciBsb29raW5nIHVwIGRvY3VtZW50YXRpb24gb24gcGFja2FnZXMgb3IgY29kZS4gVGhlIHJlc3VsdHMgd2lsbCBkaXNwbGF5IGluIHRoZSBIZWxwIHRhYiB3aXRoaW4gUiBTdHVkaW8uIElmIHlvdSBkbyBub3QgZmluZCB3aGF0IHlvdSBhcmUgbG9va2luZyBmb3IsIHJlbWVtYmVyIHRoYXQgeW91IGNhbiBmaW5kIGxvdHMgb2YgaGVscCBieSBzZWFyY2hpbmcgb25saW5lLg0KDQpgYGB7ciBldmFsPUZBTFNFfQ0KIyBXaGF0IGRvIHRoZXNlIHBhY2thZ2VzIGRvPw0KP3NwICNwcm92aWRlcyBjbGFzc2VzICYgbWV0aG9kcyBmb3Igc3BhdGlhbCBkYXRhDQo/cmdkYWwgI2hlbHBzIHRvIHJlYWQgc2hhcGVmaWxlcw0KYGBgDQoNCiMjSW1wb3J0aW5nIFNoYXBlZmlsZXMNCg0KVGhlcmUgYXJlIG1hbnkgZGlmZmVyZW50IGNvbW1hbmRzIHRvIGltcG9ydCBkYXRhIGluIFIsIGRlcGVuZGluZyBvbiB0aGUgdHlwZSBvZiBkYXRhLiBXZSBkb3dubG9hZGVkIGhlYWx0aCBmYWNpbGl0aWVzIGFuZCBwcm92aW5jZXMgYXMgKnNoYXBmaWxlcyosIHdoaWNoIG1lYW5zIHRoZXkgYXJlIHNwYXRpYWwgKnZlY3RvciogZGF0YS4gU2hhcGVmaWxlcyBhcmUgcHJldHR5IGVhc3kgdG8gd29yayB3aXRoLg0KVXNlIHRoZSBgcmVhZE9HUigpYCBmdW5jdGlvbiBmcm9tIHRoZSByZ2RhbCBwYWNrYWdlIHRvIGltcG9ydCBzaGFwZWZpbGVzIChmaWxlcyBlbmRpbmcgaW4gYC5zaHBgKS4gUiBjYW4gZWFzaWx5IGZpbmQgdGhlIGZpbGUgYnkgbmFtZSBiZWNhdXNlIHlvdSBzZXQgeW91ciB3b3JraW5nIGRpcmVjdG9yeSB0byB0aGUgbG9jYXRpb24gb2YgdGhlIGZpbGUuIEFzc2lnbiB5b3VyIHNoYXBlZmlsZSB0byBhbiBvYmplY3QgY2FsbGVkIGBmYWNpbGl0aWVzX3NocGAsIHVzaW5nIHRoZSBgPC1gIG5vdGF0aW9uLg0KDQpgYGB7cn0NCiMgT3B0aW9ucw0Kb3B0aW9ucyhzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpICNpbXBvcnQgdGV4dCB2YXJpYWJsZXMgYXMgY2hhcmFjdGVycw0KDQojIEltcG9ydCB0aGUgaGVhbHRoIGZhY2lsaXRpZXMgc2hhcGVmaWxlDQpmYWNpbGl0aWVzX3NocCA8LSByZWFkT0dSKCJ6d2VfaGVhbHRoX2ZhY2lsaXR5X21vaGN3LnNocCIpDQpgYGANCg0KIyNFeGFtaW5pbmcgRGF0YQ0KDQpJdCdzIGFsd2F5cyBhIGdvb2QgaWRlYSB0byBleGFtaW5lIHlvdXIgZGF0YSBhZnRlciB5b3UgaW1wb3J0IGl0LiBJbiBwYXJ0aWN1bGFyLCB3ZSBuZWVkIHRvIGtub3cgd2hhdCBjbGFzcyBvZiBkYXRhIHdlIGFyZSB3b3JraW5nIHdpdGguIERpZmZlcmVudCBjbGFzc2VzIG9mIGRhdGEgcmVxdWlyZSBkaWZmZXJlbnQgY29tbWFuZHMuDQoNCmBgYHtyfQ0KIyBDbGFzcyBvZiBkYXRhDQpjbGFzcyhmYWNpbGl0aWVzX3NocCkNCmBgYA0KDQpXZSBzZWUgdGhhdCBmYWNpbGl0aWVzX3NocCBpcyBhIGBTcGF0aWFsUG9pbnRzRGF0YUZyYW1lYCwgd2hpY2ggbWVhbnMgaXQgY29udGFpbnMgcG9pbnQgdmVjdG9yIGRhdGEgd2hpY2ggY2FuIGJlIHJlYWRpbHkgbWFwcGVkLiBUcnkgaXQgb3V0IHdpdGggUidzIGJ1aWx0LWluIGBwbG90KClgIGZ1bmN0aW9uIQ0KDQpgYGB7cn0NCiMgUGxvdCBhcyBhIG1hcA0KcGxvdChmYWNpbGl0aWVzX3NocCkNCmBgYA0KDQoNCmBgYHtyIGV2YWw9RkFMU0V9DQojIFZpZXcgdGhlIGRhdGFzZXQNClZpZXcoZmFjaWxpdGllc19zaHApICNWaWV3IG9wZW5zIGEgbmV3IHRhYiBzaG93aW5nIHRoZSBkYXRhIGFzIGEgc3ByZWFkc2hlZXQNCmBgYA0KDQpgYGB7cn0NCiMgTG9vayBhdCB0aGUgZmlyc3QgZmV3IHJvd3Mgb2YgZGF0YSBpbiB0aGUgQ29uc29sZQ0KaGVhZChmYWNpbGl0aWVzX3NocCkNCmBgYA0KDQpJdCBhcHBlYXJzIHRoYXQgb3VyIGhlYWx0aCBmYWNpbGl0aWVzIHNoYXBlZmlsZSBjYW1lIHdpdGggbG90cyBvZiBkYXRhIGFib3V0IGVhY2ggZmFjaWxpdHkhIFRoZXJlIGFyZSB2YXJpYWJsZXMgaW5jbHVkaW5nIGl0cyBuYW1lLCB5ZWFyIGJ1aWx0LCB0eXBlIG9mIGZhY2lsaXR5LCBudW1iZXIgb2YgZG9jdG9ycywgbnVtYmVyIG9mIG51cnNlcywgZXRjISBVbmZvcnR1bmF0ZWx5IGl0IGFwcGVhcnMgdGhhdCBtYW55IG9mIHRoZXNlIHZhbHVlcyBhcmUgbWlzc2luZywganVkZ2luZyBieSBhbGwgb2YgdGhvc2UgemVyb3MuIEl0IGxvb2tzIGxpa2UgdGhlIGRhdGEgaGF2ZSBub3QgYmVlbiB1cGRhdGVkIHNpbmNlIDE5OTggZm9yIHRoZXNlIGZhY2lsaXRpZXMuDQoNCmBgYHtyfQ0KIyBMb29rIGF0IHRoZSBsYXN0IGZldyByb3dzIG9mIGRhdGENCnRhaWwoZmFjaWxpdGllc19zaHApDQpgYGANCg0KQXQgdGhlIGVuZCBvZiB0aGUgZGF0YXNldCwgdGhlIHVwZGF0ZWQgeWVhciBpcyBtb3JlIHJlY2VudCAoMjAwNyksIGFuZCB0aGVyZSBhcmUgc29tZSB2YWx1ZXMgZmlsbGVkIGluIGZvciBkb2N0b3JzLCBudXJzZXMsIGJlZHMsIGV0Yy4gRXhjaXRpbmchIE5vdyBsZXQncyB0YWtlIGEgbG9vayBhdCB0aGUgZGF0YSBmb3Igc29tZSBvZiB0aGVzZSB2YXJpYWJsZXMuDQoNCioqVElQISoqIElmIHlvdSBoYXZlIGV2ZXIgdXNlZCBTdGF0YSwgeW91IHNob3VsZCBub3RlIGEga2V5IGRpZmZlcmVuY2UgaW4gUiBpcyB0aGF0IHlvdSBjYW4gZWFzaWx5IHdvcmsgd2l0aCBudW1lcm91cyBkYXRhc2V0cyBhdCBhIHRpbWUuIFNvLCB3aGVuIHlvdSB3YW50IHRvIGFjY2VzcyBhIHZhcmlhYmxlLCB5b3UgbmVlZCB0byB0ZWxsIFIgd2hpY2ggZGF0YXNldCB0aGUgdmFyaWFibGUgaXMgaW4uIFRoaXMgaXMgZG9uZSB1c2luZyB0aGUgYCRgIHN5bWJvbC4NCg0KYGBge3J9DQojIFllYXIgdXBkYXRlZA0KdGFibGUoZmFjaWxpdGllc19zaHAkVVBEQVRFRCkNCmBgYA0KV2Ugc2VlIHRoYXQgdGhlcmUgYXJlIHR3byB5ZWFycyBmb3IgdGhlIGBVUERBVEVEYCB2YXJpYWJsZTogMTk5OCBhbmQgMjAwNy4gTW9zdCBvZiB0aGUgZmFjaWxpdGllcyAoMSwyMTIgb2YgdGhlbSkgd2VyZSB1cGRhdGVkIGluIDE5OTgsIHdoaWxlIDI1OCBmYWNpbGl0aWVzIHdlcmUgdXBkYXRlZCBpbiAyMDA3Lg0KDQpgYGB7cn0NCiMgTnVtYmVyIG9mIGRvY3RvcnMNCnRhYmxlKGZhY2lsaXRpZXNfc2hwJE5VTU9GRE9DVE8pDQpgYGANCldlIHNlZSB0aGF0IG1vc3QgZmFjaWxpdGllcyBoYXZlIGAwYCByZWNvcmRlZCBmb3IgdGhlIG51bWJlciBvZiBkb2N0b3JzLiAxNSBmYWNpbGl0aWVzIGhhdmUgMSBkb2N0b3IsIDUgZmFjaWxpdGllcyBoYXZlIDIgZG9jdG9ycywgYW5kIDIgZmFjaWxpdGllcyBoYXZlIDMgZG9jdG9ycyByZWNvcmRlZC4gSXQncyBsaWtlbHkgdGhhdCBtYW55IG9mIHRoZSAwIHZhbHVlcyBzaG91bGQgYWN0dWFsbHkgYmUgcmVjb3JkZWQgYXMgbWlzc2luZyAoYE5BYCkuDQpgYGB7cn0NCiMgTnVtYmVyIG9mIG51cnNlcw0KdGFibGUoZmFjaWxpdGllc19zaHAkTlVNT0ZOVVJTRSkNCmBgYA0KQWdhaW4sIG1vc3Qgb2YgdGhlIGZhY2lsaXRpZXMgaGF2ZSAwIHJlY29yZGVkIGZvciB0aGUgbnVtYmVyIG9mIG51cnNlcy4gSG93ZXZlciwgdGhlcmUgYXJlIG1vcmUgZmFjaWxpdGllcyB3aXRoIGF0IGxlYXN0IDEgbnVyc2UsIGFuZCAxIGZhY2lsaXR5IGV2ZW4gaGFzIDQxIG51cnNlcyByZWNvcmRlZC4NCmBgYHtyfQ0KIyBOdW1iZXIgb2YgYmVkcw0Kc3VtbWFyeShmYWNpbGl0aWVzX3NocCROVU1PRkJFRFMpDQpgYGANClVzaW5nIHRoZSBzdW1tYXJ5IGNvbW1hbmQsIHdlIGNhbiBzZWUgdGhhdCBhdCBsZWFzdCB0aHJlZS1xdWFydGVycyBvZiBmYWNpbGl0aWVzIGhhdmUgMCBiZWRzIHJlY29yZGVkLiBUaGUgbWF4aW11bSBudW1iZXIgb2YgYmVkcyByZWNvcmRlZCBpcyAxNTAuDQpgYGB7cn0NCiMgVHlwZXMgb2YgZmFjaWxpdGllcw0KdGFibGUoZmFjaWxpdGllc19zaHAkVFlQRU9GRkFDSSkNCmBgYA0KVGhlcmUgYXJlIHNvIG1hbnkgZmFjaWxpdHkgdHlwZXMgdGhhdCBpdCBpcyBkaWZmaWN1bHQgdG8gdGVsbCB3aGljaCBhcmUgbW9zdCBjb21tb24uIFdoeSBhcmUgdGhleSBub3Qgc29ydGVkIGJ5IG9yZGVyIG9mIGZyZXF1ZW5jeSBsaWtlIHRoZXkgd2VyZSBmb3IgZG9jdG9ycywgbnVyc2VzLCBhbmQgYmVkcz8NCmBgYHtyfQ0KIyBDaGVjayBjbGFzcyBvZiBkYXRhDQpjbGFzcyhmYWNpbGl0aWVzX3NocCRUWVBFT0ZGQUNJKQ0KYGBgDQpBZnRlciBjaGVja2luZyB0aGUgY2xhc3MsIHdlIHNlZSB0aGF0IGZhY2lsaXR5IHR5cGVzIGFyZSAiY2hhcmFjdGVyIiBkYXRhLCBtZWFuaW5nIHRoZXkgYXJlIG1hZGUgdXAgb2YgbGV0dGVyIG9yIHN5bWJvbHMgcmF0aGVyIHRoYW4gbnVtYmVycyAoY2FsbGVkICJzdHJpbmciIGluIFN0YXRhKS4gU28gd2hlbiB3ZSB1c2UgdGhlIGB0YWJsZSgpYCBmdW5jdGlvbiwgUiBzb3J0cyBieSBhbHBoYWJldGljYWwgbGV0dGVyLiBUaGlzIGlzIGhlbHBmdWwgZm9yIHNwb3R0aW5nIHNvbWUgb2YgdGhlIGRhdGEgY2xlYW5pbmcgbmVlZHMsIGJ1dCB3ZSBuZWVkIHRvIGdpdmUgUiBzcGVjaWFsIGluc3RydWN0aW9ucyBpZiB3ZSB3YW50IHRvIG9yZGVyIGJ5IGZyZXF1ZW5jeS4NCmBgYHtyfQ0KI1NvcnQgaW4gZGVzY2VuZGluZyBvcmRlcg0Kc29ydCh0YWJsZShmYWNpbGl0aWVzX3NocCRUWVBFT0ZGQUNJKSxkZWNyZWFzaW5nPVRSVUUpDQpgYGANCipXaGF0IGlzIHRoZSBtb3N0IGNvbW1vbiB0eXBlIG9mIGZhY2lsaXR5PyoNCg0KR3JlYXQhIE5vdyB3ZSBoYXZlIGEgZmVlbCBmb3Igb3VyIGZhY2lsaXRpZXMgZGF0YS4gQnV0IGFsbCBvZiB0aG9zZSBwb2ludHMgbWFwcGVkIGluIGEgYmxhbmsgc3BhY2UgYXJlIG5vdCB2ZXJ5IGhlbHBmdWwgZm9yIGdldHRpbmcgYSBzZW5zZSBvZiB3aGVyZSB0aGUgZmFjaWxpdGllcyBhcmUgbG9jYXRlZC4NCg0KYGBge3J9DQojIEltcG9ydCB0aGUgcHJvdmluY2VzIHNoYXBlZmlsZQ0KcHJvdmluY2VzX3NocCA8LSByZWFkT0dSKCJ6d2VfcG9sYm5kYV9hZG0xXzI1MGtfY3NvLnNocCIpDQoNCiMgQ2xhc3Mgb2YgZGF0YQ0KY2xhc3MocHJvdmluY2VzX3NocCkNCmBgYA0KQWdhaW4sIHdlIGhhdmUgc3BhdGlhbCB2ZWN0b3IgZGF0YSwgYnV0IHRoaXMgdGltZSB0aGUgZGF0YSBhcmUgcG9seWdvbnMuIExldCdzIHNlZSB3aGF0IHRoZXkgbG9vayBsaWtlLg0KYGBge3J9DQojIFBsb3QgYXMgYSBtYXANCnBsb3QocHJvdmluY2VzX3NocCkNCmBgYA0KDQpOZWF0ISBCdXQgd2hlcmUgZGlkIG91ciBmYWNpbGl0aWVzIGdvPyBXZSBuZWVkIHRvIGFkZCB0aGVtIG9uIHRvcCBvZiB0aGUgcHJvdmluY2VzLg0KYGBge3J9DQojIFBsb3QgZmFjaWxpdGllcyBvbiB0b3Agb2YgcHJvdmluY2VzDQpwbG90KHByb3ZpbmNlc19zaHApDQpwbG90KGZhY2lsaXRpZXNfc2hwLCBhZGQ9VFJVRSkgI2FkZD1UUlVFIGFkZHMgdG8gcHJldmlvdXMgcGxvdA0KYGBgDQoNCiMjU2VsZWN0aW5nIGEgU3Vic2V0IG9mIGEgU2hhcGVmaWxlDQpOb3cgdGhhdCB3ZSBoYXZlIGV4YW1pbmVkIG91ciBkYXRhIGFuZCBkZXRlcm1pbmVkIHRoYXQgbXVjaCBvZiB0aGUgZGF0YSBhcmUgb3V0IG9mIGRhdGUsIG1vdmluZyBmb3J3YXJkIHdlIGp1c3Qgd2FudCB0byB1c2UgdGhlIGZhY2lsaXRpZXMgdGhhdCB3ZXJlIHVwZGF0ZWQgbW9yZSByZWNlbnRseS4gTGV0J3MgbG9vayBhdCB3aGF0IHByb3BvcnRpb24gb2YgdGhlIHRvdGFsIGZhY2lsaXRpZXMgd2Ugd2lsbCBiZSBrZWVwaW5nIGlmIHdlIGRvIHRoYXQuDQoNCmBgYHtyfQ0KIyBFeGFtaW5lIHRoZSBkYXRhIGFnYWluLCB0aGlzIHRpbWUgd2l0aCBhIHByb3BvcnRpb24gdGFibGUNCnByb3AudGFibGUodGFibGUoZmFjaWxpdGllc19zaHAkVVBEQVRFRCkpDQpgYGANCg0KV2l0aCB0aGUgYHByb3AudGFibGUoKWAgKHByb3BvcnRpb24gdGFibGUpIGZ1bmN0aW9uLCB3ZSBzZWUgdGhhdCAxNy41NSUgb2YgZmFjaWxpdGllcyB0aGF0IHdlcmUgdXBkYXRlZCBpbiAyMDA3LiBMZXQncyBzZWxlY3QgdGhvc2UgZmFjaWxpdGllcyB1c2luZyB0aGUgYHN1YnNldCgpYCBmdW5jdGlvbjogDQoNCiogV2Ugc3BlY2lmeSB0aGF0IHdpdGhpbiB0aGUgZGF0YXNldCBgZmFjaWxpdGllc19zaHBgLCB3ZSB3YW50IHRvIGtlZXAgYWxsIHJlY29yZHMgd2hlcmUgdGhlIHZhcmlhYmxlIGBVUERBVEVEYCBpcyBlcXVhbCB0byBgMjAwN2AuIA0KKiBXZSBhc3NpZ24gdGhpcyBzdWJzZXQgdG8gYSBuZXcgb2JqZWN0IGNhbGxlZCBgZmFjaWxpdGllczIwMDdfc2hwYC4gDQoNCmBgYHtyfQ0KIyBTZWxlY3QgZmFjaWxpdGllcyB1cGRhdGVkIGluIDIwMDcNCmZhY2lsaXRpZXMyMDA3X3NocCA8LSBzdWJzZXQoZmFjaWxpdGllc19zaHAsIFVQREFURUQ9PTIwMDcpDQpgYGANCg0KTm93IGxldCdzIHBsb3Qgb3VyIG5ldyBzaGFwZWZpbGUgdG8gbG9vayBhdCB0aGUgc3BhdGlhbCBkaXN0cmlidXRpb24gb2YgZmFjaWxpdGllcyB3aXRoIGRhdGEgdXBkYXRlZCBpbiAyMDA3Lg0KDQpgYGB7cn0NCiMgUGxvdA0KcGxvdChwcm92aW5jZXNfc2hwKQ0KcGxvdChmYWNpbGl0aWVzMjAwN19zaHAsIGFkZD1UUlVFKQ0KYGBgDQoNCipXaGF0IGRvIHlvdSBub3RpY2U/IFdoaWNoIHByb3ZpbmNlcyBkaWQgbm90IGhhdmUgYW55IGZhY2lsaXRpZXMgaW5jbHVkZWQgaW4gdGhlIDIwMDcgZGF0YSB1cGRhdGU/Kg0KDQpBbHJpZ2h0LCBsZXQncyBleGFtaW5lIHRoZSBkYXRhIGluIG91ciAyMDA3IGZhY2lsaXRpZXMgc2hhcGVmaWxlLiBUaGlzIHRpbWUgd2UnbGwgY29uc3RydWN0IGEgbW9yZSBuaWNlbHkgZm9ybWF0dGVkIG91dHB1dCB3aXRoIGNvbHVtbnMgZm9yIHRoZSBmcmVxdWVuY3kgYW5kIHByb3BvcnRpb24gb2YgZmFjaWxpdGllcyBieSB0eXBlLiBXZSBkbyB0aGlzIGJ5IGNyZWF0aW5nIHR3byBuZXcgb2JqZWN0cyB3ZSdsbCBjYWxsIGBGcmVxYCBhbmQgYFBjdGAsIGFuZCBiaW5kaW5nIHRoZW0gdG9nZXRoZXIgd2l0aCB0aGUgYGNiaW5kKClgIGZ1bmN0aW9uLiBXZSdsbCBhbHNvIHVzZSB0aGUgYGhlYWQoKWAgZnVuY3Rpb24gYWdhaW4sIHRoaXMgdGltZSBzcGVjaWZ5aW5nIHRoYXQgd2Ugd2FudCB0byBzZWUgdGhlIGZpcnN0IDE1IHJvd3MuDQoNCmBgYHtyfQ0KIyBXaXRoaW4gdGhlIHJlY2VudGx5IHVwZGF0ZWQgZmFjaWxpdGllcywgc2VsZWN0IHRoZSBjbGluaWNzLCBSSENzLCBhbmQgaG9zcGl0YWxzLg0KIyBFeHBsb3JlIHRoZSB0eXBlcyBvZiBmYWNpbGl0aWVzDQpGcmVxIDwtIHNvcnQodGFibGUoZmFjaWxpdGllc19zaHAkVFlQRU9GRkFDSSksIGRlY3JlYXNpbmc9VFJVRSkNClBjdCA8LSBwcm9wLnRhYmxlKEZyZXEpKjEwMCAjbXVsdGlwbHkgYnkgMTAwIGZvciBwZXJjZW50YWdlIGZvcm1hdA0KUGN0IDwtIHJvdW5kKFBjdCwgMikgIyByb3VuZCB0aGUgUGN0IHZhbHVlcyB0byB0d28gZGVjaW1hbCBwb2ludHMNCmhlYWQoY2JpbmQoRnJlcSwgUGN0KSwxNSkgI3VzZSBoZWFkKCAsMTUpIHRvIGp1c3QgbG9vayBhdCBmaXJzdCAxNSByb3dzIG9mIHRoZSB0YWJsZQ0KYGBgDQoNCldlIGNhbiBzZWUgdGhlIG1vc3Qgb2YgdGhlIGZhY2lsaXRpZXMgYXJlIHNvbWUgdHlwZSBvZiBjbGluaWMsIHJ1cmFsIGhlYWx0aCBjZW50cmUsIG9yIGhvc3BpdGFsLiBMZXQncyBjcmVhdGUgdGhyZWUgbmV3IHNoYXBlZmlsZXMsIG9uZSBmb3IgZWFjaCBvZiB0aGVzZSBmYWNpbGl0eSB0eXBlcy4gV2UnbGwgdXNlIHRoZSBgc3Vic2V0KClgIGZ1bmN0aW9uIGFnYWluLiBUbyBpbmRpY2F0ZSBtdWx0aXBsZSB2YWx1ZXMgdG8gaW5jbHVkZSBpbiBhIHNpbmdsZSBzdWJzZXQsIHVzZSB0aGUgYHxgIHN5bWJvbCAobWVhbmluZyAib3IiKS4gUiBpcyBjYXNlIHNlbnNpdGl2ZSwgc28gd2UgbmVlZCB0byBzcGVjaWZ5IHRoYXQgd2Ugd2FudCBib3RoIGBDbGluaWNgIGFuZCBgY2xpbmljYCB2YWx1ZXMgaW4gb3VyIG5ldyBgY2xpbmljczIwMDdfc2hwYCBvYmplY3QuDQoNCmBgYHtyfQ0KIyBDcmVhdGUgYSBuZXcgc2hhcGVmaWxlIHdpdGgganVzdCBzZWxlY3RlZCBjbGluaWNzDQpjbGluaWNzMjAwN19zaHAgPC0gc3Vic2V0KGZhY2lsaXRpZXMyMDA3X3NocCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgVFlQRU9GRkFDST09IkNsaW5pYyIgfCAjdGhpcyBiYXIgc2lnbmlmaWVzICJPUiINCiAgICAgICAgICAgICAgICAgICAgICAgICAgVFlQRU9GRkFDST09ImNsaW5pYyIpDQoNCiMgQ3JlYXRlIGEgbmV3IHNoYXBlZmlsZSBmb3IgUkhDcw0KUkhDczIwMDdfc2hwIDwtIHN1YnNldChmYWNpbGl0aWVzMjAwN19zaHAsDQogICAgICAgICAgICAgICAgICAgICAgIFRZUEVPRkZBQ0k9PSJSdXJhbCBIZWFsdGggQ2VudHJlIiB8DQogICAgICAgICAgICAgICAgICAgICAgIFRZUEVPRkZBQ0k9PSJSdXJhbCBIZWFsdGggY2VudHJlIikNCg0KIyBDcmVhdGUgYSBuZXcgc2hhcGVmaWxlIGZvciBIb3NwaXRhbHMNCmhvc3BpdGFsczIwMDdfc2hwIDwtIHN1YnNldChmYWNpbGl0aWVzMjAwN19zaHAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgVFlQRU9GRkFDST09Ikhvc3BpdGFsIiB8DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgVFlQRU9GRkFDST09Ik1pc3Npb24gSG9zcGl0YWwiIHwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUWVBFT0ZGQUNJPT0iUnVyYWwgSG9zcGl0YWwiIHwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUWVBFT0ZGQUNJPT0iRGlzdHJpY3QgSG9zcGl0YWwiIHwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUWVBFT0ZGQUNJPT0iUHJvdmluY2lhbCBIb3NwaXRhbCIpDQpgYGANCg0KIyNWaXN1YWxpemluZyBRdWFsaXRhdGl2ZSBEYXRhDQpOb3cgbGV0J3MgbWFwIHRoZXNlIHRocmVlIG5ldyBzaGFwZWZpbGVzIHVzaW5nIGRpZmZlcmVudCBzaGFwZXMgYW5kIGNvbG9ycy4gV2l0aGluIHRoZSBwbG90IGNvbW1hbmQsIHlvdSBjYW4gc3BlY2lmeSB0aGUgZm9sbG93aW5nIGlucHV0czoNCg0KKiBgY29sYDogYSBjb2xvcg0KKiBgcGNoYDogYSBzeW1ib2wgY29kZSAoYDFgIHRvIGAyNGApDQoNCmBgYHtyfQ0KIyBQbG90IGZhY2lsaXRpZXMgYnkgdHlwZSB1c2luZyBkaWZmZXJlbnQgc2hhcGVzIGFuZCBjb2xvcnMNCnBsb3QocHJvdmluY2VzX3NocCkNCnBsb3QoY2xpbmljczIwMDdfc2hwLCBhZGQgPSBULCBjb2wgPSAicHVycGxlIiwgcGNoID0gMTkpICMxOT1jaXJjbGUgc3ltYm9sDQpwbG90KFJIQ3MyMDA3X3NocCwgYWRkID0gVCwgY29sID0gImJsdWUiLCBwY2ggPSAxNSkgIzE1PXNxdWFyZSBzeW1ib2wNCnBsb3QoaG9zcGl0YWxzMjAwN19zaHAsIGFkZCA9IFQsIGNvbCA9ICJyZWQiLCBwY2ggPSAxNykgIzE3PXRyaWFuZ2xlIHN5bWJvbA0KYGBgDQoNCg0KYGBge3IgZXZhbD1GQUxTRX0NCiMgVGlwOiB2aWV3IG1vcmUgc3ltYm9scyBhbmQgY29sb3JzDQo/cGxvdCAjc2VlIG1vcmUgcGxvdCBvcHRpb25zLCBpbmNsdWRpbmcgcGNoIHN5bWJvbCBvcHRpb25zDQpjb2xvcnMoKSAjc2VlIGxpc3Qgb2YgY29sb3Igb3B0aW9ucw0KYGBgDQoNCk5vdyBhZGQgc29tZSBtb3JlIHBsb3Qgc3BlY2lmaWNhdGlvbnMuDQoNCiAgKiBQcm92aW5jZXMgcG9seWdvbnM6DQogICAgKiBgY29sYDogZmlsbCBjb2xvcg0KICAgICogYGJvcmRlcmA6IGJvcmRlciBjb2xvcg0KICAgICogYG1haW5gOiB0aXRsZSBmb3IgdGhlIHBsb3QNCiAgDQogICogRmFjaWxpdGllcyBwb2ludHM6DQogICAgKiBgcGNoYDogdGhpcyB0aW1lLCBzcGVjaWZ5IGZpbGxlZCBzeW1ib2xzIA0KICAgICogYGNvbGA6IG91dGxpbmUgY29sb3INCiAgICAqIGBiZ2A6IGZpbGwgY29sb3INCiAgICAqIGBhbHBoYWA6IHRyYW5zcGFyZW5jeSBmb3IgdGhlIGZpbGwgY29sb3INCiAgICAqIGBjZXhgOiBmb250IHNpemUgKGAxYCBpcyBkZWZhdWx0KQ0KICANCmBgYHtyfQ0KIyBNYWtlIGl0IHByZXR0aWVyDQpwbG90KHByb3ZpbmNlc19zaHAsIGNvbCA9ICJncmV5OTMiLCBib3JkZXIgPSAiZ3JleSIsDQogICAgICBtYWluID0gIlppbWJhYndlIEhlYWx0aCBGYWNpbGl0aWVzIFVwZGF0ZWQgaW4gMjAwNyIpICN0aXRsZSBvZiBwbG90DQpwbG90KGNsaW5pY3MyMDA3X3NocCwgYWRkID0gVCwNCiAgICAgIHBjaCA9IDIxLCAjZmlsbGVkIGNpcmNsZSBzeW1ib2wNCiAgICAgIGNvbCA9ICJibHVlNCIsICNvdXRsaW5lIGNvbG9yDQogICAgICBiZyA9IGFkanVzdGNvbG9yKCJibHVlMSIsIGFscGhhID0gMC42KSwgI2ZpbGwgY29sb3IsIGFscGhhPXRyYW5zcGFyZW5jeQ0KICAgICAgY2V4ID0gMS41KSAjIGluY3JlYXNlIGZvbnQgc2l6ZQ0KcGxvdChSSENzMjAwN19zaHAsIGFkZCA9IFQsDQogICAgICBwY2ggPSAyMiwgI2ZpbGxlZCBzcXVhcmUgc3ltYm9sDQogICAgICBjb2wgPSAicHVycGxlNCIsDQogICAgICBiZyA9IGFkanVzdGNvbG9yKCJwdXJwbGUxIiwgYWxwaGEgPSAwLjcpLA0KICAgICAgY2V4ID0gMS41KQ0KcGxvdChob3NwaXRhbHMyMDA3X3NocCwgYWRkID0gVCwNCiAgICAgIHBjaCA9IDI0LCAjZmlsbGVkIHRyaWFuZ2xlIHN5bWJvbA0KICAgICAgY29sID0gInJlZDQiLA0KICAgICAgYmcgPSBhZGp1c3Rjb2xvcigicmVkMSIsIGFscGhhID0gMC44KSwNCiAgICAgIGNleCA9IDEuNSkNCg0KIyBBc3NpZ24gcGxvdCB0byBhbiBvYmplY3QgZm9yIGVhc3kgbW9kaWZpY2F0aW9uIQ0KcGxvdF8yMDA3IDwtIHJlY29yZFBsb3QoKQ0KYGBgDQoNCiMjQWRkaW5nIGEgTGVnZW5kDQoNCk5vdyBsZXQncyBjcmVhdGUgYSBsZWdlbmQuIFdlJ2xsIG5lZWQgYSBsaXN0IG9mIHRoZSBsYWJlbHMgd2Ugd2FudCB0byBnaXZlIHRvIGVhY2ggc3ltYm9sLg0KDQpgYGB7cn0NCiMgQ3JlYXRlIGEgdmVjdG9yIG9mIGxhYmVscyBmb3IgdGhlIGxlZ2VuZA0KbGVnZW5kTGFiIDwtIGMoIkNsaW5pYyIsICJSdXJhbCBIZWFsdGggQ2VudHJlIiwgIkhvc3BpdGFsIikNCmxlZ2VuZExhYg0KDQojIFBsb3Qgd2l0aCBsZWdlbmQNCnBsb3RfMjAwNyAjIFJlbmRlciB0aGUgc2F2ZWQgcGxvdA0KbGVnZW5kKCJib3R0b21sZWZ0IiwgbGVnZW5kPWxlZ2VuZExhYikgIyBBZGQgbGVnZW5kDQpgYGANCg0KV2UgY2FuIHNlZSB0aGF0IGp1c3QgcHJvdmlkaW5nIHRoZSBsYWJlbHMgd2FzIG5vdCBzdWZmaWNpZW50LiBXZSBhbHNvIG5lZWQgdG8gdGVsbCB0aGUgYGxlZ2VuZCgpYCBmdW5jdGlvbiB0aGUgc3ltYm9scyBhbmQgY29sb3JzIHRvIGdvIHdpdGggZWFjaCBsYWJlbC4NCg0KYGBge3J9DQojIENyZWF0ZSBhIHZlY3RvciBvZiBzeW1ib2xzIGZvciB0aGUgbGVnZW5kDQpsZWdlbmRTeW0gPC0gYygxOSwgMTUsIDE3KQ0KIyBDcmVhdGUgYSB2ZWN0b3Igb2YgY29sb3JzIGZvciB0aGUgbGVnZW5kDQpsZWdlbmRDb2wgPC0gYygiYmx1ZSIsICJwdXJwbGUiLCAicmVkIikNCg0KIyBSZS1kcmF3IHRoZSBwbG90IGFuZCBsZWdlbmQNCnBsb3RfMjAwNw0KbGVnZW5kKCJ0b3BsZWZ0IiwgbGVnZW5kID0gbGVnZW5kTGFiLA0KICAgICAgIHBjaCA9IGxlZ2VuZFN5bSwgDQogICAgICAgY29sID0gbGVnZW5kQ29sLA0KICAgICAgIGNleCA9IDEsICMgZm9udCBzaXplDQogICAgICAgcHQuY2V4ID0gMS41LCAjIGluY3JlYXNlIHRoZSBzeW1ib2wgc2l6ZQ0KICAgICAgIGJ0eSA9ICJuIikgIyB0dXJuIG9mZiB0aGUgbGVnZW5kIGJvcmRlcg0KDQojIFNhdmUgY2hhbmdlcyB0byBwbG90DQpwbG90XzIwMDcgPC0gcmVjb3JkUGxvdCgpDQpgYGANCg0KIyNBZGRpbmcgYSBTY2FsZSBCYXIgYW5kIE5vcnRoIEFycm93DQoNCk5vdyBsZXQncyBhZGQgc29tZSBmaW5pc2hpbmcgdG91Y2hlcy4gRXZlcnkgZmluaXNoZWQgbWFwIHNob3VsZCBpbmNsdWRlIGEgc2NhbGUgYmFyIGFuZCBub3J0aCBhcnJvdyBhcyByZWZlcmVuY2VzLg0KDQpgYGB7cn0NCiMgTG9hZCB0aGUgcHJldHR5bWFwciBwYWNrYWdlDQpsaWJyYXJ5KHByZXR0eW1hcHIpDQoNCiMgVHJ5IGFkZGluZyB0aGVzZQ0KcGxvdF8yMDA3DQphZGRzY2FsZWJhcigpDQphZGRub3J0aGFycm93KCkNCmBgYA0KDQpUaGUgZGVmYXVsdCBzZXR0aW5ncyBhcmUgbm90IGlkZWFsIGZvciBvdXIgbWFwLiBUaGUgc2NhbGUgYmFyIGFuZCBsZWdlbmQgYXJlIGltcG9ydGFudCwgYnV0IHNob3VsZCBub3QgZGlzdHJhY3QgZnJvbSB0aGUgbWFwLiBMZXQncyBpbnZlc3RpZ2F0ZSBob3cgd2UgY2FuIGN1c3RvbWl6ZSB0aGVzZSBzbyB0aGV5IGF0dHJhY3QgbGVzcyBhdHRlbnRpb24uDQoNCmBgYHtyIGV2YWw9RkFMU0V9DQojIENoZWNrIGhvdyB0byBhZGp1c3QgdGhlIHNjYWxlIGJhciBhbmQgbm9ydGggYXJyb3cNCj9hZGRzY2FsZWJhcg0KP2FkZG5vcnRoYXJyb3cNCmBgYA0KDQpgYGB7cn0NCiMgVHJ5IGFnYWluDQpwbG90XzIwMDcNCmFkZHNjYWxlYmFyKHN0eWxlID0gInRpY2tzIikNCmFkZG5vcnRoYXJyb3coY29scyA9IGMoIndoaXRlIiwgImdyZXk1MCIpLCBzY2FsZSA9IDAuNCkNCiMgU2F2ZSBjaGFuZ2VzIHRvIHBsb3QNCnBsb3RfMjAwNyA8LSByZWNvcmRQbG90KCkNCmBgYA0KDQpbKio8PCBXb3Jrc2hvcCBIb21lKipdKGh0dHBzOi8vY2FmYWhleS5naXRodWIuaW8vc3BhdGlhbCkNCg==