Install

Before you begin this tutorial you must download R R Markdown. Then install R Studio’s IDE (stands for integrated development environment), a powerful user interface for R. Get the Open Source Edition of RStudio Desktop. R Studio . Then open R Studio.

If you have a pre-existing installation of R and/or RStudio, I highly recommend that you reinstall both and get as current as possible. It can be considerably harder to run old software than new.

Libraries

R is an extensible system and many people share useful code they have developed as a package via CRAN and GitHub. This provides most of the functionality we are looking to use, for instance plotting, GIS operations, etc. To install a package from CRAN, for example the dplyr package for data manipulation, here is one way to do it in the R console (there are others).

Keep in mind you only need to install new packages (aka libraries) the first time you run R.

install.packages('dplyr') # data manipulation and cleaning

Now let’s install the libraries (additional functions) we need to use for this tutorial.

install.packages('sf')         # spatial data handling
install.packages('tidycensus') # census data download see https://walkerke.github.io/tidycensus/articles/basic-usage.html
install.packages("cli")        # needed for devtools install
install.packages('devtools')   # allows installation of libraries from github
devtools::install_github("tidyverse/ggplot2")    # plotting installing latest version from github so that it works with sf
          # if prompted please select "1" to install all additional packages
install.packages('ggthemes')   # plotting themes

Getting Access to Census Data

Now that we have installed all the needed libraries (packages), we need to load them into R. You will need to run this bit of code every time you open R to get this to work.

library(tidycensus)
library(sf)
library(ggplot2)
library(ggthemes)
library(dplyr)

To get started working with tidycensus, users should load the package along with the tidyverse package, and set their Census API key. A key can be obtained from Census API Key. It will provide you with a 40 digit text string. Please keep track of this number. Store it in a safe place.

API_Key = '983980b9fc504149e82117csdfwefwe23dsdc507'  # non working example - please paste your own in
census_api_key(API_Key, install = TRUE, overwrite=TRUE)  

Basic Census Data Analysis

Now that we have access to the census API we can start accessing the data. We have to make a few choices, what census “decennial” vs “acs” (American Community Survey),the geography level e.g. “state”,“county”,“tract”, or “block group”, the question identifier (not all questions are available at all geography levels), and the year.

There are two major functions implemented in tidycensus: get_decennial, which grants access to the 1990, 2000, and 2010 decennial US Census APIs, and get_acs, which grants access to the 5-year American Community Survey APIs.

In this basic example, let’s look at Median household income in the past 12 months of 2016.

m90 <- get_decennial(geography = "state", variables = c(rent="H043A001"), year = 1990, output = 'wide')
Getting data from the 1990 decennial Census
head(m90)

medinc <- get_acs(geography = "state", year = 2016,
                     variables = c(medincome = "B19013_001"), 
                     output = 'wide')
Getting data from the 2012-2016 5-year ACS
head(medinc)
NA

Above we can see that the variables = c(rent="H043A001") assigned the values for question “B19013_001” to a column called ‘medincome’. There are two variables that get returned “E” designates this is the income “estimate” and “M” is the “margin of error”. So we want to use “medincomeE” for our work. We are also set output = 'wide', just do this from now on the default output is harder to use.

Now let’s visualize the data. Here notice that the data hasn’t been sorted.

medinc %>%
  ggplot(aes(x = medincomeE, y =  NAME )) + 
  geom_point()

Let’s look at the same data, but we will sort it decending by rent. We can also clean up the labels for x and y. For more help with plotting in ggplot go here.

medinc %>%
  ggplot(aes(x = medincomeE, y =  reorder(NAME, medincomeE) )) + 
  geom_point() +xlab('Median Income 2016')+ylab('State')

Finding the right question

Before we start you need to find the census code for the question you want. Tidycensus makes this fairly simple. We just need to download all questions and codes for either the ACS or Decennial census. For most interesting questions we will want to look at the ACS five year estimates, we are going to use the function load_variables to download all the questions.

acs <- load_variables(year = 2016,
                      dataset = "acs5", 
                      cache = TRUE)     #stores it so you don't have to download it again later
head(acs)

So the name column holds the question codes, label gives the description, and concept gives the question category. To acs double click it in the upper right hand corner of RStudio, notice you can filter questions.

Mapping Census Data

Now let’s download the data and geometry from the API. We do this by rerunning get_acs but with geometry = True. Notice below the column called geometry. This holds the lat and lon of each point making up the state polygons.

medinc <- get_acs(geography = "state", year = 2016,
                     variables = c(medincome = "B19013_001"), 
                     output = 'wide',
                     geometry = TRUE, # this downloads the lat and lon data
                     shift_geo = TRUE # this move AK and PR closer to the US so we can map them easily
                      )
Getting data from the 2012-2016 5-year ACS
Using feature geometry obtained from the albersusa package
Please note: Alaska and Hawaii are being shifted and are not to scale.
head(medinc)
Simple feature collection with 6 features and 4 fields
geometry type:  MULTIPOLYGON
dimension:      XY
bbox:           xmin: -2031905 ymin: -1470717 xmax: 2295505 ymax: 67481.2
epsg (SRID):    NA
proj4string:    +proj=laea +lat_0=45 +lon_0=-100 +x_0=0 +y_0=0 +a=6370997 +b=6370997 +units=m +no_defs
  GEOID                 NAME medincomeE medincomeM                       geometry
1    04              Arizona      51340        231 MULTIPOLYGON (((-1111066 -8...
2    05             Arkansas      42336        234 MULTIPOLYGON (((557903.1 -1...
3    06           California      63783        188 MULTIPOLYGON (((-1853480 -9...
4    08             Colorado      62520        287 MULTIPOLYGON (((-613452.9 -...
5    09          Connecticut      71755        473 MULTIPOLYGON (((2226838 519...
6    11 District of Columbia      72935       1164 MULTIPOLYGON (((1960720 -41...

Now let’s plot it using the powers of ggplot and sf.


ggplot()+geom_sf(data=medinc, aes(fill = medincomeE))

Let’s learn quickly how to reproject data as well. Here we are going to use what is called a “proj4string” which holds all the information needed, for instance the location of the prime meridian, linear units etc. (Site to help identify appropriate projection)[https://projectionwizard.org/#]. (Site to help identify proj4strings)[https://epsg.io/].

Here we will project the data to web mercator and plot the result.

medinc_bg_albers = st_transform(medinc, 
                         crs = '+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext  +no_defs')  


ggplot()+geom_sf(data=medinc_bg_albers,               # this tells ggplot where the data is stored
                 aes(fill = medincomeE)) +   # we are saying to use the values of medincomeE as the fill color
                 ggtitle('Median Income')

Write Out Shapefiles

Writing out data to shapefiles is also very easy.

# write a geojson
st_write(medinc, 
         dsn = "path_to_a_folder/acs_2016_medincome.geojson",  
         driver = "GeoJSON")

# write a shapefile 
st_write(medinc_bg, 
         dsn =  "path_to_a_folder/acs_2016_medincome.shp",  
         driver = "ESRI Shapefile")
LS0tCnRpdGxlOiAiSGFuZGxpbmcgQ2Vuc3VzIERhdGEgaW4gUiIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyBJbnN0YWxsCkJlZm9yZSB5b3UgYmVnaW4gdGhpcyB0dXRvcmlhbCB5b3UgbXVzdCBkb3dubG9hZCBSICBbUiBNYXJrZG93bl0oaHR0cHM6Ly9taXJyb3JzLm5pY3MudXRrLmVkdS9jcmFuLykuIFRoZW4gaW5zdGFsbCBbUiBTdHVkaW/igJlzXShodHRwczovL3JzdHVkaW8uY29tL3Byb2R1Y3RzL3JzdHVkaW8vZG93bmxvYWQvKSBJREUgKHN0YW5kcyBmb3IgaW50ZWdyYXRlZCBkZXZlbG9wbWVudCBlbnZpcm9ubWVudCksIGEgcG93ZXJmdWwgdXNlciBpbnRlcmZhY2UgZm9yIFIuIEdldCB0aGUgT3BlbiBTb3VyY2UgRWRpdGlvbiBvZiBSU3R1ZGlvIERlc2t0b3AuIFIgU3R1ZGlvIC4gVGhlbiBvcGVuIFIgU3R1ZGlvLiAKCklmIHlvdSBoYXZlIGEgcHJlLWV4aXN0aW5nIGluc3RhbGxhdGlvbiBvZiBSIGFuZC9vciBSU3R1ZGlvLCBJIGhpZ2hseSByZWNvbW1lbmQgdGhhdCB5b3UgcmVpbnN0YWxsIGJvdGggYW5kIGdldCBhcyBjdXJyZW50IGFzIHBvc3NpYmxlLiBJdCBjYW4gYmUgY29uc2lkZXJhYmx5IGhhcmRlciB0byBydW4gb2xkIHNvZnR3YXJlIHRoYW4gbmV3LgoKIyBMaWJyYXJpZXMKUiBpcyBhbiBleHRlbnNpYmxlIHN5c3RlbSBhbmQgbWFueSBwZW9wbGUgc2hhcmUgdXNlZnVsIGNvZGUgdGhleSBoYXZlIGRldmVsb3BlZCBhcyBhIHBhY2thZ2UgdmlhIENSQU4gYW5kIEdpdEh1Yi4gVGhpcyBwcm92aWRlcyBtb3N0IG9mIHRoZSBmdW5jdGlvbmFsaXR5IHdlIGFyZSBsb29raW5nIHRvIHVzZSwgZm9yIGluc3RhbmNlIHBsb3R0aW5nLCBHSVMgb3BlcmF0aW9ucywgZXRjLiAgVG8gaW5zdGFsbCBhIHBhY2thZ2UgZnJvbSBDUkFOLCBmb3IgZXhhbXBsZSB0aGUgZHBseXIgcGFja2FnZSBmb3IgZGF0YSBtYW5pcHVsYXRpb24sIGhlcmUgaXMgb25lIHdheSB0byBkbyBpdCBpbiB0aGUgUiBjb25zb2xlICh0aGVyZSBhcmUgb3RoZXJzKS4KCipLZWVwIGluIG1pbmQgeW91IG9ubHkgbmVlZCB0byBpbnN0YWxsIG5ldyBwYWNrYWdlcyAoYWthIGxpYnJhcmllcykgdGhlIGZpcnN0IHRpbWUgeW91IHJ1biBSLioKIApgYGB7ciBldmFsPUZBTFNFLCAgaW5jbHVkZT1UfQppbnN0YWxsLnBhY2thZ2VzKCdkcGx5cicpICMgZGF0YSBtYW5pcHVsYXRpb24gYW5kIGNsZWFuaW5nCmBgYAoKTm93IGxldCdzIGluc3RhbGwgdGhlIGxpYnJhcmllcyAoYWRkaXRpb25hbCBmdW5jdGlvbnMpIHdlIG5lZWQgdG8gdXNlIGZvciB0aGlzIHR1dG9yaWFsLiAKCmBgYHtyIGV2YWw9RkFMU0UsICBpbmNsdWRlPVR9Cmluc3RhbGwucGFja2FnZXMoJ3NmJykgICAgICAgICAjIHNwYXRpYWwgZGF0YSBoYW5kbGluZwppbnN0YWxsLnBhY2thZ2VzKCd0aWR5Y2Vuc3VzJykgIyBjZW5zdXMgZGF0YSBkb3dubG9hZCBzZWUgaHR0cHM6Ly93YWxrZXJrZS5naXRodWIuaW8vdGlkeWNlbnN1cy9hcnRpY2xlcy9iYXNpYy11c2FnZS5odG1sCmluc3RhbGwucGFja2FnZXMoImNsaSIpICAgICAgICAjIG5lZWRlZCBmb3IgZGV2dG9vbHMgaW5zdGFsbAppbnN0YWxsLnBhY2thZ2VzKCdkZXZ0b29scycpICAgIyBhbGxvd3MgaW5zdGFsbGF0aW9uIG9mIGxpYnJhcmllcyBmcm9tIGdpdGh1YgpkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoInRpZHl2ZXJzZS9nZ3Bsb3QyIikgICAgIyBwbG90dGluZyBpbnN0YWxsaW5nIGxhdGVzdCB2ZXJzaW9uIGZyb20gZ2l0aHViIHNvIHRoYXQgaXQgd29ya3Mgd2l0aCBzZgogICAgICAgICAgIyBpZiBwcm9tcHRlZCBwbGVhc2Ugc2VsZWN0ICIxIiB0byBpbnN0YWxsIGFsbCBhZGRpdGlvbmFsIHBhY2thZ2VzCmluc3RhbGwucGFja2FnZXMoJ2dndGhlbWVzJykgICAjIHBsb3R0aW5nIHRoZW1lcwpgYGAKCgojIEdldHRpbmcgQWNjZXNzIHRvIENlbnN1cyBEYXRhCgpOb3cgdGhhdCB3ZSBoYXZlIGluc3RhbGxlZCBhbGwgdGhlIG5lZWRlZCBsaWJyYXJpZXMgKHBhY2thZ2VzKSwgd2UgbmVlZCB0byBsb2FkIHRoZW0gaW50byBSLiAqWW91IHdpbGwgbmVlZCB0byBydW4gdGhpcyBiaXQgb2YgY29kZSBldmVyeSB0aW1lIHlvdSBvcGVuIFIqIHRvIGdldCB0aGlzIHRvIHdvcmsuIAoKYGBge3IgaW5jbHVkZT1UfQpsaWJyYXJ5KHRpZHljZW5zdXMpCmxpYnJhcnkoc2YpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShnZ3RoZW1lcykKbGlicmFyeShkcGx5cikKYGBgCgoKVG8gZ2V0IHN0YXJ0ZWQgd29ya2luZyB3aXRoIHRpZHljZW5zdXMsIHVzZXJzIHNob3VsZCBsb2FkIHRoZSBwYWNrYWdlIGFsb25nIHdpdGggdGhlIHRpZHl2ZXJzZSBwYWNrYWdlLCBhbmQgc2V0IHRoZWlyIENlbnN1cyBBUEkga2V5LiBBIGtleSBjYW4gYmUgb2J0YWluZWQgZnJvbSBbQ2Vuc3VzIEFQSSBLZXldKGh0dHA6Ly9hcGkuY2Vuc3VzLmdvdi9kYXRhL2tleV9zaWdudXAuaHRtbCkuICAqKkl0IHdpbGwgcHJvdmlkZSB5b3Ugd2l0aCBhIDQwIGRpZ2l0IHRleHQgc3RyaW5nLiBQbGVhc2Uga2VlcCB0cmFjayBvZiB0aGlzIG51bWJlci4gU3RvcmUgaXQgaW4gYSBzYWZlIHBsYWNlLioqCiAKYGBge3IgaW5jbHVkZT1ULCBldmFsPUZBTFNFfQpBUElfS2V5ID0gJzk4Mzk4MGI5ZmM1MDQxNDllODIxMTdjc2Rmd2Vmd2UyM2RzZGM1MDcnICAjIG5vbiB3b3JraW5nIGV4YW1wbGUgLSBwbGVhc2UgcGFzdGUgeW91ciBvd24gaW4KY2Vuc3VzX2FwaV9rZXkoQVBJX0tleSwgaW5zdGFsbCA9IFRSVUUsIG92ZXJ3cml0ZT1UUlVFKSAgCmBgYAoKIAoKCiMgQmFzaWMgQ2Vuc3VzIERhdGEgQW5hbHlzaXMKCk5vdyB0aGF0IHdlIGhhdmUgYWNjZXNzIHRvIHRoZSBjZW5zdXMgQVBJIHdlIGNhbiBzdGFydCBhY2Nlc3NpbmcgdGhlIGRhdGEuIFdlIGhhdmUgdG8gbWFrZSBhIGZldyBjaG9pY2VzLCB3aGF0IGNlbnN1cyAiZGVjZW5uaWFsIiB2cyAiYWNzIiAoQW1lcmljYW4gQ29tbXVuaXR5IFN1cnZleSksdGhlIGdlb2dyYXBoeSBsZXZlbCBlLmcuICJzdGF0ZSIsImNvdW50eSIsInRyYWN0Iiwgb3IgImJsb2NrIGdyb3VwIiwgdGhlIHF1ZXN0aW9uIGlkZW50aWZpZXIgKCpub3QgYWxsIHF1ZXN0aW9ucyBhcmUgYXZhaWxhYmxlIGF0IGFsbCBnZW9ncmFwaHkgbGV2ZWxzKiksIGFuZCB0aGUgeWVhci4KClRoZXJlIGFyZSB0d28gbWFqb3IgZnVuY3Rpb25zIGltcGxlbWVudGVkIGluIHRpZHljZW5zdXM6IGdldF9kZWNlbm5pYWwsIHdoaWNoIGdyYW50cyBhY2Nlc3MgdG8gdGhlIDE5OTAsIDIwMDAsIGFuZCAyMDEwIGRlY2VubmlhbCBVUyBDZW5zdXMgQVBJcywgYW5kIGdldF9hY3MsIHdoaWNoIGdyYW50cyBhY2Nlc3MgdG8gdGhlIDUteWVhciBBbWVyaWNhbiBDb21tdW5pdHkgU3VydmV5IEFQSXMuIAoKSW4gdGhpcyBiYXNpYyBleGFtcGxlLCBsZXTigJlzIGxvb2sgYXQgTWVkaWFuIGhvdXNlaG9sZCBpbmNvbWUgaW4gdGhlIHBhc3QgMTIgbW9udGhzIG9mIDIwMTYuIAoKYGBge3J9Cm1lZGluYyA8LSBnZXRfYWNzKGdlb2dyYXBoeSA9ICJzdGF0ZSIsIHllYXIgPSAyMDE2LAogICAgICAgICAgICAgICAgICAgICB2YXJpYWJsZXMgPSBjKG1lZGluY29tZSA9ICJCMTkwMTNfMDAxIiksIAogICAgICAgICAgICAgICAgICAgICBvdXRwdXQgPSAnd2lkZScpCmhlYWQobWVkaW5jKQpgYGAKCkFib3ZlIHdlIGNhbiBzZWUgdGhhdCB0aGUgYHZhcmlhYmxlcyA9IGMocmVudD0iSDA0M0EwMDEiKWAgYXNzaWduZWQgdGhlIHZhbHVlcyBmb3IgcXVlc3Rpb24gIkIxOTAxM18wMDEiIHRvIGEgY29sdW1uIGNhbGxlZCAnbWVkaW5jb21lJy4gVGhlcmUgYXJlIHR3byB2YXJpYWJsZXMgdGhhdCBnZXQgcmV0dXJuZWQgIkUiIGRlc2lnbmF0ZXMgdGhpcyBpcyB0aGUgaW5jb21lICJlc3RpbWF0ZSIgYW5kICJNIiBpcyB0aGUgIm1hcmdpbiBvZiBlcnJvciIuIFNvIHdlIHdhbnQgdG8gdXNlICJtZWRpbmNvbWVFIiBmb3Igb3VyIHdvcmsuIFdlIGFyZSBhbHNvIHNldCBgIG91dHB1dCA9ICd3aWRlJ2AsICpqdXN0IGRvIHRoaXMgZnJvbSBub3cgb24gdGhlIGRlZmF1bHQgb3V0cHV0IGlzIGhhcmRlciB0byB1c2UqLiAKCk5vdyBsZXQncyB2aXN1YWxpemUgdGhlIGRhdGEuIEhlcmUgbm90aWNlIHRoYXQgdGhlIGRhdGEgaGFzbid0IGJlZW4gc29ydGVkLiAKCmBgYHtyIGZpZy5oZWlnaHQ9N30KbWVkaW5jICU+JQogIGdncGxvdChhZXMoeCA9IG1lZGluY29tZUUsIHkgPSAgTkFNRSApKSArIAogIGdlb21fcG9pbnQoKQpgYGAKCkxldCdzIGxvb2sgYXQgdGhlIHNhbWUgZGF0YSwgYnV0IHdlIHdpbGwgc29ydCBpdCBkZWNlbmRpbmcgYnkgcmVudC4gV2UgY2FuIGFsc28gY2xlYW4gdXAgdGhlIGxhYmVscyBmb3IgeCBhbmQgeS4gRm9yIG1vcmUgaGVscCB3aXRoIHBsb3R0aW5nIGluIGdncGxvdCBnbyBbaGVyZV0oaHR0cHM6Ly9nZ3Bsb3QyLnRpZHl2ZXJzZS5vcmcvcmVmZXJlbmNlLykuCgpgYGB7ciBmaWcuaGVpZ2h0PTd9Cm1lZGluYyAlPiUKICBnZ3Bsb3QoYWVzKHggPSBtZWRpbmNvbWVFLCB5ID0gIHJlb3JkZXIoTkFNRSwgbWVkaW5jb21lRSkgKSkgKyAKICBnZW9tX3BvaW50KCkgK3hsYWIoJ01lZGlhbiBJbmNvbWUgMjAxNicpK3lsYWIoJ1N0YXRlJykKYGBgCgoKCiMgRmluZGluZyB0aGUgcmlnaHQgcXVlc3Rpb24KCkJlZm9yZSB3ZSBzdGFydCB5b3UgbmVlZCB0byBmaW5kIHRoZSBjZW5zdXMgY29kZSBmb3IgdGhlIHF1ZXN0aW9uIHlvdSB3YW50LiBUaWR5Y2Vuc3VzIG1ha2VzIHRoaXMgZmFpcmx5IHNpbXBsZS4gV2UganVzdCBuZWVkIHRvIGRvd25sb2FkIGFsbCBxdWVzdGlvbnMgYW5kIGNvZGVzIGZvciBlaXRoZXIgdGhlIEFDUyBvciBEZWNlbm5pYWwgY2Vuc3VzLiBGb3IgbW9zdCBpbnRlcmVzdGluZyBxdWVzdGlvbnMgd2Ugd2lsbCB3YW50IHRvIGxvb2sgYXQgdGhlIEFDUyBmaXZlIHllYXIgZXN0aW1hdGVzLCB3ZSBhcmUgZ29pbmcgdG8gdXNlIHRoZSBmdW5jdGlvbiBbbG9hZF92YXJpYWJsZXNdKGh0dHBzOi8vd2Fsa2Vya2UuZ2l0aHViLmlvL3RpZHljZW5zdXMvcmVmZXJlbmNlL2xvYWRfdmFyaWFibGVzLmh0bWwpIHRvIGRvd25sb2FkIGFsbCB0aGUgcXVlc3Rpb25zLiAKCgpgYGB7cn0KYWNzIDwtIGxvYWRfdmFyaWFibGVzKHllYXIgPSAyMDE2LAogICAgICAgICAgICAgICAgICAgICAgZGF0YXNldCA9ICJhY3M1IiwgCiAgICAgICAgICAgICAgICAgICAgICBjYWNoZSA9IFRSVUUpICAgICAjc3RvcmVzIGl0IHNvIHlvdSBkb24ndCBoYXZlIHRvIGRvd25sb2FkIGl0IGFnYWluIGxhdGVyCmhlYWQoYWNzKQpgYGAKClNvIHRoZSBgbmFtZWAgY29sdW1uIGhvbGRzIHRoZSBxdWVzdGlvbiBjb2RlcywgYGxhYmVsYCBnaXZlcyB0aGUgZGVzY3JpcHRpb24sIGFuZCBgY29uY2VwdGAgZ2l2ZXMgdGhlIHF1ZXN0aW9uIGNhdGVnb3J5LiBUbyBgYWNzYCBkb3VibGUgY2xpY2sgaXQgaW4gdGhlIHVwcGVyIHJpZ2h0IGhhbmQgY29ybmVyIG9mIFJTdHVkaW8sIG5vdGljZSB5b3UgY2FuIGZpbHRlciBxdWVzdGlvbnMuIAoKIyBNYXBwaW5nIENlbnN1cyBEYXRhCgpOb3cgbGV0J3MgZG93bmxvYWQgdGhlIGRhdGEgYW5kIGdlb21ldHJ5IGZyb20gdGhlIEFQSS4gV2UgZG8gdGhpcyBieSByZXJ1bm5pbmcgYGdldF9hY3NgICBidXQgd2l0aCBgZ2VvbWV0cnkgPSBUcnVlYC4gTm90aWNlIGJlbG93IHRoZSBjb2x1bW4gY2FsbGVkIGdlb21ldHJ5LiBUaGlzIGhvbGRzIHRoZSBsYXQgYW5kIGxvbiBvZiBlYWNoIHBvaW50IG1ha2luZyB1cCB0aGUgc3RhdGUgcG9seWdvbnMuIAoKYGBge3J9Cm1lZGluYyA8LSBnZXRfYWNzKGdlb2dyYXBoeSA9ICJzdGF0ZSIsIHllYXIgPSAyMDE2LAogICAgICAgICAgICAgICAgICAgICB2YXJpYWJsZXMgPSBjKG1lZGluY29tZSA9ICJCMTkwMTNfMDAxIiksIAogICAgICAgICAgICAgICAgICAgICBvdXRwdXQgPSAnd2lkZScsCiAgICAgICAgICAgICAgICAgICAgIGdlb21ldHJ5ID0gVFJVRSwgIyB0aGlzIGRvd25sb2FkcyB0aGUgbGF0IGFuZCBsb24gZGF0YQogICAgICAgICAgICAgICAgICAgICBzaGlmdF9nZW8gPSBUUlVFICMgdGhpcyBtb3ZlIEFLIGFuZCBQUiBjbG9zZXIgdG8gdGhlIFVTIHNvIHdlIGNhbiBtYXAgdGhlbSBlYXNpbHkKICAgICAgICAgICAgICAgICAgICAgICkKaGVhZChtZWRpbmMpCmBgYAoKTm93IGxldCdzIHBsb3QgaXQgdXNpbmcgdGhlIHBvd2VycyBvZiBnZ3Bsb3QgYW5kIHNmLiAKCmBgYHtyfQoKZ2dwbG90KCkrZ2VvbV9zZihkYXRhPW1lZGluYywgICAgICAgICAgICAgICAjIHRoaXMgdGVsbHMgZ2dwbG90IHdoZXJlIHRoZSBkYXRhIGlzIHN0b3JlZAogICAgICAgICAgICAgICAgIGFlcyhmaWxsID0gbWVkaW5jb21lRSkpICAgICMgd2UgYXJlIHNheWluZyB0byB1c2UgdGhlIHZhbHVlcyBvZiBtZWRpbmNvbWVFIGFzIHRoZSBmaWxsIGNvbG9yCgpgYGAKCgpMZXQncyBsZWFybiBxdWlja2x5IGhvdyB0byByZXByb2plY3QgZGF0YSBhcyB3ZWxsLiBIZXJlIHdlIGFyZSBnb2luZyB0byB1c2Ugd2hhdCBpcyBjYWxsZWQgYSAicHJvajRzdHJpbmciIHdoaWNoIGhvbGRzIGFsbCB0aGUgaW5mb3JtYXRpb24gbmVlZGVkLCBmb3IgaW5zdGFuY2UgdGhlIGxvY2F0aW9uIG9mIHRoZSBwcmltZSBtZXJpZGlhbiwgbGluZWFyIHVuaXRzIGV0Yy4gKFNpdGUgdG8gaGVscCBpZGVudGlmeSBhcHByb3ByaWF0ZSBwcm9qZWN0aW9uKVtodHRwczovL3Byb2plY3Rpb253aXphcmQub3JnLyNdLiAoU2l0ZSB0byBoZWxwIGlkZW50aWZ5IHByb2o0c3RyaW5ncylbaHR0cHM6Ly9lcHNnLmlvL10uCgpIZXJlIHdlIHdpbGwgcHJvamVjdCB0aGUgZGF0YSB0byB3ZWIgbWVyY2F0b3IgYW5kIHBsb3QgdGhlIHJlc3VsdC4KCmBgYHtyfQptZWRpbmNfYmdfYWxiZXJzID0gc3RfdHJhbnNmb3JtKG1lZGluYywgCiAgICAgICAgICAgICAgICAgICAgICAgICBjcnMgPSAnK3Byb2o9bWVyYyArYT02Mzc4MTM3ICtiPTYzNzgxMzcgK2xhdF90cz0wLjAgK2xvbl8wPTAuMCAreF8wPTAuMCAreV8wPTAgK2s9MS4wICt1bml0cz1tICtuYWRncmlkcz1AbnVsbCArd2t0ZXh0ICArbm9fZGVmcycpICAKCgpnZ3Bsb3QoKStnZW9tX3NmKGRhdGE9bWVkaW5jX2JnX2FsYmVycywgICAgICAgICAgICAgICAjIHRoaXMgdGVsbHMgZ2dwbG90IHdoZXJlIHRoZSBkYXRhIGlzIHN0b3JlZAogICAgICAgICAgICAgICAgIGFlcyhmaWxsID0gbWVkaW5jb21lRSkpICsgICAjIHdlIGFyZSBzYXlpbmcgdG8gdXNlIHRoZSB2YWx1ZXMgb2YgbWVkaW5jb21lRSBhcyB0aGUgZmlsbCBjb2xvcgogICAgICAgICAgICAgICAgIGdndGl0bGUoJ01lZGlhbiBJbmNvbWUnKQpgYGAKCiMgV3JpdGUgT3V0IFNoYXBlZmlsZXMKCldyaXRpbmcgb3V0IGRhdGEgdG8gc2hhcGVmaWxlcyBpcyBhbHNvIHZlcnkgZWFzeS4gCgpgYGB7cn0KIyB3cml0ZSBhIGdlb2pzb24Kc3Rfd3JpdGUobWVkaW5jLCAKICAgICAgICAgZHNuID0gInBhdGhfdG9fYV9mb2xkZXIvYWNzXzIwMTZfbWVkaW5jb21lLmdlb2pzb24iLCAgCiAgICAgICAgIGRyaXZlciA9ICJHZW9KU09OIikKCiMgd3JpdGUgYSBzaGFwZWZpbGUgCnN0X3dyaXRlKG1lZGluY19iZywgCiAgICAgICAgIGRzbiA9ICAicGF0aF90b19hX2ZvbGRlci9hY3NfMjAxNl9tZWRpbmNvbWUuc2hwIiwgIAogICAgICAgICBkcml2ZXIgPSAiRVNSSSBTaGFwZWZpbGUiKQoKYGBgCgoK