I recently updated RStudio (yeahhhh 1.0.143!) and have been hearing lots about notebook workflow for a while now, so here we are: welcome to my first attempt at making a R Markdown Notebook!

I decided that I would try out the workflow by creating a notebook for a previous project of mine. I landed on the New Yorker caption contest choropleths project since it was one of the most difficult to code for me. I spent lots of time tripping my way through using geodata with R and running (clicking) around in circles on StackOverflow. Moreover, Alaska and Hawaii became the bane of my existence for a few weeks in generating these images. (This post ended up being super useful in the end for dealing with those states. Nathan Yau made a tutorial on this also if you’re curious and a FlowingData member.)

tl;dr Hopefully this notebook can be a useful resource for people who want to make similar US choropleth visuals in R.

First things first: load necessary libraries for the code!

library(maptools);library(mapproj);library(rgeos);library(rgdal);library(RColorBrewer);library(ggplot2);library(choroplethr);library(choroplethrMaps);library(maps);library(scales);library(grid);library(gridExtra);library(ggthemes);library(BAMMtools)

Then, I define the theme that I like to use for my plots.

I will call this in a later chunk.

my_theme <- function() {
  # Define colors for the chart
  palette <- brewer.pal("Greys", n=9)
  color.background = palette[1]
  color.grid.major = palette[1]
  color.panel = palette[1]
  color.axis.text = palette[9]
  color.axis.title = palette[9]
  color.title = palette[9]
  # Create basic construction of chart
  theme_bw(base_size=7, base_family="Georgia") + 
  # Set the entire chart region to a light gray color
  theme(panel.background=element_rect(fill=color.panel, color=color.background)) +
  theme(plot.background=element_rect(fill=color.background, color=color.background)) +
  theme(panel.border=element_rect(color=color.background)) +
  # Format grid
  theme(panel.grid.major=element_line(color=color.grid.major,size=.25)) +
  theme(panel.grid.minor=element_blank()) +
  theme(axis.ticks=element_blank()) +
  # Format legend
  theme(legend.position="right") +
  theme(legend.background = element_rect(fill=color.panel)) +
  theme(legend.text = element_text(size=12,color=color.axis.title)) + 
  # Format title and axes labels these and tick marks
  theme(plot.title=element_text(color=color.title, size=18, vjust=0.5, hjust=0, face="bold")) +
  theme(axis.text.x=element_text(size=0,color=color.axis.text)) +
  theme(axis.text.y=element_text(size=0,color=color.axis.text)) +
  theme(axis.title.x=element_text(size=12,color=color.axis.title, vjust=-1, face="italic")) +
  theme(axis.title.y=element_text(size=0,color=color.axis.title, vjust=1.8, face="italic")) +
  # Plot margins
  theme(plot.margin = unit(c(.5, .5, .5, .5), "cm"))
}

Now, we get into getting all the geo data in shape to make something with it!

I call the geojson in my data folder for grabbing the important layer to manipulate. State IDs of 2 and 15 for Alaska and Hawaii are from Census source.

setwd("data")
us <- readOGR(dsn="usa_alex_2.geojson", layer="OGRGeoJSON")
OGR data source with driver: GeoJSON 
Source: "usa_alex_2.geojson", layer: "OGRGeoJSON"
with 51 features
It has 9 fields
us_aea <- spTransform(us, CRS("+proj=laea +lat_0=45 +lon_0=-100 +x_0=0 +y_0=0 +a=6370997 +b=6370997 +units=m +no_defs"))
us_aea@data$id <- rownames(us_aea@data)
# extract, then rotate, shrink & move alaska (and reset projection)
alaska <- us_aea[us_aea$STATEFP=="02",]
alaska <- elide(alaska, rotate=-50)
alaska <- elide(alaska, scale=max(apply(bbox(alaska), 1, diff)) / 2.3)
alaska <- elide(alaska, shift=c(-2100000, -2500000))
proj4string(alaska) <- proj4string(us_aea)
# extract, then rotate & shift hawaii
hawaii <- us_aea[us_aea$STATEFP=="15",]
hawaii <- elide(hawaii, rotate=-35)
hawaii <- elide(hawaii, shift=c(5400000, -1700000))
proj4string(hawaii) <- proj4string(us_aea)
# remove old states and put new ones back in; note the different order
us_aea <- us_aea[!us_aea$STATEFP %in% c("02", "15", "72"),]
us_aea <- rbind(us_aea, alaska, hawaii)

Now that we have the data in shape. We can now get to generating each of the three images in the article.

First off, I see how absolute wins are distributed across the country:

#let's plot the number of winners!
data<-read.csv("data/winners_new.csv", header=TRUE)
fips<-read.csv("data/fips.csv",header=T)
merge<-merge(data,fips,by.x="winnerstate",by.y="state")
merge$id <- sprintf("%02d", as.numeric(as.character(merge$fips)))
# get ready for ggplotting it... this takes a couple of seconds
map <- fortify(us_aea, region="GEOID")
#using Jenks natural breaks classification method!
q=getJenksBreaks(merge$n, 10, subset = NULL)
merge$value.binned = cut(merge$n,breaks=q,include.lowest=TRUE)
# plot it
gg <- ggplot()
gg <- gg + geom_map(data=map, map=map,
                    aes(x=long, y=lat, map_id=id, group=group),
                    fill="#ffffff", color="#0e0e0e", size=0.15)
gg <- gg + geom_map(data=merge, map=map, aes(map_id=id, fill=value.binned),
                    color="#0e0e0e", size=0.15)
gg <- gg + scale_fill_brewer(type="div",palette="YlGnBu",name="Number of\nWinners") +              # change fill colors
  guides(fill=guide_legend(override.aes = list(colour = NULL)))
gg <- gg + my_theme()
gg <- gg + ggtitle(expression(bold(paste("The United States of the ", bolditalic("New Yorker "), bold("Caption Contest: Total Wins")))))
gg <- gg + theme(plot.title = element_text(size = 18, face = "bold", colour = "black", vjust = 0.5, hjust=0.5), legend.title=element_text(size=12),legend.key = element_rect(colour = "black"))  
gg <- gg + coord_equal() +xlab("Data via the New Yorker Caption Contest Archive & Cartoon Editor Bob Mankoff | Visualization via Alex Albright (thelittledataset.com)")
gg

However, it could be that states who win the most are simply submitting the most. So, I illustrate how submission numbers look across the country:

#let's plot submissions now!
data<-read.csv("data/subs.csv", header=TRUE)
df<-data.frame(state.abb,state.name)
merge<-merge(data,df,by.x="State",by.y="state.abb")
fips<-read.csv("data/fips.csv",header=T)
merge<-merge(merge,fips,by.x="state.name",by.y="state")
merge$id <- sprintf("%02d", as.numeric(as.character(merge$fips)))
merge$count1<-merge$numsubs/1000
# get ready for ggplotting it
map <- fortify(us_aea, region="GEOID")
#using Jenks natural breaks classification method!
q=getJenksBreaks(merge$count1, 10, subset = NULL)
merge$value.binned = cut(merge$count1,breaks=q,include.lowest=TRUE)
# plot it
gg <- ggplot()
gg <- gg + geom_map(data=map, map=map,
                    aes(x=long, y=lat, map_id=id, group=group),
                    fill="#ffffff", color="#0e0e0e", size=0.15)
gg <- gg + geom_map(data=merge, map=map, aes(map_id=id, fill=value.binned),
                    color="#0e0e0e", size=0.15)
gg <- gg + scale_fill_brewer(type="div",palette="YlGnBu",name="Thousands of\nSubmissions") +              # change fill colors
  guides(fill=guide_legend(override.aes = list(colour = NULL)))
gg <- gg + my_theme()
gg <- gg + ggtitle(expression(bold(paste("The United States of the ", bolditalic("New Yorker "), bold("Caption Contest: Thousands of Submissions")))))
gg <- gg + theme(plot.title = element_text(size = 18, face = "bold", colour = "black", vjust = 0.5, hjust=0.5), legend.title=element_text(size=12),legend.key = element_rect(colour = "black"))  
gg <- gg + coord_equal() +xlab("Data via the New Yorker Caption Contest Archive & Cartoon Editor Bob Mankoff | Visualization via Alex Albright (thelittledataset.com)")
gg

Based on the wins and submissions numbers, one metric of success could be wins per 10K submission (think of this as a state batting average for caption contest success):

#let's plot wins per 10k submissions!
data1<-read.csv("data/winners_new.csv", header=TRUE)
data1$region<-tolower(data1$winnerstate)
data2<-read.csv("data/subs.csv", header=TRUE)
df<-data.frame(state.abb,state.name)
data2<-merge(data2,df,by.x="State",by.y="state.abb")
data2$region<-tolower(data2$state.name)
data2$sub<-as.numeric(data2$numsubs/10000)
merge<-merge(data1,data2,by="region")
merge$winspsub<-merge$n/merge$sub
fips<-read.csv("data/fips.csv",header=T)
merge<-merge(merge,fips,by.x="state.name",by.y="state")
merge$id <- sprintf("%02d", as.numeric(as.character(merge$fips)))
# get ready for ggplotting it...
map <- fortify(us_aea, region="GEOID")
#jenks again!
q=unique(getJenksBreaks(merge$winspsub, 10, subset = NULL))
merge$value.binned = cut(merge$winspsub,breaks=q,include.lowest=TRUE)
# plot it
gg <- ggplot()
gg <- gg + geom_map(data=map, map=map,
                    aes(x=long, y=lat, map_id=id, group=group),
                    fill="#ffffff", color="#0e0e0e", size=0.15)
gg <- gg + geom_map(data=merge, map=map, aes(map_id=id, fill=value.binned),
                    color="#0e0e0e", size=0.15)
gg <- gg + scale_fill_brewer(type="div",palette="YlGnBu",name="Wins per 10K\n Submissions") +              # change fill colors
  guides(fill=guide_legend(override.aes = list(colour = NULL)))
gg <- gg + my_theme()
gg <- gg + ggtitle(expression(bold(paste("The United States of the ", bolditalic("New Yorker "), bold("Caption Contest: Wins Per 10 Thousand Submissions")))))
gg <- gg + theme(plot.title = element_text(size = 18, face = "bold", colour = "black", vjust = 0.5, hjust=0.5), legend.title=element_text(size=12),legend.key = element_rect(colour = "black"))  
gg <- gg + coord_equal() +xlab("Data via the New Yorker Caption Contest Archive & Cartoon Editor Bob Mankoff | Visualization via Alex Albright (thelittledataset.com)")
gg

The above leads to the following conclusion from the article: This map shows that Alaska is actually the most successful state in terms of wins per ten thousand submissions. Though Alaska has only won the contest twice, the fact that it had a mere twenty-one hundred and two documented contest entries renders its rate of approximately 9.5 wins per ten thousand submissions the highest in the country. Mississippi, another state not commonly associated with the New Yorker crowd, comes in at a close second, with 8.14 wins per ten thousand submissions. Beyond Alaska and Mississippi, the other states in the top ten with respect to this metric are Hawaii, Utah, Oklahoma, Illinois, Virginia, Kentucky, Vermont, and Connecticut. Only three of these ten were in the Top Ten in terms of the total win count—namely, Illinois, Virginia, and Connecticut.

Therefore, after all that discussions about the mores of the cultural élite and familiarity with New Yorker-esque sensibilities, it’s not the states saturated with Prius-driving soccer fans that are the most successful caption-contest competitors. Instead, the most successful states are scattered across the country, no longer confined to the coasts, and the ultimate winner is able to see Russia from its house.

So, that is how to generate those three graphs.

This has been an R Markdown Notebook!

The End.

LS0tCnRpdGxlOiAnQmFieScncyBGaXJzdCBSIE1hcmtkb3duIE5vdGVib29rOiAqTmV3IFlvcmtlciogQ2FwdGlvbiBDb250ZXN0IENob3JvcGxldGhzCiAgRXhhbXBsZScKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKLS0tCgpJIHJlY2VudGx5IHVwZGF0ZWQgUlN0dWRpbyAqKHllYWhoaGggMS4wLjE0MyEpKiBhbmQgaGF2ZSBiZWVuIGhlYXJpbmcgbG90cyBhYm91dCBub3RlYm9vayB3b3JrZmxvdyBmb3IgYSB3aGlsZSBub3csIHNvIGhlcmUgd2UgYXJlOiB3ZWxjb21lIHRvIG15IGZpcnN0IGF0dGVtcHQgYXQgbWFraW5nIGEgW1IgTWFya2Rvd25dKGh0dHA6Ly9ybWFya2Rvd24ucnN0dWRpby5jb20pIE5vdGVib29rISAKCkkgZGVjaWRlZCB0aGF0IEkgd291bGQgdHJ5IG91dCB0aGUgd29ya2Zsb3cgYnkgY3JlYXRpbmcgYSBub3RlYm9vayBmb3IgYSBwcmV2aW91cyBwcm9qZWN0IG9mIG1pbmUuIEkgbGFuZGVkIG9uIHRoZSBbKk5ldyBZb3JrZXIqIGNhcHRpb24gY29udGVzdCBjaG9yb3BsZXRocyBwcm9qZWN0XShodHRwOi8vd3d3Lm5ld3lvcmtlci5jb20vY3VsdHVyZS9jdWx0dXJlLWRlc2svd2hpY2gtdS1zLXN0YXRlLXBlcmZvcm1zLWJlc3QtaW4tdGhlLW5ldy15b3JrZXItY2FwdGlvbi1jb250ZXN0KSBzaW5jZSBpdCB3YXMgb25lIG9mIHRoZSBtb3N0IGRpZmZpY3VsdCB0byBjb2RlIGZvciBtZS4gSSBzcGVudCBsb3RzIG9mIHRpbWUgdHJpcHBpbmcgbXkgd2F5IHRocm91Z2ggdXNpbmcgZ2VvZGF0YSB3aXRoIFIgYW5kIHJ1bm5pbmcgKGNsaWNraW5nKSBhcm91bmQgaW4gY2lyY2xlcyBvbiBTdGFja092ZXJmbG93LiBNb3Jlb3ZlciwgQWxhc2thIGFuZCBIYXdhaWkgYmVjYW1lIHRoZSBiYW5lIG9mIG15IGV4aXN0ZW5jZSBmb3IgYSBmZXcgd2Vla3MgaW4gZ2VuZXJhdGluZyB0aGVzZSBpbWFnZXMuIChbVGhpcyBwb3N0XShodHRwOi8vd3d3LnItYmxvZ2dlcnMuY29tL21vdmluZy10aGUtZWFydGgtd2VsbC1hbGFza2EtaGF3YWlpLXdpdGgtci8pIGVuZGVkIHVwIGJlaW5nIHN1cGVyIHVzZWZ1bCBpbiB0aGUgZW5kIGZvciBkZWFsaW5nIHdpdGggdGhvc2Ugc3RhdGVzLiBOYXRoYW4gWWF1IG1hZGUgW2EgdHV0b3JpYWxdKGh0dHA6Ly9mbG93aW5nZGF0YS5jb20vMjAxNS8wOS8wMS9ob3ctdG8tbWFrZS1tYXBzLWluLXItdGhhdC1pbmNsdWRlLWFsYXNrYS1hbmQtaGF3YWlpLykgb24gdGhpcyBhbHNvIGlmIHlvdSdyZSBjdXJpb3VzIGFuZCBhIEZsb3dpbmdEYXRhIG1lbWJlci4pCgojIyMgdGw7ZHIgSG9wZWZ1bGx5IHRoaXMgbm90ZWJvb2sgY2FuIGJlIGEgdXNlZnVsIHJlc291cmNlIGZvciBwZW9wbGUgd2hvIHdhbnQgdG8gbWFrZSBzaW1pbGFyIFVTIGNob3JvcGxldGggdmlzdWFscyBpbiBSLgoKIyBGaXJzdCB0aGluZ3MgZmlyc3Q6IGxvYWQgbmVjZXNzYXJ5IGxpYnJhcmllcyBmb3IgdGhlIGNvZGUhCmBgYHtyIGxvYWRpbmcgbGlicmFyaWVzLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBpbmNsdWRlPVRSVUV9CmxpYnJhcnkobWFwdG9vbHMpO2xpYnJhcnkobWFwcHJvaik7bGlicmFyeShyZ2Vvcyk7bGlicmFyeShyZ2RhbCk7bGlicmFyeShSQ29sb3JCcmV3ZXIpO2xpYnJhcnkoZ2dwbG90Mik7bGlicmFyeShjaG9yb3BsZXRocik7bGlicmFyeShjaG9yb3BsZXRock1hcHMpO2xpYnJhcnkobWFwcyk7bGlicmFyeShzY2FsZXMpO2xpYnJhcnkoZ3JpZCk7bGlicmFyeShncmlkRXh0cmEpO2xpYnJhcnkoZ2d0aGVtZXMpO2xpYnJhcnkoQkFNTXRvb2xzKQpgYGAKCiMjIFRoZW4sIEkgZGVmaW5lIHRoZSB0aGVtZSB0aGF0IEkgbGlrZSB0byB1c2UgZm9yIG15IHBsb3RzLgpJIHdpbGwgY2FsbCB0aGlzIGluIGEgbGF0ZXIgY2h1bmsuCmBgYHtyIGRlZmluZSB0aGVtZSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbXlfdGhlbWUgPC0gZnVuY3Rpb24oKSB7CgogICMgRGVmaW5lIGNvbG9ycyBmb3IgdGhlIGNoYXJ0CiAgcGFsZXR0ZSA8LSBicmV3ZXIucGFsKCJHcmV5cyIsIG49OSkKICBjb2xvci5iYWNrZ3JvdW5kID0gcGFsZXR0ZVsxXQogIGNvbG9yLmdyaWQubWFqb3IgPSBwYWxldHRlWzFdCiAgY29sb3IucGFuZWwgPSBwYWxldHRlWzFdCiAgY29sb3IuYXhpcy50ZXh0ID0gcGFsZXR0ZVs5XQogIGNvbG9yLmF4aXMudGl0bGUgPSBwYWxldHRlWzldCiAgY29sb3IudGl0bGUgPSBwYWxldHRlWzldCgogICMgQ3JlYXRlIGJhc2ljIGNvbnN0cnVjdGlvbiBvZiBjaGFydAogIHRoZW1lX2J3KGJhc2Vfc2l6ZT03LCBiYXNlX2ZhbWlseT0iR2VvcmdpYSIpICsgCgogICMgU2V0IHRoZSBlbnRpcmUgY2hhcnQgcmVnaW9uIHRvIGEgbGlnaHQgZ3JheSBjb2xvcgogIHRoZW1lKHBhbmVsLmJhY2tncm91bmQ9ZWxlbWVudF9yZWN0KGZpbGw9Y29sb3IucGFuZWwsIGNvbG9yPWNvbG9yLmJhY2tncm91bmQpKSArCiAgdGhlbWUocGxvdC5iYWNrZ3JvdW5kPWVsZW1lbnRfcmVjdChmaWxsPWNvbG9yLmJhY2tncm91bmQsIGNvbG9yPWNvbG9yLmJhY2tncm91bmQpKSArCiAgdGhlbWUocGFuZWwuYm9yZGVyPWVsZW1lbnRfcmVjdChjb2xvcj1jb2xvci5iYWNrZ3JvdW5kKSkgKwoKICAjIEZvcm1hdCBncmlkCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvcj1lbGVtZW50X2xpbmUoY29sb3I9Y29sb3IuZ3JpZC5tYWpvcixzaXplPS4yNSkpICsKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yPWVsZW1lbnRfYmxhbmsoKSkgKwogIHRoZW1lKGF4aXMudGlja3M9ZWxlbWVudF9ibGFuaygpKSArCgogICMgRm9ybWF0IGxlZ2VuZAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0icmlnaHQiKSArCiAgdGhlbWUobGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD1jb2xvci5wYW5lbCkpICsKICB0aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTEyLGNvbG9yPWNvbG9yLmF4aXMudGl0bGUpKSArIAoKICAjIEZvcm1hdCB0aXRsZSBhbmQgYXhlcyBsYWJlbHMgdGhlc2UgYW5kIHRpY2sgbWFya3MKICB0aGVtZShwbG90LnRpdGxlPWVsZW1lbnRfdGV4dChjb2xvcj1jb2xvci50aXRsZSwgc2l6ZT0xOCwgdmp1c3Q9MC41LCBoanVzdD0wLCBmYWNlPSJib2xkIikpICsKICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoc2l6ZT0wLGNvbG9yPWNvbG9yLmF4aXMudGV4dCkpICsKICB0aGVtZShheGlzLnRleHQueT1lbGVtZW50X3RleHQoc2l6ZT0wLGNvbG9yPWNvbG9yLmF4aXMudGV4dCkpICsKICB0aGVtZShheGlzLnRpdGxlLng9ZWxlbWVudF90ZXh0KHNpemU9MTIsY29sb3I9Y29sb3IuYXhpcy50aXRsZSwgdmp1c3Q9LTEsIGZhY2U9Iml0YWxpYyIpKSArCiAgdGhlbWUoYXhpcy50aXRsZS55PWVsZW1lbnRfdGV4dChzaXplPTAsY29sb3I9Y29sb3IuYXhpcy50aXRsZSwgdmp1c3Q9MS44LCBmYWNlPSJpdGFsaWMiKSkgKwoKICAjIFBsb3QgbWFyZ2lucwogIHRoZW1lKHBsb3QubWFyZ2luID0gdW5pdChjKC41LCAuNSwgLjUsIC41KSwgImNtIikpCn0KYGBgCiMjIE5vdywgd2UgZ2V0IGludG8gZ2V0dGluZyBhbGwgdGhlIGdlbyBkYXRhIGluIHNoYXBlIHRvIG1ha2Ugc29tZXRoaW5nIHdpdGggaXQhCkkgY2FsbCB0aGUgZ2VvanNvbiBpbiBteSBkYXRhIGZvbGRlciBmb3IgZ3JhYmJpbmcgdGhlIGltcG9ydGFudCBsYXllciB0byBtYW5pcHVsYXRlLiBTdGF0ZSBJRHMgb2YgMiBhbmQgMTUgZm9yIEFsYXNrYSBhbmQgSGF3YWlpIGFyZSBmcm9tIFtDZW5zdXMgc291cmNlXShodHRwczovL3d3dy5jZW5zdXMuZ292L2dlby9yZWZlcmVuY2UvYW5zaV9zdGF0ZXRhYmxlcy5odG1sKS4KYGBge3IgY2FsbCBkYXRhL2Zvcm1hdCBnZW9kYXRhLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpzZXR3ZCgiZGF0YSIpCnVzIDwtIHJlYWRPR1IoZHNuPSJ1c2FfYWxleF8yLmdlb2pzb24iLCBsYXllcj0iT0dSR2VvSlNPTiIpCgp1c19hZWEgPC0gc3BUcmFuc2Zvcm0odXMsIENSUygiK3Byb2o9bGFlYSArbGF0XzA9NDUgK2xvbl8wPS0xMDAgK3hfMD0wICt5XzA9MCArYT02MzcwOTk3ICtiPTYzNzA5OTcgK3VuaXRzPW0gK25vX2RlZnMiKSkKdXNfYWVhQGRhdGEkaWQgPC0gcm93bmFtZXModXNfYWVhQGRhdGEpCgojIGV4dHJhY3QsIHRoZW4gcm90YXRlLCBzaHJpbmsgJiBtb3ZlIGFsYXNrYSAoYW5kIHJlc2V0IHByb2plY3Rpb24pCmFsYXNrYSA8LSB1c19hZWFbdXNfYWVhJFNUQVRFRlA9PSIwMiIsXQphbGFza2EgPC0gZWxpZGUoYWxhc2thLCByb3RhdGU9LTUwKQphbGFza2EgPC0gZWxpZGUoYWxhc2thLCBzY2FsZT1tYXgoYXBwbHkoYmJveChhbGFza2EpLCAxLCBkaWZmKSkgLyAyLjMpCmFsYXNrYSA8LSBlbGlkZShhbGFza2EsIHNoaWZ0PWMoLTIxMDAwMDAsIC0yNTAwMDAwKSkKcHJvajRzdHJpbmcoYWxhc2thKSA8LSBwcm9qNHN0cmluZyh1c19hZWEpCgojIGV4dHJhY3QsIHRoZW4gcm90YXRlICYgc2hpZnQgaGF3YWlpCmhhd2FpaSA8LSB1c19hZWFbdXNfYWVhJFNUQVRFRlA9PSIxNSIsXQpoYXdhaWkgPC0gZWxpZGUoaGF3YWlpLCByb3RhdGU9LTM1KQpoYXdhaWkgPC0gZWxpZGUoaGF3YWlpLCBzaGlmdD1jKDU0MDAwMDAsIC0xNzAwMDAwKSkKcHJvajRzdHJpbmcoaGF3YWlpKSA8LSBwcm9qNHN0cmluZyh1c19hZWEpCgojIHJlbW92ZSBvbGQgc3RhdGVzIGFuZCBwdXQgbmV3IG9uZXMgYmFjayBpbjsgbm90ZSB0aGUgZGlmZmVyZW50IG9yZGVyCnVzX2FlYSA8LSB1c19hZWFbIXVzX2FlYSRTVEFURUZQICVpbiUgYygiMDIiLCAiMTUiLCAiNzIiKSxdCnVzX2FlYSA8LSByYmluZCh1c19hZWEsIGFsYXNrYSwgaGF3YWlpKQpgYGAKCiMjIyBOb3cgdGhhdCB3ZSBoYXZlIHRoZSBkYXRhIGluIHNoYXBlLiBXZSBjYW4gbm93IGdldCB0byBnZW5lcmF0aW5nIGVhY2ggb2YgdGhlIHRocmVlIGltYWdlcyBpbiB0aGUgYXJ0aWNsZS4gCgojIEZpcnN0IG9mZiwgSSBzZWUgaG93IGFic29sdXRlIHdpbnMgYXJlIGRpc3RyaWJ1dGVkIGFjcm9zcyB0aGUgY291bnRyeToKCmBgYHtyIHBsb3QgdG90YWwgd2lucywgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9NiwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KI2xldCdzIHBsb3QgdGhlIG51bWJlciBvZiB3aW5uZXJzIQpkYXRhPC1yZWFkLmNzdigiZGF0YS93aW5uZXJzX25ldy5jc3YiLCBoZWFkZXI9VFJVRSkKZmlwczwtcmVhZC5jc3YoImRhdGEvZmlwcy5jc3YiLGhlYWRlcj1UKQptZXJnZTwtbWVyZ2UoZGF0YSxmaXBzLGJ5Lng9Indpbm5lcnN0YXRlIixieS55PSJzdGF0ZSIpCm1lcmdlJGlkIDwtIHNwcmludGYoIiUwMmQiLCBhcy5udW1lcmljKGFzLmNoYXJhY3RlcihtZXJnZSRmaXBzKSkpCgojIGdldCByZWFkeSBmb3IgZ2dwbG90dGluZyBpdC4uLiB0aGlzIHRha2VzIGEgY291cGxlIG9mIHNlY29uZHMKbWFwIDwtIGZvcnRpZnkodXNfYWVhLCByZWdpb249IkdFT0lEIikKCiN1c2luZyBKZW5rcyBuYXR1cmFsIGJyZWFrcyBjbGFzc2lmaWNhdGlvbiBtZXRob2QhCnE9Z2V0SmVua3NCcmVha3MobWVyZ2UkbiwgMTAsIHN1YnNldCA9IE5VTEwpCm1lcmdlJHZhbHVlLmJpbm5lZCA9IGN1dChtZXJnZSRuLGJyZWFrcz1xLGluY2x1ZGUubG93ZXN0PVRSVUUpCgojIHBsb3QgaXQKZ2cgPC0gZ2dwbG90KCkKZ2cgPC0gZ2cgKyBnZW9tX21hcChkYXRhPW1hcCwgbWFwPW1hcCwKICAgICAgICAgICAgICAgICAgICBhZXMoeD1sb25nLCB5PWxhdCwgbWFwX2lkPWlkLCBncm91cD1ncm91cCksCiAgICAgICAgICAgICAgICAgICAgZmlsbD0iI2ZmZmZmZiIsIGNvbG9yPSIjMGUwZTBlIiwgc2l6ZT0wLjE1KQpnZyA8LSBnZyArIGdlb21fbWFwKGRhdGE9bWVyZ2UsIG1hcD1tYXAsIGFlcyhtYXBfaWQ9aWQsIGZpbGw9dmFsdWUuYmlubmVkKSwKICAgICAgICAgICAgICAgICAgICBjb2xvcj0iIzBlMGUwZSIsIHNpemU9MC4xNSkKZ2cgPC0gZ2cgKyBzY2FsZV9maWxsX2JyZXdlcih0eXBlPSJkaXYiLHBhbGV0dGU9IllsR25CdSIsbmFtZT0iTnVtYmVyIG9mXG5XaW5uZXJzIikgKyAgICAgICAgICAgICAgIyBjaGFuZ2UgZmlsbCBjb2xvcnMKICBndWlkZXMoZmlsbD1ndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChjb2xvdXIgPSBOVUxMKSkpCmdnIDwtIGdnICsgbXlfdGhlbWUoKQpnZyA8LSBnZyArIGdndGl0bGUoZXhwcmVzc2lvbihib2xkKHBhc3RlKCJUaGUgVW5pdGVkIFN0YXRlcyBvZiB0aGUgIiwgYm9sZGl0YWxpYygiTmV3IFlvcmtlciAiKSwgYm9sZCgiQ2FwdGlvbiBDb250ZXN0OiBUb3RhbCBXaW5zIikpKSkpCmdnIDwtIGdnICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgsIGZhY2UgPSAiYm9sZCIsIGNvbG91ciA9ICJibGFjayIsIHZqdXN0ID0gMC41LCBoanVzdD0wLjUpLCBsZWdlbmQudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTIpLGxlZ2VuZC5rZXkgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImJsYWNrIikpICAKZ2cgPC0gZ2cgKyBjb29yZF9lcXVhbCgpICt4bGFiKCJEYXRhIHZpYSB0aGUgTmV3IFlvcmtlciBDYXB0aW9uIENvbnRlc3QgQXJjaGl2ZSAmIENhcnRvb24gRWRpdG9yIEJvYiBNYW5rb2ZmIHwgVmlzdWFsaXphdGlvbiB2aWEgQWxleCBBbGJyaWdodCAodGhlbGl0dGxlZGF0YXNldC5jb20pIikKZ2cKYGBgCgojIEhvd2V2ZXIsIGl0IGNvdWxkIGJlIHRoYXQgc3RhdGVzIHdobyB3aW4gdGhlIG1vc3QgYXJlIHNpbXBseSBzdWJtaXR0aW5nIHRoZSBtb3N0LiBTbywgSSBpbGx1c3RyYXRlIGhvdyBzdWJtaXNzaW9uIG51bWJlcnMgbG9vayBhY3Jvc3MgdGhlIGNvdW50cnk6CgoKYGBge3IgcGxvdCBzdWJtaXNzaW9ucywgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9NiwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KI2xldCdzIHBsb3Qgc3VibWlzc2lvbnMgbm93IQpkYXRhPC1yZWFkLmNzdigiZGF0YS9zdWJzLmNzdiIsIGhlYWRlcj1UUlVFKQpkZjwtZGF0YS5mcmFtZShzdGF0ZS5hYmIsc3RhdGUubmFtZSkKbWVyZ2U8LW1lcmdlKGRhdGEsZGYsYnkueD0iU3RhdGUiLGJ5Lnk9InN0YXRlLmFiYiIpCmZpcHM8LXJlYWQuY3N2KCJkYXRhL2ZpcHMuY3N2IixoZWFkZXI9VCkKbWVyZ2U8LW1lcmdlKG1lcmdlLGZpcHMsYnkueD0ic3RhdGUubmFtZSIsYnkueT0ic3RhdGUiKQptZXJnZSRpZCA8LSBzcHJpbnRmKCIlMDJkIiwgYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIobWVyZ2UkZmlwcykpKQptZXJnZSRjb3VudDE8LW1lcmdlJG51bXN1YnMvMTAwMAoKIyBnZXQgcmVhZHkgZm9yIGdncGxvdHRpbmcgaXQKbWFwIDwtIGZvcnRpZnkodXNfYWVhLCByZWdpb249IkdFT0lEIikKCiN1c2luZyBKZW5rcyBuYXR1cmFsIGJyZWFrcyBjbGFzc2lmaWNhdGlvbiBtZXRob2QhCnE9Z2V0SmVua3NCcmVha3MobWVyZ2UkY291bnQxLCAxMCwgc3Vic2V0ID0gTlVMTCkKbWVyZ2UkdmFsdWUuYmlubmVkID0gY3V0KG1lcmdlJGNvdW50MSxicmVha3M9cSxpbmNsdWRlLmxvd2VzdD1UUlVFKQoKIyBwbG90IGl0CmdnIDwtIGdncGxvdCgpCmdnIDwtIGdnICsgZ2VvbV9tYXAoZGF0YT1tYXAsIG1hcD1tYXAsCiAgICAgICAgICAgICAgICAgICAgYWVzKHg9bG9uZywgeT1sYXQsIG1hcF9pZD1pZCwgZ3JvdXA9Z3JvdXApLAogICAgICAgICAgICAgICAgICAgIGZpbGw9IiNmZmZmZmYiLCBjb2xvcj0iIzBlMGUwZSIsIHNpemU9MC4xNSkKZ2cgPC0gZ2cgKyBnZW9tX21hcChkYXRhPW1lcmdlLCBtYXA9bWFwLCBhZXMobWFwX2lkPWlkLCBmaWxsPXZhbHVlLmJpbm5lZCksCiAgICAgICAgICAgICAgICAgICAgY29sb3I9IiMwZTBlMGUiLCBzaXplPTAuMTUpCmdnIDwtIGdnICsgc2NhbGVfZmlsbF9icmV3ZXIodHlwZT0iZGl2IixwYWxldHRlPSJZbEduQnUiLG5hbWU9IlRob3VzYW5kcyBvZlxuU3VibWlzc2lvbnMiKSArICAgICAgICAgICAgICAjIGNoYW5nZSBmaWxsIGNvbG9ycwogIGd1aWRlcyhmaWxsPWd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KGNvbG91ciA9IE5VTEwpKSkKZ2cgPC0gZ2cgKyBteV90aGVtZSgpCmdnIDwtIGdnICsgZ2d0aXRsZShleHByZXNzaW9uKGJvbGQocGFzdGUoIlRoZSBVbml0ZWQgU3RhdGVzIG9mIHRoZSAiLCBib2xkaXRhbGljKCJOZXcgWW9ya2VyICIpLCBib2xkKCJDYXB0aW9uIENvbnRlc3Q6IFRob3VzYW5kcyBvZiBTdWJtaXNzaW9ucyIpKSkpKQpnZyA8LSBnZyArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4LCBmYWNlID0gImJvbGQiLCBjb2xvdXIgPSAiYmxhY2siLCB2anVzdCA9IDAuNSwgaGp1c3Q9MC41KSwgbGVnZW5kLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTEyKSxsZWdlbmQua2V5ID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJibGFjayIpKSAgCmdnIDwtIGdnICsgY29vcmRfZXF1YWwoKSAreGxhYigiRGF0YSB2aWEgdGhlIE5ldyBZb3JrZXIgQ2FwdGlvbiBDb250ZXN0IEFyY2hpdmUgJiBDYXJ0b29uIEVkaXRvciBCb2IgTWFua29mZiB8IFZpc3VhbGl6YXRpb24gdmlhIEFsZXggQWxicmlnaHQgKHRoZWxpdHRsZWRhdGFzZXQuY29tKSIpCmdnCmBgYAoKIyBCYXNlZCBvbiB0aGUgd2lucyBhbmQgc3VibWlzc2lvbnMgbnVtYmVycywgb25lIG1ldHJpYyBvZiBzdWNjZXNzIGNvdWxkIGJlIHdpbnMgcGVyIDEwSyBzdWJtaXNzaW9uICoodGhpbmsgb2YgdGhpcyBhcyBhIHN0YXRlIGJhdHRpbmcgYXZlcmFnZSBmb3IgY2FwdGlvbiBjb250ZXN0IHN1Y2Nlc3MpKjoKCmBgYHtyIHBsb3Qgd2lucyBwZXIgMTBrIHN1Ym1pc3Npb25zLCBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD02LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojbGV0J3MgcGxvdCB3aW5zIHBlciAxMGsgc3VibWlzc2lvbnMhCmRhdGExPC1yZWFkLmNzdigiZGF0YS93aW5uZXJzX25ldy5jc3YiLCBoZWFkZXI9VFJVRSkKZGF0YTEkcmVnaW9uPC10b2xvd2VyKGRhdGExJHdpbm5lcnN0YXRlKQpkYXRhMjwtcmVhZC5jc3YoImRhdGEvc3Vicy5jc3YiLCBoZWFkZXI9VFJVRSkKZGY8LWRhdGEuZnJhbWUoc3RhdGUuYWJiLHN0YXRlLm5hbWUpCmRhdGEyPC1tZXJnZShkYXRhMixkZixieS54PSJTdGF0ZSIsYnkueT0ic3RhdGUuYWJiIikKZGF0YTIkcmVnaW9uPC10b2xvd2VyKGRhdGEyJHN0YXRlLm5hbWUpCmRhdGEyJHN1YjwtYXMubnVtZXJpYyhkYXRhMiRudW1zdWJzLzEwMDAwKQptZXJnZTwtbWVyZ2UoZGF0YTEsZGF0YTIsYnk9InJlZ2lvbiIpCm1lcmdlJHdpbnNwc3ViPC1tZXJnZSRuL21lcmdlJHN1YgpmaXBzPC1yZWFkLmNzdigiZGF0YS9maXBzLmNzdiIsaGVhZGVyPVQpCm1lcmdlPC1tZXJnZShtZXJnZSxmaXBzLGJ5Lng9InN0YXRlLm5hbWUiLGJ5Lnk9InN0YXRlIikKbWVyZ2UkaWQgPC0gc3ByaW50ZigiJTAyZCIsIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKG1lcmdlJGZpcHMpKSkKCiMgZ2V0IHJlYWR5IGZvciBnZ3Bsb3R0aW5nIGl0Li4uCm1hcCA8LSBmb3J0aWZ5KHVzX2FlYSwgcmVnaW9uPSJHRU9JRCIpCgojamVua3MgYWdhaW4hCnE9dW5pcXVlKGdldEplbmtzQnJlYWtzKG1lcmdlJHdpbnNwc3ViLCAxMCwgc3Vic2V0ID0gTlVMTCkpCm1lcmdlJHZhbHVlLmJpbm5lZCA9IGN1dChtZXJnZSR3aW5zcHN1YixicmVha3M9cSxpbmNsdWRlLmxvd2VzdD1UUlVFKQoKIyBwbG90IGl0CmdnIDwtIGdncGxvdCgpCmdnIDwtIGdnICsgZ2VvbV9tYXAoZGF0YT1tYXAsIG1hcD1tYXAsCiAgICAgICAgICAgICAgICAgICAgYWVzKHg9bG9uZywgeT1sYXQsIG1hcF9pZD1pZCwgZ3JvdXA9Z3JvdXApLAogICAgICAgICAgICAgICAgICAgIGZpbGw9IiNmZmZmZmYiLCBjb2xvcj0iIzBlMGUwZSIsIHNpemU9MC4xNSkKZ2cgPC0gZ2cgKyBnZW9tX21hcChkYXRhPW1lcmdlLCBtYXA9bWFwLCBhZXMobWFwX2lkPWlkLCBmaWxsPXZhbHVlLmJpbm5lZCksCiAgICAgICAgICAgICAgICAgICAgY29sb3I9IiMwZTBlMGUiLCBzaXplPTAuMTUpCmdnIDwtIGdnICsgc2NhbGVfZmlsbF9icmV3ZXIodHlwZT0iZGl2IixwYWxldHRlPSJZbEduQnUiLG5hbWU9IldpbnMgcGVyIDEwS1xuIFN1Ym1pc3Npb25zIikgKyAgICAgICAgICAgICAgIyBjaGFuZ2UgZmlsbCBjb2xvcnMKICBndWlkZXMoZmlsbD1ndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChjb2xvdXIgPSBOVUxMKSkpCmdnIDwtIGdnICsgbXlfdGhlbWUoKQpnZyA8LSBnZyArIGdndGl0bGUoZXhwcmVzc2lvbihib2xkKHBhc3RlKCJUaGUgVW5pdGVkIFN0YXRlcyBvZiB0aGUgIiwgYm9sZGl0YWxpYygiTmV3IFlvcmtlciAiKSwgYm9sZCgiQ2FwdGlvbiBDb250ZXN0OiBXaW5zIFBlciAxMCBUaG91c2FuZCBTdWJtaXNzaW9ucyIpKSkpKQpnZyA8LSBnZyArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4LCBmYWNlID0gImJvbGQiLCBjb2xvdXIgPSAiYmxhY2siLCB2anVzdCA9IDAuNSwgaGp1c3Q9MC41KSwgbGVnZW5kLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTEyKSxsZWdlbmQua2V5ID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJibGFjayIpKSAgCmdnIDwtIGdnICsgY29vcmRfZXF1YWwoKSAreGxhYigiRGF0YSB2aWEgdGhlIE5ldyBZb3JrZXIgQ2FwdGlvbiBDb250ZXN0IEFyY2hpdmUgJiBDYXJ0b29uIEVkaXRvciBCb2IgTWFua29mZiB8IFZpc3VhbGl6YXRpb24gdmlhIEFsZXggQWxicmlnaHQgKHRoZWxpdHRsZWRhdGFzZXQuY29tKSIpCmdnCmBgYAoKVGhlIGFib3ZlIGxlYWRzIHRvIHRoZSBmb2xsb3dpbmcgY29uY2x1c2lvbiBmcm9tIHRoZSBhcnRpY2xlOiAqVGhpcyBtYXAgc2hvd3MgdGhhdCBBbGFza2EgaXMgYWN0dWFsbHkgdGhlIG1vc3Qgc3VjY2Vzc2Z1bCBzdGF0ZSBpbiB0ZXJtcyBvZiB3aW5zIHBlciB0ZW4gdGhvdXNhbmQgc3VibWlzc2lvbnMuIFRob3VnaCBBbGFza2EgaGFzIG9ubHkgd29uIHRoZSBjb250ZXN0IHR3aWNlLCB0aGUgZmFjdCB0aGF0IGl0IGhhZCBhIG1lcmUgdHdlbnR5LW9uZSBodW5kcmVkIGFuZCB0d28gZG9jdW1lbnRlZCBjb250ZXN0IGVudHJpZXMgcmVuZGVycyBpdHMgcmF0ZSBvZiBhcHByb3hpbWF0ZWx5IDkuNSB3aW5zIHBlciB0ZW4gdGhvdXNhbmQgc3VibWlzc2lvbnMgdGhlIGhpZ2hlc3QgaW4gdGhlIGNvdW50cnkuIE1pc3Npc3NpcHBpLCBhbm90aGVyIHN0YXRlIG5vdCBjb21tb25seSBhc3NvY2lhdGVkIHdpdGggdGhlIE5ldyBZb3JrZXIgY3Jvd2QsIGNvbWVzIGluIGF0IGEgY2xvc2Ugc2Vjb25kLCB3aXRoIDguMTQgd2lucyBwZXIgdGVuIHRob3VzYW5kIHN1Ym1pc3Npb25zLiBCZXlvbmQgQWxhc2thIGFuZCBNaXNzaXNzaXBwaSwgdGhlIG90aGVyIHN0YXRlcyBpbiB0aGUgdG9wIHRlbiB3aXRoIHJlc3BlY3QgdG8gdGhpcyBtZXRyaWMgYXJlIEhhd2FpaSwgVXRhaCwgT2tsYWhvbWEsIElsbGlub2lzLCBWaXJnaW5pYSwgS2VudHVja3ksIFZlcm1vbnQsIGFuZCBDb25uZWN0aWN1dC4gT25seSB0aHJlZSBvZiB0aGVzZSB0ZW4gd2VyZSBpbiB0aGUgVG9wIFRlbiBpbiB0ZXJtcyBvZiB0aGUgdG90YWwgd2luIGNvdW504oCUbmFtZWx5LCBJbGxpbm9pcywgVmlyZ2luaWEsIGFuZCBDb25uZWN0aWN1dC4qCgoqVGhlcmVmb3JlLCBhZnRlciBhbGwgdGhhdCBkaXNjdXNzaW9ucyBhYm91dCB0aGUgbW9yZXMgb2YgdGhlIGN1bHR1cmFsIMOpbGl0ZSBhbmQgZmFtaWxpYXJpdHkgd2l0aCBOZXcgWW9ya2VyLWVzcXVlIHNlbnNpYmlsaXRpZXMsIGl04oCZcyBub3QgdGhlIHN0YXRlcyBzYXR1cmF0ZWQgd2l0aCBQcml1cy1kcml2aW5nIHNvY2NlciBmYW5zIHRoYXQgYXJlIHRoZSBtb3N0IHN1Y2Nlc3NmdWwgY2FwdGlvbi1jb250ZXN0IGNvbXBldGl0b3JzLiBJbnN0ZWFkLCB0aGUgbW9zdCBzdWNjZXNzZnVsIHN0YXRlcyBhcmUgc2NhdHRlcmVkIGFjcm9zcyB0aGUgY291bnRyeSwgbm8gbG9uZ2VyIGNvbmZpbmVkIHRvIHRoZSBjb2FzdHMsIGFuZCB0aGUgdWx0aW1hdGUgd2lubmVyIGlzIGFibGUgdG8gc2VlIFJ1c3NpYSBmcm9tIGl0cyBob3VzZS4qCgojIyMgU28sIHRoYXQgaXMgaG93IHRvIGdlbmVyYXRlIHRob3NlIHRocmVlIGdyYXBocy4gCiMjIFRoaXMgaGFzIGJlZW4gYW4gUiBNYXJrZG93biBOb3RlYm9vayEKIyBUaGUgRW5kLgo=