Disclaimer: The purpose of the Open Case Studies project is to demonstrate the use of various data science methods, tools, and software in the context of messy, real-world data. A given case study does not cover all aspects of the research process, is not claiming to be the most appropriate way to analyze a given data set, and should not be used in the context of making policy decisions without external consultation from scientific experts. ####

This work is licensed under the Creative Commons Attribution-NonCommercial 3.0 (CC BY-NC 3.0) United States License.

To cite this case study please use:

Wright, Carrie and Ontiveros, Michael and Jager, Leah and Taub, Margaret and Hicks, Stephanie. (2020). https://github.com/opencasestudies/ocs-bp-RTC-wrangling. Influence of Multicollinearity on Measured Impact of Right-to-Carry Gun Laws Part 1 (Version v1.0.0).

To access the GitHub repository for this case study see here: https://github.com/opencasestudies/ocs-bp-RTC-wrangling.
This case study is part of a series of public health case studies for the Bloomberg American Health Initiative.
See this case study for part 2 which includes a data analysis and information about data visualization.

Please help us by filling out our survey.

Motivation


This case study shows the wrangling performed for another case study.

This other case study introduces the topic of multicollinearity, which occurs in regression when one or more independent variables can be predicted by other independent variables.

It does so by showcasing a real world example where multicollinearity in part resulted in historically controversial and conflicting findings about the influence of the adoption of right-to-carry (RTC) concealed handgun laws on violent crime rates in the United States.

We will focus on two articles:

  1. The first analysis by Mustard and Lott published in 1996 suggests that RTC laws reduce violent crime. Lott authored a book extending these findings in 1998 called More Guns, Less Crime.

[source]
  1. The second analysis is a recent article by Donohue, et al. published in 2017 that suggests that RTC laws increase violent crime. Donohue has also published previous articles with titles such as Shooting down the “More Guns, Less Crime” Hypothesis.

[source]

This has been a controversial topic as many other analyses also produced conflicting results. See here for a list of studies.

The Donohue, et al. article discusses how there are many other important methodological aspects besides multicollinearity (which occurs when predictor or input variables are highly related in a regression analysis) that could account for the historically conflicting results in these previous manuscripts.

In fact, nearly every aspect of the data analysis process was different between the Donohue, et al. and Mustard and Lott analyses.

However, we will focus particularly on multicollinearity and how it can influence the results we get from linear regression. Specifically, this analysis will demonstrate how methodological details can be critically influential for our overall conclusions and can result in important policy related consequences. The Donohue, et al. article will provide a basis for the motivation.

John J. Donohue et al., Right‐to‐Carry Laws and Violent Crime: A Comprehensive Assessment Using Panel Data and a State‐Level Synthetic Control Analysis. Journal of Empirical Legal Studies, 16,2 (2019).

David B. Mustard & John Lott. Crime, Deterrence, and Right-to-Carry Concealed Handguns. Coase-Sandor Institute for Law & Economics Working Paper No. 41, (1996).

Before we leave this section, we provide a high-level overview of what variables were (or were not) included in the Donohue, Aneja and Weber) (DAW) paper and the Mustard and Lott (ML) paper:

[source]
*ML is abbreviated as LM in the source article

Note: We are not attempting to re-create the analyses from the original authors. Instead, we aim to use a subset of the listed explanatory variables in this case study to demonstrate multicollinearity. These variables will be consistent for both analyses that we will perform, with the exception that one analysis will have 6 demographic variables as in the analysis in the Donohue, et al. article and the other will have 36 demographic variables, grouping individuals into more specific categories, as in the analysis in the Mustard and Lott article.

Main Question


Our main question:

What is the effect of multicollinearity on coefficient estimates from linear regression models when analyzing right to carry laws and violence rates?

Specifically, we will consider the two ways to define the demographic variables (as described above) and investigate how the inclusion of different numbers of age groups influences the results of an analysis of right to carry laws and violence rates

In this case study we only demonstrate how to import and wrangle the data.

Learning Objectives


Data Science Learning Objectives:

  1. Data import of many different file types with special cases (readr, readxl, pdftools)
  2. Joining data from multiple sources (dplyr)
  3. Working with character strings (stringr)
  4. Data comparisons (dplyr and janitor)
  5. Reshaping data into different formats (tidyr)

We will especially focus on using packages and functions from the tidyverse, such as dplyr and ggplot2. The tidyverse is a library of packages created by RStudio. While some students may be familiar with previous R programming packages, these packages make data science in R especially legible.

Context


So what exactly is a right-to-carry law?

It is a law that specifies if and how citizens are allowed to have a firearm on their person or nearby (for example, in a citizen’s car) in public.

The Second Amendment to the United States Constitution guarantees the right to “keep and bear arms”. The amendment was ratified in 1791 as part of the Bill of Rights.

[source]

However, there are no federal laws about carrying firearms in public.

These laws are created and enforced at the US state level. States vary greatly in their laws about the right to carry firearms. Some require extensive effort to obtain a permit to legally carry a firearm, while other states require very minimal effort to do so.

Click here for more information on history of right-to-carry policies in the US.

According to the Wikipedia entry about the history of right-to-carry policies in the United States:

Public perception on concealed carry vs open carry has largely flipped. In the early days of the United States, open carrying of firearms, long guns and revolvers was a common and well-accepted practice. Seeing guns carried openly was not considered to be any cause for alarm. Therefore, anyone who would carry a firearm but attempt to conceal it was considered to have something to hide, and presumed to be a criminal. For this reason, concealed carry was denounced as a detestable practice in the early days of the United States.

Concealed weapons bans were passed in Kentucky and Louisiana in 1813. (In those days open carry of weapons for self-defense was considered acceptable; concealed carry was denounced as the practice of criminals.) By 1859, Indiana, Tennessee, Virginia, Alabama, and Ohio had followed suit. By the end of the nineteenth century, similar laws were passed in places such as Texas, Florida, and Oklahoma, which protected some gun rights in their state constitutions. Before the mid 1900s, most U.S. states had passed concealed carry laws rather than banning weapons completely. Until the late 1990s, many Southern states were either “No-Issue” or “Restrictive May-Issue”. Since then, these states have largely enacted “Shall-Issue” licensing laws, with numerous states legalizing “Unrestricted concealed carry”.

There are five broad categories of right-to-carry laws:

[source]

You can see that no state in the US currently (this map is from 2020) has a “Rights Infringed/Non-Issue” law (the gray category) – meaning that all 50 states in the US allow the right to carry firearms at least in some way. However the level of restrictions is dramatically different from one state to another.

Click here for more information about how restrictions vary from one state to another.

There is variation from state to state even within the same general category:

For example here is an abridged version of the current carry laws in Idaho which is considered an “Unrestricted - no permit required” state:

State law … allows any resident of Idaho or a current member of the armed forces of the United States to carry a concealed handgun without a license to carry, provided the person is over 18 years old and not disqualified from being issued a license to carry concealed weapons under state law. An amendment to state law that takes effect on July 1, 2020 changes the reference in the above law from “a resident of Idaho” to “any citizen of the United States.”

And here are is an abridged version of the current carry laws in Arizona which is also considered an “Unrestricted - no permit required” state:

Any person 21 years of age or older, who is not prohibited possessor, may carry a weapon openly or concealed without the need for a license…

Notice that citizens in Idaho only need to be 18 to carry a firearm, whereas they must be 21 in Arizona.

Limitations


There are some important considerations regarding this data analysis to keep in mind:

  1. We do not use all of the data used by either the Mustard and Lott or Donohue, et al. analyses, nor do we perform the same analysis as in each article. We instead perform a much simpler analysis with fewer variables for the purposes of illustration of the concept of multicollinearity and its influence on regression coefficients, not to reproduce either analysis.

  2. Our analysis accounts for either the adoption or lack of adoption of a permissive right-to-carry law in each state, but does not account for differences in the level of permissiveness of the laws.

Recall that these are the categories of right to carry laws:

States with laws of the category rights restricted - very limited issue (red) are considered as not having a permissive right-to-carry law. Recall that no states currently have a rights infringed/non-issue law.

States of all other categories (shall issue, discretionary/reasonable issue, and no permit required, all shades of blue) are considered the same in our analysis, as having a permissive right-to-carry law.

  1. Because our analysis in the next case study is an oversimplification, the results presented here should not be used for determining policy changes; instead we suggest that users interested in such a determination consult with a specialist.

  2. The inclusion of race as an explanatory variable in an epidemiological study can be useful in certain circumstances. However, there are limitations and issues around defining, determining, and reporting race, as well as in interpreting differences in public health outcomes by race. For more information on this topic, we have included a link to a paper on the use of race as a measure in epidemiology. We include race in this analysis to demonstrate and consider the limitations of what the previous papers have done to analyze the influence of RTC laws on violent crime, with a focus on multicollinearity. Thus in our analysis we have also defined race as was previously done in these papers. Furthermore, we want to point out that reporting analyses about crime with race as a variable can have very unexpected consequences and thus care should be taken. See here for suggestions. Any association between demographic variables (indicating the proportion of the population from specific race and age groups) and violent crime does not necessarily indicate that the two are linked causally, as aside from the issues presented in the article, this may instead indicate higher rates of police engagement with certain racial groups due to racial profling.

The ACLU defines racial profiling as:

“Racial Profiling” refers to the discriminatory practice by law enforcement officials of targeting individuals for suspicion of crime based on the individual’s race, ethnicity, religion or national origin.


We will begin by loading the packages that we will need:

library(here)
library(readxl)
library(readr)
library(pdftools)
library(dplyr)
library(magrittr)
library(tidyr)
library(stringr)
library(purrr)
library(forcats)
library(tibble)

Packages used in this case study:

Package Use in this case study
here to easily load and save data
readxl to import the data in the excel files
readr to import the CSV file data
pdftools to import data from a pdf file
dplyr to arrange/filter/select/compare specific subsets of the data
magrittr to use the compound assignment pipe operator %<>%
tidyr to rearrange data in wide and long formats
stringr to manipulate the character strings within the data
purrr to import the data in all the different excel and csv files efficiently
forcats to allow for reordering of factors in plots
tibble to create data objects that we can manipulate with dplyr/stringr/tidyr/purrr

What are the data?


Below is a table from the Donohue, et al. paper that shows the data used in both analyses, where DAW stands for Donohue, et al. and ML stands for Mustard and Lott.

We will be using a subset of these variables, which are highlighted in green:

Data Import


Demographic and population data


To obtain information about age, sex, and race, and overall population we will use US Census Bureau data, just like both of the articles. The census data is available for different time spans. Here are the links for the years used in our analysis. We will use data from 1977 to 2010.

Data Link
years 1977 to 1979 link
years 1980 to 1989 link * county data was used for this decade which also has state information
years 1990 to 1999 link
years 2000 to 2010 link
technical documentation

To import the data we will use the read_csv() function of the readr package for the csv files. In some decades, there are separate files for each year, we will read each of these together using the base list.files() function to get all of the names for each file and then the map() function of the purrr package to apply the read_csv() function on all of the file paths in the list created by list.files(). For years that are txt files we will use read_table2() also for the readr package. The read_table2() function, unlike the read_table(), allows for any number of white space characters between columns, and the lines can be of different lengths.

We will save our data to a directory within our working directory called data. We will create subdirectories within this directory to organize our data. We can use the here function from the here package to make this process easier. The here() function allows us to specify the path or location of the document that we want to import, starting from the directory where a .Rproj file is located. In this case, we will import our files within subdirectories of a directory called raw of the data directory. (Note the next chunk of code will only work for you if you pull the repository from GitHub and set up your file structure in the same way.) If you had trouble downloading the data from the orginal sources you can download them from our GitHub repository for this case study.


Click here to see more about creating new projects in RStudio.

You can create a project by going to the File menu of RStudio like so:

You can also do so by clicking the project button:

See here to learn more about using RStudio projects and here to learn more about the here package.



dem_77_79 <- read_csv(here::here("data", "raw", "Demographics", "Decade_1970", "pe-19.csv"), skip = 5)

dem_80_89 <- list.files(recursive = TRUE,
                  path = here("data", "raw", "Demographics", "Decade_1980"),
                  pattern = "*.csv",
                  full.names = TRUE) %>% 
  map(~read_csv(., skip=5))

dem_90_99 <- list.files(recursive = TRUE,
                  path = here("data", "raw", "Demographics", "Decade_1990"),
                  pattern = "*.txt",
                  full.names = TRUE) %>% 
  map(~read_table2(., skip = 14))


dem_00_10 <- list.files(recursive = TRUE,
                  path = here("data", "raw", "Demographics", "Decade_2000"),
                  pattern = "*.csv",
                   full.names = TRUE) %>% 
   map(~read_csv(.))

head(dem_00_10)
[[1]]
# A tibble: 62,244 × 21
   REGION DIVISION STATE NAME            SEX ORIGIN  RACE AGEGRP ESTIMATESBASE20…
    <dbl>    <dbl> <dbl> <chr>         <dbl>  <dbl> <dbl>  <dbl>            <dbl>
 1      0        0     0 United States     0      0     0      0        281424600
 2      0        0     0 United States     0      0     0      1         19176154
 3      0        0     0 United States     0      0     0      2         20549855
 4      0        0     0 United States     0      0     0      3         20528425
 5      0        0     0 United States     0      0     0      4         20218782
 6      0        0     0 United States     0      0     0      5         18962964
 7      0        0     0 United States     0      0     0      6         19381792
 8      0        0     0 United States     0      0     0      7         20511067
 9      0        0     0 United States     0      0     0      8         22707390
10      0        0     0 United States     0      0     0      9         22442442
# … with 62,234 more rows, and 12 more variables: POPESTIMATE2000 <dbl>,
#   POPESTIMATE2001 <dbl>, POPESTIMATE2002 <dbl>, POPESTIMATE2003 <dbl>,
#   POPESTIMATE2004 <dbl>, POPESTIMATE2005 <dbl>, POPESTIMATE2006 <dbl>,
#   POPESTIMATE2007 <dbl>, POPESTIMATE2008 <dbl>, POPESTIMATE2009 <dbl>,
#   CENSUS2010POP <dbl>, POPESTIMATE2010 <dbl>

Notice that the STATE variable for the demographic data is numeric. That is because it is encoded by Federal Information Processing Standard (FIPS) state codes{target="_blank". Thus we also need to import data about FIPS encoding so that we can identify what data corresponds to what state.

State FIPS codes


The following data was downloaded from the US Census Bureau.

To import the data we will use the read_xls() function of the readxl package. Since the first five lines of this excel is information about the source of the data and when it was released, we need to skip importing these lines using the skip argument so that the data has the same number of columns for each row.

knitr::include_graphics(here("img", "FIPS.png"))

STATE_FIPS <- read_xls(here("data", "raw", "State_FIPS_codes", "state-geocodes-v2014.xls"), skip = 5)
(STATE_FIPS)
# A tibble: 64 × 4
   Region Division `State\n(FIPS)` Name                    
   <chr>  <chr>    <chr>           <chr>                   
 1 1      0        00              Northeast Region        
 2 1      1        00              New England Division    
 3 1      1        09              Connecticut             
 4 1      1        23              Maine                   
 5 1      1        25              Massachusetts           
 6 1      1        33              New Hampshire           
 7 1      1        44              Rhode Island            
 8 1      1        50              Vermont                 
 9 1      2        00              Middle Atlantic Division
10 1      2        34              New Jersey              
# … with 54 more rows

Police staffing data


The following data was downloaded from the Federal Bureau of Investigation.

The read_csv() function of the readr package guesses what the class is for each variable, but sometimes it makes mistakes. It is good to specify the class for variables if you know them. We know that we want the variables about male and female counts to be numeric. We can specify that using the col_types = argument. See here and here for more information. We can also indicate that empty values should be evaluated as NA values, as there are many empty values. Note that this is a large file.

ps_data <- read_csv(here("data", "raw", "Police_staffing", "pe_1960_2018.csv"),
                   col_types =  cols(male_total_ct = col_double(),
                                   female_total_ct = col_double()), na = c(""))

Unemployment data


The following data was downloaded from the U.S. Bureau of Labor Statistics.

There are excel files for each state. As you can see, there are many rows to skip to make sure that there are the same number of columns for each row. We can also see that the state name is located in a couple of the first rows.

knitr::include_graphics(here("img", "Unemp.png"))

We can also see that here if we just try to read in the files directly.

ue_rate_data <- list.files(recursive = TRUE,
                  path = here("data", "raw", "Unemployment"),
                  pattern = "*.xlsx",
                  full.names = TRUE) %>% 
  map(~read_xlsx(.))
      
head(ue_rate_data)[1]
[[1]]
# A tibble: 55 × 14
   `Local Area Unem… ...2  ...3  ...4  ...5  ...6  ...7  ...8  ...9  ...10 ...11
   <chr>             <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
 1 Original Data Va… <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA> 
 2 <NA>              <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA> 
 3 Series Id:        LAUS… <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA> 
 4 Not Seasonally A… <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA> 
 5 Area:             Alab… <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA> 
 6 Area Type:        Stat… <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA> 
 7 State/Region/Div… Alab… <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA> 
 8 Measure:          unem… <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA> 
 9 Years:            1977… <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA> 
10 <NA>              <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA> 
# … with 45 more rows, and 3 more variables: ...12 <chr>, ...13 <chr>,
#   ...14 <chr>

So now we will skip the first 10 lines. And also create a names tibble that contains only the cell with the state information.

 ue_rate_data <- list.files(recursive = TRUE,
                  path = here("data", "raw", "Unemployment"),
                  pattern = "*.xlsx",
                  full.names = TRUE) %>% 
  map(~read_xlsx(., skip = 10))
  
head(ue_rate_data[1])
[[1]]
# A tibble: 44 × 14
    Year   Jan   Feb   Mar   Apr   May   Jun   Jul   Aug   Sep   Oct   Nov   Dec
   <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
 1  1977   7.5   9     7.7   7.2   6.8   8.6   8     7.8   6.7   6.3   6.3   6  
 2  1978   7.1   6.9   6.2   5.4   5.1   6.9   6.7   6.7   6.5   6.3   6.3   6.5
 3  1979   6.7   7.5   6.9   6.6   6.4   8.4   7.7   7.8   7.1   7.2   6.9   6.7
 4  1980   7.7   7.8   7.4   7.4   8.4   9.7  10.4  10.3   9.3   9.6   9.4   9  
 5  1981  10    10.3   9.5   9.1   9.4  11.1  10.4  10.9  10.8  11.7  11.5  11.8
 6  1982  13.2  13.2  12.9  12.6  12.8  14.5  14.7  14.8  14.7  15.1  15.4  15.3
 7  1983  16    16    14.5  13.7  13.3  14.6  13.9  13.8  13.2  12.8  12.1  11.8
 8  1984  12.5  12.4  11.4  10.8  10.1  11.3  11.5  11.3  10.8  10.2   9.7  10.1
 9  1985  10.7  10.5   9.8   8.7   8.4   9.6   9.2   8.8   8.6   8.6   8.4   8.7
10  1986   9.3  10.4  10.1   9.4   9.4  10.5   9.7   9.6   9.7   9.7   9.6   9  
# … with 34 more rows, and 1 more variable: Annual <dbl>

To get the state name for each file using the map() function to perform functions across all of the files, we will specifically import only a small range of cells using the range = argument and then grab the cell that has state information based on it’s location within the range of cells imported using c() and then use the base unlist() function to unlist the list that this creates.

ue_rate_names <- list.files(recursive = TRUE,
                  path = here("data", "raw", "Unemployment"),
                  pattern = "*.xlsx",
                  full.names = TRUE) %>%
  map(~read_xlsx(., range = "B4:B6")) %>%
  map(., c(1,2)) %>%
  unlist()

ue_rate_names
 [1] "Alabama"              "Alaska"               "Arizona"             
 [4] "Arkansas"             "California"           "Colorado"            
 [7] "Connecticut"          "Delaware"             "District of Columbia"
[10] "Florida"              "Georgia"              "Hawaii"              
[13] "Idaho"                "Illinois"             "Indiana"             
[16] "Iowa"                 "Kansas"               "Kentucky"            
[19] "Louisiana"            "Maine"                "Maryland"            
[22] "Massachusetts"        "Michigan"             "Minnesota"           
[25] "Mississippi"          "Missouri"             "Montana"             
[28] "Nebraska"             "Nevada"               "New Hampshire"       
[31] "New Jersey"           "New Mexico"           "New York"            
[34] "North Carolina"       "North Dakota"         "Ohio"                
[37] "Oklahoma"             "Oregon"               "Pennsylvania"        
[40] "Rhode Island"         "South Carolina"       "South Dakota"        
[43] "Tennessee"            "Texas"                "Utah"                
[46] "Vermont"              "Virginia"             "Washington"          
[49] "West Virginia"        "Wisconsin"            "Wyoming"             

Now we will make these values the names of the different tibbles within ue_rate_data.

names(ue_rate_data) <- ue_rate_names

Poverty data


Extracted from Table 21 from US Census Bureau Poverty Data.

#**persistent warning from unknown origin** https://community.rstudio.com/t/persistent-unknown-or-uninitialised-column-warnings/64879

#solution to above is alledgedly: "In any case the suggested approach is to initialize the column"


poverty_rate_data <- read_xls(here("data", "raw", "Poverty", "hstpov21.xls"), skip=2) #This may cause initialization issue, not easily reproducible (even after restarting R)

head(poverty_rate_data)
# A tibble: 6 × 6
  `NOTE: Number in thousands.` ...2  ...3   ...4              ...5      ...6    
  <chr>                        <chr> <chr>  <chr>             <chr>     <chr>   
1 2018                         <NA>  <NA>    <NA>             <NA>       <NA>   
2 STATE                        Total Number "Standard\nerror" Percent   "Standa…
3 Alabama                      4877  779    "65"              16        "1.3"   
4 Alaska                       720   94     "9"               13.1      "1.2"   
5 Arizona                      7241  929    "80"              12.80000… "1.1000…
6 Arkansas                     2912  462    "38"              15.9      "1.3"   

We can see that this will require some wrangling to make the data more usable.

Violent crime


Violent crime data was obtained from here. This data is a bit trickier because of spaces and / in the column names, thus the read_lines() function of the readr package works better than the read_csv() function.

knitr::include_graphics(here("img", "crime.png"))

crime_data <- read_lines(here("data", "raw", "Crime", "CrimeStatebyState.csv"), skip = 2, skip_empty_rows = TRUE)
head(crime_data)
[1] "Estimated crime in Alabama"                                                                                                           
[2] "\n,,National or state crime,,,,,,,"                                                                                                   
[3] "\n,,Violent crime,,,,,,,"                                                                                                             
[4] "\nYear,Population,Violent crime total,Murder and nonnegligent Manslaughter,Legacy rape /1,Revised rape /2,Robbery,Aggravated assault,"
[5] "1977,   3690000,      15293,         524,         929,,       3572,      10268 "                                                      
[6] "1978,   3742000,      15682,         499,         954,,       3708,      10521 "                                                      

We can see that this data will also require some wrangling to make it more usable.

Right-to-carry data


This data is extracted from table in Donohue paper. We will use the function pdf_text() of the pdftools package to import the pdf document.

if(!file.exists(here("data", "raw", "w23510.pdf"))){
  url <- "https://www.nber.org/papers/w23510.pdf"
  utils::download.file(url, here("data", "raw", "w23510.pdf"))
}

DAWpaper <- pdf_text(here("data", "raw", "w23510.pdf"))

head(DAWpaper[1])
[1] "                              NBER WORKING PAPER SERIES\n\n\n\n                  RIGHT-TO-CARRY LAWS AND VIOLENT CRIME:\n             A COMPREHENSIVE ASSESSMENT USING PANEL DATA AND\n                 A STATE-LEVEL SYNTHETIC CONTROL ANALYSIS\n\n                                        John J. Donohue\n                                          Abhay Aneja\n                                         Kyle D. Weber\n\n                                      Working Paper 23510\n                              http://www.nber.org/papers/w23510\n\n\n                     NATIONAL BUREAU OF ECONOMIC RESEARCH\n                              1050 Massachusetts Avenue\n                                 Cambridge, MA 02138\n                           June 2017, Revised November 2018\n\n\n\nPreviously circulated as \"Right-to-Carry Laws and Violent Crime: A Comprehensive Assessment\nUsing Panel Data and a State-Level Synthetic Controls Analysis.\" We thank Dan Ho, Stefano\nDellaVigna, Rob Tibshirani, Trevor Hastie, StefanWager, Jeff Strnad, and participants at the\n2011 Conference of Empirical Legal Studies (CELS), 2012 American Law and Economics\nAssociation (ALEA) Annual Meeting, 2013 Canadian Law and Economics Association (CLEA)\nAnnual Meeting, 2015 NBER Summer Institute (Crime), and the Stanford Law School faculty\nworkshop for their comments and helpful suggestions. Financial support was provided by\nStanford Law School. We are indebted to Alberto Abadie, Alexis Diamond, and Jens\nHainmueller for their work developing the synthetic control algorithm and programming the Stata\nmodule used in this paper and for their helpful comments. The authors would also like to thank\nAlex Albright, Andrew Baker, Jacob Dorn, Bhargav Gopal, Crystal Huang, Mira Korb, Haksoo\nLee, Isaac Rabbani, Akshay Rao, Vikram Rao, Henrik Sachs and Sidharth Sah who provided\nexcellent research assistance, as well as Addis O’Connor and Alex Chekholko at the Research\nComputing division of Stanford’s Information Technology Services for their technical support.\nThe views expressed herein are those of the author and do not necessarily reflect the views of the\nNational Bureau of Economic Research.\n\nNBER working papers are circulated for discussion and comment purposes. They have not been\npeer-reviewed or been subject to the review by the NBER Board of Directors that accompanies\nofficial NBER publications.\n\n© 2017 by John J. Donohue, Abhay Aneja, and Kyle D. Weber. All rights reserved. Short\nsections of text, not to exceed two paragraphs, may be quoted without explicit permission\nprovided that full credit, including © notice, is given to the source.\n"

Again, this data will also require quite a bit of wrangling.

Before we move on, we will save our data so that we can pick up from this point.

save(dem_77_79, dem_80_89, dem_90_99, dem_00_10, #demographic data
     STATE_FIPS, # codes for states 
     ps_data, # police staffing data
     ue_rate_data, # unemployment data
     poverty_rate_data, # poverty data
     crime_data, # crime data
     DAWpaper, file = here("data", "imported", "imported_data.rda"))

Data Wrangling


If you have been following along but stopped. You can start here again with the following code:

load(here::here("data", "imported", "imported_data.rda"))

If you skipped the data import section click here.

An RDA file (stands for R data) of the data can be found here or slightly more directly here. Download this file and then place it in your current working directory within a subdirectory called “imported” within a subdirectory called “data” to copy and paste our code. We used an RStudio project and the here package to navigate to the file more easily.

load(here::here("data", "imported", "imported_data.rda"))

Click here to see more about creating new projects in RStudio.

You can create a project by going to the File menu of RStudio like so:

You can also do so by clicking the project button:

See here to learn more about using RStudio projects and here to learn more about the here package.



State FIPS codes


Let’s first take a look at our state FIPS data to see if it needs any cleaning or reshaping. We should start with this data, because we will need to use it to wrangle some of the other data.

head(STATE_FIPS)
# A tibble: 6 × 4
  Region Division `State\n(FIPS)` Name                
  <chr>  <chr>    <chr>           <chr>               
1 1      0        00              Northeast Region    
2 1      1        00              New England Division
3 1      1        09              Connecticut         
4 1      1        23              Maine               
5 1      1        25              Massachusetts       
6 1      1        33              New Hampshire       

We only need the last two columns, but we might want to rename them. The Name variable is vague. The variable with the FIPS code is called State\n(FIPS). To get rid of the new line in this variable name and to change the Name variable to something more informative, we will use the rename() function of the dplyr package. To use this function, we need to list the new name first followed by = and then the existing variable. We can rename multiple variables at the same time by using a comma to separate the variables we are renaming. We will use the select() function also of the dplyr package just to keep these variables, and we will filter out the rows with FIPS values of 00 with the filter() function, again also part of the dplyr package. we will specify that we want STATEFP values that are not equal to 00 by using this operator: !=. We will also use the double pipe operator %<>% of the magrittr package which allows us to use data as input and then reassign it after we perform sum functions using it.

STATE_FIPS %<>% 
dplyr::rename( STATEFP = `State\n(FIPS)`,
                 STATE = Name) %>%
    dplyr::select(STATEFP, STATE) %>%
    dplyr::filter(STATEFP != "00")

STATE_FIPS
# A tibble: 51 × 2
   STATEFP STATE        
   <chr>   <chr>        
 1 09      Connecticut  
 2 23      Maine        
 3 25      Massachusetts
 4 33      New Hampshire
 5 44      Rhode Island 
 6 50      Vermont      
 7 34      New Jersey   
 8 36      New York     
 9 42      Pennsylvania 
10 17      Illinois     
# … with 41 more rows

Demographic and population data


1977-1979


Now let’s take a look at our demographic data across the decades that we wish to study. If you have very wide data (meaning it has many columns), one way to view the data so that you can see all of the columns at the same time is to use the glimpse() function of the dplyr package.

Taking a look at the first decade of data, we can see that the Race/Sex Indicator contains two types of data, the race and the sex. This does not follow the tidy data philosophy, where each cell of a tibble should only contain one piece of information. Typically one might think of using the separate() function of the tidyr package to split this variable into two. However, one of the race values is Other races and since this also has a space, this makes separating this data more tricky.

Instead we will use the str_extract() function of the stringr package and the mutate() function of the dplyr package. The “mutate()” will allow us to create new variables, and “str_extract()” function will allow us to match specific patterns and pull out matches to those patterns. Therefore, if the Race/Sex Indicator value is Other races male and if we extract patterns matching either "male" or "female" which we can specify like this pattern = "male|female" then, the value will be male.

First we need to rename the Race/Sex Indicator variable to not have spaces so that it is compatible with the str_extract() function.

We also want to rename a couple of variables to be simpler and filter the data to only include the years of the data we are interested in, as well as remove some variables that we don’t need like the FIPS State Code. We can remove variables by using the select() function with a - minus sign in front of the variable we wish to remove.

dplyr::glimpse(dem_77_79)
Rows: 3,060
Columns: 22
$ `Year of Estimate`   <dbl> 1970, 1970, 1970, 1970, 1970, 1970, 1970, 1970, 1…
$ `FIPS State Code`    <chr> "01", "01", "01", "01", "01", "01", "02", "02", "…
$ `State Name`         <chr> "Alabama", "Alabama", "Alabama", "Alabama", "Alab…
$ `Race/Sex Indicator` <chr> "White male", "White female", "Black male", "Blac…
$ `Under 5 years`      <dbl> 105856, 100613, 47403, 47079, 244, 250, 12382, 11…
$ `5 to 9 years`       <dbl> 120876, 115194, 55443, 54851, 255, 251, 13888, 13…
$ `10 to 14 years`     <dbl> 129091, 122352, 60427, 60065, 253, 245, 13255, 12…
$ `15 to 19 years`     <dbl> 119500, 116107, 52921, 55144, 281, 254, 11179, 95…
$ `20 to 24 years`     <dbl> 103665, 108513, 29948, 35165, 413, 331, 20237, 10…
$ `25 to 29 years`     <dbl> 86538, 88359, 19535, 23662, 239, 302, 12538, 1073…
$ `30 to 34 years`     <dbl> 74452, 77595, 17196, 22021, 236, 284, 10331, 8657…
$ `35 to 39 years`     <dbl> 71511, 74941, 16654, 22248, 161, 279, 9548, 7510,…
$ `40 to 44 years`     <dbl> 75242, 78908, 17564, 24249, 127, 253, 8282, 6353,…
$ `45 to 49 years`     <dbl> 73874, 78589, 18186, 23028, 108, 148, 6995, 5820,…
$ `50 to 54 years`     <dbl> 68048, 72481, 17618, 22104, 95, 100, 5609, 4494, …
$ `55 to 59 years`     <dbl> 61071, 67699, 18118, 21909, 88, 93, 4029, 2986, 9…
$ `60 to 64 years`     <dbl> 52361, 61065, 16456, 20068, 69, 94, 2392, 1830, 6…
$ `65 to 69 years`     <dbl> 38977, 49685, 14498, 19364, 54, 73, 1292, 965, 22…
$ `70 to 74 years`     <dbl> 26767, 37227, 9541, 12509, 70, 66, 602, 496, 8, 9…
$ `75 to 79 years`     <dbl> 17504, 27163, 6030, 8291, 31, 52, 326, 305, 1, 5,…
$ `80 to 84 years`     <dbl> 9937, 16470, 3485, 5031, 37, 30, 211, 186, 4, 5, …
$ `85 years and over`  <dbl> 5616, 10445, 2448, 4035, 76, 29, 143, 126, 19, 4,…
dem_77_79 <- dem_77_79 %>%
  rename("race_sex" =`Race/Sex Indicator`) %>%
  mutate(SEX = str_extract(race_sex, "male|female"),
        RACE = str_extract(race_sex, "Black|White|Other"))%>%
  select(-`FIPS State Code`, -`race_sex`) %>%
  rename("YEAR" = `Year of Estimate`,
        "STATE" = `State Name`) %>%
  filter(YEAR %in% 1977:1979)

glimpse(dem_77_79)
Rows: 918
Columns: 22
$ YEAR                <dbl> 1977, 1977, 1977, 1977, 1977, 1977, 1977, 1977, 19…
$ STATE               <chr> "Alabama", "Alabama", "Alabama", "Alabama", "Alaba…
$ `Under 5 years`     <dbl> 98814, 94595, 46201, 45784, 590, 621, 14316, 13530…
$ `5 to 9 years`      <dbl> 113365, 107395, 50097, 49329, 672, 660, 14621, 138…
$ `10 to 14 years`    <dbl> 123107, 116182, 54925, 53955, 677, 653, 14795, 136…
$ `15 to 19 years`    <dbl> 135343, 130433, 58468, 59926, 674, 605, 15207, 131…
$ `20 to 24 years`    <dbl> 126053, 125352, 43898, 51433, 722, 773, 20106, 161…
$ `25 to 29 years`    <dbl> 111547, 112471, 31014, 36648, 638, 835, 20444, 182…
$ `30 to 34 years`    <dbl> 100674, 101543, 22528, 26694, 571, 766, 17514, 151…
$ `35 to 39 years`    <dbl> 81038, 83369, 17473, 22213, 498, 586, 13098, 10690…
$ `40 to 44 years`    <dbl> 75042, 77793, 16446, 22146, 356, 479, 10067, 7935,…
$ `45 to 49 years`    <dbl> 76296, 79753, 16578, 22576, 295, 432, 8460, 6848, …
$ `50 to 54 years`    <dbl> 74844, 81079, 17117, 23028, 206, 326, 7268, 5914, …
$ `55 to 59 years`    <dbl> 67785, 75905, 16437, 21435, 166, 213, 5398, 4485, …
$ `60 to 64 years`    <dbl> 58853, 69406, 16276, 21075, 145, 174, 3349, 2708, …
$ `65 to 69 years`    <dbl> 48848, 62430, 15837, 21126, 107, 173, 1714, 1468, …
$ `70 to 74 years`    <dbl> 34475, 50075, 11450, 16028, 90, 138, 915, 928, 22,…
$ `75 to 79 years`    <dbl> 20977, 34027, 7601, 10825, 53, 106, 500, 493, 10, …
$ `80 to 84 years`    <dbl> 10831, 21483, 3896, 6272, 25, 49, 237, 268, 4, 7, …
$ `85 years and over` <dbl> 6683, 15729, 2667, 5426, 33, 41, 153, 211, 11, 6, …
$ SEX                 <chr> "male", "female", "male", "female", "male", "femal…
$ RACE                <chr> "White", "White", "Black", "Black", "Other", "Othe…

That’s looking pretty good! We also want to take all the age group variables and make one variable that is the age group name and one that is the value of the population count for that age group. To do this we will use the pivot_longer() function of the tidyr package. To use this function, we need to use the cols argument to indicate which columns we want to pivot. We also name the new variables we will create with the names_to and values_to arguments. The names_to will be the name of the variable that will identify each age group and values_to will be the name of the variable that contains the corresponding population values.

dem_77_79 <- dem_77_79 %>%
  pivot_longer(cols=contains("years"),
               names_to = "AGE_GROUP",
               values_to = "SUB_POP")

glimpse(dem_77_79)
Rows: 16,524
Columns: 6
$ YEAR      <dbl> 1977, 1977, 1977, 1977, 1977, 1977, 1977, 1977, 1977, 1977, …
$ STATE     <chr> "Alabama", "Alabama", "Alabama", "Alabama", "Alabama", "Alab…
$ SEX       <chr> "male", "male", "male", "male", "male", "male", "male", "mal…
$ RACE      <chr> "White", "White", "White", "White", "White", "White", "White…
$ AGE_GROUP <chr> "Under 5 years", "5 to 9 years", "10 to 14 years", "15 to 19…
$ SUB_POP   <dbl> 98814, 113365, 123107, 135343, 126053, 111547, 100674, 81038…

We also want to get data about the total population for the state for each year.

To do so we can sum all the values for the SUB_POP variable that we just created. To do this we can use the group_by and summarize() functions of the dplyr package. The group_by() function specifies how we want to calculate our sum, that we would like to calculate it for each year and each state individually. Thus, all the values that have the same STATE and YEAR values will be summed together, rather than summing using all of the values in the SUB_POP variable. The .groups argument allows us to remove the grouping after we perform the calculation with summarize().

pop_77_79 <- dem_77_79 %>%
  group_by(YEAR, STATE) %>%
  summarize("TOT_POP" = sum(SUB_POP), .groups = "drop") 

pop_77_79 
# A tibble: 153 × 3
    YEAR STATE                 TOT_POP
   <dbl> <chr>                   <dbl>
 1  1977 Alabama               3782571
 2  1977 Alaska                 397220
 3  1977 Arizona               2427296
 4  1977 Arkansas              2207195
 5  1977 California           22350332
 6  1977 Colorado              2696179
 7  1977 Connecticut           3088745
 8  1977 Delaware               594815
 9  1977 District of Columbia   681766
10  1977 Florida               8888806
# … with 143 more rows

Now we will add the population value to the demographic tibble using the left_join() function of the dplyr package. It is important that we specify how this should be done, that the YEAR and STATE variable values should match each other. This will place the dem_77_79 variables to the left of the pop_77_79 data.

dem_77_79 <- dem_77_79 %>%
  left_join(pop_77_79, by = c("YEAR","STATE"))

dem_77_79
# A tibble: 16,524 × 7
    YEAR STATE   SEX   RACE  AGE_GROUP      SUB_POP TOT_POP
   <dbl> <chr>   <chr> <chr> <chr>            <dbl>   <dbl>
 1  1977 Alabama male  White Under 5 years    98814 3782571
 2  1977 Alabama male  White 5 to 9 years    113365 3782571
 3  1977 Alabama male  White 10 to 14 years  123107 3782571
 4  1977 Alabama male  White 15 to 19 years  135343 3782571
 5  1977 Alabama male  White 20 to 24 years  126053 3782571
 6  1977 Alabama male  White 25 to 29 years  111547 3782571
 7  1977 Alabama male  White 30 to 34 years  100674 3782571
 8  1977 Alabama male  White 35 to 39 years   81038 3782571
 9  1977 Alabama male  White 40 to 44 years   75042 3782571
10  1977 Alabama male  White 45 to 49 years   76296 3782571
# … with 16,514 more rows

We will also calculate the percentage that each group makes up of the total population, by dividing the SUB_POP by the TOT_POP and multiplying by 100 using the mutate() function. we will also remove the other population variables.

dem_77_79 %<>%
  mutate(PERC_SUB_POP = (SUB_POP/TOT_POP)*100) %>%
  select(-SUB_POP, -TOT_POP)

dem_77_79
# A tibble: 16,524 × 6
    YEAR STATE   SEX   RACE  AGE_GROUP      PERC_SUB_POP
   <dbl> <chr>   <chr> <chr> <chr>                 <dbl>
 1  1977 Alabama male  White Under 5 years          2.61
 2  1977 Alabama male  White 5 to 9 years           3.00
 3  1977 Alabama male  White 10 to 14 years         3.25
 4  1977 Alabama male  White 15 to 19 years         3.58
 5  1977 Alabama male  White 20 to 24 years         3.33
 6  1977 Alabama male  White 25 to 29 years         2.95
 7  1977 Alabama male  White 30 to 34 years         2.66
 8  1977 Alabama male  White 35 to 39 years         2.14
 9  1977 Alabama male  White 40 to 44 years         1.98
10  1977 Alabama male  White 45 to 49 years         2.02
# … with 16,514 more rows

It is important to make sure that we have the total values we would expect. We have two levels of SEX, three levels of Race, three levels of YEAR, eighteen levels of AGE_GROUP, and fifty one levels of STATE. If we multiply this together we get 16,524 which is the same as the number of rows in our final dem_77_79 data. Looks good!

Also Let’s make the values of the SEX variable capitalized so that they match the other values of the other variables like RACE etc. This will help us to keep consistent values across the different years as we wrangle the data for the other decades. To do so we will use the str_to_title() function of the stringr package. We need to use the pull() function to get the values of SEX out of dem_77_79. Once we make them capitalized they are then reassigned to the SEX variable.

dem_77_79 %<>%
  mutate(SEX = str_to_title(pull(dem_77_79, SEX)))

# This can also be done line this:
dem_77_79 %<>%
  mutate(SEX = str_to_title(pull(., SEX)))

1980-1989


For this decade each year is a separate tibble and they are combined as a list.

class(dem_80_89)
[1] "list"

So the first thing we need to do is combine each tibble of the list together. We can do that using the bind_rows() function of dplyr which appends the data together based on the presence of columns with the same name in the different tibbles. We will use the map_df() function of the purrr package to allow us to do this across each tibble in our list.

dem_80_89 <- dem_80_89 %>%
  map_df(bind_rows)

glimpse(dem_80_89 )
Rows: 188,460
Columns: 21
$ `Year of Estimate`            <dbl> 1980, 1980, 1980, 1980, 1980, 1980, 1980…
$ `FIPS State and County Codes` <chr> "01001", "01001", "01001", "01001", "010…
$ `Race/Sex Indicator`          <chr> "White male", "White female", "Black mal…
$ `Under 5 years`               <dbl> 985, 831, 357, 346, 4, 7, 2422, 2346, 67…
$ `5 to 9 years`                <dbl> 1096, 987, 427, 395, 9, 8, 2661, 2467, 7…
$ `10 to 14 years`              <dbl> 1271, 1074, 395, 415, 4, 11, 2783, 2614,…
$ `15 to 19 years`              <dbl> 1308, 1259, 460, 429, 10, 5, 3049, 2841,…
$ `20 to 24 years`              <dbl> 972, 1006, 300, 380, 3, 3, 2423, 2428, 5…
$ `25 to 29 years`              <dbl> 850, 912, 240, 235, 2, 11, 2372, 2475, 4…
$ `30 to 34 years`              <dbl> 891, 983, 163, 196, 4, 10, 2410, 2400, 3…
$ `35 to 39 years`              <dbl> 942, 1015, 120, 158, 3, 12, 2101, 2202, …
$ `40 to 44 years`              <dbl> 854, 882, 133, 147, 2, 11, 1881, 1859, 2…
$ `45 to 49 years`              <dbl> 828, 739, 107, 154, 4, 11, 1708, 1694, 2…
$ `50 to 54 years`              <dbl> 631, 602, 113, 165, 1, 7, 1657, 1798, 20…
$ `55 to 59 years`              <dbl> 524, 532, 113, 150, 1, 2, 1641, 1943, 17…
$ `60 to 64 years`              <dbl> 428, 451, 126, 166, 0, 1, 1630, 1819, 17…
$ `65 to 69 years`              <dbl> 358, 417, 128, 160, 1, 0, 1503, 1729, 17…
$ `70 to 74 years`              <dbl> 242, 332, 87, 119, 0, 0, 1163, 1335, 164…
$ `75 to 79 years`              <dbl> 123, 237, 70, 94, 0, 0, 671, 906, 87, 12…
$ `80 to 84 years`              <dbl> 52, 137, 31, 57, 0, 0, 331, 527, 43, 67,…
$ `85 years and over`           <dbl> 39, 86, 13, 44, 0, 1, 187, 408, 27, 65, …

Great! Now our data is all together.

Now we will wrangle the data similarly to the previous decade.

dem_80_89 <- dem_80_89 %>%
  rename("race_sex" =`Race/Sex Indicator`) %>%
  mutate(SEX = str_extract(race_sex, "male|female"),
        RACE = str_extract(race_sex, "Black|White|Other"))%>%
  select( -`race_sex`) %>%
  rename("YEAR" = `Year of Estimate`)
         
glimpse(dem_80_89)
Rows: 188,460
Columns: 22
$ YEAR                          <dbl> 1980, 1980, 1980, 1980, 1980, 1980, 1980…
$ `FIPS State and County Codes` <chr> "01001", "01001", "01001", "01001", "010…
$ `Under 5 years`               <dbl> 985, 831, 357, 346, 4, 7, 2422, 2346, 67…
$ `5 to 9 years`                <dbl> 1096, 987, 427, 395, 9, 8, 2661, 2467, 7…
$ `10 to 14 years`              <dbl> 1271, 1074, 395, 415, 4, 11, 2783, 2614,…
$ `15 to 19 years`              <dbl> 1308, 1259, 460, 429, 10, 5, 3049, 2841,…
$ `20 to 24 years`              <dbl> 972, 1006, 300, 380, 3, 3, 2423, 2428, 5…
$ `25 to 29 years`              <dbl> 850, 912, 240, 235, 2, 11, 2372, 2475, 4…
$ `30 to 34 years`              <dbl> 891, 983, 163, 196, 4, 10, 2410, 2400, 3…
$ `35 to 39 years`              <dbl> 942, 1015, 120, 158, 3, 12, 2101, 2202, …
$ `40 to 44 years`              <dbl> 854, 882, 133, 147, 2, 11, 1881, 1859, 2…
$ `45 to 49 years`              <dbl> 828, 739, 107, 154, 4, 11, 1708, 1694, 2…
$ `50 to 54 years`              <dbl> 631, 602, 113, 165, 1, 7, 1657, 1798, 20…
$ `55 to 59 years`              <dbl> 524, 532, 113, 150, 1, 2, 1641, 1943, 17…
$ `60 to 64 years`              <dbl> 428, 451, 126, 166, 0, 1, 1630, 1819, 17…
$ `65 to 69 years`              <dbl> 358, 417, 128, 160, 1, 0, 1503, 1729, 17…
$ `70 to 74 years`              <dbl> 242, 332, 87, 119, 0, 0, 1163, 1335, 164…
$ `75 to 79 years`              <dbl> 123, 237, 70, 94, 0, 0, 671, 906, 87, 12…
$ `80 to 84 years`              <dbl> 52, 137, 31, 57, 0, 0, 331, 527, 43, 67,…
$ `85 years and over`           <dbl> 39, 86, 13, 44, 0, 1, 187, 408, 27, 65, …
$ SEX                           <chr> "male", "female", "male", "female", "mal…
$ RACE                          <chr> "White", "White", "Black", "Black", "Oth…

Notice that this time the state information is based on the numeric FIPS value. We want only the first two values, as the rest indicate the county. We can use the str_sub() function of the stringr package for this. We will specify that we want to start at the first position and end at the second. Just like str_extract() we need to rename this variable first so that it is compatible.

dem_80_89 %<>%
rename("STATEFP_temp" = "FIPS State and County Codes") %>%
mutate(STATEFP = str_sub(STATEFP_temp, start = 1, end = 2)) %>%
    left_join(STATE_FIPS, by = "STATEFP") %>%
  dplyr::select(-STATEFP)

glimpse(dem_80_89)
Rows: 188,460
Columns: 23
$ YEAR                <dbl> 1980, 1980, 1980, 1980, 1980, 1980, 1980, 1980, 19…
$ STATEFP_temp        <chr> "01001", "01001", "01001", "01001", "01001", "0100…
$ `Under 5 years`     <dbl> 985, 831, 357, 346, 4, 7, 2422, 2346, 672, 645, 30…
$ `5 to 9 years`      <dbl> 1096, 987, 427, 395, 9, 8, 2661, 2467, 740, 680, 3…
$ `10 to 14 years`    <dbl> 1271, 1074, 395, 415, 4, 11, 2783, 2614, 644, 670,…
$ `15 to 19 years`    <dbl> 1308, 1259, 460, 429, 10, 5, 3049, 2841, 711, 762,…
$ `20 to 24 years`    <dbl> 972, 1006, 300, 380, 3, 3, 2423, 2428, 516, 601, 1…
$ `25 to 29 years`    <dbl> 850, 912, 240, 235, 2, 11, 2372, 2475, 414, 469, 1…
$ `30 to 34 years`    <dbl> 891, 983, 163, 196, 4, 10, 2410, 2400, 303, 352, 1…
$ `35 to 39 years`    <dbl> 942, 1015, 120, 158, 3, 12, 2101, 2202, 224, 260, …
$ `40 to 44 years`    <dbl> 854, 882, 133, 147, 2, 11, 1881, 1859, 206, 288, 1…
$ `45 to 49 years`    <dbl> 828, 739, 107, 154, 4, 11, 1708, 1694, 219, 236, 1…
$ `50 to 54 years`    <dbl> 631, 602, 113, 165, 1, 7, 1657, 1798, 203, 261, 7,…
$ `55 to 59 years`    <dbl> 524, 532, 113, 150, 1, 2, 1641, 1943, 178, 219, 8,…
$ `60 to 64 years`    <dbl> 428, 451, 126, 166, 0, 1, 1630, 1819, 171, 209, 8,…
$ `65 to 69 years`    <dbl> 358, 417, 128, 160, 1, 0, 1503, 1729, 170, 232, 6,…
$ `70 to 74 years`    <dbl> 242, 332, 87, 119, 0, 0, 1163, 1335, 164, 182, 4, …
$ `75 to 79 years`    <dbl> 123, 237, 70, 94, 0, 0, 671, 906, 87, 129, 3, 6, 1…
$ `80 to 84 years`    <dbl> 52, 137, 31, 57, 0, 0, 331, 527, 43, 67, 1, 2, 56,…
$ `85 years and over` <dbl> 39, 86, 13, 44, 0, 1, 187, 408, 27, 65, 1, 1, 30, …
$ SEX                 <chr> "male", "female", "male", "female", "male", "femal…
$ RACE                <chr> "White", "White", "Black", "Black", "Other", "Othe…
$ STATE               <chr> "Alabama", "Alabama", "Alabama", "Alabama", "Alaba…
dem_80_89 %<>%
  pivot_longer(cols=contains("years"),
               names_to = "AGE_GROUP",
               values_to = "SUB_POP_temp") %>%
  group_by(YEAR, STATE, AGE_GROUP, SEX, RACE) %>%
  summarize(SUB_POP = sum(SUB_POP_temp), .groups="drop")

dem_80_89
# A tibble: 55,080 × 6
    YEAR STATE   AGE_GROUP      SEX    RACE  SUB_POP
   <dbl> <chr>   <chr>          <chr>  <chr>   <dbl>
 1  1980 Alabama 10 to 14 years female Black   50108
 2  1980 Alabama 10 to 14 years female Other     805
 3  1980 Alabama 10 to 14 years female White  109066
 4  1980 Alabama 10 to 14 years male   Black   50768
 5  1980 Alabama 10 to 14 years male   Other     826
 6  1980 Alabama 10 to 14 years male   White  115988
 7  1980 Alabama 15 to 19 years female Black   58428
 8  1980 Alabama 15 to 19 years female Other     743
 9  1980 Alabama 15 to 19 years female White  126783
10  1980 Alabama 15 to 19 years male   Black   56808
# … with 55,070 more rows
pop_80_89 <- dem_80_89 %>%
  group_by(YEAR, STATE) %>%
  summarize("TOT_POP" = sum(SUB_POP), .groups = "drop") 


dem_80_89 <- dem_80_89 %>%
  left_join(pop_80_89, by = c("YEAR","STATE")) %>%
  mutate(PERC_SUB_POP = (SUB_POP/TOT_POP)*100) %>%
  dplyr::select(-SUB_POP, -TOT_POP)

dem_80_89
# A tibble: 55,080 × 6
    YEAR STATE   AGE_GROUP      SEX    RACE  PERC_SUB_POP
   <dbl> <chr>   <chr>          <chr>  <chr>        <dbl>
 1  1980 Alabama 10 to 14 years female Black       1.28  
 2  1980 Alabama 10 to 14 years female Other       0.0206
 3  1980 Alabama 10 to 14 years female White       2.80  
 4  1980 Alabama 10 to 14 years male   Black       1.30  
 5  1980 Alabama 10 to 14 years male   Other       0.0212
 6  1980 Alabama 10 to 14 years male   White       2.97  
 7  1980 Alabama 15 to 19 years female Black       1.50  
 8  1980 Alabama 15 to 19 years female Other       0.0191
 9  1980 Alabama 15 to 19 years female White       3.25  
10  1980 Alabama 15 to 19 years male   Black       1.46  
# … with 55,070 more rows

Just like with the data from the 70s we will also change the values for SEX to be capitalized.

dem_80_89 %<>%
  mutate(SEX = str_to_title(pull(., SEX)))

Again, it is important to make sure that we have the total values we would expect. This time we have: two levels of SEX, three levels of Race, ten levels of YEAR, eighteen levels of AGE_GROUP, and fifty one levels of STATE.

If we multiply these together we get 55,080, which is the same as the number of rows of the final dem_80_89 data. Looks good!

1990-1999


Just like the 80s we need to combine the data across the files:

dem_90_99 <- dem_90_99 %>%
  map_df(bind_rows)
glimpse(dem_90_99)
Rows: 43,870
Columns: 19
$ Year     <dbl> NA, 1990, 1990, 1990, 1990, 1990, 1990, 1990, 1990, 1990, 199…
$ e        <chr> NA, "01", "01", "01", "01", "01", "01", "01", "01", "01", "01…
$ Age      <dbl> NA, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,…
$ Male     <dbl> NA, 20406, 19393, 18990, 19246, 19502, 19560, 19091, 19605, 1…
$ Female   <dbl> NA, 19101, 18114, 18043, 17786, 18366, 18386, 18047, 18316, 1…
$ Male_1   <dbl> NA, 9794, 9475, 9097, 9002, 9076, 9169, 8919, 9219, 9247, 101…
$ Female_1 <dbl> NA, 9414, 9247, 8837, 8701, 8989, 9093, 8736, 9192, 9108, 978…
$ Male_2   <dbl> NA, 103, 87, 97, 94, 108, 128, 160, 178, 166, 205, 194, 179, …
$ Female_2 <dbl> NA, 90, 93, 100, 115, 114, 130, 134, 162, 155, 193, 185, 202,…
$ Male_3   <dbl> NA, 192, 146, 175, 150, 168, 170, 183, 171, 136, 177, 169, 15…
$ Female_3 <dbl> NA, 170, 182, 160, 157, 178, 158, 173, 177, 185, 179, 171, 16…
$ Male_4   <dbl> NA, 223, 190, 198, 186, 190, 210, 188, 178, 182, 221, 194, 15…
$ Female_4 <dbl> NA, 220, 196, 173, 191, 190, 170, 172, 179, 173, 166, 175, 17…
$ Male_5   <dbl> NA, 47, 41, 32, 35, 36, 30, 28, 27, 29, 32, 31, 33, 34, 32, 3…
$ Female_5 <dbl> NA, 45, 47, 41, 30, 26, 37, 23, 35, 31, 28, 38, 22, 39, 29, 3…
$ Male_6   <dbl> NA, 1, 2, 1, 9, 5, 8, 2, 4, 6, 6, 0, 1, 9, 6, 7, 5, 2, 2, 4, …
$ Female_6 <dbl> NA, 8, 0, 2, 1, 4, 5, 3, 4, 4, 3, 4, 2, 2, 7, 0, 2, 2, 1, 6, …
$ Male_7   <dbl> NA, 5, 7, 2, 3, 5, 11, 2, 7, 12, 10, 7, 5, 6, 5, 6, 6, 2, 11,…
$ Female_7 <dbl> NA, 5, 5, 5, 3, 14, 6, 7, 6, 3, 11, 5, 5, 7, 8, 6, 6, 7, 3, 1…

For this decade the column names can’t all be imported in a simple way from the table, so they need to be recoded.

Here is what the data looks like before importing:

So, first using the base colnames() function we change the names of the column names.

colnames(dem_90_99) <- c("YEAR",
                         "STATEFP",
                         "Age",
                         "NH_W_M",
                         "NH_W_F",
                         "NH_B_M",
                         "NH_B_F",
                         "NH_AIAN_M",
                         "NH_AIAN_F",
                         "NH_API_M",
                         "NH_API_F",
                         "H_W_M",
                         "H_W_F",
                         "H_B_M",
                         "H_B_F",
                         "H_AIAN_M",
                         "H_AIAN_F",
                         "H_API_M",
                         "H_API_F")

glimpse(dem_90_99)
Rows: 43,870
Columns: 19
$ YEAR      <dbl> NA, 1990, 1990, 1990, 1990, 1990, 1990, 1990, 1990, 1990, 19…
$ STATEFP   <chr> NA, "01", "01", "01", "01", "01", "01", "01", "01", "01", "0…
$ Age       <dbl> NA, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16…
$ NH_W_M    <dbl> NA, 20406, 19393, 18990, 19246, 19502, 19560, 19091, 19605, …
$ NH_W_F    <dbl> NA, 19101, 18114, 18043, 17786, 18366, 18386, 18047, 18316, …
$ NH_B_M    <dbl> NA, 9794, 9475, 9097, 9002, 9076, 9169, 8919, 9219, 9247, 10…
$ NH_B_F    <dbl> NA, 9414, 9247, 8837, 8701, 8989, 9093, 8736, 9192, 9108, 97…
$ NH_AIAN_M <dbl> NA, 103, 87, 97, 94, 108, 128, 160, 178, 166, 205, 194, 179,…
$ NH_AIAN_F <dbl> NA, 90, 93, 100, 115, 114, 130, 134, 162, 155, 193, 185, 202…
$ NH_API_M  <dbl> NA, 192, 146, 175, 150, 168, 170, 183, 171, 136, 177, 169, 1…
$ NH_API_F  <dbl> NA, 170, 182, 160, 157, 178, 158, 173, 177, 185, 179, 171, 1…
$ H_W_M     <dbl> NA, 223, 190, 198, 186, 190, 210, 188, 178, 182, 221, 194, 1…
$ H_W_F     <dbl> NA, 220, 196, 173, 191, 190, 170, 172, 179, 173, 166, 175, 1…
$ H_B_M     <dbl> NA, 47, 41, 32, 35, 36, 30, 28, 27, 29, 32, 31, 33, 34, 32, …
$ H_B_F     <dbl> NA, 45, 47, 41, 30, 26, 37, 23, 35, 31, 28, 38, 22, 39, 29, …
$ H_AIAN_M  <dbl> NA, 1, 2, 1, 9, 5, 8, 2, 4, 6, 6, 0, 1, 9, 6, 7, 5, 2, 2, 4,…
$ H_AIAN_F  <dbl> NA, 8, 0, 2, 1, 4, 5, 3, 4, 4, 3, 4, 2, 2, 7, 0, 2, 2, 1, 6,…
$ H_API_M   <dbl> NA, 5, 7, 2, 3, 5, 11, 2, 7, 12, 10, 7, 5, 6, 5, 6, 6, 2, 11…
$ H_API_F   <dbl> NA, 5, 5, 5, 3, 14, 6, 7, 6, 3, 11, 5, 5, 7, 8, 6, 6, 7, 3, …

Notice also that the first row is all NA values from white space in the original table for 1990, this is probably true for each year. We can check them dimensions of our table using the base dim() function. When we filter for rows where YEAR is NA, we indeed see 10 rows, which is what we would expect if we have a row like this for each of the years in the decade. We see the same if we try a different variable. Now we will test to see how large our tibble is if we drop rows with NA values using the drop_na() function of tidyr. We that indeed our dimensions only changed by ten, so there are not other rows with missing values that we might not expect. So now we will resign the dem_90_99 variable after removing these rows.

dim(dem_90_99)
[1] 43870    19
dem_90_99 %>%
  filter(is.na(YEAR))
# A tibble: 10 × 19
    YEAR STATEFP   Age NH_W_M NH_W_F NH_B_M NH_B_F NH_AIAN_M NH_AIAN_F NH_API_M
   <dbl> <chr>   <dbl>  <dbl>  <dbl>  <dbl>  <dbl>     <dbl>     <dbl>    <dbl>
 1    NA <NA>       NA     NA     NA     NA     NA        NA        NA       NA
 2    NA <NA>       NA     NA     NA     NA     NA        NA        NA       NA
 3    NA <NA>       NA     NA     NA     NA     NA        NA        NA       NA
 4    NA <NA>       NA     NA     NA     NA     NA        NA        NA       NA
 5    NA <NA>       NA     NA     NA     NA     NA        NA        NA       NA
 6    NA <NA>       NA     NA     NA     NA     NA        NA        NA       NA
 7    NA <NA>       NA     NA     NA     NA     NA        NA        NA       NA
 8    NA <NA>       NA     NA     NA     NA     NA        NA        NA       NA
 9    NA <NA>       NA     NA     NA     NA     NA        NA        NA       NA
10    NA <NA>       NA     NA     NA     NA     NA        NA        NA       NA
# … with 9 more variables: NH_API_F <dbl>, H_W_M <dbl>, H_W_F <dbl>,
#   H_B_M <dbl>, H_B_F <dbl>, H_AIAN_M <dbl>, H_AIAN_F <dbl>, H_API_M <dbl>,
#   H_API_F <dbl>
dem_90_99 %>%
  filter(is.na(Age)) 
# A tibble: 10 × 19
    YEAR STATEFP   Age NH_W_M NH_W_F NH_B_M NH_B_F NH_AIAN_M NH_AIAN_F NH_API_M
   <dbl> <chr>   <dbl>  <dbl>  <dbl>  <dbl>  <dbl>     <dbl>     <dbl>    <dbl>
 1    NA <NA>       NA     NA     NA     NA     NA        NA        NA       NA
 2    NA <NA>       NA     NA     NA     NA     NA        NA        NA       NA
 3    NA <NA>       NA     NA     NA     NA     NA        NA        NA       NA
 4    NA <NA>       NA     NA     NA     NA     NA        NA        NA       NA
 5    NA <NA>       NA     NA     NA     NA     NA        NA        NA       NA
 6    NA <NA>       NA     NA     NA     NA     NA        NA        NA       NA
 7    NA <NA>       NA     NA     NA     NA     NA        NA        NA       NA
 8    NA <NA>       NA     NA     NA     NA     NA        NA        NA       NA
 9    NA <NA>       NA     NA     NA     NA     NA        NA        NA       NA
10    NA <NA>       NA     NA     NA     NA     NA        NA        NA       NA
# … with 9 more variables: NH_API_F <dbl>, H_W_M <dbl>, H_W_F <dbl>,
#   H_B_M <dbl>, H_B_F <dbl>, H_AIAN_M <dbl>, H_AIAN_F <dbl>, H_API_M <dbl>,
#   H_API_F <dbl>
dem_90_99 %>%drop_na() 
# A tibble: 43,860 × 19
    YEAR STATEFP   Age NH_W_M NH_W_F NH_B_M NH_B_F NH_AIAN_M NH_AIAN_F NH_API_M
   <dbl> <chr>   <dbl>  <dbl>  <dbl>  <dbl>  <dbl>     <dbl>     <dbl>    <dbl>
 1  1990 01          0  20406  19101   9794   9414       103        90      192
 2  1990 01          1  19393  18114   9475   9247        87        93      146
 3  1990 01          2  18990  18043   9097   8837        97       100      175
 4  1990 01          3  19246  17786   9002   8701        94       115      150
 5  1990 01          4  19502  18366   9076   8989       108       114      168
 6  1990 01          5  19560  18386   9169   9093       128       130      170
 7  1990 01          6  19091  18047   8919   8736       160       134      183
 8  1990 01          7  19605  18316   9219   9192       178       162      171
 9  1990 01          8  18823  17743   9247   9108       166       155      136
10  1990 01          9  20226  19178  10194   9784       205       193      177
# … with 43,850 more rows, and 9 more variables: NH_API_F <dbl>, H_W_M <dbl>,
#   H_W_F <dbl>, H_B_M <dbl>, H_B_F <dbl>, H_AIAN_M <dbl>, H_AIAN_F <dbl>,
#   H_API_M <dbl>, H_API_F <dbl>
dem_90_99 %<>%drop_na() 

Then we sum across the non-hispanic and Hispanic groups because this information is not available for the other previous decades. Then we will remove the variables for the Hispanic and non-Hispanic subgroups using select().

dem_90_99%<>%
    mutate(W_M = NH_W_M + H_W_M,
           W_F = NH_W_F + H_W_F,
           B_M = NH_B_M + H_B_M,
           B_F = NH_B_F + H_B_F,
           AIAN_M = NH_AIAN_M + H_AIAN_M,
           AIAN_F = NH_AIAN_F + H_AIAN_F,
           API_M = NH_API_M + H_API_M,
           API_F = NH_API_F + H_API_F) %>%
  select(-starts_with("NH_"), -starts_with("H_"))

glimpse(dem_90_99)
Rows: 43,860
Columns: 11
$ YEAR    <dbl> 1990, 1990, 1990, 1990, 1990, 1990, 1990, 1990, 1990, 1990, 19…
$ STATEFP <chr> "01", "01", "01", "01", "01", "01", "01", "01", "01", "01", "0…
$ Age     <dbl> 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, …
$ W_M     <dbl> 20629, 19583, 19188, 19432, 19692, 19770, 19279, 19783, 19005,…
$ W_F     <dbl> 19321, 18310, 18216, 17977, 18556, 18556, 18219, 18495, 17916,…
$ B_M     <dbl> 9841, 9516, 9129, 9037, 9112, 9199, 8947, 9246, 9276, 10226, 1…
$ B_F     <dbl> 9459, 9294, 8878, 8731, 9015, 9130, 8759, 9227, 9139, 9812, 10…
$ AIAN_M  <dbl> 104, 89, 98, 103, 113, 136, 162, 182, 172, 211, 194, 180, 209,…
$ AIAN_F  <dbl> 98, 93, 102, 116, 118, 135, 137, 166, 159, 196, 189, 204, 198,…
$ API_M   <dbl> 197, 153, 177, 153, 173, 181, 185, 178, 148, 187, 176, 164, 17…
$ API_F   <dbl> 175, 187, 165, 160, 192, 164, 180, 183, 188, 190, 176, 168, 17…

Looking better! We also need to add age groups like the other decades. We will take a look at the 80s data using the distinct() function of the dplyr package to see what age groups we need. We can use the base cut() function to create a new variable with mutate() called AGE_GROUP that will have a label for every change in 5 years of age. The right = FALSE argument specifies that the interval is not closed on the right, meaning that if the value is at the cut point like the Age value is 5, then it will be in the 5 to 9 years group.

We can make the labels for the AGE_GROUP variable match those of dem_77_79 but we need to pull out the values of the tibble created by distinct(). To do this we can use the pull() function from the dplyr package. Note that it is important to check that the AGE_GROUP values are listed in order for dem_77_79. We will also remove the Age variable after we create the new AGE_GROUP variable for the dem_90_99 data.

distinct(dem_77_79, AGE_GROUP)
# A tibble: 18 × 1
   AGE_GROUP        
   <chr>            
 1 Under 5 years    
 2 5 to 9 years     
 3 10 to 14 years   
 4 15 to 19 years   
 5 20 to 24 years   
 6 25 to 29 years   
 7 30 to 34 years   
 8 35 to 39 years   
 9 40 to 44 years   
10 45 to 49 years   
11 50 to 54 years   
12 55 to 59 years   
13 60 to 64 years   
14 65 to 69 years   
15 70 to 74 years   
16 75 to 79 years   
17 80 to 84 years   
18 85 years and over
pull(distinct(dem_77_79, AGE_GROUP))
 [1] "Under 5 years"     "5 to 9 years"      "10 to 14 years"   
 [4] "15 to 19 years"    "20 to 24 years"    "25 to 29 years"   
 [7] "30 to 34 years"    "35 to 39 years"    "40 to 44 years"   
[10] "45 to 49 years"    "50 to 54 years"    "55 to 59 years"   
[13] "60 to 64 years"    "65 to 69 years"    "70 to 74 years"   
[16] "75 to 79 years"    "80 to 84 years"    "85 years and over"
dem_90_99 %<>%
  mutate(AGE_GROUP = cut(Age,
                         breaks = seq(0,90, by=5),
                         right = FALSE, labels = pull(distinct(dem_77_79,AGE_GROUP), AGE_GROUP))) %>%
  select(-Age)

glimpse(dem_90_99)
Rows: 43,860
Columns: 11
$ YEAR      <dbl> 1990, 1990, 1990, 1990, 1990, 1990, 1990, 1990, 1990, 1990, …
$ STATEFP   <chr> "01", "01", "01", "01", "01", "01", "01", "01", "01", "01", …
$ W_M       <dbl> 20629, 19583, 19188, 19432, 19692, 19770, 19279, 19783, 1900…
$ W_F       <dbl> 19321, 18310, 18216, 17977, 18556, 18556, 18219, 18495, 1791…
$ B_M       <dbl> 9841, 9516, 9129, 9037, 9112, 9199, 8947, 9246, 9276, 10226,…
$ B_F       <dbl> 9459, 9294, 8878, 8731, 9015, 9130, 8759, 9227, 9139, 9812, …
$ AIAN_M    <dbl> 104, 89, 98, 103, 113, 136, 162, 182, 172, 211, 194, 180, 20…
$ AIAN_F    <dbl> 98, 93, 102, 116, 118, 135, 137, 166, 159, 196, 189, 204, 19…
$ API_M     <dbl> 197, 153, 177, 153, 173, 181, 185, 178, 148, 187, 176, 164, …
$ API_F     <dbl> 175, 187, 165, 160, 192, 164, 180, 183, 188, 190, 176, 168, …
$ AGE_GROUP <fct> Under 5 years, Under 5 years, Under 5 years, Under 5 years, …

Like the previous decades we will create a RACE and SUB_POP variable using pivot_longer() to create a single Race variable out of all the subgroup variables.

Now we need to collapse the data for the various races so that it matches the previous decades. This time we will use the case_when() function of the dplyr package and the str_detect() function of the stringr package to identify when the race is something other than B or W and replace with the value Other. The value to the right of the ~ indicates what we want the value of the new variable to be if the value of the variable we are using with str_decect() matches the condition specified. If the value does not match the specified condition, than the other values will be what ever is listed after TRUE ~. We will then create population counts as we did previously for the other decades.

Finally, we will create new sums for the sub-populations where we sum across the two Other subgroups Race to a create a single value for each value of YEAR, SEX, AGE_GROUP, and STATE by using the group_by() function and summarie().

dem_90_99  %<>%
  pivot_longer(cols = c(starts_with("W_"),
                    starts_with("B_"),
                    starts_with("AIAN_"),
                    starts_with("API_")),
               names_to = "RACE",
               values_to = "SUB_POP_temp")

dem_90_99 %<>%
  mutate(SEX = case_when(str_detect(RACE, "_M") ~ "Male",
                         TRUE ~ "Female"),
         RACE = case_when(str_detect(RACE, "W_") ~ "White",
                          str_detect(RACE, "B_") ~ "Black",
                          TRUE ~ "Other")) %>%
  left_join(STATE_FIPS, by = "STATEFP") %>%
  dplyr::select(-STATEFP)

dem_90_99 %<>%
  group_by(YEAR, STATE, AGE_GROUP, SEX, RACE) %>%
  summarize(SUB_POP = sum(SUB_POP_temp), .groups="drop")
pop_90_99 <- dem_90_99 %>%
  group_by(YEAR, STATE) %>%
  summarize(TOT_POP = sum(SUB_POP), .groups = "drop")

dem_90_99 <- dem_90_99 %>%
  left_join(pop_90_99, by=c("YEAR", "STATE")) %>%
  mutate(PERC_SUB_POP = (SUB_POP/TOT_POP)*100) %>%
  dplyr::select(-SUB_POP, -TOT_POP)

dem_90_99
# A tibble: 55,080 × 6
    YEAR STATE   AGE_GROUP     SEX    RACE  PERC_SUB_POP
   <dbl> <chr>   <fct>         <chr>  <chr>        <dbl>
 1  1990 Alabama Under 5 years Female Black       1.12  
 2  1990 Alabama Under 5 years Female Other       0.0347
 3  1990 Alabama Under 5 years Female White       2.28  
 4  1990 Alabama Under 5 years Male   Black       1.15  
 5  1990 Alabama Under 5 years Male   Other       0.0336
 6  1990 Alabama Under 5 years Male   White       2.43  
 7  1990 Alabama 5 to 9 years  Female Black       1.14  
 8  1990 Alabama 5 to 9 years  Female Other       0.0419
 9  1990 Alabama 5 to 9 years  Female White       2.29  
10  1990 Alabama 5 to 9 years  Male   Black       1.16  
# … with 55,070 more rows

Again, we should check to make sure that we have the total values we would expect. We have the same number of unique values for each of our variables as in with the data from the 80s, so if we collapsed the data for the different additional sub-populations in this data, then we have done it correctly.

Indeed it looks like we have 55,080 rows, which is what we would expect and is the same as the number of rows of the final dem_80_89 data. Looks good!

2000-2010


Again, for this decade we need to combine the data across years.

dem_00_10 <- dem_00_10 %>%
  map_df(bind_rows)

glimpse(dem_00_10)
Rows: 62,244
Columns: 21
$ REGION            <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…
$ DIVISION          <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…
$ STATE             <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…
$ NAME              <chr> "United States", "United States", "United States", "…
$ SEX               <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…
$ ORIGIN            <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…
$ RACE              <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…
$ AGEGRP            <dbl> 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15…
$ ESTIMATESBASE2000 <dbl> 281424600, 19176154, 20549855, 20528425, 20218782, 1…
$ POPESTIMATE2000   <dbl> 282162411, 19178293, 20463852, 20637696, 20294955, 1…
$ POPESTIMATE2001   <dbl> 284968955, 19298217, 20173362, 20978678, 20456284, 1…
$ POPESTIMATE2002   <dbl> 287625193, 19429192, 19872417, 21261421, 20610370, 2…
$ POPESTIMATE2003   <dbl> 290107933, 19592446, 19620851, 21415353, 20797166, 2…
$ POPESTIMATE2004   <dbl> 292805298, 19785885, 19454237, 21411680, 21102552, 2…
$ POPESTIMATE2005   <dbl> 295516599, 19917400, 19389067, 21212579, 21486214, 2…
$ POPESTIMATE2006   <dbl> 298379912, 19938883, 19544688, 21033138, 21807709, 2…
$ POPESTIMATE2007   <dbl> 301231207, 20125962, 19714611, 20841042, 22067816, 2…
$ POPESTIMATE2008   <dbl> 304093966, 20271127, 19929602, 20706655, 22210880, 2…
$ POPESTIMATE2009   <dbl> 306771529, 20244518, 20182499, 20660564, 22192810, 2…
$ CENSUS2010POP     <dbl> 308745538, 20201362, 20348657, 20677194, 22040343, 2…
$ POPESTIMATE2010   <dbl> 309349689, 20200529, 20382409, 20694011, 21959087, 2…

OK, the data looks a bit different from the others. First we will remove a couple of variables that we probably don’t need. Also it looks like we have some values for the entire United Sates and we will drop these to be like the other decades.

dem_00_10 %<>%
  select(-ESTIMATESBASE2000,-CENSUS2010POP) %>%
  filter(NAME != "United States")

We can see that there are lots of values that are zero. According to the technical documentation for this data, zero values indicate the total for the other categories of Sex, Origin, Race, and AGEGRP.

So we will drop the total values for SEX, RACE, and AGEGRP by removing the rows where these variables are equal to zero.

We will also want to only select for the total values for Origin as we do not wish to divide the data into subgroups about Hispanic ethnicity because we do not have that information for the first two decades. Thus we will filter for only the rows where Origin is equal to zero.

We will also then remove the REGION, Division, STATE, and Origin variables. We will then rename NAME to be STATE and rename AGEGRP to be like the other decades as AGE_GROUP.

dem_00_10 %<>%
  filter(SEX != 0,
         RACE != 0,
         AGEGRP != 0, 
         ORIGIN == 0) %>%
  dplyr::select(-REGION, -DIVISION, -ORIGIN, -STATE) %>%
  rename("STATE" = NAME,
         "AGE_GROUP" = AGEGRP)

dem_00_10
# A tibble: 11,016 × 15
   STATE     SEX  RACE AGE_GROUP POPESTIMATE2000 POPESTIMATE2001 POPESTIMATE2002
   <chr>   <dbl> <dbl>     <dbl>           <dbl>           <dbl>           <dbl>
 1 Alabama     1     1         1           99527           99985           99578
 2 Alabama     1     1         2          104423          102518          101023
 3 Alabama     1     1         3          108325          108412          108059
 4 Alabama     1     1         4          108638          107370          107337
 5 Alabama     1     1         5          104337          107230          108195
 6 Alabama     1     1         6          106491          101466           98949
 7 Alabama     1     1         7          110116          110630          110416
 8 Alabama     1     1         8          123719          120283          116502
 9 Alabama     1     1         9          124961          125443          124751
10 Alabama     1     1        10          115024          117010          119354
# … with 11,006 more rows, and 8 more variables: POPESTIMATE2003 <dbl>,
#   POPESTIMATE2004 <dbl>, POPESTIMATE2005 <dbl>, POPESTIMATE2006 <dbl>,
#   POPESTIMATE2007 <dbl>, POPESTIMATE2008 <dbl>, POPESTIMATE2009 <dbl>,
#   POPESTIMATE2010 <dbl>

Now we need to recode the numeric values to the values in the technical documentation. We can do so by adding labels to each numeric level using the base function factor().

dem_00_10 %<>%
  mutate(SEX = factor(SEX,
                            levels = 1:2,
                            labels = c("Male",
                                    "Female")),
         RACE = factor(RACE,
                            levels = 1:6,
                            labels = c("White",
                                    "Black",
                                    rep("Other",4))),
         AGE_GROUP = factor(AGE_GROUP,
                            levels = 1:18,
                            labels = pull(distinct(dem_77_79,AGE_GROUP), AGE_GROUP)))
                            
glimpse(dem_00_10)
Rows: 11,016
Columns: 15
$ STATE           <chr> "Alabama", "Alabama", "Alabama", "Alabama", "Alabama",…
$ SEX             <fct> Male, Male, Male, Male, Male, Male, Male, Male, Male, …
$ RACE            <fct> White, White, White, White, White, White, White, White…
$ AGE_GROUP       <fct> Under 5 years, 5 to 9 years, 10 to 14 years, 15 to 19 …
$ POPESTIMATE2000 <dbl> 99527, 104423, 108325, 108638, 104337, 106491, 110116,…
$ POPESTIMATE2001 <dbl> 99985, 102518, 108412, 107370, 107230, 101466, 110630,…
$ POPESTIMATE2002 <dbl> 99578, 101023, 108059, 107337, 108195, 98949, 110416, …
$ POPESTIMATE2003 <dbl> 99627, 99920, 108026, 107749, 109360, 98276, 109893, 1…
$ POPESTIMATE2004 <dbl> 99788, 99306, 107627, 108666, 109037, 98742, 107653, 1…
$ POPESTIMATE2005 <dbl> 100316, 99754, 106570, 110278, 108727, 100327, 105151,…
$ POPESTIMATE2006 <dbl> 100820, 101251, 106228, 111640, 108847, 103869, 101617…
$ POPESTIMATE2007 <dbl> 101766, 101985, 106243, 112353, 109496, 105175, 99917,…
$ POPESTIMATE2008 <dbl> 102304, 102479, 106155, 113305, 110007, 106348, 99921,…
$ POPESTIMATE2009 <dbl> 101411, 102688, 106130, 113741, 111167, 106497, 101382…
$ POPESTIMATE2010 <dbl> 99480, 102939, 106324, 112272, 112423, 106593, 102923,…

OK, we also want to change the shape of the data so that we have a YEAR variable and each estimate of the population is a value in a new variable called SUB_POP_temp.

dem_00_10 %<>%
  pivot_longer(cols=contains("ESTIMATE"),
               names_to = "YEAR",
               values_to = "SUB_POP_temp")

We will now clean up the YEAR variable to only be the numeric value by keeping only the last 4 values of each string using the str_sub() function of the stringr package.

dem_00_10 %<>%
  mutate(YEAR = str_sub(YEAR, start=-4)) %>%
  mutate(YEAR = as.numeric(YEAR))

Now we will collapse the data for the different RACES and calculate a new SUB_POP value.

dem_00_10 %<>%
  group_by(YEAR, AGE_GROUP, STATE, SEX, RACE) %>%
  summarize(SUB_POP = sum(SUB_POP_temp), .groups = "drop")

Again, the dimensions look as we expect with 60,588 rows. This time we have two levels of SEX, three levels of Race, 11 levels of YEAR, eighteen levels of AGE_GROUP, and fifty one levels of STATE. If we multiply this together we get 16,588. Looks good!

Now we will calculate the total population and percent of the total as we have done with the previous decades.

pop_00_10 <- dem_00_10 %>%
  group_by(YEAR, STATE) %>%
  summarize(TOT_POP = sum(SUB_POP), .groups = "drop")

We can also check that our wrangling was performed correctly by summing the values for the individual sub-populations percentages and seeing if it totals to 100.

dem_00_10 %>%
  left_join(pop_00_10, by=c("YEAR", "STATE")) %>%
  group_by(YEAR, STATE) %>%
  mutate(PERC_SUB_POP = (SUB_POP/TOT_POP)*100) %>%
  summarize(perc_tot = sum(PERC_SUB_POP), .groups = "drop") %>%
  mutate(poss_error = case_when(abs(perc_tot - 100) > 0 ~ TRUE,
                                TRUE ~ FALSE)) %>%
  group_by(poss_error) %>%
  tally()
# A tibble: 1 × 2
  poss_error     n
  <lgl>      <int>
1 FALSE        561

Looks like the percentages for each state for each year all add up to 100, as we would expect. Great! Now we will reassign the dem_00_10 data with this processing.

dem_00_10 %<>%
  left_join(pop_00_10, by = c("YEAR", "STATE")) %>%
  mutate(PERC_SUB_POP = (SUB_POP/TOT_POP)*100) %>%
 select(-SUB_POP, -TOT_POP)

dem_00_10
# A tibble: 60,588 × 6
    YEAR AGE_GROUP     STATE   SEX    RACE  PERC_SUB_POP
   <dbl> <fct>         <chr>   <fct>  <fct>        <dbl>
 1  2000 Under 5 years Alabama Male   White       2.24  
 2  2000 Under 5 years Alabama Male   Black       1.05  
 3  2000 Under 5 years Alabama Male   Other       0.101 
 4  2000 Under 5 years Alabama Female White       2.12  
 5  2000 Under 5 years Alabama Female Black       1.03  
 6  2000 Under 5 years Alabama Female Other       0.0995
 7  2000 Under 5 years Alaska  Male   White       2.35  
 8  2000 Under 5 years Alaska  Male   Black       0.165 
 9  2000 Under 5 years Alaska  Male   Other       1.37  
10  2000 Under 5 years Alaska  Female White       2.26  
# … with 60,578 more rows

OK, now we are ready to combine all of our demographic data together!


Combining demographic data


We can check that the column names are the same for the data for each of the decades by using the setequal() function of the dplyr package.

setequal(colnames(dem_77_79),colnames(dem_80_89))
[1] TRUE
setequal(colnames(dem_80_89),colnames(dem_90_99))
[1] TRUE
setequal(colnames(dem_90_99),colnames(dem_00_10))
[1] TRUE

We can also confirm that we have the same number of age groups for each decade by using the base length() function. If you did not take a look at the wrangling for the demographic data then you may be unfamiliar with the pull() function of the dplyr package. This allows you to grab the values of a variable from a tibble. The distinct() function which is also of the dplyr package creates a tibble of the unique values for a variable.

length(pull(distinct(dem_77_79, AGE_GROUP), AGE_GROUP))
[1] 18
length(pull(distinct(dem_80_89, AGE_GROUP), AGE_GROUP))
[1] 18
length(pull(distinct(dem_90_99, AGE_GROUP), AGE_GROUP))
[1] 18
length(pull(distinct(dem_00_10, AGE_GROUP), AGE_GROUP))
[1] 18

Looks good!

Now we will combine the data using the bind_rows() function of the dplyr package. This function appends the data together based on the presence of columns with the same name in the different tibbles.

dem <- bind_rows(dem_77_79,
                 dem_80_89,
                 dem_90_99,
                 dem_00_10)
glimpse(dem)
Rows: 187,272
Columns: 6
$ YEAR         <dbl> 1977, 1977, 1977, 1977, 1977, 1977, 1977, 1977, 1977, 197…
$ STATE        <chr> "Alabama", "Alabama", "Alabama", "Alabama", "Alabama", "A…
$ SEX          <chr> "Male", "Male", "Male", "Male", "Male", "Male", "Male", "…
$ RACE         <chr> "White", "White", "White", "White", "White", "White", "Wh…
$ AGE_GROUP    <chr> "Under 5 years", "5 to 9 years", "10 to 14 years", "15 to…
$ PERC_SUB_POP <dbl> 2.6123502, 2.9970356, 3.2545853, 3.5780690, 3.3324688, 2.…

Great! now we have a really large single tibble.

Now we want to select similar demographic data to what was used in the previous analyses.

Here is the table from the Donohue paper that compares the data used in the analyses.

We can see that only the percentage of males that were from age 15-39 of the race groups (black, white, and other) were used in the Donohue analysis.

Ultimately we intend to make a tibble of data that is similar to each analysis. Therefore, we will create a data tibble about the demographic data for each analysis now.

To do so we will first create a vector of the age groups that should be included in the Donohue-like analysis, that we will call DONOHUE_AGE_GROUPS. We will then filter for only the age groups in this vector by using the filter() function of the dplyr package and the %in% operator to indicate that we want to keep all AGE_GROUP values that are equal to those within DONOHUE_AGE_GROUPS. We also want to filter for only population percentages for males by using the == operator. Then we can collapse the age groups from 20-39 by using the fct_collpase() function of the forcats package.

DONOHUE_AGE_GROUPS <- c("15 to 19 years",
                        "20 to 24 years",
                        "25 to 29 years",
                        "30 to 34 years",
                        "35 to 39 years")

dem_DONOHUE <- dem %>%
  filter(AGE_GROUP %in% DONOHUE_AGE_GROUPS,
               SEX == "Male") %>%
  mutate(AGE_GROUP = fct_collapse(AGE_GROUP, "20 to 39 years"=c("20 to 24 years",
                                                                "25 to 29 years",
                                                                "30 to 34 years",
                                                                "35 to 39 years")))

dem_DONOHUE
# A tibble: 26,010 × 6
    YEAR STATE   SEX   RACE  AGE_GROUP      PERC_SUB_POP
   <dbl> <chr>   <chr> <chr> <fct>                 <dbl>
 1  1977 Alabama Male  White 15 to 19 years        3.58 
 2  1977 Alabama Male  White 20 to 39 years        3.33 
 3  1977 Alabama Male  White 20 to 39 years        2.95 
 4  1977 Alabama Male  White 20 to 39 years        2.66 
 5  1977 Alabama Male  White 20 to 39 years        2.14 
 6  1977 Alabama Male  Black 15 to 19 years        1.55 
 7  1977 Alabama Male  Black 20 to 39 years        1.16 
 8  1977 Alabama Male  Black 20 to 39 years        0.820
 9  1977 Alabama Male  Black 20 to 39 years        0.596
10  1977 Alabama Male  Black 20 to 39 years        0.462
# … with 26,000 more rows

We also want to create a new variable that will contain all the demographic information for each percentage just as was done in the Donohue, et al. analysis. This should result in 6 different demographic variables.

To do this we will modify the AGE_GROUP variable by using the mutate() function of the dplyr package. We will replace the spaces in the now two age group categories with and underscore using the str_replace_all() function of the stringr package which replaces all instances of a pattern in a character string.

Then we will use the group_by() function and the summarize() function also of the dplyr package to allow us to calculate a sum of the percentages for each of the sub-population percentages for the newly modified age groups in AGE_GROUP. The .groups = "drop" argument allows for the grouping to be removed after the summarize() function.

dem_DONOHUE %<>%
  mutate(AGE_GROUP = str_replace_all(string = AGE_GROUP, 
                                     pattern = " ", 
                                     replacement = "_")) %>%
  group_by(YEAR, STATE, RACE, SEX, AGE_GROUP) %>%
  summarize(PERC_SUB_POP = sum(PERC_SUB_POP), .groups = "drop")

dem_DONOHUE
# A tibble: 10,404 × 6
    YEAR STATE   RACE  SEX   AGE_GROUP      PERC_SUB_POP
   <dbl> <chr>   <chr> <chr> <chr>                 <dbl>
 1  1977 Alabama Black Male  15_to_19_years       1.55  
 2  1977 Alabama Black Male  20_to_39_years       3.04  
 3  1977 Alabama Other Male  15_to_19_years       0.0178
 4  1977 Alabama Other Male  20_to_39_years       0.0642
 5  1977 Alabama White Male  15_to_19_years       3.58  
 6  1977 Alabama White Male  20_to_39_years      11.1   
 7  1977 Alaska  Black Male  15_to_19_years       0.163 
 8  1977 Alaska  Black Male  20_to_39_years       0.968 
 9  1977 Alaska  Other Male  15_to_19_years       1.12  
10  1977 Alaska  Other Male  20_to_39_years       2.73  
# … with 10,394 more rows

Now we will combine the variables RACE, SEX, and AGE_GROUP together into one string separated by underscores using the unite function of the tidyr package. we will call this new variable VARIABLE. We will rename the PERC_SUB_POP variable to be VALUE using the rename() function of the dplyr package. The new name should be listed first before the =.

dem_DONOHUE %<>%
  unite(col = "VARIABLE", RACE, SEX, AGE_GROUP, sep = "_") %>%
  rename("VALUE" = PERC_SUB_POP)

dem_DONOHUE
# A tibble: 10,404 × 4
    YEAR STATE   VARIABLE                    VALUE
   <dbl> <chr>   <chr>                       <dbl>
 1  1977 Alabama Black_Male_15_to_19_years  1.55  
 2  1977 Alabama Black_Male_20_to_39_years  3.04  
 3  1977 Alabama Other_Male_15_to_19_years  0.0178
 4  1977 Alabama Other_Male_20_to_39_years  0.0642
 5  1977 Alabama White_Male_15_to_19_years  3.58  
 6  1977 Alabama White_Male_20_to_39_years 11.1   
 7  1977 Alaska  Black_Male_15_to_19_years  0.163 
 8  1977 Alaska  Black_Male_20_to_39_years  0.968 
 9  1977 Alaska  Other_Male_15_to_19_years  1.12  
10  1977 Alaska  Other_Male_20_to_39_years  2.73  
# … with 10,394 more rows

Let’s do a quick row number check. We have six different demographic variables, 51 states (DC counts as a state in this case), and 34 different years from 1977 to 2010, we should have 10,404 rows, which we do!

Now, let’s do the same for the “Lott-like” analysis.

So, in this analysis there were 36 variables covering percentages of individuals from 10 to over 65, three race groups and both males and females. This table is misprinted and does not include the word “Other” for the third race group that was used.

First we will filter out the age groups that were not included. Then we will collapse the age groups to those that were used by Mustard and Lott again using the fct_collpase() function of the forcats package.

Also we will again combine the values across the variables to create a new demographic variable with 36 levels.

LOTT_AGE_GROUPS_NULL <- c("Under 5 years",
                          "5 to 9 years")

dem_LOTT <- dem %>%
  filter(!(AGE_GROUP %in% LOTT_AGE_GROUPS_NULL) )%>%
  mutate(AGE_GROUP = fct_collapse(AGE_GROUP,
                                  "10 to 19 years"=c("10 to 14 years",
                                                     "15 to 19 years"),
                                  "20 to 29 years"=c("20 to 24 years",
                                                     "25 to 29 years"),
                                  "30 to 39 years"=c("30 to 34 years",
                                                     "35 to 39 years"),
                                  "40 to 49 years"=c("40 to 44 years",
                                                     "45 to 49 years"),
                                  "50 to 64 years"=c("50 to 54 years",
                                                     "55 to 59 years",
                                                     "60 to 64 years"),
                                  "65 years and over"=c("65 to 69 years",
                                                        "70 to 74 years",
                                                        "75 to 79 years",
                                                        "80 to 84 years",
                                                        "85 years and over"))) %>%
  mutate(AGE_GROUP = str_replace_all(AGE_GROUP," ","_")) %>%
  group_by(YEAR, STATE, RACE, SEX, AGE_GROUP) %>%
  summarize(PERC_SUB_POP = sum(PERC_SUB_POP), .groups = "drop") %>%
  unite(col = "VARIABLE", RACE, SEX, AGE_GROUP, sep = "_") %>%
  rename("VALUE"=PERC_SUB_POP)

We can indeed check that we have the correct number of levels for VARIABLE using the distinct() function.

 distinct(dem_LOTT, VARIABLE)
# A tibble: 36 × 1
   VARIABLE                      
   <chr>                         
 1 Black_Female_10_to_19_years   
 2 Black_Female_20_to_29_years   
 3 Black_Female_30_to_39_years   
 4 Black_Female_40_to_49_years   
 5 Black_Female_50_to_64_years   
 6 Black_Female_65_years_and_over
 7 Black_Male_10_to_19_years     
 8 Black_Male_20_to_29_years     
 9 Black_Male_30_to_39_years     
10 Black_Male_40_to_49_years     
# … with 26 more rows

Combining population data


We also have population data for each decade that came from wrangling the demographic data.

We again want to combine this data, so let’s again make sure that all the different tibbles have the same column names.

setequal(colnames(pop_77_79),colnames(pop_80_89))
[1] TRUE
setequal(colnames(pop_80_89),colnames(pop_90_99))
[1] TRUE
setequal(colnames(pop_90_99),colnames(pop_00_10))
[1] TRUE
head(pop_77_79)
# A tibble: 6 × 3
   YEAR STATE       TOT_POP
  <dbl> <chr>         <dbl>
1  1977 Alabama     3782571
2  1977 Alaska       397220
3  1977 Arizona     2427296
4  1977 Arkansas    2207195
5  1977 California 22350332
6  1977 Colorado    2696179
head(pop_80_89)
# A tibble: 6 × 3
   YEAR STATE       TOT_POP
  <dbl> <chr>         <dbl>
1  1980 Alabama     3899671
2  1980 Alaska       404680
3  1980 Arizona     2735840
4  1980 Arkansas    2288809
5  1980 California 23792840
6  1980 Colorado    2909545
head(pop_90_99)
# A tibble: 6 × 3
   YEAR STATE       TOT_POP
  <dbl> <chr>         <dbl>
1  1990 Alabama     4048508
2  1990 Alaska       553120
3  1990 Arizona     3679056
4  1990 Arkansas    2354343
5  1990 California 29950111
6  1990 Colorado    3303862
head(pop_00_10)
# A tibble: 6 × 3
   YEAR STATE       TOT_POP
  <dbl> <chr>         <dbl>
1  2000 Alabama     4452173
2  2000 Alaska       627963
3  2000 Arizona     5160586
4  2000 Arkansas    2678588
5  2000 California 33987977
6  2000 Colorado    4326921

Looks good!

population_data <- bind_rows(pop_77_79,
                             pop_80_89,
                             pop_90_99,
                             pop_00_10)

population_data <- population_data %>%
  mutate(VARIABLE = "Population") %>%
  rename("VALUE" = TOT_POP)

We could check that we have 51 values for each year by using the count() function of the dplyr package.

population_data %>%
  count(YEAR)
# A tibble: 34 × 2
    YEAR     n
   <dbl> <int>
 1  1977    51
 2  1978    51
 3  1979    51
 4  1980    51
 5  1981    51
 6  1982    51
 7  1983    51
 8  1984    51
 9  1985    51
10  1986    51
# … with 24 more rows

Police staffing


Click here to see details about how the police staffing data was wrangled.

OK, now we will wrangle the police staffing data. We want to limit the data to only the years of interest. Then we will also replace NA values with zero for the male_total_ct and female_total_ct variables using the replace_na() function of the tidyr package. This is because we plan to sum up the number of employees for different agencies within a state to obtain a total state value (like the previous analyses as you can see in the table again below). In these analyses, the number of employees was used which is why we are using these particular columns.

We will use the across() function of the dplyr package to select and mutate both of these columns. Since both of these variables have total_ct in the name and no other variables do, we can use the contains() function of the dplyr package to specify that we want to use these columns instead of listing both out.

glimpse(ps_data)
Rows: 1,439,467
Columns: 21
$ data_year             <dbl> 1960, 1960, 1960, 1960, 1960, 1960, 1960, 1960, …
$ ori                   <chr> "AK020045Y", "AL0011000", "AL0160600", "AL019000…
$ pub_agency_name       <chr> "Alcohol Beverage Control Board", "Homewood", "C…
$ pub_agency_unit       <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ state_abbr            <chr> "AK", "AL", "AL", "AL", "AL", "AL", "AL", "AL", …
$ division_name         <chr> "Pacific", "East South Central", "East South Cen…
$ region_name           <chr> "West", "South", "South", "South", "South", "Sou…
$ county_name           <chr> "N/A", "JEFFERSON", "N/A", "COFFEE", "N/A", "HAL…
$ agency_type_name      <chr> "Other State Agency", "City", "City", "County", …
$ population_group_desc <chr> "Cities under 2,500", "Cities from 10,000 thru 2…
$ population            <dbl> 0, 20289, 0, 14852, 0, 3081, 0, 18739, 2776, 0, …
$ male_officer_ct       <dbl> NA, 17, NA, 0, NA, 0, NA, 0, 0, NA, NA, 0, NA, N…
$ male_civilian_ct      <dbl> NA, 3, NA, 0, NA, 0, NA, 0, 0, NA, NA, 0, NA, NA…
$ male_total_ct         <dbl> NA, 20, NA, 0, NA, 0, NA, 0, 0, NA, NA, 0, NA, N…
$ female_officer_ct     <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ female_civilian_ct    <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ female_total_ct       <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ officer_ct            <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ civilian_ct           <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ total_pe_ct           <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ pe_ct_per_1000        <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
ps_data %<>%
  filter(data_year >= 1977, 
         data_year <= 2014) %>%
mutate(across(.cols =contains("total_ct"), ~replace_na(., 0)))

glimpse(ps_data)
Rows: 932,063
Columns: 21
$ data_year             <dbl> 1977, 1977, 1977, 1977, 1977, 1977, 1977, 1977, …
$ ori                   <chr> "AK0012000", "AK0012300", "AKASP0000", "AL001250…
$ pub_agency_name       <chr> "Soldotna", "Kenai", "Alaska State Troopers", "T…
$ pub_agency_unit       <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ state_abbr            <chr> "AK", "AK", "AK", "AL", "AL", "AL", "AL", "AL", …
$ division_name         <chr> "Pacific", "Pacific", "Pacific", "East South Cen…
$ region_name           <chr> "West", "West", "West", "South", "South", "South…
$ county_name           <chr> "KENAI PENINSULA", "KENAI PENINSULA", "N/A", "JE…
$ agency_type_name      <chr> "City", "City", "State Police", "City", "Other",…
$ population_group_desc <chr> "Cities under 2,500", "Cities from 2,500 thru 9,…
$ population            <dbl> 2131, 5800, 172397, 1000, 0, 8611, 2850, 975, 21…
$ male_officer_ct       <dbl> 6, 10, 0, 3, NA, 16, 6, 2, 5, NA, NA, 3, 26, 5, …
$ male_civilian_ct      <dbl> 6, 0, 0, 0, NA, 5, 0, 0, 0, NA, NA, 0, 0, 0, 4, …
$ male_total_ct         <dbl> 12, 10, 0, 3, 0, 21, 6, 2, 5, 0, 0, 3, 26, 5, 62…
$ female_officer_ct     <lgl> FALSE, FALSE, NA, FALSE, NA, FALSE, FALSE, FALSE…
$ female_civilian_ct    <lgl> TRUE, NA, NA, FALSE, NA, FALSE, FALSE, FALSE, FA…
$ female_total_ct       <dbl> 1, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 13, 0,…
$ officer_ct            <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ civilian_ct           <lgl> NA, NA, NA, FALSE, NA, NA, FALSE, FALSE, FALSE, …
$ total_pe_ct           <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ pe_ct_per_1000        <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …

Now we can create a new variable called police_emp_total which will be the sum of these variables. We will then keep just this variable as well as the data_year, pub_agency_name, and state_abbr.

ps_data %<>%
  mutate(police_emp_total = male_total_ct + female_total_ct) %>%
  dplyr::select(data_year,
                pub_agency_name,
                state_abbr,
                police_emp_total)

ps_data
# A tibble: 932,063 × 4
   data_year pub_agency_name                         state_abbr police_emp_total
       <dbl> <chr>                                   <chr>                 <dbl>
 1      1977 Soldotna                                AK                       13
 2      1977 Kenai                                   AK                       15
 3      1977 Alaska State Troopers                   AK                        0
 4      1977 Trafford                                AL                        3
 5      1977 Trussville Fire Department Fire and Ex… AL                        0
 6      1977 Atmore                                  AL                       21
 7      1977 East Brewton                            AL                        6
 8      1977 Brilliant                               AL                        2
 9      1977 Camden                                  AL                        5
10      1977 Drug Enforcement Administration, Birmi… AL                        0
# … with 932,053 more rows

Now we also want to get collapse by pub_agency_name to get a total count for each year and each state. So we will do this by using the group_by() function and grouping by data_year and state_abbr and using the summarize() function to calculate a sum.

ps_data %<>%
  group_by(data_year, state_abbr) %>%
  summarize(police_state_total=sum(police_emp_total), .groups = "drop")

ps_data
# A tibble: 2,242 × 3
   data_year state_abbr police_state_total
       <dbl> <chr>                   <dbl>
 1      1977 AK                        544
 2      1977 AL                       7380
 3      1977 AR                       3344
 4      1977 AS                          0
 5      1977 AZ                       6414
 6      1977 CA                      65596
 7      1977 CO                       7337
 8      1977 CT                       6051
 9      1977 CZ                          0
10      1977 DC                       4751
# … with 2,232 more rows

And we will check that we have same number of values (the number of years included in the data) for each state.

ps_data %>%
  count(state_abbr)  %>% head()
# A tibble: 6 × 2
  state_abbr     n
  <chr>      <int>
1 AK            38
2 AL            38
3 AR            38
4 AS            38
5 AZ            38
6 CA            38
ps_data %>%
  count(state_abbr) %>%
  filter(n != 38) %>%
  dim()
[1] 0 2

Looks like all the states have 38 values.

Notice also that there are some unusual abbreviations in the state_abbr variable.

We will remove data for US terroitories and associated states

Abbreviation Territory and associated states
AS American Samoa
GM Guam
CZ Canal Zone
FS ??Federated States of Micronesia (usually FM)
MP Northern Mariana Islands
OT ??U.S. Minor Outlying Islands (usually UM)
PR Puerto Rico
VI Virgin Islands
state_of_interest_NULL <- c("AS",
                            "GM",
                            "CZ",
                            "FS",
                            "MP",
                            "OT",
                            "PR",
                            "VI")

ps_data <- ps_data %>%
  filter(!(state_abbr %in% state_of_interest_NULL)) 

Within the datasets package that is loaded with R, there is a data set called state that contains an object called state.abb that has the state abbreviations and state.name that has the state names. We will combine these now to add the state names to our data.

state_abb_data <- tibble( "state_abbr" = state.abb, "STATE" =state.name)
head(state_abb_data)
# A tibble: 6 × 2
  state_abbr STATE     
  <chr>      <chr>     
1 AL         Alabama   
2 AK         Alaska    
3 AZ         Arizona   
4 AR         Arkansas  
5 CA         California
6 CO         Colorado  

One unusual thing about this data is that NE is used for Nebraska to avoid confusions with NB in Canada. So we want to replace that using the str_replace() function of the stringr package

state_abb_data %<>%
  mutate(state_abbr = str_replace(string = state_abbr, 
                                pattern = "NE", 
                            replacement = "NB"))
state_abb_data %>% print(n = 50)
# A tibble: 50 × 2
   state_abbr STATE         
   <chr>      <chr>         
 1 AL         Alabama       
 2 AK         Alaska        
 3 AZ         Arizona       
 4 AR         Arkansas      
 5 CA         California    
 6 CO         Colorado      
 7 CT         Connecticut   
 8 DE         Delaware      
 9 FL         Florida       
10 GA         Georgia       
11 HI         Hawaii        
12 ID         Idaho         
13 IL         Illinois      
14 IN         Indiana       
15 IA         Iowa          
16 KS         Kansas        
17 KY         Kentucky      
18 LA         Louisiana     
19 ME         Maine         
20 MD         Maryland      
21 MA         Massachusetts 
22 MI         Michigan      
23 MN         Minnesota     
24 MS         Mississippi   
25 MO         Missouri      
26 MT         Montana       
27 NB         Nebraska      
28 NV         Nevada        
29 NH         New Hampshire 
30 NJ         New Jersey    
31 NM         New Mexico    
32 NY         New York      
33 NC         North Carolina
34 ND         North Dakota  
35 OH         Ohio          
36 OK         Oklahoma      
37 OR         Oregon        
38 PA         Pennsylvania  
39 RI         Rhode Island  
40 SC         South Carolina
41 SD         South Dakota  
42 TN         Tennessee     
43 TX         Texas         
44 UT         Utah          
45 VT         Vermont       
46 VA         Virginia      
47 WA         Washington    
48 WV         West Virginia 
49 WI         Wisconsin     
50 WY         Wyoming       

We need to add DC to this. We will use the add_row() function of dplyr to do this. We just need to specify values for both of the variables.

state_abb_data %<>%
  dplyr::add_row(state_abbr = "DC",
                      STATE = "District of Columbia")

Now we will add this to our police staffing data and then remove the state_abbr variable, so that we just have state names. We will also

ps_data %<>%
  left_join(state_abb_data, by = "state_abbr") %>%
  dplyr::select(-state_abbr)
ps_data
# A tibble: 1,938 × 3
   data_year police_state_total STATE               
       <dbl>              <dbl> <chr>               
 1      1977                544 Alaska              
 2      1977               7380 Alabama             
 3      1977               3344 Arkansas            
 4      1977               6414 Arizona             
 5      1977              65596 California          
 6      1977               7337 Colorado            
 7      1977               6051 Connecticut         
 8      1977               4751 District of Columbia
 9      1977               1018 Delaware            
10      1977              24588 Florida             
# … with 1,928 more rows

Now we will rename the variables to match those of the other datasets.

ps_data %<>%
  rename(YEAR = "data_year",
         VALUE = "police_state_total") %>%
  mutate(VARIABLE = "police_state_total")
ps_data
# A tibble: 1,938 × 4
    YEAR VALUE STATE                VARIABLE          
   <dbl> <dbl> <chr>                <chr>             
 1  1977   544 Alaska               police_state_total
 2  1977  7380 Alabama              police_state_total
 3  1977  3344 Arkansas             police_state_total
 4  1977  6414 Arizona              police_state_total
 5  1977 65596 California           police_state_total
 6  1977  7337 Colorado             police_state_total
 7  1977  6051 Connecticut          police_state_total
 8  1977  4751 District of Columbia police_state_total
 9  1977  1018 Delaware             police_state_total
10  1977 24588 Florida              police_state_total
# … with 1,928 more rows

We also need to adjust the value to be that of every 100,000 people in the state. To do so we need the population for each state, which luckily we already have. We will slightly modify the population data and create a new tibble that will make it more clear how we are dividing by it.

denominator_temp <- population_data %>%
 select(-VARIABLE) %>%
  rename("Population_temp"=VALUE)
head(denominator_temp)
# A tibble: 6 × 3
   YEAR STATE      Population_temp
  <dbl> <chr>                <dbl>
1  1977 Alabama            3782571
2  1977 Alaska              397220
3  1977 Arizona            2427296
4  1977 Arkansas           2207195
5  1977 California        22350332
6  1977 Colorado           2696179
ps_data %<>%
  left_join(denominator_temp, by=c("STATE","YEAR"))
head(ps_data)
# A tibble: 6 × 5
   YEAR VALUE STATE      VARIABLE           Population_temp
  <dbl> <dbl> <chr>      <chr>                        <dbl>
1  1977   544 Alaska     police_state_total          397220
2  1977  7380 Alabama    police_state_total         3782571
3  1977  3344 Arkansas   police_state_total         2207195
4  1977  6414 Arizona    police_state_total         2427296
5  1977 65596 California police_state_total        22350332
6  1977  7337 Colorado   police_state_total         2696179
ps_data %<>%
  mutate(VALUE = (VALUE * 100000) / Population_temp) %>%
  #mutate(VALUE = lag(VALUE)) %>%
  mutate(VARIABLE = "police_per_100k_lag") %>%
  select(-Population_temp)

ps_data
# A tibble: 1,938 × 4
    YEAR VALUE STATE                VARIABLE           
   <dbl> <dbl> <chr>                <chr>              
 1  1977  137. Alaska               police_per_100k_lag
 2  1977  195. Alabama              police_per_100k_lag
 3  1977  152. Arkansas             police_per_100k_lag
 4  1977  264. Arizona              police_per_100k_lag
 5  1977  293. California           police_per_100k_lag
 6  1977  272. Colorado             police_per_100k_lag
 7  1977  196. Connecticut          police_per_100k_lag
 8  1977  697. District of Columbia police_per_100k_lag
 9  1977  171. Delaware             police_per_100k_lag
10  1977  277. Florida              police_per_100k_lag
# … with 1,928 more rows

Unemployment


The first thing we need to do with the unemployment data is combine the data across the different states. We can do that using the bind_rows() function of dplyr which appends the data together based on the presence of columns with the same name in the different tibbles. We will use the map_df() function of the purrr package to allow us to do this across each tibble in our list. We will then select just the annual data for each state and year and we will rename our variables to be consistent with some of other data that we are working with. Thus we would like our variables to be YEAR, VALUE and VARIABLE in all caps.

ue_rate_data <- ue_rate_data %>%
  map_df(bind_rows, .id = "STATE")

head(ue_rate_data)
# A tibble: 6 × 15
  STATE   Year   Jan   Feb   Mar   Apr   May   Jun   Jul   Aug   Sep   Oct   Nov
  <chr>  <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 Alaba…  1977   7.5   9     7.7   7.2   6.8   8.6   8     7.8   6.7   6.3   6.3
2 Alaba…  1978   7.1   6.9   6.2   5.4   5.1   6.9   6.7   6.7   6.5   6.3   6.3
3 Alaba…  1979   6.7   7.5   6.9   6.6   6.4   8.4   7.7   7.8   7.1   7.2   6.9
4 Alaba…  1980   7.7   7.8   7.4   7.4   8.4   9.7  10.4  10.3   9.3   9.6   9.4
5 Alaba…  1981  10    10.3   9.5   9.1   9.4  11.1  10.4  10.9  10.8  11.7  11.5
6 Alaba…  1982  13.2  13.2  12.9  12.6  12.8  14.5  14.7  14.8  14.7  15.1  15.4
# … with 2 more variables: Dec <dbl>, Annual <dbl>
ue_rate_data <- ue_rate_data %>%
  dplyr::select(STATE, Year, Annual) %>%
  rename("YEAR" = Year,
        "VALUE" = Annual) %>%
  mutate(VARIABLE = "Unemployment_rate")

head(ue_rate_data)
# A tibble: 6 × 4
  STATE    YEAR VALUE VARIABLE         
  <chr>   <dbl> <dbl> <chr>            
1 Alabama  1977   7.3 Unemployment_rate
2 Alabama  1978   6.4 Unemployment_rate
3 Alabama  1979   7.2 Unemployment_rate
4 Alabama  1980   8.9 Unemployment_rate
5 Alabama  1981  10.6 Unemployment_rate
6 Alabama  1982  14.1 Unemployment_rate

Poverty rate



Click here to see details about how the poverty data was wrangled.

OK, now for wrangling the poverty data. First let’s take a look at it.

head(poverty_rate_data)
# A tibble: 6 × 6
  `NOTE: Number in thousands.` ...2  ...3   ...4              ...5      ...6    
  <chr>                        <chr> <chr>  <chr>             <chr>     <chr>   
1 2018                         <NA>  <NA>    <NA>             <NA>       <NA>   
2 STATE                        Total Number "Standard\nerror" Percent   "Standa…
3 Alabama                      4877  779    "65"              16        "1.3"   
4 Alaska                       720   94     "9"               13.1      "1.2"   
5 Arizona                      7241  929    "80"              12.80000… "1.1000…
6 Arkansas                     2912  462    "38"              15.9      "1.3"   

We can see that the column names are actually shifted down below the row with the year. So we will manually make these values the actual column names.

colnames(poverty_rate_data) <- c("STATE",
                                 "Total",
                                 "Number",
                                 "Number_se",
                                 "Percent",
                                 "Percent_se")

poverty_rate_data2 <-poverty_rate_data

Let’s also remove the rows where the column names are listed, like row number 2.

poverty_rate_data  %<>%
  filter(STATE != "STATE")
head(poverty_rate_data)
# A tibble: 6 × 6
  STATE      Total Number Number_se Percent            Percent_se        
  <chr>      <chr> <chr>  <chr>     <chr>              <chr>             
1 2018       <NA>  <NA>   <NA>      <NA>               <NA>              
2 Alabama    4877  779    65        16                 1.3               
3 Alaska     720   94     9         13.1               1.2               
4 Arizona    7241  929    80        12.800000000000001 1.1000000000000001
5 Arkansas   2912  462    38        15.9               1.3               
6 California 39150 4664   184       11.9               0.5               

We can also see that there are some extra notes at the end of our data. This is why it is a good idea to look at both the head and tail of your data.

tail(poverty_rate_data)
# A tibble: 6 × 6
  STATE                             Total Number Number_se Percent Percent_se   
  <chr>                             <chr> <chr>  <chr>     <chr>   <chr>        
1 Wisconsin                         4724  403    57        8.5     1.1000000000…
2 Wyoming                           468   49     20        10.4    4            
3 Standard errors shown in this ta… <NA>  <NA>   <NA>      <NA>    <NA>         
4 For information on confidentiali… <NA>  <NA>   <NA>      <NA>    <NA>         
5 Footnotes are available at <www.… <NA>  <NA>   <NA>      <NA>    <NA>         
6 SOURCE: U.S. Bureau of the Censu… <NA>  <NA>   <NA>      <NA>    <NA>         

We can see that the strings for the state for these rows are very long. We can also see that there are rows that just have the year, where the state is only 4 characters long. We will create a new variable called length_state based on the number of characters in the STATE values. We will use the str_length() function of the stringr package. We need to use the map_dbl() function to apply this to each row of the STATE variable. The map() function creates a list, whereas the map_dbl() function creates a vector of class double. If we were to use map() we would need to use unlist() and pull().

poverty_rate_data %<>%
 mutate(length_state = map_dbl(STATE, str_length))

# Alternatively with map()
#poverty_rate_data %<>%
#mutate(length_state = unlist(map(pull(poverty_rate_data, STATE), str_length)))

poverty_rate_data
# A tibble: 2,136 × 7
   STATE                Total Number Number_se Percent   Percent_se length_state
   <chr>                <chr> <chr>  <chr>     <chr>     <chr>             <dbl>
 1 2018                 <NA>  <NA>   <NA>      <NA>      <NA>                  4
 2 Alabama              4877  779    65        16        1.3                   7
 3 Alaska               720   94     9         13.1      1.2                   6
 4 Arizona              7241  929    80        12.80000… 1.1000000…            7
 5 Arkansas             2912  462    38        15.9      1.3                   8
 6 California           39150 4664   184       11.9      0.5                  10
 7 Colorado             5739  521    51        9.099999… 0.9000000…            8
 8 Connecticut          3413  348    43        10.19999… 1.3                  11
 9 Delaware             976   72     9         7.400000… 1                     8
10 District of Columbia 692   102    8         14.69999… 1.1000000…           20
# … with 2,126 more rows

Great, now let’s look at the tail with our new variable length_state

tail(pull(poverty_rate_data, length_state))
[1]   9   7 285 164 129 101
poverty_rate_data %<>% 
  filter(length_state <100)

tail(poverty_rate_data)
# A tibble: 6 × 7
  STATE         Total Number Number_se Percent            Percent_se length_state
  <chr>         <chr> <chr>  <chr>     <chr>              <chr>             <dbl>
1 Vermont       520   62     22        12                 4                     7
2 Virginia      5204  647    72        12.4               1.3                   8
3 Washington    4223  538    65        12.699999999999999 1.3999999…           10
4 West Virginia 1952  297    49        15.199999999999999 2.2999999…           13
5 Wisconsin     4724  403    57        8.5                1.1000000…            9
6 Wyoming       468   49     20        10.4               4                     7

Looks good!

Now let’s select all the states that are actually year values to create a new variable about the year. We can do so by using the str_detect() function of the stringr package to look for digits or values of 0-9. This is indicated by using the "[:digit:]".

As you can see in the RStudio cheatsheet about regular expressions this notation indicates any digit between 0 and 9.

knitr::include_graphics(here("img", "regex.png"))

poverty_rate_data %>% 
  filter(str_detect(STATE, "[:digit:]")) %>%
  print(n = 51)
# A tibble: 41 × 7
   STATE     Total Number Number_se Percent Percent_se length_state
   <chr>     <chr> <chr>  <chr>     <chr>   <chr>             <dbl>
 1 2018      <NA>  <NA>   <NA>      <NA>    <NA>                  4
 2 2017 (21) <NA>  <NA>   <NA>      <NA>    <NA>                  9
 3 2017      <NA>  <NA>   <NA>      <NA>    <NA>                  4
 4 2016      <NA>  <NA>   <NA>      <NA>    <NA>                  4
 5 2015      <NA>  <NA>   <NA>      <NA>    <NA>                  4
 6 2014      <NA>  <NA>   <NA>      <NA>    <NA>                  4
 7 2013 (19) <NA>  <NA>   <NA>      <NA>    <NA>                  9
 8 2013 (18) <NA>  <NA>   <NA>      <NA>    <NA>                  9
 9 2012      <NA>  <NA>   <NA>      <NA>    <NA>                  4
10 2011      <NA>  <NA>   <NA>      <NA>    <NA>                  4
11 2010 (17) <NA>  <NA>   <NA>      <NA>    <NA>                  9
12 2009      <NA>  <NA>   <NA>      <NA>    <NA>                  4
13 2008      <NA>  <NA>   <NA>      <NA>    <NA>                  4
14 2007      <NA>  <NA>   <NA>      <NA>    <NA>                  4
15 2006      <NA>  <NA>   <NA>      <NA>    <NA>                  4
16 2005      <NA>  <NA>   <NA>      <NA>    <NA>                  4
17 2004 (14) <NA>  <NA>   <NA>      <NA>    <NA>                  9
18 2003      <NA>  <NA>   <NA>      <NA>    <NA>                  4
19 2002      <NA>  <NA>   <NA>      <NA>    <NA>                  4
20 2001      <NA>  <NA>   <NA>      <NA>    <NA>                  4
21 2000 (12) <NA>  <NA>   <NA>      <NA>    <NA>                  9
22 1999 (11) <NA>  <NA>   <NA>      <NA>    <NA>                  9
23 1998      <NA>  <NA>   <NA>      <NA>    <NA>                  4
24 1997      <NA>  <NA>   <NA>      <NA>    <NA>                  4
25 1996      <NA>  <NA>   <NA>      <NA>    <NA>                  4
26 1995      <NA>  <NA>   <NA>      <NA>    <NA>                  4
27 1994      <NA>  <NA>   <NA>      <NA>    <NA>                  4
28 1993 (10) <NA>  <NA>   <NA>      <NA>    <NA>                  9
29 1992 (9)  <NA>  <NA>   <NA>      <NA>    <NA>                  8
30 1991 (8)  <NA>  <NA>   <NA>      <NA>    <NA>                  8
31 1990      <NA>  <NA>   <NA>      <NA>    <NA>                  4
32 1989      <NA>  <NA>   <NA>      <NA>    <NA>                  4
33 1988      <NA>  <NA>   <NA>      <NA>    <NA>                  4
34 1987 (7)  <NA>  <NA>   <NA>      <NA>    <NA>                  8
35 1986      <NA>  <NA>   <NA>      <NA>    <NA>                  4
36 1985      <NA>  <NA>   <NA>      <NA>    <NA>                  4
37 1984      <NA>  <NA>   <NA>      <NA>    <NA>                  4
38 1983 (6)  <NA>  <NA>   <NA>      <NA>    <NA>                  8
39 1982      <NA>  <NA>   <NA>      <NA>    <NA>                  4
40 1981 (5)  <NA>  <NA>   <NA>      <NA>    <NA>                  8
41 1980      <NA>  <NA>   <NA>      <NA>    <NA>                  4

Some of the years (2013 and 2017) are listed twice with a number in parentheses, others are just listed once with a number in parentheses. Looking at the technical documentation, this seems to do with updates to the definition of poverty and to the methods used to estimate poverty levels. See here and here for more information. We will simply select one of the sets of data for 2013 and 2017.

poverty_rate_data %>% 
  filter(str_detect(STATE, "2013")) %>%
  filter(str_detect(STATE, "2017"))
# A tibble: 0 × 7
# … with 7 variables: STATE <chr>, Total <chr>, Number <chr>, Number_se <chr>,
#   Percent <chr>, Percent_se <chr>, length_state <dbl>

First let’s add the year value to our data.

There should be consistently data for 51 states (including DC). We can see that sometimes DC is spelled out and sometimes it is not.

poverty_rate_data %>% 
  filter(str_detect(STATE, "[:alpha:]")) %>%
  distinct(STATE) %>% print(n = 100)
# A tibble: 52 × 1
   STATE               
   <chr>               
 1 Alabama             
 2 Alaska              
 3 Arizona             
 4 Arkansas            
 5 California          
 6 Colorado            
 7 Connecticut         
 8 Delaware            
 9 District of Columbia
10 Florida             
11 Georgia             
12 Hawaii              
13 Idaho               
14 Illinois            
15 Indiana             
16 Iowa                
17 Kansas              
18 Kentucky            
19 Louisiana           
20 Maine               
21 Maryland            
22 Massachusetts       
23 Michigan            
24 Minnesota           
25 Mississippi         
26 Missouri            
27 Montana             
28 Nebraska            
29 Nevada              
30 New Hampshire       
31 New Jersey          
32 New Mexico          
33 New York            
34 North Carolina      
35 North Dakota        
36 Ohio                
37 Oklahoma            
38 Oregon              
39 Pennsylvania        
40 Rhode Island        
41 South Carolina      
42 South Dakota        
43 Tennessee           
44 Texas               
45 Utah                
46 Vermont             
47 Virginia            
48 Washington          
49 West Virginia       
50 Wisconsin           
51 Wyoming             
52 D.C.                

Now we will replace "D.C." with "District of Columbia" using str_replace(). We can use the tally() function of the dplyr package to check that we have fewer now.

poverty_rate_data %<>% 
mutate(STATE = str_replace(STATE, pattern = "D.C.", 
                              replacement = "District of Columbia" ))

poverty_rate_data %>% 
  filter(str_detect(STATE, "[:alpha:]")) %>%
  distinct(STATE) %>% tally()
# A tibble: 1 × 1
      n
  <int>
1    51

Great! Now are each of the states occurring as often as the unique year values? We can first check how many year values there are. Then can use the count() function of the dplyr package to check how often the states are repeated.

poverty_rate_data %>% 
  filter(str_detect(STATE, "[:digit:]")) %>%
  tally()
# A tibble: 1 × 1
      n
  <int>
1    41

There are 41 different sets of data according to year values.

poverty_rate_data %>% 
  filter(str_detect(STATE, "[:alpha:]")) %>%
  count(STATE) %>% 
  print(n = 51)
# A tibble: 51 × 2
   STATE                    n
   <chr>                <int>
 1 Alabama                 41
 2 Alaska                  41
 3 Arizona                 41
 4 Arkansas                41
 5 California              41
 6 Colorado                41
 7 Connecticut             41
 8 Delaware                41
 9 District of Columbia    41
10 Florida                 41
11 Georgia                 41
12 Hawaii                  41
13 Idaho                   41
14 Illinois                41
15 Indiana                 41
16 Iowa                    41
17 Kansas                  41
18 Kentucky                41
19 Louisiana               41
20 Maine                   41
21 Maryland                41
22 Massachusetts           41
23 Michigan                41
24 Minnesota               41
25 Mississippi             41
26 Missouri                41
27 Montana                 41
28 Nebraska                41
29 Nevada                  41
30 New Hampshire           41
31 New Jersey              41
32 New Mexico              41
33 New York                41
34 North Carolina          41
35 North Dakota            41
36 Ohio                    41
37 Oklahoma                41
38 Oregon                  41
39 Pennsylvania            41
40 Rhode Island            41
41 South Carolina          41
42 South Dakota            41
43 Tennessee               41
44 Texas                   41
45 Utah                    41
46 Vermont                 41
47 Virginia                41
48 Washington              41
49 West Virginia           41
50 Wisconsin               41
51 Wyoming                 41

Indeed, looks like each of the states are repeated the same number of times!

Now let’s create a new variable YEAR that repeats the year values for all of the different states and for the row that has just the year value for a total of 52.

year_values <- poverty_rate_data %>% 
  filter(str_detect(STATE, "[:digit:]")) %>%
  distinct(STATE)

  year_values<-rep(pull(year_values, STATE), each = 52)
setequal(length(year_values), length(poverty_rate_data$STATE))
[1] TRUE

Now we will add this to our poverty_rate_data. We will also remove the length_state variable using the select() function of the dplyr package and a minus sign before the variable name.

poverty_rate_data %<>%
  mutate(year_value = year_values) %>%
  select(-length_state)
poverty_rate_data %>% print(n = 100)
# A tibble: 2,132 × 7
    STATE                Total Number Number_se Percent   Percent_se  year_value
    <chr>                <chr> <chr>  <chr>     <chr>     <chr>       <chr>     
  1 2018                 <NA>  <NA>   <NA>      <NA>      <NA>        2018      
  2 Alabama              4877  779    65        16        1.3         2018      
  3 Alaska               720   94     9         13.1      1.2         2018      
  4 Arizona              7241  929    80        12.80000… 1.10000000… 2018      
  5 Arkansas             2912  462    38        15.9      1.3         2018      
  6 California           39150 4664   184       11.9      0.5         2018      
  7 Colorado             5739  521    51        9.099999… 0.90000000… 2018      
  8 Connecticut          3413  348    43        10.19999… 1.3         2018      
  9 Delaware             976   72     9         7.400000… 1           2018      
 10 District of Columbia 692   102    8         14.69999… 1.10000000… 2018      
 11 Florida              21117 2883   173       13.69999… 0.80000000… 2018      
 12 Georgia              10423 1548   115       14.80000… 1.10000000… 2018      
 13 Hawaii               1393  128    16        9.199999… 1.10000000… 2018      
 14 Idaho                1766  202    25        11.5      1.39999999… 2018      
 15 Illinois             12589 1292   130       10.30000… 1           2018      
 16 Indiana              6582  761    68        11.6      1           2018      
 17 Iowa                 3110  277    30        8.900000… 1           2018      
 18 Kansas               2835  212    27        7.5       0.90000000… 2018      
 19 Kentucky             4445  696    76        15.69999… 1.7         2018      
 20 Louisiana            4510  858    38        19        0.80000000… 2018      
 21 Maine                1321  153    19        11.6      1.39999999… 2018      
 22 Maryland             6030  480    50        8         0.80000000… 2018      
 23 Massachusetts        6883  601    59        8.699999… 0.90000000… 2018      
 24 Michigan             9913  1036   78        10.5      0.80000000… 2018      
 25 Minnesota            5746  456    47        7.900000… 0.80000000… 2018      
 26 Mississippi          2899  567    27        19.60000… 0.90000000… 2018      
 27 Missouri             6026  745    81        12.4      1.3         2018      
 28 Montana              1041  107    12        10.30000… 1.10000000… 2018      
 29 Nebraska             1893  199    25        10.5      1.3         2018      
 30 Nevada               3008  390    37        13        1.2         2018      
 31 New Hampshire        1349  82     11        6.099999… 0.80000000… 2018      
 32 New Jersey           8790  725    65        8.199999… 0.69999999… 2018      
 33 New Mexico           2054  342    27        16.60000… 1.3         2018      
 34 New York             19343 2145   110       11.1      0.59999999… 2018      
 35 North Carolina       10369 1355   96        13.1      0.90000000… 2018      
 36 North Dakota         745   72     9         9.699999… 1.2         2018      
 37 Ohio                 11452 1365   115       11.9      1           2018      
 38 Oklahoma             3858  518    48        13.4      1.2         2018      
 39 Oregon               4172  404    45        9.699999… 1.10000000… 2018      
 40 Pennsylvania         12519 1476   124       11.80000… 1           2018      
 41 Rhode Island         1036  92     15        8.900000… 1.39999999… 2018      
 42 South Carolina       5036  642    45        12.80000… 0.90000000… 2018      
 43 South Dakota         853   90     8         10.6      0.90000000… 2018      
 44 Tennessee            6665  800    73        12        1.10000000… 2018      
 45 Texas                28497 3894   173       13.69999… 0.59999999… 2018      
 46 Utah                 3173  219    37        6.900000… 1.2         2018      
 47 Vermont              616   60     7         9.699999… 1.10000000… 2018      
 48 Virginia             8393  821    86        9.800000… 1           2018      
 49 Washington           7555  647    101       8.599999… 1.3         2018      
 50 West Virginia        1762  279    21        15.9      1.2         2018      
 51 Wisconsin            5795  499    54        8.599999… 0.90000000… 2018      
 52 Wyoming              565   53     6         9.5       1.10000000… 2018      
 53 2017 (21)            <NA>  <NA>   <NA>      <NA>      <NA>        2017 (21) 
 54 Alabama              4801  735    58        15.30000… 1.2         2017 (21) 
 55 Alaska               719   87     12        12.1      1.7         2017 (21) 
 56 Arizona              6981  951    104       13.6      1.5         2017 (21) 
 57 Arkansas             2921  436    33        14.9      1.10000000… 2017 (21) 
 58 California           39247 4759   182       12.1      0.5         2017 (21) 
 59 Colorado             5527  489    51        8.900000… 0.90000000… 2017 (21) 
 60 Connecticut          3553  377    43        10.6      1.2         2017 (21) 
 61 Delaware             967   85     10        8.800000… 1.10000000… 2017 (21) 
 62 District of Columbia 691   96     8         13.9      1.10000000… 2017 (21) 
 63 Florida              20909 2809   173       13.4      0.80000000… 2017 (21) 
 64 Georgia              10231 1339   104       13.1      1           2017 (21) 
 65 Hawaii               1402  149    17        10.6      1.2         2017 (21) 
 66 Idaho                1730  199    23        11.5      1.3         2017 (21) 
 67 Illinois             12597 1454   102       11.5      0.80000000… 2017 (21) 
 68 Indiana              6532  762    70        11.69999… 1.10000000… 2017 (21) 
 69 Iowa                 3053  230    33        7.5       1.10000000… 2017 (21) 
 70 Kansas               2868  411    33        14.30000… 1.2         2017 (21) 
 71 Kentucky             4395  591    76        13.5      1.7         2017 (21) 
 72 Louisiana            4535  931    48        20.5      1.10000000… 2017 (21) 
 73 Maine                1315  163    19        12.4      1.39999999… 2017 (21) 
 74 Maryland             5977  451    58        7.599999… 1           2017 (21) 
 75 Massachusetts        6784  763    71        11.19999… 1           2017 (21) 
 76 Michigan             9895  1135   88        11.5      0.90000000… 2017 (21) 
 77 Minnesota            5619  479    57        8.5       1           2017 (21) 
 78 Mississippi          2948  544    27        18.5      0.90000000… 2017 (21) 
 79 Missouri             5988  683    81        11.4      1.39999999… 2017 (21) 
 80 Montana              1041  107    11        10.30000… 1           2017 (21) 
 81 Nebraska             1878  216    25        11.5      1.3         2017 (21) 
 82 Nevada               2979  392    37        13.19999… 1.2         2017 (21) 
 83 New Hampshire        1333  95     13        7.200000… 1           2017 (21) 
 84 New Jersey           9015  894    95        9.900000… 1.10000000… 2017 (21) 
 85 New Mexico           2035  402    28        19.69999… 1.39999999… 2017 (21) 
 86 New York             19735 2510   141       12.69999… 0.69999999… 2017 (21) 
 87 North Carolina       10297 1567   96        15.19999… 0.90000000… 2017 (21) 
 88 North Dakota         740   92     11        12.4      1.5         2017 (21) 
 89 Ohio                 11491 1479   98        12.9      0.90000000… 2017 (21) 
 90 Oklahoma             3817  490    47        12.80000… 1.2         2017 (21) 
 91 Oregon               4202  482    55        11.5      1.3         2017 (21) 
 92 Pennsylvania         12568 1373   94        10.9      0.80000000… 2017 (21) 
 93 Rhode Island         1046  118    15        11.30000… 1.39999999… 2017 (21) 
 94 South Carolina       4955  756    55        15.19999… 1.10000000… 2017 (21) 
 95 South Dakota         870   93     15        10.69999… 1.7         2017 (21) 
 96 Tennessee            6699  759    65        11.30000… 1           2017 (21) 
 97 Texas                28090 3715   186       13.19999… 0.69999999… 2017 (21) 
 98 Utah                 3130  272    34        8.699999… 1.10000000… 2017 (21) 
 99 Vermont              613   53     6         8.599999… 1           2017 (21) 
100 Virginia             8242  862    71        10.5      0.90000000… 2017 (21) 
# … with 2,032 more rows

Looks good! Now we will remove the rows that have just the year values by only preserving those with alpha characters.

poverty_rate_data %<>%
    filter(str_detect(STATE, "[:alpha:]"))

Now let’s remove the older data for 2013 and 2017 which is the data that appears lower in the tibble.

poverty_rate_data %<>%
filter(year_value != "2017") %>%
filter(year_value != "2013 (18)")

We also want to just keep the first 4 digits of the year_value and create a YEAR variable. We need to pull the year_value data because str_sub() expects a character vector not a tibble.

poverty_rate_data %<>%
  mutate(YEAR = str_sub(pull(., year_value), start = 1, end=4))
poverty_rate_data 
# A tibble: 1,989 × 8
   STATE       Total Number Number_se Percent     Percent_se    year_value YEAR 
   <chr>       <chr> <chr>  <chr>     <chr>       <chr>         <chr>      <chr>
 1 Alabama     4877  779    65        16          1.3           2018       2018 
 2 Alaska      720   94     9         13.1        1.2           2018       2018 
 3 Arizona     7241  929    80        12.8000000… 1.1000000000… 2018       2018 
 4 Arkansas    2912  462    38        15.9        1.3           2018       2018 
 5 California  39150 4664   184       11.9        0.5           2018       2018 
 6 Colorado    5739  521    51        9.09999999… 0.9000000000… 2018       2018 
 7 Connecticut 3413  348    43        10.1999999… 1.3           2018       2018 
 8 Delaware    976   72     9         7.40000000… 1             2018       2018 
 9 District o… 692   102    8         14.6999999… 1.1000000000… 2018       2018 
10 Florida     21117 2883   173       13.6999999… 0.8000000000… 2018       2018 
# … with 1,979 more rows

Looks good! Now we will just remove the extra variables and rename the variables we want to keep to be similar to our other data.

poverty_rate_data %<>%
  dplyr::select(- Number,
                - Number_se,
                - Percent_se,
                - Total,
                - year_value) %>%
  rename("VALUE" = Percent) %>%
  mutate(VARIABLE = "Poverty_rate",
         YEAR = as.numeric(YEAR),
         VALUE = as.numeric(VALUE))
head(poverty_rate_data)
# A tibble: 6 × 4
  STATE      VALUE  YEAR VARIABLE    
  <chr>      <dbl> <dbl> <chr>       
1 Alabama     16    2018 Poverty_rate
2 Alaska      13.1  2018 Poverty_rate
3 Arizona     12.8  2018 Poverty_rate
4 Arkansas    15.9  2018 Poverty_rate
5 California  11.9  2018 Poverty_rate
6 Colorado     9.1  2018 Poverty_rate

Looks great!


Violent crime



Click here to see details about how the violent crime data was wrangled

The crime_data was imported using read_lines() and we have some lines that we don’t necessarily need. A large amount of the original data is notes at the end of the table. We want to remove these lines. We can determine where they start by searching for the row that contains the first statement of these notes using the str_which() function of the stringr package. We will subtract one from this as there is a blank line in between.

tail(crime_data)
[1] ",,\"Vermont - The state UCR Program was unable to provide complete 1997 offense figures in accordance with UCR guidelines.  The 1996 and 1997 percent changes within the geographic division in which Vermont is categorized were applied to the valid 1996 state total to effect the 1997 state total.\""                                                                                                              
[2] "  "                                                                                                                                                                                                                                                                                                                                                                                                                     
[3] " "                                                                                                                                                                                                                                                                                                                                                                                                                      
[4] ",,\"Wisconsin - The state UCR Program was unable to provide complete 1998 offense figures in accordance with UCR guidelines.  The state total was estimated by using 1997 figures for the nonreporting areas and applying 1997 versus 1998 percentage changes for the division in which Wisconsin is located.  The estimates for the nonreporting areas were then increased by any actual 1998 crime counts received.\""
[5] " "                                                                                                                                                                                                                                                                                                                                                                                                                      
[6] "\"Sources: FBI, Uniform Crime Reports, prepared by the National Archive of Criminal Justice Data\" "                                                                                                                                                                                                                                                                                                                    
crime_data <- crime_data[-((str_which(crime_data, "The figures shown in this column for the offense of rape were estimated using the legacy UCR definition of rape")-1): length(crime_data))]
#crime_data <- crime_data[-(2143:length(crime_data))]
tail(crime_data)
[1] "2009,     544270,       1196,          11,         172,,          78,         935 "            
[2] "2010,     564554,       1117,           8,         162,,          77,         870 "            
[3] "2011,     567356,       1245,          18,         146,,          71,       1010 "             
[4] "2012,     576626,       1161,          14,         154,,          61,         932 "            
[5] "2013,     583223,       1212,          17,         144,         204,          74,         917 "
[6] "2014,     584153,       1142,          16,         126,         174,          53,         899 "

There are lines for each year from 1977 to 2014 as well as four lines about each state and the header information for each state. Here you can see what the original data looks like:

knitr::include_graphics(here("img", "crime_data.png"))

We want to delete the header information and only retain the lines numeric values or state names. Thus since there are 38 years worth of data for each state and 4 lines for each header, then each state has 42 lines. We want to delete the lines between and including line 2 to 4 for each state. We will save the header information once to use later.

head(crime_data)
[1] "Estimated crime in Alabama"                                                                                                           
[2] "\n,,National or state crime,,,,,,,"                                                                                                   
[3] "\n,,Violent crime,,,,,,,"                                                                                                             
[4] "\nYear,Population,Violent crime total,Murder and nonnegligent Manslaughter,Legacy rape /1,Revised rape /2,Robbery,Aggravated assault,"
[5] "1977,   3690000,      15293,         524,         929,,       3572,      10268 "                                                      
[6] "1978,   3742000,      15682,         499,         954,,       3708,      10521 "                                                      
x <- 2014-1977+1
rep_cycle <- 4 + x
rep_cycle_cut <- 2 + x
colnames_crime<-(crime_data[4])

So starting at line 2 and and 3 and 4 we create a sequence of numbers that increase by the number of rows of the length of the individual state data. We can do so using the base seq() function. We can take a look at these in order using the base sort() function.

delete_rows <- c(seq(from = 2,
                       to = length(crime_data),
                       by = rep_cycle),
                 seq(from = 3,
                       to = length(crime_data),
                       by = rep_cycle), 
                 seq(from = 4,
                       to = length(crime_data),
                       by = rep_cycle))
sort(delete_rows)
  [1]    2    3    4   44   45   46   86   87   88  128  129  130  170  171  172
 [16]  212  213  214  254  255  256  296  297  298  338  339  340  380  381  382
 [31]  422  423  424  464  465  466  506  507  508  548  549  550  590  591  592
 [46]  632  633  634  674  675  676  716  717  718  758  759  760  800  801  802
 [61]  842  843  844  884  885  886  926  927  928  968  969  970 1010 1011 1012
 [76] 1052 1053 1054 1094 1095 1096 1136 1137 1138 1178 1179 1180 1220 1221 1222
 [91] 1262 1263 1264 1304 1305 1306 1346 1347 1348 1388 1389 1390 1430 1431 1432
[106] 1472 1473 1474 1514 1515 1516 1556 1557 1558 1598 1599 1600 1640 1641 1642
[121] 1682 1683 1684 1724 1725 1726 1766 1767 1768 1808 1809 1810 1850 1851 1852
[136] 1892 1893 1894 1934 1935 1936 1976 1977 1978 2018 2019 2020 2060 2061 2062
[151] 2102 2103 2104

Thus we will delete lines 2, 3, and 4 and then skip 40 lines (to account for the state information for the first state, the lines of information for the 38 years, and then the state information for the next state) and then delete the next 3 consecutive lines and so on. We can indeed see that line 44-46 are what we wish to remove.

crime_data[44:46]
[1] "\n,,National or state crime,,,,,,,"                                                                                                   
[2] "\n,,Violent crime,,,,,,,"                                                                                                             
[3] "\nYear,Population,Violent crime total,Murder and nonnegligent Manslaughter,Legacy rape /1,Revised rape /2,Robbery,Aggravated assault,"
crime_data <- crime_data[-delete_rows]

Nice!

Now we can select all the lines that have state information. We can repeat each of these for the 38 years for each state as well as this line that contains the state information by using the base rep() function with the each = argument. Finally we will remove the "Estimated crime in " portion of the string using the str_remove() function of the stringr package. We will later combine this with the crime data.

state_label_order <-crime_data[str_which(crime_data, "Estimated crime")]
state_label_order
 [1] "Estimated crime in Alabama"             
 [2] "Estimated crime in Alaska"              
 [3] "Estimated crime in Arizona"             
 [4] "Estimated crime in Arkansas"            
 [5] "Estimated crime in California"          
 [6] "Estimated crime in Colorado"            
 [7] "Estimated crime in Connecticut"         
 [8] "Estimated crime in Delaware"            
 [9] "Estimated crime in District of Columbia"
[10] "Estimated crime in Florida"             
[11] "Estimated crime in Georgia"             
[12] "Estimated crime in Hawaii"              
[13] "Estimated crime in Idaho"               
[14] "Estimated crime in Illinois"            
[15] "Estimated crime in Indiana"             
[16] "Estimated crime in Iowa"                
[17] "Estimated crime in Kansas"              
[18] "Estimated crime in Kentucky"            
[19] "Estimated crime in Louisiana"           
[20] "Estimated crime in Maine"               
[21] "Estimated crime in Maryland"            
[22] "Estimated crime in Massachusetts"       
[23] "Estimated crime in Michigan"            
[24] "Estimated crime in Minnesota"           
[25] "Estimated crime in Mississippi"         
[26] "Estimated crime in Missouri"            
[27] "Estimated crime in Montana"             
[28] "Estimated crime in Nebraska"            
[29] "Estimated crime in Nevada"              
[30] "Estimated crime in New Hampshire"       
[31] "Estimated crime in New Jersey"          
[32] "Estimated crime in New Mexico"          
[33] "Estimated crime in New York"            
[34] "Estimated crime in North Carolina"      
[35] "Estimated crime in North Dakota"        
[36] "Estimated crime in Ohio"                
[37] "Estimated crime in Oklahoma"            
[38] "Estimated crime in Oregon"              
[39] "Estimated crime in Pennsylvania"        
[40] "Estimated crime in Rhode Island"        
[41] "Estimated crime in South Carolina"      
[42] "Estimated crime in South Dakota"        
[43] "Estimated crime in Tennessee"           
[44] "Estimated crime in Texas"               
[45] "Estimated crime in Utah"                
[46] "Estimated crime in Vermont"             
[47] "Estimated crime in Virginia"            
[48] "Estimated crime in Washington"          
[49] "Estimated crime in West Virginia"       
[50] "Estimated crime in Wisconsin"           
[51] "Estimated crime in Wyoming"             
state_label_order <- rep(state_label_order, each = 38)

crime_states <-str_remove(state_label_order, pattern = "Estimated crime in ")
head(crime_states)
[1] "Alabama" "Alabama" "Alabama" "Alabama" "Alabama" "Alabama"

Nice! Now for the rest of the data. We now need to remove the lines with the state information.

crime_data <-crime_data[-str_which(crime_data, "Estimated crime")]
head(crime_data)
[1] "1977,   3690000,      15293,         524,         929,,       3572,      10268 "
[2] "1978,   3742000,      15682,         499,         954,,       3708,      10521 "
[3] "1979,   3769000,      15578,         496,       1037,,       4127,       9918 " 
[4] "1980,   3861466,      17320,         509,       1158,,       5102,      10551 " 
[5] "1981,   3916000,      18423,         465,       1021,,       4952,      11985 " 
[6] "1982,   3943000,      17653,         417,       1026,,       4417,      11793 " 
tail(crime_data)
[1] "2009,     544270,       1196,          11,         172,,          78,         935 "            
[2] "2010,     564554,       1117,           8,         162,,          77,         870 "            
[3] "2011,     567356,       1245,          18,         146,,          71,       1010 "             
[4] "2012,     576626,       1161,          14,         154,,          61,         932 "            
[5] "2013,     583223,       1212,          17,         144,         204,          74,         917 "
[6] "2014,     584153,       1142,          16,         126,         174,          53,         899 "

It appears that the data is comma separated with 8 columns. One of the middle columns often has no values, we need to fill these in with NAs. We can use the read_csv() function from the readr package to do this. It turns out you don’t have to have a file, but you can also use a string our a vector.

crime_data_sep <-read_csv(crime_data, col_names = FALSE)
head(crime_data)
[1] "1977,   3690000,      15293,         524,         929,,       3572,      10268 "
[2] "1978,   3742000,      15682,         499,         954,,       3708,      10521 "
[3] "1979,   3769000,      15578,         496,       1037,,       4127,       9918 " 
[4] "1980,   3861466,      17320,         509,       1158,,       5102,      10551 " 
[5] "1981,   3916000,      18423,         465,       1021,,       4952,      11985 " 
[6] "1982,   3943000,      17653,         417,       1026,,       4417,      11793 " 

Nice! Now we just need our column names. Recall that we saved this information.

colnames_crime
[1] "\nYear,Population,Violent crime total,Murder and nonnegligent Manslaughter,Legacy rape /1,Revised rape /2,Robbery,Aggravated assault,"
colnames(crime_data_sep) <-c("Year",
                             "Population",
                             "Violent_crime_total",
                             "Murder_and_nonnegligent_Manslaughter",
                             "Legacy_rape" ,
                             "Revised_rape", 
                             "Robbery",
                             "Aggravated_assault")
head(crime_data_sep)
# A tibble: 6 × 8
   Year Population Violent_crime_to… Murder_and_nonneg… Legacy_rape Revised_rape
  <dbl>      <dbl>             <dbl>              <dbl>       <dbl>        <dbl>
1  1977    3690000             15293                524         929           NA
2  1978    3742000             15682                499         954           NA
3  1979    3769000             15578                496        1037           NA
4  1980    3861466             17320                509        1158           NA
5  1981    3916000             18423                465        1021           NA
6  1982    3943000             17653                417        1026           NA
# … with 2 more variables: Robbery <dbl>, Aggravated_assault <dbl>

We also want to combine this with the state information we collected earlier. We will use the bind_cols() function of the dplyr package to do this. This requires that the data have the same number of rows.

crime_data_sep <-bind_cols(STATE =crime_states, 
          crime_data_sep)

Now we will rename the Viol_crime_count variable to be Variable and we will remove all of the other columns except for Year. We will also rename the variables to look like the other datasets.

crime_data <- crime_data_sep %>%
  mutate(VARIABLE = "Viol_crime_count") %>%
  rename("VALUE" = Violent_crime_total) %>%
  rename("YEAR" = Year) %>%
  select(YEAR,STATE, VARIABLE, VALUE)

crime_data
# A tibble: 1,938 × 4
    YEAR STATE   VARIABLE         VALUE
   <dbl> <chr>   <chr>            <dbl>
 1  1977 Alabama Viol_crime_count 15293
 2  1978 Alabama Viol_crime_count 15682
 3  1979 Alabama Viol_crime_count 15578
 4  1980 Alabama Viol_crime_count 17320
 5  1981 Alabama Viol_crime_count 18423
 6  1982 Alabama Viol_crime_count 17653
 7  1983 Alabama Viol_crime_count 16471
 8  1984 Alabama Viol_crime_count 17204
 9  1985 Alabama Viol_crime_count 18398
10  1986 Alabama Viol_crime_count 22616
# … with 1,928 more rows

Right-to-carry laws



Click here to see details about how the RTC Law data was wrangled

The information about the laws for each state are located on page 62 of the Donohue, et al. article, so first we will select just this page. We can print part of the character string for this page using the utils str() function and the ncar.max argument.

DAWpaper_p_62 <- DAWpaper[[62]]
str(DAWpaper_p_62, nchar.max = 1000)
 chr "                                          Table A1: RTC Adoption Dates\n\n         State         Effective Date of RTC Law   Fraction of Year In Effect Year of Passage   RTC Date (Synthetic Controls Analysis)\n      Alabama                      1975                                                                        1975\n       Alaska                   10/1/1994                            0.252                                     1995\n       Arizona                  7/17/1994                            0.460                                     1995\n      Arkansas                  7/27/1995                            0.433                                     1996\n     California                    N/A                                                                            0\n      Colorado                  5/17/2003                            0.627                                     2003\n    Connecticut                    1970                                "| __truncated__

We can also use the cat function to see the data printed nicely to see what we are going for.

cat(DAWpaper_p_62)
                                          Table A1: RTC Adoption Dates

         State         Effective Date of RTC Law   Fraction of Year In Effect Year of Passage   RTC Date (Synthetic Controls Analysis)
      Alabama                      1975                                                                        1975
       Alaska                   10/1/1994                            0.252                                     1995
       Arizona                  7/17/1994                            0.460                                     1995
      Arkansas                  7/27/1995                            0.433                                     1996
     California                    N/A                                                                            0
      Colorado                  5/17/2003                            0.627                                     2003
    Connecticut                    1970                                                                        1970
      Delaware                     N/A                                                                            0
District of Columbia               N/A                                                                            0
       Florida                  10/1/1987                            0.252                                     1988
       Georgia                  8/25/1989                            0.353                                     1990
       Hawaii                      N/A                                                                            0
        Idaho                    7/1/1990                            0.504                                     1990
       Illinois                  1/5/2014                                                                      2014
       Indiana                  1/15/1980                            0.962                                     1980
         Iowa                    1/1/2011                            1.000                                     2011
       Kansas                    1/1/2007                            1.000                                     2007
      Kentucky                  10/1/1996                            0.251                                     1997
      Louisiana                 4/19/1996                            0.702                                     1996
        Maine                   9/19/1985                            0.285                                     1986
      Maryland                     N/A                                                                            0
   Massachusetts                   N/A                                                                            0
      Michigan                   7/1/2001                            0.504                                     2001
     Minnesota                  5/28/2003                            0.597                                     2003
     Mississippi                 7/1/1990                            0.504                                     1990
      Missouri                  2/26/2004                            0.847                                     2004
      Montana                   10/1/1991                            0.252                                     1992
      Nebraska                   1/1/2007                            1.000                                     2007
       Nevada                   10/1/1995                            0.252                                     1996
  New Hampshire                    1959                                                                        1959
     New Jersey                    N/A                                                                            0
    New Mexico                   1/1/2004                            1.000                                     2004
     New York                      N/A                                                                            0
  North Carolina                12/1/1995                            0.085                                     1996
   North Dakota                  8/1/1985                            0.419                                     1986
         Ohio                    4/8/2004                            0.732                                     2004
     Oklahoma                    1/1/1996                            1.000                                     1996
       Oregon                    1/1/1990                            1.000                                     1990
   Pennsylvania                 6/17/1989                            0.542                                     1989
    Philadelphia               10/11/1995                            0.225                                     1996
   Rhode Island                    N/A                                                                            0
  South Carolina                8/23/1996                            0.358                                     1997
   South Dakota                  7/1/1985                            0.504                                     1985
     Tennessee                  10/1/1996                            0.251                                     1997
        Texas                    1/1/1996                            1.000                                     1996
         Utah                    5/1/1995                            0.671                                     1995
      Vermont                      1970                                                                        1970
       Virginia                  5/5/1995                            0.660                                     1995
    Washington                     1961                                                                        1961
   West Virginia                 7/7/1989                            0.488                                     1990
     Wisconsin                  11/1/2011                            0.167                                     2012
      Wyoming                   10/1/1994                            0.252                                     1995

                                                                60

We can see that this is one continuous character string. We can separate into lines based on the presence of "\n" in the string using the str_split() function of the stringr package. We need to unlist the data first, as the output of str_split() is a list. Finally, we can convert it to a tibble using the as.tibble() function of the tibble package. We also see that we don’t need the first line about the table. We can remove this with the slice() function of the dplyr package. We can also use this to remove the column names so that we can replace them. Thus we will use slice(-(1:2)) to remove the first two lines.

So we will split and unlit() the data.

p_62 <- DAWpaper_p_62 %>%
    str_split("\n") %>%
    unlist() %>%
    dplyr::as_tibble() %>%
    slice(-(1:2))

head(p_62)
# A tibble: 6 × 1
  value                                                                         
  <chr>                                                                         
1 "         State         Effective Date of RTC Law   Fraction of Year In Effec…
2 "      Alabama                      1975                                     …
3 "       Alaska                   10/1/1994                            0.252  …
4 "       Arizona                  7/17/1994                            0.460  …
5 "      Arkansas                  7/27/1995                            0.433  …
6 "     California                    N/A                                      …
tail(p_62)
# A tibble: 6 × 1
  value                                                               
  <chr>                                                               
1 ""                                                                  
2 ""                                                                  
3 ""                                                                  
4 ""                                                                  
5 "                                                                60"
6 ""                                                                  

We also see by looking at the tail that we want to remove the last two lines. One is empty and the other has only 63 characters, which is the line with the page number.

p_62 %<>%
  rename(RTC = value)
p_62 %>%
  mutate(RTC = map_chr(RTC, str_length)) %>%tail()
# A tibble: 6 × 1
  RTC  
  <chr>
1 0    
2 0    
3 0    
4 0    
5 66   
6 0    
p_62[53,] # physcial page 60
# A tibble: 1 × 1
  RTC                                                                           
  <chr>                                                                         
1 "      Wyoming                   10/1/1994                            0.252  …
p_62[54,] # empty line
# A tibble: 1 × 1
  RTC  
  <chr>
1 ""   
p_62 %<>%
    slice(-c(53:54))

Now we will try splitting by spaces. We can show the output withe the first() and nth() functions of the dplyr package.

p_62 %>% pull(RTC) %>% map(str_split, pattern = " ") %>% first()
[[1]]
 [1] ""           ""           ""           ""           ""          
 [6] ""           ""           ""           ""           "State"     
[11] ""           ""           ""           ""           ""          
[16] ""           ""           ""           "Effective"  "Date"      
[21] "of"         "RTC"        "Law"        ""           ""          
[26] "Fraction"   "of"         "Year"       "In"         "Effect"    
[31] "Year"       "of"         "Passage"    ""           ""          
[36] "RTC"        "Date"       "(Synthetic" "Controls"   "Analysis)" 
p_62 %>% pull(RTC) %>% map(str_split, pattern = " ") %>% nth( 5)
[[1]]
 [1] ""          ""          ""          ""          ""          ""         
 [7] "Arkansas"  ""          ""          ""          ""          ""         
[13] ""          ""          ""          ""          ""          ""         
[19] ""          ""          ""          ""          ""          ""         
[25] "7/27/1995" ""          ""          ""          ""          ""         
[31] ""          ""          ""          ""          ""          ""         
[37] ""          ""          ""          ""          ""          ""         
[43] ""          ""          ""          ""          ""          ""         
[49] ""          ""          ""          ""          "0.433"     ""         
[55] ""          ""          ""          ""          ""          ""         
[61] ""          ""          ""          ""          ""          ""         
[67] ""          ""          ""          ""          ""          ""         
[73] ""          ""          ""          ""          ""          ""         
[79] ""          ""          ""          ""          ""          ""         
[85] ""          ""          ""          ""          ""          "1996"     

Interesting, we can see that there are lots of spaces between the elements of the table and that they vary by line. For example there are 6 spaces before Alabama and 7 spaces before Alaska.

Overall, that didn’t work quite like we expected.

Recall from the cheatsheet that "\\s" indicates a space. There are also ways to specify how many spaces using curly brackets{}.

knitr::include_graphics(here("img", "regex.png"))

knitr::include_graphics(here("img", "quantifiers.png"))

The spacing appears to vary quite a bit. WE can use the str_count() function of the stringr package to see how often we have white spaces larger than 5, 10, 15, or 40 spaces.

# how often are there white spaces with more than 5 spaces
p_62 %>% 
  pull(RTC) %>% 
  map(str_count, pattern = "\\s{5,}") %>% 
  unlist()
 [1] 2 3 4 4 4 3 4 2 3 2 4 4 3 4 3 4 4 4 4 4 4 3 2 4 4 4 4 4 4 4 2 3 3 3 3 3 4 4
[39] 4 3 3 2 3 3 4 4 4 3 4 2 3 4 0 0 0 1 0
# how often are there white spaces with more than 10 spaces
p_62 %>% 
  pull(RTC) %>% 
  map(str_count, pattern = "\\s{10,}") %>%
  unlist()
 [1] 0 2 3 3 3 2 3 2 2 2 3 3 2 3 2 3 3 3 3 3 3 2 2 3 3 3 3 3 3 3 2 2 3 2 3 3 3 3
[39] 3 3 3 2 3 3 3 3 3 2 3 2 3 3 0 0 0 1 0
# how often are there white spaces with more than 15 spaces
p_62 %>% 
  pull(RTC) %>% 
  map(str_count, pattern = "\\s{15,}") %>%
  unlist()
 [1] 0 2 3 3 3 2 3 2 2 2 3 3 2 3 2 3 3 3 3 3 3 2 2 3 3 3 3 3 3 3 2 2 3 2 3 3 3 3
[39] 3 3 3 2 3 3 3 3 3 2 3 2 3 3 0 0 0 1 0
# how often are there white spaces with more than 40 spaces
p_62 %>% 
  pull(RTC) %>%
  map(str_count, pattern = "\\s{40,}") %>% 
  unlist()
 [1] 0 1 0 0 0 1 0 1 1 1 0 0 1 0 1 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 1 1 0 1 0 0 0 0
[39] 0 0 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0

Rows with white spaces with more than 40 consecutive spaces is less common. It appears to be the case in the 1st and 5th row.

If we take a look at those rows we can see that this occurs when we have a missing value.

cat(DAWpaper_p_62)
                                          Table A1: RTC Adoption Dates

         State         Effective Date of RTC Law   Fraction of Year In Effect Year of Passage   RTC Date (Synthetic Controls Analysis)
      Alabama                      1975                                                                        1975
       Alaska                   10/1/1994                            0.252                                     1995
       Arizona                  7/17/1994                            0.460                                     1995
      Arkansas                  7/27/1995                            0.433                                     1996
     California                    N/A                                                                            0
      Colorado                  5/17/2003                            0.627                                     2003
    Connecticut                    1970                                                                        1970
      Delaware                     N/A                                                                            0
District of Columbia               N/A                                                                            0
       Florida                  10/1/1987                            0.252                                     1988
       Georgia                  8/25/1989                            0.353                                     1990
       Hawaii                      N/A                                                                            0
        Idaho                    7/1/1990                            0.504                                     1990
       Illinois                  1/5/2014                                                                      2014
       Indiana                  1/15/1980                            0.962                                     1980
         Iowa                    1/1/2011                            1.000                                     2011
       Kansas                    1/1/2007                            1.000                                     2007
      Kentucky                  10/1/1996                            0.251                                     1997
      Louisiana                 4/19/1996                            0.702                                     1996
        Maine                   9/19/1985                            0.285                                     1986
      Maryland                     N/A                                                                            0
   Massachusetts                   N/A                                                                            0
      Michigan                   7/1/2001                            0.504                                     2001
     Minnesota                  5/28/2003                            0.597                                     2003
     Mississippi                 7/1/1990                            0.504                                     1990
      Missouri                  2/26/2004                            0.847                                     2004
      Montana                   10/1/1991                            0.252                                     1992
      Nebraska                   1/1/2007                            1.000                                     2007
       Nevada                   10/1/1995                            0.252                                     1996
  New Hampshire                    1959                                                                        1959
     New Jersey                    N/A                                                                            0
    New Mexico                   1/1/2004                            1.000                                     2004
     New York                      N/A                                                                            0
  North Carolina                12/1/1995                            0.085                                     1996
   North Dakota                  8/1/1985                            0.419                                     1986
         Ohio                    4/8/2004                            0.732                                     2004
     Oklahoma                    1/1/1996                            1.000                                     1996
       Oregon                    1/1/1990                            1.000                                     1990
   Pennsylvania                 6/17/1989                            0.542                                     1989
    Philadelphia               10/11/1995                            0.225                                     1996
   Rhode Island                    N/A                                                                            0
  South Carolina                8/23/1996                            0.358                                     1997
   South Dakota                  7/1/1985                            0.504                                     1985
     Tennessee                  10/1/1996                            0.251                                     1997
        Texas                    1/1/1996                            1.000                                     1996
         Utah                    5/1/1995                            0.671                                     1995
      Vermont                      1970                                                                        1970
       Virginia                  5/5/1995                            0.660                                     1995
    Washington                     1961                                                                        1961
   West Virginia                 7/7/1989                            0.488                                     1990
     Wisconsin                  11/1/2011                            0.167                                     2012
      Wyoming                   10/1/1994                            0.252                                     1995

                                                                60

So we will replace white spaces with more than 40 consecutive spaces with NA. Let’s also remove the leading white spaces that varies in front of the state names, as DC does not have any and this could cause a problem later. We will also replace any white spaces of 2 consecutive spaces or more , but less than 15 white spaces with “|” so that we can split the data based on this symbol. Thus we will also put these around the NA value that we are using replace the white spaces made of 40+ spaces.

p_62b <-p_62 %>%
  mutate(RTC = str_replace_all(pull(., RTC), "\\s{40,}", "|N/A|")) %>%
  mutate(RTC =str_trim(pull(., RTC), side = "left")) %>%
  mutate(RTC = str_replace_all(pull(., RTC), "\\s{2,15}", "|"))
head(p_62b)
# A tibble: 6 × 1
  RTC                                                                           
  <chr>                                                                         
1 State|Effective Date of RTC Law|Fraction of Year In Effect Year of Passage|RT…
2 Alabama||1975|N/A|1975                                                        
3 Alaska||10/1/1994||0.252|||1995                                               
4 Arizona||7/17/1994||0.460|||1995                                              
5 Arkansas||7/27/1995||0.433|||1996                                             
6 California||N/A|N/A|0                                                         

Now anytime there is one or more "|" we should have a column break. So now we will split the data by this symbol.

p_62b <-pull(p_62b, RTC) %>%
  str_split( "\\|{1,}") 

head(p_62b)
[[1]]
[1] "State"                                     
[2] "Effective Date of RTC Law"                 
[3] "Fraction of Year In Effect Year of Passage"
[4] "RTC Date (Synthetic Controls Analysis)"    

[[2]]
[1] "Alabama" "1975"    "N/A"     "1975"   

[[3]]
[1] "Alaska"    "10/1/1994" "0.252"     "1995"     

[[4]]
[1] "Arizona"   "7/17/1994" "0.460"     "1995"     

[[5]]
[1] "Arkansas"  "7/27/1995" "0.433"     "1996"     

[[6]]
[1] "California" "N/A"        "N/A"        "0"         

Great! Now we want to put our data in tibble format. To do so we need to bind the rows together. We can do so using the base rbind() function. We will use this instead of the bind_rows() function of dplyr because rbind() is less restrictive and allows for columns without names. We will use the base do.call() function, so that this is performed along each character string within the list of p_62b while maintaining the structure. Then we create a tibble out of this.

p_62 <- as.tibble(do.call(rbind, p_62b))

colnames(p_62) <- c("STATE",
                    "E_Date_RTC",
                    "Frac_Yr_Eff_Yr_Pass",
                    "RTC_Date_SA")

p_62 <- p_62 %>%
  dplyr::select(STATE, RTC_Date_SA) %>%
  rename("RTC_LAW_YEAR"= RTC_Date_SA) %>%
  mutate(RTC_LAW_YEAR = as.numeric(RTC_LAW_YEAR)) %>%
  mutate(RTC_LAW_YEAR = case_when(RTC_LAW_YEAR == 0 ~ Inf,
                              TRUE ~ RTC_LAW_YEAR))

RTC <-p_62
RTC
# A tibble: 57 × 2
   STATE                RTC_LAW_YEAR
   <chr>                       <dbl>
 1 State                          NA
 2 Alabama                      1975
 3 Alaska                       1995
 4 Arizona                      1995
 5 Arkansas                     1996
 6 California                    Inf
 7 Colorado                     2003
 8 Connecticut                  1970
 9 Delaware                      Inf
10 District of Columbia          Inf
# … with 47 more rows

Joining Data


Now we will join the data from the different data sets together to create a tibble of data for an analysis that will be similar to the data used by Donohue et al. {target="_blank"} and Mustard and Lott.

First we need to check that our data is indeed ready to be joined. We need to make sure that the column names are the same for each dataset that we intend to combine together.

We will use the compare_df_cols() and compare_df_cols_same() functions of the janitor package, to ensure that the column names are the same and that the column values are the same type so that the tibbles can be joined by row.

If they can be joined by row, then compare_df_cols_same() returns the value TRUE, while compare_df_cols(), provides a description of the columns.

library(janitor)

data_list <-  list(dem_DONOHUE,
                dem_LOTT,
                population_data,
                ue_rate_data,
                poverty_rate_data,
                crime_data,
                ps_data) #police staffing

janitor::compare_df_cols_same(data_list)
[1] TRUE
janitor::compare_df_cols(data_list)
  column_name data_list_1 data_list_2 data_list_3 data_list_4 data_list_5
1       STATE   character   character   character   character   character
2       VALUE     numeric     numeric     numeric     numeric     numeric
3    VARIABLE   character   character   character   character   character
4        YEAR     numeric     numeric     numeric     numeric     numeric
  data_list_6 data_list_7
1   character   character
2     numeric     numeric
3   character   character
4     numeric     numeric
checkstate <- function(x) { x %<>% distinct(STATE) %>% tally() %>% pull(n) }
map(data_list, checkstate)
[[1]]
[1] 51

[[2]]
[1] 51

[[3]]
[1] 51

[[4]]
[1] 51

[[5]]
[1] 51

[[6]]
[1] 51

[[7]]
[1] 51
checkyear <- function(x) { x %<>% distinct(YEAR) %>% tally() %>% pull(n) }
map(data_list, checkyear)
[[1]]
[1] 34

[[2]]
[1] 34

[[3]]
[1] 34

[[4]]
[1] 44

[[5]]
[1] 39

[[6]]
[1] 38

[[7]]
[1] 38

Donohue, et al.


We will now bind the demographic data that we made for the Donohue-like analysis called dem_DONOHUE, as well as all the other datasets that we have wrangled. This is possible because we have the same column names for each dataset. We will also use the pivot_wider() function of the tidyr package to change the shape of the data. This will make the data have more columns. Each unique value in the column called VARIABLE will be used to make new columns. and the values for each will come from the column called VALUE.

DONOHUE_DF <- bind_rows(dem_DONOHUE,
                        ue_rate_data,
                        poverty_rate_data,
                        crime_data,
                        population_data,
                        ps_data)
head(DONOHUE_DF)
# A tibble: 6 × 4
   YEAR STATE   VARIABLE                    VALUE
  <dbl> <chr>   <chr>                       <dbl>
1  1977 Alabama Black_Male_15_to_19_years  1.55  
2  1977 Alabama Black_Male_20_to_39_years  3.04  
3  1977 Alabama Other_Male_15_to_19_years  0.0178
4  1977 Alabama Other_Male_20_to_39_years  0.0642
5  1977 Alabama White_Male_15_to_19_years  3.58  
6  1977 Alabama White_Male_20_to_39_years 11.1   
DONOHUE_DF %<>%
  pivot_wider(names_from = "VARIABLE",
              values_from = "VALUE")

DONOHUE_DF %>%
  slice_sample(n = 10) %>%
  glimpse()
Rows: 10
Columns: 13
$ YEAR                      <dbl> 1982, 1978, 1993, 1998, 1998, 2016, 2008, 20…
$ STATE                     <chr> "Indiana", "Oklahoma", "Rhode Island", "New …
$ Black_Male_15_to_19_years <dbl> 0.39641942, 0.43275524, 0.19752428, 0.703027…
$ Black_Male_20_to_39_years <dbl> 1.1183541, 0.9699746, 0.8113428, 2.6955630, …
$ Other_Male_15_to_19_years <dbl> 0.03167551, 0.35342021, 0.10843291, 0.204552…
$ Other_Male_20_to_39_years <dbl> 0.1260803, 0.8188570, 0.4721141, 0.9650934, …
$ White_Male_15_to_19_years <dbl> 4.022955, 4.119929, 2.703808, 2.432495, 3.34…
$ White_Male_20_to_39_years <dbl> 14.73968, 13.30899, 15.05454, 10.96980, 11.5…
$ Unemployment_rate         <dbl> 12.0, 3.6, 7.7, 5.6, 6.3, 3.1, 3.9, 5.9, 4.3…
$ Poverty_rate              <dbl> 12.6, NA, 11.2, 16.7, 9.4, 11.1, 7.0, 16.5, …
$ Viol_crime_count          <dbl> 16444, 10165, 4017, 115915, 4015, NA, 2054, …
$ Population                <dbl> 5467946, 2912963, 997852, 18159175, 615205, …
$ police_per_100k_lag       <dbl> 175.5687, 192.6904, 279.8010, 459.1894, 288.…

We will also add the Right to Carry Law data using the left_join() function of the dplyr package. Which will place the DONOHUE_DF data on the left of the RTC data. Values will be matched by STATE. Then we will create a new variable called RTC_LAW using the mutate() function and the case_when() function of the dplyr package that will have the value TRUE if the current year data is equal to or greater than the year that a more permissive RTC law was adopted, otherwise the value will be FALSE.

head(RTC)
# A tibble: 6 × 2
  STATE      RTC_LAW_YEAR
  <chr>             <dbl>
1 State                NA
2 Alabama            1975
3 Alaska             1995
4 Arizona            1995
5 Arkansas           1996
6 California          Inf
DONOHUE_DF %<>%
  left_join(RTC , by = c("STATE")) %>%
  mutate(RTC_LAW = case_when(YEAR >= RTC_LAW_YEAR ~ TRUE,
                              TRUE ~ FALSE))

DONOHUE_DF %>%
  slice_sample(n = 10) %>%
  glimpse()
Rows: 10
Columns: 15
$ YEAR                      <dbl> 2000, 2012, 2015, 2017, 1994, 2020, 2019, 20…
$ STATE                     <chr> "Oklahoma", "Wisconsin", "Delaware", "Pennsy…
$ Black_Male_15_to_19_years <dbl> 0.37549593, NA, NA, NA, 0.30501789, NA, NA, …
$ Black_Male_20_to_39_years <dbl> 1.2110185, NA, NA, NA, 1.4013203, NA, NA, 0.…
$ Other_Male_15_to_19_years <dbl> 0.6899966, NA, NA, NA, 0.4413584, NA, NA, 0.…
$ Other_Male_20_to_39_years <dbl> 1.9453069, NA, NA, NA, 2.1232117, NA, NA, 1.…
$ White_Male_15_to_19_years <dbl> 2.974787, NA, NA, NA, 2.655022, NA, NA, 3.39…
$ White_Male_20_to_39_years <dbl> 10.89523, NA, NA, NA, 13.93190, NA, NA, 11.2…
$ Unemployment_rate         <dbl> 3.0, 7.0, 4.9, 4.9, 8.6, NA, 5.4, 4.4, 3.6, …
$ Poverty_rate              <dbl> 14.9, 11.4, 11.1, 10.9, 17.9, NA, NA, 13.8, …
$ Viol_crime_count          <dbl> 17177, 16254, NA, NA, 318395, NA, NA, 2634, …
$ Population                <dbl> 3454365, NA, NA, NA, 31317179, NA, NA, 94010…
$ police_per_100k_lag       <dbl> 303.9922, NA, NA, NA, 283.5728, NA, NA, 328.…
$ RTC_LAW_YEAR              <dbl> 1996, 2012, Inf, 1989, Inf, 2014, 1990, 1992…
$ RTC_LAW                   <lgl> TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, …

Since we have differing numbers of years for each data set, we can use the drop_na() function of the tidyr package. to remove years that have incomplete data. Thus any row with NA values will be removed.

For example, we can see that for 1977, although we have most of the data, we do not have the poverty rate.

DONOHUE_DF %>%
  filter(YEAR == 1977) %>%
  head() %>%
  glimpse()
Rows: 6
Columns: 15
$ YEAR                      <dbl> 1977, 1977, 1977, 1977, 1977, 1977
$ STATE                     <chr> "Alabama", "Alaska", "Arizona", "Arkansas", …
$ Black_Male_15_to_19_years <dbl> 1.5457212, 0.1631338, 0.1804065, 1.0106946, …
$ Black_Male_20_to_39_years <dbl> 3.0379602, 0.9684809, 0.4796284, 1.8185525, …
$ Other_Male_15_to_19_years <dbl> 0.01781857, 1.11902724, 0.40213472, 0.030581…
$ Other_Male_20_to_39_years <dbl> 0.06421558, 2.72594532, 0.89144464, 0.092606…
$ White_Male_15_to_19_years <dbl> 3.578069, 3.828357, 4.391965, 3.879766, 4.14…
$ White_Male_20_to_39_years <dbl> 11.08537, 17.91501, 14.07430, 11.70744, 14.3…
$ Unemployment_rate         <dbl> 7.3, 9.9, 8.2, 6.5, 8.3, 6.4
$ Poverty_rate              <dbl> NA, NA, NA, NA, NA, NA
$ Viol_crime_count          <dbl> 15293, 1804, 11347, 6924, 154582, 13407
$ Population                <dbl> 3782571, 397220, 2427296, 2207195, 22350332,…
$ police_per_100k_lag       <dbl> 195.1054, 136.9518, 264.2447, 151.5045, 293.…
$ RTC_LAW_YEAR              <dbl> 1975, 1995, 1995, 1996, Inf, 2003
$ RTC_LAW                   <lgl> TRUE, FALSE, FALSE, FALSE, FALSE, FALSE

Another example, in 2018 we only have information about unemployment rates, poverty rates, and RTC laws.

DONOHUE_DF %>%
  filter(YEAR == 2018) %>%
  head() %>%
  glimpse()
Rows: 6
Columns: 15
$ YEAR                      <dbl> 2018, 2018, 2018, 2018, 2018, 2018
$ STATE                     <chr> "Alabama", "Alaska", "Arizona", "Arkansas", …
$ Black_Male_15_to_19_years <dbl> NA, NA, NA, NA, NA, NA
$ Black_Male_20_to_39_years <dbl> NA, NA, NA, NA, NA, NA
$ Other_Male_15_to_19_years <dbl> NA, NA, NA, NA, NA, NA
$ Other_Male_20_to_39_years <dbl> NA, NA, NA, NA, NA, NA
$ White_Male_15_to_19_years <dbl> NA, NA, NA, NA, NA, NA
$ White_Male_20_to_39_years <dbl> NA, NA, NA, NA, NA, NA
$ Unemployment_rate         <dbl> 3.9, 6.5, 4.7, 3.6, 4.3, 3.2
$ Poverty_rate              <dbl> 16.0, 13.1, 12.8, 15.9, 11.9, 9.1
$ Viol_crime_count          <dbl> NA, NA, NA, NA, NA, NA
$ Population                <dbl> NA, NA, NA, NA, NA, NA
$ police_per_100k_lag       <dbl> NA, NA, NA, NA, NA, NA
$ RTC_LAW_YEAR              <dbl> 1975, 1995, 1995, 1996, Inf, 2003
$ RTC_LAW                   <lgl> TRUE, TRUE, TRUE, TRUE, FALSE, TRUE
DONOHUE_DF %<>%
 drop_na()

head(DONOHUE_DF) %>% 
  glimpse()
Rows: 6
Columns: 15
$ YEAR                      <dbl> 1980, 1980, 1980, 1980, 1980, 1980
$ STATE                     <chr> "Alabama", "Alaska", "Arizona", "Arkansas", …
$ Black_Male_15_to_19_years <dbl> 1.4567383, 0.1670456, 0.1747544, 0.9545139, …
$ Black_Male_20_to_39_years <dbl> 3.3613348, 0.9933775, 0.5267121, 1.9738213, …
$ Other_Male_15_to_19_years <dbl> 0.02128385, 1.12978156, 0.41504620, 0.038491…
$ Other_Male_20_to_39_years <dbl> 0.08608419, 2.96332905, 0.98492602, 0.124256…
$ White_Male_15_to_19_years <dbl> 3.398210, 3.627805, 4.091577, 3.740199, 3.83…
$ White_Male_20_to_39_years <dbl> 11.57164, 18.28852, 14.69238, 12.12513, 14.9…
$ Unemployment_rate         <dbl> 8.9, 9.6, 6.6, 7.6, 6.8, 5.8
$ Poverty_rate              <dbl> 21.2, 9.6, 12.8, 21.5, 11.0, 8.6
$ Viol_crime_count          <dbl> 17320, 1919, 17673, 7656, 210290, 15215
$ Population                <dbl> 3899671, 404680, 2735840, 2288809, 23792840,…
$ police_per_100k_lag       <dbl> 201.3247, 194.7218, 262.6616, 152.0005, 243.…
$ RTC_LAW_YEAR              <dbl> 1975, 1995, 1995, 1996, Inf, 2003
$ RTC_LAW                   <lgl> TRUE, FALSE, FALSE, FALSE, FALSE, FALSE
tail(DONOHUE_DF) %>% 
  glimpse()
Rows: 6
Columns: 15
$ YEAR                      <dbl> 2010, 2010, 2010, 2010, 2010, 2010
$ STATE                     <chr> "Utah", "Vermont", "Virginia", "Washington",…
$ Black_Male_15_to_19_years <dbl> 0.06630724, 0.06725669, 0.83162848, 0.159641…
$ Black_Male_20_to_39_years <dbl> 0.2460319, 0.2056042, 2.7300368, 0.6653574, …
$ Other_Male_15_to_19_years <dbl> 0.3311760, 0.1702984, 0.3274050, 0.5979246, …
$ Other_Male_20_to_39_years <dbl> 1.0701722, 0.4754297, 1.3483385, 2.1186016, …
$ White_Male_15_to_19_years <dbl> 3.622191, 3.531216, 2.338080, 2.755299, 3.05…
$ White_Male_20_to_39_years <dbl> 14.382260, 11.363026, 9.776093, 11.195603, 1…
$ Unemployment_rate         <dbl> 7.8, 6.1, 7.1, 10.0, 8.7, 8.7
$ Poverty_rate              <dbl> 10.0, 10.8, 10.7, 11.6, 16.8, 10.1
$ Viol_crime_count          <dbl> 5925, 820, 17184, 21138, 5586, 14167
$ Population                <dbl> 2776469, 625960, 8024617, 6744496, 1853973, …
$ police_per_100k_lag       <dbl> 263.9324, 264.2341, 302.9677, 265.1495, 272.…
$ RTC_LAW_YEAR              <dbl> 1995, 1970, 1995, 1961, 1990, 2012
$ RTC_LAW                   <lgl> TRUE, TRUE, TRUE, TRUE, TRUE, FALSE

Now we have complete data and the data spans from 1980 to 2010.

DONOHUE_DF %>% distinct(YEAR) %>% pull(YEAR)
 [1] 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994
[16] 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009
[31] 2010

If we include states that had a RTC law adopted before our time span of data, say 1975, then we only have information about crime rates and the other variables of interest after the law was adopted but not before, therefore including these states doesn’t really makes sense. Thus, we will drop the data for these states. We can use the set_diff() function of the dplyr package to see what states are in the population_data that contains all the original 51 states (recall this includes the District of Columbia) but are not in the DONOHUE_DF. The order matters here. If we did it the other way around with population_data listed second, then set_diff would test if there are any states in Donohue_DF that are not in population_data. As there are none this would result in nothing.

baseline_year <- min(DONOHUE_DF$YEAR)
censoring_year <- max(DONOHUE_DF$YEAR)

DONOHUE_DF %<>%
  mutate(TIME_0 = baseline_year,
         TIME_INF = censoring_year) %>%
  filter(RTC_LAW_YEAR > TIME_0)

# DONOHUE_DF %<>% 
#   mutate(STATE = as.factor(STATE))
# 
# DONOHUE_DF %>% 
#   pull(STATE) %>% 
#   levels()

setdiff(distinct(population_data, STATE), 
        distinct(DONOHUE_DF, STATE))
# A tibble: 7 × 1
  STATE        
  <chr>        
1 Alabama      
2 Connecticut  
3 Indiana      
4 New Hampshire
5 Vermont      
6 Washington   
7 Wyoming      

We will also calculate a violent crime rate relative to the population in that state at that time, now that we have data for both crime count and population. Will will also calculate the log value of this rate and the population.

DONOHUE_DF %<>%
  mutate(Viol_crime_rate_1k = (Viol_crime_count*1000)/Population,
         Viol_crime_rate_1k_log = log(Viol_crime_rate_1k),
         Population_log = log(Population))

Mustard and Lott


We will now bind the demographic data that we made for the Mustard and Lott analysis called dem_Lott, as well as all the other datasets that we have wrangled just as we did for the Donohue-like analysis. Again, this is possible because we have the same column names for each dataset.

LOTT_DF <- bind_rows(dem_LOTT,
                     ue_rate_data,
                     poverty_rate_data,
                     crime_data,
                     population_data,
                     ps_data) %>%
  pivot_wider(names_from = "VARIABLE",
              values_from = "VALUE") %>%
  left_join(RTC , by = c("STATE")) %>%
  mutate(RTC_LAW = case_when(YEAR >= RTC_LAW_YEAR ~ TRUE,
                              TRUE ~ FALSE)) %>%
   drop_na()


baseline_year <- min(LOTT_DF$YEAR)
censoring_year <- max(LOTT_DF$YEAR)

LOTT_DF %<>%
  mutate(TIME_0 = baseline_year,
         TIME_INF = censoring_year) %>%
  filter(RTC_LAW_YEAR > TIME_0)

setdiff(distinct(population_data, STATE), 
        distinct(LOTT_DF, STATE))
# A tibble: 7 × 1
  STATE        
  <chr>        
1 Alabama      
2 Connecticut  
3 Indiana      
4 New Hampshire
5 Vermont      
6 Washington   
7 Wyoming      
LOTT_DF %<>%
  mutate(Viol_crime_rate_1k = (Viol_crime_count*1000)/Population,
         Viol_crime_rate_1k_log = log(Viol_crime_rate_1k),
         Population_log = log(Population))

Let’s see how the data compares:

We will check the dimensions of each using the base dim() function

dim(LOTT_DF)
[1] 1364   50
dim(DONOHUE_DF)
[1] 1364   20

As expected the Lott_DF is 30 columns larger, due to the 30 additional demographic variables. We can check those now as well.

LOTT_DF %>%
   colnames()
 [1] "YEAR"                           "STATE"                         
 [3] "Black_Female_10_to_19_years"    "Black_Female_20_to_29_years"   
 [5] "Black_Female_30_to_39_years"    "Black_Female_40_to_49_years"   
 [7] "Black_Female_50_to_64_years"    "Black_Female_65_years_and_over"
 [9] "Black_Male_10_to_19_years"      "Black_Male_20_to_29_years"     
[11] "Black_Male_30_to_39_years"      "Black_Male_40_to_49_years"     
[13] "Black_Male_50_to_64_years"      "Black_Male_65_years_and_over"  
[15] "Other_Female_10_to_19_years"    "Other_Female_20_to_29_years"   
[17] "Other_Female_30_to_39_years"    "Other_Female_40_to_49_years"   
[19] "Other_Female_50_to_64_years"    "Other_Female_65_years_and_over"
[21] "Other_Male_10_to_19_years"      "Other_Male_20_to_29_years"     
[23] "Other_Male_30_to_39_years"      "Other_Male_40_to_49_years"     
[25] "Other_Male_50_to_64_years"      "Other_Male_65_years_and_over"  
[27] "White_Female_10_to_19_years"    "White_Female_20_to_29_years"   
[29] "White_Female_30_to_39_years"    "White_Female_40_to_49_years"   
[31] "White_Female_50_to_64_years"    "White_Female_65_years_and_over"
[33] "White_Male_10_to_19_years"      "White_Male_20_to_29_years"     
[35] "White_Male_30_to_39_years"      "White_Male_40_to_49_years"     
[37] "White_Male_50_to_64_years"      "White_Male_65_years_and_over"  
[39] "Unemployment_rate"              "Poverty_rate"                  
[41] "Viol_crime_count"               "Population"                    
[43] "police_per_100k_lag"            "RTC_LAW_YEAR"                  
[45] "RTC_LAW"                        "TIME_0"                        
[47] "TIME_INF"                       "Viol_crime_rate_1k"            
[49] "Viol_crime_rate_1k_log"         "Population_log"                
DONOHUE_DF %>%
   colnames()
 [1] "YEAR"                      "STATE"                    
 [3] "Black_Male_15_to_19_years" "Black_Male_20_to_39_years"
 [5] "Other_Male_15_to_19_years" "Other_Male_20_to_39_years"
 [7] "White_Male_15_to_19_years" "White_Male_20_to_39_years"
 [9] "Unemployment_rate"         "Poverty_rate"             
[11] "Viol_crime_count"          "Population"               
[13] "police_per_100k_lag"       "RTC_LAW_YEAR"             
[15] "RTC_LAW"                   "TIME_0"                   
[17] "TIME_INF"                  "Viol_crime_rate_1k"       
[19] "Viol_crime_rate_1k_log"    "Population_log"           

Lastly, we will check that the YEAR values are the same. We can use the setequal() function of the dplyr package to see if the values are the same.

setequal(DONOHUE_DF %>% distinct(YEAR),
          LOTT_DF %>% distinct(YEAR))
[1] TRUE

Looks as expected!

Now we will save our wrangled data for the part 2 case study:

We can use the here() function of the here package to easily save this in a directory called wrangled within the data directory within the directory where are .Rproj file is located.

save(LOTT_DF, DONOHUE_DF, file = here::here("data", "wrangled", "wrangled_data.rda"))

Summary


This case study has introduced many concepts for data importation and data wrangling. To continue with this data to see more about data analysis and visualization see this next case study.

Suggested Homework


Ask students to import and wrangle similar datasets to those used here.

Additional Information


Session Info


devtools::session_info()
─ Session info ───────────────────────────────────────────────────────────────
 setting  value                       
 version  R version 4.0.3 (2020-10-10)
 os       macOS Mojave 10.14.6        
 system   x86_64, darwin17.0          
 ui       X11                         
 language (EN)                        
 collate  en_US.UTF-8                 
 ctype    en_US.UTF-8                 
 tz       America/New_York            
 date     2021-11-09                  

─ Packages ───────────────────────────────────────────────────────────────────
 package     * version date       lib source                            
 askpass       1.1     2019-01-13 [1] CRAN (R 4.0.0)                    
 assertthat    0.2.1   2019-03-21 [1] CRAN (R 4.0.0)                    
 bslib         0.2.5.1 2021-05-18 [1] CRAN (R 4.0.2)                    
 cachem        1.0.5   2021-05-15 [1] CRAN (R 4.0.2)                    
 callr         3.7.0   2021-04-20 [1] CRAN (R 4.0.2)                    
 cellranger    1.1.0   2016-07-27 [1] CRAN (R 4.0.0)                    
 cli           3.0.1   2021-07-17 [1] CRAN (R 4.0.2)                    
 crayon        1.4.1   2021-02-08 [1] CRAN (R 4.0.3)                    
 DBI           1.1.1   2021-01-15 [1] CRAN (R 4.0.2)                    
 desc          1.3.0   2021-03-05 [1] CRAN (R 4.0.2)                    
 devtools      2.4.2   2021-06-07 [1] CRAN (R 4.0.2)                    
 digest        0.6.27  2020-10-24 [1] CRAN (R 4.0.2)                    
 dplyr       * 1.0.7   2021-06-18 [1] CRAN (R 4.0.2)                    
 ellipsis      0.3.2   2021-04-29 [1] CRAN (R 4.0.2)                    
 evaluate      0.14    2019-05-28 [1] CRAN (R 4.0.0)                    
 fansi         0.5.0   2021-05-25 [1] CRAN (R 4.0.2)                    
 fastmap       1.1.0   2021-01-25 [1] CRAN (R 4.0.2)                    
 forcats     * 0.5.1   2021-01-27 [1] CRAN (R 4.0.2)                    
 fs            1.5.0   2020-07-31 [1] CRAN (R 4.0.2)                    
 generics      0.1.0   2020-10-31 [1] CRAN (R 4.0.2)                    
 glue          1.4.2   2020-08-27 [1] CRAN (R 4.0.2)                    
 here        * 1.0.1   2020-12-13 [1] CRAN (R 4.0.2)                    
 highr         0.9     2021-04-16 [1] CRAN (R 4.0.2)                    
 hms           1.1.0   2021-05-17 [1] CRAN (R 4.0.2)                    
 htmltools     0.5.2   2021-08-25 [1] CRAN (R 4.0.2)                    
 janitor     * 2.1.0   2021-01-05 [1] CRAN (R 4.0.2)                    
 jquerylib     0.1.4   2021-04-26 [1] CRAN (R 4.0.2)                    
 jsonlite      1.7.2   2020-12-09 [1] CRAN (R 4.0.2)                    
 knitr       * 1.34.1  2021-09-10 [1] Github (yihui/knitr@0c90228)      
 lifecycle     1.0.0   2021-02-15 [1] CRAN (R 4.0.2)                    
 lubridate     1.7.10  2021-02-26 [1] CRAN (R 4.0.2)                    
 magrittr    * 2.0.1   2020-11-17 [1] CRAN (R 4.0.2)                    
 memoise       2.0.0   2021-01-26 [1] CRAN (R 4.0.2)                    
 pdftools    * 3.0.1   2021-05-06 [1] CRAN (R 4.0.2)                    
 pillar        1.6.2   2021-07-29 [1] CRAN (R 4.0.2)                    
 pkgbuild      1.2.0   2020-12-15 [1] CRAN (R 4.0.2)                    
 pkgconfig     2.0.3   2019-09-22 [1] CRAN (R 4.0.0)                    
 pkgload       1.2.1   2021-04-06 [1] CRAN (R 4.0.2)                    
 prettyunits   1.1.1   2020-01-24 [1] CRAN (R 4.0.0)                    
 processx      3.5.2   2021-04-30 [1] CRAN (R 4.0.2)                    
 ps            1.6.0   2021-02-28 [1] CRAN (R 4.0.2)                    
 purrr       * 0.3.4   2020-04-17 [1] CRAN (R 4.0.0)                    
 qpdf          1.1     2019-03-07 [1] CRAN (R 4.0.0)                    
 R6            2.5.1   2021-08-19 [1] CRAN (R 4.0.2)                    
 Rcpp          1.0.7   2021-07-07 [1] CRAN (R 4.0.2)                    
 readr       * 1.4.0   2020-10-05 [1] CRAN (R 4.0.2)                    
 readxl      * 1.3.1   2019-03-13 [1] CRAN (R 4.0.0)                    
 rematch       1.0.1   2016-04-21 [1] CRAN (R 4.0.0)                    
 remotes       2.4.0   2021-06-02 [1] CRAN (R 4.0.2)                    
 rlang         0.4.11  2021-04-30 [1] CRAN (R 4.0.2)                    
 rmarkdown     2.10.6  2021-09-10 [1] Github (rstudio/rmarkdown@eaf6efc)
 rprojroot     2.0.2   2020-11-15 [1] CRAN (R 4.0.2)                    
 rstudioapi    0.13    2020-11-12 [1] CRAN (R 4.0.2)                    
 sass          0.4.0   2021-05-12 [1] CRAN (R 4.0.2)                    
 sessioninfo   1.1.1   2018-11-05 [1] CRAN (R 4.0.2)                    
 snakecase     0.11.0  2019-05-25 [1] CRAN (R 4.0.0)                    
 stringi       1.7.4   2021-08-25 [1] CRAN (R 4.0.2)                    
 stringr     * 1.4.0   2019-02-10 [1] CRAN (R 4.0.0)                    
 testthat      3.0.4   2021-07-01 [1] CRAN (R 4.0.2)                    
 tibble      * 3.1.4   2021-08-25 [1] CRAN (R 4.0.2)                    
 tidyr       * 1.1.3   2021-03-03 [1] CRAN (R 4.0.2)                    
 tidyselect    1.1.1   2021-04-30 [1] CRAN (R 4.0.2)                    
 usethis       2.0.1   2021-02-10 [1] CRAN (R 4.0.2)                    
 utf8          1.2.2   2021-07-24 [1] CRAN (R 4.0.2)                    
 vctrs         0.3.8   2021-04-29 [1] CRAN (R 4.0.2)                    
 withr         2.4.2   2021-04-18 [1] CRAN (R 4.0.2)                    
 xfun          0.25    2021-08-06 [1] CRAN (R 4.0.2)                    
 yaml          2.2.1   2020-02-01 [1] CRAN (R 4.0.0)                    

[1] /Library/Frameworks/R.framework/Versions/4.0/Resources/library

Acknowledgments


We would like to acknowledge Daniel Webster for assisting in framing the major direction of the case study.

We would also like to acknowledge the Bloomberg American Health Initiative for funding this work.

LS0tCnRpdGxlOiAiT3BlbiBDYXNlIFN0dWRpZXM6IEluZmx1ZW5jZSBvZiBNdWx0aWNvbGxpbmVhcml0eSBvbiBNZWFzdXJlZCBJbXBhY3Qgb2YgUmlnaHQtdG8tQ2FycnkgR3VuIExhd3MgUGFydCAxIgpjc3M6IHN0eWxlLmNzcwpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIGluY2x1ZGVzOgogICAgICBpbl9oZWFkZXI6IEdBX1NjcmlwdC5SaHRtbAogICAgc2VsZl9jb250YWluZWQ6IHllcwogICAgY29kZV9kb3dubG9hZDogeWVzCiAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICBudW1iZXJfc2VjdGlvbnM6IG5vCiAgICB0aGVtZTogY29zbW8KICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwogIHBkZl9kb2N1bWVudDoKICAgIHRvYzogeWVzCiAgd29yZF9kb2N1bWVudDoKICAgIHRvYzogeWVzCi0tLQoKPHN0eWxlPgojVE9DIHsKICBiYWNrZ3JvdW5kOiB1cmwoImh0dHBzOi8vb3BlbmNhc2VzdHVkaWVzLmdpdGh1Yi5pby9pbWcvaWNvbi1iYWhpLnBuZyIpOwogIGJhY2tncm91bmQtc2l6ZTogY29udGFpbjsKICBwYWRkaW5nLXRvcDogMjQwcHggIWltcG9ydGFudDsKICBiYWNrZ3JvdW5kLXJlcGVhdDogbm8tcmVwZWF0Owp9Cjwvc3R5bGU+CgoKLS0tCgoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChpbmNsdWRlID0gVFJVRSwgY29tbWVudCA9IE5BLCBlY2hvID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFLCBjYWNoZSA9IEZBTFNFLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9NywKICAgICAgICAgICAgICAgICAgICAgIGZpZy5hbGlnbiA9ICJjZW50ZXIiLCBvdXQud2lkdGggPSAnOTAlJykKbGlicmFyeShoZXJlKQpsaWJyYXJ5KGtuaXRyKQoKYGBgCgo8IS0tIE9wZW4gYWxsIGxpbmtzIGluIG5ldyB0YWItLT4gIAo8YmFzZSB0YXJnZXQ9Il9ibGFuayIvPiAKCgo8ZGl2IGlkPSJnb29nbGVfdHJhbnNsYXRlX2VsZW1lbnQiPjwvZGl2PgoKPHNjcmlwdCB0eXBlPSJ0ZXh0L2phdmFzY3JpcHQiIHNyYz0nLy90cmFuc2xhdGUuZ29vZ2xlLmNvbS90cmFuc2xhdGVfYS9lbGVtZW50LmpzP2NiPWdvb2dsZVRyYW5zbGF0ZUVsZW1lbnRJbml0Jz48L3NjcmlwdD4KCjxzY3JpcHQgdHlwZT0idGV4dC9qYXZhc2NyaXB0Ij4KZnVuY3Rpb24gZ29vZ2xlVHJhbnNsYXRlRWxlbWVudEluaXQoKSB7CiAgbmV3IGdvb2dsZS50cmFuc2xhdGUuVHJhbnNsYXRlRWxlbWVudCh7cGFnZUxhbmd1YWdlOiAnZW4nfSwgJ2dvb2dsZV90cmFuc2xhdGVfZWxlbWVudCcpOwp9Cjwvc2NyaXB0PgoKCgojIyMjIHsub3V0bGluZSB9CmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aCA9ICI4MDAgcHgifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWciLCAibWFpbnBsb3QucG5nIikpCmBgYAoKIyMjIwoKIyMjIyB7LmRpc2NsYWltZXJfYmxvY2t9CgoqKkRpc2NsYWltZXIqKjogVGhlIHB1cnBvc2Ugb2YgdGhlIFtPcGVuIENhc2UgU3R1ZGllc10oaHR0cHM6Ly9vcGVuY2FzZXN0dWRpZXMuZ2l0aHViLmlvKXt0YXJnZXQ9Il9ibGFuayJ9IHByb2plY3QgaXMgKip0byBkZW1vbnN0cmF0ZSB0aGUgdXNlIG9mIHZhcmlvdXMgZGF0YSBzY2llbmNlIG1ldGhvZHMsIHRvb2xzLCBhbmQgc29mdHdhcmUgaW4gdGhlIGNvbnRleHQgb2YgbWVzc3ksIHJlYWwtd29ybGQgZGF0YSoqLiBBIGdpdmVuIGNhc2Ugc3R1ZHkgZG9lcyBub3QgY292ZXIgYWxsIGFzcGVjdHMgb2YgdGhlIHJlc2VhcmNoIHByb2Nlc3MsIGlzIG5vdCBjbGFpbWluZyB0byBiZSB0aGUgbW9zdCBhcHByb3ByaWF0ZSB3YXkgdG8gYW5hbHl6ZSBhIGdpdmVuIGRhdGEgc2V0LCBhbmQgc2hvdWxkIG5vdCBiZSB1c2VkIGluIHRoZSBjb250ZXh0IG9mIG1ha2luZyBwb2xpY3kgZGVjaXNpb25zIHdpdGhvdXQgZXh0ZXJuYWwgY29uc3VsdGF0aW9uIGZyb20gc2NpZW50aWZpYyBleHBlcnRzLiAKIyMjIwoKIyMjIyB7LmxpY2Vuc2VfYmxvY2t9CgpUaGlzIHdvcmsgaXMgbGljZW5zZWQgdW5kZXIgdGhlIENyZWF0aXZlIENvbW1vbnMgQXR0cmlidXRpb24tTm9uQ29tbWVyY2lhbCAzLjAgWyhDQyBCWS1OQyAzLjApXShodHRwczovL2NyZWF0aXZlY29tbW9ucy5vcmcvbGljZW5zZXMvYnktbmMvMy4wL3VzLyl7dGFyZ2V0PSJfYmxhbmsifSAgVW5pdGVkIFN0YXRlcyBMaWNlbnNlLgoKIyMjIwoKIyMjIyB7LnJlZmVyZW5jZV9ibG9ja30KClRvIGNpdGUgdGhpcyBjYXNlIHN0dWR5IHBsZWFzZSB1c2U6CgpXcmlnaHQsIENhcnJpZSBhbmQgT250aXZlcm9zLCBNaWNoYWVsIGFuZCBKYWdlciwgTGVhaCBhbmQgVGF1YiwgTWFyZ2FyZXQgYW5kIEhpY2tzLCBTdGVwaGFuaWUuICgyMDIwKS4gaHR0cHM6Ly9naXRodWIuY29tL29wZW5jYXNlc3R1ZGllcy9vY3MtYnAtUlRDLXdyYW5nbGluZy4gIEluZmx1ZW5jZSBvZiBNdWx0aWNvbGxpbmVhcml0eSBvbiBNZWFzdXJlZCBJbXBhY3Qgb2YgUmlnaHQtdG8tQ2FycnkgR3VuIExhd3MgUGFydCAxIChWZXJzaW9uIHYxLjAuMCkuCgojIyMjCgpUbyBhY2Nlc3MgdGhlIEdpdEh1YiByZXBvc2l0b3J5IGZvciB0aGlzIGNhc2Ugc3R1ZHkgc2VlIGhlcmU6IGh0dHBzOi8vZ2l0aHViLmNvbS9vcGVuY2FzZXN0dWRpZXMvb2NzLWJwLVJUQy13cmFuZ2xpbmcuICAgClRoaXMgY2FzZSBzdHVkeSBpcyBwYXJ0IG9mIGEgc2VyaWVzIG9mIHB1YmxpYyBoZWFsdGggY2FzZSBzdHVkaWVzIGZvciB0aGUgW0Jsb29tYmVyZyBBbWVyaWNhbiBIZWFsdGggSW5pdGlhdGl2ZV0oaHR0cHM6Ly9hbWVyaWNhbmhlYWx0aC5qaHUuZWR1L29wZW4tY2FzZS1zdHVkaWVzKS4gICAKU2VlIFt0aGlzIGNhc2Ugc3R1ZHldKGh0dHBzOi8vZ2l0aHViLmNvbS9vcGVuY2FzZXN0dWRpZXMvb2NzLWJwLVJUQy1hbmFseXNpcykgZm9yIHBhcnQgMiB3aGljaCBpbmNsdWRlcyBhIGRhdGEgYW5hbHlzaXMgYW5kIGluZm9ybWF0aW9uIGFib3V0IGRhdGEgdmlzdWFsaXphdGlvbi4gIAoKUGxlYXNlIGhlbHAgdXMgYnkgZmlsbGluZyBvdXQgb3VyIHN1cnZleS4KCgo8ZGl2IHN0eWxlPSJkaXNwbGF5OiBmbGV4OyBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjsiPjxpZnJhbWUgc3JjPSJodHRwczovL2RvY3MuZ29vZ2xlLmNvbS9mb3Jtcy9kL2UvMUZBSXBRTFNmcE40Rk4zS0VMcUJORWdmMkF0cGk3V3k3TnF5MmJlU2tGUUlOTDdZNXNBTVY1X3cvdmlld2Zvcm0/ZW1iZWRkZWQ9dHJ1ZSIgd2lkdGg9IjEyMDAiIGhlaWdodD0iNzAwIiBmcmFtZWJvcmRlcj0iMCIgbWFyZ2luaGVpZ2h0PSIwIiBtYXJnaW53aWR0aD0iMCI+TG9hZGluZ+KApjwvaWZyYW1lPjwvZGl2PgoKCiMgKipNb3RpdmF0aW9uKioKKioqIAoKVGhpcyBjYXNlIHN0dWR5IHNob3dzIHRoZSB3cmFuZ2xpbmcgcGVyZm9ybWVkIGZvciBhbm90aGVyIFtjYXNlIHN0dWR5XShodHRwczovL3d3dy5vcGVuY2FzZXN0dWRpZXMub3JnL29jcy1icC1SVEMtYW5hbHlzaXMvKS4KClRoaXMgb3RoZXIgY2FzZSBzdHVkeSBpbnRyb2R1Y2VzIHRoZSB0b3BpYyBvZiBbbXVsdGljb2xsaW5lYXJpdHldKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL011bHRpY29sbGluZWFyaXR5KXt0YXJnZXQ9Il9ibGFuayJ9LCB3aGljaCBvY2N1cnMgaW4gcmVncmVzc2lvbiB3aGVuIG9uZSBvciBtb3JlIGluZGVwZW5kZW50IHZhcmlhYmxlcyBjYW4gYmUgcHJlZGljdGVkIGJ5IG90aGVyIGluZGVwZW5kZW50IHZhcmlhYmxlcy4gCgpJdCBkb2VzIHNvIGJ5IHNob3djYXNpbmcgYSByZWFsIHdvcmxkIGV4YW1wbGUgd2hlcmUgbXVsdGljb2xsaW5lYXJpdHkgaW4gcGFydCByZXN1bHRlZCBpbiBoaXN0b3JpY2FsbHkgY29udHJvdmVyc2lhbCBhbmQgY29uZmxpY3RpbmcgZmluZGluZ3MgYWJvdXQgdGhlIGluZmx1ZW5jZSBvZiB0aGUgYWRvcHRpb24gb2YgcmlnaHQtdG8tY2FycnkgKFJUQykgY29uY2VhbGVkIGhhbmRndW4gbGF3cyBvbiB2aW9sZW50IGNyaW1lIHJhdGVzIGluIHRoZSBVbml0ZWQgU3RhdGVzLiAgCgpXZSB3aWxsIGZvY3VzIG9uIHR3byBhcnRpY2xlczoKCjEuIFRoZSBmaXJzdCBhbmFseXNpcyBieSBbTXVzdGFyZCBhbmQgTG90dF0oaHR0cHM6Ly9jaGljYWdvdW5ib3VuZC51Y2hpY2Fnby5lZHUvY2dpL3ZpZXdjb250ZW50LmNnaT9hcnRpY2xlPTExNTAmY29udGV4dD1sYXdfYW5kX2Vjb25vbWljcyl7dGFyZ2V0PSJfYmxhbmsifSBwdWJsaXNoZWQgaW4gMTk5NiBzdWdnZXN0cyB0aGF0IFJUQyBsYXdzIHJlZHVjZSB2aW9sZW50IGNyaW1lLiBMb3R0IGF1dGhvcmVkIGEgYm9vayBleHRlbmRpbmcgdGhlc2UgZmluZGluZ3MgaW4gMTk5OCBjYWxsZWQgWyoqKk1vcmUgR3VucywgTGVzcyBDcmltZSoqKl0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvTW9yZV9HdW5zLF9MZXNzX0NyaW1lKXt0YXJnZXQ9Il9ibGFuayJ9LgoKYGBge3IsIGVjaG89RkFMU0UsIG91dC5oZWlnaHQgPSAnMTAwJScsIG91dC53aWR0aCA9ICcxMDAlJywgZmlnLmFsaWduPSdjZW50ZXInfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlKCJpbWciLCAiTG90dC5wbmciKSkKYGBgCgojIyMjIyBbW3NvdXJjZV1dKGh0dHBzOi8vY2hpY2Fnb3VuYm91bmQudWNoaWNhZ28uZWR1L2NnaS92aWV3Y29udGVudC5jZ2k/YXJ0aWNsZT0xMTUwJmNvbnRleHQ9bGF3X2FuZF9lY29ub21pY3Mpe3RhcmdldD0iX2JsYW5rIn0KCjIuIFRoZSBzZWNvbmQgYW5hbHlzaXMgaXMgYSByZWNlbnQgYXJ0aWNsZSBieSBbRG9ub2h1ZSwgZXQgYWwuXShodHRwczovL3d3dy5uYmVyLm9yZy9wYXBlcnMvdzIzNTEwLnBkZil7dGFyZ2V0PSJfYmxhbmsifSBwdWJsaXNoZWQgaW4gMjAxNyB0aGF0IHN1Z2dlc3RzIHRoYXQgUlRDIGxhd3MgaW5jcmVhc2UgdmlvbGVudCBjcmltZS4gRG9ub2h1ZSBoYXMgYWxzbyBwdWJsaXNoZWQgcHJldmlvdXMgYXJ0aWNsZXMgd2l0aCB0aXRsZXMgc3VjaCBhcyBbKioqU2hvb3RpbmcgZG93biB0aGUgIk1vcmUgR3VucywgTGVzcyBDcmltZSIgSHlwb3RoZXNpcyoqKl0oaHR0cHM6Ly93d3cuanN0b3Iub3JnL3N0YWJsZS8xMjI5NjAzP3NlcT0xKXt0YXJnZXQ9Il9ibGFuayJ9LiAKCmBgYHtyLCBlY2hvPUZBTFNFLCBvdXQuaGVpZ2h0ID0gJzEwMCUnLCBvdXQud2lkdGggPSAnMTAwJScsIGZpZy5hbGlnbj0nY2VudGVyJ30Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZSgiaW1nIiwgIkRvbm9odWUucG5nIikpCmBgYAoKIyMjIyMgW1tzb3VyY2VdXShodHRwczovL3d3dy5uYmVyLm9yZy9wYXBlcnMvdzIzNTEwLnBkZil7dGFyZ2V0PSJfYmxhbmsifQoKVGhpcyBoYXMgYmVlbiBhIGNvbnRyb3ZlcnNpYWwgdG9waWMgYXMgbWFueSBvdGhlciBhbmFseXNlcyBhbHNvIHByb2R1Y2VkIGNvbmZsaWN0aW5nIHJlc3VsdHMuIFNlZSBbaGVyZV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvTW9yZV9HdW5zLF9MZXNzX0NyaW1lKXt0YXJnZXQ9Il9ibGFuayJ9IGZvciBhIGxpc3Qgb2Ygc3R1ZGllcy4KClRoZSBbRG9ub2h1ZSwgZXQgYWwuXShodHRwczovL3d3dy5uYmVyLm9yZy9wYXBlcnMvdzIzNTEwLnBkZil7dGFyZ2V0PSJfYmxhbmsifSBhcnRpY2xlIGRpc2N1c3NlcyBob3cgdGhlcmUgYXJlIG1hbnkgb3RoZXIgaW1wb3J0YW50IG1ldGhvZG9sb2dpY2FsIGFzcGVjdHMgYmVzaWRlcyBbbXVsdGljb2xsaW5lYXJpdHldKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL011bHRpY29sbGluZWFyaXR5KXt0YXJnZXQ9Il9ibGFuayJ9ICh3aGljaCBvY2N1cnMgd2hlbiBwcmVkaWN0b3Igb3IgaW5wdXQgdmFyaWFibGVzIGFyZSBoaWdobHkgcmVsYXRlZCBpbiBhIHJlZ3Jlc3Npb24gYW5hbHlzaXMpIHRoYXQgY291bGQgYWNjb3VudCBmb3IgdGhlIGhpc3RvcmljYWxseSBjb25mbGljdGluZyByZXN1bHRzIGluIHRoZXNlIHByZXZpb3VzIG1hbnVzY3JpcHRzLgoKSW4gZmFjdCwgbmVhcmx5IGV2ZXJ5IGFzcGVjdCBvZiB0aGUgZGF0YSBhbmFseXNpcyBwcm9jZXNzIHdhcyBkaWZmZXJlbnQgYmV0d2VlbiB0aGUgW0Rvbm9odWUsIGV0IGFsLl0oaHR0cHM6Ly93d3cubmJlci5vcmcvcGFwZXJzL3cyMzUxMC5wZGYpe3RhcmdldD0iX2JsYW5rIn0gYW5kIFtNdXN0YXJkIGFuZCBMb3R0XShodHRwczovL2NoaWNhZ291bmJvdW5kLnVjaGljYWdvLmVkdS9jZ2kvdmlld2NvbnRlbnQuY2dpP2FydGljbGU9MTE1MCZjb250ZXh0PWxhd19hbmRfZWNvbm9taWNzKXt0YXJnZXQ9Il9ibGFuayJ9IGFuYWx5c2VzLgpgYGB7ciwgZWNobz1GQUxTRSwgb3V0LmhlaWdodCA9ICc3NSUnLCBvdXQud2lkdGggPSAnNzUlJywgZmlnLmFsaWduPSdjZW50ZXInfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlKCJpbWciLCAiRWR1Y2F0aW9uYWxfR3JhcGhpYzEuanBnIikpCmBgYAoKCkhvd2V2ZXIsIHdlIHdpbGwgZm9jdXMgcGFydGljdWxhcmx5IG9uIG11bHRpY29sbGluZWFyaXR5IGFuZCBob3cgaXQgY2FuIGluZmx1ZW5jZSB0aGUgcmVzdWx0cyB3ZSBnZXQgZnJvbSBsaW5lYXIgcmVncmVzc2lvbi4gClNwZWNpZmljYWxseSwgdGhpcyBhbmFseXNpcyB3aWxsIGRlbW9uc3RyYXRlIGhvdyBtZXRob2RvbG9naWNhbCBkZXRhaWxzIGNhbiBiZSBjcml0aWNhbGx5IGluZmx1ZW50aWFsIGZvciBvdXIgb3ZlcmFsbCBjb25jbHVzaW9ucyBhbmQgY2FuIHJlc3VsdCBpbiBpbXBvcnRhbnQgcG9saWN5IHJlbGF0ZWQgY29uc2VxdWVuY2VzLiBUaGUgW0Rvbm9odWUsIGV0IGFsLiBhcnRpY2xlXSgoaHR0cHM6Ly93d3cubmJlci5vcmcvcGFwZXJzL3cyMzUxMC5wZGYpe3RhcmdldD0iX2JsYW5rIn0pIHdpbGwgcHJvdmlkZSBhIGJhc2lzIGZvciB0aGUgbW90aXZhdGlvbi4gCgojIyMjIHsucmVmZXJlbmNlX2Jsb2NrfQoKSm9obiBKLiBEb25vaHVlIGV0IGFsLiwgUmlnaHTigJB0b+KAkENhcnJ5IExhd3MgYW5kIFZpb2xlbnQgQ3JpbWU6IEEgQ29tcHJlaGVuc2l2ZSBBc3Nlc3NtZW50IFVzaW5nIFBhbmVsIERhdGEgYW5kIGEgU3RhdGXigJBMZXZlbCBTeW50aGV0aWMgQ29udHJvbCBBbmFseXNpcy4gKkpvdXJuYWwgb2YgRW1waXJpY2FsIExlZ2FsIFN0dWRpZXMqLCAxNiwyICgyMDE5KS4KCkRhdmlkIEIuIE11c3RhcmQgJiBKb2huIExvdHQuIENyaW1lLCBEZXRlcnJlbmNlLCBhbmQgUmlnaHQtdG8tQ2FycnkgQ29uY2VhbGVkIEhhbmRndW5zLiAqQ29hc2UtU2FuZG9yIEluc3RpdHV0ZSBmb3IgTGF3ICYgRWNvbm9taWNzKiBXb3JraW5nIFBhcGVyIE5vLiA0MSwgKDE5OTYpLgoKIyMjIwoKCkJlZm9yZSB3ZSBsZWF2ZSB0aGlzIHNlY3Rpb24sIHdlIHByb3ZpZGUgYSBoaWdoLWxldmVsIG92ZXJ2aWV3IG9mIHdoYXQgdmFyaWFibGVzIHdlcmUgKG9yIHdlcmUgbm90KSBpbmNsdWRlZCBpbiB0aGUgW0Rvbm9odWUsIEFuZWphIGFuZCBXZWJlcl0oaHR0cHM6Ly93d3cubmJlci5vcmcvcGFwZXJzL3cyMzUxMC5wZGYpe3RhcmdldD0iX2JsYW5rIn0pIChEQVcpIHBhcGVyIGFuZCB0aGUgW011c3RhcmQgYW5kIExvdHRdKGh0dHBzOi8vY2hpY2Fnb3VuYm91bmQudWNoaWNhZ28uZWR1L2NnaS92aWV3Y29udGVudC5jZ2k/YXJ0aWNsZT0xMTUwJmNvbnRleHQ9bGF3X2FuZF9lY29ub21pY3Mpe3RhcmdldD0iX2JsYW5rIn0gKE1MKSBwYXBlcjoKCgpgYGB7ciwgZWNobz1GQUxTRSwgb3V0LmhlaWdodCA9ICcxMDAlJywgb3V0LndpZHRoID0gJzEwMCUnLCBmaWcuYWxpZ249J2NlbnRlcid9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmUoImltZyIsJ0Rvbm9odWVfVGFibGUyX2VkaXRlZC5wbmcnKSkKYGBgCgojIyMjIyBbW3NvdXJjZV1dKGh0dHBzOi8vd3d3Lm5iZXIub3JnL3BhcGVycy93MjM1MTAucGRmKXt0YXJnZXQ9Il9ibGFuayJ9CgoKIyMjIyMjICpNTCBpcyBhYmJyZXZpYXRlZCBhcyBMTSBpbiB0aGUgc291cmNlIGFydGljbGUKCioqTm90ZSoqOiBXZSBhcmUgbm90IGF0dGVtcHRpbmcgdG8gcmUtY3JlYXRlIHRoZSBhbmFseXNlcyBmcm9tIHRoZSBvcmlnaW5hbCBhdXRob3JzLiBJbnN0ZWFkLCB3ZSBhaW0gdG8gdXNlIGEgc3Vic2V0IG9mIHRoZSBsaXN0ZWQgZXhwbGFuYXRvcnkgdmFyaWFibGVzIGluIHRoaXMgY2FzZSBzdHVkeSB0byBkZW1vbnN0cmF0ZSBtdWx0aWNvbGxpbmVhcml0eS4gVGhlc2UgdmFyaWFibGVzIHdpbGwgYmUgY29uc2lzdGVudCBmb3IgYm90aCBhbmFseXNlcyB0aGF0IHdlIHdpbGwgcGVyZm9ybSwgd2l0aCB0aGUgZXhjZXB0aW9uIHRoYXQgb25lIGFuYWx5c2lzIHdpbGwgaGF2ZSA2IGRlbW9ncmFwaGljIHZhcmlhYmxlcyBhcyBpbiB0aGUgYW5hbHlzaXMgaW4gdGhlIFtEb25vaHVlLCBldCBhbC5dKGh0dHBzOi8vd3d3Lm5iZXIub3JnL3BhcGVycy93MjM1MTAucGRmKXt0YXJnZXQ9Il9ibGFuayJ9IGFydGljbGUgYW5kIHRoZSBvdGhlciB3aWxsIGhhdmUgMzYgZGVtb2dyYXBoaWMgdmFyaWFibGVzLCBncm91cGluZyBpbmRpdmlkdWFscyBpbnRvIG1vcmUgc3BlY2lmaWMgY2F0ZWdvcmllcywgYXMgaW4gdGhlIGFuYWx5c2lzIGluIHRoZSBbTXVzdGFyZCBhbmQgTG90dF0oaHR0cHM6Ly9jaGljYWdvdW5ib3VuZC51Y2hpY2Fnby5lZHUvY2dpL3ZpZXdjb250ZW50LmNnaT9hcnRpY2xlPTExNTAmY29udGV4dD1sYXdfYW5kX2Vjb25vbWljcyl7dGFyZ2V0PSJfYmxhbmsifSBhcnRpY2xlLgoKCgojICoqTWFpbiBRdWVzdGlvbioqCioqKiAKCiMjIyMgey5tYWluX3F1ZXN0aW9uX2Jsb2NrfQo8Yj48dT4gT3VyIG1haW4gcXVlc3Rpb246IDwvdT48L2I+CgpXaGF0IGlzIHRoZSBlZmZlY3Qgb2YgbXVsdGljb2xsaW5lYXJpdHkgb24gY29lZmZpY2llbnQgZXN0aW1hdGVzIGZyb20gbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWxzIHdoZW4gYW5hbHl6aW5nIHJpZ2h0IHRvIGNhcnJ5IGxhd3MgYW5kIHZpb2xlbmNlIHJhdGVzPwoKIyMjIwoKClNwZWNpZmljYWxseSwgd2Ugd2lsbCBjb25zaWRlciB0aGUgdHdvIHdheXMgdG8gZGVmaW5lIHRoZSBkZW1vZ3JhcGhpYyB2YXJpYWJsZXMgKGFzIGRlc2NyaWJlZCBhYm92ZSkgYW5kIGludmVzdGlnYXRlIGhvdyB0aGUgaW5jbHVzaW9uIG9mIGRpZmZlcmVudCBudW1iZXJzIG9mIGFnZSBncm91cHMgaW5mbHVlbmNlcyB0aGUgcmVzdWx0cyBvZiBhbiBhbmFseXNpcyBvZiByaWdodCB0byBjYXJyeSBsYXdzIGFuZCB2aW9sZW5jZSByYXRlcwoKSW4gdGhpcyBjYXNlIHN0dWR5IHdlIG9ubHkgZGVtb25zdHJhdGUgaG93IHRvIGltcG9ydCBhbmQgd3JhbmdsZSB0aGUgZGF0YS4KCiMgKipMZWFybmluZyBPYmplY3RpdmVzKiogCioqKiAKCjx1PioqRGF0YSBTY2llbmNlIExlYXJuaW5nIE9iamVjdGl2ZXM6Kio8L3U+CgoxLiBEYXRhIGltcG9ydCBvZiBtYW55IGRpZmZlcmVudCBmaWxlIHR5cGVzIHdpdGggc3BlY2lhbCBjYXNlcyAoYHJlYWRyYCwgYHJlYWR4bGAsIGBwZGZ0b29sc2ApICAKMi4gSm9pbmluZyBkYXRhIGZyb20gbXVsdGlwbGUgc291cmNlcyAoYGRwbHlyYCkgIAozLiBXb3JraW5nIHdpdGggY2hhcmFjdGVyIHN0cmluZ3MgKGBzdHJpbmdyYCkgIAo0LiBEYXRhIGNvbXBhcmlzb25zIChgZHBseXJgIGFuZCBgamFuaXRvcmApICAKNS4gUmVzaGFwaW5nIGRhdGEgaW50byBkaWZmZXJlbnQgZm9ybWF0cyAoYHRpZHlyYCkgIAoKCldlIHdpbGwgZXNwZWNpYWxseSBmb2N1cyBvbiB1c2luZyBwYWNrYWdlcyBhbmQgZnVuY3Rpb25zIGZyb20gdGhlIFtgdGlkeXZlcnNlYF0oaHR0cHM6Ly93d3cudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0sIHN1Y2ggYXMgYGRwbHlyYCBhbmQgYGdncGxvdDJgLiBUaGUgdGlkeXZlcnNlIGlzIGEgbGlicmFyeSBvZiBwYWNrYWdlcyBjcmVhdGVkIGJ5IFJTdHVkaW8uIFdoaWxlIHNvbWUgc3R1ZGVudHMgbWF5IGJlIGZhbWlsaWFyIHdpdGggcHJldmlvdXMgUiBwcm9ncmFtbWluZyBwYWNrYWdlcywgdGhlc2UgcGFja2FnZXMgbWFrZSBkYXRhIHNjaWVuY2UgaW4gUiBlc3BlY2lhbGx5IGxlZ2libGUuCgpgYGB7ciwgb3V0LndpZHRoID0gIjIwJSIsIGVjaG8gPSBGQUxTRSwgZmlnLmFsaWduID0iY2VudGVyIn0KaW5jbHVkZV9ncmFwaGljcygiaHR0cHM6Ly90aWR5dmVyc2UudGlkeXZlcnNlLm9yZy9sb2dvLnBuZyIpCmBgYAoKIyAqKkNvbnRleHQqKgoqKioKClNvIHdoYXQgZXhhY3RseSBpcyBhICoqcmlnaHQtdG8tY2FycnkgbGF3Kio/CgpJdCBpcyBhIGxhdyB0aGF0IHNwZWNpZmllcyBfaWZfIGFuZCBfaG93XyBjaXRpemVucyBhcmUgYWxsb3dlZCB0byBoYXZlIGEgZmlyZWFybSBvbiB0aGVpciBwZXJzb24gb3IgbmVhcmJ5IChmb3IgZXhhbXBsZSwgaW4gYSBjaXRpemVuJ3MgY2FyKSBpbiBwdWJsaWMuIAoKVGhlIFtTZWNvbmQgQW1lbmRtZW50XShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9TZWNvbmRfQW1lbmRtZW50X3RvX3RoZV9Vbml0ZWRfU3RhdGVzX0NvbnN0aXR1dGlvbil7dGFyZ2V0PSJfYmxhbmsifSB0byB0aGUgVW5pdGVkIFN0YXRlcyBDb25zdGl0dXRpb24gZ3VhcmFudGVlcyB0aGUgcmlnaHQgdG8gImtlZXAgYW5kIGJlYXIgYXJtcyIuIFRoZSBhbWVuZG1lbnQgd2FzIHJhdGlmaWVkIGluIDE3OTEgYXMgcGFydCBvZiB0aGUgW0JpbGwgb2YgUmlnaHRzXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Vbml0ZWRfU3RhdGVzX0JpbGxfb2ZfUmlnaHRzKXt0YXJnZXQ9Il9ibGFuayJ9LgoKYGBge3IsIGVjaG89RkFMU0UsIG91dC5oZWlnaHQgPSAnNTAlJywgb3V0LndpZHRoID0gJzUwJScsIGZpZy5hbGlnbj0nY2VudGVyJ30Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImh0dHBzOi8vdXBsb2FkLndpa2ltZWRpYS5vcmcvd2lraXBlZGlhL2NvbW1vbnMvNy83OS9CaWxsX29mX1JpZ2h0c19QZzFvZjFfQUMuanBnIikKYGBgCgojIyMjIyBbW3NvdXJjZV1dKGh0dHBzOi8vdXBsb2FkLndpa2ltZWRpYS5vcmcvd2lraXBlZGlhL2NvbW1vbnMvNy83OS9CaWxsX29mX1JpZ2h0c19QZzFvZjFfQUMuanBnKXt0YXJnZXQ9Il9ibGFuayJ9CgpIb3dldmVyLCB0aGVyZSBhcmUgbm8gZmVkZXJhbCBsYXdzIGFib3V0IGNhcnJ5aW5nIGZpcmVhcm1zIGluIHB1YmxpYy4gCgpUaGVzZSBsYXdzIGFyZSBjcmVhdGVkIGFuZCBlbmZvcmNlZCBhdCB0aGUgVVMgc3RhdGUgbGV2ZWwuIApTdGF0ZXMgdmFyeSBncmVhdGx5IGluIHRoZWlyIGxhd3MgYWJvdXQgdGhlIHJpZ2h0IHRvIGNhcnJ5IGZpcmVhcm1zLiAKU29tZSByZXF1aXJlIGV4dGVuc2l2ZSBlZmZvcnQgdG8gb2J0YWluIGEgcGVybWl0IHRvIGxlZ2FsbHkgY2FycnkgYSBmaXJlYXJtLCB3aGlsZSBvdGhlciBzdGF0ZXMgcmVxdWlyZSB2ZXJ5IG1pbmltYWwgZWZmb3J0IHRvIGRvIHNvLgoKPGRldGFpbHM+IDxzdW1tYXJ5PiBDbGljayBoZXJlIGZvciBtb3JlIGluZm9ybWF0aW9uIG9uIGhpc3Rvcnkgb2YgcmlnaHQtdG8tY2FycnkgcG9saWNpZXMgaW4gdGhlIFVTLiA8L3N1bW1hcnk+CgpBY2NvcmRpbmcgdG8gdGhlIFtXaWtpcGVkaWEgZW50cnldKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0hpc3Rvcnlfb2ZfY29uY2VhbGVkX2NhcnJ5X2luX3RoZV9VLlMuKXt0YXJnZXQ9Il9ibGFuayJ9IGFib3V0IHRoZSBoaXN0b3J5IG9mIHJpZ2h0LXRvLWNhcnJ5IHBvbGljaWVzIGluIHRoZSBVbml0ZWQgU3RhdGVzOgoKPiBQdWJsaWMgcGVyY2VwdGlvbiBvbiBjb25jZWFsZWQgY2FycnkgdnMgb3BlbiBjYXJyeSBoYXMgbGFyZ2VseSBmbGlwcGVkLiBJbiB0aGUgZWFybHkgZGF5cyBvZiB0aGUgVW5pdGVkIFN0YXRlcywgb3BlbiBjYXJyeWluZyBvZiBmaXJlYXJtcywgbG9uZyBndW5zIGFuZCByZXZvbHZlcnMgd2FzIGEgY29tbW9uIGFuZCB3ZWxsLWFjY2VwdGVkIHByYWN0aWNlLiBTZWVpbmcgZ3VucyBjYXJyaWVkIG9wZW5seSB3YXMgbm90IGNvbnNpZGVyZWQgdG8gYmUgYW55IGNhdXNlIGZvciBhbGFybS4gVGhlcmVmb3JlLCBhbnlvbmUgd2hvIHdvdWxkIGNhcnJ5IGEgZmlyZWFybSBidXQgYXR0ZW1wdCB0byBjb25jZWFsIGl0IHdhcyBjb25zaWRlcmVkIHRvIGhhdmUgc29tZXRoaW5nIHRvIGhpZGUsIGFuZCBwcmVzdW1lZCB0byBiZSBhIGNyaW1pbmFsLiBGb3IgdGhpcyByZWFzb24sIGNvbmNlYWxlZCBjYXJyeSB3YXMgZGVub3VuY2VkIGFzIGEgZGV0ZXN0YWJsZSBwcmFjdGljZSBpbiB0aGUgZWFybHkgZGF5cyBvZiB0aGUgVW5pdGVkIFN0YXRlcy4KCj4gQ29uY2VhbGVkIHdlYXBvbnMgYmFucyB3ZXJlIHBhc3NlZCBpbiBLZW50dWNreSBhbmQgTG91aXNpYW5hIGluIDE4MTMuIChJbiB0aG9zZSBkYXlzIG9wZW4gY2Fycnkgb2Ygd2VhcG9ucyBmb3Igc2VsZi1kZWZlbnNlIHdhcyBjb25zaWRlcmVkIGFjY2VwdGFibGU7IGNvbmNlYWxlZCBjYXJyeSB3YXMgZGVub3VuY2VkIGFzIHRoZSBwcmFjdGljZSBvZiBjcmltaW5hbHMuKSBCeSAxODU5LCBJbmRpYW5hLCBUZW5uZXNzZWUsIFZpcmdpbmlhLCBBbGFiYW1hLCBhbmQgT2hpbyBoYWQgZm9sbG93ZWQgc3VpdC4gQnkgdGhlIGVuZCBvZiB0aGUgbmluZXRlZW50aCBjZW50dXJ5LCBzaW1pbGFyIGxhd3Mgd2VyZSBwYXNzZWQgaW4gcGxhY2VzIHN1Y2ggYXMgVGV4YXMsIEZsb3JpZGEsIGFuZCBPa2xhaG9tYSwgd2hpY2ggcHJvdGVjdGVkIHNvbWUgZ3VuIHJpZ2h0cyBpbiB0aGVpciBzdGF0ZSBjb25zdGl0dXRpb25zLiBCZWZvcmUgdGhlIG1pZCAxOTAwcywgbW9zdCBVLlMuIHN0YXRlcyBoYWQgcGFzc2VkIGNvbmNlYWxlZCBjYXJyeSBsYXdzIHJhdGhlciB0aGFuIGJhbm5pbmcgd2VhcG9ucyBjb21wbGV0ZWx5LiBVbnRpbCB0aGUgbGF0ZSAxOTkwcywgbWFueSBTb3V0aGVybiBzdGF0ZXMgd2VyZSBlaXRoZXIgIk5vLUlzc3VlIiBvciAiUmVzdHJpY3RpdmUgTWF5LUlzc3VlIi4gU2luY2UgdGhlbiwgdGhlc2Ugc3RhdGVzIGhhdmUgbGFyZ2VseSBlbmFjdGVkICJTaGFsbC1Jc3N1ZSIgbGljZW5zaW5nIGxhd3MsIHdpdGggbnVtZXJvdXMgc3RhdGVzIGxlZ2FsaXppbmcgIlVucmVzdHJpY3RlZCBjb25jZWFsZWQgY2FycnkiLgoKPC9kZXRhaWxzPgoKVGhlcmUgYXJlIGZpdmUgYnJvYWQgY2F0ZWdvcmllcyBvZiByaWdodC10by1jYXJyeSBsYXdzOgoKYGBge3IsIGVjaG89RkFMU0UsIG91dC5oZWlnaHQgPSAnMTAwJScsIG91dC53aWR0aCA9ICcxMDAlJywgZmlnLmFsaWduPSdjZW50ZXInfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlKCJpbWciLCAiUlRDLnBuZyIpKQpgYGAKCiMjIyMjIFtbc291cmNlXV0oaHR0cHM6Ly93d3cubnJhaWxhLm9yZy9ndW4tbGF3cy8pe3RhcmdldD0iX2JsYW5rIn0KCmBgYHtyLCBlY2hvPUZBTFNFLCBvdXQuaGVpZ2h0ID0gJzEwMCUnLCBvdXQud2lkdGggPSAnMTAwJScsIGZpZy5hbGlnbj0nY2VudGVyJ30Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZSgiaW1nIiwgIlJUQ19tYXAucG5nIikpCmBgYAoKIyMjIyMgW1tzb3VyY2VdXShodHRwczovL3d3dy5ucmFpbGEub3JnL2d1bi1sYXdzLyl7dGFyZ2V0PSJfYmxhbmsifQoKWW91IGNhbiBzZWUgdGhhdCBubyBzdGF0ZSBpbiB0aGUgVVMgY3VycmVudGx5ICh0aGlzIG1hcCBpcyBmcm9tIDIwMjApIGhhcyBhICJSaWdodHMgSW5mcmluZ2VkL05vbi1Jc3N1ZSIgbGF3ICh0aGUgZ3JheSBjYXRlZ29yeSkgLS0gbWVhbmluZyB0aGF0IGFsbCA1MCBzdGF0ZXMgaW4gdGhlIFVTIGFsbG93IHRoZSByaWdodCB0byBjYXJyeSBmaXJlYXJtcyBhdCBsZWFzdCBpbiBzb21lIHdheS4gCkhvd2V2ZXIgdGhlIGxldmVsIG9mIHJlc3RyaWN0aW9ucyBpcyBkcmFtYXRpY2FsbHkgZGlmZmVyZW50IGZyb20gb25lIHN0YXRlIHRvIGFub3RoZXIuCgoKPGRldGFpbHM+IDxzdW1tYXJ5PiBDbGljayBoZXJlIGZvciBtb3JlIGluZm9ybWF0aW9uIGFib3V0IGhvdyByZXN0cmljdGlvbnMgdmFyeSBmcm9tIG9uZSBzdGF0ZSB0byBhbm90aGVyLiA8L3N1bW1hcnk+CgpUaGVyZSBpcyB2YXJpYXRpb24gZnJvbSBzdGF0ZSB0byBzdGF0ZSBldmVuIHdpdGhpbiB0aGUgc2FtZSBnZW5lcmFsIGNhdGVnb3J5OgoKRm9yIGV4YW1wbGUgaGVyZSBpcyBhbiBhYnJpZGdlZCB2ZXJzaW9uIG9mIHRoZSBbY3VycmVudCBjYXJyeSBsYXdzIGluIElkYWhvXShodHRwczovL3d3dy5ucmFpbGEub3JnL2d1bi1sYXdzL3N0YXRlLWd1bi1sYXdzL2lkYWhvLykgd2hpY2ggaXMgY29uc2lkZXJlZCBhbiAiVW5yZXN0cmljdGVkIC0gbm8gcGVybWl0IHJlcXVpcmVkIiBzdGF0ZToKCj4gU3RhdGUgbGF3IC4uLiBhbGxvd3MgYW55IHJlc2lkZW50IG9mIElkYWhvIG9yIGEgY3VycmVudCBtZW1iZXIgb2YgdGhlIGFybWVkIGZvcmNlcyBvZiB0aGUgVW5pdGVkIFN0YXRlcyB0byBjYXJyeSBhIGNvbmNlYWxlZCBoYW5kZ3VuIHdpdGhvdXQgYSBsaWNlbnNlIHRvIGNhcnJ5LCBwcm92aWRlZCB0aGUgcGVyc29uIGlzIG92ZXIgMTggeWVhcnMgb2xkIGFuZCBub3QgZGlzcXVhbGlmaWVkIGZyb20gYmVpbmcgaXNzdWVkIGEgbGljZW5zZSB0byBjYXJyeSBjb25jZWFsZWQgd2VhcG9ucyB1bmRlciBzdGF0ZSBsYXcuIEFuIGFtZW5kbWVudCB0byBzdGF0ZSBsYXcgdGhhdCB0YWtlcyBlZmZlY3Qgb24gSnVseSAxLCAyMDIwIGNoYW5nZXMgdGhlIHJlZmVyZW5jZSBpbiB0aGUgYWJvdmUgbGF3IGZyb20g4oCcYSByZXNpZGVudCBvZiBJZGFob+KAnSB0byDigJxhbnkgY2l0aXplbiBvZiB0aGUgVW5pdGVkIFN0YXRlcy7igJ0gIAoKCkFuZCBoZXJlIGFyZSBpcyBhbiBhYnJpZGdlZCB2ZXJzaW9uIG9mIHRoZSBbY3VycmVudCBjYXJyeSBsYXdzIGluIEFyaXpvbmFdKGh0dHBzOi8vd3d3Lm5yYWlsYS5vcmcvZ3VuLWxhd3Mvc3RhdGUtZ3VuLWxhd3MvYXJpem9uYS8pIHdoaWNoIGlzIGFsc28gY29uc2lkZXJlZCBhbiAiVW5yZXN0cmljdGVkIC0gbm8gcGVybWl0IHJlcXVpcmVkIiBzdGF0ZToKCj4gQW55IHBlcnNvbiAyMSB5ZWFycyBvZiBhZ2Ugb3Igb2xkZXIsIHdobyBpcyBub3QgcHJvaGliaXRlZCBwb3NzZXNzb3IsIG1heSBjYXJyeSBhIHdlYXBvbiBvcGVubHkgb3IgY29uY2VhbGVkIHdpdGhvdXQgdGhlIG5lZWQgZm9yIGEgbGljZW5zZS4uLgoKTm90aWNlIHRoYXQgY2l0aXplbnMgaW4gSWRhaG8gb25seSBuZWVkIHRvIGJlIDE4IHRvIGNhcnJ5IGEgZmlyZWFybSwgd2hlcmVhcyB0aGV5IG11c3QgYmUgMjEgaW4gQXJpem9uYS4gCgo8L2RldGFpbHM+CgoKIyAqKkxpbWl0YXRpb25zKioKKioqIAoKVGhlcmUgYXJlIHNvbWUgaW1wb3J0YW50IGNvbnNpZGVyYXRpb25zIHJlZ2FyZGluZyB0aGlzIGRhdGEgYW5hbHlzaXMgdG8ga2VlcCBpbiBtaW5kOiAKCjEuIFdlIGRvIG5vdCB1c2UgYWxsIG9mIHRoZSBkYXRhIHVzZWQgYnkgZWl0aGVyIHRoZSBbTXVzdGFyZCBhbmQgTG90dF0oaHR0cHM6Ly9jaGljYWdvdW5ib3VuZC51Y2hpY2Fnby5lZHUvY2dpL3ZpZXdjb250ZW50LmNnaT9hcnRpY2xlPTExNTAmY29udGV4dD1sYXdfYW5kX2Vjb25vbWljcyl7dGFyZ2V0PSJfYmxhbmsifSBvciBbRG9ub2h1ZSwgZXQgYWwuXShodHRwczovL3d3dy5uYmVyLm9yZy9wYXBlcnMvdzIzNTEwLnBkZil7dGFyZ2V0PSJfYmxhbmsifSBhbmFseXNlcywgbm9yIGRvIHdlIHBlcmZvcm0gdGhlIHNhbWUgYW5hbHlzaXMgYXMgaW4gZWFjaCBhcnRpY2xlLiBXZSBpbnN0ZWFkIHBlcmZvcm0gYSBtdWNoIHNpbXBsZXIgYW5hbHlzaXMgd2l0aCBmZXdlciB2YXJpYWJsZXMgZm9yIHRoZSBwdXJwb3NlcyBvZiBpbGx1c3RyYXRpb24gb2YgdGhlIGNvbmNlcHQgb2YgbXVsdGljb2xsaW5lYXJpdHkgYW5kIGl0cyBpbmZsdWVuY2Ugb24gcmVncmVzc2lvbiBjb2VmZmljaWVudHMsIG5vdCB0byByZXByb2R1Y2UgZWl0aGVyIGFuYWx5c2lzLgoKMi4gT3VyIGFuYWx5c2lzIGFjY291bnRzIGZvciBlaXRoZXIgdGhlIGFkb3B0aW9uIG9yIGxhY2sgb2YgYWRvcHRpb24gb2YgYSBwZXJtaXNzaXZlIHJpZ2h0LXRvLWNhcnJ5IGxhdyBpbiBlYWNoIHN0YXRlLCBidXQgZG9lcyBub3QgYWNjb3VudCBmb3IgZGlmZmVyZW5jZXMgaW4gdGhlIGxldmVsIG9mIHBlcm1pc3NpdmVuZXNzIG9mIHRoZSBsYXdzLgoKUmVjYWxsIHRoYXQgdGhlc2UgYXJlIHRoZSBjYXRlZ29yaWVzIG9mIHJpZ2h0IHRvIGNhcnJ5IGxhd3M6CmBgYHtyLCBlY2hvPUZBTFNFLCBvdXQuaGVpZ2h0ID0gJzEwMCUnLCBvdXQud2lkdGggPSAnMTAwJScsIGZpZy5hbGlnbj0nY2VudGVyJ30Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZSgiaW1nIiwgIlJUQy5wbmciKSkKYGBgCgpTdGF0ZXMgd2l0aCBsYXdzIG9mIHRoZSBjYXRlZ29yeSByaWdodHMgcmVzdHJpY3RlZCAtIHZlcnkgbGltaXRlZCBpc3N1ZSAocmVkKSBhcmUgY29uc2lkZXJlZCBhcyBub3QgaGF2aW5nIGEgcGVybWlzc2l2ZSByaWdodC10by1jYXJyeSBsYXcuIFJlY2FsbCB0aGF0IG5vIHN0YXRlcyBjdXJyZW50bHkgaGF2ZSBhIHJpZ2h0cyBpbmZyaW5nZWQvbm9uLWlzc3VlIGxhdy4KClN0YXRlcyBvZiBhbGwgb3RoZXIgY2F0ZWdvcmllcyAoc2hhbGwgaXNzdWUsIGRpc2NyZXRpb25hcnkvcmVhc29uYWJsZSBpc3N1ZSwgYW5kIG5vIHBlcm1pdCByZXF1aXJlZCwgYWxsIHNoYWRlcyBvZiBibHVlKSBhcmUgY29uc2lkZXJlZCB0aGUgc2FtZSBpbiBvdXIgYW5hbHlzaXMsIGFzIGhhdmluZyBhIHBlcm1pc3NpdmUgcmlnaHQtdG8tY2FycnkgbGF3LgoKMykgQmVjYXVzZSBvdXIgYW5hbHlzaXMgaW4gdGhlIG5leHQgW2Nhc2Ugc3R1ZHldKGh0dHBzOi8vd3d3Lm9wZW5jYXNlc3R1ZGllcy5vcmcvb2NzLWJwLVJUQy1hbmFseXNpcykgaXMgYW4gb3ZlcnNpbXBsaWZpY2F0aW9uLCB0aGUgcmVzdWx0cyBwcmVzZW50ZWQgaGVyZSBzaG91bGQgbm90IGJlIHVzZWQgZm9yIGRldGVybWluaW5nIHBvbGljeSBjaGFuZ2VzOyBpbnN0ZWFkIHdlIHN1Z2dlc3QgdGhhdCB1c2VycyBpbnRlcmVzdGVkIGluIHN1Y2ggYSBkZXRlcm1pbmF0aW9uIGNvbnN1bHQgd2l0aCBhIHNwZWNpYWxpc3QuCgo0KSBUaGUgaW5jbHVzaW9uIG9mIHJhY2UgYXMgYW4gZXhwbGFuYXRvcnkgdmFyaWFibGUgaW4gYW4gZXBpZGVtaW9sb2dpY2FsIHN0dWR5IGNhbiBiZSB1c2VmdWwgaW4gY2VydGFpbiBjaXJjdW1zdGFuY2VzLiBIb3dldmVyLCB0aGVyZSBhcmUgbGltaXRhdGlvbnMgYW5kIGlzc3VlcyBhcm91bmQgZGVmaW5pbmcsIGRldGVybWluaW5nLCBhbmQgcmVwb3J0aW5nIHJhY2UsIGFzIHdlbGwgYXMgaW4gaW50ZXJwcmV0aW5nIGRpZmZlcmVuY2VzIGluIHB1YmxpYyBoZWFsdGggb3V0Y29tZXMgYnkgcmFjZS4gRm9yIG1vcmUgaW5mb3JtYXRpb24gb24gdGhpcyB0b3BpYywgd2UgaGF2ZSBpbmNsdWRlZCBhIFtsaW5rXShodHRwczovL2FjYWRlbWljLm91cC5jb20vZXBpcmV2L2FydGljbGUvMjIvMi8xODcvNDU2OTQyKSB0byBhIHBhcGVyIG9uIHRoZSB1c2Ugb2YgcmFjZSBhcyBhIG1lYXN1cmUgaW4gZXBpZGVtaW9sb2d5LiBXZSBpbmNsdWRlIHJhY2UgaW4gdGhpcyBhbmFseXNpcyB0byBkZW1vbnN0cmF0ZSBhbmQgY29uc2lkZXIgdGhlIGxpbWl0YXRpb25zIG9mIHdoYXQgdGhlIHByZXZpb3VzIHBhcGVycyBoYXZlIGRvbmUgdG8gYW5hbHl6ZSB0aGUgaW5mbHVlbmNlIG9mIFJUQyBsYXdzIG9uIHZpb2xlbnQgY3JpbWUsIHdpdGggYSBmb2N1cyBvbiBtdWx0aWNvbGxpbmVhcml0eS4gVGh1cyBpbiBvdXIgYW5hbHlzaXMgd2UgaGF2ZSBhbHNvIGRlZmluZWQgcmFjZSBhcyB3YXMgcHJldmlvdXNseSBkb25lIGluIHRoZXNlIHBhcGVycy4gRnVydGhlcm1vcmUsIHdlIHdhbnQgdG8gcG9pbnQgb3V0IHRoYXQgcmVwb3J0aW5nIGFuYWx5c2VzIGFib3V0IGNyaW1lIHdpdGggcmFjZSBhcyBhIHZhcmlhYmxlIGNhbiBoYXZlIHZlcnkgdW5leHBlY3RlZCBjb25zZXF1ZW5jZXMgYW5kIHRodXMgY2FyZSBzaG91bGQgYmUgdGFrZW4uIFNlZSBbaGVyZV0oaHR0cHM6Ly9qb3VybmFscy5zYWdlcHViLmNvbS9kb2kvZnVsbC8xMC4xMTc3LzA5NjM3MjE0MTg3NjM5MzEpIGZvciBzdWdnZXN0aW9ucy4gQW55IGFzc29jaWF0aW9uIGJldHdlZW4gZGVtb2dyYXBoaWMgdmFyaWFibGVzIChpbmRpY2F0aW5nIHRoZSBwcm9wb3J0aW9uIG9mIHRoZSBwb3B1bGF0aW9uIGZyb20gc3BlY2lmaWMgcmFjZSBhbmQgYWdlIGdyb3VwcykgYW5kIHZpb2xlbnQgY3JpbWUgZG9lcyBub3QgbmVjZXNzYXJpbHkgaW5kaWNhdGUgdGhhdCB0aGUgdHdvIGFyZSBsaW5rZWQgY2F1c2FsbHksIGFzIGFzaWRlIGZyb20gdGhlIGlzc3VlcyBwcmVzZW50ZWQgaW4gdGhlIFthcnRpY2xlXSgoaHR0cHM6Ly9hY2FkZW1pYy5vdXAuY29tL2VwaXJldi9hcnRpY2xlLzIyLzIvMTg3LzQ1Njk0MikpLCB0aGlzIG1heSBpbnN0ZWFkIGluZGljYXRlIGhpZ2hlciByYXRlcyBvZiBwb2xpY2UgZW5nYWdlbWVudCB3aXRoIGNlcnRhaW4gcmFjaWFsIGdyb3VwcyBkdWUgdG8gW3JhY2lhbCBwcm9mbGluZ10oaHR0cHM6Ly93d3cuYWNsdS5vcmcvb3RoZXIvcmFjaWFsLXByb2ZpbGluZy1kZWZpbml0aW9uKS4KClRoZSBBQ0xVIGRlZmluZXMgcmFjaWFsIHByb2ZpbGluZyBhczoKCj4iUmFjaWFsIFByb2ZpbGluZyIgcmVmZXJzIHRvIHRoZSBkaXNjcmltaW5hdG9yeSBwcmFjdGljZSBieSBsYXcgZW5mb3JjZW1lbnQgb2ZmaWNpYWxzIG9mIHRhcmdldGluZyBpbmRpdmlkdWFscyBmb3Igc3VzcGljaW9uIG9mIGNyaW1lIGJhc2VkIG9uIHRoZSBpbmRpdmlkdWFsJ3MgcmFjZSwgZXRobmljaXR5LCByZWxpZ2lvbiBvciBuYXRpb25hbCBvcmlnaW4uCgoqKioKCgoKV2Ugd2lsbCBiZWdpbiBieSBsb2FkaW5nIHRoZSBwYWNrYWdlcyB0aGF0IHdlIHdpbGwgbmVlZDoKCmBgYHtyfQpsaWJyYXJ5KGhlcmUpCmxpYnJhcnkocmVhZHhsKQpsaWJyYXJ5KHJlYWRyKQpsaWJyYXJ5KHBkZnRvb2xzKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KG1hZ3JpdHRyKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KHN0cmluZ3IpCmxpYnJhcnkocHVycnIpCmxpYnJhcnkoZm9yY2F0cykKbGlicmFyeSh0aWJibGUpCmBgYAoKPHU+KipQYWNrYWdlcyB1c2VkIGluIHRoaXMgY2FzZSBzdHVkeToqKiA8L3U+CgogIFBhY2thZ2UgICB8IFVzZSBpbiB0aGlzIGNhc2Ugc3R1ZHkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKLS0tLS0tLS0tLSB8LS0tLS0tLS0tLS0tLQpbaGVyZV0oaHR0cHM6Ly9naXRodWIuY29tL2plbm55YmMvaGVyZV9oZXJlKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgIHwgdG8gZWFzaWx5IGxvYWQgYW5kIHNhdmUgZGF0YQpbcmVhZHhsXShodHRwczovL3JlYWR4bC50aWR5dmVyc2Uub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSAgICAgIHwgdG8gaW1wb3J0IHRoZSBkYXRhIGluIHRoZSBleGNlbCBmaWxlcyAKW3JlYWRyXShodHRwczovL3JlYWRyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byBpbXBvcnQgdGhlIENTViBmaWxlIGRhdGEKW3BkZnRvb2xzXShodHRwczovL2dpdGh1Yi5jb20vcm9wZW5zY2kvcGRmdG9vbHMpe3RhcmdldD0iX2JsYW5rIn0gfCB0byBpbXBvcnQgZGF0YSBmcm9tIGEgcGRmIGZpbGUKW2RwbHlyXShodHRwczovL2RwbHlyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byBhcnJhbmdlL2ZpbHRlci9zZWxlY3QvY29tcGFyZSBzcGVjaWZpYyBzdWJzZXRzIG9mIHRoZSBkYXRhICAKW21hZ3JpdHRyXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvbWFncml0dHIvdmlnbmV0dGVzL21hZ3JpdHRyLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gfCB0byB1c2UgdGhlIGNvbXBvdW5kIGFzc2lnbm1lbnQgcGlwZSBvcGVyYXRvciBgJTw+JWAKW3RpZHlyXShodHRwczovL3RpZHlyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byByZWFycmFuZ2UgZGF0YSBpbiB3aWRlIGFuZCBsb25nIGZvcm1hdHMgCltzdHJpbmdyXShodHRwczovL3N0cmluZ3IudGlkeXZlcnNlLm9yZy9hcnRpY2xlcy9zdHJpbmdyLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gICAgfCB0byBtYW5pcHVsYXRlIHRoZSBjaGFyYWN0ZXIgc3RyaW5ncyB3aXRoaW4gdGhlIGRhdGEgIApbcHVycnJdKGh0dHBzOi8vcHVycnIudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gICB8IHRvIGltcG9ydCB0aGUgZGF0YSBpbiBhbGwgdGhlIGRpZmZlcmVudCBleGNlbCBhbmQgY3N2IGZpbGVzIGVmZmljaWVudGx5Cltmb3JjYXRzXShodHRwczovL2ZvcmNhdHMudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gICAgfCB0byBhbGxvdyBmb3IgcmVvcmRlcmluZyBvZiBmYWN0b3JzIGluIHBsb3RzClt0aWJibGVdKGh0dHBzOi8vdGliYmxlLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICB8IHRvIGNyZWF0ZSBkYXRhIG9iamVjdHMgdGhhdCB3ZSBjYW4gbWFuaXB1bGF0ZSB3aXRoIGBkcGx5cmAvYHN0cmluZ3JgL2B0aWR5cmAvYHB1cnJyYAoKIyAqKldoYXQgYXJlIHRoZSBkYXRhPyoqCioqKgoKQmVsb3cgaXMgYSB0YWJsZSBmcm9tIHRoZSBbRG9ub2h1ZSwgZXQgYWwuXShodHRwczovL3d3dy5uYmVyLm9yZy9wYXBlcnMvdzIzNTEwLnBkZil7dGFyZ2V0PSJfYmxhbmsifSBwYXBlciB0aGF0IHNob3dzIHRoZSBkYXRhIHVzZWQgaW4gYm90aCBhbmFseXNlcywgd2hlcmUgREFXIHN0YW5kcyBmb3IgW0Rvbm9odWUsIGV0IGFsLl0oaHR0cHM6Ly93d3cubmJlci5vcmcvcGFwZXJzL3cyMzUxMC5wZGYpe3RhcmdldD0iX2JsYW5rIn0gYW5kIE1MIHN0YW5kcyBmb3IgW011c3RhcmQgYW5kIExvdHRdKGh0dHBzOi8vY2hpY2Fnb3VuYm91bmQudWNoaWNhZ28uZWR1L2NnaS92aWV3Y29udGVudC5jZ2k/YXJ0aWNsZT0xMTUwJmNvbnRleHQ9bGF3X2FuZF9lY29ub21pY3Mpe3RhcmdldD0iX2JsYW5rIn0uCgoKYGBge3IsIGVjaG89RkFMU0UsIG91dC5oZWlnaHQgPSAnMTAwJScsIG91dC53aWR0aCA9ICcxMDAlJywgZmlnLmFsaWduPSdjZW50ZXInfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlKCJpbWciLCAiRG9ub2h1ZV9BcHBlbmRpeEoucG5nIikpCmBgYAoKV2Ugd2lsbCBiZSB1c2luZyBhIHN1YnNldCBvZiB0aGVzZSB2YXJpYWJsZXMsIHdoaWNoIGFyZSBoaWdobGlnaHRlZCBpbiBncmVlbjoKCgpgYGB7ciwgZWNobz1GQUxTRSwgb3V0LmhlaWdodCA9ICcxMDAlJywgb3V0LndpZHRoID0gJzEwMCUnLCBmaWcuYWxpZ249J2NlbnRlcid9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmUoImltZyIsICJvdXJkYXRhLnBuZyIpKQpgYGAKCgojICoqRGF0YSBJbXBvcnQqKgoqKioKCgojIyAqKkRlbW9ncmFwaGljIGFuZCBwb3B1bGF0aW9uIGRhdGEqKgoqKioKVG8gb2J0YWluIGluZm9ybWF0aW9uIGFib3V0IGFnZSwgc2V4LCBhbmQgcmFjZSwgYW5kIG92ZXJhbGwgcG9wdWxhdGlvbiB3ZSB3aWxsIHVzZSBVUyBDZW5zdXMgQnVyZWF1IGRhdGEsIGp1c3QgbGlrZSBib3RoIG9mIHRoZSBhcnRpY2xlcy4gVGhlIGNlbnN1cyBkYXRhIGlzIGF2YWlsYWJsZSBmb3IgZGlmZmVyZW50IHRpbWUgc3BhbnMuIEhlcmUgYXJlIHRoZSBsaW5rcyBmb3IgdGhlIHllYXJzIHVzZWQgaW4gb3VyIGFuYWx5c2lzLiBXZSB3aWxsIHVzZSBkYXRhIGZyb20gMTk3NyB0byAyMDEwLgoKRGF0YSAgIHwgTGluayAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAotLS0tLS0tLS0tIHwtLS0tLS0tLS0tLS0tCioqeWVhcnMgMTk3NyB0byAxOTc5KiogIHwgW2xpbmtdKGh0dHBzOi8vd3d3Mi5jZW5zdXMuZ292L3Byb2dyYW1zLXN1cnZleXMvcG9wZXN0L3RhYmxlcy8xOTAwLTE5ODAvc3RhdGUvYXNyaC8pICAKKip5ZWFycyAxOTgwIHRvIDE5ODkqKiAgfCBbbGlua10oaHR0cHM6Ly93d3cyLmNlbnN1cy5nb3YvcHJvZ3JhbXMtc3VydmV5cy9wb3Blc3QvdGFibGVzLzE5ODAtMTk5MC9jb3VudGllcy9hc3JoLykgKiBjb3VudHkgZGF0YSB3YXMgdXNlZCBmb3IgdGhpcyBkZWNhZGUgd2hpY2ggYWxzbyBoYXMgc3RhdGUgaW5mb3JtYXRpb24KKip5ZWFycyAxOTkwIHRvIDE5OTkqKiAgfCBbbGlua10oaHR0cHM6Ly93d3cyLmNlbnN1cy5nb3YvcHJvZ3JhbXMtc3VydmV5cy9wb3Blc3QvdGFibGVzLzE5OTAtMjAwMC9zdGF0ZS9hc3JoLykKKip5ZWFycyAyMDAwIHRvIDIwMTAqKiAgfCBbbGlua10oaHR0cHM6Ly93d3cuY2Vuc3VzLmdvdi9kYXRhL2RhdGFzZXRzL3RpbWUtc2VyaWVzL2RlbW8vcG9wZXN0L2ludGVyY2Vuc2FsLTIwMDAtMjAxMC1zdGF0ZS5odG1sKSA8YnI+IFt0ZWNobmljYWwgZG9jdW1lbnRhdGlvbl0oaHR0cHM6Ly93d3cyLmNlbnN1cy5nb3YvcHJvZ3JhbXMtc3VydmV5cy9wb3Blc3QvdGVjaG5pY2FsLWRvY3VtZW50YXRpb24vZmlsZS1sYXlvdXRzLzIwMDAtMjAxMC9pbnRlcmNlbnNhbC9zdGF0ZS9zdC1lc3QwMGludC1hbGxkYXRhLnBkZil7dGFyZ2V0PSJfYmxhbmsifQoKVG8gaW1wb3J0IHRoZSBkYXRhIHdlIHdpbGwgdXNlIHRoZSBgcmVhZF9jc3YoKWAgZnVuY3Rpb24gb2YgdGhlIGByZWFkcmAgcGFja2FnZSBmb3IgdGhlIGNzdiBmaWxlcy4gSW4gc29tZSBkZWNhZGVzLCB0aGVyZSBhcmUgc2VwYXJhdGUgZmlsZXMgZm9yIGVhY2ggeWVhciwgd2Ugd2lsbCByZWFkIGVhY2ggb2YgdGhlc2UgdG9nZXRoZXIgdXNpbmcgdGhlIGJhc2UgYGxpc3QuZmlsZXMoKWAgZnVuY3Rpb24gdG8gZ2V0IGFsbCBvZiB0aGUgbmFtZXMgZm9yIGVhY2ggZmlsZSBhbmQgdGhlbiB0aGUgYG1hcCgpYCBmdW5jdGlvbiBvZiB0aGUgYHB1cnJyYCBwYWNrYWdlIHRvIGFwcGx5IHRoZSBgcmVhZF9jc3YoKWAgZnVuY3Rpb24gb24gYWxsIG9mIHRoZSBmaWxlIHBhdGhzIGluIHRoZSBsaXN0IGNyZWF0ZWQgYnkgYGxpc3QuZmlsZXMoKWAuIEZvciB5ZWFycyB0aGF0IGFyZSB0eHQgZmlsZXMgd2Ugd2lsbCB1c2UgYHJlYWRfdGFibGUyKClgIGFsc28gZm9yIHRoZSBgcmVhZHJgIHBhY2thZ2UuIFRoZSBgcmVhZF90YWJsZTIoKWAgZnVuY3Rpb24sIHVubGlrZSB0aGUgYHJlYWRfdGFibGUoKWAsICBhbGxvd3MgZm9yIGFueSBudW1iZXIgb2Ygd2hpdGUgc3BhY2UgY2hhcmFjdGVycyBiZXR3ZWVuIGNvbHVtbnMsIGFuZCB0aGUgbGluZXMgY2FuIGJlIG9mIGRpZmZlcmVudCBsZW5ndGhzLgoKV2Ugd2lsbCBzYXZlIG91ciBkYXRhIHRvIGEgZGlyZWN0b3J5IHdpdGhpbiBvdXIgd29ya2luZyBkaXJlY3RvcnkgY2FsbGVkIGRhdGEuIFdlIHdpbGwgY3JlYXRlIHN1YmRpcmVjdG9yaWVzIHdpdGhpbiB0aGlzIGRpcmVjdG9yeSB0byBvcmdhbml6ZSBvdXIgZGF0YS4gV2UgY2FuIHVzZSB0aGUgYGhlcmVgIGZ1bmN0aW9uIGZyb20gdGhlIGBoZXJlYCBwYWNrYWdlIHRvIG1ha2UgdGhpcyBwcm9jZXNzIGVhc2llci4gVGhlIGBoZXJlKClgIGZ1bmN0aW9uIGFsbG93cyB1cyB0byBzcGVjaWZ5IHRoZSBwYXRoIG9yIGxvY2F0aW9uIG9mIHRoZSBkb2N1bWVudCB0aGF0IHdlIHdhbnQgdG8gaW1wb3J0LCBzdGFydGluZyBmcm9tIHRoZSBkaXJlY3Rvcnkgd2hlcmUgYSBgLlJwcm9qYCBmaWxlIGlzIGxvY2F0ZWQuIEluIHRoaXMgY2FzZSwgd2Ugd2lsbCBpbXBvcnQgb3VyIGZpbGVzIHdpdGhpbiBzdWJkaXJlY3RvcmllcyBvZiAgYSBkaXJlY3RvcnkgY2FsbGVkIGByYXdgIG9mIHRoZSBgZGF0YWAgZGlyZWN0b3J5LiAoKk5vdGUgdGhlIG5leHQgY2h1bmsgb2YgY29kZSB3aWxsIG9ubHkgd29yayBmb3IgeW91IGlmIHlvdSBwdWxsIHRoZSByZXBvc2l0b3J5IGZyb20gR2l0SHViIGFuZCBzZXQgdXAgeW91ciBmaWxlIHN0cnVjdHVyZSBpbiB0aGUgc2FtZSB3YXkuKikgSWYgeW91IGhhZCB0cm91YmxlIGRvd25sb2FkaW5nIHRoZSBkYXRhIGZyb20gdGhlIG9yZ2luYWwgc291cmNlcyB5b3UgY2FuIGRvd25sb2FkIHRoZW0gZnJvbSBvdXIgW0dpdEh1YiByZXBvc2l0b3J5IGZvciB0aGlzIGNhc2Ugc3R1ZHldKGh0dHBzOi8vZ2l0aHViLmNvbS9vcGVuY2FzZXN0dWRpZXMvb2NzLWJwLVJUQy13cmFuZ2xpbmcvdHJlZS9tYXN0ZXIvZGF0YSkuCgoqKioKCjxkZXRhaWxzPiA8c3VtbWFyeT4gQ2xpY2sgaGVyZSB0byBzZWUgbW9yZSBhYm91dCBjcmVhdGluZyBuZXcgcHJvamVjdHMgaW4gUlN0dWRpby4gPC9zdW1tYXJ5PgoKWW91IGNhbiBjcmVhdGUgYSBwcm9qZWN0IGJ5IGdvaW5nIHRvIHRoZSBGaWxlIG1lbnUgb2YgUlN0dWRpbyBsaWtlIHNvOgoKCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aD0iNjAlIn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgIk5ld19wcm9qZWN0LnBuZyIpKQpgYGAKCllvdSBjYW4gYWxzbyBkbyBzbyBieSBjbGlja2luZyB0aGUgcHJvamVjdCBidXR0b246CgpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXQud2lkdGg9IjYwJSJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJwcm9qZWN0X2J1dHRvbi5wbmciKSkKYGBgCgpTZWUgW2hlcmVdKGh0dHBzOi8vc3VwcG9ydC5yc3R1ZGlvLmNvbS9oYy9lbi11cy9hcnRpY2xlcy8yMDA1MjYyMDctVXNpbmctUHJvamVjdHMpIHRvIGxlYXJuIG1vcmUgYWJvdXQgdXNpbmcgUlN0dWRpbyBwcm9qZWN0cyBhbmQgW2hlcmVdKGh0dHBzOi8vZ2l0aHViLmNvbS9qZW5ueWJjL2hlcmVfaGVyZSkgdG8gbGVhcm4gbW9yZSBhYm91dCB0aGUgYGhlcmVgIHBhY2thZ2UuCgo8L2RldGFpbHM+CioqKgo8L2RldGFpbHM+CgoqKioKCmBgYHtyfQoKZGVtXzc3Xzc5IDwtIHJlYWRfY3N2KGhlcmU6OmhlcmUoImRhdGEiLCAicmF3IiwgIkRlbW9ncmFwaGljcyIsICJEZWNhZGVfMTk3MCIsICJwZS0xOS5jc3YiKSwgc2tpcCA9IDUpCgpkZW1fODBfODkgPC0gbGlzdC5maWxlcyhyZWN1cnNpdmUgPSBUUlVFLAogICAgICAgICAgICAgICAgICBwYXRoID0gaGVyZSgiZGF0YSIsICJyYXciLCAiRGVtb2dyYXBoaWNzIiwgIkRlY2FkZV8xOTgwIiksCiAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiKi5jc3YiLAogICAgICAgICAgICAgICAgICBmdWxsLm5hbWVzID0gVFJVRSkgJT4lIAogIG1hcCh+cmVhZF9jc3YoLiwgc2tpcD01KSkKCmRlbV85MF85OSA8LSBsaXN0LmZpbGVzKHJlY3Vyc2l2ZSA9IFRSVUUsCiAgICAgICAgICAgICAgICAgIHBhdGggPSBoZXJlKCJkYXRhIiwgInJhdyIsICJEZW1vZ3JhcGhpY3MiLCAiRGVjYWRlXzE5OTAiKSwKICAgICAgICAgICAgICAgICAgcGF0dGVybiA9ICIqLnR4dCIsCiAgICAgICAgICAgICAgICAgIGZ1bGwubmFtZXMgPSBUUlVFKSAlPiUgCiAgbWFwKH5yZWFkX3RhYmxlMiguLCBza2lwID0gMTQpKQoKCmRlbV8wMF8xMCA8LSBsaXN0LmZpbGVzKHJlY3Vyc2l2ZSA9IFRSVUUsCiAgICAgICAgICAgICAgICAgIHBhdGggPSBoZXJlKCJkYXRhIiwgInJhdyIsICJEZW1vZ3JhcGhpY3MiLCAiRGVjYWRlXzIwMDAiKSwKICAgICAgICAgICAgICAgICAgcGF0dGVybiA9ICIqLmNzdiIsCiAgICAgICAgICAgICAgICAgICBmdWxsLm5hbWVzID0gVFJVRSkgJT4lIAogICBtYXAofnJlYWRfY3N2KC4pKQoKaGVhZChkZW1fMDBfMTApCgpgYGAKCk5vdGljZSB0aGF0IHRoZSBgU1RBVEVgIHZhcmlhYmxlIGZvciB0aGUgZGVtb2dyYXBoaWMgZGF0YSBpcyBudW1lcmljLiBUaGF0IGlzIGJlY2F1c2UgaXQgaXMgZW5jb2RlZCBieSBbRmVkZXJhbCBJbmZvcm1hdGlvbiBQcm9jZXNzaW5nIFN0YW5kYXJkIChGSVBTKSBzdGF0ZSBjb2Rlc10oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvRmVkZXJhbF9JbmZvcm1hdGlvbl9Qcm9jZXNzaW5nX1N0YW5kYXJkX3N0YXRlX2NvZGUpe3RhcmdldD0iX2JsYW5rIi4gVGh1cyB3ZSBhbHNvIG5lZWQgdG8gaW1wb3J0IGRhdGEgIGFib3V0IEZJUFMgZW5jb2Rpbmcgc28gdGhhdCB3ZSBjYW4gaWRlbnRpZnkgd2hhdCBkYXRhIGNvcnJlc3BvbmRzIHRvIHdoYXQgc3RhdGUuCgoKIyMgKipTdGF0ZSBGSVBTIGNvZGVzKioKKioqCgoKClRoZSBmb2xsb3dpbmcgZGF0YSB3YXMgZG93bmxvYWRlZCBmcm9tIHRoZSBbVVMgQ2Vuc3VzIEJ1cmVhdV0oaHR0cHM6Ly93d3cuY2Vuc3VzLmdvdi9nZW9ncmFwaGllcy9yZWZlcmVuY2UtZmlsZXMvMjAxNC9kZW1vL3BvcGVzdC8yMDE0LWdlb2NvZGVzLXN0YXRlLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0uCgpUbyBpbXBvcnQgdGhlIGRhdGEgd2Ugd2lsbCB1c2UgdGhlIGByZWFkX3hscygpYCBmdW5jdGlvbiBvZiB0aGUgYHJlYWR4bGAgcGFja2FnZS4gU2luY2UgdGhlIGZpcnN0IGZpdmUgbGluZXMgb2YgdGhpcyBleGNlbCBpcyBpbmZvcm1hdGlvbiBhYm91dCB0aGUgc291cmNlIG9mIHRoZSBkYXRhIGFuZCB3aGVuIGl0IHdhcyByZWxlYXNlZCwgd2UgbmVlZCB0byBza2lwIGltcG9ydGluZyB0aGVzZSBsaW5lcyB1c2luZyB0aGUgYHNraXBgIGFyZ3VtZW50IHNvIHRoYXQgdGhlIGRhdGEgaGFzIHRoZSBzYW1lIG51bWJlciBvZiBjb2x1bW5zIGZvciBlYWNoIHJvdy4gCgpgYGB7ciwgb3V0LndpZHRoID0gIjUwMCBweCJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmUoImltZyIsICJGSVBTLnBuZyIpKQoKYGBgCgpgYGB7cn0KU1RBVEVfRklQUyA8LSByZWFkX3hscyhoZXJlKCJkYXRhIiwgInJhdyIsICJTdGF0ZV9GSVBTX2NvZGVzIiwgInN0YXRlLWdlb2NvZGVzLXYyMDE0LnhscyIpLCBza2lwID0gNSkKKFNUQVRFX0ZJUFMpCmBgYAoKIyMgKipQb2xpY2Ugc3RhZmZpbmcgZGF0YSoqCioqKgoKVGhlIGZvbGxvd2luZyBkYXRhIHdhcyBkb3dubG9hZGVkIGZyb20gdGhlIFtGZWRlcmFsIEJ1cmVhdSBvZiBJbnZlc3RpZ2F0aW9uXShodHRwczovL2NyaW1lLWRhdGEtZXhwbG9yZXIuZnIuY2xvdWQuZ292L2Rvd25sb2Fkcy1hbmQtZG9jcykuIAoKClRoZSBgcmVhZF9jc3YoKWAgZnVuY3Rpb24gb2YgdGhlIGByZWFkcmAgcGFja2FnZSBndWVzc2VzIHdoYXQgdGhlIGNsYXNzIGlzIGZvciBlYWNoIHZhcmlhYmxlLCBidXQgc29tZXRpbWVzIGl0IG1ha2VzIG1pc3Rha2VzLiBJdCBpcyBnb29kIHRvIHNwZWNpZnkgdGhlIGNsYXNzIGZvciB2YXJpYWJsZXMgaWYgeW91IGtub3cgdGhlbS4gV2Uga25vdyB0aGF0IHdlIHdhbnQgdGhlIHZhcmlhYmxlcyBhYm91dCBtYWxlIGFuZCBmZW1hbGUgY291bnRzIHRvIGJlIG51bWVyaWMuIFdlIGNhbiBzcGVjaWZ5IHRoYXQgdXNpbmcgdGhlIGBjb2xfdHlwZXMgPWAgYXJndW1lbnQuIFNlZSBbaGVyZV0oaHR0cHM6Ly9yZWFkci50aWR5dmVyc2Uub3JnL2FydGljbGVzL3JlYWRyLmh0bWwpIGFuZCBbaGVyZV0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL3JlYWRyL3ZpZ25ldHRlcy9yZWFkci5odG1sKSBmb3IgbW9yZSBpbmZvcm1hdGlvbi4gV2UgY2FuIGFsc28gaW5kaWNhdGUgdGhhdCBlbXB0eSB2YWx1ZXMgc2hvdWxkIGJlIGV2YWx1YXRlZCBhcyBOQSB2YWx1ZXMsIGFzIHRoZXJlIGFyZSBtYW55IGVtcHR5IHZhbHVlcy4gTm90ZSB0aGF0IHRoaXMgaXMgYSBsYXJnZSBmaWxlLgoKYGBge3IsIGV2YWwgPSBGQUxTRX0KCnBzX2RhdGEgPC0gcmVhZF9jc3YoaGVyZSgiZGF0YSIsICJyYXciLCAiUG9saWNlX3N0YWZmaW5nIiwgInBlXzE5NjBfMjAxOC5jc3YiKSwKICAgICAgICAgICAgICAgICAgIGNvbF90eXBlcyA9ICBjb2xzKG1hbGVfdG90YWxfY3QgPSBjb2xfZG91YmxlKCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmVtYWxlX3RvdGFsX2N0ID0gY29sX2RvdWJsZSgpKSwgbmEgPSBjKCIiKSkKYGBgCgoKCiMjICoqVW5lbXBsb3ltZW50IGRhdGEqKgoqKioKVGhlIGZvbGxvd2luZyBkYXRhIHdhcyBkb3dubG9hZGVkIGZyb20gdGhlIFtVLlMuIEJ1cmVhdSBvZiBMYWJvciBTdGF0aXN0aWNzXShodHRwczovL2RhdGEuYmxzLmdvdi9jZ2ktYmluL2RzcnY/bGEpLiAKClRoZXJlIGFyZSBleGNlbCBmaWxlcyBmb3IgZWFjaCBzdGF0ZS4gIEFzIHlvdSBjYW4gc2VlLCB0aGVyZSBhcmUgbWFueSByb3dzIHRvIHNraXAgdG8gbWFrZSBzdXJlIHRoYXQgdGhlcmUgYXJlIHRoZSBzYW1lIG51bWJlciBvZiBjb2x1bW5zIGZvciBlYWNoIHJvdy4gV2UgY2FuIGFsc28gc2VlIHRoYXQgdGhlIHN0YXRlIG5hbWUgaXMgbG9jYXRlZCBpbiBhIGNvdXBsZSBvZiB0aGUgZmlyc3Qgcm93cy4gCgpgYGB7cn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZSgiaW1nIiwgIlVuZW1wLnBuZyIpKQpgYGAKCldlIGNhbiBhbHNvIHNlZSB0aGF0IGhlcmUgaWYgd2UganVzdCB0cnkgdG8gcmVhZCBpbiB0aGUgZmlsZXMgZGlyZWN0bHkuCgpgYGB7cn0KCnVlX3JhdGVfZGF0YSA8LSBsaXN0LmZpbGVzKHJlY3Vyc2l2ZSA9IFRSVUUsCiAgICAgICAgICAgICAgICAgIHBhdGggPSBoZXJlKCJkYXRhIiwgInJhdyIsICJVbmVtcGxveW1lbnQiKSwKICAgICAgICAgICAgICAgICAgcGF0dGVybiA9ICIqLnhsc3giLAogICAgICAgICAgICAgICAgICBmdWxsLm5hbWVzID0gVFJVRSkgJT4lIAogIG1hcCh+cmVhZF94bHN4KC4pKQogICAgICAKaGVhZCh1ZV9yYXRlX2RhdGEpWzFdCmBgYAoKU28gbm93IHdlIHdpbGwgc2tpcCB0aGUgZmlyc3QgMTAgbGluZXMuIEFuZCBhbHNvIGNyZWF0ZSBhIG5hbWVzIHRpYmJsZSB0aGF0IGNvbnRhaW5zIG9ubHkgdGhlIGNlbGwgd2l0aCB0aGUgc3RhdGUgaW5mb3JtYXRpb24uCgpgYGB7cn0KIAogdWVfcmF0ZV9kYXRhIDwtIGxpc3QuZmlsZXMocmVjdXJzaXZlID0gVFJVRSwKICAgICAgICAgICAgICAgICAgcGF0aCA9IGhlcmUoImRhdGEiLCAicmF3IiwgIlVuZW1wbG95bWVudCIpLAogICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIioueGxzeCIsCiAgICAgICAgICAgICAgICAgIGZ1bGwubmFtZXMgPSBUUlVFKSAlPiUgCiAgbWFwKH5yZWFkX3hsc3goLiwgc2tpcCA9IDEwKSkKICAKaGVhZCh1ZV9yYXRlX2RhdGFbMV0pCmBgYAoKVG8gZ2V0IHRoZSBzdGF0ZSBuYW1lIGZvciBlYWNoIGZpbGUgdXNpbmcgdGhlIGBtYXAoKWAgZnVuY3Rpb24gdG8gcGVyZm9ybSBmdW5jdGlvbnMgYWNyb3NzIGFsbCBvZiB0aGUgZmlsZXMsIHdlIHdpbGwgc3BlY2lmaWNhbGx5IGltcG9ydCBvbmx5IGEgc21hbGwgcmFuZ2Ugb2YgY2VsbHMgdXNpbmcgdGhlIGByYW5nZSA9IGAgYXJndW1lbnQgYW5kIHRoZW4gZ3JhYiB0aGUgY2VsbCB0aGF0IGhhcyBzdGF0ZSBpbmZvcm1hdGlvbiBiYXNlZCBvbiBpdCdzIGxvY2F0aW9uIHdpdGhpbiB0aGUgcmFuZ2Ugb2YgY2VsbHMgaW1wb3J0ZWQgdXNpbmcgYGMoKWAgYW5kIHRoZW4gdXNlIHRoZSBiYXNlIGB1bmxpc3QoKWAgZnVuY3Rpb24gdG8gdW5saXN0IHRoZSBsaXN0IHRoYXQgdGhpcyBjcmVhdGVzLgoKYGBge3J9CnVlX3JhdGVfbmFtZXMgPC0gbGlzdC5maWxlcyhyZWN1cnNpdmUgPSBUUlVFLAogICAgICAgICAgICAgICAgICBwYXRoID0gaGVyZSgiZGF0YSIsICJyYXciLCAiVW5lbXBsb3ltZW50IiksCiAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiKi54bHN4IiwKICAgICAgICAgICAgICAgICAgZnVsbC5uYW1lcyA9IFRSVUUpICU+JQogIG1hcCh+cmVhZF94bHN4KC4sIHJhbmdlID0gIkI0OkI2IikpICU+JQogIG1hcCguLCBjKDEsMikpICU+JQogIHVubGlzdCgpCgp1ZV9yYXRlX25hbWVzCmBgYAoKTm93IHdlIHdpbGwgbWFrZSB0aGVzZSB2YWx1ZXMgdGhlIG5hbWVzIG9mIHRoZSBkaWZmZXJlbnQgdGliYmxlcyB3aXRoaW4gYHVlX3JhdGVfZGF0YWAuCmBgYHtyfQpuYW1lcyh1ZV9yYXRlX2RhdGEpIDwtIHVlX3JhdGVfbmFtZXMKYGBgCgojIyAqKlBvdmVydHkgZGF0YSoqCioqKgoKRXh0cmFjdGVkIGZyb20gVGFibGUgMjEgZnJvbSBbVVMgQ2Vuc3VzIEJ1cmVhdSBQb3ZlcnR5IERhdGEgXShodHRwczovL3d3dy5jZW5zdXMuZ292L2RhdGEvdGFibGVzL3RpbWUtc2VyaWVzL2RlbW8vaW5jb21lLXBvdmVydHkvaGlzdG9yaWNhbC1wb3ZlcnR5LXBlb3BsZS5odG1sKS4KCmBgYHtyfQoKIyoqcGVyc2lzdGVudCB3YXJuaW5nIGZyb20gdW5rbm93biBvcmlnaW4qKiBodHRwczovL2NvbW11bml0eS5yc3R1ZGlvLmNvbS90L3BlcnNpc3RlbnQtdW5rbm93bi1vci11bmluaXRpYWxpc2VkLWNvbHVtbi13YXJuaW5ncy82NDg3OQoKI3NvbHV0aW9uIHRvIGFib3ZlIGlzIGFsbGVkZ2VkbHk6ICJJbiBhbnkgY2FzZSB0aGUgc3VnZ2VzdGVkIGFwcHJvYWNoIGlzIHRvIGluaXRpYWxpemUgdGhlIGNvbHVtbiIKCgpwb3ZlcnR5X3JhdGVfZGF0YSA8LSByZWFkX3hscyhoZXJlKCJkYXRhIiwgInJhdyIsICJQb3ZlcnR5IiwgImhzdHBvdjIxLnhscyIpLCBza2lwPTIpICNUaGlzIG1heSBjYXVzZSBpbml0aWFsaXphdGlvbiBpc3N1ZSwgbm90IGVhc2lseSByZXByb2R1Y2libGUgKGV2ZW4gYWZ0ZXIgcmVzdGFydGluZyBSKQoKaGVhZChwb3ZlcnR5X3JhdGVfZGF0YSkKYGBgCgpXZSBjYW4gc2VlIHRoYXQgdGhpcyB3aWxsIHJlcXVpcmUgc29tZSB3cmFuZ2xpbmcgdG8gbWFrZSB0aGUgZGF0YSBtb3JlIHVzYWJsZS4gCgojIyAqKlZpb2xlbnQgY3JpbWUqKgoqKioKClZpb2xlbnQgY3JpbWUgZGF0YSB3YXMgb2J0YWluZWQgZnJvbSBbaGVyZV0oaHR0cHM6Ly93d3cudWNyZGF0YXRvb2wuZ292L1NlYXJjaC9DcmltZS9TdGF0ZS9TdGF0ZWJ5U3RhdGUuY2ZtKS4gVGhpcyBkYXRhIGlzIGEgYml0IHRyaWNraWVyIGJlY2F1c2Ugb2Ygc3BhY2VzIGFuZCBgL2AgaW4gdGhlIGNvbHVtbiBuYW1lcywgdGh1cyB0aGUgYHJlYWRfbGluZXMoKWAgZnVuY3Rpb24gb2YgdGhlIGByZWFkcmAgcGFja2FnZSB3b3JrcyBiZXR0ZXIgdGhhbiB0aGUgYHJlYWRfY3N2KClgIGZ1bmN0aW9uLgoKCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlKCJpbWciLCAiY3JpbWUucG5nIikpCmBgYAoKYGBge3J9CmNyaW1lX2RhdGEgPC0gcmVhZF9saW5lcyhoZXJlKCJkYXRhIiwgInJhdyIsICJDcmltZSIsICJDcmltZVN0YXRlYnlTdGF0ZS5jc3YiKSwgc2tpcCA9IDIsIHNraXBfZW1wdHlfcm93cyA9IFRSVUUpCmhlYWQoY3JpbWVfZGF0YSkKCmBgYAoKV2UgY2FuIHNlZSB0aGF0IHRoaXMgZGF0YSB3aWxsIGFsc28gcmVxdWlyZSBzb21lIHdyYW5nbGluZyB0byBtYWtlIGl0IG1vcmUgdXNhYmxlLiAKCiMjICoqUmlnaHQtdG8tY2FycnkgZGF0YSoqCioqKgoKVGhpcyBkYXRhIGlzIGV4dHJhY3RlZCBmcm9tIHRhYmxlIGluIFtEb25vaHVlIHBhcGVyXShodHRwczovL3d3dy5uYmVyLm9yZy9wYXBlcnMvdzIzNTEwLnBkZil7dGFyZ2V0PSJfYmxhbmsifS4gV2Ugd2lsbCB1c2UgdGhlIGZ1bmN0aW9uIGBwZGZfdGV4dCgpYCAgb2YgdGhlIGBwZGZ0b29sc2AgcGFja2FnZSB0byBpbXBvcnQgdGhlIHBkZiBkb2N1bWVudC4KCmBgYHtyfQoKaWYoIWZpbGUuZXhpc3RzKGhlcmUoImRhdGEiLCAicmF3IiwgIncyMzUxMC5wZGYiKSkpewogIHVybCA8LSAiaHR0cHM6Ly93d3cubmJlci5vcmcvcGFwZXJzL3cyMzUxMC5wZGYiCiAgdXRpbHM6OmRvd25sb2FkLmZpbGUodXJsLCBoZXJlKCJkYXRhIiwgInJhdyIsICJ3MjM1MTAucGRmIikpCn0KCkRBV3BhcGVyIDwtIHBkZl90ZXh0KGhlcmUoImRhdGEiLCAicmF3IiwgIncyMzUxMC5wZGYiKSkKCmhlYWQoREFXcGFwZXJbMV0pCgpgYGAKCkFnYWluLCB0aGlzIGRhdGEgd2lsbCBhbHNvIHJlcXVpcmUgcXVpdGUgYSBiaXQgb2Ygd3JhbmdsaW5nLgoKQmVmb3JlIHdlIG1vdmUgb24sIHdlIHdpbGwgc2F2ZSBvdXIgZGF0YSBzbyB0aGF0IHdlIGNhbiBwaWNrIHVwIGZyb20gdGhpcyBwb2ludC4gCgpgYGB7ciwgZXZhbCA9IEZBTFNFfQpzYXZlKGRlbV83N183OSwgZGVtXzgwXzg5LCBkZW1fOTBfOTksIGRlbV8wMF8xMCwgI2RlbW9ncmFwaGljIGRhdGEKICAgICBTVEFURV9GSVBTLCAjIGNvZGVzIGZvciBzdGF0ZXMgCiAgICAgcHNfZGF0YSwgIyBwb2xpY2Ugc3RhZmZpbmcgZGF0YQogICAgIHVlX3JhdGVfZGF0YSwgIyB1bmVtcGxveW1lbnQgZGF0YQogICAgIHBvdmVydHlfcmF0ZV9kYXRhLCAjIHBvdmVydHkgZGF0YQogICAgIGNyaW1lX2RhdGEsICMgY3JpbWUgZGF0YQogICAgIERBV3BhcGVyLCBmaWxlID0gaGVyZSgiZGF0YSIsICJpbXBvcnRlZCIsICJpbXBvcnRlZF9kYXRhLnJkYSIpKQoKYGBgCgoKCiMgKipEYXRhIFdyYW5nbGluZyoqCioqKgoKSWYgeW91IGhhdmUgYmVlbiBmb2xsb3dpbmcgYWxvbmcgYnV0IHN0b3BwZWQuIFlvdSBjYW4gc3RhcnQgaGVyZSBhZ2FpbiB3aXRoIHRoZSBmb2xsb3dpbmcgY29kZToKCmBgYHtyfQpsb2FkKGhlcmU6OmhlcmUoImRhdGEiLCAiaW1wb3J0ZWQiLCAiaW1wb3J0ZWRfZGF0YS5yZGEiKSkKYGBgCgoqKioKPGRldGFpbHM+IDxzdW1tYXJ5PiBJZiB5b3Ugc2tpcHBlZCB0aGUgZGF0YSBpbXBvcnQgc2VjdGlvbiBjbGljayBoZXJlLiA8L3N1bW1hcnk+CgpBbiBSREEgZmlsZSAoc3RhbmRzIGZvciBSIGRhdGEpIG9mIHRoZSBkYXRhIGNhbiBiZSBmb3VuZCBbaGVyZV0oaHR0cHM6Ly9naXRodWIuY29tLy9vcGVuY2FzZXN0dWRpZXMvb2NzLWJwLVJUQy13cmFuZ2xpbmcvdHJlZS9tYXN0ZXIvZGF0YS9pbXBvcnRlZCkgb3Igc2xpZ2h0bHkgbW9yZSBkaXJlY3RseSBbaGVyZV0oaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL29wZW5jYXNlc3R1ZGllcy9vY3MtYnAtUlRDLXdyYW5nbGluZy9tYXN0ZXIvZGF0YS9pbXBvcnRlZC9pbXBvdGVkX2RhdGEucmRhKS4gRG93bmxvYWQgdGhpcyBmaWxlIGFuZCB0aGVuIHBsYWNlIGl0IGluIHlvdXIgY3VycmVudCB3b3JraW5nIGRpcmVjdG9yeSB3aXRoaW4gYSBzdWJkaXJlY3RvcnkgY2FsbGVkICJpbXBvcnRlZCIgd2l0aGluIGEgc3ViZGlyZWN0b3J5IGNhbGxlZCAiZGF0YSIgdG8gY29weSBhbmQgcGFzdGUgb3VyIGNvZGUuIFdlIHVzZWQgYW4gUlN0dWRpbyBwcm9qZWN0IGFuZCB0aGUgW2BoZXJlYCBwYWNrYWdlXShodHRwczovL2dpdGh1Yi5jb20vamVubnliYy9oZXJlX2hlcmUpIHRvIG5hdmlnYXRlIHRvIHRoZSBmaWxlIG1vcmUgZWFzaWx5LiAKCmBgYHtyfQpsb2FkKGhlcmU6OmhlcmUoImRhdGEiLCAiaW1wb3J0ZWQiLCAiaW1wb3J0ZWRfZGF0YS5yZGEiKSkKYGBgCgoKKioqCjxkZXRhaWxzPiA8c3VtbWFyeT4gQ2xpY2sgaGVyZSB0byBzZWUgbW9yZSBhYm91dCBjcmVhdGluZyBuZXcgcHJvamVjdHMgaW4gUlN0dWRpby4gPC9zdW1tYXJ5PgoKWW91IGNhbiBjcmVhdGUgYSBwcm9qZWN0IGJ5IGdvaW5nIHRvIHRoZSBGaWxlIG1lbnUgb2YgUlN0dWRpbyBsaWtlIHNvOgoKCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aD0iNjAlIn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgIk5ld19wcm9qZWN0LnBuZyIpKQpgYGAKCllvdSBjYW4gYWxzbyBkbyBzbyBieSBjbGlja2luZyB0aGUgcHJvamVjdCBidXR0b246CgpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXQud2lkdGg9IjYwJSJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICJwcm9qZWN0X2J1dHRvbi5wbmciKSkKYGBgCgpTZWUgW2hlcmVdKGh0dHBzOi8vc3VwcG9ydC5yc3R1ZGlvLmNvbS9oYy9lbi11cy9hcnRpY2xlcy8yMDA1MjYyMDctVXNpbmctUHJvamVjdHMpIHRvIGxlYXJuIG1vcmUgYWJvdXQgdXNpbmcgUlN0dWRpbyBwcm9qZWN0cyBhbmQgW2hlcmVdKGh0dHBzOi8vZ2l0aHViLmNvbS9qZW5ueWJjL2hlcmVfaGVyZSkgdG8gbGVhcm4gbW9yZSBhYm91dCB0aGUgYGhlcmVgIHBhY2thZ2UuCgo8L2RldGFpbHM+CioqKgo8L2RldGFpbHM+CioqKgoKIyMgKipTdGF0ZSBGSVBTIGNvZGVzKioKKioqCgpMZXQncyBmaXJzdCB0YWtlIGEgbG9vayBhdCBvdXIgc3RhdGUgRklQUyBkYXRhIHRvIHNlZSBpZiBpdCBuZWVkcyBhbnkgY2xlYW5pbmcgb3IgcmVzaGFwaW5nLiBXZSBzaG91bGQgc3RhcnQgd2l0aCB0aGlzIGRhdGEsIGJlY2F1c2Ugd2Ugd2lsbCBuZWVkIHRvIHVzZSBpdCB0byB3cmFuZ2xlIHNvbWUgb2YgdGhlIG90aGVyIGRhdGEuCgpgYGB7cn0KaGVhZChTVEFURV9GSVBTKQpgYGAKCldlIG9ubHkgbmVlZCB0aGUgbGFzdCB0d28gY29sdW1ucywgYnV0IHdlIG1pZ2h0IHdhbnQgdG8gcmVuYW1lIHRoZW0uIFRoZSBgTmFtZWAgdmFyaWFibGUgaXMgdmFndWUuIFRoZSB2YXJpYWJsZSB3aXRoIHRoZSBGSVBTIGNvZGUgaXMgY2FsbGVkIGBTdGF0ZVxuKEZJUFMpYC4gVG8gZ2V0IHJpZCBvZiB0aGUgbmV3IGxpbmUgaW4gdGhpcyB2YXJpYWJsZSBuYW1lIGFuZCB0byBjaGFuZ2UgdGhlIGBOYW1lYCB2YXJpYWJsZSB0byBzb21ldGhpbmcgbW9yZSBpbmZvcm1hdGl2ZSwgd2Ugd2lsbCB1c2UgdGhlIGByZW5hbWUoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZS4gIFRvIHVzZSB0aGlzIGZ1bmN0aW9uLCB3ZSBuZWVkIHRvIGxpc3QgdGhlIG5ldyBuYW1lIGZpcnN0IGZvbGxvd2VkIGJ5IGA9YCBhbmQgdGhlbiB0aGUgZXhpc3RpbmcgdmFyaWFibGUuIFdlIGNhbiByZW5hbWUgbXVsdGlwbGUgdmFyaWFibGVzIGF0IHRoZSBzYW1lIHRpbWUgYnkgdXNpbmcgYSBjb21tYSB0byBzZXBhcmF0ZSB0aGUgdmFyaWFibGVzIHdlIGFyZSByZW5hbWluZy4gV2Ugd2lsbCB1c2UgdGhlIGBzZWxlY3QoKWAgZnVuY3Rpb24gYWxzbyBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlIGp1c3QgdG8ga2VlcCB0aGVzZSB2YXJpYWJsZXMsIGFuZCB3ZSB3aWxsIGZpbHRlciBvdXQgdGhlIHJvd3Mgd2l0aCBGSVBTIHZhbHVlcyBvZiBgMDBgIHdpdGggdGhlIGBmaWx0ZXIoKWAgZnVuY3Rpb24sIGFnYWluIGFsc28gcGFydCBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlLiB3ZSB3aWxsIHNwZWNpZnkgdGhhdCB3ZSB3YW50IGBTVEFURUZQYCB2YWx1ZXMgdGhhdCBhcmUgbm90IGVxdWFsIHRvIGAwMGAgYnkgdXNpbmcgdGhpcyBvcGVyYXRvcjogYCE9YC4gV2Ugd2lsbCBhbHNvIHVzZSB0aGUgZG91YmxlIHBpcGUgb3BlcmF0b3IgYCU8PiVgIG9mIHRoZSBgbWFncml0dHJgIHBhY2thZ2Ugd2hpY2ggYWxsb3dzIHVzIHRvIHVzZSBkYXRhIGFzIGlucHV0IGFuZCB0aGVuIHJlYXNzaWduIGl0IGFmdGVyIHdlIHBlcmZvcm0gc3VtIGZ1bmN0aW9ucyB1c2luZyBpdC4KCmBgYHtyfQoKU1RBVEVfRklQUyAlPD4lIApkcGx5cjo6cmVuYW1lKCBTVEFURUZQID0gYFN0YXRlXG4oRklQUylgLAogICAgICAgICAgICAgICAgIFNUQVRFID0gTmFtZSkgJT4lCiAgICBkcGx5cjo6c2VsZWN0KFNUQVRFRlAsIFNUQVRFKSAlPiUKICAgIGRwbHlyOjpmaWx0ZXIoU1RBVEVGUCAhPSAiMDAiKQoKU1RBVEVfRklQUwoKYGBgCgojIyAqKkRlbW9ncmFwaGljIGFuZCBwb3B1bGF0aW9uIGRhdGEqKgoqKioKCgojIyMgKioxOTc3LTE5NzkqKgoKKioqCgpOb3cgbGV0J3MgdGFrZSBhIGxvb2sgYXQgb3VyIGRlbW9ncmFwaGljIGRhdGEgYWNyb3NzIHRoZSBkZWNhZGVzIHRoYXQgd2Ugd2lzaCB0byBzdHVkeS4gSWYgeW91IGhhdmUgdmVyeSB3aWRlIGRhdGEgKG1lYW5pbmcgaXQgaGFzIG1hbnkgY29sdW1ucyksIG9uZSB3YXkgdG8gdmlldyB0aGUgZGF0YSBzbyB0aGF0IHlvdSBjYW4gc2VlIGFsbCBvZiB0aGUgY29sdW1ucyBhdCB0aGUgc2FtZSB0aW1lIGlzIHRvIHVzZSB0aGUgYGdsaW1wc2UoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZS4gCgpUYWtpbmcgYSBsb29rIGF0IHRoZSBmaXJzdCBkZWNhZGUgb2YgZGF0YSwgd2UgY2FuIHNlZSB0aGF0IHRoZSBgUmFjZS9TZXggSW5kaWNhdG9yYCBjb250YWlucyB0d28gdHlwZXMgb2YgZGF0YSwgdGhlIHJhY2UgYW5kIHRoZSBzZXguIFRoaXMgZG9lcyBub3QgZm9sbG93IHRoZSB0aWR5IGRhdGEgcGhpbG9zb3BoeSwgd2hlcmUgZWFjaCBjZWxsIG9mIGEgdGliYmxlIHNob3VsZCBvbmx5IGNvbnRhaW4gb25lIHBpZWNlIG9mIGluZm9ybWF0aW9uLiBUeXBpY2FsbHkgb25lIG1pZ2h0IHRoaW5rIG9mIHVzaW5nIHRoZSBgc2VwYXJhdGUoKWAgZnVuY3Rpb24gb2YgdGhlIGB0aWR5cmAgcGFja2FnZSB0byBzcGxpdCB0aGlzIHZhcmlhYmxlIGludG8gdHdvLiBIb3dldmVyLCBvbmUgb2YgdGhlIHJhY2UgdmFsdWVzIGlzIGBPdGhlciByYWNlc2AgYW5kIHNpbmNlIHRoaXMgYWxzbyBoYXMgYSBzcGFjZSwgdGhpcyBtYWtlcyBzZXBhcmF0aW5nIHRoaXMgZGF0YSBtb3JlIHRyaWNreS4KCkluc3RlYWQgd2Ugd2lsbCB1c2UgdGhlIGBzdHJfZXh0cmFjdCgpYCBmdW5jdGlvbiBvZiB0aGUgYHN0cmluZ3JgIHBhY2thZ2UgYW5kIHRoZSBgbXV0YXRlKClgIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UuIFRoZSAibXV0YXRlKCkiIHdpbGwgYWxsb3cgdXMgdG8gY3JlYXRlIG5ldyB2YXJpYWJsZXMsIGFuZCAic3RyX2V4dHJhY3QoKSIgZnVuY3Rpb24gIHdpbGwgYWxsb3cgdXMgdG8gbWF0Y2ggc3BlY2lmaWMgcGF0dGVybnMgYW5kIHB1bGwgb3V0IG1hdGNoZXMgdG8gdGhvc2UgcGF0dGVybnMuIFRoZXJlZm9yZSwgaWYgdGhlIGBSYWNlL1NleCBJbmRpY2F0b3JgIHZhbHVlIGlzIGBPdGhlciByYWNlcyBtYWxlYCBhbmQgaWYgd2UgZXh0cmFjdCBwYXR0ZXJucyBtYXRjaGluZyBlaXRoZXIgYCJtYWxlImAgb3IgYCJmZW1hbGUiYCB3aGljaCB3ZSBjYW4gc3BlY2lmeSBsaWtlIHRoaXMgYHBhdHRlcm4gPSAibWFsZXxmZW1hbGUiYCB0aGVuLCB0aGUgdmFsdWUgd2lsbCBiZSBgbWFsZWAuCgpGaXJzdCB3ZSBuZWVkIHRvIHJlbmFtZSB0aGUgYFJhY2UvU2V4IEluZGljYXRvcmAgdmFyaWFibGUgdG8gbm90IGhhdmUgc3BhY2VzIHNvIHRoYXQgaXQgaXMgY29tcGF0aWJsZSB3aXRoIHRoZSBgc3RyX2V4dHJhY3QoKWAgZnVuY3Rpb24uCgpXZSBhbHNvIHdhbnQgdG8gcmVuYW1lIGEgY291cGxlIG9mIHZhcmlhYmxlcyB0byBiZSBzaW1wbGVyIGFuZCBmaWx0ZXIgdGhlIGRhdGEgdG8gb25seSBpbmNsdWRlIHRoZSB5ZWFycyBvZiB0aGUgZGF0YSB3ZSBhcmUgaW50ZXJlc3RlZCBpbiwgYXMgd2VsbCBhcyByZW1vdmUgc29tZSB2YXJpYWJsZXMgdGhhdCB3ZSBkb24ndCBuZWVkIGxpa2UgdGhlIGBGSVBTIFN0YXRlIENvZGVgLiBXZSBjYW4gcmVtb3ZlIHZhcmlhYmxlcyBieSB1c2luZyB0aGUgYHNlbGVjdCgpYCBmdW5jdGlvbiB3aXRoIGEgYC1gIG1pbnVzIHNpZ24gaW4gZnJvbnQgb2YgdGhlIHZhcmlhYmxlIHdlIHdpc2ggdG8gcmVtb3ZlLgoKYGBge3J9CmRwbHlyOjpnbGltcHNlKGRlbV83N183OSkKCgpkZW1fNzdfNzkgPC0gZGVtXzc3Xzc5ICU+JQogIHJlbmFtZSgicmFjZV9zZXgiID1gUmFjZS9TZXggSW5kaWNhdG9yYCkgJT4lCiAgbXV0YXRlKFNFWCA9IHN0cl9leHRyYWN0KHJhY2Vfc2V4LCAibWFsZXxmZW1hbGUiKSwKICAgICAgICBSQUNFID0gc3RyX2V4dHJhY3QocmFjZV9zZXgsICJCbGFja3xXaGl0ZXxPdGhlciIpKSU+JQogIHNlbGVjdCgtYEZJUFMgU3RhdGUgQ29kZWAsIC1gcmFjZV9zZXhgKSAlPiUKICByZW5hbWUoIllFQVIiID0gYFllYXIgb2YgRXN0aW1hdGVgLAogICAgICAgICJTVEFURSIgPSBgU3RhdGUgTmFtZWApICU+JQogIGZpbHRlcihZRUFSICVpbiUgMTk3NzoxOTc5KQoKZ2xpbXBzZShkZW1fNzdfNzkpCmBgYAoKVGhhdCdzIGxvb2tpbmcgcHJldHR5ICBnb29kISBXZSBhbHNvIHdhbnQgdG8gdGFrZSBhbGwgdGhlIGFnZSBncm91cCB2YXJpYWJsZXMgYW5kIG1ha2Ugb25lIHZhcmlhYmxlIHRoYXQgaXMgdGhlIGFnZSBncm91cCBuYW1lIGFuZCBvbmUgdGhhdCBpcyB0aGUgdmFsdWUgb2YgdGhlIHBvcHVsYXRpb24gY291bnQgZm9yIHRoYXQgYWdlIGdyb3VwLiBUbyBkbyB0aGlzIHdlIHdpbGwgdXNlIHRoZSBgcGl2b3RfbG9uZ2VyKClgIGZ1bmN0aW9uIG9mIHRoZSBgdGlkeXJgIHBhY2thZ2UuIFRvIHVzZSB0aGlzIGZ1bmN0aW9uLCB3ZSBuZWVkIHRvIHVzZSB0aGUgYGNvbHNgIGFyZ3VtZW50IHRvIGluZGljYXRlIHdoaWNoIGNvbHVtbnMgd2Ugd2FudCB0byBwaXZvdC4gV2UgYWxzbyBuYW1lIHRoZSBuZXcgdmFyaWFibGVzIHdlIHdpbGwgY3JlYXRlIHdpdGggdGhlIGBuYW1lc190b2AgYW5kIGB2YWx1ZXNfdG9gIGFyZ3VtZW50cy4gVGhlIGBuYW1lc190b2Agd2lsbCBiZSB0aGUgbmFtZSBvZiB0aGUgdmFyaWFibGUgdGhhdCB3aWxsIGlkZW50aWZ5IGVhY2ggYWdlIGdyb3VwIGFuZCBgdmFsdWVzX3RvYCB3aWxsIGJlIHRoZSBuYW1lIG9mIHRoZSB2YXJpYWJsZSB0aGF0IGNvbnRhaW5zIHRoZSBjb3JyZXNwb25kaW5nIHBvcHVsYXRpb24gdmFsdWVzLgoKYGBge3J9CmRlbV83N183OSA8LSBkZW1fNzdfNzkgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHM9Y29udGFpbnMoInllYXJzIiksCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gIkFHRV9HUk9VUCIsCiAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJTVUJfUE9QIikKCmdsaW1wc2UoZGVtXzc3Xzc5KQpgYGAKCldlIGFsc28gd2FudCB0byBnZXQgZGF0YSBhYm91dCB0aGUgdG90YWwgcG9wdWxhdGlvbiBmb3IgdGhlIHN0YXRlIGZvciBlYWNoIHllYXIuCgpUbyBkbyBzbyB3ZSBjYW4gc3VtIGFsbCB0aGUgdmFsdWVzIGZvciB0aGUgYFNVQl9QT1BgIHZhcmlhYmxlIHRoYXQgd2UganVzdCBjcmVhdGVkLiBUbyBkbyB0aGlzIHdlIGNhbiB1c2UgdGhlIGBncm91cF9ieWAgYW5kIGBzdW1tYXJpemUoKWAgZnVuY3Rpb25zIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UuIFRoZSBgZ3JvdXBfYnkoKWAgZnVuY3Rpb24gc3BlY2lmaWVzIGhvdyB3ZSB3YW50IHRvIGNhbGN1bGF0ZSAgb3VyIHN1bSwgdGhhdCB3ZSB3b3VsZCBsaWtlIHRvIGNhbGN1bGF0ZSBpdCBmb3IgZWFjaCB5ZWFyIGFuZCBlYWNoIHN0YXRlIGluZGl2aWR1YWxseS4gVGh1cywgYWxsIHRoZSB2YWx1ZXMgdGhhdCBoYXZlIHRoZSBzYW1lIGBTVEFURWAgYW5kIGBZRUFSYCB2YWx1ZXMgd2lsbCBiZSBzdW1tZWQgdG9nZXRoZXIsIHJhdGhlciB0aGFuIHN1bW1pbmcgdXNpbmcgYWxsIG9mIHRoZSB2YWx1ZXMgaW4gdGhlIGBTVUJfUE9QYCB2YXJpYWJsZS4gVGhlIGAuZ3JvdXBzYCBhcmd1bWVudCBhbGxvd3MgdXMgdG8gcmVtb3ZlIHRoZSBncm91cGluZyBhZnRlciB3ZSBwZXJmb3JtIHRoZSBjYWxjdWxhdGlvbiB3aXRoIGBzdW1tYXJpemUoKWAuCgpgYGB7cn0KcG9wXzc3Xzc5IDwtIGRlbV83N183OSAlPiUKICBncm91cF9ieShZRUFSLCBTVEFURSkgJT4lCiAgc3VtbWFyaXplKCJUT1RfUE9QIiA9IHN1bShTVUJfUE9QKSwgLmdyb3VwcyA9ICJkcm9wIikgCgpwb3BfNzdfNzkgCmBgYAoKCiBOb3cgd2Ugd2lsbCBhZGQgdGhlIHBvcHVsYXRpb24gdmFsdWUgdG8gdGhlIGRlbW9ncmFwaGljIHRpYmJsZSB1c2luZyB0aGUgYGxlZnRfam9pbigpYCBmdW5jdGlvbiBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlLiBJdCBpcyBpbXBvcnRhbnQgdGhhdCB3ZSBzcGVjaWZ5IGhvdyB0aGlzIHNob3VsZCBiZSBkb25lLCB0aGF0IHRoZSBgWUVBUmAgYW5kIGBTVEFURWAgdmFyaWFibGUgdmFsdWVzIHNob3VsZCBtYXRjaCBlYWNoIG90aGVyLiBUaGlzIHdpbGwgcGxhY2UgdGhlIGBkZW1fNzdfNzlgIHZhcmlhYmxlcyB0byB0aGUgbGVmdCBvZiB0aGUgYHBvcF83N183OWAgZGF0YS4gCiAKYGBge3J9CmRlbV83N183OSA8LSBkZW1fNzdfNzkgJT4lCiAgbGVmdF9qb2luKHBvcF83N183OSwgYnkgPSBjKCJZRUFSIiwiU1RBVEUiKSkKCmRlbV83N183OQpgYGAKCldlIHdpbGwgYWxzbyBjYWxjdWxhdGUgdGhlIHBlcmNlbnRhZ2UgdGhhdCBlYWNoIGdyb3VwIG1ha2VzIHVwIG9mIHRoZSB0b3RhbCBwb3B1bGF0aW9uLCBieSBkaXZpZGluZyB0aGUgYFNVQl9QT1BgIGJ5IHRoZSBgVE9UX1BPUGAgYW5kIG11bHRpcGx5aW5nIGJ5IDEwMCB1c2luZyB0aGUgYG11dGF0ZSgpYCBmdW5jdGlvbi4gd2Ugd2lsbCBhbHNvIHJlbW92ZSB0aGUgb3RoZXIgcG9wdWxhdGlvbiB2YXJpYWJsZXMuCgpgYGB7cn0KZGVtXzc3Xzc5ICU8PiUKICBtdXRhdGUoUEVSQ19TVUJfUE9QID0gKFNVQl9QT1AvVE9UX1BPUCkqMTAwKSAlPiUKICBzZWxlY3QoLVNVQl9QT1AsIC1UT1RfUE9QKQoKZGVtXzc3Xzc5CmBgYAoKSXQgaXMgaW1wb3J0YW50IHRvIG1ha2Ugc3VyZSB0aGF0IHdlIGhhdmUgdGhlIHRvdGFsIHZhbHVlcyB3ZSB3b3VsZCBleHBlY3QuIFdlIGhhdmUgdHdvIGxldmVscyBvZiBgU0VYYCwgdGhyZWUgbGV2ZWxzIG9mIGBSYWNlYCwgdGhyZWUgbGV2ZWxzIG9mIGBZRUFSYCwgZWlnaHRlZW4gbGV2ZWxzIG9mIGBBR0VfR1JPVVBgLCBhbmQgZmlmdHkgb25lIGxldmVscyBvZiBgU1RBVEVgLiBJZiB3ZSBtdWx0aXBseSB0aGlzIHRvZ2V0aGVyIHdlIGdldCAxNiw1MjQgd2hpY2ggaXMgdGhlIHNhbWUgYXMgdGhlIG51bWJlciBvZiByb3dzIGluIG91ciBmaW5hbCBgZGVtXzc3Xzc5YCBkYXRhLiBMb29rcyBnb29kIQoKQWxzbyBMZXQncyBtYWtlIHRoZSB2YWx1ZXMgb2YgdGhlIGBTRVhgIHZhcmlhYmxlIGNhcGl0YWxpemVkIHNvIHRoYXQgdGhleSBtYXRjaCB0aGUgb3RoZXIgdmFsdWVzIG9mIHRoZSBvdGhlciB2YXJpYWJsZXMgbGlrZSBgUkFDRWAgZXRjLiBUaGlzIHdpbGwgaGVscCB1cyB0byBrZWVwIGNvbnNpc3RlbnQgdmFsdWVzIGFjcm9zcyB0aGUgZGlmZmVyZW50IHllYXJzIGFzIHdlIHdyYW5nbGUgdGhlIGRhdGEgZm9yIHRoZSBvdGhlciBkZWNhZGVzLiBUbyBkbyBzbyB3ZSB3aWxsIHVzZSB0aGUgYHN0cl90b190aXRsZSgpYCBmdW5jdGlvbiBvZiB0aGUgYHN0cmluZ3JgIHBhY2thZ2UuIFdlIG5lZWQgdG8gdXNlIHRoZSBgcHVsbCgpYCBmdW5jdGlvbiB0byBnZXQgdGhlIHZhbHVlcyBvZiBgU0VYYCBvdXQgb2YgYGRlbV83N183OWAuIE9uY2Ugd2UgbWFrZSB0aGVtIGNhcGl0YWxpemVkIHRoZXkgYXJlIHRoZW4gcmVhc3NpZ25lZCB0byB0aGUgYFNFWGAgdmFyaWFibGUuIAoKYGBge3J9CgpkZW1fNzdfNzkgJTw+JQogIG11dGF0ZShTRVggPSBzdHJfdG9fdGl0bGUocHVsbChkZW1fNzdfNzksIFNFWCkpKQoKIyBUaGlzIGNhbiBhbHNvIGJlIGRvbmUgbGluZSB0aGlzOgpkZW1fNzdfNzkgJTw+JQogIG11dGF0ZShTRVggPSBzdHJfdG9fdGl0bGUocHVsbCguLCBTRVgpKSkKYGBgCgojIyMgKioxOTgwLTE5ODkqKgoKKioqCgoKRm9yIHRoaXMgZGVjYWRlIGVhY2ggeWVhciBpcyBhIHNlcGFyYXRlIHRpYmJsZSBhbmQgdGhleSBhcmUgY29tYmluZWQgYXMgYSBsaXN0LgpgYGB7cn0KY2xhc3MoZGVtXzgwXzg5KQpgYGAKClNvIHRoZSBmaXJzdCB0aGluZyB3ZSBuZWVkIHRvIGRvIGlzIGNvbWJpbmUgZWFjaCB0aWJibGUgb2YgdGhlIGxpc3QgdG9nZXRoZXIuIFdlIGNhbiBkbyB0aGF0IHVzaW5nIHRoZSBgYmluZF9yb3dzKClgIGZ1bmN0aW9uIG9mIGBkcGx5cmAgd2hpY2ggYXBwZW5kcyB0aGUgZGF0YSB0b2dldGhlciBiYXNlZCBvbiB0aGUgcHJlc2VuY2Ugb2YgY29sdW1ucyB3aXRoIHRoZSBzYW1lIG5hbWUgaW4gdGhlIGRpZmZlcmVudCB0aWJibGVzLiBXZSB3aWxsIHVzZSB0aGUgYG1hcF9kZigpYCBmdW5jdGlvbiBvZiB0aGUgYHB1cnJyYCBwYWNrYWdlIHRvIGFsbG93IHVzIHRvIGRvIHRoaXMgYWNyb3NzIGVhY2ggdGliYmxlIGluIG91ciBsaXN0LiAKCmBgYHtyfQpkZW1fODBfODkgPC0gZGVtXzgwXzg5ICU+JQogIG1hcF9kZihiaW5kX3Jvd3MpCgpnbGltcHNlKGRlbV84MF84OSApCmBgYAoKR3JlYXQhIE5vdyBvdXIgZGF0YSBpcyBhbGwgdG9nZXRoZXIuCgpOb3cgd2Ugd2lsbCB3cmFuZ2xlIHRoZSBkYXRhIHNpbWlsYXJseSB0byB0aGUgcHJldmlvdXMgZGVjYWRlLgpgYGB7cn0KZGVtXzgwXzg5IDwtIGRlbV84MF84OSAlPiUKICByZW5hbWUoInJhY2Vfc2V4IiA9YFJhY2UvU2V4IEluZGljYXRvcmApICU+JQogIG11dGF0ZShTRVggPSBzdHJfZXh0cmFjdChyYWNlX3NleCwgIm1hbGV8ZmVtYWxlIiksCiAgICAgICAgUkFDRSA9IHN0cl9leHRyYWN0KHJhY2Vfc2V4LCAiQmxhY2t8V2hpdGV8T3RoZXIiKSklPiUKICBzZWxlY3QoIC1gcmFjZV9zZXhgKSAlPiUKICByZW5hbWUoIllFQVIiID0gYFllYXIgb2YgRXN0aW1hdGVgKQogICAgICAgICAKZ2xpbXBzZShkZW1fODBfODkpCmBgYApOb3RpY2UgdGhhdCB0aGlzIHRpbWUgdGhlIHN0YXRlIGluZm9ybWF0aW9uIGlzIGJhc2VkIG9uIHRoZSBudW1lcmljIEZJUFMgdmFsdWUuIFdlIHdhbnQgb25seSB0aGUgZmlyc3QgdHdvIHZhbHVlcywgYXMgdGhlIHJlc3QgaW5kaWNhdGUgdGhlIGNvdW50eS4gV2UgY2FuIHVzZSB0aGUgYHN0cl9zdWIoKWAgZnVuY3Rpb24gb2YgdGhlIGBzdHJpbmdyYCBwYWNrYWdlIGZvciB0aGlzLiBXZSB3aWxsIHNwZWNpZnkgdGhhdCB3ZSB3YW50IHRvIHN0YXJ0IGF0IHRoZSBmaXJzdCBwb3NpdGlvbiBhbmQgZW5kIGF0IHRoZSBzZWNvbmQuICBKdXN0IGxpa2UgYHN0cl9leHRyYWN0KClgIHdlIG5lZWQgdG8gcmVuYW1lIHRoaXMgdmFyaWFibGUgZmlyc3Qgc28gdGhhdCBpdCBpcyBjb21wYXRpYmxlLiAKYGBge3J9CmRlbV84MF84OSAlPD4lCnJlbmFtZSgiU1RBVEVGUF90ZW1wIiA9ICJGSVBTIFN0YXRlIGFuZCBDb3VudHkgQ29kZXMiKSAlPiUKbXV0YXRlKFNUQVRFRlAgPSBzdHJfc3ViKFNUQVRFRlBfdGVtcCwgc3RhcnQgPSAxLCBlbmQgPSAyKSkgJT4lCiAgICBsZWZ0X2pvaW4oU1RBVEVfRklQUywgYnkgPSAiU1RBVEVGUCIpICU+JQogIGRwbHlyOjpzZWxlY3QoLVNUQVRFRlApCgpnbGltcHNlKGRlbV84MF84OSkKYGBgCgoKYGBge3J9CmRlbV84MF84OSAlPD4lCiAgcGl2b3RfbG9uZ2VyKGNvbHM9Y29udGFpbnMoInllYXJzIiksCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gIkFHRV9HUk9VUCIsCiAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJTVUJfUE9QX3RlbXAiKSAlPiUKICBncm91cF9ieShZRUFSLCBTVEFURSwgQUdFX0dST1VQLCBTRVgsIFJBQ0UpICU+JQogIHN1bW1hcml6ZShTVUJfUE9QID0gc3VtKFNVQl9QT1BfdGVtcCksIC5ncm91cHM9ImRyb3AiKQoKZGVtXzgwXzg5CmBgYAogIApgYGB7cn0KcG9wXzgwXzg5IDwtIGRlbV84MF84OSAlPiUKICBncm91cF9ieShZRUFSLCBTVEFURSkgJT4lCiAgc3VtbWFyaXplKCJUT1RfUE9QIiA9IHN1bShTVUJfUE9QKSwgLmdyb3VwcyA9ICJkcm9wIikgCgoKZGVtXzgwXzg5IDwtIGRlbV84MF84OSAlPiUKICBsZWZ0X2pvaW4ocG9wXzgwXzg5LCBieSA9IGMoIllFQVIiLCJTVEFURSIpKSAlPiUKICBtdXRhdGUoUEVSQ19TVUJfUE9QID0gKFNVQl9QT1AvVE9UX1BPUCkqMTAwKSAlPiUKICBkcGx5cjo6c2VsZWN0KC1TVUJfUE9QLCAtVE9UX1BPUCkKCmRlbV84MF84OQpgYGAKCkp1c3QgbGlrZSB3aXRoIHRoZSBkYXRhIGZyb20gdGhlIDcwcyB3ZSB3aWxsIGFsc28gY2hhbmdlIHRoZSB2YWx1ZXMgZm9yIGBTRVhgIHRvIGJlIGNhcGl0YWxpemVkLgoKYGBge3J9CmRlbV84MF84OSAlPD4lCiAgbXV0YXRlKFNFWCA9IHN0cl90b190aXRsZShwdWxsKC4sIFNFWCkpKQpgYGAKCkFnYWluLCBpdCBpcyBpbXBvcnRhbnQgdG8gbWFrZSBzdXJlIHRoYXQgd2UgaGF2ZSB0aGUgdG90YWwgdmFsdWVzIHdlIHdvdWxkIGV4cGVjdC4gVGhpcyB0aW1lIHdlIGhhdmU6IHR3byBsZXZlbHMgb2YgYFNFWGAsIHRocmVlIGxldmVscyBvZiBgUmFjZWAsIHRlbiBsZXZlbHMgb2YgYFlFQVJgLCBlaWdodGVlbiBsZXZlbHMgb2YgYEFHRV9HUk9VUGAsIGFuZCBmaWZ0eSBvbmUgbGV2ZWxzIG9mIGBTVEFURWAuCgpJZiB3ZSBtdWx0aXBseSB0aGVzZSB0b2dldGhlciB3ZSBnZXQgNTUsMDgwLCB3aGljaCBpcyB0aGUgc2FtZSBhcyB0aGUgbnVtYmVyIG9mIHJvd3Mgb2YgdGhlIGZpbmFsIGBkZW1fODBfODlgIGRhdGEuIExvb2tzIGdvb2QhCgojIyMgKioxOTkwLTE5OTkqKgoKKioqCgpKdXN0IGxpa2UgdGhlIDgwcyB3ZSBuZWVkIHRvIGNvbWJpbmUgdGhlIGRhdGEgYWNyb3NzIHRoZSBmaWxlczoKCmBgYHtyfQpkZW1fOTBfOTkgPC0gZGVtXzkwXzk5ICU+JQogIG1hcF9kZihiaW5kX3Jvd3MpCmBgYAoKYGBge3J9CmdsaW1wc2UoZGVtXzkwXzk5KQpgYGAKRm9yIHRoaXMgZGVjYWRlIHRoZSBjb2x1bW4gbmFtZXMgY2FuJ3QgYWxsIGJlIGltcG9ydGVkIGluIGEgc2ltcGxlIHdheSBmcm9tIHRoZSB0YWJsZSwgc28gdGhleSBuZWVkIHRvIGJlIHJlY29kZWQuCgpIZXJlIGlzIHdoYXQgdGhlIGRhdGEgbG9va3MgbGlrZSBiZWZvcmUgaW1wb3J0aW5nOgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoID0gIjgwMCBweCJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltZyIsICI5MC5wbmciKSkKYGBgCgpTbywgZmlyc3QgdXNpbmcgdGhlIGJhc2UgYGNvbG5hbWVzKClgIGZ1bmN0aW9uIHdlIGNoYW5nZSB0aGUgbmFtZXMgb2YgdGhlIGNvbHVtbiBuYW1lcy4KCmBgYHtyfQoKY29sbmFtZXMoZGVtXzkwXzk5KSA8LSBjKCJZRUFSIiwKICAgICAgICAgICAgICAgICAgICAgICAgICJTVEFURUZQIiwKICAgICAgICAgICAgICAgICAgICAgICAgICJBZ2UiLAogICAgICAgICAgICAgICAgICAgICAgICAgIk5IX1dfTSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAiTkhfV19GIiwKICAgICAgICAgICAgICAgICAgICAgICAgICJOSF9CX00iLAogICAgICAgICAgICAgICAgICAgICAgICAgIk5IX0JfRiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAiTkhfQUlBTl9NIiwKICAgICAgICAgICAgICAgICAgICAgICAgICJOSF9BSUFOX0YiLAogICAgICAgICAgICAgICAgICAgICAgICAgIk5IX0FQSV9NIiwKICAgICAgICAgICAgICAgICAgICAgICAgICJOSF9BUElfRiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAiSF9XX00iLAogICAgICAgICAgICAgICAgICAgICAgICAgIkhfV19GIiwKICAgICAgICAgICAgICAgICAgICAgICAgICJIX0JfTSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAiSF9CX0YiLAogICAgICAgICAgICAgICAgICAgICAgICAgIkhfQUlBTl9NIiwKICAgICAgICAgICAgICAgICAgICAgICAgICJIX0FJQU5fRiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAiSF9BUElfTSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAiSF9BUElfRiIpCgpnbGltcHNlKGRlbV85MF85OSkKYGBgCgpOb3RpY2UgYWxzbyB0aGF0IHRoZSBmaXJzdCByb3cgaXMgYWxsIGBOQWAgdmFsdWVzIGZyb20gd2hpdGUgc3BhY2UgaW4gdGhlIG9yaWdpbmFsIHRhYmxlIGZvciAxOTkwLCB0aGlzIGlzIHByb2JhYmx5IHRydWUgZm9yIGVhY2ggeWVhci4gV2UgY2FuIGNoZWNrIHRoZW0gZGltZW5zaW9ucyBvZiBvdXIgdGFibGUgdXNpbmcgdGhlIGJhc2UgYGRpbSgpYCBmdW5jdGlvbi4gV2hlbiB3ZSBmaWx0ZXIgZm9yIHJvd3Mgd2hlcmUgYFlFQVJgIGlzIGBOQWAsIHdlIGluZGVlZCBzZWUgMTAgcm93cywgd2hpY2ggaXMgd2hhdCB3ZSB3b3VsZCBleHBlY3QgaWYgd2UgaGF2ZSBhIHJvdyBsaWtlIHRoaXMgZm9yIGVhY2ggb2YgdGhlIHllYXJzIGluIHRoZSBkZWNhZGUuIFdlIHNlZSB0aGUgc2FtZSBpZiB3ZSB0cnkgYSBkaWZmZXJlbnQgdmFyaWFibGUuIE5vdyB3ZSB3aWxsIHRlc3QgdG8gc2VlIGhvdyBsYXJnZSBvdXIgdGliYmxlIGlzIGlmIHdlIGRyb3Agcm93cyB3aXRoIGBOQWAgdmFsdWVzIHVzaW5nIHRoZSBgZHJvcF9uYSgpYCBmdW5jdGlvbiBvZiBgdGlkeXJgLiBXZSB0aGF0IGluZGVlZCBvdXIgZGltZW5zaW9ucyBvbmx5IGNoYW5nZWQgYnkgdGVuLCBzbyB0aGVyZSBhcmUgbm90IG90aGVyIHJvd3Mgd2l0aCBtaXNzaW5nIHZhbHVlcyB0aGF0IHdlIG1pZ2h0IG5vdCBleHBlY3QuIFNvIG5vdyB3ZSB3aWxsIHJlc2lnbiB0aGUgYGRlbV85MF85OWAgdmFyaWFibGUgYWZ0ZXIgcmVtb3ZpbmcgdGhlc2Ugcm93cy4KCmBgYHtyfQoKZGltKGRlbV85MF85OSkKCmRlbV85MF85OSAlPiUKICBmaWx0ZXIoaXMubmEoWUVBUikpCgpkZW1fOTBfOTkgJT4lCiAgZmlsdGVyKGlzLm5hKEFnZSkpIAoKZGVtXzkwXzk5ICU+JWRyb3BfbmEoKSAKCmRlbV85MF85OSAlPD4lZHJvcF9uYSgpIApgYGAKClRoZW4gd2Ugc3VtIGFjcm9zcyB0aGUgbm9uLWhpc3BhbmljIGFuZCBIaXNwYW5pYyBncm91cHMgYmVjYXVzZSB0aGlzIGluZm9ybWF0aW9uIGlzIG5vdCBhdmFpbGFibGUgZm9yIHRoZSBvdGhlciBwcmV2aW91cyBkZWNhZGVzLiBUaGVuIHdlIHdpbGwgcmVtb3ZlIHRoZSB2YXJpYWJsZXMgZm9yIHRoZSBIaXNwYW5pYyBhbmQgbm9uLUhpc3BhbmljIHN1Ymdyb3VwcyB1c2luZyBgc2VsZWN0KClgLgoKYGBge3J9CgpkZW1fOTBfOTklPD4lCiAgICBtdXRhdGUoV19NID0gTkhfV19NICsgSF9XX00sCiAgICAgICAgICAgV19GID0gTkhfV19GICsgSF9XX0YsCiAgICAgICAgICAgQl9NID0gTkhfQl9NICsgSF9CX00sCiAgICAgICAgICAgQl9GID0gTkhfQl9GICsgSF9CX0YsCiAgICAgICAgICAgQUlBTl9NID0gTkhfQUlBTl9NICsgSF9BSUFOX00sCiAgICAgICAgICAgQUlBTl9GID0gTkhfQUlBTl9GICsgSF9BSUFOX0YsCiAgICAgICAgICAgQVBJX00gPSBOSF9BUElfTSArIEhfQVBJX00sCiAgICAgICAgICAgQVBJX0YgPSBOSF9BUElfRiArIEhfQVBJX0YpICU+JQogIHNlbGVjdCgtc3RhcnRzX3dpdGgoIk5IXyIpLCAtc3RhcnRzX3dpdGgoIkhfIikpCgpnbGltcHNlKGRlbV85MF85OSkKYGBgCgpMb29raW5nIGJldHRlciEgV2UgYWxzbyBuZWVkIHRvIGFkZCBhZ2UgZ3JvdXBzIGxpa2UgdGhlIG90aGVyIGRlY2FkZXMuIFdlIHdpbGwgdGFrZSBhIGxvb2sgYXQgdGhlIDgwcyBkYXRhIHVzaW5nIHRoZSBgZGlzdGluY3QoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZSB0byBzZWUgd2hhdCBhZ2UgZ3JvdXBzIHdlIG5lZWQuIFdlIGNhbiB1c2UgdGhlIGJhc2UgYGN1dCgpYCBmdW5jdGlvbiB0byBjcmVhdGUgYSBuZXcgdmFyaWFibGUgd2l0aCBgbXV0YXRlKClgIGNhbGxlZCBgQUdFX0dST1VQYCB0aGF0IHdpbGwgaGF2ZSBhIGxhYmVsIGZvciBldmVyeSBjaGFuZ2UgaW4gNSB5ZWFycyBvZiBhZ2UuIFRoZSBgcmlnaHQgPSBGQUxTRWAgYXJndW1lbnQgc3BlY2lmaWVzIHRoYXQgdGhlIGludGVydmFsIGlzIG5vdCBjbG9zZWQgb24gdGhlIHJpZ2h0LCBtZWFuaW5nIHRoYXQgaWYgdGhlIHZhbHVlIGlzIGF0IHRoZSBjdXQgcG9pbnQgbGlrZSB0aGUgYEFnZWAgdmFsdWUgaXMgNSwgdGhlbiBpdCB3aWxsIGJlIGluIHRoZSBgNSB0byA5IHllYXJzYCBncm91cC4KCldlIGNhbiBtYWtlIHRoZSBsYWJlbHMgZm9yIHRoZSBgQUdFX0dST1VQYCB2YXJpYWJsZSBtYXRjaCB0aG9zZSBvZiBgZGVtXzc3Xzc5YCBidXQgd2UgbmVlZCB0byBwdWxsIG91dCB0aGUgdmFsdWVzIG9mIHRoZSB0aWJibGUgY3JlYXRlZCBieSBgZGlzdGluY3QoKWAuIFRvIGRvIHRoaXMgd2UgY2FuIHVzZSB0aGUgYHB1bGwoKWAgZnVuY3Rpb24gZnJvbSB0aGUgYGRwbHlyYCBwYWNrYWdlLiBOb3RlIHRoYXQgaXQgaXMgaW1wb3J0YW50IHRvIGNoZWNrIHRoYXQgdGhlIGBBR0VfR1JPVVBgIHZhbHVlcyBhcmUgbGlzdGVkIGluIG9yZGVyIGZvciBgZGVtXzc3Xzc5YC4gV2Ugd2lsbCBhbHNvIHJlbW92ZSB0aGUgYEFnZWAgdmFyaWFibGUgYWZ0ZXIgd2UgY3JlYXRlIHRoZSBuZXcgYEFHRV9HUk9VUGAgdmFyaWFibGUgZm9yIHRoZSBgZGVtXzkwXzk5YCBkYXRhLiAKCgpgYGB7cn0KCmRpc3RpbmN0KGRlbV83N183OSwgQUdFX0dST1VQKQpwdWxsKGRpc3RpbmN0KGRlbV83N183OSwgQUdFX0dST1VQKSkKCmRlbV85MF85OSAlPD4lCiAgbXV0YXRlKEFHRV9HUk9VUCA9IGN1dChBZ2UsCiAgICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzZXEoMCw5MCwgYnk9NSksCiAgICAgICAgICAgICAgICAgICAgICAgICByaWdodCA9IEZBTFNFLCBsYWJlbHMgPSBwdWxsKGRpc3RpbmN0KGRlbV83N183OSxBR0VfR1JPVVApLCBBR0VfR1JPVVApKSkgJT4lCiAgc2VsZWN0KC1BZ2UpCgpnbGltcHNlKGRlbV85MF85OSkKCmBgYAoKTGlrZSB0aGUgcHJldmlvdXMgZGVjYWRlcyB3ZSB3aWxsIGNyZWF0ZSBhIGBSQUNFYCBhbmQgYFNVQl9QT1BgIHZhcmlhYmxlIHVzaW5nIGBwaXZvdF9sb25nZXIoKWAgdG8gY3JlYXRlIGEgc2luZ2xlIGBSYWNlYCB2YXJpYWJsZSBvdXQgb2YgYWxsIHRoZSBzdWJncm91cCB2YXJpYWJsZXMuIAoKTm93IHdlIG5lZWQgdG8gY29sbGFwc2UgdGhlIGRhdGEgZm9yIHRoZSB2YXJpb3VzIHJhY2VzIHNvIHRoYXQgaXQgbWF0Y2hlcyB0aGUgcHJldmlvdXMgZGVjYWRlcy4gVGhpcyB0aW1lIHdlIHdpbGwgdXNlIHRoZSBgY2FzZV93aGVuKClgIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UgYW5kIHRoZSBgc3RyX2RldGVjdCgpYCBmdW5jdGlvbiBvZiB0aGUgYHN0cmluZ3JgIHBhY2thZ2UgdG8gaWRlbnRpZnkgd2hlbiB0aGUgcmFjZSBpcyBzb21ldGhpbmcgb3RoZXIgdGhhbiBgQmAgb3IgYFdgIGFuZCByZXBsYWNlIHdpdGggdGhlIHZhbHVlIGBPdGhlcmAuIFRoZSB2YWx1ZSB0byB0aGUgcmlnaHQgb2YgdGhlIGB+YCBpbmRpY2F0ZXMgd2hhdCB3ZSB3YW50IHRoZSB2YWx1ZSBvZiB0aGUgbmV3IHZhcmlhYmxlIHRvIGJlIGlmIHRoZSB2YWx1ZSBvZiB0aGUgdmFyaWFibGUgd2UgYXJlIHVzaW5nIHdpdGggYHN0cl9kZWNlY3QoKWAgbWF0Y2hlcyB0aGUgY29uZGl0aW9uIHNwZWNpZmllZC4gSWYgdGhlIHZhbHVlIGRvZXMgbm90IG1hdGNoIHRoZSBzcGVjaWZpZWQgY29uZGl0aW9uLCB0aGFuIHRoZSBvdGhlciB2YWx1ZXMgd2lsbCBiZSB3aGF0IGV2ZXIgaXMgbGlzdGVkIGFmdGVyIGBUUlVFIH5gLiBXZSB3aWxsIHRoZW4gY3JlYXRlIHBvcHVsYXRpb24gY291bnRzIGFzIHdlIGRpZCBwcmV2aW91c2x5IGZvciB0aGUgb3RoZXIgZGVjYWRlcy4KCkZpbmFsbHksIHdlIHdpbGwgY3JlYXRlIG5ldyBzdW1zIGZvciB0aGUgc3ViLXBvcHVsYXRpb25zIHdoZXJlIHdlIHN1bSBhY3Jvc3MgdGhlIHR3byBgT3RoZXJgIHN1Ymdyb3VwcyBgUmFjZWAgIHRvIGEgY3JlYXRlIGEgc2luZ2xlIHZhbHVlIGZvciBlYWNoIHZhbHVlIG9mIGBZRUFSYCwgYFNFWGAsIGBBR0VfR1JPVVBgLCBhbmQgYFNUQVRFYCBieSB1c2luZyB0aGUgYGdyb3VwX2J5KClgIGZ1bmN0aW9uIGFuZCBgc3VtbWFyaWUoKWAuICAKCmBgYHtyfQpkZW1fOTBfOTkgICU8PiUKICBwaXZvdF9sb25nZXIoY29scyA9IGMoc3RhcnRzX3dpdGgoIldfIiksCiAgICAgICAgICAgICAgICAgICAgc3RhcnRzX3dpdGgoIkJfIiksCiAgICAgICAgICAgICAgICAgICAgc3RhcnRzX3dpdGgoIkFJQU5fIiksCiAgICAgICAgICAgICAgICAgICAgc3RhcnRzX3dpdGgoIkFQSV8iKSksCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gIlJBQ0UiLAogICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAiU1VCX1BPUF90ZW1wIikKCmRlbV85MF85OSAlPD4lCiAgbXV0YXRlKFNFWCA9IGNhc2Vfd2hlbihzdHJfZGV0ZWN0KFJBQ0UsICJfTSIpIH4gIk1hbGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJGZW1hbGUiKSwKICAgICAgICAgUkFDRSA9IGNhc2Vfd2hlbihzdHJfZGV0ZWN0KFJBQ0UsICJXXyIpIH4gIldoaXRlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJfZGV0ZWN0KFJBQ0UsICJCXyIpIH4gIkJsYWNrIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIk90aGVyIikpICU+JQogIGxlZnRfam9pbihTVEFURV9GSVBTLCBieSA9ICJTVEFURUZQIikgJT4lCiAgZHBseXI6OnNlbGVjdCgtU1RBVEVGUCkKCmRlbV85MF85OSAlPD4lCiAgZ3JvdXBfYnkoWUVBUiwgU1RBVEUsIEFHRV9HUk9VUCwgU0VYLCBSQUNFKSAlPiUKICBzdW1tYXJpemUoU1VCX1BPUCA9IHN1bShTVUJfUE9QX3RlbXApLCAuZ3JvdXBzPSJkcm9wIikKCmBgYAoKYGBge3J9CnBvcF85MF85OSA8LSBkZW1fOTBfOTkgJT4lCiAgZ3JvdXBfYnkoWUVBUiwgU1RBVEUpICU+JQogIHN1bW1hcml6ZShUT1RfUE9QID0gc3VtKFNVQl9QT1ApLCAuZ3JvdXBzID0gImRyb3AiKQoKZGVtXzkwXzk5IDwtIGRlbV85MF85OSAlPiUKICBsZWZ0X2pvaW4ocG9wXzkwXzk5LCBieT1jKCJZRUFSIiwgIlNUQVRFIikpICU+JQogIG11dGF0ZShQRVJDX1NVQl9QT1AgPSAoU1VCX1BPUC9UT1RfUE9QKSoxMDApICU+JQogIGRwbHlyOjpzZWxlY3QoLVNVQl9QT1AsIC1UT1RfUE9QKQoKZGVtXzkwXzk5CmBgYAoKCkFnYWluLCB3ZSBzaG91bGQgY2hlY2sgdG8gbWFrZSBzdXJlIHRoYXQgd2UgaGF2ZSB0aGUgdG90YWwgdmFsdWVzIHdlIHdvdWxkIGV4cGVjdC4gV2UgaGF2ZSB0aGUgc2FtZSBudW1iZXIgb2YgdW5pcXVlIHZhbHVlcyBmb3IgZWFjaCBvZiBvdXIgdmFyaWFibGVzIGFzIGluIHdpdGggdGhlIGRhdGEgZnJvbSB0aGUgODBzLCBzbyBpZiB3ZSBjb2xsYXBzZWQgdGhlIGRhdGEgZm9yIHRoZSBkaWZmZXJlbnQgYWRkaXRpb25hbCBzdWItcG9wdWxhdGlvbnMgaW4gdGhpcyBkYXRhLCB0aGVuIHdlIGhhdmUgZG9uZSBpdCBjb3JyZWN0bHkuIAoKSW5kZWVkIGl0IGxvb2tzIGxpa2Ugd2UgaGF2ZSA1NSwwODAgcm93cywgd2hpY2ggaXMgd2hhdCB3ZSB3b3VsZCBleHBlY3QgYW5kIGlzIHRoZSBzYW1lIGFzIHRoZSBudW1iZXIgb2Ygcm93cyBvZiB0aGUgZmluYWwgYGRlbV84MF84OWAgZGF0YS4gTG9va3MgZ29vZCEKCiMjIyAqKjIwMDAtMjAxMCoqCgoqKioKCkFnYWluLCBmb3IgdGhpcyBkZWNhZGUgd2UgbmVlZCB0byBjb21iaW5lIHRoZSBkYXRhIGFjcm9zcyB5ZWFycy4KCmBgYHtyfQpkZW1fMDBfMTAgPC0gZGVtXzAwXzEwICU+JQogIG1hcF9kZihiaW5kX3Jvd3MpCgpnbGltcHNlKGRlbV8wMF8xMCkKCmBgYAoKT0ssIHRoZSBkYXRhIGxvb2tzIGEgYml0IGRpZmZlcmVudCBmcm9tIHRoZSBvdGhlcnMuIEZpcnN0IHdlIHdpbGwgcmVtb3ZlIGEgY291cGxlIG9mIHZhcmlhYmxlcyB0aGF0IHdlIHByb2JhYmx5IGRvbid0IG5lZWQuIEFsc28gaXQgbG9va3MgbGlrZSB3ZSBoYXZlIHNvbWUgdmFsdWVzIGZvciB0aGUgZW50aXJlIFVuaXRlZCBTYXRlcyBhbmQgd2Ugd2lsbCBkcm9wIHRoZXNlIHRvIGJlIGxpa2UgdGhlIG90aGVyIGRlY2FkZXMuCgoKCmBgYHtyfQpkZW1fMDBfMTAgJTw+JQogIHNlbGVjdCgtRVNUSU1BVEVTQkFTRTIwMDAsLUNFTlNVUzIwMTBQT1ApICU+JQogIGZpbHRlcihOQU1FICE9ICJVbml0ZWQgU3RhdGVzIikKYGBgCgpXZSBjYW4gc2VlIHRoYXQgdGhlcmUgYXJlIGxvdHMgb2YgdmFsdWVzIHRoYXQgYXJlIHplcm8uIEFjY29yZGluZyB0byB0aGUgW3RlY2huaWNhbCBkb2N1bWVudGF0aW9uXShodHRwczovL3d3dzIuY2Vuc3VzLmdvdi9wcm9ncmFtcy1zdXJ2ZXlzL3BvcGVzdC90ZWNobmljYWwtZG9jdW1lbnRhdGlvbi9maWxlLWxheW91dHMvMjAwMC0yMDEwL2ludGVyY2Vuc2FsL3N0YXRlL3N0LWVzdDAwaW50LWFsbGRhdGEucGRmKXt0YXJnZXQ9Il9ibGFuayJ9IGZvciB0aGlzIGRhdGEsIHplcm8gdmFsdWVzIGluZGljYXRlIHRoZSB0b3RhbCBmb3IgdGhlIG90aGVyIGNhdGVnb3JpZXMgb2YgYFNleGAsIGBPcmlnaW5gLCBgUmFjZWAsIGFuZCBgQUdFR1JQYC4KCgpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXQud2lkdGggPSAiNjAwIHB4In0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1nIiwgInRlY2hfaW5mby5wbmciKSkKYGBgCgpTbyB3ZSB3aWxsIGRyb3AgdGhlIHRvdGFsIHZhbHVlcyBmb3IgYFNFWGAsIGBSQUNFYCwgYW5kIGBBR0VHUlBgIGJ5IHJlbW92aW5nIHRoZSByb3dzIHdoZXJlIHRoZXNlIHZhcmlhYmxlcyBhcmUgZXF1YWwgdG8gemVyby4KCldlIHdpbGwgYWxzbyB3YW50IHRvIG9ubHkgc2VsZWN0IGZvciB0aGUgdG90YWwgdmFsdWVzIGZvciBgT3JpZ2luYCBhcyB3ZSBkbyBub3Qgd2lzaCB0byBkaXZpZGUgdGhlIGRhdGEgaW50byBzdWJncm91cHMgYWJvdXQgSGlzcGFuaWMgZXRobmljaXR5IGJlY2F1c2Ugd2UgZG8gbm90IGhhdmUgdGhhdCBpbmZvcm1hdGlvbiBmb3IgdGhlIGZpcnN0IHR3byBkZWNhZGVzLiBUaHVzIHdlIHdpbGwgZmlsdGVyIGZvciBvbmx5IHRoZSByb3dzIHdoZXJlIGBPcmlnaW5gIGlzIGVxdWFsIHRvIHplcm8uCgpXZSB3aWxsIGFsc28gdGhlbiByZW1vdmUgdGhlIGBSRUdJT05gLCBgRGl2aXNpb25gLCBgU1RBVEVgLCBhbmQgYE9yaWdpbmAgdmFyaWFibGVzLiBXZSB3aWxsIHRoZW4gcmVuYW1lIGBOQU1FYCB0byBiZSBgU1RBVEVgIGFuZCByZW5hbWUgYEFHRUdSUGAgdG8gYmUgbGlrZSB0aGUgb3RoZXIgZGVjYWRlcyBhcyBgQUdFX0dST1VQYC4KCmBgYHtyfQpkZW1fMDBfMTAgJTw+JQogIGZpbHRlcihTRVggIT0gMCwKICAgICAgICAgUkFDRSAhPSAwLAogICAgICAgICBBR0VHUlAgIT0gMCwgCiAgICAgICAgIE9SSUdJTiA9PSAwKSAlPiUKICBkcGx5cjo6c2VsZWN0KC1SRUdJT04sIC1ESVZJU0lPTiwgLU9SSUdJTiwgLVNUQVRFKSAlPiUKICByZW5hbWUoIlNUQVRFIiA9IE5BTUUsCiAgICAgICAgICJBR0VfR1JPVVAiID0gQUdFR1JQKQoKZGVtXzAwXzEwCmBgYAoKCk5vdyB3ZSBuZWVkIHRvIHJlY29kZSB0aGUgbnVtZXJpYyB2YWx1ZXMgdG8gdGhlIHZhbHVlcyBpbiB0aGUgdGVjaG5pY2FsIGRvY3VtZW50YXRpb24uIFdlIGNhbiBkbyBzbyBieSBhZGRpbmcgbGFiZWxzIHRvIGVhY2ggbnVtZXJpYyBsZXZlbCB1c2luZyB0aGUgYmFzZSBmdW5jdGlvbiBgZmFjdG9yKClgLgoKYGBge3J9CmRlbV8wMF8xMCAlPD4lCiAgbXV0YXRlKFNFWCA9IGZhY3RvcihTRVgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSAxOjIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJNYWxlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkZlbWFsZSIpKSwKICAgICAgICAgUkFDRSA9IGZhY3RvcihSQUNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gMTo2LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiV2hpdGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQmxhY2siLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXAoIk90aGVyIiw0KSkpLAogICAgICAgICBBR0VfR1JPVVAgPSBmYWN0b3IoQUdFX0dST1VQLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gMToxOCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IHB1bGwoZGlzdGluY3QoZGVtXzc3Xzc5LEFHRV9HUk9VUCksIEFHRV9HUk9VUCkpKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgCmdsaW1wc2UoZGVtXzAwXzEwKQpgYGAKCk9LLCB3ZSBhbHNvIHdhbnQgdG8gY2hhbmdlIHRoZSBzaGFwZSBvZiB0aGUgZGF0YSBzbyB0aGF0IHdlIGhhdmUgYSBgWUVBUmAgdmFyaWFibGUgYW5kIGVhY2ggZXN0aW1hdGUgb2YgdGhlIHBvcHVsYXRpb24gaXMgYSB2YWx1ZSBpbiBhIG5ldyB2YXJpYWJsZSBjYWxsZWQgYFNVQl9QT1BfdGVtcGAuIAoKYGBge3J9CmRlbV8wMF8xMCAlPD4lCiAgcGl2b3RfbG9uZ2VyKGNvbHM9Y29udGFpbnMoIkVTVElNQVRFIiksCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gIllFQVIiLAogICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAiU1VCX1BPUF90ZW1wIikKYGBgCgpXZSB3aWxsIG5vdyBjbGVhbiB1cCB0aGUgYFlFQVJgIHZhcmlhYmxlIHRvIG9ubHkgYmUgdGhlIG51bWVyaWMgdmFsdWUgYnkga2VlcGluZyBvbmx5IHRoZSBsYXN0IDQgdmFsdWVzIG9mIGVhY2ggc3RyaW5nIHVzaW5nIHRoZSBgc3RyX3N1YigpYCBmdW5jdGlvbiBvZiB0aGUgYHN0cmluZ3JgIHBhY2thZ2UuCgpgYGB7cn0KZGVtXzAwXzEwICU8PiUKICBtdXRhdGUoWUVBUiA9IHN0cl9zdWIoWUVBUiwgc3RhcnQ9LTQpKSAlPiUKICBtdXRhdGUoWUVBUiA9IGFzLm51bWVyaWMoWUVBUikpCmBgYAoKCk5vdyB3ZSB3aWxsIGNvbGxhcHNlIHRoZSBkYXRhIGZvciB0aGUgZGlmZmVyZW50IFJBQ0VTIGFuZCBjYWxjdWxhdGUgYSBuZXcgYFNVQl9QT1BgIHZhbHVlLiAKCmBgYHtyfQpkZW1fMDBfMTAgJTw+JQogIGdyb3VwX2J5KFlFQVIsIEFHRV9HUk9VUCwgU1RBVEUsIFNFWCwgUkFDRSkgJT4lCiAgc3VtbWFyaXplKFNVQl9QT1AgPSBzdW0oU1VCX1BPUF90ZW1wKSwgLmdyb3VwcyA9ICJkcm9wIikKYGBgCgpBZ2FpbiwgdGhlIGRpbWVuc2lvbnMgbG9vayBhcyB3ZSBleHBlY3Qgd2l0aCA2MCw1ODggcm93cy4gVGhpcyB0aW1lIHdlIGhhdmUgdHdvIGxldmVscyBvZiBgU0VYYCwgdGhyZWUgbGV2ZWxzIG9mIGBSYWNlYCwgKioxMSoqIGxldmVscyBvZiBgWUVBUmAsIGVpZ2h0ZWVuIGxldmVscyBvZiBgQUdFX0dST1VQYCwgYW5kIGZpZnR5IG9uZSBsZXZlbHMgb2YgYFNUQVRFYC4gSWYgd2UgbXVsdGlwbHkgdGhpcyB0b2dldGhlciB3ZSBnZXQgMTYsNTg4LiBMb29rcyBnb29kIQoKTm93IHdlIHdpbGwgY2FsY3VsYXRlIHRoZSB0b3RhbCBwb3B1bGF0aW9uIGFuZCBwZXJjZW50IG9mIHRoZSB0b3RhbCBhcyB3ZSBoYXZlIGRvbmUgd2l0aCB0aGUgcHJldmlvdXMgZGVjYWRlcy4KCgpgYGB7cn0KcG9wXzAwXzEwIDwtIGRlbV8wMF8xMCAlPiUKICBncm91cF9ieShZRUFSLCBTVEFURSkgJT4lCiAgc3VtbWFyaXplKFRPVF9QT1AgPSBzdW0oU1VCX1BPUCksIC5ncm91cHMgPSAiZHJvcCIpCmBgYAoKV2UgY2FuIGFsc28gY2hlY2sgdGhhdCBvdXIgd3JhbmdsaW5nIHdhcyBwZXJmb3JtZWQgY29ycmVjdGx5IGJ5IHN1bW1pbmcgdGhlIHZhbHVlcyBmb3IgdGhlIGluZGl2aWR1YWwgc3ViLXBvcHVsYXRpb25zIHBlcmNlbnRhZ2VzIGFuZCBzZWVpbmcgaWYgaXQgdG90YWxzIHRvIDEwMC4KCmBgYHtyfQpkZW1fMDBfMTAgJT4lCiAgbGVmdF9qb2luKHBvcF8wMF8xMCwgYnk9YygiWUVBUiIsICJTVEFURSIpKSAlPiUKICBncm91cF9ieShZRUFSLCBTVEFURSkgJT4lCiAgbXV0YXRlKFBFUkNfU1VCX1BPUCA9IChTVUJfUE9QL1RPVF9QT1ApKjEwMCkgJT4lCiAgc3VtbWFyaXplKHBlcmNfdG90ID0gc3VtKFBFUkNfU1VCX1BPUCksIC5ncm91cHMgPSAiZHJvcCIpICU+JQogIG11dGF0ZShwb3NzX2Vycm9yID0gY2FzZV93aGVuKGFicyhwZXJjX3RvdCAtIDEwMCkgPiAwIH4gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gRkFMU0UpKSAlPiUKICBncm91cF9ieShwb3NzX2Vycm9yKSAlPiUKICB0YWxseSgpCgpgYGAKCkxvb2tzIGxpa2UgdGhlIHBlcmNlbnRhZ2VzIGZvciBlYWNoIHN0YXRlIGZvciBlYWNoIHllYXIgYWxsIGFkZCB1cCB0byAxMDAsIGFzIHdlIHdvdWxkIGV4cGVjdC4gR3JlYXQhIE5vdyB3ZSB3aWxsIHJlYXNzaWduIHRoZSBgZGVtXzAwXzEwYCBkYXRhIHdpdGggdGhpcyBwcm9jZXNzaW5nLiAKCmBgYHtyfQpkZW1fMDBfMTAgJTw+JQogIGxlZnRfam9pbihwb3BfMDBfMTAsIGJ5ID0gYygiWUVBUiIsICJTVEFURSIpKSAlPiUKICBtdXRhdGUoUEVSQ19TVUJfUE9QID0gKFNVQl9QT1AvVE9UX1BPUCkqMTAwKSAlPiUKIHNlbGVjdCgtU1VCX1BPUCwgLVRPVF9QT1ApCgpkZW1fMDBfMTAKYGBgCgpPSywgbm93IHdlIGFyZSByZWFkeSB0byBjb21iaW5lIGFsbCBvZiBvdXIgZGVtb2dyYXBoaWMgZGF0YSB0b2dldGhlciEKCgoKKioqCgojIyAqKkNvbWJpbmluZyBkZW1vZ3JhcGhpYyBkYXRhKioKKioqCgpXZSBjYW4gY2hlY2sgdGhhdCB0aGUgY29sdW1uIG5hbWVzIGFyZSB0aGUgc2FtZSBmb3IgdGhlIGRhdGEgZm9yIGVhY2ggb2YgdGhlIGRlY2FkZXMgYnkgdXNpbmcgdGhlIGBzZXRlcXVhbCgpYCBmdW5jdGlvbiBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlLgoKYGBge3J9CnNldGVxdWFsKGNvbG5hbWVzKGRlbV83N183OSksY29sbmFtZXMoZGVtXzgwXzg5KSkKc2V0ZXF1YWwoY29sbmFtZXMoZGVtXzgwXzg5KSxjb2xuYW1lcyhkZW1fOTBfOTkpKQpzZXRlcXVhbChjb2xuYW1lcyhkZW1fOTBfOTkpLGNvbG5hbWVzKGRlbV8wMF8xMCkpCmBgYAoKCldlIGNhbiBhbHNvIGNvbmZpcm0gdGhhdCB3ZSBoYXZlIHRoZSBzYW1lIG51bWJlciBvZiBhZ2UgZ3JvdXBzIGZvciBlYWNoIGRlY2FkZSBieSB1c2luZyB0aGUgYmFzZSBgbGVuZ3RoKClgIGZ1bmN0aW9uLiBJZiB5b3UgZGlkIG5vdCB0YWtlIGEgbG9vayBhdCB0aGUgd3JhbmdsaW5nIGZvciB0aGUgZGVtb2dyYXBoaWMgZGF0YSB0aGVuIHlvdSBtYXkgYmUgdW5mYW1pbGlhciB3aXRoIHRoZSBgcHVsbCgpYCBmdW5jdGlvbiBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlLiBUaGlzIGFsbG93cyB5b3UgdG8gZ3JhYiB0aGUgdmFsdWVzIG9mIGEgdmFyaWFibGUgZnJvbSBhIHRpYmJsZS4gVGhlIGBkaXN0aW5jdCgpYCBmdW5jdGlvbiB3aGljaCBpcyBhbHNvIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UgY3JlYXRlcyBhIHRpYmJsZSBvZiB0aGUgdW5pcXVlIHZhbHVlcyBmb3IgYSB2YXJpYWJsZS4KCmBgYHtyfQpsZW5ndGgocHVsbChkaXN0aW5jdChkZW1fNzdfNzksIEFHRV9HUk9VUCksIEFHRV9HUk9VUCkpCmxlbmd0aChwdWxsKGRpc3RpbmN0KGRlbV84MF84OSwgQUdFX0dST1VQKSwgQUdFX0dST1VQKSkKbGVuZ3RoKHB1bGwoZGlzdGluY3QoZGVtXzkwXzk5LCBBR0VfR1JPVVApLCBBR0VfR1JPVVApKQpsZW5ndGgocHVsbChkaXN0aW5jdChkZW1fMDBfMTAsIEFHRV9HUk9VUCksIEFHRV9HUk9VUCkpCmBgYAoKTG9va3MgZ29vZCEKCgpOb3cgd2Ugd2lsbCBjb21iaW5lIHRoZSBkYXRhIHVzaW5nIHRoZSBgYmluZF9yb3dzKClgIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UuIFRoaXMgZnVuY3Rpb24gYXBwZW5kcyB0aGUgZGF0YSB0b2dldGhlciBiYXNlZCBvbiB0aGUgcHJlc2VuY2Ugb2YgY29sdW1ucyB3aXRoIHRoZSBzYW1lIG5hbWUgaW4gdGhlIGRpZmZlcmVudCB0aWJibGVzLgoKYGBge3J9CmRlbSA8LSBiaW5kX3Jvd3MoZGVtXzc3Xzc5LAogICAgICAgICAgICAgICAgIGRlbV84MF84OSwKICAgICAgICAgICAgICAgICBkZW1fOTBfOTksCiAgICAgICAgICAgICAgICAgZGVtXzAwXzEwKQpgYGAKCgpgYGB7cn0KZ2xpbXBzZShkZW0pCmBgYAoKR3JlYXQhIG5vdyB3ZSBoYXZlIGEgcmVhbGx5IGxhcmdlIHNpbmdsZSB0aWJibGUuCgpOb3cgd2Ugd2FudCB0byBzZWxlY3Qgc2ltaWxhciBkZW1vZ3JhcGhpYyBkYXRhIHRvIHdoYXQgd2FzIHVzZWQgaW4gdGhlIHByZXZpb3VzIGFuYWx5c2VzLgoKSGVyZSBpcyB0aGUgdGFibGUgZnJvbSB0aGUgW0Rvbm9odWUgcGFwZXJdKGh0dHBzOi8vd3d3Lm5iZXIub3JnL3BhcGVycy93MjM1MTAucGRmKXt0YXJnZXQ9Il9ibGFuayJ9IHRoYXQgY29tcGFyZXMgdGhlIGRhdGEgdXNlZCBpbiB0aGUgYW5hbHlzZXMuCgoKYGBge3IsIGVjaG89RkFMU0UsIG91dC5oZWlnaHQgPSAnMTAwJScsIG91dC53aWR0aCA9ICcxMDAlJywgZmlnLmFsaWduPSdjZW50ZXInfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlKCJpbWciLCdEb25vaHVlX1RhYmxlMi5wbmcnKSkKYGBgCldlIGNhbiBzZWUgdGhhdCBvbmx5IHRoZSBwZXJjZW50YWdlIG9mIG1hbGVzIHRoYXQgd2VyZSBmcm9tIGFnZSAxNS0zOSBvZiB0aGUgcmFjZSBncm91cHMgKGJsYWNrLCB3aGl0ZSwgYW5kIG90aGVyKSB3ZXJlIHVzZWQgaW4gdGhlIERvbm9odWUgYW5hbHlzaXMuCgpVbHRpbWF0ZWx5IHdlIGludGVuZCB0byBtYWtlIGEgdGliYmxlIG9mIGRhdGEgdGhhdCBpcyBzaW1pbGFyIHRvIGVhY2ggYW5hbHlzaXMuIFRoZXJlZm9yZSwgd2Ugd2lsbCBjcmVhdGUgYSBkYXRhIHRpYmJsZSBhYm91dCB0aGUgZGVtb2dyYXBoaWMgZGF0YSBmb3IgZWFjaCBhbmFseXNpcyBub3cuCgpUbyBkbyBzbyB3ZSB3aWxsIGZpcnN0IGNyZWF0ZSBhIHZlY3RvciBvZiB0aGUgYWdlIGdyb3VwcyB0aGF0IHNob3VsZCBiZSBpbmNsdWRlZCBpbiB0aGUgRG9ub2h1ZS1saWtlIGFuYWx5c2lzLCB0aGF0IHdlIHdpbGwgY2FsbCBgRE9OT0hVRV9BR0VfR1JPVVBTYC4gV2Ugd2lsbCB0aGVuIGZpbHRlciBmb3Igb25seSB0aGUgYWdlIGdyb3VwcyBpbiB0aGlzIHZlY3RvciBieSB1c2luZyB0aGUgYGZpbHRlcigpYCBmdW5jdGlvbiBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlIGFuZCB0aGUgYCVpbiVgIG9wZXJhdG9yIHRvIGluZGljYXRlIHRoYXQgd2Ugd2FudCB0byBrZWVwIGFsbCBgQUdFX0dST1VQYCB2YWx1ZXMgdGhhdCBhcmUgZXF1YWwgdG8gdGhvc2Ugd2l0aGluIGBET05PSFVFX0FHRV9HUk9VUFNgLiBXZSBhbHNvIHdhbnQgdG8gZmlsdGVyIGZvciBvbmx5IHBvcHVsYXRpb24gcGVyY2VudGFnZXMgZm9yIG1hbGVzIGJ5IHVzaW5nIHRoZSBgPT1gIG9wZXJhdG9yLiBUaGVuIHdlIGNhbiBjb2xsYXBzZSB0aGUgYWdlIGdyb3VwcyBmcm9tIDIwLTM5IGJ5IHVzaW5nIHRoZSBgZmN0X2NvbGxwYXNlKClgIGZ1bmN0aW9uIG9mIHRoZSBgZm9yY2F0c2AgcGFja2FnZS4KCmBgYHtyfQpET05PSFVFX0FHRV9HUk9VUFMgPC0gYygiMTUgdG8gMTkgeWVhcnMiLAogICAgICAgICAgICAgICAgICAgICAgICAiMjAgdG8gMjQgeWVhcnMiLAogICAgICAgICAgICAgICAgICAgICAgICAiMjUgdG8gMjkgeWVhcnMiLAogICAgICAgICAgICAgICAgICAgICAgICAiMzAgdG8gMzQgeWVhcnMiLAogICAgICAgICAgICAgICAgICAgICAgICAiMzUgdG8gMzkgeWVhcnMiKQoKZGVtX0RPTk9IVUUgPC0gZGVtICU+JQogIGZpbHRlcihBR0VfR1JPVVAgJWluJSBET05PSFVFX0FHRV9HUk9VUFMsCiAgICAgICAgICAgICAgIFNFWCA9PSAiTWFsZSIpICU+JQogIG11dGF0ZShBR0VfR1JPVVAgPSBmY3RfY29sbGFwc2UoQUdFX0dST1VQLCAiMjAgdG8gMzkgeWVhcnMiPWMoIjIwIHRvIDI0IHllYXJzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIyNSB0byAyOSB5ZWFycyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMzAgdG8gMzQgeWVhcnMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjM1IHRvIDM5IHllYXJzIikpKQoKZGVtX0RPTk9IVUUKYGBgCgpXZSBhbHNvIHdhbnQgdG8gY3JlYXRlIGEgbmV3IHZhcmlhYmxlIHRoYXQgd2lsbCBjb250YWluIGFsbCB0aGUgZGVtb2dyYXBoaWMgaW5mb3JtYXRpb24gZm9yIGVhY2ggcGVyY2VudGFnZSBqdXN0IGFzIHdhcyBkb25lIGluIHRoZSBbRG9ub2h1ZSwgZXQgYWwuXShodHRwczovL3d3dy5uYmVyLm9yZy9wYXBlcnMvdzIzNTEwLnBkZil7dGFyZ2V0PSJfYmxhbmsifSBhbmFseXNpcy4gVGhpcyBzaG91bGQgcmVzdWx0IGluIDYgZGlmZmVyZW50IGRlbW9ncmFwaGljIHZhcmlhYmxlcy4KClRvIGRvIHRoaXMgd2Ugd2lsbCBtb2RpZnkgdGhlIGBBR0VfR1JPVVBgIHZhcmlhYmxlIGJ5IHVzaW5nIHRoZSBgbXV0YXRlKClgIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UuIFdlIHdpbGwgcmVwbGFjZSB0aGUgc3BhY2VzIGluIHRoZSBub3cgdHdvIGFnZSBncm91cCBjYXRlZ29yaWVzIHdpdGggYW5kIHVuZGVyc2NvcmUgdXNpbmcgdGhlIGBzdHJfcmVwbGFjZV9hbGwoKWAgZnVuY3Rpb24gb2YgdGhlIGBzdHJpbmdyYCBwYWNrYWdlIHdoaWNoIHJlcGxhY2VzIGFsbCBpbnN0YW5jZXMgb2YgYSBwYXR0ZXJuIGluIGEgY2hhcmFjdGVyIHN0cmluZy4gCgpUaGVuIHdlIHdpbGwgdXNlIHRoZSBgZ3JvdXBfYnkoKWAgZnVuY3Rpb24gYW5kIHRoZSBgc3VtbWFyaXplKClgIGZ1bmN0aW9uIGFsc28gb2YgdGhlIGBkcGx5cmAgcGFja2FnZSB0byBhbGxvdyB1cyB0byBjYWxjdWxhdGUgYSBzdW0gb2YgdGhlIHBlcmNlbnRhZ2VzIGZvciBlYWNoIG9mIHRoZSBzdWItcG9wdWxhdGlvbiBwZXJjZW50YWdlcyBmb3IgdGhlIG5ld2x5IG1vZGlmaWVkIGFnZSBncm91cHMgaW4gYEFHRV9HUk9VUGAuIFRoZSBgLmdyb3VwcyA9ICJkcm9wImAgYXJndW1lbnQgYWxsb3dzIGZvciB0aGUgZ3JvdXBpbmcgdG8gYmUgcmVtb3ZlZCBhZnRlciB0aGUgYHN1bW1hcml6ZSgpYCBmdW5jdGlvbi4KCmBgYHtyfQpkZW1fRE9OT0hVRSAlPD4lCiAgbXV0YXRlKEFHRV9HUk9VUCA9IHN0cl9yZXBsYWNlX2FsbChzdHJpbmcgPSBBR0VfR1JPVVAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGF0dGVybiA9ICIgIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXBsYWNlbWVudCA9ICJfIikpICU+JQogIGdyb3VwX2J5KFlFQVIsIFNUQVRFLCBSQUNFLCBTRVgsIEFHRV9HUk9VUCkgJT4lCiAgc3VtbWFyaXplKFBFUkNfU1VCX1BPUCA9IHN1bShQRVJDX1NVQl9QT1ApLCAuZ3JvdXBzID0gImRyb3AiKQoKZGVtX0RPTk9IVUUKYGBgCgpOb3cgd2Ugd2lsbCBjb21iaW5lIHRoZSB2YXJpYWJsZXMgYFJBQ0VgLCBgU0VYYCwgYW5kIGBBR0VfR1JPVVBgIHRvZ2V0aGVyIGludG8gb25lIHN0cmluZyBzZXBhcmF0ZWQgYnkgdW5kZXJzY29yZXMgdXNpbmcgdGhlIGB1bml0ZWAgZnVuY3Rpb24gb2YgdGhlIGB0aWR5cmAgcGFja2FnZS4gd2Ugd2lsbCBjYWxsIHRoaXMgbmV3IHZhcmlhYmxlIGBWQVJJQUJMRWAuCldlIHdpbGwgcmVuYW1lIHRoZSBgUEVSQ19TVUJfUE9QYCB2YXJpYWJsZSB0byBiZSBgVkFMVUVgIHVzaW5nIHRoZSBgcmVuYW1lKClgIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UuIFRoZSBuZXcgbmFtZSBzaG91bGQgYmUgbGlzdGVkIGZpcnN0IGJlZm9yZSB0aGUgYD1gLgoKYGBge3J9CmRlbV9ET05PSFVFICU8PiUKICB1bml0ZShjb2wgPSAiVkFSSUFCTEUiLCBSQUNFLCBTRVgsIEFHRV9HUk9VUCwgc2VwID0gIl8iKSAlPiUKICByZW5hbWUoIlZBTFVFIiA9IFBFUkNfU1VCX1BPUCkKCmRlbV9ET05PSFVFCmBgYAoKTGV0J3MgZG8gYSBxdWljayByb3cgbnVtYmVyIGNoZWNrLiBXZSBoYXZlIHNpeCBkaWZmZXJlbnQgZGVtb2dyYXBoaWMgdmFyaWFibGVzLCA1MSBzdGF0ZXMgKERDIGNvdW50cyBhcyBhIHN0YXRlIGluIHRoaXMgY2FzZSksIGFuZCAzNCBkaWZmZXJlbnQgeWVhcnMgZnJvbSAxOTc3IHRvIDIwMTAsIHdlIHNob3VsZCBoYXZlIDEwLDQwNCByb3dzLCB3aGljaCB3ZSBkbyEKCk5vdywgbGV0J3MgZG8gdGhlIHNhbWUgZm9yIHRoZSAiTG90dC1saWtlIiBhbmFseXNpcy4KCgpgYGB7ciwgZWNobz1GQUxTRSwgb3V0LmhlaWdodCA9ICcxMDAlJywgb3V0LndpZHRoID0gJzEwMCUnLCBmaWcuYWxpZ249J2NlbnRlcid9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmUoImltZyIsJ0Rvbm9odWVfVGFibGUyLnBuZycpKQpgYGAKClNvLCBpbiB0aGlzIGFuYWx5c2lzIHRoZXJlIHdlcmUgMzYgdmFyaWFibGVzIGNvdmVyaW5nIHBlcmNlbnRhZ2VzIG9mIGluZGl2aWR1YWxzIGZyb20gMTAgdG8gb3ZlciA2NSwgdGhyZWUgIHJhY2UgZ3JvdXBzIGFuZCBib3RoIG1hbGVzIGFuZCBmZW1hbGVzLiBUaGlzIHRhYmxlIGlzIG1pc3ByaW50ZWQgYW5kIGRvZXMgbm90IGluY2x1ZGUgdGhlIHdvcmQgIk90aGVyIiBmb3IgdGhlIHRoaXJkIHJhY2UgZ3JvdXAgdGhhdCB3YXMgdXNlZC4gCgpGaXJzdCB3ZSB3aWxsIGZpbHRlciBvdXQgdGhlIGFnZSBncm91cHMgdGhhdCB3ZXJlIG5vdCBpbmNsdWRlZC4gVGhlbiB3ZSB3aWxsIGNvbGxhcHNlIHRoZSBhZ2UgZ3JvdXBzIHRvIHRob3NlIHRoYXQgd2VyZSB1c2VkIGJ5IE11c3RhcmQgYW5kIExvdHQgYWdhaW4gdXNpbmcgdGhlIGBmY3RfY29sbHBhc2UoKWAgZnVuY3Rpb24gb2YgdGhlIGBmb3JjYXRzYCBwYWNrYWdlLiAKCkFsc28gd2Ugd2lsbCBhZ2FpbiBjb21iaW5lIHRoZSB2YWx1ZXMgYWNyb3NzIHRoZSB2YXJpYWJsZXMgdG8gY3JlYXRlIGEgbmV3IGRlbW9ncmFwaGljIHZhcmlhYmxlIHdpdGggMzYgbGV2ZWxzLiAKCmBgYHtyfQpMT1RUX0FHRV9HUk9VUFNfTlVMTCA8LSBjKCJVbmRlciA1IHllYXJzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAiNSB0byA5IHllYXJzIikKCmRlbV9MT1RUIDwtIGRlbSAlPiUKICBmaWx0ZXIoIShBR0VfR1JPVVAgJWluJSBMT1RUX0FHRV9HUk9VUFNfTlVMTCkgKSU+JQogIG11dGF0ZShBR0VfR1JPVVAgPSBmY3RfY29sbGFwc2UoQUdFX0dST1VQLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjEwIHRvIDE5IHllYXJzIj1jKCIxMCB0byAxNCB5ZWFycyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjE1IHRvIDE5IHllYXJzIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMjAgdG8gMjkgeWVhcnMiPWMoIjIwIHRvIDI0IHllYXJzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMjUgdG8gMjkgeWVhcnMiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIzMCB0byAzOSB5ZWFycyI9YygiMzAgdG8gMzQgeWVhcnMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIzNSB0byAzOSB5ZWFycyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjQwIHRvIDQ5IHllYXJzIj1jKCI0MCB0byA0NCB5ZWFycyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjQ1IHRvIDQ5IHllYXJzIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiNTAgdG8gNjQgeWVhcnMiPWMoIjUwIHRvIDU0IHllYXJzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiNTUgdG8gNTkgeWVhcnMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI2MCB0byA2NCB5ZWFycyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjY1IHllYXJzIGFuZCBvdmVyIj1jKCI2NSB0byA2OSB5ZWFycyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjcwIHRvIDc0IHllYXJzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiNzUgdG8gNzkgeWVhcnMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI4MCB0byA4NCB5ZWFycyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjg1IHllYXJzIGFuZCBvdmVyIikpKSAlPiUKICBtdXRhdGUoQUdFX0dST1VQID0gc3RyX3JlcGxhY2VfYWxsKEFHRV9HUk9VUCwiICIsIl8iKSkgJT4lCiAgZ3JvdXBfYnkoWUVBUiwgU1RBVEUsIFJBQ0UsIFNFWCwgQUdFX0dST1VQKSAlPiUKICBzdW1tYXJpemUoUEVSQ19TVUJfUE9QID0gc3VtKFBFUkNfU1VCX1BPUCksIC5ncm91cHMgPSAiZHJvcCIpICU+JQogIHVuaXRlKGNvbCA9ICJWQVJJQUJMRSIsIFJBQ0UsIFNFWCwgQUdFX0dST1VQLCBzZXAgPSAiXyIpICU+JQogIHJlbmFtZSgiVkFMVUUiPVBFUkNfU1VCX1BPUCkKYGBgCgpXZSBjYW4gaW5kZWVkIGNoZWNrIHRoYXQgd2UgaGF2ZSB0aGUgY29ycmVjdCBudW1iZXIgb2YgbGV2ZWxzIGZvciBgVkFSSUFCTEVgIHVzaW5nIHRoZSBgZGlzdGluY3QoKWAgZnVuY3Rpb24uCgpgYGB7cn0KIGRpc3RpbmN0KGRlbV9MT1RULCBWQVJJQUJMRSkKYGBgCiAgCiMjICoqQ29tYmluaW5nIHBvcHVsYXRpb24gZGF0YSoqCioqKgoKV2UgYWxzbyBoYXZlIHBvcHVsYXRpb24gZGF0YSBmb3IgZWFjaCBkZWNhZGUgdGhhdCBjYW1lIGZyb20gd3JhbmdsaW5nIHRoZSBkZW1vZ3JhcGhpYyBkYXRhLgoKV2UgYWdhaW4gd2FudCB0byBjb21iaW5lIHRoaXMgZGF0YSwgc28gbGV0J3MgYWdhaW4gbWFrZSBzdXJlIHRoYXQgYWxsIHRoZSBkaWZmZXJlbnQgdGliYmxlcyBoYXZlIHRoZSBzYW1lIGNvbHVtbiBuYW1lcy4KCmBgYHtyfQpzZXRlcXVhbChjb2xuYW1lcyhwb3BfNzdfNzkpLGNvbG5hbWVzKHBvcF84MF84OSkpCnNldGVxdWFsKGNvbG5hbWVzKHBvcF84MF84OSksY29sbmFtZXMocG9wXzkwXzk5KSkKc2V0ZXF1YWwoY29sbmFtZXMocG9wXzkwXzk5KSxjb2xuYW1lcyhwb3BfMDBfMTApKQoKaGVhZChwb3BfNzdfNzkpCmhlYWQocG9wXzgwXzg5KQpoZWFkKHBvcF85MF85OSkKaGVhZChwb3BfMDBfMTApCmBgYAoKTG9va3MgZ29vZCEKCmBgYHtyfQpwb3B1bGF0aW9uX2RhdGEgPC0gYmluZF9yb3dzKHBvcF83N183OSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwb3BfODBfODksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9wXzkwXzk5LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvcF8wMF8xMCkKCnBvcHVsYXRpb25fZGF0YSA8LSBwb3B1bGF0aW9uX2RhdGEgJT4lCiAgbXV0YXRlKFZBUklBQkxFID0gIlBvcHVsYXRpb24iKSAlPiUKICByZW5hbWUoIlZBTFVFIiA9IFRPVF9QT1ApCmBgYAoKV2UgY291bGQgY2hlY2sgdGhhdCB3ZSBoYXZlIDUxIHZhbHVlcyBmb3IgZWFjaCB5ZWFyIGJ5IHVzaW5nIHRoZSBgY291bnQoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZS4KCmBgYHtyfQpwb3B1bGF0aW9uX2RhdGEgJT4lCiAgY291bnQoWUVBUikKYGBgCgojIyAqKlBvbGljZSBzdGFmZmluZyoqCioqKgoKPGRldGFpbHM+PHN1bW1hcnk+IENsaWNrIGhlcmUgdG8gc2VlIGRldGFpbHMgYWJvdXQgaG93IHRoZSBwb2xpY2Ugc3RhZmZpbmcgZGF0YSB3YXMgd3JhbmdsZWQuIDwvc3VtbWFyeT4KCk9LLCBub3cgd2Ugd2lsbCB3cmFuZ2xlIHRoZSBwb2xpY2Ugc3RhZmZpbmcgZGF0YS4gV2Ugd2FudCB0byBsaW1pdCB0aGUgZGF0YSB0byBvbmx5IHRoZSB5ZWFycyBvZiBpbnRlcmVzdC4gVGhlbiB3ZSB3aWxsIGFsc28gcmVwbGFjZSBOQSB2YWx1ZXMgd2l0aCB6ZXJvIGZvciB0aGUgYG1hbGVfdG90YWxfY3RgIGFuZCBgZmVtYWxlX3RvdGFsX2N0YCB2YXJpYWJsZXMgdXNpbmcgdGhlIGByZXBsYWNlX25hKClgIGZ1bmN0aW9uIG9mIHRoZSBgdGlkeXJgIHBhY2thZ2UuIFRoaXMgaXMgYmVjYXVzZSB3ZSBwbGFuIHRvIHN1bSB1cCB0aGUgbnVtYmVyIG9mIGVtcGxveWVlcyBmb3IgZGlmZmVyZW50IGFnZW5jaWVzIHdpdGhpbiBhIHN0YXRlIHRvIG9idGFpbiBhIHRvdGFsIHN0YXRlIHZhbHVlIChsaWtlIHRoZSBwcmV2aW91cyBhbmFseXNlcyBhcyB5b3UgY2FuIHNlZSBpbiB0aGUgdGFibGUgYWdhaW4gYmVsb3cpLiBJbiB0aGVzZSBhbmFseXNlcywgdGhlIG51bWJlciBvZiBlbXBsb3llZXMgd2FzIHVzZWQgd2hpY2ggaXMgd2h5IHdlIGFyZSB1c2luZyB0aGVzZSBwYXJ0aWN1bGFyIGNvbHVtbnMuCgpgYGB7ciwgZWNobz1GQUxTRSwgb3V0LmhlaWdodCA9ICcxMDAlJywgb3V0LndpZHRoID0gJzEwMCUnLCBmaWcuYWxpZ249J2NlbnRlcid9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmUoImltZyIsICJvdXJkYXRhLnBuZyIpKQpgYGAKCgpXZSB3aWxsIHVzZSB0aGUgYGFjcm9zcygpYCBmdW5jdGlvbiBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlIHRvIHNlbGVjdCBhbmQgbXV0YXRlIGJvdGggb2YgdGhlc2UgY29sdW1ucy4gU2luY2UgYm90aCBvZiB0aGVzZSB2YXJpYWJsZXMgaGF2ZSBgdG90YWxfY3RgIGluIHRoZSBuYW1lIGFuZCBubyBvdGhlciB2YXJpYWJsZXMgZG8sIHdlIGNhbiB1c2UgdGhlIGBjb250YWlucygpYCBmdW5jdGlvbiBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlIHRvIHNwZWNpZnkgdGhhdCB3ZSB3YW50IHRvIHVzZSB0aGVzZSBjb2x1bW5zIGluc3RlYWQgb2YgbGlzdGluZyBib3RoIG91dC4KCgpgYGB7cn0KZ2xpbXBzZShwc19kYXRhKQoKcHNfZGF0YSAlPD4lCiAgZmlsdGVyKGRhdGFfeWVhciA+PSAxOTc3LCAKICAgICAgICAgZGF0YV95ZWFyIDw9IDIwMTQpICU+JQptdXRhdGUoYWNyb3NzKC5jb2xzID1jb250YWlucygidG90YWxfY3QiKSwgfnJlcGxhY2VfbmEoLiwgMCkpKQoKZ2xpbXBzZShwc19kYXRhKQpgYGAKCk5vdyB3ZSBjYW4gY3JlYXRlIGEgbmV3IHZhcmlhYmxlIGNhbGxlZCBgcG9saWNlX2VtcF90b3RhbGAgd2hpY2ggd2lsbCBiZSB0aGUgc3VtIG9mIHRoZXNlIHZhcmlhYmxlcy4gV2Ugd2lsbCB0aGVuIGtlZXAganVzdCB0aGlzIHZhcmlhYmxlIGFzIHdlbGwgYXMgdGhlIGBkYXRhX3llYXJgLCBgcHViX2FnZW5jeV9uYW1lYCwgYW5kIGBzdGF0ZV9hYmJyYC4KCmBgYHtyfQoKcHNfZGF0YSAlPD4lCiAgbXV0YXRlKHBvbGljZV9lbXBfdG90YWwgPSBtYWxlX3RvdGFsX2N0ICsgZmVtYWxlX3RvdGFsX2N0KSAlPiUKICBkcGx5cjo6c2VsZWN0KGRhdGFfeWVhciwKICAgICAgICAgICAgICAgIHB1Yl9hZ2VuY3lfbmFtZSwKICAgICAgICAgICAgICAgIHN0YXRlX2FiYnIsCiAgICAgICAgICAgICAgICBwb2xpY2VfZW1wX3RvdGFsKQoKcHNfZGF0YQpgYGAKCk5vdyB3ZSBhbHNvIHdhbnQgdG8gZ2V0IGNvbGxhcHNlIGJ5IGBwdWJfYWdlbmN5X25hbWVgIHRvIGdldCBhIHRvdGFsIGNvdW50IGZvciBlYWNoIHllYXIgYW5kIGVhY2ggc3RhdGUuIFNvIHdlIHdpbGwgZG8gdGhpcyBieSB1c2luZyB0aGUgYGdyb3VwX2J5KClgIGZ1bmN0aW9uIGFuZCBncm91cGluZyBieSBgZGF0YV95ZWFyYCBhbmQgYHN0YXRlX2FiYnJgIGFuZCB1c2luZyB0aGUgYHN1bW1hcml6ZSgpYCBmdW5jdGlvbiB0byBjYWxjdWxhdGUgYSBzdW0uCgpgYGB7cn0KcHNfZGF0YSAlPD4lCiAgZ3JvdXBfYnkoZGF0YV95ZWFyLCBzdGF0ZV9hYmJyKSAlPiUKICBzdW1tYXJpemUocG9saWNlX3N0YXRlX3RvdGFsPXN1bShwb2xpY2VfZW1wX3RvdGFsKSwgLmdyb3VwcyA9ICJkcm9wIikKCnBzX2RhdGEKYGBgCkFuZCB3ZSB3aWxsIGNoZWNrIHRoYXQgd2UgaGF2ZSBzYW1lIG51bWJlciBvZiB2YWx1ZXMgKHRoZSBudW1iZXIgb2YgeWVhcnMgaW5jbHVkZWQgaW4gdGhlIGRhdGEpIGZvciBlYWNoIHN0YXRlLgoKYGBge3J9Cgpwc19kYXRhICU+JQogIGNvdW50KHN0YXRlX2FiYnIpICAlPiUgaGVhZCgpCgpwc19kYXRhICU+JQogIGNvdW50KHN0YXRlX2FiYnIpICU+JQogIGZpbHRlcihuICE9IDM4KSAlPiUKICBkaW0oKQpgYGAKTG9va3MgbGlrZSBhbGwgdGhlIHN0YXRlcyBoYXZlIDM4IHZhbHVlcy4KCk5vdGljZSBhbHNvIHRoYXQgdGhlcmUgYXJlIHNvbWUgdW51c3VhbCBhYmJyZXZpYXRpb25zIGluIHRoZSBgc3RhdGVfYWJicmAgdmFyaWFibGUuCgpXZSB3aWxsIHJlbW92ZSBkYXRhIGZvciBbVVMgdGVycm9pdG9yaWVzIGFuZCBhc3NvY2lhdGVkIHN0YXRlc10oIGh0dHBzOi8vd3d3LmZzLmZlZC51cy9kYXRhYmFzZS9mZWlzL2Zvcm1hdC5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9ICAKCgpBYmJyZXZpYXRpb24gICB8IFRlcnJpdG9yeSBhbmQgYXNzb2NpYXRlZCBzdGF0ZXMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAotLS0tLS0tLS0tIHwtLS0tLS0tLS0tLS0tCioqQVMqKiAgfCBBbWVyaWNhbiBTYW1vYSAKKipHTSoqICB8IEd1YW0KKipDWioqICB8IENhbmFsIFpvbmUKKipGUyoqICB8ID8/RmVkZXJhdGVkIFN0YXRlcyBvZiBNaWNyb25lc2lhICh1c3VhbGx5IEZNKSAgCioqTVAqKiAgfCAgTm9ydGhlcm4gTWFyaWFuYSBJc2xhbmRzCioqT1QqKiAgfCA/P1UuUy4gTWlub3IgT3V0bHlpbmcgSXNsYW5kcyAodXN1YWxseSBVTSkKKipQUioqICB8IFB1ZXJ0byBSaWNvIAoqKlZJKiogIHwgVmlyZ2luIElzbGFuZHMKCgpgYGB7cn0KCnN0YXRlX29mX2ludGVyZXN0X05VTEwgPC0gYygiQVMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdNIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDWiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRlMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1QIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJPVCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUFIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIlZJIikKCnBzX2RhdGEgPC0gcHNfZGF0YSAlPiUKICBmaWx0ZXIoIShzdGF0ZV9hYmJyICVpbiUgc3RhdGVfb2ZfaW50ZXJlc3RfTlVMTCkpIApgYGAKICAKV2l0aGluIHRoZSBgZGF0YXNldHNgIHBhY2thZ2UgdGhhdCBpcyBsb2FkZWQgd2l0aCBSLCB0aGVyZSBpcyBhIGRhdGEgc2V0IGNhbGxlZCBgc3RhdGVgIHRoYXQgY29udGFpbnMgYW4gb2JqZWN0IGNhbGxlZCBgc3RhdGUuYWJiYCB0aGF0IGhhcyB0aGUgc3RhdGUgYWJicmV2aWF0aW9ucyBhbmQgYHN0YXRlLm5hbWVgIHRoYXQgaGFzIHRoZSBzdGF0ZSBuYW1lcy4KV2Ugd2lsbCBjb21iaW5lIHRoZXNlIG5vdyB0byBhZGQgdGhlIHN0YXRlIG5hbWVzIHRvIG91ciBkYXRhLgoKYGBge3J9CnN0YXRlX2FiYl9kYXRhIDwtIHRpYmJsZSggInN0YXRlX2FiYnIiID0gc3RhdGUuYWJiLCAiU1RBVEUiID1zdGF0ZS5uYW1lKQpoZWFkKHN0YXRlX2FiYl9kYXRhKQpgYGAKCk9uZSB1bnVzdWFsIHRoaW5nIGFib3V0IHRoaXMgZGF0YSBpcyB0aGF0IE5FIGlzIHVzZWQgZm9yIE5lYnJhc2thIHRvIGF2b2lkIGNvbmZ1c2lvbnMgd2l0aCBOQiBpbiBDYW5hZGEuIApTbyB3ZSB3YW50IHRvIHJlcGxhY2UgdGhhdCB1c2luZyB0aGUgYHN0cl9yZXBsYWNlKClgIGZ1bmN0aW9uIG9mIHRoZSBgc3RyaW5ncmAgcGFja2FnZQoKYGBge3J9CnN0YXRlX2FiYl9kYXRhICU8PiUKICBtdXRhdGUoc3RhdGVfYWJiciA9IHN0cl9yZXBsYWNlKHN0cmluZyA9IHN0YXRlX2FiYnIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiTkUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcGxhY2VtZW50ID0gIk5CIikpCmBgYAoKYGBge3J9CnN0YXRlX2FiYl9kYXRhICU+JSBwcmludChuID0gNTApCmBgYAoKCgpXZSBuZWVkIHRvIGFkZCBEQyB0byB0aGlzLiBXZSB3aWxsIHVzZSB0aGUgYGFkZF9yb3coKWAgZnVuY3Rpb24gb2YgYGRwbHlyYCB0byBkbyB0aGlzLiAgV2UganVzdCBuZWVkIHRvIHNwZWNpZnkgdmFsdWVzIGZvciBib3RoIG9mIHRoZSB2YXJpYWJsZXMuCgpgYGB7cn0Kc3RhdGVfYWJiX2RhdGEgJTw+JQogIGRwbHlyOjphZGRfcm93KHN0YXRlX2FiYnIgPSAiREMiLAogICAgICAgICAgICAgICAgICAgICAgU1RBVEUgPSAiRGlzdHJpY3Qgb2YgQ29sdW1iaWEiKQpgYGAKCk5vdyB3ZSB3aWxsIGFkZCB0aGlzIHRvIG91ciBwb2xpY2Ugc3RhZmZpbmcgZGF0YSBhbmQgdGhlbiByZW1vdmUgdGhlIGBzdGF0ZV9hYmJyYCB2YXJpYWJsZSwgc28gdGhhdCB3ZSBqdXN0IGhhdmUgc3RhdGUgbmFtZXMuIFdlIHdpbGwgYWxzbyAKCmBgYHtyfQpwc19kYXRhICU8PiUKICBsZWZ0X2pvaW4oc3RhdGVfYWJiX2RhdGEsIGJ5ID0gInN0YXRlX2FiYnIiKSAlPiUKICBkcGx5cjo6c2VsZWN0KC1zdGF0ZV9hYmJyKQpwc19kYXRhCmBgYAoKTm93IHdlIHdpbGwgcmVuYW1lIHRoZSB2YXJpYWJsZXMgdG8gbWF0Y2ggdGhvc2Ugb2YgdGhlIG90aGVyIGRhdGFzZXRzLgpgYGB7cn0KcHNfZGF0YSAlPD4lCiAgcmVuYW1lKFlFQVIgPSAiZGF0YV95ZWFyIiwKICAgICAgICAgVkFMVUUgPSAicG9saWNlX3N0YXRlX3RvdGFsIikgJT4lCiAgbXV0YXRlKFZBUklBQkxFID0gInBvbGljZV9zdGF0ZV90b3RhbCIpCnBzX2RhdGEKYGBgCgoKV2UgYWxzbyBuZWVkIHRvIGFkanVzdCB0aGUgdmFsdWUgdG8gYmUgdGhhdCBvZiBldmVyeSAxMDAsMDAwIHBlb3BsZSBpbiB0aGUgc3RhdGUuIFRvIGRvIHNvIHdlIG5lZWQgdGhlIHBvcHVsYXRpb24gZm9yIGVhY2ggc3RhdGUsIHdoaWNoIGx1Y2tpbHkgd2UgYWxyZWFkeSBoYXZlLiBXZSB3aWxsIHNsaWdodGx5IG1vZGlmeSB0aGUgcG9wdWxhdGlvbiBkYXRhIGFuZCBjcmVhdGUgYSBuZXcgdGliYmxlIHRoYXQgd2lsbCBtYWtlIGl0IG1vcmUgY2xlYXIgaG93IHdlIGFyZSBkaXZpZGluZyBieSBpdC4KCmBgYHtyfQpkZW5vbWluYXRvcl90ZW1wIDwtIHBvcHVsYXRpb25fZGF0YSAlPiUKIHNlbGVjdCgtVkFSSUFCTEUpICU+JQogIHJlbmFtZSgiUG9wdWxhdGlvbl90ZW1wIj1WQUxVRSkKaGVhZChkZW5vbWluYXRvcl90ZW1wKQoKcHNfZGF0YSAlPD4lCiAgbGVmdF9qb2luKGRlbm9taW5hdG9yX3RlbXAsIGJ5PWMoIlNUQVRFIiwiWUVBUiIpKQpoZWFkKHBzX2RhdGEpCmBgYAoKCgpgYGB7cn0KcHNfZGF0YSAlPD4lCiAgbXV0YXRlKFZBTFVFID0gKFZBTFVFICogMTAwMDAwKSAvIFBvcHVsYXRpb25fdGVtcCkgJT4lCiAgI211dGF0ZShWQUxVRSA9IGxhZyhWQUxVRSkpICU+JQogIG11dGF0ZShWQVJJQUJMRSA9ICJwb2xpY2VfcGVyXzEwMGtfbGFnIikgJT4lCiAgc2VsZWN0KC1Qb3B1bGF0aW9uX3RlbXApCgpwc19kYXRhCmBgYAoKPC9kZXRhaWxzPgoqKioKCgojIyAqKlVuZW1wbG95bWVudCoqCioqKgoKVGhlIGZpcnN0IHRoaW5nIHdlIG5lZWQgdG8gZG8gd2l0aCB0aGUgdW5lbXBsb3ltZW50IGRhdGEgaXMgY29tYmluZSB0aGUgZGF0YSBhY3Jvc3MgdGhlIGRpZmZlcmVudCBzdGF0ZXMuCiBXZSBjYW4gZG8gdGhhdCB1c2luZyB0aGUgYGJpbmRfcm93cygpYCBmdW5jdGlvbiBvZiBgZHBseXJgIHdoaWNoIGFwcGVuZHMgdGhlIGRhdGEgdG9nZXRoZXIgYmFzZWQgb24gdGhlIHByZXNlbmNlIG9mIGNvbHVtbnMgd2l0aCB0aGUgc2FtZSBuYW1lIGluIHRoZSBkaWZmZXJlbnQgdGliYmxlcy4gV2Ugd2lsbCB1c2UgdGhlIGBtYXBfZGYoKWAgZnVuY3Rpb24gb2YgdGhlIGBwdXJycmAgcGFja2FnZSB0byBhbGxvdyB1cyB0byBkbyB0aGlzIGFjcm9zcyBlYWNoIHRpYmJsZSBpbiBvdXIgbGlzdC4gV2Ugd2lsbCB0aGVuIHNlbGVjdCBqdXN0IHRoZSBhbm51YWwgZGF0YSBmb3IgZWFjaCBzdGF0ZSBhbmQgeWVhciBhbmQgd2Ugd2lsbCByZW5hbWUgb3VyIHZhcmlhYmxlcyB0byBiZSBjb25zaXN0ZW50IHdpdGggc29tZSBvZiBvdGhlciBkYXRhIHRoYXQgd2UgYXJlIHdvcmtpbmcgd2l0aC4gVGh1cyB3ZSB3b3VsZCBsaWtlIG91ciB2YXJpYWJsZXMgdG8gYmUgYFlFQVJgLCBgVkFMVUVgIGFuZCBgVkFSSUFCTEVgIGluIGFsbCBjYXBzLgogCmBgYHtyfQoKdWVfcmF0ZV9kYXRhIDwtIHVlX3JhdGVfZGF0YSAlPiUKICBtYXBfZGYoYmluZF9yb3dzLCAuaWQgPSAiU1RBVEUiKQoKaGVhZCh1ZV9yYXRlX2RhdGEpCgp1ZV9yYXRlX2RhdGEgPC0gdWVfcmF0ZV9kYXRhICU+JQogIGRwbHlyOjpzZWxlY3QoU1RBVEUsIFllYXIsIEFubnVhbCkgJT4lCiAgcmVuYW1lKCJZRUFSIiA9IFllYXIsCiAgICAgICAgIlZBTFVFIiA9IEFubnVhbCkgJT4lCiAgbXV0YXRlKFZBUklBQkxFID0gIlVuZW1wbG95bWVudF9yYXRlIikKCmhlYWQodWVfcmF0ZV9kYXRhKQpgYGAKCiMjICoqUG92ZXJ0eSByYXRlKioKCioqKgoKKioqCjxkZXRhaWxzPjxzdW1tYXJ5PiBDbGljayBoZXJlIHRvIHNlZSBkZXRhaWxzIGFib3V0IGhvdyB0aGUgcG92ZXJ0eSBkYXRhIHdhcyB3cmFuZ2xlZC4gPC9zdW1tYXJ5PgoKT0ssIG5vdyBmb3Igd3JhbmdsaW5nIHRoZSBwb3ZlcnR5IGRhdGEuIEZpcnN0IGxldCdzIHRha2UgYSBsb29rIGF0IGl0LiAKYGBge3J9CmhlYWQocG92ZXJ0eV9yYXRlX2RhdGEpCmBgYAoKV2UgY2FuIHNlZSB0aGF0IHRoZSBjb2x1bW4gbmFtZXMgYXJlIGFjdHVhbGx5IHNoaWZ0ZWQgZG93biBiZWxvdyB0aGUgcm93IHdpdGggdGhlIHllYXIuIFNvIHdlIHdpbGwgbWFudWFsbHkgbWFrZSB0aGVzZSB2YWx1ZXMgdGhlIGFjdHVhbCBjb2x1bW4gbmFtZXMuCgpgYGB7cn0KY29sbmFtZXMocG92ZXJ0eV9yYXRlX2RhdGEpIDwtIGMoIlNUQVRFIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRvdGFsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk51bWJlciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOdW1iZXJfc2UiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUGVyY2VudCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQZXJjZW50X3NlIikKCnBvdmVydHlfcmF0ZV9kYXRhMiA8LXBvdmVydHlfcmF0ZV9kYXRhCgpgYGAKCkxldCdzIGFsc28gcmVtb3ZlIHRoZSByb3dzIHdoZXJlIHRoZSBjb2x1bW4gbmFtZXMgYXJlIGxpc3RlZCwgbGlrZSByb3cgbnVtYmVyIDIuCgpgYGB7cn0KcG92ZXJ0eV9yYXRlX2RhdGEgICU8PiUKICBmaWx0ZXIoU1RBVEUgIT0gIlNUQVRFIikKaGVhZChwb3ZlcnR5X3JhdGVfZGF0YSkKYGBgCgpXZSBjYW4gYWxzbyBzZWUgdGhhdCB0aGVyZSBhcmUgc29tZSBleHRyYSBub3RlcyBhdCB0aGUgZW5kIG9mIG91ciBkYXRhLiBUaGlzIGlzIHdoeSBpdCBpcyBhIGdvb2QgaWRlYSB0byBsb29rIGF0IGJvdGggdGhlIGhlYWQgYW5kIHRhaWwgb2YgeW91ciBkYXRhLgoKYGBge3J9CnRhaWwocG92ZXJ0eV9yYXRlX2RhdGEpCmBgYApXZSBjYW4gc2VlIHRoYXQgdGhlIHN0cmluZ3MgZm9yIHRoZSBzdGF0ZSBmb3IgdGhlc2Ugcm93cyBhcmUgdmVyeSBsb25nLiBXZSBjYW4gYWxzbyBzZWUgdGhhdCB0aGVyZSBhcmUgcm93cyB0aGF0IGp1c3QgaGF2ZSB0aGUgeWVhciwgd2hlcmUgdGhlIHN0YXRlIGlzIG9ubHkgNCBjaGFyYWN0ZXJzIGxvbmcuIFdlIHdpbGwgY3JlYXRlIGEgbmV3IHZhcmlhYmxlIGNhbGxlZCBgbGVuZ3RoX3N0YXRlYCBiYXNlZCBvbiB0aGUgbnVtYmVyIG9mIGNoYXJhY3RlcnMgaW4gdGhlIGBTVEFURWAgdmFsdWVzLiBXZSB3aWxsIHVzZSB0aGUgYHN0cl9sZW5ndGgoKWAgZnVuY3Rpb24gb2YgdGhlIGBzdHJpbmdyYCBwYWNrYWdlLiBXZSBuZWVkIHRvIHVzZSB0aGUgYG1hcF9kYmwoKWAgZnVuY3Rpb24gdG8gYXBwbHkgdGhpcyB0byBlYWNoIHJvdyBvZiB0aGUgYFNUQVRFYCB2YXJpYWJsZS4gVGhlIGBtYXAoKWAgZnVuY3Rpb24gY3JlYXRlcyBhIGxpc3QsIHdoZXJlYXMgdGhlIGBtYXBfZGJsKClgIGZ1bmN0aW9uIGNyZWF0ZXMgYSB2ZWN0b3Igb2YgY2xhc3MgZG91YmxlLiBJZiB3ZSB3ZXJlIHRvIHVzZSBgbWFwKClgIHdlIHdvdWxkIG5lZWQgdG8gdXNlIGB1bmxpc3QoKWAgYW5kIGBwdWxsKClgLgoKYGBge3J9Cgpwb3ZlcnR5X3JhdGVfZGF0YSAlPD4lCiBtdXRhdGUobGVuZ3RoX3N0YXRlID0gbWFwX2RibChTVEFURSwgc3RyX2xlbmd0aCkpCgojIEFsdGVybmF0aXZlbHkgd2l0aCBtYXAoKQojcG92ZXJ0eV9yYXRlX2RhdGEgJTw+JQojbXV0YXRlKGxlbmd0aF9zdGF0ZSA9IHVubGlzdChtYXAocHVsbChwb3ZlcnR5X3JhdGVfZGF0YSwgU1RBVEUpLCBzdHJfbGVuZ3RoKSkpCgpwb3ZlcnR5X3JhdGVfZGF0YQpgYGAKCgpHcmVhdCwgbm93IGxldCdzIGxvb2sgYXQgdGhlIHRhaWwgd2l0aCBvdXIgbmV3IHZhcmlhYmxlIGBsZW5ndGhfc3RhdGVgCmBgYHtyfQp0YWlsKHB1bGwocG92ZXJ0eV9yYXRlX2RhdGEsIGxlbmd0aF9zdGF0ZSkpCgpgYGAKCmBgYHtyfQpwb3ZlcnR5X3JhdGVfZGF0YSAlPD4lIAogIGZpbHRlcihsZW5ndGhfc3RhdGUgPDEwMCkKCnRhaWwocG92ZXJ0eV9yYXRlX2RhdGEpCmBgYApMb29rcyBnb29kIQoKTm93IGxldCdzIHNlbGVjdCBhbGwgdGhlIHN0YXRlcyB0aGF0IGFyZSBhY3R1YWxseSB5ZWFyIHZhbHVlcyB0byBjcmVhdGUgYSBuZXcgdmFyaWFibGUgYWJvdXQgdGhlIHllYXIuIFdlIGNhbiBkbyBzbyBieSB1c2luZyB0aGUgYHN0cl9kZXRlY3QoKWAgZnVuY3Rpb24gb2YgdGhlIGBzdHJpbmdyYCBwYWNrYWdlIHRvIGxvb2sgZm9yIGRpZ2l0cyBvciB2YWx1ZXMgb2YgMC05LiBUaGlzIGlzIGluZGljYXRlZCBieSB1c2luZyB0aGUgYCJbOmRpZ2l0Ol0iYC4KCkFzIHlvdSBjYW4gc2VlIGluIHRoZSBbUlN0dWRpbyBjaGVhdHNoZWV0XShodHRwczovL3JzdHVkaW8uY29tL3Jlc291cmNlcy9jaGVhdHNoZWV0cy8pe3RhcmdldD0iX2JsYW5rIn0gIGFib3V0IHJlZ3VsYXIgZXhwcmVzc2lvbnMgdGhpcyBub3RhdGlvbiBpbmRpY2F0ZXMgYW55IGRpZ2l0IGJldHdlZW4gMCBhbmQgOS4KCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlKCJpbWciLCAicmVnZXgucG5nIikpCmBgYAoKCgpgYGB7cn0KcG92ZXJ0eV9yYXRlX2RhdGEgJT4lIAogIGZpbHRlcihzdHJfZGV0ZWN0KFNUQVRFLCAiWzpkaWdpdDpdIikpICU+JQogIHByaW50KG4gPSA1MSkKYGBgCgoKClNvbWUgb2YgdGhlIHllYXJzICgyMDEzIGFuZCAyMDE3KSBhcmUgbGlzdGVkIHR3aWNlIHdpdGggYSBudW1iZXIgaW4gcGFyZW50aGVzZXMsIG90aGVycyBhcmUganVzdCBsaXN0ZWQgb25jZSB3aXRoIGEgbnVtYmVyIGluIHBhcmVudGhlc2VzLiBMb29raW5nIGF0IHRoZSB0ZWNobmljYWwgZG9jdW1lbnRhdGlvbiwgdGhpcyBzZWVtcyB0byBkbyB3aXRoIHVwZGF0ZXMgdG8gdGhlIGRlZmluaXRpb24gb2YgcG92ZXJ0eSBhbmQgdG8gdGhlIG1ldGhvZHMgdXNlZCB0byBlc3RpbWF0ZSBwb3ZlcnR5IGxldmVscy4gU2VlIFtoZXJlXShodHRwczovL3d3dy5jZW5zdXMuZ292L3RvcGljcy9pbmNvbWUtcG92ZXJ0eS9wb3ZlcnR5L2d1aWRhbmNlL3BvdmVydHktZm9vdG5vdGVzL2Nwcy1oaXN0b3JpYy1mb290bm90ZXMuaHRtbCl7dGFyZ2V0PSJfYmxhbmsifSBhbmQgW2hlcmVdKGh0dHBzOi8vd3d3Mi5jZW5zdXMuZ292L3Byb2dyYW1zLXN1cnZleXMvY3BzL3RlY2hkb2NzL2Nwc21hcjE5LnBkZil7dGFyZ2V0PSJfYmxhbmsifSBmb3IgbW9yZSBpbmZvcm1hdGlvbi4gV2Ugd2lsbCBzaW1wbHkgc2VsZWN0IG9uZSBvZiB0aGUgc2V0cyBvZiBkYXRhIGZvciAyMDEzIGFuZCAyMDE3LgoKYGBge3J9CnBvdmVydHlfcmF0ZV9kYXRhICU+JSAKICBmaWx0ZXIoc3RyX2RldGVjdChTVEFURSwgIjIwMTMiKSkgJT4lCiAgZmlsdGVyKHN0cl9kZXRlY3QoU1RBVEUsICIyMDE3IikpCmBgYAoKRmlyc3QgbGV0J3MgYWRkIHRoZSB5ZWFyIHZhbHVlIHRvIG91ciBkYXRhLiAKCgpUaGVyZSBzaG91bGQgYmUgY29uc2lzdGVudGx5IGRhdGEgZm9yIDUxIHN0YXRlcyAoaW5jbHVkaW5nIERDKS4gV2UgY2FuIHNlZSB0aGF0IHNvbWV0aW1lcyBEQyBpcyBzcGVsbGVkIG91dCBhbmQgc29tZXRpbWVzIGl0IGlzIG5vdC4KCgpgYGB7cn0KcG92ZXJ0eV9yYXRlX2RhdGEgJT4lIAogIGZpbHRlcihzdHJfZGV0ZWN0KFNUQVRFLCAiWzphbHBoYTpdIikpICU+JQogIGRpc3RpbmN0KFNUQVRFKSAlPiUgcHJpbnQobiA9IDEwMCkKCmBgYAoKCgpOb3cgd2Ugd2lsbCByZXBsYWNlIGAiRC5DLiJgIHdpdGggYCJEaXN0cmljdCBvZiBDb2x1bWJpYSJgIHVzaW5nIGBzdHJfcmVwbGFjZSgpYC4gV2UgY2FuIHVzZSB0aGUgYHRhbGx5KClgIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UgdG8gY2hlY2sgdGhhdCB3ZSBoYXZlIGZld2VyIG5vdy4KCmBgYHtyfQpwb3ZlcnR5X3JhdGVfZGF0YSAlPD4lIAptdXRhdGUoU1RBVEUgPSBzdHJfcmVwbGFjZShTVEFURSwgcGF0dGVybiA9ICJELkMuIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcGxhY2VtZW50ID0gIkRpc3RyaWN0IG9mIENvbHVtYmlhIiApKQoKcG92ZXJ0eV9yYXRlX2RhdGEgJT4lIAogIGZpbHRlcihzdHJfZGV0ZWN0KFNUQVRFLCAiWzphbHBoYTpdIikpICU+JQogIGRpc3RpbmN0KFNUQVRFKSAlPiUgdGFsbHkoKQpgYGAKR3JlYXQhIE5vdyBhcmUgZWFjaCBvZiB0aGUgc3RhdGVzIG9jY3VycmluZyBhcyBvZnRlbiBhcyB0aGUgdW5pcXVlIHllYXIgdmFsdWVzPyBXZSBjYW4gZmlyc3QgY2hlY2sgaG93IG1hbnkgeWVhciB2YWx1ZXMgdGhlcmUgYXJlLiBUaGVuIGNhbiB1c2UgdGhlIGBjb3VudCgpYCBmdW5jdGlvbiBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlIHRvIGNoZWNrIGhvdyBvZnRlbiB0aGUgc3RhdGVzIGFyZSByZXBlYXRlZC4KCmBgYHtyfQoKcG92ZXJ0eV9yYXRlX2RhdGEgJT4lIAogIGZpbHRlcihzdHJfZGV0ZWN0KFNUQVRFLCAiWzpkaWdpdDpdIikpICU+JQogIHRhbGx5KCkKYGBgCgpUaGVyZSBhcmUgNDEgZGlmZmVyZW50IHNldHMgb2YgZGF0YSBhY2NvcmRpbmcgdG8geWVhciB2YWx1ZXMuCgoKYGBge3J9CnBvdmVydHlfcmF0ZV9kYXRhICU+JSAKICBmaWx0ZXIoc3RyX2RldGVjdChTVEFURSwgIls6YWxwaGE6XSIpKSAlPiUKICBjb3VudChTVEFURSkgJT4lIAogIHByaW50KG4gPSA1MSkKYGBgCgoKSW5kZWVkLCBsb29rcyBsaWtlIGVhY2ggb2YgdGhlIHN0YXRlcyBhcmUgcmVwZWF0ZWQgdGhlIHNhbWUgbnVtYmVyIG9mIHRpbWVzIQoKTm93IGxldCdzIGNyZWF0ZSBhIG5ldyB2YXJpYWJsZSBgWUVBUmAgdGhhdCByZXBlYXRzIHRoZSB5ZWFyIHZhbHVlcyBmb3IgYWxsIG9mIHRoZSBkaWZmZXJlbnQgc3RhdGVzIGFuZCBmb3IgdGhlIHJvdyB0aGF0IGhhcyBqdXN0IHRoZSB5ZWFyIHZhbHVlIGZvciBhIHRvdGFsIG9mIDUyLgoKYGBge3J9Cgp5ZWFyX3ZhbHVlcyA8LSBwb3ZlcnR5X3JhdGVfZGF0YSAlPiUgCiAgZmlsdGVyKHN0cl9kZXRlY3QoU1RBVEUsICJbOmRpZ2l0Ol0iKSkgJT4lCiAgZGlzdGluY3QoU1RBVEUpCgogIHllYXJfdmFsdWVzPC1yZXAocHVsbCh5ZWFyX3ZhbHVlcywgU1RBVEUpLCBlYWNoID0gNTIpCnNldGVxdWFsKGxlbmd0aCh5ZWFyX3ZhbHVlcyksIGxlbmd0aChwb3ZlcnR5X3JhdGVfZGF0YSRTVEFURSkpCmBgYAoKTm93IHdlIHdpbGwgYWRkIHRoaXMgdG8gb3VyIGBwb3ZlcnR5X3JhdGVfZGF0YWAuIFdlIHdpbGwgYWxzbyByZW1vdmUgdGhlIGBsZW5ndGhfc3RhdGVgIHZhcmlhYmxlIHVzaW5nIHRoZSBgc2VsZWN0KClgIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UgYW5kIGEgbWludXMgc2lnbiBiZWZvcmUgdGhlIHZhcmlhYmxlIG5hbWUuCgpgYGB7cn0KcG92ZXJ0eV9yYXRlX2RhdGEgJTw+JQogIG11dGF0ZSh5ZWFyX3ZhbHVlID0geWVhcl92YWx1ZXMpICU+JQogIHNlbGVjdCgtbGVuZ3RoX3N0YXRlKQpgYGAKCgpgYGB7cn0KcG92ZXJ0eV9yYXRlX2RhdGEgJT4lIHByaW50KG4gPSAxMDApCmBgYAoKCkxvb2tzIGdvb2QhIE5vdyB3ZSB3aWxsIHJlbW92ZSB0aGUgcm93cyB0aGF0IGhhdmUganVzdCB0aGUgeWVhciB2YWx1ZXMgYnkgb25seSBwcmVzZXJ2aW5nIHRob3NlIHdpdGggYWxwaGEgY2hhcmFjdGVycy4KCmBgYHtyfQpwb3ZlcnR5X3JhdGVfZGF0YSAlPD4lCiAgICBmaWx0ZXIoc3RyX2RldGVjdChTVEFURSwgIls6YWxwaGE6XSIpKQoKYGBgCgpOb3cgbGV0J3MgcmVtb3ZlIHRoZSBvbGRlciBkYXRhIGZvciAyMDEzIGFuZCAyMDE3IHdoaWNoIGlzIHRoZSBkYXRhIHRoYXQgYXBwZWFycyBsb3dlciBpbiB0aGUgdGliYmxlLgoKYGBge3J9CnBvdmVydHlfcmF0ZV9kYXRhICU8PiUKZmlsdGVyKHllYXJfdmFsdWUgIT0gIjIwMTciKSAlPiUKZmlsdGVyKHllYXJfdmFsdWUgIT0gIjIwMTMgKDE4KSIpCmBgYAoKCldlIGFsc28gd2FudCB0byBqdXN0IGtlZXAgdGhlIGZpcnN0IDQgZGlnaXRzIG9mIHRoZSB5ZWFyX3ZhbHVlIGFuZCBjcmVhdGUgYSBgWUVBUmAgdmFyaWFibGUuIFdlIG5lZWQgdG8gcHVsbCB0aGUgYHllYXJfdmFsdWVgIGRhdGEgYmVjYXVzZSBgc3RyX3N1YigpYCBleHBlY3RzIGEgY2hhcmFjdGVyIHZlY3RvciBub3QgYSB0aWJibGUuCgpgYGB7cn0KcG92ZXJ0eV9yYXRlX2RhdGEgJTw+JQogIG11dGF0ZShZRUFSID0gc3RyX3N1YihwdWxsKC4sIHllYXJfdmFsdWUpLCBzdGFydCA9IDEsIGVuZD00KSkKYGBgCgoKYGBge3J9CnBvdmVydHlfcmF0ZV9kYXRhIApgYGAKCgpMb29rcyBnb29kISBOb3cgd2Ugd2lsbCBqdXN0IHJlbW92ZSB0aGUgZXh0cmEgdmFyaWFibGVzIGFuZCByZW5hbWUgdGhlIHZhcmlhYmxlcyB3ZSB3YW50IHRvIGtlZXAgdG8gYmUgc2ltaWxhciB0byBvdXIgb3RoZXIgZGF0YS4KCmBgYHtyfQpwb3ZlcnR5X3JhdGVfZGF0YSAlPD4lCiAgZHBseXI6OnNlbGVjdCgtIE51bWJlciwKICAgICAgICAgICAgICAgIC0gTnVtYmVyX3NlLAogICAgICAgICAgICAgICAgLSBQZXJjZW50X3NlLAogICAgICAgICAgICAgICAgLSBUb3RhbCwKICAgICAgICAgICAgICAgIC0geWVhcl92YWx1ZSkgJT4lCiAgcmVuYW1lKCJWQUxVRSIgPSBQZXJjZW50KSAlPiUKICBtdXRhdGUoVkFSSUFCTEUgPSAiUG92ZXJ0eV9yYXRlIiwKICAgICAgICAgWUVBUiA9IGFzLm51bWVyaWMoWUVBUiksCiAgICAgICAgIFZBTFVFID0gYXMubnVtZXJpYyhWQUxVRSkpCmhlYWQocG92ZXJ0eV9yYXRlX2RhdGEpCmBgYAoKTG9va3MgZ3JlYXQhIAoKCjwvZGV0YWlscz4KKioqCgoKCiMjICoqVmlvbGVudCBjcmltZSoqCioqKgoKKioqCjxkZXRhaWxzPjxzdW1tYXJ5PiBDbGljayBoZXJlIHRvIHNlZSBkZXRhaWxzIGFib3V0IGhvdyB0aGUgdmlvbGVudCBjcmltZSBkYXRhIHdhcyB3cmFuZ2xlZCA8L3N1bW1hcnk+CgpUaGUgYGNyaW1lX2RhdGFgIHdhcyBpbXBvcnRlZCB1c2luZyBgcmVhZF9saW5lcygpYCBhbmQgd2UgaGF2ZSBzb21lIGxpbmVzIHRoYXQgd2UgZG9uJ3QgbmVjZXNzYXJpbHkgbmVlZC4gQSBsYXJnZSBhbW91bnQgb2YgdGhlIG9yaWdpbmFsIGRhdGEgaXMgbm90ZXMgYXQgdGhlIGVuZCBvZiB0aGUgdGFibGUuIFdlIHdhbnQgdG8gcmVtb3ZlIHRoZXNlIGxpbmVzLiBXZSBjYW4gZGV0ZXJtaW5lIHdoZXJlIHRoZXkgc3RhcnQgYnkgc2VhcmNoaW5nIGZvciB0aGUgcm93IHRoYXQgY29udGFpbnMgdGhlIGZpcnN0IHN0YXRlbWVudCBvZiB0aGVzZSBub3RlcyB1c2luZyB0aGUgYHN0cl93aGljaCgpYCBmdW5jdGlvbiBvZiB0aGUgYHN0cmluZ3JgIHBhY2thZ2UuIFdlIHdpbGwgc3VidHJhY3Qgb25lIGZyb20gdGhpcyBhcyB0aGVyZSBpcyBhIGJsYW5rIGxpbmUgaW4gYmV0d2Vlbi4KCmBgYHtyfQp0YWlsKGNyaW1lX2RhdGEpCmNyaW1lX2RhdGEgPC0gY3JpbWVfZGF0YVstKChzdHJfd2hpY2goY3JpbWVfZGF0YSwgIlRoZSBmaWd1cmVzIHNob3duIGluIHRoaXMgY29sdW1uIGZvciB0aGUgb2ZmZW5zZSBvZiByYXBlIHdlcmUgZXN0aW1hdGVkIHVzaW5nIHRoZSBsZWdhY3kgVUNSIGRlZmluaXRpb24gb2YgcmFwZSIpLTEpOiBsZW5ndGgoY3JpbWVfZGF0YSkpXQojY3JpbWVfZGF0YSA8LSBjcmltZV9kYXRhWy0oMjE0MzpsZW5ndGgoY3JpbWVfZGF0YSkpXQp0YWlsKGNyaW1lX2RhdGEpCmBgYAoKVGhlcmUgYXJlIGxpbmVzIGZvciBlYWNoIHllYXIgZnJvbSAxOTc3IHRvIDIwMTQgYXMgd2VsbCBhcyBmb3VyIGxpbmVzIGFib3V0IGVhY2ggc3RhdGUgYW5kIHRoZSBoZWFkZXIgaW5mb3JtYXRpb24gZm9yIGVhY2ggc3RhdGUuIApIZXJlIHlvdSBjYW4gc2VlIHdoYXQgdGhlIG9yaWdpbmFsIGRhdGEgbG9va3MgbGlrZToKYGBge3J9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmUoImltZyIsICJjcmltZV9kYXRhLnBuZyIpKQpgYGAKCldlIHdhbnQgdG8gZGVsZXRlIHRoZSBoZWFkZXIgaW5mb3JtYXRpb24gYW5kIG9ubHkgcmV0YWluIHRoZSBsaW5lcyBudW1lcmljIHZhbHVlcyBvciBzdGF0ZSBuYW1lcy4gIFRodXMgc2luY2UgdGhlcmUgYXJlIDM4IHllYXJzIHdvcnRoIG9mIGRhdGEgZm9yIGVhY2ggc3RhdGUgYW5kIDQgbGluZXMgZm9yIGVhY2ggaGVhZGVyLCB0aGVuIGVhY2ggc3RhdGUgaGFzIDQyIGxpbmVzLiBXZSB3YW50IHRvIGRlbGV0ZSB0aGUgbGluZXMgYmV0d2VlbiBhbmQgaW5jbHVkaW5nIGxpbmUgMiB0byA0IGZvciBlYWNoIHN0YXRlLiBXZSB3aWxsIHNhdmUgdGhlIGhlYWRlciBpbmZvcm1hdGlvbiBvbmNlIHRvIHVzZSBsYXRlci4KYGBge3J9CmhlYWQoY3JpbWVfZGF0YSkKeCA8LSAyMDE0LTE5NzcrMQpyZXBfY3ljbGUgPC0gNCArIHgKcmVwX2N5Y2xlX2N1dCA8LSAyICsgeApjb2xuYW1lc19jcmltZTwtKGNyaW1lX2RhdGFbNF0pCmBgYAoKU28gc3RhcnRpbmcgYXQgbGluZSAyIGFuZCBhbmQgMyBhbmQgNCB3ZSBjcmVhdGUgYSBzZXF1ZW5jZSBvZiBudW1iZXJzIHRoYXQgaW5jcmVhc2UgYnkgdGhlIG51bWJlciBvZiByb3dzIG9mIHRoZSBsZW5ndGggb2YgdGhlIGluZGl2aWR1YWwgc3RhdGUgZGF0YS4gV2UgY2FuIGRvIHNvIHVzaW5nIHRoZSBiYXNlIGBzZXEoKWAgZnVuY3Rpb24uIFdlIGNhbiB0YWtlIGEgbG9vayBhdCB0aGVzZSBpbiBvcmRlciB1c2luZyB0aGUgYmFzZSBgc29ydCgpYCBmdW5jdGlvbi4KCmBgYHtyfQpkZWxldGVfcm93cyA8LSBjKHNlcShmcm9tID0gMiwKICAgICAgICAgICAgICAgICAgICAgICB0byA9IGxlbmd0aChjcmltZV9kYXRhKSwKICAgICAgICAgICAgICAgICAgICAgICBieSA9IHJlcF9jeWNsZSksCiAgICAgICAgICAgICAgICAgc2VxKGZyb20gPSAzLAogICAgICAgICAgICAgICAgICAgICAgIHRvID0gbGVuZ3RoKGNyaW1lX2RhdGEpLAogICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gcmVwX2N5Y2xlKSwgCiAgICAgICAgICAgICAgICAgc2VxKGZyb20gPSA0LAogICAgICAgICAgICAgICAgICAgICAgIHRvID0gbGVuZ3RoKGNyaW1lX2RhdGEpLAogICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gcmVwX2N5Y2xlKSkKc29ydChkZWxldGVfcm93cykKCmBgYApUaHVzIHdlIHdpbGwgZGVsZXRlIGxpbmVzIDIsIDMsIGFuZCA0IGFuZCB0aGVuIHNraXAgNDAgbGluZXMgKHRvIGFjY291bnQgZm9yIHRoZSBzdGF0ZSBpbmZvcm1hdGlvbiBmb3IgdGhlIGZpcnN0IHN0YXRlLCB0aGUgbGluZXMgb2YgaW5mb3JtYXRpb24gZm9yIHRoZSAzOCB5ZWFycywgYW5kIHRoZW4gdGhlIHN0YXRlIGluZm9ybWF0aW9uIGZvciB0aGUgbmV4dCBzdGF0ZSkgYW5kIHRoZW4gZGVsZXRlIHRoZSBuZXh0IDMgY29uc2VjdXRpdmUgbGluZXMgYW5kIHNvIG9uLiBXZSBjYW4gaW5kZWVkIHNlZSB0aGF0IGxpbmUgNDQtNDYgYXJlIHdoYXQgd2Ugd2lzaCB0byByZW1vdmUuCgpgYGB7cn0KY3JpbWVfZGF0YVs0NDo0Nl0KYGBgCgpgYGB7cn0KY3JpbWVfZGF0YSA8LSBjcmltZV9kYXRhWy1kZWxldGVfcm93c10KYGBgCgoKTmljZSEKCk5vdyB3ZSBjYW4gc2VsZWN0IGFsbCB0aGUgbGluZXMgdGhhdCBoYXZlIHN0YXRlIGluZm9ybWF0aW9uLiBXZSBjYW4gcmVwZWF0IGVhY2ggb2YgdGhlc2UgZm9yIHRoZSAzOCB5ZWFycyBmb3IgZWFjaCBzdGF0ZSBhcyB3ZWxsIGFzIHRoaXMgbGluZSB0aGF0IGNvbnRhaW5zIHRoZSBzdGF0ZSBpbmZvcm1hdGlvbiBieSB1c2luZyB0aGUgYmFzZSBgcmVwKClgIGZ1bmN0aW9uIHdpdGggdGhlIGBlYWNoID1gIGFyZ3VtZW50LiBGaW5hbGx5IHdlIHdpbGwgcmVtb3ZlIHRoZSBgIkVzdGltYXRlZCBjcmltZSBpbiAiYCBwb3J0aW9uIG9mIHRoZSBzdHJpbmcgdXNpbmcgdGhlIGBzdHJfcmVtb3ZlKClgIGZ1bmN0aW9uIG9mIHRoZSBgc3RyaW5ncmAgcGFja2FnZS4gIFdlIHdpbGwgbGF0ZXIgY29tYmluZSB0aGlzIHdpdGggdGhlIGNyaW1lIGRhdGEuCgpgYGB7cn0Kc3RhdGVfbGFiZWxfb3JkZXIgPC1jcmltZV9kYXRhW3N0cl93aGljaChjcmltZV9kYXRhLCAiRXN0aW1hdGVkIGNyaW1lIildCnN0YXRlX2xhYmVsX29yZGVyCgpzdGF0ZV9sYWJlbF9vcmRlciA8LSByZXAoc3RhdGVfbGFiZWxfb3JkZXIsIGVhY2ggPSAzOCkKCmNyaW1lX3N0YXRlcyA8LXN0cl9yZW1vdmUoc3RhdGVfbGFiZWxfb3JkZXIsIHBhdHRlcm4gPSAiRXN0aW1hdGVkIGNyaW1lIGluICIpCmhlYWQoY3JpbWVfc3RhdGVzKQpgYGAKCk5pY2UhIE5vdyBmb3IgdGhlIHJlc3Qgb2YgdGhlIGRhdGEuIFdlIG5vdyBuZWVkIHRvIHJlbW92ZSB0aGUgbGluZXMgd2l0aCB0aGUgc3RhdGUgaW5mb3JtYXRpb24uCgpgYGB7cn0KY3JpbWVfZGF0YSA8LWNyaW1lX2RhdGFbLXN0cl93aGljaChjcmltZV9kYXRhLCAiRXN0aW1hdGVkIGNyaW1lIildCmhlYWQoY3JpbWVfZGF0YSkKdGFpbChjcmltZV9kYXRhKQpgYGAKCkl0IGFwcGVhcnMgdGhhdCB0aGUgZGF0YSBpcyBjb21tYSBzZXBhcmF0ZWQgd2l0aCA4IGNvbHVtbnMuIE9uZSBvZiB0aGUgbWlkZGxlIGNvbHVtbnMgb2Z0ZW4gaGFzIG5vIHZhbHVlcywgd2UgbmVlZCB0byBmaWxsIHRoZXNlIGluIHdpdGggTkFzLiBXZSBjYW4gdXNlIHRoZSBgcmVhZF9jc3YoKWAgZnVuY3Rpb24gZnJvbSB0aGUgYHJlYWRyYCBwYWNrYWdlIHRvIGRvIHRoaXMuIEl0IHR1cm5zIG91dCB5b3UgZG9uJ3QgaGF2ZSB0byBoYXZlIGEgZmlsZSwgYnV0IHlvdSBjYW4gYWxzbyB1c2UgYSBzdHJpbmcgb3VyIGEgdmVjdG9yLgoKYGBge3J9CmNyaW1lX2RhdGFfc2VwIDwtcmVhZF9jc3YoY3JpbWVfZGF0YSwgY29sX25hbWVzID0gRkFMU0UpCmhlYWQoY3JpbWVfZGF0YSkKYGBgCk5pY2UhIE5vdyB3ZSBqdXN0IG5lZWQgb3VyIGNvbHVtbiBuYW1lcy4gUmVjYWxsIHRoYXQgd2Ugc2F2ZWQgdGhpcyBpbmZvcm1hdGlvbi4gCgpgYGB7cn0KY29sbmFtZXNfY3JpbWUKCmNvbG5hbWVzKGNyaW1lX2RhdGFfc2VwKSA8LWMoIlllYXIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQb3B1bGF0aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVmlvbGVudF9jcmltZV90b3RhbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk11cmRlcl9hbmRfbm9ubmVnbGlnZW50X01hbnNsYXVnaHRlciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkxlZ2FjeV9yYXBlIiAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlJldmlzZWRfcmFwZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJSb2JiZXJ5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQWdncmF2YXRlZF9hc3NhdWx0IikKaGVhZChjcmltZV9kYXRhX3NlcCkKYGBgCgpXZSBhbHNvIHdhbnQgdG8gY29tYmluZSB0aGlzIHdpdGggdGhlIHN0YXRlIGluZm9ybWF0aW9uIHdlIGNvbGxlY3RlZCBlYXJsaWVyLgpXZSB3aWxsIHVzZSB0aGUgYGJpbmRfY29scygpYCBmdW5jdGlvbiBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlIHRvIGRvIHRoaXMuIFRoaXMgcmVxdWlyZXMgdGhhdCB0aGUgZGF0YSBoYXZlIHRoZSBzYW1lIG51bWJlciBvZiByb3dzLgoKYGBge3J9CmNyaW1lX2RhdGFfc2VwIDwtYmluZF9jb2xzKFNUQVRFID1jcmltZV9zdGF0ZXMsIAogICAgICAgICAgY3JpbWVfZGF0YV9zZXApCgpgYGAKCk5vdyB3ZSB3aWxsIHJlbmFtZSB0aGUgYFZpb2xfY3JpbWVfY291bnRgIHZhcmlhYmxlIHRvIGJlIGBWYXJpYWJsZWAgYW5kIHdlIHdpbGwgcmVtb3ZlIGFsbCBvZiB0aGUgb3RoZXIgY29sdW1ucyBleGNlcHQgZm9yIGBZZWFyYC4gV2Ugd2lsbCBhbHNvIHJlbmFtZSB0aGUgdmFyaWFibGVzIHRvIGxvb2sgbGlrZSB0aGUgb3RoZXIgZGF0YXNldHMuCgpgYGB7cn0KY3JpbWVfZGF0YSA8LSBjcmltZV9kYXRhX3NlcCAlPiUKICBtdXRhdGUoVkFSSUFCTEUgPSAiVmlvbF9jcmltZV9jb3VudCIpICU+JQogIHJlbmFtZSgiVkFMVUUiID0gVmlvbGVudF9jcmltZV90b3RhbCkgJT4lCiAgcmVuYW1lKCJZRUFSIiA9IFllYXIpICU+JQogIHNlbGVjdChZRUFSLFNUQVRFLCBWQVJJQUJMRSwgVkFMVUUpCgpjcmltZV9kYXRhCmBgYAoKPC9kZXRhaWxzPgoqKioKCgojIyAqKlJpZ2h0LXRvLWNhcnJ5IGxhd3MqKiAgCioqKgoKKioqCjxkZXRhaWxzPjxzdW1tYXJ5PiBDbGljayBoZXJlIHRvIHNlZSBkZXRhaWxzIGFib3V0IGhvdyB0aGUgUlRDIExhdyBkYXRhIHdhcyB3cmFuZ2xlZCA8L3N1bW1hcnk+CgoKVGhlIGluZm9ybWF0aW9uIGFib3V0IHRoZSBsYXdzIGZvciBlYWNoIHN0YXRlIGFyZSBsb2NhdGVkIG9uIHBhZ2UgNjIgb2YgdGhlIFtEb25vaHVlLCBldCBhbC5dKGh0dHBzOi8vd3d3Lm5iZXIub3JnL3BhcGVycy93MjM1MTAucGRmKXt0YXJnZXQ9Il9ibGFuayJ9IGFydGljbGUsIHNvIGZpcnN0IHdlIHdpbGwgc2VsZWN0IGp1c3QgdGhpcyBwYWdlLiBXZSBjYW4gcHJpbnQgcGFydCBvZiB0aGUgY2hhcmFjdGVyIHN0cmluZyBmb3IgdGhpcyBwYWdlIHVzaW5nIHRoZSBgdXRpbHNgIGBzdHIoKWAgZnVuY3Rpb24gYW5kIHRoZSBgbmNhci5tYXhgIGFyZ3VtZW50LgoKYGBge3J9CkRBV3BhcGVyX3BfNjIgPC0gREFXcGFwZXJbWzYyXV0Kc3RyKERBV3BhcGVyX3BfNjIsIG5jaGFyLm1heCA9IDEwMDApCmBgYAoKIFdlIGNhbiBhbHNvIHVzZSB0aGUgYGNhdGAgZnVuY3Rpb24gdG8gc2VlIHRoZSBkYXRhIHByaW50ZWQgbmljZWx5IHRvIHNlZSB3aGF0IHdlIGFyZSBnb2luZyBmb3IuCmBgYHtyfQoKY2F0KERBV3BhcGVyX3BfNjIpCmBgYAoKCldlIGNhbiBzZWUgdGhhdCB0aGlzIGlzIG9uZSBjb250aW51b3VzIGNoYXJhY3RlciBzdHJpbmcuIFdlIGNhbiBzZXBhcmF0ZSBpbnRvIGxpbmVzIGJhc2VkIG9uIHRoZSBwcmVzZW5jZSBvZiBgIlxuImAgaW4gdGhlIHN0cmluZyB1c2luZyB0aGUgYHN0cl9zcGxpdCgpYCBmdW5jdGlvbiBvZiB0aGUgYHN0cmluZ3JgIHBhY2thZ2UuIFdlIG5lZWQgdG8gdW5saXN0IHRoZSBkYXRhIGZpcnN0LCBhcyB0aGUgb3V0cHV0IG9mIGBzdHJfc3BsaXQoKWAgaXMgYSBsaXN0LiBGaW5hbGx5LCB3ZSBjYW4gY29udmVydCBpdCB0byBhIHRpYmJsZSB1c2luZyB0aGUgYGFzLnRpYmJsZSgpYCBmdW5jdGlvbiBvZiB0aGUgYHRpYmJsZWAgcGFja2FnZS4gIFdlIGFsc28gc2VlIHRoYXQgd2UgZG9uJ3QgbmVlZCB0aGUgZmlyc3QgbGluZSBhYm91dCB0aGUgdGFibGUuIFdlIGNhbiByZW1vdmUgdGhpcyB3aXRoIHRoZSBgc2xpY2UoKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZS4gV2UgY2FuIGFsc28gdXNlIHRoaXMgdG8gcmVtb3ZlIHRoZSBjb2x1bW4gbmFtZXMgc28gdGhhdCB3ZSBjYW4gcmVwbGFjZSB0aGVtLiBUaHVzIHdlIHdpbGwgdXNlIGBzbGljZSgtKDE6MikpYCB0byByZW1vdmUgdGhlIGZpcnN0IHR3byBsaW5lcy4KClNvIHdlIHdpbGwgc3BsaXQgYW5kIHVubGl0KCkgdGhlIGRhdGEuCmBgYHtyfQpwXzYyIDwtIERBV3BhcGVyX3BfNjIgJT4lCiAgICBzdHJfc3BsaXQoIlxuIikgJT4lCiAgICB1bmxpc3QoKSAlPiUKICAgIGRwbHlyOjphc190aWJibGUoKSAlPiUKICAgIHNsaWNlKC0oMToyKSkKCmhlYWQocF82MikKdGFpbChwXzYyKQoKYGBgCgoKCldlIGFsc28gc2VlIGJ5IGxvb2tpbmcgYXQgdGhlIHRhaWwgdGhhdCB3ZSB3YW50IHRvIHJlbW92ZSB0aGUgbGFzdCB0d28gbGluZXMuIE9uZSBpcyBlbXB0eSBhbmQgdGhlIG90aGVyIGhhcyBvbmx5IDYzIGNoYXJhY3RlcnMsIHdoaWNoIGlzIHRoZSBsaW5lIHdpdGggdGhlIHBhZ2UgbnVtYmVyLgoKYGBge3J9CnBfNjIgJTw+JQogIHJlbmFtZShSVEMgPSB2YWx1ZSkKcF82MiAlPiUKICBtdXRhdGUoUlRDID0gbWFwX2NocihSVEMsIHN0cl9sZW5ndGgpKSAlPiV0YWlsKCkKCnBfNjJbNTMsXSAjIHBoeXNjaWFsIHBhZ2UgNjAKcF82Mls1NCxdICMgZW1wdHkgbGluZQpwXzYyICU8PiUKICAgIHNsaWNlKC1jKDUzOjU0KSkKYGBgCgpOb3cgd2Ugd2lsbCB0cnkgc3BsaXR0aW5nIGJ5IHNwYWNlcy4gV2UgY2FuIHNob3cgdGhlIG91dHB1dCB3aXRoZSB0aGUgYGZpcnN0KClgIGFuZCBgbnRoKClgIGZ1bmN0aW9ucyBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlLgoKYGBge3J9CnBfNjIgJT4lIHB1bGwoUlRDKSAlPiUgbWFwKHN0cl9zcGxpdCwgcGF0dGVybiA9ICIgIikgJT4lIGZpcnN0KCkKcF82MiAlPiUgcHVsbChSVEMpICU+JSBtYXAoc3RyX3NwbGl0LCBwYXR0ZXJuID0gIiAiKSAlPiUgbnRoKCA1KQpgYGAKCgpJbnRlcmVzdGluZywgd2UgY2FuIHNlZSB0aGF0IHRoZXJlIGFyZSBsb3RzIG9mIHNwYWNlcyBiZXR3ZWVuIHRoZSBlbGVtZW50cyBvZiB0aGUgdGFibGUgYW5kIHRoYXQgdGhleSB2YXJ5IGJ5IGxpbmUuIEZvciBleGFtcGxlIHRoZXJlIGFyZSA2IHNwYWNlcyBiZWZvcmUgQWxhYmFtYSBhbmQgNyBzcGFjZXMgYmVmb3JlIEFsYXNrYS4KCk92ZXJhbGwsIHRoYXQgZGlkbid0IHdvcmsgcXVpdGUgbGlrZSB3ZSBleHBlY3RlZC4gCgpSZWNhbGwgZnJvbSB0aGUgY2hlYXRzaGVldCB0aGF0IGAiXFxzImAgaW5kaWNhdGVzIGEgc3BhY2UuIFRoZXJlIGFyZSBhbHNvIHdheXMgdG8gc3BlY2lmeSBob3cgbWFueSBzcGFjZXMgdXNpbmcgY3VybHkgYnJhY2tldHNge31gLiAKCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlKCJpbWciLCAicmVnZXgucG5nIikpCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmUoImltZyIsICJxdWFudGlmaWVycy5wbmciKSkKYGBgCgpUaGUgc3BhY2luZyBhcHBlYXJzIHRvIHZhcnkgcXVpdGUgYSBiaXQuIFdFIGNhbiB1c2UgdGhlIGBzdHJfY291bnQoKWAgZnVuY3Rpb24gb2YgdGhlIGBzdHJpbmdyYCBwYWNrYWdlIHRvIHNlZSBob3cgb2Z0ZW4gd2UgaGF2ZSB3aGl0ZSBzcGFjZXMgbGFyZ2VyIHRoYW4gNSwgMTAsIDE1LCBvciA0MCBzcGFjZXMuCmBgYHtyfQojIGhvdyBvZnRlbiBhcmUgdGhlcmUgd2hpdGUgc3BhY2VzIHdpdGggbW9yZSB0aGFuIDUgc3BhY2VzCnBfNjIgJT4lIAogIHB1bGwoUlRDKSAlPiUgCiAgbWFwKHN0cl9jb3VudCwgcGF0dGVybiA9ICJcXHN7NSx9IikgJT4lIAogIHVubGlzdCgpCiMgaG93IG9mdGVuIGFyZSB0aGVyZSB3aGl0ZSBzcGFjZXMgd2l0aCBtb3JlIHRoYW4gMTAgc3BhY2VzCnBfNjIgJT4lIAogIHB1bGwoUlRDKSAlPiUgCiAgbWFwKHN0cl9jb3VudCwgcGF0dGVybiA9ICJcXHN7MTAsfSIpICU+JQogIHVubGlzdCgpCgojIGhvdyBvZnRlbiBhcmUgdGhlcmUgd2hpdGUgc3BhY2VzIHdpdGggbW9yZSB0aGFuIDE1IHNwYWNlcwpwXzYyICU+JSAKICBwdWxsKFJUQykgJT4lIAogIG1hcChzdHJfY291bnQsIHBhdHRlcm4gPSAiXFxzezE1LH0iKSAlPiUKICB1bmxpc3QoKQoKIyBob3cgb2Z0ZW4gYXJlIHRoZXJlIHdoaXRlIHNwYWNlcyB3aXRoIG1vcmUgdGhhbiA0MCBzcGFjZXMKcF82MiAlPiUgCiAgcHVsbChSVEMpICU+JQogIG1hcChzdHJfY291bnQsIHBhdHRlcm4gPSAiXFxzezQwLH0iKSAlPiUgCiAgdW5saXN0KCkKYGBgCgpSb3dzIHdpdGggd2hpdGUgc3BhY2VzIHdpdGggbW9yZSB0aGFuIDQwIGNvbnNlY3V0aXZlIHNwYWNlcyBpcyBsZXNzIGNvbW1vbi4gSXQgYXBwZWFycyB0byBiZSB0aGUgY2FzZSBpbiB0aGUgMXN0IGFuZCA1dGggcm93LiAKCklmIHdlIHRha2UgYSBsb29rIGF0IHRob3NlIHJvd3Mgd2UgY2FuIHNlZSB0aGF0IHRoaXMgb2NjdXJzIHdoZW4gd2UgaGF2ZSBhIG1pc3NpbmcgdmFsdWUuCgoKYGBge3J9CmNhdChEQVdwYXBlcl9wXzYyKQpgYGAKCgpTbyB3ZSB3aWxsIHJlcGxhY2Ugd2hpdGUgc3BhY2VzIHdpdGggbW9yZSB0aGFuIDQwIGNvbnNlY3V0aXZlIHNwYWNlcyB3aXRoIGBOQWAuIExldCdzIGFsc28gcmVtb3ZlIHRoZSBsZWFkaW5nIHdoaXRlIHNwYWNlcyB0aGF0IHZhcmllcyBpbiBmcm9udCBvZiB0aGUgc3RhdGUgbmFtZXMsIGFzIERDIGRvZXMgbm90IGhhdmUgYW55IGFuZCB0aGlzIGNvdWxkIGNhdXNlIGEgcHJvYmxlbSBsYXRlci4gV2Ugd2lsbCBhbHNvIHJlcGxhY2UgYW55IHdoaXRlIHNwYWNlcyBvZiAyIGNvbnNlY3V0aXZlIHNwYWNlcyBvciBtb3JlICwgYnV0IGxlc3MgdGhhbiAxNSB3aGl0ZSBzcGFjZXMgd2l0aCAifCIgc28gdGhhdCB3ZSBjYW4gc3BsaXQgdGhlIGRhdGEgYmFzZWQgb24gdGhpcyBzeW1ib2wuIFRodXMgd2Ugd2lsbCBhbHNvIHB1dCB0aGVzZSBhcm91bmQgdGhlIGBOQWAgdmFsdWUgdGhhdCB3ZSBhcmUgdXNpbmcgcmVwbGFjZSB0aGUgd2hpdGUgc3BhY2VzIG1hZGUgb2YgNDArIHNwYWNlcy4gCmBgYHtyfQoKcF82MmIgPC1wXzYyICU+JQogIG11dGF0ZShSVEMgPSBzdHJfcmVwbGFjZV9hbGwocHVsbCguLCBSVEMpLCAiXFxzezQwLH0iLCAifE4vQXwiKSkgJT4lCiAgbXV0YXRlKFJUQyA9c3RyX3RyaW0ocHVsbCguLCBSVEMpLCBzaWRlID0gImxlZnQiKSkgJT4lCiAgbXV0YXRlKFJUQyA9IHN0cl9yZXBsYWNlX2FsbChwdWxsKC4sIFJUQyksICJcXHN7MiwxNX0iLCAifCIpKQpoZWFkKHBfNjJiKQpgYGAKCk5vdyBhbnl0aW1lIHRoZXJlIGlzICBvbmUgb3IgbW9yZSBgInwiYCB3ZSBzaG91bGQgaGF2ZSBhIGNvbHVtbiBicmVhay4gU28gbm93IHdlIHdpbGwgc3BsaXQgdGhlIGRhdGEgYnkgdGhpcyBzeW1ib2wuCmBgYHtyfQoKcF82MmIgPC1wdWxsKHBfNjJiLCBSVEMpICU+JQogIHN0cl9zcGxpdCggIlxcfHsxLH0iKSAKCmhlYWQocF82MmIpCmBgYAoKR3JlYXQhIE5vdyB3ZSB3YW50IHRvIHB1dCBvdXIgZGF0YSBpbiB0aWJibGUgZm9ybWF0LiBUbyBkbyBzbyB3ZSBuZWVkIHRvIGJpbmQgdGhlIHJvd3MgdG9nZXRoZXIuIFdlIGNhbiBkbyBzbyB1c2luZyB0aGUgYmFzZSBgcmJpbmQoKWAgZnVuY3Rpb24uIFdlIHdpbGwgdXNlIHRoaXMgaW5zdGVhZCBvZiB0aGUgYGJpbmRfcm93cygpYCBmdW5jdGlvbiBvZiBgZHBseXJgIGJlY2F1c2UgYHJiaW5kKClgIGlzIGxlc3MgcmVzdHJpY3RpdmUgYW5kIGFsbG93cyBmb3IgY29sdW1ucyB3aXRob3V0IG5hbWVzLiBXZSB3aWxsIHVzZSB0aGUgYmFzZSBgZG8uY2FsbCgpYCBmdW5jdGlvbiwgc28gdGhhdCB0aGlzIGlzIHBlcmZvcm1lZCBhbG9uZyBlYWNoIGNoYXJhY3RlciBzdHJpbmcgd2l0aGluIHRoZSBsaXN0IG9mIGBwXzYyYmAgd2hpbGUgbWFpbnRhaW5pbmcgdGhlIHN0cnVjdHVyZS4gVGhlbiB3ZSBjcmVhdGUgYSB0aWJibGUgb3V0IG9mIHRoaXMuIAoKYGBge3J9CnBfNjIgPC0gYXMudGliYmxlKGRvLmNhbGwocmJpbmQsIHBfNjJiKSkKCmNvbG5hbWVzKHBfNjIpIDwtIGMoIlNUQVRFIiwKICAgICAgICAgICAgICAgICAgICAiRV9EYXRlX1JUQyIsCiAgICAgICAgICAgICAgICAgICAgIkZyYWNfWXJfRWZmX1lyX1Bhc3MiLAogICAgICAgICAgICAgICAgICAgICJSVENfRGF0ZV9TQSIpCgpwXzYyIDwtIHBfNjIgJT4lCiAgZHBseXI6OnNlbGVjdChTVEFURSwgUlRDX0RhdGVfU0EpICU+JQogIHJlbmFtZSgiUlRDX0xBV19ZRUFSIj0gUlRDX0RhdGVfU0EpICU+JQogIG11dGF0ZShSVENfTEFXX1lFQVIgPSBhcy5udW1lcmljKFJUQ19MQVdfWUVBUikpICU+JQogIG11dGF0ZShSVENfTEFXX1lFQVIgPSBjYXNlX3doZW4oUlRDX0xBV19ZRUFSID09IDAgfiBJbmYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBSVENfTEFXX1lFQVIpKQoKUlRDIDwtcF82MgpSVEMKYGBgCgo8L2RldGFpbHM+CioqKgoKIyMgKipKb2luaW5nIERhdGEqKgoqKioKCk5vdyB3ZSB3aWxsIGpvaW4gdGhlIGRhdGEgZnJvbSB0aGUgZGlmZmVyZW50IGRhdGEgc2V0cyB0b2dldGhlciB0byBjcmVhdGUgYSB0aWJibGUgb2YgZGF0YSBmb3IgYW4gYW5hbHlzaXMgdGhhdCB3aWxsIGJlIHNpbWlsYXIgdG8gdGhlIGRhdGEgdXNlZCBieSBbRG9ub2h1ZSBldCBhbC5dKGh0dHBzOi8vd3d3Lm5iZXIub3JnL3BhcGVycy93MjM1MTAucGRmKSB7dGFyZ2V0PSJfYmxhbmsifSBhbmQgW011c3RhcmQgYW5kIExvdHRdKGh0dHBzOi8vY2hpY2Fnb3VuYm91bmQudWNoaWNhZ28uZWR1L2NnaS92aWV3Y29udGVudC5jZ2k/YXJ0aWNsZT0xMTUwJmNvbnRleHQ9bGF3X2FuZF9lY29ub21pY3Mpe3RhcmdldD0iX2JsYW5rIn0uCgpGaXJzdCB3ZSBuZWVkIHRvIGNoZWNrIHRoYXQgb3VyIGRhdGEgaXMgaW5kZWVkIHJlYWR5IHRvIGJlIGpvaW5lZC4gV2UgbmVlZCB0byBtYWtlIHN1cmUgdGhhdCB0aGUgY29sdW1uIG5hbWVzIGFyZSB0aGUgc2FtZSBmb3IgZWFjaCBkYXRhc2V0IHRoYXQgd2UgaW50ZW5kIHRvIGNvbWJpbmUgdG9nZXRoZXIuIAoKV2Ugd2lsbCB1c2UgdGhlIGBjb21wYXJlX2RmX2NvbHMoKWAgYW5kIGBjb21wYXJlX2RmX2NvbHNfc2FtZSgpYCBmdW5jdGlvbnMgb2YgdGhlIGphbml0b3IgcGFja2FnZSwgdG8gZW5zdXJlIHRoYXQgdGhlIGNvbHVtbiBuYW1lcyBhcmUgdGhlIHNhbWUgYW5kIHRoYXQgdGhlIGNvbHVtbiB2YWx1ZXMgYXJlIHRoZSBzYW1lIHR5cGUgc28gdGhhdCB0aGUgdGliYmxlcyBjYW4gYmUgam9pbmVkIGJ5IHJvdy4gCgpJZiB0aGV5IGNhbiBiZSBqb2luZWQgYnkgcm93LCB0aGVuIGBjb21wYXJlX2RmX2NvbHNfc2FtZSgpYCAgcmV0dXJucyB0aGUgdmFsdWUgYFRSVUVgLCB3aGlsZSBjb21wYXJlX2RmX2NvbHMoKSwgcHJvdmlkZXMgYSBkZXNjcmlwdGlvbiBvZiB0aGUgY29sdW1ucy4KCmBgYHtyfQpsaWJyYXJ5KGphbml0b3IpCgpkYXRhX2xpc3QgPC0gIGxpc3QoZGVtX0RPTk9IVUUsCiAgICAgICAgICAgICAgICBkZW1fTE9UVCwKICAgICAgICAgICAgICAgIHBvcHVsYXRpb25fZGF0YSwKICAgICAgICAgICAgICAgIHVlX3JhdGVfZGF0YSwKICAgICAgICAgICAgICAgIHBvdmVydHlfcmF0ZV9kYXRhLAogICAgICAgICAgICAgICAgY3JpbWVfZGF0YSwKICAgICAgICAgICAgICAgIHBzX2RhdGEpICNwb2xpY2Ugc3RhZmZpbmcKCmphbml0b3I6OmNvbXBhcmVfZGZfY29sc19zYW1lKGRhdGFfbGlzdCkKamFuaXRvcjo6Y29tcGFyZV9kZl9jb2xzKGRhdGFfbGlzdCkKCgpjaGVja3N0YXRlIDwtIGZ1bmN0aW9uKHgpIHsgeCAlPD4lIGRpc3RpbmN0KFNUQVRFKSAlPiUgdGFsbHkoKSAlPiUgcHVsbChuKSB9Cm1hcChkYXRhX2xpc3QsIGNoZWNrc3RhdGUpCmNoZWNreWVhciA8LSBmdW5jdGlvbih4KSB7IHggJTw+JSBkaXN0aW5jdChZRUFSKSAlPiUgdGFsbHkoKSAlPiUgcHVsbChuKSB9Cm1hcChkYXRhX2xpc3QsIGNoZWNreWVhcikKYGBgCgoKIyMgKipEb25vaHVlLCBldCBhbC4qKgoqKioKCldlIHdpbGwgbm93IGJpbmQgdGhlIGRlbW9ncmFwaGljIGRhdGEgdGhhdCB3ZSBtYWRlIGZvciB0aGUgRG9ub2h1ZS1saWtlIGFuYWx5c2lzIGNhbGxlZCBgZGVtX0RPTk9IVUVgLCBhcyB3ZWxsIGFzIGFsbCB0aGUgb3RoZXIgZGF0YXNldHMgdGhhdCB3ZSBoYXZlIHdyYW5nbGVkLiBUaGlzIGlzIHBvc3NpYmxlIGJlY2F1c2Ugd2UgaGF2ZSB0aGUgc2FtZSBjb2x1bW4gbmFtZXMgZm9yIGVhY2ggZGF0YXNldC4gV2Ugd2lsbCBhbHNvIHVzZSB0aGUgYHBpdm90X3dpZGVyKClgIGZ1bmN0aW9uIG9mIHRoZSBgdGlkeXJgIHBhY2thZ2UgdG8gY2hhbmdlIHRoZSBzaGFwZSBvZiB0aGUgZGF0YS4gVGhpcyB3aWxsIG1ha2UgdGhlIGRhdGEgaGF2ZSBtb3JlIGNvbHVtbnMuIEVhY2ggdW5pcXVlIHZhbHVlIGluIHRoZSBjb2x1bW4gY2FsbGVkIGBWQVJJQUJMRWAgd2lsbCBiZSB1c2VkIHRvIG1ha2UgbmV3IGNvbHVtbnMuIGFuZCB0aGUgdmFsdWVzIGZvciBlYWNoIHdpbGwgY29tZSBmcm9tIHRoZSBjb2x1bW4gY2FsbGVkIGBWQUxVRWAuCgpgYGB7cn0KRE9OT0hVRV9ERiA8LSBiaW5kX3Jvd3MoZGVtX0RPTk9IVUUsCiAgICAgICAgICAgICAgICAgICAgICAgIHVlX3JhdGVfZGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgcG92ZXJ0eV9yYXRlX2RhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgIGNyaW1lX2RhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgIHBvcHVsYXRpb25fZGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgcHNfZGF0YSkKaGVhZChET05PSFVFX0RGKQpgYGAKCgpgYGB7cn0KRE9OT0hVRV9ERiAlPD4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9ICJWQVJJQUJMRSIsCiAgICAgICAgICAgICAgdmFsdWVzX2Zyb20gPSAiVkFMVUUiKQoKRE9OT0hVRV9ERiAlPiUKICBzbGljZV9zYW1wbGUobiA9IDEwKSAlPiUKICBnbGltcHNlKCkKYGBgCgpXZSB3aWxsIGFsc28gYWRkIHRoZSBSaWdodCB0byBDYXJyeSBMYXcgZGF0YSB1c2luZyB0aGUgYGxlZnRfam9pbigpYCBmdW5jdGlvbiBvZiB0aGUgYGRwbHlyYCBwYWNrYWdlLiBXaGljaCB3aWxsIHBsYWNlIHRoZSBgRE9OT0hVRV9ERmAgZGF0YSBvbiB0aGUgbGVmdCBvZiB0aGUgYFJUQ2AgZGF0YS4gIFZhbHVlcyB3aWxsIGJlIG1hdGNoZWQgYnkgU1RBVEUuIFRoZW4gd2Ugd2lsbCBjcmVhdGUgYSBuZXcgdmFyaWFibGUgY2FsbGVkIGBSVENfTEFXYCB1c2luZyB0aGUgYG11dGF0ZSgpYCBmdW5jdGlvbiBhbmQgdGhlIGBjYXNlX3doZW4oKWAgZnVuY3Rpb24gb2YgdGhlIGBkcGx5cmAgcGFja2FnZSAgdGhhdCB3aWxsIGhhdmUgdGhlIHZhbHVlIGBUUlVFYCBpZiB0aGUgY3VycmVudCB5ZWFyIGRhdGEgaXMgZXF1YWwgdG8gb3IgZ3JlYXRlciB0aGFuIHRoZSB5ZWFyIHRoYXQgYSBtb3JlIHBlcm1pc3NpdmUgUlRDIGxhdyB3YXMgYWRvcHRlZCwgb3RoZXJ3aXNlIHRoZSB2YWx1ZSB3aWxsIGJlIGBGQUxTRWAuCgpgYGB7cn0KCmhlYWQoUlRDKQoKRE9OT0hVRV9ERiAlPD4lCiAgbGVmdF9qb2luKFJUQyAsIGJ5ID0gYygiU1RBVEUiKSkgJT4lCiAgbXV0YXRlKFJUQ19MQVcgPSBjYXNlX3doZW4oWUVBUiA+PSBSVENfTEFXX1lFQVIgfiBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gRkFMU0UpKQoKRE9OT0hVRV9ERiAlPiUKICBzbGljZV9zYW1wbGUobiA9IDEwKSAlPiUKICBnbGltcHNlKCkKYGBgCgpTaW5jZSB3ZSBoYXZlIGRpZmZlcmluZyBudW1iZXJzIG9mIHllYXJzIGZvciBlYWNoIGRhdGEgc2V0LCB3ZSBjYW4gdXNlIHRoZSBgZHJvcF9uYSgpYCBmdW5jdGlvbiBvZiB0aGUgYHRpZHlyYCBwYWNrYWdlLiB0byByZW1vdmUgeWVhcnMgdGhhdCBoYXZlIGluY29tcGxldGUgZGF0YS4gVGh1cyBhbnkgcm93IHdpdGggTkEgdmFsdWVzIHdpbGwgYmUgcmVtb3ZlZC4KCkZvciBleGFtcGxlLCB3ZSBjYW4gc2VlIHRoYXQgZm9yIDE5NzcsIGFsdGhvdWdoIHdlIGhhdmUgbW9zdCBvZiB0aGUgZGF0YSwgd2UgZG8gbm90IGhhdmUgdGhlIHBvdmVydHkgcmF0ZS4gCmBgYHtyfQpET05PSFVFX0RGICU+JQogIGZpbHRlcihZRUFSID09IDE5NzcpICU+JQogIGhlYWQoKSAlPiUKICBnbGltcHNlKCkKCmBgYAoKQW5vdGhlciBleGFtcGxlLCBpbiAyMDE4IHdlIG9ubHkgaGF2ZSBpbmZvcm1hdGlvbiBhYm91dCB1bmVtcGxveW1lbnQgcmF0ZXMsIHBvdmVydHkgcmF0ZXMsIGFuZCBSVEMgbGF3cy4KCmBgYHtyfQpET05PSFVFX0RGICU+JQogIGZpbHRlcihZRUFSID09IDIwMTgpICU+JQogIGhlYWQoKSAlPiUKICBnbGltcHNlKCkKCmBgYAoKYGBge3J9CkRPTk9IVUVfREYgJTw+JQogZHJvcF9uYSgpCgpoZWFkKERPTk9IVUVfREYpICU+JSAKICBnbGltcHNlKCkKdGFpbChET05PSFVFX0RGKSAlPiUgCiAgZ2xpbXBzZSgpCgpgYGAKCk5vdyB3ZSBoYXZlIGNvbXBsZXRlIGRhdGEgYW5kIHRoZSBkYXRhIHNwYW5zIGZyb20gMTk4MCB0byAyMDEwLgoKYGBge3J9CkRPTk9IVUVfREYgJT4lIGRpc3RpbmN0KFlFQVIpICU+JSBwdWxsKFlFQVIpCmBgYAoKSWYgd2UgaW5jbHVkZSBzdGF0ZXMgdGhhdCBoYWQgYSBSVEMgbGF3IGFkb3B0ZWQgYmVmb3JlIG91ciB0aW1lIHNwYW4gb2YgZGF0YSwgc2F5IDE5NzUsIHRoZW4gd2Ugb25seSBoYXZlIGluZm9ybWF0aW9uIGFib3V0IGNyaW1lIHJhdGVzIGFuZCB0aGUgb3RoZXIgdmFyaWFibGVzIG9mIGludGVyZXN0IGFmdGVyIHRoZSBsYXcgd2FzIGFkb3B0ZWQgYnV0IG5vdCBiZWZvcmUsIHRoZXJlZm9yZSBpbmNsdWRpbmcgdGhlc2Ugc3RhdGVzIGRvZXNuJ3QgcmVhbGx5IG1ha2VzIHNlbnNlLiBUaHVzLCB3ZSB3aWxsIGRyb3AgdGhlIGRhdGEgZm9yIHRoZXNlIHN0YXRlcy4gV2UgY2FuIHVzZSB0aGUgYHNldF9kaWZmKClgIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UgdG8gc2VlIHdoYXQgc3RhdGVzIGFyZSBpbiB0aGUgYHBvcHVsYXRpb25fZGF0YWAgdGhhdCBjb250YWlucyBhbGwgdGhlIG9yaWdpbmFsIDUxIHN0YXRlcyAocmVjYWxsIHRoaXMgaW5jbHVkZXMgdGhlIERpc3RyaWN0IG9mIENvbHVtYmlhKSBidXQgYXJlIG5vdCBpbiB0aGUgYERPTk9IVUVfREZgLiBUaGUgb3JkZXIgbWF0dGVycyBoZXJlLiBJZiB3ZSBkaWQgaXQgdGhlIG90aGVyIHdheSBhcm91bmQgd2l0aCBgcG9wdWxhdGlvbl9kYXRhYCBsaXN0ZWQgc2Vjb25kLCB0aGVuIHNldF9kaWZmIHdvdWxkIHRlc3QgaWYgdGhlcmUgYXJlIGFueSBzdGF0ZXMgaW4gYERvbm9odWVfREZgIHRoYXQgYXJlIG5vdCBpbiBgcG9wdWxhdGlvbl9kYXRhYC4gQXMgdGhlcmUgYXJlIG5vbmUgdGhpcyB3b3VsZCByZXN1bHQgaW4gbm90aGluZy4KCmBgYHtyfQpiYXNlbGluZV95ZWFyIDwtIG1pbihET05PSFVFX0RGJFlFQVIpCmNlbnNvcmluZ195ZWFyIDwtIG1heChET05PSFVFX0RGJFlFQVIpCgpET05PSFVFX0RGICU8PiUKICBtdXRhdGUoVElNRV8wID0gYmFzZWxpbmVfeWVhciwKICAgICAgICAgVElNRV9JTkYgPSBjZW5zb3JpbmdfeWVhcikgJT4lCiAgZmlsdGVyKFJUQ19MQVdfWUVBUiA+IFRJTUVfMCkKCiMgRE9OT0hVRV9ERiAlPD4lIAojICAgbXV0YXRlKFNUQVRFID0gYXMuZmFjdG9yKFNUQVRFKSkKIyAKIyBET05PSFVFX0RGICU+JSAKIyAgIHB1bGwoU1RBVEUpICU+JSAKIyAgIGxldmVscygpCgpzZXRkaWZmKGRpc3RpbmN0KHBvcHVsYXRpb25fZGF0YSwgU1RBVEUpLCAKICAgICAgICBkaXN0aW5jdChET05PSFVFX0RGLCBTVEFURSkpCmBgYAoKV2Ugd2lsbCBhbHNvIGNhbGN1bGF0ZSBhIHZpb2xlbnQgY3JpbWUgcmF0ZSByZWxhdGl2ZSB0byB0aGUgcG9wdWxhdGlvbiBpbiB0aGF0IHN0YXRlIGF0IHRoYXQgdGltZSwgbm93IHRoYXQgd2UgaGF2ZSBkYXRhIGZvciBib3RoIGNyaW1lIGNvdW50IGFuZCBwb3B1bGF0aW9uLiAgV2lsbCB3aWxsIGFsc28gY2FsY3VsYXRlIHRoZSBsb2cgdmFsdWUgb2YgdGhpcyByYXRlIGFuZCB0aGUgcG9wdWxhdGlvbi4KCmBgYHtyfQpET05PSFVFX0RGICU8PiUKICBtdXRhdGUoVmlvbF9jcmltZV9yYXRlXzFrID0gKFZpb2xfY3JpbWVfY291bnQqMTAwMCkvUG9wdWxhdGlvbiwKICAgICAgICAgVmlvbF9jcmltZV9yYXRlXzFrX2xvZyA9IGxvZyhWaW9sX2NyaW1lX3JhdGVfMWspLAogICAgICAgICBQb3B1bGF0aW9uX2xvZyA9IGxvZyhQb3B1bGF0aW9uKSkKYGBgCgoKCiMjICoqTXVzdGFyZCBhbmQgTG90dCoqCioqKgoKV2Ugd2lsbCBub3cgYmluZCB0aGUgZGVtb2dyYXBoaWMgZGF0YSB0aGF0IHdlIG1hZGUgZm9yIHRoZSBNdXN0YXJkIGFuZCBMb3R0IGFuYWx5c2lzIGNhbGxlZCBgZGVtX0xvdHRgLCBhcyB3ZWxsIGFzIGFsbCB0aGUgb3RoZXIgZGF0YXNldHMgdGhhdCB3ZSBoYXZlIHdyYW5nbGVkIGp1c3QgYXMgd2UgZGlkIGZvciB0aGUgRG9ub2h1ZS1saWtlIGFuYWx5c2lzLiBBZ2FpbiwgdGhpcyBpcyBwb3NzaWJsZSBiZWNhdXNlIHdlIGhhdmUgdGhlIHNhbWUgY29sdW1uIG5hbWVzIGZvciBlYWNoIGRhdGFzZXQuIAoKYGBge3J9CkxPVFRfREYgPC0gYmluZF9yb3dzKGRlbV9MT1RULAogICAgICAgICAgICAgICAgICAgICB1ZV9yYXRlX2RhdGEsCiAgICAgICAgICAgICAgICAgICAgIHBvdmVydHlfcmF0ZV9kYXRhLAogICAgICAgICAgICAgICAgICAgICBjcmltZV9kYXRhLAogICAgICAgICAgICAgICAgICAgICBwb3B1bGF0aW9uX2RhdGEsCiAgICAgICAgICAgICAgICAgICAgIHBzX2RhdGEpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSAiVkFSSUFCTEUiLAogICAgICAgICAgICAgIHZhbHVlc19mcm9tID0gIlZBTFVFIikgJT4lCiAgbGVmdF9qb2luKFJUQyAsIGJ5ID0gYygiU1RBVEUiKSkgJT4lCiAgbXV0YXRlKFJUQ19MQVcgPSBjYXNlX3doZW4oWUVBUiA+PSBSVENfTEFXX1lFQVIgfiBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gRkFMU0UpKSAlPiUKICAgZHJvcF9uYSgpCgoKYmFzZWxpbmVfeWVhciA8LSBtaW4oTE9UVF9ERiRZRUFSKQpjZW5zb3JpbmdfeWVhciA8LSBtYXgoTE9UVF9ERiRZRUFSKQoKTE9UVF9ERiAlPD4lCiAgbXV0YXRlKFRJTUVfMCA9IGJhc2VsaW5lX3llYXIsCiAgICAgICAgIFRJTUVfSU5GID0gY2Vuc29yaW5nX3llYXIpICU+JQogIGZpbHRlcihSVENfTEFXX1lFQVIgPiBUSU1FXzApCgpzZXRkaWZmKGRpc3RpbmN0KHBvcHVsYXRpb25fZGF0YSwgU1RBVEUpLCAKICAgICAgICBkaXN0aW5jdChMT1RUX0RGLCBTVEFURSkpCgpMT1RUX0RGICU8PiUKICBtdXRhdGUoVmlvbF9jcmltZV9yYXRlXzFrID0gKFZpb2xfY3JpbWVfY291bnQqMTAwMCkvUG9wdWxhdGlvbiwKICAgICAgICAgVmlvbF9jcmltZV9yYXRlXzFrX2xvZyA9IGxvZyhWaW9sX2NyaW1lX3JhdGVfMWspLAogICAgICAgICBQb3B1bGF0aW9uX2xvZyA9IGxvZyhQb3B1bGF0aW9uKSkKCmBgYApMZXQncyBzZWUgaG93IHRoZSBkYXRhIGNvbXBhcmVzOgoKV2Ugd2lsbCBjaGVjayB0aGUgZGltZW5zaW9ucyBvZiBlYWNoIHVzaW5nIHRoZSBiYXNlIGBkaW0oKWAgZnVuY3Rpb24KYGBge3J9CmRpbShMT1RUX0RGKQpkaW0oRE9OT0hVRV9ERikKYGBgCgpBcyBleHBlY3RlZCB0aGUgYExvdHRfREZgIGlzIDMwIGNvbHVtbnMgbGFyZ2VyLCBkdWUgdG8gdGhlIDMwIGFkZGl0aW9uYWwgZGVtb2dyYXBoaWMgdmFyaWFibGVzLiBXZSBjYW4gY2hlY2sgdGhvc2Ugbm93IGFzIHdlbGwuCgpgYGB7cn0KTE9UVF9ERiAlPiUKICAgY29sbmFtZXMoKQoKRE9OT0hVRV9ERiAlPiUKICAgY29sbmFtZXMoKQpgYGAKCkxhc3RseSwgd2Ugd2lsbCBjaGVjayB0aGF0IHRoZSBgWUVBUmAgdmFsdWVzIGFyZSB0aGUgc2FtZS4gV2UgY2FuIHVzZSB0aGUgYHNldGVxdWFsKClgIGZ1bmN0aW9uIG9mIHRoZSBgZHBseXJgIHBhY2thZ2UgdG8gc2VlIGlmIHRoZSB2YWx1ZXMgYXJlIHRoZSBzYW1lLiAKCmBgYHtyfQpzZXRlcXVhbChET05PSFVFX0RGICU+JSBkaXN0aW5jdChZRUFSKSwKICAgICAgICAgIExPVFRfREYgJT4lIGRpc3RpbmN0KFlFQVIpKQpgYGAKCgpMb29rcyBhcyBleHBlY3RlZCEgCgoKTm93IHdlIHdpbGwgc2F2ZSBvdXIgd3JhbmdsZWQgZGF0YSBmb3IgdGhlIHBhcnQgMiBjYXNlIHN0dWR5OgoKV2UgY2FuIHVzZSB0aGUgYGhlcmUoKWAgZnVuY3Rpb24gb2YgdGhlIGBoZXJlYCBwYWNrYWdlIHRvIGVhc2lseSBzYXZlIHRoaXMgaW4gYSBkaXJlY3RvcnkgY2FsbGVkIGB3cmFuZ2xlZGAgd2l0aGluIHRoZSBgZGF0YWAgZGlyZWN0b3J5IHdpdGhpbiB0aGUgZGlyZWN0b3J5IHdoZXJlIGFyZSAuUnByb2ogZmlsZSBpcyBsb2NhdGVkLgoKYGBge3J9CnNhdmUoTE9UVF9ERiwgRE9OT0hVRV9ERiwgZmlsZSA9IGhlcmU6OmhlcmUoImRhdGEiLCAid3JhbmdsZWQiLCAid3JhbmdsZWRfZGF0YS5yZGEiKSkKYGBgCgojICoqU3VtbWFyeSoqCioqKiAKClRoaXMgY2FzZSBzdHVkeSBoYXMgaW50cm9kdWNlZCBtYW55IGNvbmNlcHRzIGZvciBkYXRhIGltcG9ydGF0aW9uIGFuZCBkYXRhIHdyYW5nbGluZy4gVG8gY29udGludWUgd2l0aCB0aGlzIGRhdGEgdG8gc2VlIG1vcmUgYWJvdXQgZGF0YSBhbmFseXNpcyBhbmQgdmlzdWFsaXphdGlvbiBzZWUgdGhpcyBuZXh0IFtjYXNlIHN0dWR5XShodHRwczovL3d3dy5vcGVuY2FzZXN0dWRpZXMub3JnL29jcy1icC1SVEMtYW5hbHlzaXMvKS4KCgojICoqU3VnZ2VzdGVkIEhvbWV3b3JrKioKKioqIAoKQXNrIHN0dWRlbnRzIHRvIGltcG9ydCBhbmQgd3JhbmdsZSBzaW1pbGFyIGRhdGFzZXRzIHRvIHRob3NlIHVzZWQgaGVyZS4KCgojICoqQWRkaXRpb25hbCBJbmZvcm1hdGlvbioqCgoqKioKCiMjICoqSGVscGZ1bCBMaW5rcyoqCioqKgoKW1RpZHl2ZXJzZV0oaHR0cHM6Ly93d3cudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gIAoKVGhlIGFydGljbGVzIHVzZWQgdG8gbW90aXZhdGUgdGhpcyBjYXNlIHN0dWR5IGFyZTogICAKW011c3RhcmQgYW5kIExvdHRdKGh0dHBzOi8vY2hpY2Fnb3VuYm91bmQudWNoaWNhZ28uZWR1L2NnaS92aWV3Y29udGVudC5jZ2k/YXJ0aWNsZT0xMTUwJmNvbnRleHQ9bGF3X2FuZF9lY29ub21pY3Mpe3RhcmdldD0iX2JsYW5rIn0gIApbRG9ub2h1ZSwgZXQgYWwuXShodHRwczovL3d3dy5uYmVyLm9yZy9wYXBlcnMvdzIzNTEwLnBkZil7dGFyZ2V0PSJfYmxhbmsifSAgICAgCltTZWUgaGVyZSBmb3IgYSBsaXN0IG9mIHN0dWRpZXMgb24gdGhpcyB0b3BpYyBdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL01vcmVfR3VucyxfTGVzc19DcmltZSl7dGFyZ2V0PSJfYmxhbmsifSAgCgo8dT4qKlBhY2thZ2VzIHVzZWQgaW4gdGhpcyBjYXNlIHN0dWR5OioqIDwvdT4KClBhY2thZ2UgICB8IFVzZSBpbiB0aGlzIGNhc2Ugc3R1ZHkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKLS0tLS0tLS0tLSB8LS0tLS0tLS0tLS0tLQpbaGVyZV0oaHR0cHM6Ly9naXRodWIuY29tL2plbm55YmMvaGVyZV9oZXJlKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgIHwgdG8gZWFzaWx5IGxvYWQgYW5kIHNhdmUgZGF0YQpbcmVhZHhsXShodHRwczovL3JlYWR4bC50aWR5dmVyc2Uub3JnLyl7dGFyZ2V0PSJfYmxhbmsifSAgICAgIHwgdG8gaW1wb3J0IHRoZSBkYXRhIGluIHRoZSBleGNlbCBmaWxlcyAKW3JlYWRyXShodHRwczovL3JlYWRyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byBpbXBvcnQgdGhlIENTViBmaWxlIGRhdGEKW3BkZnRvb2xzXShodHRwczovL2dpdGh1Yi5jb20vcm9wZW5zY2kvcGRmdG9vbHMpe3RhcmdldD0iX2JsYW5rIn0gfCB0byBpbXBvcnQgZGF0YSBmcm9tIGEgcGRmIGZpbGUKW2RwbHlyXShodHRwczovL2RwbHlyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byBhcnJhbmdlL2ZpbHRlci9zZWxlY3QvY29tcGFyZSBzcGVjaWZpYyBzdWJzZXRzIG9mIHRoZSBkYXRhICAKW21hZ3JpdHRyXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvbWFncml0dHIvdmlnbmV0dGVzL21hZ3JpdHRyLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gfCB0byB1c2UgdGhlIGNvbXBvdW5kIGFzc2lnbm1lbnQgcGlwZSBvcGVyYXRvciBgJTw+JWAKW3RpZHlyXShodHRwczovL3RpZHlyLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICAgfCB0byByZWFycmFuZ2UgZGF0YSBpbiB3aWRlIGFuZCBsb25nIGZvcm1hdHMgCltzdHJpbmdyXShodHRwczovL3N0cmluZ3IudGlkeXZlcnNlLm9yZy9hcnRpY2xlcy9zdHJpbmdyLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0gICAgfCB0byBtYW5pcHVsYXRlIHRoZSBjaGFyYWN0ZXIgc3RyaW5ncyB3aXRoaW4gdGhlIGRhdGEgIApbcHVycnJdKGh0dHBzOi8vcHVycnIudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gICB8IHRvIGltcG9ydCB0aGUgZGF0YSBpbiBhbGwgdGhlIGRpZmZlcmVudCBleGNlbCBhbmQgY3N2IGZpbGVzIGVmZmljaWVudGx5Cltmb3JjYXRzXShodHRwczovL2ZvcmNhdHMudGlkeXZlcnNlLm9yZy8pe3RhcmdldD0iX2JsYW5rIn0gICAgfCB0byBhbGxvdyBmb3IgcmVvcmRlcmluZyBvZiBmYWN0b3JzIGluIHBsb3RzClt0aWJibGVdKGh0dHBzOi8vdGliYmxlLnRpZHl2ZXJzZS5vcmcvKXt0YXJnZXQ9Il9ibGFuayJ9ICAgICB8IHRvIGNyZWF0ZSBkYXRhIG9iamVjdHMgdGhhdCB3ZSBjYW4gbWFuaXB1bGF0ZSB3aXRoIGBkcGx5cmAvYHN0cmluZ3JgL2B0aWR5cmAvYHB1cnJyYAoKIyMgKipTZXNzaW9uIEluZm8qKgoqKioKCmBgYHtyfQpkZXZ0b29sczo6c2Vzc2lvbl9pbmZvKCkKYGBgCgojIyAqKkFja25vd2xlZGdtZW50cyoqCioqKgoKV2Ugd291bGQgbGlrZSB0byBhY2tub3dsZWRnZSBbRGFuaWVsIFdlYnN0ZXJdKGh0dHBzOi8vd3d3Lmpoc3BoLmVkdS9mYWN1bHR5L2RpcmVjdG9yeS9wcm9maWxlLzczOS9kYW5pZWwtd2Vic3RlcikgZm9yIGFzc2lzdGluZyBpbiBmcmFtaW5nIHRoZSBtYWpvciBkaXJlY3Rpb24gb2YgdGhlIGNhc2Ugc3R1ZHkuCgpXZSB3b3VsZCBhbHNvIGxpa2UgdG8gYWNrbm93bGVkZ2UgdGhlIFtCbG9vbWJlcmcgQW1lcmljYW4gSGVhbHRoIEluaXRpYXRpdmVdKGh0dHBzOi8vYW1lcmljYW5oZWFsdGguamh1LmVkdS8pIGZvciBmdW5kaW5nIHRoaXMgd29yay4gCgo8c2NyaXB0IHR5cGU9J3RleHQvamF2YXNjcmlwdCcgaWQ9J2NsdXN0cm1hcHMnIHNyYz0nLy9jZG4uY2x1c3RybWFwcy5jb20vbWFwX3YyLmpzP2NsPTA4MDgwOCZ3PWEmdD10dCZkPXZJMTByVlcwWnFPcE5ZMWRIeVhKOWxQTzItM0w2cG5LN2oyZlV5bUU0dDAmY289ZmZmZmZmJmNtbz0zYWNjM2EmY21uPWZmNTM1MyZjdD04MDgwODAnPjwvc2NyaXB0PgoK